From dc03585bb01165d537f85584ee1f7d96d8c30d96 Mon Sep 17 00:00:00 2001 From: ofek Date: Sun, 24 Mar 2024 02:05:39 +0000 Subject: [PATCH] release Hatchling v1.22.4 026bcf4fe52f9fe31975895fb062ea89e881e95c --- 1.9/404.html | 2 +- .../images/social/community/highlights.png | Bin 33969 -> 41461 bytes .../social/how-to/config/dynamic-metadata.png | Bin 0 -> 39409 bytes .../social/how-to/meta/report-issues.png | Bin 0 -> 37808 bytes .../images/social/how-to/publish/auth.png | Bin 0 -> 38429 bytes .../images/social/how-to/publish/repo.png | Bin 0 -> 40991 bytes .../how-to/static-analysis/behavior.png | Bin 0 -> 42416 bytes .../images/social/plugins/builder/app.png | Bin 37264 -> 0 bytes .../images/social/plugins/builder/binary.png | Bin 0 -> 34027 bytes .../tutorials/environment/basic-usage.png | Bin 0 -> 38785 bytes 1.9/blog/2022/10/08/hatch-v160/index.html | 2 +- 1.9/blog/2023/12/11/hatch-v180/index.html | 2 +- 1.9/blog/2023/12/18/hatch-v190/index.html | 2 +- 1.9/blog/archive/2022/index.html | 2 +- 1.9/blog/archive/2023/index.html | 2 +- 1.9/blog/category/release/index.html | 2 +- 1.9/blog/index.html | 2 +- 1.9/build/index.html | 2 +- 1.9/cli/about/index.html | 6 +- 1.9/cli/reference/index.html | 10 +- 1.9/community/contributing/index.html | 6 +- 1.9/community/highlights/index.html | 4 +- 1.9/community/users/index.html | 2 +- 1.9/config/build/index.html | 4 +- 1.9/config/context/index.html | 2 +- 1.9/config/dependency/index.html | 4 +- 1.9/config/environment/advanced/index.html | 4 +- 1.9/config/environment/overview/index.html | 4 +- 1.9/config/hatch/index.html | 4 +- 1.9/config/metadata/index.html | 6 +- 1.9/config/project-templates/index.html | 2 +- 1.9/config/static-analysis/index.html | 22 +- 1.9/environment/index.html | 4 +- 1.9/history/hatch/index.html | 4 +- 1.9/history/hatchling/index.html | 4 +- 1.9/how-to/config/dynamic-metadata/index.html | 30 + .../environment/package-indices/index.html | 6 +- 1.9/how-to/meta/report-issues/index.html | 13 + 1.9/how-to/plugins/testing-builds/index.html | 6 +- 1.9/how-to/publish/auth/index.html | 10 + 1.9/how-to/publish/repo/index.html | 13 + .../static-analysis/behavior/index.html | 38 + 1.9/index.html | 4 +- 1.9/install/index.html | 23 +- 1.9/intro/index.html | 2 +- 1.9/meta/authors/index.html | 2 +- 1.9/meta/faq/index.html | 6 +- 1.9/next-steps/index.html | 2 +- 1.9/objects.inv | Bin 1350 -> 1415 bytes 1.9/plugins/about/index.html | 4 +- 1.9/plugins/build-hook/custom/index.html | 4 +- 1.9/plugins/build-hook/reference/index.html | 107 +- 1.9/plugins/build-hook/version/index.html | 4 +- 1.9/plugins/builder/app/index.html | 27 +- 1.9/plugins/builder/binary/index.html | 12 + 1.9/plugins/builder/custom/index.html | 6 +- 1.9/plugins/builder/reference/index.html | 527 +++--- 1.9/plugins/builder/sdist/index.html | 6 +- 1.9/plugins/builder/wheel/index.html | 6 +- .../environment-collector/custom/index.html | 4 +- .../environment-collector/default/index.html | 4 +- .../reference/index.html | 4 +- 1.9/plugins/environment/reference/index.html | 1453 +++++++++-------- 1.9/plugins/environment/virtual/index.html | 4 +- 1.9/plugins/metadata-hook/custom/index.html | 12 +- .../metadata-hook/reference/index.html | 4 +- .../publisher/package-index/index.html | 14 +- 1.9/plugins/publisher/reference/index.html | 4 +- 1.9/plugins/utilities/index.html | 6 +- .../version-scheme/reference/index.html | 4 +- .../version-scheme/standard/index.html | 4 +- 1.9/plugins/version-source/code/index.html | 4 +- 1.9/plugins/version-source/env/index.html | 4 +- .../version-source/reference/index.html | 4 +- 1.9/plugins/version-source/regex/index.html | 4 +- 1.9/publish/index.html | 13 +- 1.9/search/search_index.json | 2 +- 1.9/sitemap.xml | 32 +- 1.9/sitemap.xml.gz | Bin 687 -> 755 bytes .../environment/basic-usage/index.html | 73 + 1.9/version/index.html | 2 +- 1.9/why/index.html | 2 +- latest/404.html | 2 +- .../images/social/community/highlights.png | Bin 33969 -> 41461 bytes .../social/how-to/config/dynamic-metadata.png | Bin 0 -> 39409 bytes .../social/how-to/meta/report-issues.png | Bin 0 -> 37808 bytes .../images/social/how-to/publish/auth.png | Bin 0 -> 38429 bytes .../images/social/how-to/publish/repo.png | Bin 0 -> 40991 bytes .../how-to/static-analysis/behavior.png | Bin 0 -> 42416 bytes .../images/social/plugins/builder/app.png | Bin 37264 -> 0 bytes .../images/social/plugins/builder/binary.png | Bin 0 -> 34027 bytes .../tutorials/environment/basic-usage.png | Bin 0 -> 38785 bytes latest/blog/2022/10/08/hatch-v160/index.html | 2 +- latest/blog/2023/12/11/hatch-v180/index.html | 2 +- latest/blog/2023/12/18/hatch-v190/index.html | 2 +- latest/blog/archive/2022/index.html | 2 +- latest/blog/archive/2023/index.html | 2 +- latest/blog/category/release/index.html | 2 +- latest/blog/index.html | 2 +- latest/build/index.html | 2 +- latest/cli/about/index.html | 6 +- latest/cli/reference/index.html | 10 +- latest/community/contributing/index.html | 6 +- latest/community/highlights/index.html | 4 +- latest/community/users/index.html | 2 +- latest/config/build/index.html | 4 +- latest/config/context/index.html | 2 +- latest/config/dependency/index.html | 4 +- latest/config/environment/advanced/index.html | 4 +- latest/config/environment/overview/index.html | 4 +- latest/config/hatch/index.html | 4 +- latest/config/metadata/index.html | 6 +- latest/config/project-templates/index.html | 2 +- latest/config/static-analysis/index.html | 22 +- latest/environment/index.html | 4 +- latest/history/hatch/index.html | 4 +- latest/history/hatchling/index.html | 4 +- .../how-to/config/dynamic-metadata/index.html | 30 + .../environment/package-indices/index.html | 6 +- latest/how-to/meta/report-issues/index.html | 13 + .../how-to/plugins/testing-builds/index.html | 6 +- latest/how-to/publish/auth/index.html | 10 + latest/how-to/publish/repo/index.html | 13 + .../static-analysis/behavior/index.html | 38 + latest/index.html | 4 +- latest/install/index.html | 23 +- latest/intro/index.html | 2 +- latest/meta/authors/index.html | 2 +- latest/meta/faq/index.html | 6 +- latest/next-steps/index.html | 2 +- latest/objects.inv | Bin 1350 -> 1415 bytes latest/plugins/about/index.html | 4 +- latest/plugins/build-hook/custom/index.html | 4 +- .../plugins/build-hook/reference/index.html | 107 +- latest/plugins/build-hook/version/index.html | 4 +- latest/plugins/builder/app/index.html | 27 +- latest/plugins/builder/binary/index.html | 12 + latest/plugins/builder/custom/index.html | 6 +- latest/plugins/builder/reference/index.html | 527 +++--- latest/plugins/builder/sdist/index.html | 6 +- latest/plugins/builder/wheel/index.html | 6 +- .../environment-collector/custom/index.html | 4 +- .../environment-collector/default/index.html | 4 +- .../reference/index.html | 4 +- .../plugins/environment/reference/index.html | 1453 +++++++++-------- latest/plugins/environment/virtual/index.html | 4 +- .../plugins/metadata-hook/custom/index.html | 12 +- .../metadata-hook/reference/index.html | 4 +- .../publisher/package-index/index.html | 14 +- latest/plugins/publisher/reference/index.html | 4 +- latest/plugins/utilities/index.html | 6 +- .../version-scheme/reference/index.html | 4 +- .../version-scheme/standard/index.html | 4 +- latest/plugins/version-source/code/index.html | 4 +- latest/plugins/version-source/env/index.html | 4 +- .../version-source/reference/index.html | 4 +- .../plugins/version-source/regex/index.html | 4 +- latest/publish/index.html | 13 +- latest/search/search_index.json | 2 +- latest/sitemap.xml | 32 +- latest/sitemap.xml.gz | Bin 687 -> 755 bytes .../environment/basic-usage/index.html | 73 + latest/version/index.html | 2 +- latest/why/index.html | 2 +- 164 files changed, 3030 insertions(+), 2220 deletions(-) create mode 100644 1.9/assets/images/social/how-to/config/dynamic-metadata.png create mode 100644 1.9/assets/images/social/how-to/meta/report-issues.png create mode 100644 1.9/assets/images/social/how-to/publish/auth.png create mode 100644 1.9/assets/images/social/how-to/publish/repo.png create mode 100644 1.9/assets/images/social/how-to/static-analysis/behavior.png delete mode 100644 1.9/assets/images/social/plugins/builder/app.png create mode 100644 1.9/assets/images/social/plugins/builder/binary.png create mode 100644 1.9/assets/images/social/tutorials/environment/basic-usage.png create mode 100644 1.9/how-to/config/dynamic-metadata/index.html create mode 100644 1.9/how-to/meta/report-issues/index.html create mode 100644 1.9/how-to/publish/auth/index.html create mode 100644 1.9/how-to/publish/repo/index.html create mode 100644 1.9/how-to/static-analysis/behavior/index.html create mode 100644 1.9/plugins/builder/binary/index.html create mode 100644 1.9/tutorials/environment/basic-usage/index.html create mode 100644 latest/assets/images/social/how-to/config/dynamic-metadata.png create mode 100644 latest/assets/images/social/how-to/meta/report-issues.png create mode 100644 latest/assets/images/social/how-to/publish/auth.png create mode 100644 latest/assets/images/social/how-to/publish/repo.png create mode 100644 latest/assets/images/social/how-to/static-analysis/behavior.png delete mode 100644 latest/assets/images/social/plugins/builder/app.png create mode 100644 latest/assets/images/social/plugins/builder/binary.png create mode 100644 latest/assets/images/social/tutorials/environment/basic-usage.png create mode 100644 latest/how-to/config/dynamic-metadata/index.html create mode 100644 latest/how-to/meta/report-issues/index.html create mode 100644 latest/how-to/publish/auth/index.html create mode 100644 latest/how-to/publish/repo/index.html create mode 100644 latest/how-to/static-analysis/behavior/index.html create mode 100644 latest/plugins/builder/binary/index.html create mode 100644 latest/tutorials/environment/basic-usage/index.html diff --git a/1.9/404.html b/1.9/404.html index 1f63cdd52..7d42c48de 100644 --- a/1.9/404.html +++ b/1.9/404.html @@ -1 +1 @@ - Hatch

404 - Not found

\ No newline at end of file + Hatch

404 - Not found

\ No newline at end of file diff --git a/1.9/assets/images/social/community/highlights.png b/1.9/assets/images/social/community/highlights.png index 9e70dacdcb2a98374d1b527d9ebc2f14fb86c1db..48ad26a6d8e31668c3a4aa8845dc9f2115fce517 100644 GIT binary patch literal 41461 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 A&;S4c literal 33969 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 U%q_kwqhCK&Wvxe*icjDCKZ|Vi^Z)<= literal 0 HcmV?d00001 diff --git a/1.9/assets/images/social/how-to/meta/report-issues.png b/1.9/assets/images/social/how-to/meta/report-issues.png new file mode 100644 index 0000000000000000000000000000000000000000..7f2ada32e06f404c529c073b3c3b5f042b2341fa GIT binary patch literal 37808 zcmeFZcUM!}_dRSw6a_34rCv2i2L%D?DguVyLJ3Wz69K8AqavUpAdw=yw}cRS3suAj zNKc5AfPl1w4xyLlaP@w^Z{Yd!mob1d7?88}I(x4&=UjQGqoqnu$3}PJ#0h%vlgD}| zPMj$@apIKsxwF7;v>*7JojCCc4u1U5z$aya zx+8H)=+D(>wv#M>t~4S~T=;X9r}F>a?*IAj-@Wkv`$pM|SvnD*I-YjfZ>O}hGD_I8 z+_GA+X8#=Z+`sqRzkccI!BQOV8&bRHEfmM)XBQb{{;|)7wCBp1)jo9v#_501fZqKT z5gWg7^WXo-oAs83Kx2_>2%)$*8)W@GbrJg*A!MvF1c?-iZwfBqh&o|XbXX?+XnG|& zzKtvYWyTqru!>Kl%kDYcXEnl3bgJ@vr6IQ(@e*a?%TPK-V`aboTC-yR+Z!U_dc-zu zk1+xt8Z!TO{?uvWYwY~3jhA1h7*ljoo{4GDw8aW6j5pmD_s#PA0r`xK7y1V-xd%Hiv41(DkxW%F2oYQaaexi?>V>N=O0CXNLA#M zwT=?#h=4_nEP6+>NvK(W`_T9KuJt|l-%ofzAbiS}kDNrhJXiFn3%rX+8~l5A7SJ`Y@e zhlaU8q09%mbLV>B@un4A7q@d5u5f(+{yn1YS>et{P(+)aV7<(*<{hQz@bGZh*SDA1 z6as3Bu}d<(a$L@&I>>nNQA6X=p+DLjYdCF7qej}y)vG?x?pqCs?cK3y14R`QZbvEn zjaC^JJfYawI;yj6?m_8ZKu?;ygvX4Axz9xC`>3e+wr4Q}C|qs4<>6o^1ARH$UZZ_a z8hNY%>ryv=+t$WrZoNm5h+S?(;qeC33+CA=4KOCQm>jJJ5rgO0QpCBkD3vqDs!y86 zVr1+zUWaW&8)_K5eDsJzK+r=#9%TTN{5^+F*Nclc(aRq*?a?-vjiN4p>qUEfo(Z_C zi7DPhcEz-o4*%l#+WzjIA<*1VrIZ%ZFlU(r1*b-Ev#0*&S-@&nphk_foJ zH&e-L#JPGt=aUwq%MRxGbs+OrDFZ_egX*(qSuQmbXU#pjBz708$2XR+%VeTuFhuvz z#o284?U(GjLVZjGbLyQe;9U&Y@*!h^HdSu>Upe}J0kC9rvy7|pF z#%B5b_Ofj%dzWjwKM$H1S>V-Qovec5lwNbvo%b#WwXYDVUML4}y04K>r`Og`P#?4RjMrv4D`nafWP(tGIgeo*uf z`|OG;3YS5d=DtRnBz}u&DLZiHlazVTBY&@MY=x|2h*C~SA(<1+`mxHzfdu6S&w;o= z${VBbGUJ?qe4hESWZKT;`PK%k>RddG7Egy^AY{X8TpFsH`b172dwy64qWr3=Xggn0 zIM^(gXNQiFk$5XwF00mKmRvIxg@SDM>L43whS*Ju8cM4^kV)8Ti$E$QaA!Ip>5kQF z5WlR)JHvf`cH&VZTZ9~(!p)EgzX+%e!_u$XNXccNo0?Ut20L2bDMlDY+Uld$lNP#VUyf$8X0OB z?j%qlQ=<`xW8Z7Mar*4VUQ^eG+}ZSCi@SI4B9Q`ws!EIl=?m7tBxV`Hen&L#lH_Eg z=~)W!RsF;?bvWDs-}@7aQ&UT=nD8W zhMk9HApRR7I#+QZypyY?cOsX+n>pH=B|@2KKAf)=JR{oGpUe#s6h|2>UJdcu*^!qB zG6+D6v8MECD()i&e_M~lreKKUBgo&JG<0+&u#FO9(w%b5DTeEd5`M-hdINCDA+F

^+i|Y~+c?31dmOBUFS>X^%yzya>FNv3 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

    i!jc?~!&jwjzN1YQfd}jz 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 literal 0 HcmV?d00001 diff --git a/1.9/assets/images/social/how-to/publish/auth.png b/1.9/assets/images/social/how-to/publish/auth.png new file mode 100644 index 0000000000000000000000000000000000000000..fe37a49598bf809681b953f9fc81278f59447b7c GIT binary patch literal 38429 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

    `XO!2OwbLN@`S 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 Aq5uE@ literal 0 HcmV?d00001 diff --git a/1.9/assets/images/social/how-to/static-analysis/behavior.png b/1.9/assets/images/social/how-to/static-analysis/behavior.png new file mode 100644 index 0000000000000000000000000000000000000000..9e5ca8aa30aadb503c49ae4a9e0b0c07b2da962a GIT binary patch literal 42416 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

    Zik*MgMqUWEv-v9N|-{kO1g`rggUuxJOD>++ zt6QOk2rjT0WPkkD7ghj^N=_5tW7Ed{3I%i`^XDt1S)<3wiPq+p1yP_$x5iBGg(h&D znQ$ABaU4mcTZz774An$p4L%$z!)ZDlbVeH*Z7i~AlzuH6qA5{#h&?ja&uXCGj0VX! zsau^A%RjzO2~1f6jnIhzTOEU_f~{|wLmXqhJU8F{B`beua&g;ciVOL#x8k@W^=DEe z+W9&oI#%oo>-{w(0u?|!qA00BnhQ!fu0E?@=*v8gd=&lYFRx@4m6$}gnH7|nJnh!C zHz9M6qLnxy+jZ*0Z?8(U+m%C*>rl?I+G9M@kZrg-* zdD`%VkSz`0frxzh+>FZ0>;F7ZFoH7YyWxC7*jWM3w7SbDgHvZuWI0PlQO+$Vs^q5v zvCqY`0CAFjE||ymqz84sL$Y{cMCch1MGRM^6@WtoI19Z?{crwP8*6fTbw#$nFhu#u zyoS&4M2dMkIR>7m&MB?c8rSMCGl#{Cb7ot&)L(|`>WcmL+xiXWEpJhQ2xi(HW&>Ip z0BVb;1edR?#da+8|A?pnl98lhd7Dh7njuU^Ft|=jRvgWXUI*y=t#{1AGiQMNZf~$( z7;PcOUBNMnRinw65pjF{wqRn6v3jcMhUU4D>?mjBS~3tK)>RJgU6#XJ~8Ff z-Fv~R%Qw|vuOM;0q;xUA{pnJl-GufD*rch=VkL;Qjnc-)68s0ll_lC1Sx^_bkL7d? zQvjlLXn&}ueWeubqf(hfY@~|E+SHKoL-!;T1xJCdoA9WPeiA^tk>idMXfZa1b?%Xi zq*A>OSi!)tJX%LnKXYpw9DyqwJuz%s(b!KHftGm~C)y)O9Aa*>9Dt$-X6ZFGLkl#n zVW%53D7#;wL&P?@8VX}(~EAC@twGYJMT6>Q=hq9Pb8C=CxeMj)U-`*tvqoeyxkvGP@G$wYVjCS#_h zBUVE*6%ZnQaQ0qbbiHxoPc|y#9yDgDy=PioGh)V|&?e<+ z#P_Aiqq-5KOi5`BwVgN)H-p;;n&n z>s~Lao-MU@ArDLQiMFaQB|T8U`IV@w@R+tQxV><(*1$ZHaT(A*?Flr_dd<$J=QrzjgBWo=QwVEjKtIKhK*@m5rYin5XrEzH<`W%4 zKKcx@-p{yNjX$0PK~|_;@dx1g;h*2n+8g3CX1$YA);kwYsb+wZ3R-@tmMW~hwBppP z1>urRj7A!*P6{ZcpT`e&%iJ<3b;xGKOy^I$zXvD-*9Hf=HT?YQ{f@U4PqQshb=BZ& zQ{ewXlt)UBZZoulYfX@)*05@E+!*F*-RxfDj(|b6b8J%m#%(HUqF7CMNjQ6cGRy($ zrDX~{>4cOBfQYu& zWvgiQ>E2)4=^zMU3Ld%Xv!xG^kZY+&j*+7ip6~Pku&nysy*|X49O8Mvq~EY6Ztk&Y z$%Bhl=2VQn_WB+iZ#`#T0VC{%gkByVs7TDWJi!N)_t$YIJ4mjZ z7weG{5GsA%d;ijP_ahRko*C*s7EI{MIzt&`rQR-{=r?hJWI1I+b^d&=qRL0MD!&3> zyRLA{L$3vK=xCypxzYeBF~;t9Ce!p0n-0*?lUZ_8l(m&d`(W;p`KNWwC3l#4oJ-PU zd8p6u{U1Fr^$FkV*>vVF575QZdyD?DRx{Pc@xp1zf?#;svj7w&H=wmC8`p;FX%!?M z(c84t+p)HHMPibZv(yu^=EA`yZ<;?xG`)@hG@EM`V?SqSUnjzc^<97r@DL9PR1CM; z-+sRKU(SsBUA7Hp{k>b3r4pA$4?fngO!6u}?PK|oh%1i%M+s`u8*X9DgT@u6Znc1V z1pQ^f1!5{NmQtl1-0?bB`u(btNd)lSJj8$*Q=2&kS6`?RPYxos-v;kl$%hvRQ9e9<;YM zy!_B6gSAsT{P&hr$FRdR2B*6|RDb|f9Q^SQUe#LkB<1sHXSI%u5MEe8kI=;W8aEPt z#1=PIcgpX0(^miZlTMv}|L(cdbnxeXL~@-bQWQaSqoSf(+3f)jNiKa)*DtZKK0es? zUdxw&A1=hMm`)$86-!<>K-2WxVpv<3GpLp-`i)Vc{20 zC2G$4fhI?8pSiK z3PDm5UMIe>`j z4vyu3O2^h6Q8Jq6+LM%i`rO%}$v3Fev?yPHWbKHm04htPGpNSUmQ%Aau4c?6x zPYYjn_X)ro> zi@MCe09FNj1qKH4JbrxqqV12W#AHTksc0Q>6-`6CGfU%SBs z9l3Gh;o)k!dcAJ+K*sX;l(m!3HmnCVe}sL3%nDye1KJN(>oJGt0DprmQ0<$jat;3g z+eGPCI8FnEcrmiE7#7`Xb4k>f&58YgR%@65TKb=^bGNs&EVb^$-$5^0LcC``aYrR3 z6-bbe@}HeW41w>WRJ&h!c$b%NbRj`9NAq>6-GaZP21(R=i{O*=A5|W0x0wx>%KJ^H zbo#QxA;{*-s|BuKl(nED<^iVsQ(5^(E}RhjTy8sxH#!Ek3doAZ-Tcb%o0EoIk*9iP z&cLG^%#y$65UJ+>QS?+ayGTyRX@KfTRH6>+7HdZBh5?;ZZk6lO>X3TuTF^jCuBB1s zv9AHs^-jYgIi#qsRhru4SJg8c$pBGQl_yS>L_Ct}=+N~=z4xC60NVtg0uvipg)TU~ zjifWiYEaK<%%K>j_4;)hXvq49AY^-cdv&U=CbbV%Ms@DoeL+FBxVSi8!QX(&q5FRY zEWlp_H4X%+5XL-orxL|#GIYF-!(r5A51)%zcK7eHcgBL`KLqoM-+TV>u5OdUIUd1# zdJkuQhFqZ4P8&G7p_62M#HA8ml9FIa=k)8m z@mdxZS-eX0H>Vhz|0PL#o1$;5M-1p2t4Y`l-iL&R|3H~4-Mn=xH&Z#*>S%vMNli_5 zrwnmKCoo=Y424D`Grn!zk?|ec?n-J*!}GX2N(}k*WpHZ-67SkPB!&AfS-n)iBIe>b z*ELI6R~-=P!4?o?4=}gYvb$xLjHsxBSJ)jNb6fhwJi~ZG4*hGC3fhGOsgBm#BZFG` zv)A1%(~r^2bbMC}+!Hra6l2 z0JJ#iGGliFv|wAX~Nf&r{OE+FE+qT7}gRDr~G4o_&@wz-xa#M%&40);LadOV=z6qI4|?6URa<(nSQ?Rsa_tqLC8@%2k{?c331uq-)lko z1DBGyfTUwvQ2iv<)cZ?4i3}qV&|aq+iK*iy#o`m)Bc>}ia}?RU^Z=Q5>M@DLNfLTe z{pbDe4F-nPHOER#E=a(&h8s+aOT(W7Sllh!?8MhTTvy8}QTMo|kF_|b`|9UYxt6!i z|Iug8=A5^X8D}WZi(W{d;Ni?WDd|{{5^hXtGefFaNUp1f`x?}wS5ptR&IE{otbar- zh$ld~lRdu|m$;UBwlR-x(9yC#RH~SAiByw4G>hw6JYSb%)A?6hx|do|y=ueCo1@|I z^wYDmzRY>B=^&XZKxUrxOioV5p?7oBU5uj;#j6a3>Vp#03l&@BI{p_}?I8fejv($u z3_d8evD1HZS9fFFrUCtql6uuiElC&G+Pi$FD2&a2t-cYNaY^VAskOMF;WcRigIivJ zO>3H%)T=$3d0w}-!v~yu@5faK6~o!`)xo6afT%Qc%CJyTn_98$wL^8HFQm#?GLTbh z?(@JZKLOP0Vwv#m+cyp{EXw@)%QB9CyUf)OfT5R=;#G=VAbY|c&=>P31UU0Fea;PY z#u}vsUSe8pqz7v~{~GT7>%*YFgh+)R73Tsnqsr9+f(!{!5! zFo-e5aw!^$W&59yiR&fmZcWj!m2t5eLnH9x$6DH1D%N|lw}$$~@7}$u$j0qs9x+2| zMErNpUY(BIRG};v*2XIw)89qS`|-Tm*g`Fq!%V#7rQO$iTS7fn$F5WJR_gLhcauhu z8749{wob48qobl$qXsbjU*=_q#5Ihl_nuWn06J^+;G+_f-snZ33kqWl z&Fn*z!9SV{$KAMcB?XDR1{Cg>aV(qvo?j`K&^+v=hX*-^6%I&db}wi;**+|qd6*7k z^DOn`cnKUYY#t(O5TDhNO^6zL9Ru3v;{6Ir^zC=%<>MQfC@B~s(vAZJ;Yr_eUpnn{ za@JW6e}8{G@Qs=tRJs+o<=RJ%9nG6hpFSNr6O%}RmWh)-`in{^-Y)U-?SLT8McV+X zp>=TN>9ny)B(AkIH?Kyj%l6GooJCaJRiq1+bFVSB4n`|4ajD+ScNMCY=Y!b~0;o0v znA3sSV9DC~`qKk%M9WoQzDxnNnLyqSCH?1q4eQZO$c(M6EyfZ10&ZPp1iuiDyVHN+UX^~qN+#2D_ajU|pn8OW@*T9jD#A)$Z}=_C^n zpr`h2Nb$a0{aBb+{`M^e5~ zuk82sW1a!3c&O##&#{h#ORf!#jrcxAcI%E90jZ<)lF9fpg+*_C-rP4gW2u=Gga{{G zEF8Q3FYYk@HlTkO0!(L#)Y_A_P`SNXxlX)1JdgltdI#ZSVHY-IvE$e0bX!tB{Cm}W zVm?CquCj6m%cb!6OZJ~XsIp#Fftwu+ed9P26Zi1h|J`Kgp5g9R{GH75_^Z13Sg7Mj zp}R1m=hZwQmb_ z>cjYQO(QWSB~-$)VIDcCBJk*ccOq~22}JAZ)1MLMn?bO$fP}FQ8;oUXm5<`*_MNOP zJ|Q7>qN@WTD-GVI9lgpn&D%TxQ) zE1x`5eSI&WNzf(Hxq)bW^soA>H*nN$=!`Bfvz8hG3(NJd0o1HvQ8$?{mQ3_%rdKjY zCMF{0E!n4?D)y;+9{kfzek<770@gwTFmCEkd6t4nmGs$;$Rs`cTNYm9IeA22Y6}Fh zD1rK&>0`rD3%oh^&zP(6H=s)o;^E^{1`1Ne7zv3TlphYARnI)Gt}Ro|_%HvGa%uO{$C##7KFC-#+%|Lux-rhoVn1Z$x!}O_%2xR@i?put8oar> z#(e_`0vI2AXMZc!|E1^1wzNNms}$w~S*nUL6{7K|D&)__v-!l11jFHp9pX~|4fSW- z9;M|c(UT4^pa}@#dE}eYa`evUzgswaRt`m(N6R99lb0$lzvvH2Ec1iv29~2CZ=e5R zUXcgR1gfL+0{Oo2{LL}O=KprtL={Yr1m)`$Jp+=B*6vJnO*+P4tX{z|_Nsf}16x2y zi$wW+JtT`?2aVDH=j}$Go%bPJ42+C68)IdvK^kIU7M{CycKXUsV`|ci4XX325X{Cc zt=^m8M^=Z>oDhKHGn`;D2>)j&@U37sz+~Q?sRKc<$2*}Ji$119BRU_4ba-C90oPnN zD6`Pf)jrxY11k*MssPiD2m65GyZ;sbR|XK(AnTSdtYekVZ%W=pa&rPULX&&& z;R6%J#0s&j{KmYP$`X^V`xUK~+r?vN4JWw&x9;>OP6re~yEO`g*y~e78VK&9{SB4x z>S_aqrqWl45p!o#ot(PCVg7ORoJm+)N5`q&loL`UV#ubkPt{<}evhjTInvlARaA_AD(5-CN1#Y-0v}COb zv1EjHuP*HqN2?a3aAT(9+n;-*x5nsFIE!S$N0Ra#*MLKOkVKfq{Q2{Tl(?n$|OQMH9H$Hz*XEDTE~|AqVq&ZpU?%bB)N4rvW+e%e|-X#On?YJ}6B8 z8Ds=zUzpeuQhuFz#p?Q+f+Bo-jPAz;08h>OB!d7|W7&v~iHTqvsZS+o?CHmFk`1=>8BzCycvJ?)#7 zKNXc8!woC#w^%@!tjrKi7acPiooJW}DC(6|`T7g$0>_fRW4_mhbk|>^s4hecG3O*r z222=?jI^ZrIIs&QP!hjJQ)M0P5!~;eFq9Aj_|ojhGAoh7inMxYp48 z9^`@bP*Bes4$@cXpyuP{-J9~kDWf(K3v*1H!|qlr=k)CF0Lv4}{$)E{>Y%jFKDJ&B zh|I+k^Z~mxJwJpAeZS!`zb}(3Z&1JZ)$c&ecqNW=!)uJlUYe+}qPPSIb((oth!yK8^0Q z$OyNl9T60$3&qXrdL-WeRBM z>ld(jFW;@(?Uq(_5E=5J9M{p)IawOs|7o-0;dnC|dQv~~$Zh#6dAE%lnZZWtL7F~M zi5yQy^ip1boP$-6dz0FYQu#D;fK7ZNb@U=a4;*N&@D5@xzw} z+-Bks((|4a)mccb8pUyjSkH1+iWCyyvngV)eL6K%8k~_CHMlB8!*V<8D^J9jG=`3+ z`gg`EMovZ}r&**;T-TVZx+2HHN9!W?zY9%}qE7Sq071zzNj=8I`N07gX{sg{Kdt`r zxqd@@79|PXZ(uexC*$2K?^PidsP5+SLFAJJ&yAHf=En~@H}L)@QK{S}W4#Vb0qKhE z_0L8()b#V4WfOiENn;Ue7btpdfOxgaf5+jdsX3(<9c{LNllkl=46GH+uJPzFRmCP^vx-tXY?O*1vC|%B`=@ z?M*b!FL*dD1GJd8sW{5E-!m%fJ*9<5>u18-)m_qhT&C4-ZOXsRF2tmZVFG4 z(~Ijm9Xz3B^QZvEoQ5%`Xh8V=jDdkcHAq(=no%6?vw>edS#QG$2-pfn*?f)|4+#y0 zpOEP93rWC$q)3~1P{_}SRj80}x%0#3XBZ5$`fIM*W8YfztLOt2!i0G3fZ~TUTY^9u zuHKD^J{^fz_cmXkli6=LFJS7L6VQE`;t$X1G6I(!BE_5r?U5=5wVn~DI_8C?B?%T? zv3*zN>2aV;z-j6ub@cRdfDvr}HxoS!lDlQY zxVpYy!>EqC;HPog(nmTJo)Lq4uZ>+>UMGr*JZ(`8(LRyAOG8(hTicMj*Lf}9z(enZ zBnz!N+(g9FQ!M+Q`oX2`I<=@qlY*!&N2|k~1u6Vs74c61VW`BiMGf~iyi(-n{^*$aD_R~D@4+l z+OZPLa5le#SFDdcH7r8Ik1zeGW5X^qo(zuFkEpwCT0{5jNucVf1b%) z=d*K>DH+X>l?i|!mwKMgS1Gpa?v^YQJI=54EsglN75uFR-YB~fa(D3I{V@#TeB9iI zK&@TXEkiJp!4GQFT)u1KADD3ZDGjAILnsBg?5u{oW(QkT zUhlx2j!1LWKz-n3Cm!$iz!#!nHY@#^NR(n$SkiXd`)6K&67xdg>Mb#TExGHBw2p)( zk6iDg#(7=#lk7n1y-n_#%Z?rs8IJ-3J#}~fD$O71#tr5Z+JG&a%QuHbg7OV3)Rw-x zegOnwQUZqMc}+js6J-I~NxRH{^P|=?2rvZ*1XIzesEPzsdr%1Elb!5c=EsX_w72|| z^U9x8uuHn}d%qkKA$(v9su-=ozQEMg<#%<@0Q1noFhg7U|PeV%T~|6%Vv+nP+f zwqeUCj)IJXB7(puN-s*45>OG4j?z0wFCp}jP*fCDno}!TDhA|70H||El{-!e zM@}!82^IM?#yr1c6CVBOrM|lRN6is#maQNnIDK0`mLjrCSnKRC?bU#k!p*UPZ_dV) zzOZx=TAmftxWb?S-i6 z3i=FbO10PC8lT^w$xK|gzz=hGh$d%$Kl>woLP3K9rz?b^t-#ba@4asYFHfbKX(e?F z+~gN57zW}LYCXI|(YQlwBgBwSbSjv;*E+P7n8Y)UB+kLMTrnZd*s1vq3Ow9#Z~N(8 z272AcfnPJZDDzvegh|)u#>wXA-X^GNiWqpRy-Gw&XPYBZw`?%+rGIfov0W>kRlTyB z@K^SMQOLOi(}g9MXZi`cwCS^c;gK1@xy5}#Ex25+nyg%EX>ohkFPD=vwZjBAPCJ`Bf2O=woB>4?*h(IB;hrT;1OQ(S&EfJJO~;tzPQCdUZlp(9to< z?^VnJ&O1{`cDK^Ww8V2aIxT-qliO+H*M%s~YsIwl7!-PV>yiBK&i%s7;r!TPemmO) zeu*X{Fq!Y%*Y0|axoU$j|2}J{uF9m3RZQ-=jfygufY9-YVbsxisVOgSuWuluZ)BFE zIBBOgX_#FsOQ?LYaqHSOL!X0y_9ur831}BjH(TPvb;G45MVb#W^f)!(Na~jC2C@|v-bxhp~)*A6b zL*4eO_u){|n;LV0r|szLGbe&du;!ME@4G;?BRcga`p>M)F;IGd5oNoo6g@q&Aj|5_ zUd$Ts*A2MIL=>Zc8mO6A#pdp^%a`hbMtH$L4yiO%4Uk0{#z6KzgLYI#oR*Agg?-<1 zD=VU7P9of{%ID+4rYLG8KZ;Gt`TOg0M~6#DP;649+GxZL-$pR~{`l3c&6eg&uPat# zoT*KND+0}N7)0c2wpNz#KIqJq?jQ~R+2P}I zUye|gJZ~c=0RE2lPMsa+KTUzz^h)=D#AfncK%Bi=NpkWlpow#I7yY4$WGU>t(2{Fd z`Pr7dv9rp-`E{t3%O?!37Q3Hw&4n6EA0z>5*}WvQ6y>b*wfH+A&=uA3>x zXoeL0ebZJK+}%HMfNc_3R8sHwbw8VVg);CQ=poS8L@RhYX7{H}nZ|Xr0RoIfeKZ=a z)ZEOh6h`Lvc=%Z>IpH5Lxs|YXd96uXx6;QU9pT3e`%=aUZ&R=9Kq&85->16F{{6>?{q;+L4Z|Yvd1r>bQ z)%CU-z{tcm>*VC*9Bnpi?E(FrE_=ezd{-Rcn%{|Hl~4m6mV_8>;##q6P^t6DbmAie z;Q1wCGew~D<2?K0ZFgTE#4~mBcUEnBhd{Jh_t1#s zj*K4iYsp?okgCbg9G)F&w$gBX7b7f}h3-!oQEzTeZ*lvq!3_o$2Dh^>fZ>;iO_XO~ zkWm6R_w37zqg9Izj?{3a@BDYoGLycP`_dM)G7fY120)Uguz~YtK`I0<#BR|axWEOg zb955)8>TPHK8t&)HPR-|2U@03Ehh+v)Ns#Gy0DdDuOp}72_uP53v7QgEud&pD>Umu zUS}U<+uHO-j23`k_B(;jXVsNt`s5F~N%6c8$3p62%zYLs;N+Zei>@&Mn24@+Ij4Ft z@0t}TZCBot+Y3TCN&M$;b{x>PJ&-&XPSpLqtdNHvbOB?cYBUWjgkxGk0Y6PaN64&J zC)T!VGCp2h&!!{t`3aRWR%j?fYqfs*^vNxzzJO98+X4u^{1AwFgWuLT(A22}^Nbsl z6)1~NyXQ|2PAT~zb89Us>DLWF zK%oCY9ZKu-j3&CN!W>VXmcIqFd3~nPa=3^&E;t1DS0ALzA$8sFIM12IL0dd&=eVajG&tzKp~*_RIzj^PJzY(IN!t#NN+0(XwtgvD^dZ(4kMk z_2k4^nE?CO)U7rKnJ>CCx#TVS4(+vEP?x#+$9vk?Yi{ITQM^q=EsZ<%MDO45@UN7w z0o5aETE?tH+oir}+8oFlEcI_>eW$c~51bSms5-5M$G`c5yxcDEH*lK!hfk(n++WE~ z{xe19mX=6UnUaEtC(L{Obxtzvd|0JKyXQ^`0Cj|&vQ5(cgzPqf@l&_>*z2A|M;b6w`o0Y(J7jQ3L~rxh@Zsq5x8H>LwJvG22Iui~H|X#8c%mkylbtqp%! zQMjFSYLDrov6G2k(8H3ozg)Us_5R&Db;nzF-(KSZd2|K{K77|qbgjA;r<#Izq0ONF zVK7L$=)PI|FCl<|jA!{pxsgHyPM?~TdD)5_VQ|+?&`LPOnmo8RzVKA9In`~M4 zTceU-;wVJm%k%)pFK+dS{O;gO_Z-06p`+e=Z0|Kiol;-tEI@Ix6e`G7{{AfTryHZZ zWCc){%F{}jY;J82=TTaYT0*VPI$)d$`z5BVG6=X-S_m8|859*oPZ}eHu%ZcyXdb!8h5YhzPlGy*h0G z*$xNUqljJz!T}MHH9HRLdIl5#9y9cg%lSTupP|^+s4PkO+G0dFffL82H!n-`-GeCPT*HTgMos3znXwzpKb%@b%P{q02+{E(Ag=<@zFa1QhlbV zr+*C%fVYW^j&+a-V$#!#@Q_+FC%VY+$TTM)xRxGl<(k!$iS5}__4p9AgK3IEyOBg+ z4gSRmfn$~>8PU#rY8Qr~n9D;IXt&{ckNX>cTa2;9vXr<8b7Z%)G-R3YhZKQVx*Wo$8 z7$?GZLHox?v-K<8Pnvdf9bkgMVFTNUNknU}^^l?-Y*otdmL(I1*-TT-!HE1|r^bkC z=#Oi^VERtUJB<7tH|R?nivzbETMRxHs952=7p#aI*IXSNR%3H~W%#~ER2;tH6?J=k zdyf02@uIh0LFK{AZZ%OogD)8$c5hA!M9_}D;KOTt^Y!jo$9lnO+j78y`8dYRTPXC@ z!1SYQbH*;?D)-5^11@|}V5`h8i_D5ER+RR*bdHAoN*G}TNB-d5Ki0y6&FxlC>G6HT zy)>+Yz)& zEvsK>w!_A)9=bZKaB-#@pZMWf%qih*n){!re5%Q!RJWeAGnxQbWGE zv%LnmFnq5h8ob*t9-bmOx!2bsww|Y&!)D7h6i+9Py%_GyxMEU`ow)EQqAmNAV&vPr z89jM_K{J7;W1LSJmf4*BWnls7FH3&7?$Aa9KLmMHMoJ|MgoU}ThwQp7S*?VVlL+oh5@gqp$MbBn&Z8my1hSS}Y z02$d)3!=k&`CVAaZNZ-^emJ=zee$n5ChxJWEt7$h~OpXgJ9;q&Rd5j!gMv@WwDN21Gd_^8<12 zH67y~feiC$5bI+^O3j3m0AAy>?Vb!&PD~`O2L4!f)J*+r>F~15OK^@hq{wFgiE2{7 z_JFXLCh1&KC=+Z_BMEyFBg40?9H3VY`5qZgnQWl>k@|S)U zb4NuD&3mLv7%tR7Wto&!*y=gz7h_*>4D4bP1A_$Xsk@K*O6I%`lCH2?S60(Tw%10HLH&D47HdNTejL$d9R9rZJ z4lC~JUJJr*5_hB|)oIOci8%5*!AAiSM9#7eI$lUu#)SN)ma+a?)a#3_^tUsp2vY4f z`Fv&POI=X>1peUO;lAh2WKfmA()fL8(_9`J5)c_P#@LeUx1aByP@{m&(VUuIQ)B@t z51TL{+TFT;2eL;IS%D4{Rvf)3cA=GleHri(3#phTKp{&R*F2#PlrUp1T_O%S@%T%Q zxX`NG5}7;*IRfC_K%6b7^e;<>RnCGr?v8-HjNhX>9;-u;(#e_lONp!kTpG*Fc@vH& z=PL#z9i}hXWF*zZGkO;P;(+;=ocd*?{PHf}gU*9i9ivf+BM$Z`E%5`@2Hfm0lZe~k zYrEvA84I)LIiN0fI!sYa5o-vi`j6aGZ0)AoW6%c`FSdyk0vS?M+tA#Hl{QGf$W~T* zJ2ID#ZEX$oISimcu+;_K`Jhm7`ChJ(V;9fMQ)5P}V?dQL@yoq01>5IN(9N&cSlDL^ zU(Ibuszz|>HQ@5!_Ega7*bSUzQRZ(o<6`@_e~=w@TK)oxe5kVXcvo?UxpA{T%an{X zzPH^y=#QZE*ZHamfCU$t#UWXio*Dm~xbiHG!)ilaVB9H*GMY=i3F0Xu?*8z$uZxu3 z8mP3UEl$FEm>?Wwb%A}igiJo=%*UTuxTe>Q=_mrqnGEXmn8>ajR@c(4l&(AG0pCyI zh!gxV{T*zslb=vZJr(hdsE5*Z*MP_lHcH+bQXa z9jjiZMtb>{Nw&`5isd-O=hbGb$;*$Sp=XcYIR5_3qIr{P?%Dg%H$y{i=Zts;)IRpv zyZ#db>Y((%fGmR&+3Dqt2t)f7Bq#UUvDne_kvbDYT1%H+P|!AzE7UBR>vDYqa=n#Q z*);j=mP@{v4<+qV;KsY~I7Y zf8gLmtJWsV^TbPI^B!d;_1#9&;a3DO?BmFj>bjwA5%Arzz6)zTock^yFNJt6@y2kV zSfvB5!FLxJOltCXk~@7j_y)m^pjAf@;x{8D71qKfPSHFsIC*r@vrf-!*cY;Yo9ozn zs!BDirl$`*$Rq;wM#O7@bc1F#+a98fiL39Eq<|h#Se8@y#=M4};3zp*vAE|c z`%Q)!X$pwYBn9;$GBPJGvwU`W>TGfjt#=1R3DJ)zkBJiyo2yKA>qL7HwhoU>^qvhJ zFI!}VL~LA6q8_01h2$jx4$B!-rovpIim@0DG`0!?wVXJc)fmu;yYW`S*S2!%^!Vr5 zPhs-e+ljm1Z4OPo^TMr8KU~VBOT44NDBt8$vvm;*=ycDw(lTI$Lm2TPH1)`_e)8X$q|n3WN@&Op z$TK}$=CK9DaN;pu5)oJgL?3a11LfSUh1lo&*H*O$ipBJ9gURCi)LqirGlZmcm6FqF~?YVNcpZgr9f3n&N9U$>SvKCqtt3Ux$bn0X=^z%7&9Qk2k`?B>X z(K_j?y^eWH3=5$hyH$^a-YO*=1w0G0fZIfD!o3qfvXNhMM7fRg$2`YTx78^42)4a` z6`>fdKTcHwHDCRKe{AD%S}(_LJbn$`y{}X54uaRLg&kc zuZZ6=NY42%51%Hc7!+NnHn$CWL?f|%8&Yj)LM^4wfq{(clx}&~?@e4MsaPnxf*{KU67DK}nzk}vY&|zp9qsN_m2hyTtYM*`F>(Iz^gHv$?hT<*Hy1fmN z&8WZvYtdwrz+yAdcs)FC&qaUPvqjK7^82YCHW2&AT;5_qDBt^yuUT$%2^j--a4<<> z9g`9@siws@*bJPs2H#+qko1wAM_6-uO^f-!xl@C3Y8UQK7R~#czx}kW7JF=ZaHpCt zf2EC8LU1?>+VqyE!jmR#SR+4)hM9UcHy_{EcNkcKIyNxn`e9PHw!{M)7mw#CX&gbB zP3}sG!duow-g_ve8`$6NPos~R(Ve1l)(@Y2M$gXqXVE~nmAZC?XLz7#d~!74ra0A` zK4WeWir(T3{FF%niG4DV>mJNm+Bbv&y+r^zJ6hrYLc8cpfA*7CGtf#WXJ|)#xEKx$ zv7F!;R&4f;Y{|)R za!EpcV3}dq-7dS514OY`T{zRYpDqy{Qr9M9MH-BqX_7)lE zPFxP&i?^(^>3zrBdh5GLgqVp>@4x@ofK0l)lVa8W)c9GH8l(KH{XHXP6;3!C$YJSD z?meG9uM%5lHXJ7c)zc~|lVWL>XKuCopl-c0W0=6e^&560d(g0 zpUJF`S5FNF)bGn?O8(XyA!OQ3(eDqv1AP)aGPOWJgvF}X$=guER_AjD5qLF&B50tA z7gwakM2g1n%jS00(>2$%XLthw1w(@-@7w?xvSd=)ly+7)n@A63JK}2bjMXvT9{7;f z4E*neVuYeoWsHdeV{YQs2ZItZ>aheS^!?KKgDf;mUf!HUY)_NR1vQ^Jz?itgB`HUC z09*5XM@GYDp3D0eSqfC@F<(5j4ZibY4nu(Gn+BK48HkLKiQ941I{@&~P(@^;Pb1Jd zEuulZ85Y;fHPL_AFldw31;pjbi|?n_ux%L*x77IkVbp*5OVam+@8Z*o!pF`KIljl> zr@w9c(!3nVMG)Q^+9}lPTs^H=etvd-0lyGEi<;V(!Xuqc5^~A^WFW+tY__La9i;rz zZ1yv~U?PO18>vyHbvMof;t$_H-zd*qW_09vJ&I4AT81~;MEdg-7KvJ%w_W+2b*sJ{ zdEH?d5QA8Sm0}ANl+xsc7dr(F0}iiY0kpEwP|#9+cd2mtTk2Jq-Cic(mfPqiNaX;d z25pcJ?|1zWsf#mta9J2UbhY@gV&L8&JC~g#8={Ej%7Dj&1jjk-oji04e!DBjyHSL0 zoZj?>T?g&kZ5_@SHMNG=$fCc&45s4A`P(Tg$!%U!M1Va0+qojY;k_mQ5afCnFA<*s z&=j;%c6Z7;omVC>BS4lt!P01DzjJ+2?T?OV@$tAm;6m?~Tsw8jobhyGb~pc=qKK=( zOs#Js@HaF5Fw|z9kAETQ8pmQG=+e>J0NJZU{vZ-o!YS6pMt-&Gmqnz20ByAQNv2Lg zx=&g0I?mE{Ia3__t$x`=gL?(Qh&p;t2x2J`iz|kb)dfWMgdv;Zai9ia_;7wXN&hEP7()eL8slP zuk9=Ytj5N$dB)#Qr7#As|KqHmy@o7nydeuBs!W1V|IKSHt-kHtax`1GbFaHi#f}em zmfaiBtCPA=+D;!MuE(+Ve;u#R!}x z4R#G_^88X#YxUBQB)?0Lpl%H>FTY!4Y2vLK(%#Htx@kMo>K7f~W~H49l!9rzkX8m1 z+uYXo)QbMWF^42?!?z%Wqmnz`E{&5lQvX6pS$-bR`5};BAL(B9YVv{#V}$EA3IFs& z0KDS(T7y%kyfu#{4x)G#tcT7Y1$+&9a8sDF&{quql`p~m{P&WL*jo3c^UHNA?R*pJ zJw|4t)J1%pyu0RoRudL;e5yB23}#81k(}0n#jy@heJVh5Ufm__ogn|#;>+6_zSfh0 zRO7Uz@rK@HoFYKI>U$z13t_LogM@~G7F)OW`{Bw9655_tu<<$3feI*$oTY^kjI0jInCPzH`t@}#(LMz3>1@CKt&kR=;WAm zdCj@|0#0AH6iAkW)f;4MO5j;*W5nFQrXPTB*wQL@2>Fz&b#FhH*0~n49I01s?OPe+ zdMag+?&z4RIkmetdz}xEC})Z@hcg)EwTDoaTVp#T^(&*35b--@l$6fP>(>iZHgD!2 zI4p5)9otXd(p}FvO@)%4TY1~23=Q9g4JY6$tHOU$GwNr4xqxv1tZ7~g#RZX?uC8#x7pv&bO|KjvbOdP8%trFRX{fM4t~~3=Hgr11JpY zQLkCR$0gU-XTSMBA=%gPL~eLuJrr>3{Jo<$UeONPkao~G#3cq;oOo%F!^DjVsZsaP z-LuJ1-QbY~eFJGC1-)`a#dxr~Qb4N!8U=#3 z^i5&K){WHEot`{UKr60YXZ`a2!VDj1@`GI|cMHFZ#te%#a0CULSG;=5gDp3_WFm5B zVj^{H*gjnWd@lEeb7!xv+7k#^W_0f`0-4Jzo%6NLN47xFgF38HbG9h^(d@HaPdKUU%C*+GA3*4P-WBB;2HK2aHPZ1LII(%3N>GLDtw(&+v**v$Paj>^um01&!3!wir6(Ya!- zql1O)hj`FHK_q2Ra6vupZ5^y3eMba*b*1`tI>6tkL64^`6bM#Mp_6SgkDcpxc8MkJ zwy}@tqpLeb9P6_qmZ}No0IuZV`#J;qMJp*i1X^Jj^h?(U;1~2^NfQ2EApq`jzh z9rSEL`ZhA27H~9Rh`6ht^h%3`J!=ltR%i($A<0;PF^UJ6MS_xTA`vykZyc`1U>?7} za$}migMq%3UlMCX*eq%_m+~eqPV&kQC!_X;0TLcoL$;p@rqtibV()+2En~Zm2Q629 z&cI;TM9Z3*<)AKuTj2_?Ug4Z#wutAt)$l?00Xg9Ti8q=aB7a2t|HvcK3$- z=NSWeqtJhCPmzgaVo)sW>YvKw;0p^E%jb|(00Q;18?m}6B5%EK+`Qvm*#g1GnPfAz zJRPd?6C7gj6Cyr%lX9<{;#4X7dMI|{73DE~Qm_QKlU40(vrc;a)(^zq7E@*_`lhRY z1ISb13&qe4cjdADoEw)2t&f97vt*gPD#O$NZ0E!*DlhCz`!?S{Z$A^4-FSQvAbT^u zGO5+~L-NU7+3nGhtK}7pHpX&^ef!JxlW*g%X|i2;Rka4!)dR1wTsA^t_>Qgsm`cU1k{@+l1aSREIx{v& zsRzJ_5&{POVQFCZ2hH_?HW6n{&HHFq@?RAa;{iGa?#Fv>CRH;Bygyk%FR&ulSFBPK zuKd2-YsFA1(BXF#f+WqV+-%oJtNV zn1yORC~2_Qcn_=asy#kF%^{&^QQNqneGqBUn5r@SHMm{gsn}XFm0mk;`b%(=qW2@7uT=KC4FzXNv49WIC1ov`Q}`pmx?iy>)iI;82i?c zb+ZsMP2Qv5=cRwDDKf5pGJ(D9Fj{Mw#1bL~|LuWeh-!A#0$?wks?Fq0&=1AAUEYW) zX?FZ-T2V3PAe!twx9~o!W~%gVO`DIun`}(mi{s&;IL3uLPJwi!B=P6U%fc`r&Z6(M zt0VxfQU_4!YZZwcFqmJn85&`X0_wc`#O0X!n7$&sx$F~KBC%Z!#9A@rX_Em*f~l%Z zfWd3{U6xdt!~aYSu*w^FMeakAB_u3veQ(Emt3Ho$YwymycoD}rY43e?`ek#*MQ^X% zENt*+q;SJ`?I4xQQKOtNR(r=(5Sl>V@JH*?vfJ{-t=~%yLtG&@?flP|f9PIqHdH2W zSGA`^g(sxAHR|o;3ec_X5{_z|^%j6;`EmjeH=k&u%*$p<*e#j<&}7!8NB*DD94!u! z$COCO62?MQN0DKl&bzLFe7EWi@P+XSQw-V{#JoHkXFD3T2dr>T+gs0E018;0@FP?8~kqbgz`>OBwrm6!y4^#4PfhLphc9Y zvgFa9-vs;z=HWfZy%BTJC&O60IA-brE|Bv3`_DfB1U)#y813caym7xZYY(hG8-vUo zpw?#OxvsJLk%@{7bl6y$Ha!Mx1}HbufF6yR@x}Gr4LZg{IB)}n!mN2oC$P-(jPzaz zTDksbRu*wpH*T*ZHM|RL@C&d|_P%i{JCEKQPzm$R1q%t_#QZMS!I}ln$Dq*!)x0kk#fQYAptKkRiGD45F2IRzPY{; zGH%@cib-S~|3%B%5(a-ZT>&7h$Z-%5C4CXAa`!Q$fo=sP=&So|VUAnW7aQ6l1{RNU zK<&Cqs^I4xEO_T`$*|{cs|gi0B(f=TRV+er$xFV3Ay!cC!Pnk89a#t0)0!@TFQ@n1 zIjPUyz_u2Bv`0S<8VxCuz>9R!`vC>(AhK7AFa$%1__Y%E8|+NT+FQcZ)auJSiK-fY zQTXPrEyjf`U1Ys5>-;4^O@s)7)uFmrLi)4J-HYKMb-Q@6lur_CX&G399=d^>IrLA8 zMviM56qXgiL2ILlkTh56uaw9vJV0B^(A`(~am<7g$iqNCQk0Jqhu1p5CIF9&{o38r z8)KwiQ$XDQKGghBIRFdg;^&r|nP!)>D1>kWs z+9V)>)4F&UBls7*)o83Rm7{!z#~;HOE@J@R->0=~Rgp{#Aw>^uFrwFE#hgKdxu``! zN~v(1bNq*0GPbPYVYpYf{<9Sw08xX3cV2(TOCv?!hI~oGJmpjaUa-Q;@6~LVdP$?z zOTZN*?yGb~Q6ZAa8m!WH9xow>RG2zgT#hYMk+8LrN0M%Z!d!dVuGP)^%lTs*|CTG) z{xH&nW$LVhCMn1WAIpn{8#kd{xbCSQ`*qATaFN?CkaR z4gTEb?(t}*NEZ*C5?IqomZy56g{3GAS4>sQA=~R-bpm#Zt##s`8s$UN2<-hdWOQvUg40Ci2Ank z{7yQbXBTIpcEpTUO^`#A7gC3>bSDshKLhLk^81k4pGjXj&LzXM5T=`cPfeyC)$O0@vIw zOO^n%k@jduq)Xv=v};m9&jnL9E1$Q!-?9Ii!MVL}&S8Muh)g#{n zJea)9VSmN>4{G7GSH|97U=z4I#sP&|rw|v7itPbYtPq50u!6!>-ycl947$MBE?ps9 z;;(8rd!h-3Tp-8mCfAZ!TsZI?)$5%jfWSI5i5jwx&N=hrg= z2dP)fcWQT#bru05SVxr59>{8r-W=F$!kW%7U^>Ar4B1DP{&>|g zR{pTwM&x+pa{ThArSbfNPok~SvFXN{;prArUjvzzF91W_vy^mh!zzL)2rzy&4h{&P zqwG+L0yP*Q2gY^eJeI3To1+Zq#(&bsf{*sF#%M0;#~Qe4t^tz0x!yVdIbwg=GlEiA z0f1Xgm&mp$F~%VY?HSwRFdACj<_4i>-~{T$mZm@AyWR~;qAV^LF7JmM@)E3;%;Xx( zhSg!N!~>>r%j*s-=?vvnaqa=Gb%R1AvvJxLr2TopVXmqB|VoXDaVL12$eXSm!)@{^RgWNB&&S_~yk zUS-UJP)gg%ID5d6I!|wDg^k~K4<(VodDS1L+hJE` zi@qw~?B~NM4it@vq1{&FpD`4B092yKfOGh)b}=9)HTCVA0xm&#x^ZE^rK#YbR|lXS zCN0t`H8U+{`72O_c_qNuf=_;VQk<<4@vL(yRl$iGNj(*!KT1sGjX3{(n?D8La7+LY z*u~AV$XIvIXEJ~?R)HY*PLu~A(q~Rw{ZfNua4Z1ycd*1|1KP3=;I~}dhT#<6??wI% zA*^yk4~x6t*3ZaE&uh(un@)^B1e^Fj1d;h6=%jA@s}Xb80b^k81Us`h(1s!Gueod0 zfxgg%bLV``;?_aZ2BH2qPmA#-b^bc3np`6KG0b0D#C2goAE%w}rn9#_`O`Y7+69(D zBj$k_h!XYw6_mxFP_jvSl4SFz_1W~_Sx zXI9q~Bi+HXoEGC(1-~-`cpEZvwl)=4d>3}VAJH78Kie5WMgVG48hI641p5cy-TEYB z4VThPWkLP=I{x-A#PbM1I=Mxu{m0yiP7S;4YPvrbL$0!2cx3Kx0M>{$htE3YkpM+K zVrzeeY&o)KR_im5asps4?SYAai9pNIwd6_~;8ibVmcfMsaDlFZ@KenG{BgDH5Zs^$ zl3f_wVnmDWUfRoiA)zC&Q|!XhkelsQZo1LqP?KCRo{{1e_!`7Hg8#)`fNhzS3hG)8 zsL#E)Y90o(b}P4E(q0w~&H8x*C*kB8+40KLE9V@hXnGln4Nr-4W9#dTquia~540$lWr1Rq3d ziG}Nqm&1-f1ij;I)NH5&zvm=E6F-LIs_YVIUqg( z@=Q0F%9;J*2?DwcsrfNe|(l4#t%w1YuYT%{hk%?{G#a$ z(7^|65=W4-jl1@agCXv;AZ*l!58ET4Ely)#g4u#GA<2i|A4wjPjcqHE^({7aJe(3f zsIT+$mkfiwkhB(VfBYH1c=J0z<&+Tgj% z58^}tB>yd~1q0%o{117+f|nq;NIQfIN5>bn%9r2k4S&6-^yZLXd_v{XBS~-{5{~!%YzL^f zq0=dafaJt3#<1NWLwkp5Z~wDm_>@J|fA$!i+IIerK)`?h1m^nwdm8^e1KN1!f9>GE zXYl`+9sD|(YS_Bh(tXDA7v8BWTLXSK>Q3&%Gf!c{O@>MapW2!v|C%a)-BWUVwZ8sc z{fDA!O(mokQ4^2wDz-=u3=f&0c&`{(wes+Sv(1B7ikIRZIN zdMf}=>J?ccBQ9M{`8Q6ye9ZLk?jRk<|54nzsQIrl-@}YQ|5Z2V75^V?o44HmD#d&q z{GUMb-yc5p-vc}KUn4nn>i>z00Tbill)V$@Ce5Wl?r+%lem0?`rl#h3^rs@hFq{#) zzO>;){?uA1x{@eH`;w{u{B~|;A^_||T$mnFwmk_VudieRSLm7>sD1tGh3;;(T~w-; zcC72f;AfJ#D4%-aS~X&N`xcH6LZy7Z(^c=o=Gjf&!saZ@hlGVPE~g48G=;>@ha%zs zc!55Y2(x}S=JPM841%nW%@cn|Y00JaJA$YvO0p2qmp_i`YWOzJ(+$4OLZg$jMY01g~X* zuu*b$!7Lp*_3S_O&k0(2dc<_0jbF_RyCci&{m8V} z(kPXn0LP~bD>noZ@#+19kwoZz#U_q__Z2C!n{Gyo-vKEqSFu#muURuNp?KHUG(9-j zslRbK9b!%o^!S(~zhQq2uh!EqWA27?j)tUe$?oTU&tJ9p)TUmeF!mRf$FvG=9(>f3 z1n4+oad)n#OUc}o6{831!d{+u(0;gyvA5?Oo5}~d{rSw|=B;(zFdo&-L&EfNA3_C2 z48k?&&qEv{J9ktV`+uD_uV}Vb%xx(X^_!LzAVI`MOxflo>}_KLmtU7n!jLm7qxs?$ zi$&c~Qm+;T8&;fN=#sSCxD?Nv>8t* ziiZn~(V8vt34Q1m^4^sI(hApeL(In!kwye+wFu&~Yp6os9RNP_=Vy?SIxk~p5#zWH zq{$acsvA6lIIesd-93ON7vAaGS)v#g5+%P{+R1x=pSbC3b+T9FeDV2Kh<~tK<6%`1 zPMLG^xoJs=1I`yy^u@1zW@W5GH*8}}$N?!MxP+7t6=^bw(>|Wd5}FC=&u=A6#%T9u z-u2-V>bqREWQtzPB&aOaW}Qcc;5TZtO}9p(8xb@zD1v1jA1>(#v`Al&(vMQ>3V_ zSvsQjR(jfVb6q4IXDSkTa+FY%@6vgi>1h7!){V5Fj(s(|rSe`=qtphTzP=FZEYSd^ z5zU4ZTS7uax4um9G{Jqfpd0m3c3TrIj8N$TZW|R+Z}^M?H+f@3_S&_aWC=eXw-$tf zMPLp$&Etq7Hdl`~95@_3%uKQFhT|L2iCGY0y%^=sQ!ju2Z3Ug3p<7x+58O!Ry1a>` z1__w5TT8q!BCXeGZ_ys?Y}|EMiEmgJ9ZVo$wN=#C9V0F-Zol|Ne+8Q(N2jqIcb0pv z3!FqRrUb#wz>s<}NB!ux-y>o9;LgHAj+3Kf@9!L+8})`HGmn*@z<{P!>(1{L_Es5k zCN_opXjAGLl54(71|j_VKZVnGUZEom00oo4%|@73#M}`OStm97J}Ia-yyFDVo7g38 zS$gRyN9C#c^kKonJw;lic`d58iu&rsn86paHY@~CLUtCFwwkmHyX(i9`Z31hfh0*m zPDH@4SUooK#+aBx+H@tyq+jsyW7<`+(Phq2(ML7f*v70&;w zny2d-u%=iIxUEIK4```uGqvo^jtn^spcUWsan1a^Zl^LYv0RH zO>SjeMYdjEM{-g-DyIWGBH8OLYaAv%y4B52ZK>&#J_wo{BoWux#K6VuS8%ayk6ceC zbEG5<1P4B5WsAEz=At`UC&(4%J8+ltX3{H4!+brP#l$+PiB!}?$Y z%Z1YU_FbW4>;y(XfN3VXZie_<6mAS9$`7RzXxBZELZCx6Hj1-Jx*kWeObaDh%G?)e zs%})AayJ}>BD#kX;T!L$f1G-_0~q9`&cu4T-K4kDi=B_83E9?%Z9uo>H)P56W)KlY zw`5N_8V`M4ULG5`;6-QO`Ku)0=rHFH>xWeJ(Hwa_P2QT~v25D?ded+3S8sBQ%n2ET z7U#qiy9AWfucz^ei1Yz(xZB4mmz1(V1mc@rP92PWc*|kW``FmnShJwRSCa@M(lq(o zv>9n6Kfl-<85=tf0`z=&1ke1INb+Y?x+(Vd9TvG#mqpMcg;9PTHp@GD!U{08lloQU?@8jx zE2Hu8canl!@$vET^P8$(q6?FERbxZQ9wTQ*?5=BfHfVExYLRPtK>Nzw@iOx9*wX8tqF2IP(Y@soa5@vrKH6SR>ra?;Dt0mSqh^4W-Jh^Gz}4~3OPjOCOI z(rsX*R6S2x354#wT= z?DzcKX(GHLC@-B<4wn?;T4fRDrq0?SE6|Lu zMsscC4`+7*d{>7zX3(-GA&eRpAJ>9+A3Gb2qO!A{=KJtLu8+MON#Ewr9oBF{kO_t3 zIYmWxI2+uj+ppBLf{7Zm{YrVR46Ae_Kk{f>-pSRqSE?jLm?Zx|Dk@5ovJlG{JwWci zk=!FZBgH6R{k6^Eq3O{RME?jd6#0`q|?1(l?{n)u4zs2;e z&Uz?J8v7j0J_J-Vc{yCHpc%SK#%>J=gV@}*X?1le%R-bFs{Bjf`o}w6P`?2+unI-r zfBIP{%@p)7MSa)NLFI?D_f^voWioh*>WD%q-fuH+Z*?gDuu3laWwOF7;@L^S1pK1VrQfJl?+P!>Yd7v1n&?awSO~I#5^b zpz34ZeB6ghLB&gg$1DL7DY;V?+Odt~$}2)tj=RP9|1~aY;z7m@VAC_7oA~k6SweoH zi=#X(%jr!c^?~(ms#*$VHojiw^{!AVvEJc%MP~D%Tn!b|s}WS^r2Fdbn9m_*E!~Nu zZgOz&Gm>(&AZYmvIXoP@F1z1XT>ugZ+0C>xfG~wIyVtyicJ$19~N#)hew;%;F zcI$Z@Lcpof+}{_^>5t&O^7S~6FZSRA3+kY3tgK!gO%;R?7`%AwXfhem%(YhCv@oHM zR62F4F$j3T!F*k(ba=4pVlOOZ)$`}~vyuo(ZB{BX47snSX^~p?qVRj`j*1lIBVNqO zji4}yU;W;}YztCv?*iUFYr5t-tK;u%q+g8&DA`KMx7)Q*j3=}_bj>vR^4`z( zXR1u?RmXJH>2rk@+3>YXLj$IzG7*WDfkFGzxu-H6^xF(#aEbeg0U!aW+gZdsH!+EA zX|a7FeE6&OP8TUyvg&Zw$uM2P$u!NiV2W1O0K@K^Q2lkmHecaY@Ns!x$~#VaFsxI{M8*OuaYt5}$Ducpm03dG+UOo*qZTl4p*; zHuHVMI%uHjmr08$5-RND;z6ZVd?r&PiTh4lLD+OJ=)mqZVzJhh#>0K7*gGIq>VB7j zGi{u~LK-VDRXO{6Nm-YnM^ga<$fatTsNH>p!_q#&9?JZ4Gcsq)r+6IC#)evwm#wOA zTLZ7IFGLry?_W{;?`=HXxpX+TWfE*XI5;?Q-1a!8AaU06U*F(07_5oB633B@l<*N! z;9Bg51*IJJPZQXUYc_;BN{$52ocguVdi948cnz91Hl7`j3a^zDR-~5}d%6nJXyW*2 z5+xqRT)UBO+_wem+rFjAm?F|-FtWN971gySW@wLoWG?1;kZRrf@sWAl9duLKi}0RC zQfaQ2dEij38Tcx0M*E>RVk#$|rE%gs>UO#`)@(HkFdA>91 zy9eS-QL$5T5Eg-~UNYOzH?NQsFc?RHe2ez`#O#ZwH}A6tnQyF!gwlyqgb+5qYYRau zV=0Y$&T9*6Pg8%)7DL@ii>qahzfz^=ep=s9$aR2|)~A18il}zYoqV=5S;&sO(p6Ho zG^Ja^ZXO-ohyh+#^7J@!cTXzEO;_xMCy zAm6ZiQG|jqAr%GJa&P02nlAH(=1F?<`uMx5&KOrptq?TjjJV5YLD5Y6A+z_Oi88yj zLw93y#{HTZX)!}Hnft1qgbgv1MhC<679mzvRze+GF5M5=?AI^tFevFM z6iZy1pVTrOj_c{!c3#u2uO1sK zN-;B4tff*9p_{5^ZJ1ITN;)ekTB)Z*Bxvijx|)Y-ONlbHRD+ZtL?YdErJjN;K|EwC z5|4={gpkO&?(LlOH=G~#LtgnQx%0ZN@5ATwzP`EdF9~1yxI|J*2*WSbY8X|tl$}Kv zDkN?F+^rVnZuNp-ZQhR;MHZUlWr0JadSvv7qh@M9sxb0?^BVHT&)9TrN~YA1ZnJ!* zs2y0#3i^_IV~D+v%ppxTINdtlP8;CE9K~YSND+8l8oX}jd|8|3yg9hTS)O-8wd$?x zf5Bn^N9q!JV;bo?SU1*l=MECb1LFzp91#Epg2cWj-eL*YbP~3ev-mhI^&q*rbaMUM zuIvs$F_0qdA%)0gM#gvFdZUAgo4v(H7r7Mg>eZ#OI13Ma;Y^NU3D?)S7%0ECw>G(w zwIXt^x$AT&G3gX|Jb|KiYGd{!)rlYD=WccP>_^}zHm&wX^KSYi+yN2)8qqo29HWZN zqGLII&PWUIli8!2t0fIaBPWXCvi_qNoor)SQ6CQGJfi=EqY2k>FB~E|L>V&plzPGuv`XoZ$cIYCbEzvk z?evJN8qo8^Bt-#9_^lX2>0?q<+^!7vvSw~ed3C>XKKG4s*+`7~ zn#hus+=D8jn1xxMRMT=|g-SsHX11=WEAQt}F7SqMT&cB@fwRYKtJ(b7F}XwdXkNje z3p$C)saUnr(Q&!06XO~yY(2j~HdjQk zb3K5NlS8U8yagDZv&GF&G&V8pSSg7;2EgfyX8;?FS6X)_OcN?;PqmD6oc^KU`vZ@A z<;@&ZCMwS#d?8c|)N_K$crju>EmXrdhIId?#g>!odW-F{bplX`>Q1Zm(+F@OfS8;W zL6Wf=UYo3(P*Z!TSK{7)&Qctzi4}yW0WCv@eBm-O`f0^}lTZoA>5nnIN6^a{f-n2ck-Y9Ay54ybFd)9@6G?)Ps)RE-eF|G-;np zYlvNYvatVeD!r-ZAiL!CXFyiODq+o)<8)Tl)e9H4f7HvI{ar)GX>6>mA-~;?XQ!M{ zi1&w#zxqC?RI;5ZiI{I}hDxh_n)0Q1UK|l&>Ad)0nvA5TQ7R@B?KESrd0+6iwp~Ek zcfr$3$*1iM%X)emA+?&3Ydcy#!>=39qfk?i2)E_a&Y*9#%~xBAvd3(IV`i$1#i)x&1$)D8r+pkET5t)fE+v)Q%3fJ!hsG8tEgD_@AOF!M#r#mwmL+zC|9S zpGS91QbNS`wf$6KmW41(spBC?eu+mu_eDL*vNt5BzE<|sv5#3V z8W}34awq8H3rl!>-yd|U+w*-95$$TOt6%r#?!z?zBVz!Uc~V|}SO}yMirq1*zZT*E zVAHMzp(VR@`w>JDJg3A+g!?`{G6U>0?yFA)E5BAD2M zhjl@9`j?(_i}8JXGvb%-WgG#WHxcv`^)>B87EhHEKA(yTKBo z;11-d`bz08niRYbz;k0S$`6lBewjqOrEz7XjxX|o{}FwkdFj=lRHY31==5^&8ZdH5 z5bTiY8je7cEti%~)hbIc$WYIE)fBBw{MHOv4vc zegV<5obUe5$JN${3f&Av16vrn^W}}v**&vCY;vh8E7~Fa{JE5XbD|=H0x`Nnab|ng z)fa}{u^s5ke&JZAuJ%^U>1Cazx0t1-;0H=n6vbmxb{jwr|jEI%%^@LP@k9x&`D}R$-%6p!`mF~VnNND_xpl?Kb~byABF|nd>jf9{_X}f;-Q=}b{?T`z$5e>~GLJ$`*!f~W zmK;)KCN)%Sw`LEg*Q%cMq<>E|l@nZ)tL?OClW-Cs%?|+kk@WAb#xm!dNzyXyFtb^M zOZVNe*%tz5#tFt1+~>69s8EV*ERfg|LFRaJJ3j8sV8%veS<txNGfOXCYwpCIBzW=L0~4z)lYi2eZdW}BFcLuQO58xA0tB2ZdrlkdHn zu4CYAIT-gwEQA1|N?H6#m1@a4vx638_U={|p5(s+M}>|{cs6^!0coLn&4wY7KE=Ou zfpSm??0`hRKXr6AWM5zR%1mBpd)l^f7w)S0fnErVuX@|S>M4;f2Y~7ls$Zb) z!lK8xziyh&quJL^Dfe-0SSe0d-@ms0q>b2m;!6K>-eNp=*+D+7`&!hFhPy!v1Ty{z zphN+I1y?T^Yj5?H(4u_}z_66d10CJb@A-hPA5Gd#NE0-wS3IgBhVuCaSj@=tP?~$_ z!QLa7?S%<&I3Uip`J&1Qn_}zhM*B<#PmnPa!poN6%!4*Te2KlU{Qy?Gl2XMwORLTT zx9{FRU@nD*3qCIPn%Du}|2jz5`D=JU=l^%wqDi}lPEq6q>OHH1!WQA>bE5w1i#Pub D^E6#X literal 0 HcmV?d00001 diff --git a/1.9/assets/images/social/plugins/builder/app.png b/1.9/assets/images/social/plugins/builder/app.png deleted file mode 100644 index 8f5fd45740da6e5879d422c68dc22a21bbdcb81d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37264 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 >y?_1nD-6R( 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 Dp#B+AR00&kMkxpq{vi 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 literal 0 HcmV?d00001 diff --git a/1.9/assets/images/social/tutorials/environment/basic-usage.png b/1.9/assets/images/social/tutorials/environment/basic-usage.png new file mode 100644 index 0000000000000000000000000000000000000000..018a6cc2c5ca4871e47dbbac1659fe88c0d16b1d GIT binary patch literal 38785 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 A9smFU literal 0 HcmV?d00001 diff --git a/1.9/blog/2022/10/08/hatch-v160/index.html b/1.9/blog/2022/10/08/hatch-v160/index.html index b0089c3b2..2c833d07b 100644 --- a/1.9/blog/2022/10/08/hatch-v160/index.html +++ b/1.9/blog/2022/10/08/hatch-v160/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Hatch v1.6.0

    Hatch v1.6.0 brings improvements to build environments, better handling of dynamic metadata, and support for tools like Visual Studio Code.

    Build environments

    Originally, the environment interface method for providing builder sub-environments was intended to be used in conjunction with some cleanup logic in order to provide a fresh setup every time. However, this is unnecessary in practice because build dependencies rarely change.

    Without caching, repeat build environment use is slow which affects the following scenarios:

    Now a new environment interface method build_environment_exists is used by Hatch to determine whether or not it has already been created, for implementations that have a caching mechanism.

    The virtual environment type now uses this method to cache build environments.

    Project metadata

    Dynamically defined metadata is now supported everywhere, thanks to the new caching of virtual build environments.

    A project metadata command is introduced that displays the fully resolved metadata. The output format is JSON unless a field is specified as an argument.

    For example, if you checkout a project that is built by Hatch, like FastAPI, and run:

    hatch project metadata readme
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Hatch v1.6.0

    Hatch v1.6.0 brings improvements to build environments, better handling of dynamic metadata, and support for tools like Visual Studio Code.

    Build environments

    Originally, the environment interface method for providing builder sub-environments was intended to be used in conjunction with some cleanup logic in order to provide a fresh setup every time. However, this is unnecessary in practice because build dependencies rarely change.

    Without caching, repeat build environment use is slow which affects the following scenarios:

    Now a new environment interface method build_environment_exists is used by Hatch to determine whether or not it has already been created, for implementations that have a caching mechanism.

    The virtual environment type now uses this method to cache build environments.

    Project metadata

    Dynamically defined metadata is now supported everywhere, thanks to the new caching of virtual build environments.

    A project metadata command is introduced that displays the fully resolved metadata. The output format is JSON unless a field is specified as an argument.

    For example, if you checkout a project that is built by Hatch, like FastAPI, and run:

    hatch project metadata readme
     

    only the readme text will be displayed. If the content is in Markdown, then Rich will render it directly in your terminal:

    FastAPI readme

    Virtual environment location

    The virtual environment type now uses a flat layout for storage in the configured virtual environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory.

    For example, if you define the following Hatch configuration:

    [dirs.env]
     virtual = ".hatch"
     

    and the following matrix:

    [[tool.hatch.envs.test.matrix]]
    diff --git a/1.9/blog/2023/12/11/hatch-v180/index.html b/1.9/blog/2023/12/11/hatch-v180/index.html
    index 5b4b2de57..ccabfedfa 100644
    --- a/1.9/blog/2023/12/11/hatch-v180/index.html
    +++ b/1.9/blog/2023/12/11/hatch-v180/index.html
    @@ -7,4 +7,4 @@
         .gdesc-inner { font-size: 0.75rem; }
         body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
         body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
    -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Hatch v1.8.0

    Hatch v1.8.0 brings Python distribution management, static analysis and formatting backed by Ruff, and binaries for every platform.

    Installation made easy

    One thing that has been a perpetual problem for Hatch and other Python applications is that Python itself is a dependency. You, and more importantly your users, need to in some way get Python before your software can even be used. The recommended way to go about that is platform-dependent and even differs based on your target audience. I viewed this as a central UX problem for Hatch and so severe that I took a bit of a hiatus to solve it.

    Luckily, I have to my satisfaction solved this problem in the form of PyApp. It is a runtime installer for Python projects written in Rust. Apps are distributed as standalone executables as users have come to expect and bootstrapping occurs upon the first invocation. Here is an example of what you would see the first time you run a binary from this release:

    Installation example

    Now that we have binaries, creating installers for different platforms becomes trivial. Starting with this release not only are binaries available for every platform but also we have installers for Windows and macOS. The installer for macOS is signed using a certificate from the same account used to sign the official distributions from https://www.python.org, so users will not get any security pop-ups. Shout out to @ewdurbin for their extreme generosity in setting up multiple certificates in their free time!

    These installers and binaries are now the recommended way to install and update Hatch. These binaries have built-in management so you can update to the latest version by running hatch self update.

    Windows signing

    In future we will sign the installers for Windows but I did not have time to look into how that works. macOS signing took way longer than I anticipated 😅

    Python management

    For a long time I and other users have desired that Hatch gain the ability to manage Python distributions. In my mind this was always blocked on a better installation experience because there was sort of a chicken-or-egg problem where you want a Python manager but you first need Python. No longer is that the case!

    The new python command group allows for easy installation of various distributions to arbitrary locations which are then added to your PATH by default. Hatch supports CPython and PyPy distributions:

    Available Python distributions

    Virtual environment Python resolution

    The virtual environment type is now far more intelligent when resolving the parent distribution to use and guarantees that, when no specific version is requested, the resolved distribution will always be compatible with the project.

    Additionally, when a requested version cannot be found on PATH it will automatically be downloaded and managed internally.

    Static analysis

    There is a new fmt command, backed entirely by Ruff, that checks and fixes your code for formatting and linting issues.

    Starting with this release, Hatch maintains default settings that are guaranteed to be up-to-date and represent best practices for programming in modern Python. The idea is to provide defaults that are so broadly applicable that the majority of users will maintain little if any of their own overrides.

    The default behavior is internal management of settings to provide an OOTB experience that works. It is recommended however that you persist the default config file in version control so that other tools like IDEs can utilize your full configuration.

    Since Ruff is now provided as a built-in feature, new project templates no longer have such configuration and are much less verbose.

    Build improvements

    Building projects that do not use Hatchling as a backend is now supported and such builds are managed with the standard build tool.

    The bridge between Hatch and the Hatchling CLI has been removed. Previously, the builder would send serialized messages to Hatch that would contain the desired content and style for each line of output. This was done in an effort to allow builder and build hook plugins to output pretty messages without actually requiring a dependency like Rich. A problem that arises with this is that builders that invoke subprocesses will not display ANSI codes as one might expect and will lose out on the interactive experience of such invocations, like the built-in app builder plugin calling cargo build. So now everything is simpler at the expense of no colored output without manual logic, or adding a dependency if you're a third-party plugin.

    Faster environment usage

    Spawning a shell or running commands within environments always first checks that your project's dependencies are satisfied and if not synchronizes the environment with what is defined. Previously, this had the potential to be quite slow for projects that have many dependencies.

    Now the set of dependency definitions is hashed and no check is performed if the hash is the same as before, significantly speeding up environment usage in most cases.

    Hatchling

    Hatch now depends on Hatchling v1.19.0, which was also just released.

    Better defaults

    Hatchling is all about providing the best possible defaults, even at the expense of backward compatibility. In this release, there are two breaking changes that provide a much better user experience and were in fact requested by users.

    • Both the force-include option and the force_include_editable wheel build data setting now raise errors if source paths do not exist.
    • The wheel build target now raises an error when no file inclusion options have been defined and none of its heuristics to determine what to ship are satisfied.

    App build target

    A new app build target is now stable that allows for the building of standalone binaries for projects. This is what Hatch itself uses for its binaries.

    Meta

    Why Hatch?

    A new page has been introduced that discusses the value proposition of Hatch and Hatchling in comparison to alternatives. Currently, it only addresses a few features but in future this page will become more comprehensive.

    Future

    Upcoming features include a test command, commands to manage dependencies, and workspaces functionality similar to Cargo that will make managing monorepos far easier.

    Next year there will be two large efforts that you should expect to see:

    1. A significant amount of my free time (and some at work) will be devoted to introducing lock file functionality in Hatch and trying to get whatever that happens to be standardized.

      I met with @brettcannon about his thoughts post-PEP 665 and about mousebender. I also met with the prefix.dev team about rip and was fortunate enough to be shown a demo before its official announcement.

      At the moment, the two options I see are to either go all in and contribute to mousebender or rely on the Prefix folks and use rip. The latter has the benefit of potentially supporting Conda as a side effect with the downside of being quite new with the spec firmly out of our control. The former has the benefit of being able to easily gain institutional support from the Python packaging team and each of our employers with the downside being a significant amount of work needing to be done.

    2. When @henryiii is able to get some free time away from teaching I plan to work with him once again and push very hard for the Python build ecosystem to adopt the extensionlib approach.

      I am of the opinion that the Python community has not fully completed the expressed outcome of PEP 517 in that build backends are still (for the most part) reliant on setuptools for building non-Python code bases.

      Basically, there are components that interact with compilers to produce extension modules and components that pack files into an archive which we call a build backend. These are two distinct pieces of functionality and my view is that there should be an API that allows backends to consume extension module builders to find out where things got created and where they should be shipped inside archives.

      In this hypothetical future any build backend would be able to trigger the building of extension modules based on user configuration.

    Support

    If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!

    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Hatch v1.8.0

    Hatch v1.8.0 brings Python distribution management, static analysis and formatting backed by Ruff, and binaries for every platform.

    Installation made easy

    One thing that has been a perpetual problem for Hatch and other Python applications is that Python itself is a dependency. You, and more importantly your users, need to in some way get Python before your software can even be used. The recommended way to go about that is platform-dependent and even differs based on your target audience. I viewed this as a central UX problem for Hatch and so severe that I took a bit of a hiatus to solve it.

    Luckily, I have to my satisfaction solved this problem in the form of PyApp. It is a runtime installer for Python projects written in Rust. Apps are distributed as standalone executables as users have come to expect and bootstrapping occurs upon the first invocation. Here is an example of what you would see the first time you run a binary from this release:

    Installation example

    Now that we have binaries, creating installers for different platforms becomes trivial. Starting with this release not only are binaries available for every platform but also we have installers for Windows and macOS. The installer for macOS is signed using a certificate from the same account used to sign the official distributions from https://www.python.org, so users will not get any security pop-ups. Shout out to @ewdurbin for their extreme generosity in setting up multiple certificates in their free time!

    These installers and binaries are now the recommended way to install and update Hatch. These binaries have built-in management so you can update to the latest version by running hatch self update.

    Windows signing

    In future we will sign the installers for Windows but I did not have time to look into how that works. macOS signing took way longer than I anticipated 😅

    Python management

    For a long time I and other users have desired that Hatch gain the ability to manage Python distributions. In my mind this was always blocked on a better installation experience because there was sort of a chicken-or-egg problem where you want a Python manager but you first need Python. No longer is that the case!

    The new python command group allows for easy installation of various distributions to arbitrary locations which are then added to your PATH by default. Hatch supports CPython and PyPy distributions:

    Available Python distributions

    Virtual environment Python resolution

    The virtual environment type is now far more intelligent when resolving the parent distribution to use and guarantees that, when no specific version is requested, the resolved distribution will always be compatible with the project.

    Additionally, when a requested version cannot be found on PATH it will automatically be downloaded and managed internally.

    Static analysis

    There is a new fmt command, backed entirely by Ruff, that checks and fixes your code for formatting and linting issues.

    Starting with this release, Hatch maintains default settings that are guaranteed to be up-to-date and represent best practices for programming in modern Python. The idea is to provide defaults that are so broadly applicable that the majority of users will maintain little if any of their own overrides.

    The default behavior is internal management of settings to provide an OOTB experience that works. It is recommended however that you persist the default config file in version control so that other tools like IDEs can utilize your full configuration.

    Since Ruff is now provided as a built-in feature, new project templates no longer have such configuration and are much less verbose.

    Build improvements

    Building projects that do not use Hatchling as a backend is now supported and such builds are managed with the standard build tool.

    The bridge between Hatch and the Hatchling CLI has been removed. Previously, the builder would send serialized messages to Hatch that would contain the desired content and style for each line of output. This was done in an effort to allow builder and build hook plugins to output pretty messages without actually requiring a dependency like Rich. A problem that arises with this is that builders that invoke subprocesses will not display ANSI codes as one might expect and will lose out on the interactive experience of such invocations, like the built-in binary builder plugin calling cargo build. So now everything is simpler at the expense of no colored output without manual logic, or adding a dependency if you're a third-party plugin.

    Faster environment usage

    Spawning a shell or running commands within environments always first checks that your project's dependencies are satisfied and if not synchronizes the environment with what is defined. Previously, this had the potential to be quite slow for projects that have many dependencies.

    Now the set of dependency definitions is hashed and no check is performed if the hash is the same as before, significantly speeding up environment usage in most cases.

    Hatchling

    Hatch now depends on Hatchling v1.19.0, which was also just released.

    Better defaults

    Hatchling is all about providing the best possible defaults, even at the expense of backward compatibility. In this release, there are two breaking changes that provide a much better user experience and were in fact requested by users.

    • Both the force-include option and the force_include_editable wheel build data setting now raise errors if source paths do not exist.
    • The wheel build target now raises an error when no file inclusion options have been defined and none of its heuristics to determine what to ship are satisfied.

    Binary build target

    A new binary build target is now stable that allows for the building of standalone binaries for projects. This is what Hatch itself uses for its binaries.

    Meta

    Why Hatch?

    A new page has been introduced that discusses the value proposition of Hatch and Hatchling in comparison to alternatives. Currently, it only addresses a few features but in future this page will become more comprehensive.

    Future

    Upcoming features include a test command, commands to manage dependencies, and workspaces functionality similar to Cargo that will make managing monorepos far easier.

    Next year there will be two large efforts that you should expect to see:

    1. A significant amount of my free time (and some at work) will be devoted to introducing lock file functionality in Hatch and trying to get whatever that happens to be standardized.

      I met with @brettcannon about his thoughts post-PEP 665 and about mousebender. I also met with the prefix.dev team about rip and was fortunate enough to be shown a demo before its official announcement.

      At the moment, the two options I see are to either go all in and contribute to mousebender or rely on the Prefix folks and use rip. The latter has the benefit of potentially supporting Conda as a side effect with the downside of being quite new with the spec firmly out of our control. The former has the benefit of being able to easily gain institutional support from the Python packaging team and each of our employers with the downside being a significant amount of work needing to be done.

    2. When @henryiii is able to get some free time away from teaching I plan to work with him once again and push very hard for the Python build ecosystem to adopt the extensionlib approach.

      I am of the opinion that the Python community has not fully completed the expressed outcome of PEP 517 in that build backends are still (for the most part) reliant on setuptools for building non-Python code bases.

      Basically, there are components that interact with compilers to produce extension modules and components that pack files into an archive which we call a build backend. These are two distinct pieces of functionality and my view is that there should be an API that allows backends to consume extension module builders to find out where things got created and where they should be shipped inside archives.

      In this hypothetical future any build backend would be able to trigger the building of extension modules based on user configuration.

    Support

    If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!

    \ No newline at end of file diff --git a/1.9/blog/2023/12/18/hatch-v190/index.html b/1.9/blog/2023/12/18/hatch-v190/index.html index 04b9e0f9d..fed2e3e79 100644 --- a/1.9/blog/2023/12/18/hatch-v190/index.html +++ b/1.9/blog/2023/12/18/hatch-v190/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Hatch v1.9.0

    Hatch v1.9.0 brings improvements to static analysis and important bug fixes.

    Static analysis

    The default version of Ruff has been increased to v0.1.8. This release brings formatting capabilities to docstrings and Hatch enables this by default with line length set to 80. This length was chosen as the default because it plays nicely with the rendering of the most popular themes for Python documentation, such as Material for MkDocs and Furo.

    Additionally, it is now possible for projects to pin to specific versions of Ruff for upgrading at a later time:

    [tool.hatch.envs.hatch-static-analysis]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Hatch v1.9.0

    Hatch v1.9.0 brings improvements to static analysis and important bug fixes.

    Static analysis

    The default version of Ruff has been increased to v0.1.8. This release brings formatting capabilities to docstrings and Hatch enables this by default with line length set to 80. This length was chosen as the default because it plays nicely with the rendering of the most popular themes for Python documentation, such as Material for MkDocs and Furo.

    Additionally, it is now possible for projects to pin to specific versions of Ruff for upgrading at a later time:

    [tool.hatch.envs.hatch-static-analysis]
     dependencies = ["ruff==X.Y.Z"]
     
    [envs.hatch-static-analysis]
     dependencies = ["ruff==X.Y.Z"]
    diff --git a/1.9/blog/archive/2022/index.html b/1.9/blog/archive/2022/index.html
    index c58a2a8bd..6842b953b 100644
    --- a/1.9/blog/archive/2022/index.html
    +++ b/1.9/blog/archive/2022/index.html
    @@ -7,4 +7,4 @@
         .gdesc-inner { font-size: 0.75rem; }
         body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
         body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
    -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    2022

    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    2022

    \ No newline at end of file diff --git a/1.9/blog/archive/2023/index.html b/1.9/blog/archive/2023/index.html index fcec05e24..1e32ce997 100644 --- a/1.9/blog/archive/2023/index.html +++ b/1.9/blog/archive/2023/index.html @@ -7,4 +7,4 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    2023

    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    2023

    \ No newline at end of file diff --git a/1.9/blog/category/release/index.html b/1.9/blog/category/release/index.html index 01977bf03..397d658ed 100644 --- a/1.9/blog/category/release/index.html +++ b/1.9/blog/category/release/index.html @@ -7,4 +7,4 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Release

    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Release

    \ No newline at end of file diff --git a/1.9/blog/index.html b/1.9/blog/index.html index 85c3fa458..d4c81c7a2 100644 --- a/1.9/blog/index.html +++ b/1.9/blog/index.html @@ -7,4 +7,4 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Blog

    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Blog

    \ No newline at end of file diff --git a/1.9/build/index.html b/1.9/build/index.html index bf0501711..4079b781a 100644 --- a/1.9/build/index.html +++ b/1.9/build/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Builds


    Configuration

    Builds are configured using the tool.hatch.build table. Every target is defined by a section within tool.hatch.build.targets, for example:

    [tool.hatch.build.targets.sdist]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Builds


    Configuration

    Builds are configured using the tool.hatch.build table. Every target is defined by a section within tool.hatch.build.targets, for example:

    [tool.hatch.build.targets.sdist]
     exclude = [
       "/.github",
       "/docs",
    diff --git a/1.9/cli/about/index.html b/1.9/cli/about/index.html
    index 0da8ce722..32ceef340 100644
    --- a/1.9/cli/about/index.html
    +++ b/1.9/cli/about/index.html
    @@ -1,4 +1,4 @@
    - About - Hatch      

    About


    Verbosity

    The amount of displayed output is controlled solely by the -v/--verbose (environment variable HATCH_VERBOSE) and -q/--quiet (environment variable HATCH_QUIET) root options.

    The levels are documented here.

    Project awareness

    No matter the mode, Hatch will always change to the project's root directory for entering or running commands in environments.

    Tab completion

    Completion is achieved by saving a script and then executing it as a part of your shell's startup sequence.

    Afterward, you'll need to start a new shell in order for the changes to take effect.

    Save the script somewhere:

    _HATCH_COMPLETE=bash_source hatch > ~/.hatch-complete.bash
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    CLI usage


    Verbosity

    The amount of displayed output is controlled solely by the -v/--verbose (environment variable HATCH_VERBOSE) and -q/--quiet (environment variable HATCH_QUIET) root options.

    The levels are documented here.

    Project awareness

    No matter the mode, Hatch will always change to the project's root directory for entering or running commands in environments.

    Tab completion

    Completion is achieved by saving a script and then executing it as a part of your shell's startup sequence.

    Afterward, you'll need to start a new shell in order for the changes to take effect.

    Save the script somewhere:

    _HATCH_COMPLETE=bash_source hatch > ~/.hatch-complete.bash
     

    Source the file in ~/.bashrc (or ~/.bash_profile if on macOS):

    . ~/.hatch-complete.bash
     

    Save the script somewhere:

    _HATCH_COMPLETE=zsh_source hatch > ~/.hatch-complete.zsh
     

    Source the file in ~/.zshrc:

    . ~/.hatch-complete.zsh
     

    Save the script in ~/.config/fish/completions:

    _HATCH_COMPLETE=fish_source hatch > ~/.config/fish/completions/hatch.fish
    -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/1.9/cli/reference/index.html b/1.9/cli/reference/index.html index a4fbf2af1..59cab860f 100644 --- a/1.9/cli/reference/index.html +++ b/1.9/cli/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

    hatch

    Usage:

    hatch [OPTIONS] COMMAND [ARGS]...
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    hatch

    Usage:

    hatch [OPTIONS] COMMAND [ARGS]...
     

    Options:

    Name Type Description Default
    --env, -e text The name of the environment to use [env var: HATCH_ENV] default
    --project, -p text The name of the project to work on [env var: HATCH_PROJECT] None
    --verbose, -v integer range (0 and above) Increase verbosity (can be used additively) [env var: HATCH_VERBOSE] 0
    --quiet, -q integer range (0 and above) Decrease verbosity (can be used additively) [env var: HATCH_QUIET] 0
    --color / --no-color boolean Whether or not to display colored output (default is auto-detection) [env vars: FORCE_COLOR/NO_COLOR] None
    --interactive / --no-interactive boolean Whether or not to allow features like prompts and progress bars (default is auto-detection) [env var: HATCH_INTERACTIVE] None
    --data-dir text The path to a custom directory used to persist data [env var: HATCH_DATA_DIR] None
    --cache-dir text The path to a custom directory used to cache data [env var: HATCH_CACHE_DIR] None
    --config text The path to a custom config file to use [env var: HATCH_CONFIG] None
    --version boolean Show the version and exit. False
    --help boolean Show this message and exit. False

    hatch build

    Build a project.

    Usage:

    hatch build [OPTIONS] [LOCATION]
     

    Options:

    Name Type Description Default
    --target, -t text The target to build, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None
    --hooks-only boolean Whether or not to only execute build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False
    --no-hooks boolean Whether or not to disable build hooks [env var: HATCH_BUILD_NO_HOOKS] False
    --ext boolean Whether or not to only execute build hooks for distributing binary Python packages, such as compiling extensions. Equivalent to --hooks-only -t wheel False
    --clean, -c boolean Whether or not existing artifacts should first be removed [env var: HATCH_BUILD_CLEAN] False
    --clean-hooks-after boolean Whether or not build hook artifacts should be removed after each build [env var: HATCH_BUILD_CLEAN_HOOKS_AFTER] False
    --help boolean Show this message and exit. False

    hatch clean

    Remove build artifacts.

    Usage:

    hatch clean [OPTIONS] [LOCATION]
     

    Options:

    Name Type Description Default
    --target, -t text The target with which to remove artifacts, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None
    --hooks-only boolean Whether or not to only remove artifacts from build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False
    --no-hooks boolean Whether or not to ignore artifacts from build hooks [env var: HATCH_BUILD_NO_HOOKS] False
    --ext boolean Whether or not to only remove artifacts from build hooks for distributing binary Python packages, such as compiled extensions. Equivalent to --hooks-only -t wheel False
    --help boolean Show this message and exit. False

    hatch config

    Manage the config file

    Usage:

    hatch config [OPTIONS] COMMAND [ARGS]...
    @@ -37,7 +37,7 @@
     

    would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

    Usage:

    hatch env run [OPTIONS] ARGS...
     

    Options:

    Name Type Description Default
    --env, -e text The environments to target None
    --include, -i text The matrix variables to include None
    --exclude, -x text The matrix variables to exclude None
    --filter, -f text The JSON data used to select environments None
    --force-continue boolean Run every command and if there were any errors exit with the first code False
    --ignore-compat boolean Ignore incompatibility when selecting specific environments False
    --help boolean Show this message and exit. False

    hatch env show

    Show the available environments.

    Usage:

    hatch env show [OPTIONS] [ENVS]...
     

    Options:

    Name Type Description Default
    --ascii boolean Whether or not to only use ASCII characters False
    --json boolean Whether or not to output in JSON format False
    --help boolean Show this message and exit. False

    hatch fmt

    Format and lint source code.

    Usage:

    hatch fmt [OPTIONS] [ARGS]...
    -

    Options:

    Name Type Description Default
    --check boolean Only check for errors rather than fixing them False
    --preview / --no-preview boolean Preview new rules and formatting None
    --linter, -l boolean Only run the linter False
    --formatter, -f boolean Only run the formatter False
    --sync boolean Sync the default config file with the current version of Hatch False
    --help boolean Show this message and exit. False

    hatch new

    Create or initialize a project.

    Usage:

    hatch new [OPTIONS] [NAME] [LOCATION]
    +

    Options:

    Name Type Description Default
    --check boolean Only check for errors rather than fixing them False
    --linter, -l boolean Only run the linter False
    --formatter, -f boolean Only run the formatter False
    --sync boolean Sync the default config file with the current version of Hatch False
    --help boolean Show this message and exit. False

    hatch new

    Create or initialize a project.

    Usage:

    hatch new [OPTIONS] [NAME] [LOCATION]
     

    Options:

    Name Type Description Default
    --interactive, -i boolean Interactively choose details about the project False
    --cli boolean Give the project a command line interface False
    --init boolean Initialize an existing project False
    --help boolean Show this message and exit. False

    hatch project

    View project information

    Usage:

    hatch project [OPTIONS] COMMAND [ARGS]...
     

    Options:

    Name Type Description Default
    --help boolean Show this message and exit. False

    hatch project metadata

    Display project metadata.

    If you want to view the raw readme file without rendering, you can use a JSON parser like jq:

    hatch project metadata | jq -r .readme
     

    Usage:

    hatch project metadata [OPTIONS] [FIELD]
    @@ -59,6 +59,10 @@
     version = ["42", "3.14", "9000"]
     

    then running:

    hatch run +py=3.10 -version=9000 test:pytest
     

    would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

    Usage:

    hatch run [OPTIONS] [ENV:]ARGS...
    +

    Options:

    Name Type Description Default
    --help boolean Show this message and exit. False

    hatch self

    Manage Hatch

    Usage:

    hatch self [OPTIONS] COMMAND [ARGS]...
    +

    Options:

    Name Type Description Default
    --help boolean Show this message and exit. False

    hatch self report

    Generate a pre-populated GitHub issue.

    Usage:

    hatch self report [OPTIONS]
    +

    Options:

    Name Type Description Default
    --no-open, -n boolean Show the URL instead of opening it False
    --help boolean Show this message and exit. False

    hatch self restore

    Restore the installation

    Usage:

    hatch self restore [OPTIONS] [ARGS]...
    +

    Options:

    Name Type Description Default
    --help boolean Show this message and exit. False

    hatch self update

    Install the latest version

    Usage:

    hatch self update [OPTIONS] [ARGS]...
     

    Options:

    Name Type Description Default
    --help boolean Show this message and exit. False

    hatch shell

    Enter a shell within a project's environment.

    Usage:

    hatch shell [OPTIONS] [SHELL_NAME] [SHELL_PATH] [SHELL_ARGS]...
     

    Options:

    Name Type Description Default
    --help boolean Show this message and exit. False

    hatch status

    Show information about the current environment.

    Usage:

    hatch status [OPTIONS]
     

    Options:

    Name Type Description Default
    --help boolean Show this message and exit. False

    hatch version

    View or set a project's version.

    Usage:

    hatch version [OPTIONS] [DESIRED_VERSION]
    diff --git a/1.9/community/contributing/index.html b/1.9/community/contributing/index.html
    index 996fc9b23..fb7ff676c 100644
    --- a/1.9/community/contributing/index.html
    +++ b/1.9/community/contributing/index.html
    @@ -7,7 +7,7 @@
         .gdesc-inner { font-size: 0.75rem; }
         body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
         body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
    -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Contributing

    The usual process to make a contribution is to:

    1. Check for existing related issues
    2. Fork the repository and create a new branch
    3. Make your changes
    4. Make sure formatting, linting and tests passes.
    5. Add tests if possible to cover the lines you added.
    6. Commit, and send a Pull Request.

    Clone the repository

    Clone the hatch repository, cd into it, and create a new branch for your contribution:

    cd hatch
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Contributing

    The usual process to make a contribution is to:

    1. Check for existing related issues
    2. Fork the repository and create a new branch
    3. Make your changes
    4. Make sure formatting, linting and tests passes.
    5. Add tests if possible to cover the lines you added.
    6. Commit, and send a Pull Request.

    Clone the repository

    Clone the hatch repository, cd into it, and create a new branch for your contribution:

    cd hatch
     git checkout -b add-my-contribution
     

    Run the tests

    Run the test suite while developing:

    hatch run dev
     

    Run the test suite with coverage report:

    hatch run cov
    @@ -15,5 +15,5 @@
     

    Lint

    Run automated formatting:

    hatch run lint:fmt
     

    Run full linting and type checking:

    hatch run lint:all
     

    Docs

    Start the documentation in development:

    hatch run docs:serve
    -

    Build and validate the documentation website:

    hatch run build-check
    -
    \ No newline at end of file +

    Build and validate the documentation website:

    hatch run docs:build-check
    +
    \ No newline at end of file diff --git a/1.9/community/highlights/index.html b/1.9/community/highlights/index.html index a9119eaa2..8fa49d757 100644 --- a/1.9/community/highlights/index.html +++ b/1.9/community/highlights/index.html @@ -1,4 +1,4 @@ - Highlights - Hatch
    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}
    \ No newline at end of file diff --git a/1.9/community/users/index.html b/1.9/community/users/index.html index 5b5c43d5e..c92898610 100644 --- a/1.9/community/users/index.html +++ b/1.9/community/users/index.html @@ -7,4 +7,4 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Users


    The following is not intended to be a complete enumeration. Be sure to view the development version of this page for an up-to-date listing.

    Projects

    aiogram | argon2-cffi | attrs | Black | coffea | Colorama | Django Anymail | Django Debug Toolbar | Django Wiki | FastAPI | filelock | github3.py | Gradio | HTTPX | iCalendar for Humans | LinkChecker | Material for MkDocs | MkDocs | openSUSE | Nox | Packit | pipx | platformdirs | Pydantic | Pygments | PyHamcrest | PyMdown Extensions | Python JSON Schema | Rye | SALib | Spack | Starlette | structlog | tox | Twisted | urllib3 | Uvicorn | virtualenv | Voilà | XGBoost | Ypy

    Industry

    Organizations

    Government

    Academia

    Research

    Security

    Crypto

    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Users


    The following is not intended to be a complete enumeration. Be sure to view the development version of this page for an up-to-date listing.

    Projects

    aiogram | Apache Airflow | argon2-cffi | attrs | Black | coffea | Colorama | Django Anymail | Django Debug Toolbar | Django Wiki | FastAPI | filelock | github3.py | Gradio | HTTPX | iCalendar for Humans | LinkChecker | Material for MkDocs | MkDocs | openSUSE | Nox | Packit | pipx | platformdirs | Pydantic | Pygments | PyHamcrest | PyMdown Extensions | Python JSON Schema | Rye | SALib | Spack | Starlette | structlog | tox | Twisted | urllib3 | Uvicorn | virtualenv | Voilà | XGBoost | Ypy

    Industry

    Organizations

    Government

    Academia

    Research

    Security

    Crypto

    \ No newline at end of file diff --git a/1.9/config/build/index.html b/1.9/config/build/index.html index a2b3c05c5..f08716016 100644 --- a/1.9/config/build/index.html +++ b/1.9/config/build/index.html @@ -1,4 +1,4 @@ - Build - Hatch

    Build configuration


    Build targets are defined as sections within tool.hatch.build.targets:

    [tool.hatch.build.targets.<TARGET_NAME>]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Build configuration


    Build targets are defined as sections within tool.hatch.build.targets:

    [tool.hatch.build.targets.<TARGET_NAME>]
     
    [build.targets.<TARGET_NAME>]
     

    Tip

    Although not recommended, you may define global configuration in the tool.hatch.build table. Keys may then be overridden by target config.

    Build system

    To be compatible with the broader Python packaging ecosystem, you must define the build system as follows:

    [build-system]
     requires = ["hatchling"]
    diff --git a/1.9/config/context/index.html b/1.9/config/context/index.html
    index ca26ed0b5..84ebd7978 100644
    --- a/1.9/config/context/index.html
    +++ b/1.9/config/context/index.html
    @@ -7,7 +7,7 @@
         .gdesc-inner { font-size: 0.75rem; }
         body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
         body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
    -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Context formatting


    You can populate configuration with the values of certain supported fields using the syntax of Python's format strings. Each field interprets the modifier part after the colon differently, if at all.

    Global fields

    Any configuration that declares support for context formatting will always support these fields.

    Paths

    Field Description
    root The root project directory
    home The user's home directory

    All paths support the following modifiers:

    Modifier Description
    uri The normalized absolute URI path prefixed by file:
    real The path with all symbolic links resolved
    parent The parent of the preceding path

    Tip

    The parent modifier can be chained and may be combined with either the uri or real modifier, with the latter placed at the end. For example:

    [tool.hatch.envs.test]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Context formatting


    You can populate configuration with the values of certain supported fields using the syntax of Python's format strings. Each field interprets the modifier part after the colon differently, if at all.

    Global fields

    Any configuration that declares support for context formatting will always support these fields.

    Paths

    Field Description
    root The root project directory
    home The user's home directory

    All paths support the following modifiers:

    Modifier Description
    uri The normalized absolute URI path prefixed by file:
    real The path with all symbolic links resolved
    parent The parent of the preceding path

    Tip

    The parent modifier can be chained and may be combined with either the uri or real modifier, with the latter placed at the end. For example:

    [tool.hatch.envs.test]
     dependencies = [
         "example-project @ {root:parent:parent:uri}/example-project",
     ]
    diff --git a/1.9/config/dependency/index.html b/1.9/config/dependency/index.html
    index 2a32def8d..0cf9c6863 100644
    --- a/1.9/config/dependency/index.html
    +++ b/1.9/config/dependency/index.html
    @@ -1,4 +1,4 @@
    - Dependencies - Hatch      

    Dependency configuration


    Project dependencies are defined with PEP 508 strings using optional PEP 440 version specifiers.

    Version specifiers

    A version specifier consists of a series of version clauses, separated by commas. For example:

    [project]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Dependency configuration


    Project dependencies are defined with PEP 508 strings using optional PEP 440 version specifiers.

    Version specifiers

    A version specifier consists of a series of version clauses, separated by commas. For example:

    [project]
     ...
     dependencies = [
       "cryptography",
    diff --git a/1.9/config/environment/advanced/index.html b/1.9/config/environment/advanced/index.html
    index dfb6211fc..118c4aded 100644
    --- a/1.9/config/environment/advanced/index.html
    +++ b/1.9/config/environment/advanced/index.html
    @@ -1,4 +1,4 @@
    - Advanced - Hatch      

    Advanced environment configuration


    Context formatting

    All environments support the following extra context formatting fields:

    Field Description
    env_name The name of the environment
    env_type The type of environment
    matrix Its modifier selects the value of that matrix variable. If the environment is not part of a matrix or was not generated with the variable, you must specify a default value as an additional modifier e.g. {matrix:version:v1.0.0}.
    verbosity The integer verbosity value of Hatch. A flag modifier is supported that will render the value as a CLI flag e.g. -2 becomes -qq, 1 becomes -v, and 0 becomes an empty string. An additional flag integer modifier may be used to adjust the verbosity level. For example, if you wanted to make a command quiet by default, you could use {verbosity:flag:-1} within the command.
    args For executed commands only, any extra command line arguments with an optional default modifier if none were provided

    Matrix

    Environments can define a series of matrices with the matrix option:

    [tool.hatch.envs.test]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Advanced environment configuration


    Context formatting

    All environments support the following extra context formatting fields:

    Field Description
    env_name The name of the environment
    env_type The type of environment
    matrix Its modifier selects the value of that matrix variable. If the environment is not part of a matrix or was not generated with the variable, you must specify a default value as an additional modifier e.g. {matrix:version:v1.0.0}.
    verbosity The integer verbosity value of Hatch. A flag modifier is supported that will render the value as a CLI flag e.g. -2 becomes -qq, 1 becomes -v, and 0 becomes an empty string. An additional flag integer modifier may be used to adjust the verbosity level. For example, if you wanted to make a command quiet by default, you could use {verbosity:flag:-1} within the command.
    args For executed commands only, any extra command line arguments with an optional default modifier if none were provided

    Matrix

    Environments can define a series of matrices with the matrix option:

    [tool.hatch.envs.test]
     dependencies = [
       "pytest"
     ]
    diff --git a/1.9/config/environment/overview/index.html b/1.9/config/environment/overview/index.html
    index 04a12e5ef..8dfa032a3 100644
    --- a/1.9/config/environment/overview/index.html
    +++ b/1.9/config/environment/overview/index.html
    @@ -1,4 +1,4 @@
    - Overview - Hatch      

    Environment configuration


    All environments are defined as sections within the tool.hatch.envs table.

    [tool.hatch.envs.<ENV_NAME>]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Environment configuration


    All environments are defined as sections within the tool.hatch.envs table.

    [tool.hatch.envs.<ENV_NAME>]
     
    [envs.<ENV_NAME>]
     

    The storage location for environments is completely configurable.

    Unless an environment is explicitly selected on the command line, the default environment will be used. The type of this environment defaults to virtual.

    Info

    Environments prefixed by hatch- are used for special purposes e.g. static analysis.

    Inheritance

    All environments inherit from the environment defined by its template option, which defaults to default.

    So for the following configuration:

    [tool.hatch.envs.foo]
     type = "baz"
    diff --git a/1.9/config/hatch/index.html b/1.9/config/hatch/index.html
    index d6bfabed8..75fdc5547 100644
    --- a/1.9/config/hatch/index.html
    +++ b/1.9/config/hatch/index.html
    @@ -1,4 +1,4 @@
    - Hatch - Hatch      

    Hatch configuration


    Configuration for Hatch itself is stored in a config.toml file located by default in one of the following platform-specific directories.

    Platform Path
    macOS ~/Library/Application Support/hatch
    Windows %USERPROFILE%\AppData\Local\hatch
    Unix $XDG_CONFIG_HOME/hatch (the XDG_CONFIG_HOME environment variable default is ~/.config)

    You can select a custom path to the file using the --config root option or by setting the HATCH_CONFIG environment variable.

    The file can be managed by the config command group.

    Mode

    The mode key controls how Hatch selects the project to work on.

    Local

    mode = "local"
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Hatch configuration


    Configuration for Hatch itself is stored in a config.toml file located by default in one of the following platform-specific directories.

    Platform Path
    macOS ~/Library/Application Support/hatch
    Windows %USERPROFILE%\AppData\Local\hatch
    Unix $XDG_CONFIG_HOME/hatch (the XDG_CONFIG_HOME environment variable default is ~/.config)

    You can select a custom path to the file using the --config root option or by setting the HATCH_CONFIG environment variable.

    The file can be managed by the config command group.

    Mode

    The mode key controls how Hatch selects the project to work on.

    Local

    mode = "local"
     

    By default, Hatch will look for a pyproject.toml file in the current working directory and any parent directories. The directory storing the first found file will be considered the project root.

    Project

    mode = "project"
     project = "proj1"
     
    diff --git a/1.9/config/metadata/index.html b/1.9/config/metadata/index.html
    index 57c841e89..78506e1f0 100644
    --- a/1.9/config/metadata/index.html
    +++ b/1.9/config/metadata/index.html
    @@ -1,4 +1,4 @@
    - Metadata - Hatch      

    Project metadata


    Project metadata is stored in a pyproject.toml file located at the root of a project's tree and is based entirely on the standard.

    Name (required)

    The name of the project.

    [project]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Configuring project metadata


    Project metadata is stored in a pyproject.toml file located at the root of a project's tree and is based entirely on the standard.

    Name (required)

    The name of the project.

    [project]
     name = "your-app"
     

    Version (required)

    See the dedicated versioning section.

    [project]
     ...
    @@ -100,4 +100,4 @@
     allow-ambiguous-features = true
     
    [metadata]
     allow-ambiguous-features = true
    -

    Deprecated

    This option temporarily exists to provide better interoperability with tools that do not yet support PEP 685 and will be removed in the first minor release after Jan 1, 2024.

    \ No newline at end of file +

    Deprecated

    This option temporarily exists to provide better interoperability with tools that do not yet support PEP 685 and will be removed in the first minor release after Jan 1, 2024.

    \ No newline at end of file diff --git a/1.9/config/project-templates/index.html b/1.9/config/project-templates/index.html index cc3d6efe4..b5eea3c47 100644 --- a/1.9/config/project-templates/index.html +++ b/1.9/config/project-templates/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Project templates


    You can control how new projects are created by the new command using Hatch's config file.

    Author

    [template]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Project templates


    You can control how new projects are created by the new command using Hatch's config file.

    Author

    [template]
     name = "..."
     email = "..."
     

    Licenses

    [template.licenses]
    diff --git a/1.9/config/static-analysis/index.html b/1.9/config/static-analysis/index.html
    index b2745b0f9..1c77a605e 100644
    --- a/1.9/config/static-analysis/index.html
    +++ b/1.9/config/static-analysis/index.html
    @@ -1,4 +1,4 @@
    - Static analysis - Hatch      

    Static analysis configuration


    Static analysis performed by the fmt command is backed entirely by Ruff.

    Hatch provides default settings that user configuration can extend.

    Extending config

    When defining your configuration, be sure to use options that are prefixed by extend- such as extend-select, for example:

    [tool.ruff.format]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Static analysis configuration


    Static analysis performed by the fmt command is (by default) backed entirely by Ruff.

    Hatch provides default settings that user configuration can extend.

    Extending config

    When defining your configuration, be sure to use options that are prefixed by extend- such as extend-select, for example:

    [tool.ruff.format]
     preview = true
     quote-style = "single"
     
    @@ -41,8 +41,22 @@
     extend = "ruff_defaults.toml"
     
    extend = "ruff_defaults.toml"
     

    Anytime you wish to update the defaults (such as when upgrading Hatch), you must run the fmt command once with the --sync flag e.g.:

    hatch fmt --check --sync
    -

    Tip

    This is the recommended approach since it allows other tools like IDEs to use the default configuration.

    Versioning

    You can pin the particular version of Ruff by explicitly defining the environment dependencies:

    [tool.hatch.envs.hatch-static-analysis]
    +

    Tip

    This is the recommended approach since it allows other tools like IDEs to use the default configuration.

    No config

    If you don't want Hatch to use any of its default configuration and rely entirely on yours, set the path to anything and then simply don't extend in your Ruff config:

    [tool.hatch.envs.hatch-static-analysis]
    +config-path = "none"
    +
    [envs.hatch-static-analysis]
    +config-path = "none"
    +

    Customize behavior

    You can fully alter the behavior of the environment used by the fmt command. See the how-to for a detailed example.

    Dependencies

    Pin the particular version of Ruff by explicitly defining the environment dependencies:

    [tool.hatch.envs.hatch-static-analysis]
     dependencies = ["ruff==X.Y.Z"]
     
    [envs.hatch-static-analysis]
     dependencies = ["ruff==X.Y.Z"]
    -

    Default settings

    Non-rule settings

    Per-file ignored rules

    Selected rules

    The following rules are based on version 0.1.8 of Ruff. Rules with a P are only selected when preview mode is enabled.

    \ No newline at end of file +

    Scripts

    If you want to change the default commands that are executed, you can override the scripts. The following four scripts must be defined:

    [tool.hatch.envs.hatch-static-analysis.scripts]
    +format-check = "..."
    +format-fix = "..."
    +lint-check = "..."
    +lint-fix = "..."
    +
    [envs.hatch-static-analysis.scripts]
    +format-check = "..."
    +format-fix = "..."
    +lint-check = "..."
    +lint-fix = "..."
    +

    The format-* scripts correspond to the --formatter/-f flag while the lint-* scripts correspond to the --linter/-l flag. The *-fix scripts run by default while the *-check scripts correspond to the --check flag.

    Reminder

    If you choose to use different tools for static analysis, be sure to update the required dependencies.

    Default settings

    Non-rule settings

    Per-file ignored rules

    Selected rules

    The following rules are based on version 0.3.1 of Ruff. Rules with a P are only selected when preview mode is enabled.

    \ No newline at end of file diff --git a/1.9/environment/index.html b/1.9/environment/index.html index 440ad6ed7..23448cacc 100644 --- a/1.9/environment/index.html +++ b/1.9/environment/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Environments


    Environments are designed to allow for isolated workspaces for testing, building documentation, or anything else projects need.

    Unless an environment is chosen explicitly, Hatch will use the default environment.

    Creation

    You can create environments by using the env create command. Let's enter the directory of the project we created in the setup phase:

    $ hatch env create
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Environments


    Environments are designed to allow for isolated workspaces for testing, building documentation, or anything else projects need.

    Unless an environment is chosen explicitly, Hatch will use the default environment.

    Tip

    For a more comprehensive walk-through, see the Basic usage tutorial.

    Creation

    You can create environments by using the env create command. Let's enter the directory of the project we created in the setup phase:

    $ hatch env create
     Creating environment: default
     Installing project in development mode
     Syncing dependencies
    @@ -100,4 +100,4 @@
     |      |         | test.py3.9-9000-foo |              |
     |      |         | test.py3.9-9000-bar |              |
     +------+---------+---------------------+--------------+
    -

    Removal

    You can remove a single environment or environment matrix by using the env remove command or all of a project's environments by using the env prune command.

    \ No newline at end of file +

    Removal

    You can remove a single environment or environment matrix by using the env remove command or all of a project's environments by using the env prune command.

    \ No newline at end of file diff --git a/1.9/history/hatch/index.html b/1.9/history/hatch/index.html index db4c72f24..6d3b09796 100644 --- a/1.9/history/hatch/index.html +++ b/1.9/history/hatch/index.html @@ -1,4 +1,4 @@ - Hatch - Hatch

    Hatch history


    All notable changes to Hatch will be documented in this file.

    The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

    Unreleased

    1.9.4 - 2024-03-12

    Fixed:

    • Limit the maximum version of Hatchling in anticipation of backward incompatible changes

    1.9.3 - 2024-01-25

    Fixed:

    • Fix loading of local plugins to account for newly released versions of a dependency

    1.9.2 - 2024-01-21

    Fixed:

    • Fix the default token variable name for publishing to PyPI

    1.9.1 - 2023-12-25

    Fixed:

    • Ensure that the dependency_hash method of the environment interface is called after sync_dependencies for cases where the hash is only known at that point, such as for dependency lockers
    • Only acknowledge the HATCH_PYTHON_VARIANT_* environment variables for Python resolution for supported platforms and architectures
    • Fix Python resolution when there are metadata hooks with unsatisfied dependencies

    1.9.0 - 2023-12-19

    Changed:

    • Environments prefixed by hatch- are now considered internal and used for special purposes such as configuration for static analysis

    Added:

    • Enable docstring formatting by default for static analysis
    • Allow for overriding config of internal environments
    • Concretely state the expected API contract for the environment interface methods find and check_compatibility
    • Upgrade Ruff to 0.1.8
    • Bump the minimum supported version of Hatchling to 1.21.0

    Fixed:

    • Ignore a project's Python requirement for environments where the project is not installed
    • When not persisting config for static analysis, properly manage internal settings when Ruff's top level table already exists
    • Ignore compatibility checks when environments have already been created, significantly improving performance of environment usage
    • Properly allow overriding of the path option for the virtual environment type
    • Fix nushell activation on non-Windows systems

    1.8.1 - 2023-12-14

    Fixed:

    • Fix regression in calling subprocesses with updated PATH
    • Fix automatic installation of environment plugins when running as a standalone binary
    • Change default location of Python installations

    1.8.0 - 2023-12-11

    Changed:

    • Drop support for Python 3.7
    • The get_build_process method of the environment interface has been removed; plugins should use the new run_builder method instead
    • Remove pyperclip dependency and the --copy flag of the config find command
    • When running the build command all output from builders is now displayed as-is in real time without the stripping of ANSI codes
    • Version information (for Hatch itself) is now derived from Git

    Added:

    • Support Python 3.12
    • Add installers and standalone binaries
    • Add the ability to manage Python installations
    • Add fmt command
    • The virtual environment type can now automatically download requested versions of Python that are not installed
    • Add dependency_hash method to the environment interface
    • The state of installed dependencies for environments is saved as metadata so if dependency definitions have not changed then no checking is performed, which can be computationally expensive
    • The build command now supports backends other than Hatchling
    • Allow the use of features for environments when skip-install is enabled
    • The default is now __token__ when prompting for a username for the publish command
    • Add a new run_builder method to the environment interface
    • Bump the minimum supported version of Hatchling to 1.19.0
    • Bump the minimum supported version of click to 8.0.6

    Fixed:

    • Fix nushell activation
    • Better handling of flat storage directory hierarchies for the virtual environment type
    • Display useful information when running the version command outside of a project rather than erroring
    • Fix the project metadata command by only capturing stdout from the backend
    • Properly support Google Artifact Registry
    • Fix parsing dependencies for environments when warnings are emitted

    1.7.0 - 2023-04-03

    Changed:

    • The src-layout project template option is now enabled by default
    • Non-critical output now goes to stderr

    Added:

    • Add tool.hatch.env.requires configuration to automatically install dependencies for environment and environment collector plugins
    • Add custom environment collector
    • Improve syncing of dependencies provided through Git direct references
    • Add isolated_data_directory attribute to the environment interface
    • Increase the timeout for and add retries to the index publisher
    • Expand home and environment variables in configured cache and data directories
    • Improve readability of exceptions
    • Update project templates
    • Bump the minimum supported version of Hatchling to 1.14.0

    Fixed:

    • Fix displaying the version with the version command when the version is static and build dependencies are unmet
    • Fix build environments for the virtual environment type when storing within a relative path
    • Work around System Integrity Protection on macOS when running commands
    • Allow setuptools metadata migration for projects without setup.py if setup.cfg is present
    • Handle additional edge cases for setuptools metadata migration
    • Support boolean values for the config set command

    1.6.3 - 2022-10-24

    Fixed:

    • Fix version command when the version is dynamic and build dependencies are unmet

    1.6.2 - 2022-10-20

    Fixed:

    • Fix getting dynamic metadata from hooks for environments when dependencies are not dynamic

    1.6.1 - 2022-10-16

    Fixed:

    • Computing the path to the user's home directory now gracefully falls back to ~ when it cannot be determined

    1.6.0 - 2022-10-08

    Changed:

    • The run_shell_command environment interface method now accepts arbitrary subprocess.Popen keyword arguments. This is not strictly breaking, but will be utilized in upcoming features.
    • The internal directory structure for storing virtual environments is now more nested. This is not breaking, but any local environments will be created anew.

    Added:

    • Add project command group to view details about the project like PEP 621 metadata
    • Better support for auto-detection of environments by tools like Visual Studio Code now that the storage directory of virtual environments will be flat if Hatch's configured virtual environment directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
    • Build environments for the virtual environment type are now cached for improved performance
    • Add build_environment_exists method to the environment interface for implementations that cache the build environment
    • Add path option to the virtual environment type
    • Add --initialize-auth flag to the index publisher to allow for the saving of authentication information before publishing
    • Support Bash on Windows for the shell command
    • The setuptools migration script no longer modifies the formatting of existing pyproject.toml configuration
    • Bump the minimum supported version of Hatchling to 1.11.0

    Fixed:

    • Environments now respect dynamically defined project dependencies
    • The dep hash and all dep show commands now respect dynamically defined project dependencies
    • The env show, dep hash, and all dep show commands now honor context formatting
    • Fix matrix variable inclusion filtering of the run and env run commands when there are multiple possible variables
    • Build environment compatibility is now checked before use
    • Decreasing verbosity now has no affect on output that should always be displayed
    • Handle more edge cases in the setuptools migration script
    • Environments now respect user defined environment variables for context formatting
    • Update the scripts in the generated test environment template for new projects to reflect the documentation
    • Allow extra-dependencies in environment overrides
    • Depend on packaging explicitly rather than relying on it being a transitive dependency of Hatchling

    1.5.0 - 2022-08-28

    Added:

    • The index publisher now recognizes repository-specific options
    • Add the --ignore-compat flag to the env run command
    • Setting the HATCH_PYTHON environment variable to self will now force the use of the Python executable Hatch is running on for virtual environment creation

    Fixed:

    • Fix the --force-continue flag of the env run command
    • Handle more edge cases in the setuptools migration script

    1.4.2 - 2022-08-16

    Fixed:

    • Fix check for updating static versions with the version command when metadata hooks are in use

    1.4.1 - 2022-08-13

    Fixed:

    • Fix non-detached inheritance disabling for environments

    1.4.0 - 2022-08-06

    Added:

    • The default Python for virtual environments now checks PATH before using the one Hatch is running on
    • Values for environment env-vars now support context formatting
    • Add name override for environments to allow for regular expression matching
    • The index publisher now better supports non-PyPI indices
    • Add certificate options to the index publisher
    • Display waiting text when checking dependencies and removing environments
    • Display help text the first time the shell command is executed
    • Update project templates with Python 3.11 and the latest versions of various GitHub Actions
    • Add support for Almquist (ash) shells
    • Add hyperlink as a dependency for better handling of package index URLs
    • Bump the minimum supported version of virtualenv to 20.16.2
    • Bump the minimum supported version of tomlkit to 0.11.1

    Fixed:

    • Acknowledge extra-dependencies for the env show command
    • Fix locating executables within virtual environments on Debian
    • Fix managing the terminal size inside the shell command
    • Fix default code coverage file omission for the src-layout project template option

    1.3.1 - 2022-07-11

    Fixed:

    • Support -h/--help flag for the run command

    1.3.0 - 2022-07-10

    Changed:

    • Rename the default publishing plugin from pypi to the more generic index

    Added:

    • Support the absence of pyproject.toml files, as is the case for apps and non-Python projects
    • Hide scripts that start with an underscore for the env show command by default
    • Ignoring the exit codes of commands by prefixing with hyphens now works with entire named scripts
    • Add a way to require confirmation for publishing
    • Add --force-continue flag to the env run command
    • Make tracebacks colorful and less verbose
    • When shell configuration has not been defined, attempt to use the current shell based on parent processes before resorting to the defaults
    • The shell name pwsh is now an alias for powershell
    • Remove atomicwrites dependency
    • Relax constraint on userpath dependency
    • Bump the minimum supported version of Hatchling to 1.4.1

    Fixed:

    • Keep environments in sync with the dependencies of the selected features
    • Use utf-8 for all files generated for new projects
    • Escape special characters Git may return in the user name when writing generated files for new projects
    • Normalize the package name to lowercase in setuptools migration script
    • Fix parsing of source distributions during publishing

    1.2.1 - 2022-05-30

    Fixed:

    • Fix handling of top level data_files in setuptools migration script

    1.2.0 - 2022-05-22

    Changed:

    • The enter_shell environment plugin method now accepts an additional args parameter

    Added:

    • Allow context string formatting for environment dependencies
    • Add environment context string formatting fields env_name, env_type, matrix, verbosity, and args
    • Support overriding the default arguments used to spawn shells on non-Windows systems
    • Bump the minimum supported version of Hatchling to 1.3.0

    Fixed:

    • Improve setuptools migration script

    1.1.2 - 2022-05-20

    Fixed:

    • Bump the minimum supported version of Hatchling to 1.2.0
    • Update project metadata to reflect support for Python 3.11

    1.1.1 - 2022-05-12

    Fixed:

    • Fix setuptools migration script for non-Windows systems

    1.1.0 - 2022-05-12

    Changed:

    • In order to simplify the implementation of command execution for environment plugins, the run_shell_commands method has been replaced by the singular run_shell_command. A new command_context method has been added to more easily satisfy complex use cases.
    • The finalize_command environment plugin method has been removed in favor of the newly introduced context formatting functionality.

    Added:

    • Add context formatting functionality i.e. the ability to insert values into configuration like environment variables and command line arguments
    • Any verbosity for command execution will now always display headers, even for single environments
    • Every executed command is now displayed when running multiple commands or when verbosity is enabled
    • Similar to make, ignore the exit code of executed commands that start with - (a hyphen)
    • Add ability for the --init flag of the new command to automatically migrate setuptools configuration
    • Update project metadata to reflect the adoption by PyPA and production stability

    1.0.0 - 2022-04-28

    This is the first stable release of Hatch v1, a complete rewrite. Enjoy!

    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Hatch history


    All notable changes to Hatch will be documented in this file.

    The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

    Unreleased

    Added:

    • Add self report command for submitting pre-populated bug reports to GitHub
    • The reserved environment used for static analysis is now completely configurable
    • Add the following methods to the environment interface for complete control over output during life cycle management: app_status_creation, app_status_pre_installation, app_status_post_installation, app_status_project_installation, app_status_dependency_state_check, app_status_dependency_installation_check, app_status_dependency_synchronization
    • Add binaries for 32-bit versions of Windows
    • Read configuration from any ~/.pypirc file for the index publisher
    • Use the Git user as the default username for new project URL metadata
    • Add HATCH_DEBUG environment variable that when enabled will show local variables in the case of unhandled tracebacks
    • Upgrade default CPython distributions to 20240224
    • Upgrade Ruff to 0.3.1
    • Upgrade PyApp to 0.15.1 for binary builds
    • Bump the minimum supported version of Hatchling to 1.22.2

    Fixed:

    • When projects derive dependencies from metadata hooks, there is now by default a status indicator for when the hooks are executed for better responsiveness
    • Fix dependency inheritance for the template of the types environment for new projects

    1.9.4 - 2024-03-12

    Fixed:

    • Limit the maximum version of Hatchling in anticipation of backward incompatible changes

    1.9.3 - 2024-01-25

    Fixed:

    • Fix loading of local plugins to account for newly released versions of a dependency

    1.9.2 - 2024-01-21

    Fixed:

    • Fix the default token variable name for publishing to PyPI

    1.9.1 - 2023-12-25

    Fixed:

    • Ensure that the dependency_hash method of the environment interface is called after sync_dependencies for cases where the hash is only known at that point, such as for dependency lockers
    • Only acknowledge the HATCH_PYTHON_VARIANT_* environment variables for Python resolution for supported platforms and architectures
    • Fix Python resolution when there are metadata hooks with unsatisfied dependencies

    1.9.0 - 2023-12-19

    Changed:

    • Environments prefixed by hatch- are now considered internal and used for special purposes such as configuration for static analysis

    Added:

    • Enable docstring formatting by default for static analysis
    • Allow for overriding config of internal environments
    • Concretely state the expected API contract for the environment interface methods find and check_compatibility
    • Upgrade Ruff to 0.1.8
    • Bump the minimum supported version of Hatchling to 1.21.0

    Fixed:

    • Ignore a project's Python requirement for environments where the project is not installed
    • When not persisting config for static analysis, properly manage internal settings when Ruff's top level table already exists
    • Ignore compatibility checks when environments have already been created, significantly improving performance of environment usage
    • Properly allow overriding of the path option for the virtual environment type
    • Fix nushell activation on non-Windows systems

    1.8.1 - 2023-12-14

    Fixed:

    • Fix regression in calling subprocesses with updated PATH
    • Fix automatic installation of environment plugins when running as a standalone binary
    • Change default location of Python installations

    1.8.0 - 2023-12-11

    Changed:

    • Drop support for Python 3.7
    • The get_build_process method of the environment interface has been removed; plugins should use the new run_builder method instead
    • Remove pyperclip dependency and the --copy flag of the config find command
    • When running the build command all output from builders is now displayed as-is in real time without the stripping of ANSI codes
    • Version information (for Hatch itself) is now derived from Git

    Added:

    • Support Python 3.12
    • Add installers and standalone binaries
    • Add the ability to manage Python installations
    • Add fmt command
    • The virtual environment type can now automatically download requested versions of Python that are not installed
    • Add dependency_hash method to the environment interface
    • The state of installed dependencies for environments is saved as metadata so if dependency definitions have not changed then no checking is performed, which can be computationally expensive
    • The build command now supports backends other than Hatchling
    • Allow the use of features for environments when skip-install is enabled
    • The default is now __token__ when prompting for a username for the publish command
    • Add a new run_builder method to the environment interface
    • Bump the minimum supported version of Hatchling to 1.19.0
    • Bump the minimum supported version of click to 8.0.6

    Fixed:

    • Fix nushell activation
    • Better handling of flat storage directory hierarchies for the virtual environment type
    • Display useful information when running the version command outside of a project rather than erroring
    • Fix the project metadata command by only capturing stdout from the backend
    • Properly support Google Artifact Registry
    • Fix parsing dependencies for environments when warnings are emitted

    1.7.0 - 2023-04-03

    Changed:

    • The src-layout project template option is now enabled by default
    • Non-critical output now goes to stderr

    Added:

    • Add tool.hatch.env.requires configuration to automatically install dependencies for environment and environment collector plugins
    • Add custom environment collector
    • Improve syncing of dependencies provided through Git direct references
    • Add isolated_data_directory attribute to the environment interface
    • Increase the timeout for and add retries to the index publisher
    • Expand home and environment variables in configured cache and data directories
    • Improve readability of exceptions
    • Update project templates
    • Bump the minimum supported version of Hatchling to 1.14.0

    Fixed:

    • Fix displaying the version with the version command when the version is static and build dependencies are unmet
    • Fix build environments for the virtual environment type when storing within a relative path
    • Work around System Integrity Protection on macOS when running commands
    • Allow setuptools metadata migration for projects without setup.py if setup.cfg is present
    • Handle additional edge cases for setuptools metadata migration
    • Support boolean values for the config set command

    1.6.3 - 2022-10-24

    Fixed:

    • Fix version command when the version is dynamic and build dependencies are unmet

    1.6.2 - 2022-10-20

    Fixed:

    • Fix getting dynamic metadata from hooks for environments when dependencies are not dynamic

    1.6.1 - 2022-10-16

    Fixed:

    • Computing the path to the user's home directory now gracefully falls back to ~ when it cannot be determined

    1.6.0 - 2022-10-08

    Changed:

    • The run_shell_command environment interface method now accepts arbitrary subprocess.Popen keyword arguments. This is not strictly breaking, but will be utilized in upcoming features.
    • The internal directory structure for storing virtual environments is now more nested. This is not breaking, but any local environments will be created anew.

    Added:

    • Add project command group to view details about the project like PEP 621 metadata
    • Better support for auto-detection of environments by tools like Visual Studio Code now that the storage directory of virtual environments will be flat if Hatch's configured virtual environment directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
    • Build environments for the virtual environment type are now cached for improved performance
    • Add build_environment_exists method to the environment interface for implementations that cache the build environment
    • Add path option to the virtual environment type
    • Add --initialize-auth flag to the index publisher to allow for the saving of authentication information before publishing
    • Support Bash on Windows for the shell command
    • The setuptools migration script no longer modifies the formatting of existing pyproject.toml configuration
    • Bump the minimum supported version of Hatchling to 1.11.0

    Fixed:

    • Environments now respect dynamically defined project dependencies
    • The dep hash and all dep show commands now respect dynamically defined project dependencies
    • The env show, dep hash, and all dep show commands now honor context formatting
    • Fix matrix variable inclusion filtering of the run and env run commands when there are multiple possible variables
    • Build environment compatibility is now checked before use
    • Decreasing verbosity now has no affect on output that should always be displayed
    • Handle more edge cases in the setuptools migration script
    • Environments now respect user defined environment variables for context formatting
    • Update the scripts in the generated test environment template for new projects to reflect the documentation
    • Allow extra-dependencies in environment overrides
    • Depend on packaging explicitly rather than relying on it being a transitive dependency of Hatchling

    1.5.0 - 2022-08-28

    Added:

    • The index publisher now recognizes repository-specific options
    • Add the --ignore-compat flag to the env run command
    • Setting the HATCH_PYTHON environment variable to self will now force the use of the Python executable Hatch is running on for virtual environment creation

    Fixed:

    • Fix the --force-continue flag of the env run command
    • Handle more edge cases in the setuptools migration script

    1.4.2 - 2022-08-16

    Fixed:

    • Fix check for updating static versions with the version command when metadata hooks are in use

    1.4.1 - 2022-08-13

    Fixed:

    • Fix non-detached inheritance disabling for environments

    1.4.0 - 2022-08-06

    Added:

    • The default Python for virtual environments now checks PATH before using the one Hatch is running on
    • Values for environment env-vars now support context formatting
    • Add name override for environments to allow for regular expression matching
    • The index publisher now better supports non-PyPI indices
    • Add certificate options to the index publisher
    • Display waiting text when checking dependencies and removing environments
    • Display help text the first time the shell command is executed
    • Update project templates with Python 3.11 and the latest versions of various GitHub Actions
    • Add support for Almquist (ash) shells
    • Add hyperlink as a dependency for better handling of package index URLs
    • Bump the minimum supported version of virtualenv to 20.16.2
    • Bump the minimum supported version of tomlkit to 0.11.1

    Fixed:

    • Acknowledge extra-dependencies for the env show command
    • Fix locating executables within virtual environments on Debian
    • Fix managing the terminal size inside the shell command
    • Fix default code coverage file omission for the src-layout project template option

    1.3.1 - 2022-07-11

    Fixed:

    • Support -h/--help flag for the run command

    1.3.0 - 2022-07-10

    Changed:

    • Rename the default publishing plugin from pypi to the more generic index

    Added:

    • Support the absence of pyproject.toml files, as is the case for apps and non-Python projects
    • Hide scripts that start with an underscore for the env show command by default
    • Ignoring the exit codes of commands by prefixing with hyphens now works with entire named scripts
    • Add a way to require confirmation for publishing
    • Add --force-continue flag to the env run command
    • Make tracebacks colorful and less verbose
    • When shell configuration has not been defined, attempt to use the current shell based on parent processes before resorting to the defaults
    • The shell name pwsh is now an alias for powershell
    • Remove atomicwrites dependency
    • Relax constraint on userpath dependency
    • Bump the minimum supported version of Hatchling to 1.4.1

    Fixed:

    • Keep environments in sync with the dependencies of the selected features
    • Use utf-8 for all files generated for new projects
    • Escape special characters Git may return in the user name when writing generated files for new projects
    • Normalize the package name to lowercase in setuptools migration script
    • Fix parsing of source distributions during publishing

    1.2.1 - 2022-05-30

    Fixed:

    • Fix handling of top level data_files in setuptools migration script

    1.2.0 - 2022-05-22

    Changed:

    • The enter_shell environment plugin method now accepts an additional args parameter

    Added:

    • Allow context string formatting for environment dependencies
    • Add environment context string formatting fields env_name, env_type, matrix, verbosity, and args
    • Support overriding the default arguments used to spawn shells on non-Windows systems
    • Bump the minimum supported version of Hatchling to 1.3.0

    Fixed:

    • Improve setuptools migration script

    1.1.2 - 2022-05-20

    Fixed:

    • Bump the minimum supported version of Hatchling to 1.2.0
    • Update project metadata to reflect support for Python 3.11

    1.1.1 - 2022-05-12

    Fixed:

    • Fix setuptools migration script for non-Windows systems

    1.1.0 - 2022-05-12

    Changed:

    • In order to simplify the implementation of command execution for environment plugins, the run_shell_commands method has been replaced by the singular run_shell_command. A new command_context method has been added to more easily satisfy complex use cases.
    • The finalize_command environment plugin method has been removed in favor of the newly introduced context formatting functionality.

    Added:

    • Add context formatting functionality i.e. the ability to insert values into configuration like environment variables and command line arguments
    • Any verbosity for command execution will now always display headers, even for single environments
    • Every executed command is now displayed when running multiple commands or when verbosity is enabled
    • Similar to make, ignore the exit code of executed commands that start with - (a hyphen)
    • Add ability for the --init flag of the new command to automatically migrate setuptools configuration
    • Update project metadata to reflect the adoption by PyPA and production stability

    1.0.0 - 2022-04-28

    This is the first stable release of Hatch v1, a complete rewrite. Enjoy!

    \ No newline at end of file diff --git a/1.9/history/hatchling/index.html b/1.9/history/hatchling/index.html index 0d59e601a..a05b118c7 100644 --- a/1.9/history/hatchling/index.html +++ b/1.9/history/hatchling/index.html @@ -1,4 +1,4 @@ - Hatchling - Hatch

    Hatchling history


    All notable changes to Hatchling will be documented in this file.

    The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

    Unreleased

    1.21.0 - 2023-12-18

    Added:

    • Add parent context modifier for path fields

    1.20.0 - 2023-12-13

    Added:

    • Add bypass-selection option to the wheel build target to allow for empty (metadata-only) wheels

    Fixed:

    • Fix regression in 1.19.1 that allowed exclude to count toward inclusion selection, thus bypassing the default inclusion selection heuristics
    • Fix writing optional dependency core metadata in situations where there are multiple environment markers

    1.19.1 - 2023-12-12

    Fixed:

    • Add better error message when the wheel build target cannot determine what to ship
    • Consider forced inclusion patterns and build-time artifacts as file selection since some build hooks generate the entire wheel contents without user configuration

    1.19.0 - 2023-12-11

    Changed:

    • An error will now be raised if a force-included path does not exist
    • An error will now be raised for the wheel build target if no file selection options are defined

    Added:

    • Officially support Python 3.12
    • Allow using an empty string for the sources option to add a prefix to distribution paths

    Fixed:

    • Properly handle non-zero version epoch for the standard version scheme
    • Fix the wheel build target for case insensitive file systems when the project metadata name does not match the directory name on disk
    • The app build target no longer has suppressed output
    • Prevent duplicate paths when projects require the sources option while build hooks overwrite included paths
    • Properly escape spaces for URI context formatting

    1.18.0 - 2023-06-12

    Changed:

    • Drop support for Python 3.7

    Added:

    • Update the list of directories that are always excluded for builds

    1.17.1 - 2023-06-03

    Fixed:

    • Fix dev mode when the project has symlinks and file inclusion is defined with the packages or only-include options
    • Change the name of generated PTH files for dev mode so they come first lexicographically and therefore load first

    1.17.0 - 2023-05-12

    Added:

    • The app build target now embeds the project version in the name of binaries

    1.16.1 - 2023-05-11

    Fixed:

    • Fix determining the built executable path for the app build target option when using a local copy of PyApp when there is an explicit target triple set

    1.16.0 - 2023-05-11

    Added:

    • Add app build target option to build using a local copy of the PyApp repository

    1.15.0 - 2023-05-09

    Added:

    • Add app build target

    1.14.1 - 2023-04-23

    Fixed:

    • Fix internal archive root naming for the sdist target when strict-naming is disabled to match the file name in order to support the expectation of some frontends

    1.14.0 - 2023-04-02

    Added:

    • Add trove-classifiers as a dependency

    Fixed:

    • Properly normalize metadata descriptions that contain line breaks

    1.13.0 - 2023-02-09

    Added:

    • Update the set of known trove classifiers to version 2023.2.8

    1.12.2 - 2023-01-05

    Fixed:

    • Add macos-max-compat option to the wheel target that is enabled by default to support the latest version 22.0 of the packaging library

    1.12.1 - 2022-12-31

    Fixed:

    • Fix minor regression in the PEP 517/660 function signatures that was discovered by Fedora

    1.12.0 - 2022-12-30

    Added:

    • Improve readability of exceptions
    • Add extra_metadata build data to the wheel target
    • Retroactively support License-Expression core metadata starting at version 2.1
    • Add more type hints
    • Update the set of known trove classifiers to version 2022.12.22
    • Update SPDX license information to version 3.19
    • Store Hatchling's metadata in pyproject.toml

    Fixed:

    • Acknowledge the ARCHFLAGS environment variable on macOS for the wheel target when build hooks set the infer_tag build data to true
    • Fix dependency checking when encountering broken distributions
    • Fix the support-legacy option for the sdist target when using a src-layout project structure
    • Remove unnecessary encoding declaration in the default template for the version build hook

    1.11.1 - 2022-10-19

    Fixed:

    • Fix default file selection behavior of the wheel target when there is a single top-level module

    1.11.0 - 2022-10-08

    Added:

    • Add env version source to retrieve the version from an environment variable
    • Add validate-bump option to the standard version scheme

    Fixed:

    • Use proper CSV formatting for the RECORD metadata file of the wheel target to avoid warnings during installation by pip if, for example, file names contain commas
    • Fix installations with pip for build hooks that modify runtime dependencies
    • Decreasing verbosity now has no affect on output that should always be displayed

    1.10.0 - 2022-09-18

    Added:

    • Add the following to the list of directories that cannot be traversed: __pypackages__, .hg, .hatch, .tox, .nox
    • Add deprecated option to allow ambiguous features

    Fixed:

    • Improve tracking of dynamic metadata
    • Fix core metadata for entries in project.optional-dependencies that use direct references

    1.9.0 - 2022-09-09

    Changed:

    • File pattern matching now more closely resembles Git's behavior

    Added:

    • Implement a minimal version of prepare_metadata_for_build_wheel and prepare_metadata_for_build_editable for non-frontend tools that only need to inspect a project's metadata
    • Add metadata command to view PEP 621 project metadata
    • Improve error messages for SPDX license errors
    • Retroactively support License-File for core metadata starting at version 2.1
    • Bump the minimum supported version of pathspec to 0.10.1

    Fixed:

    • Allow the valid non-SPDX license values LicenseRef-Public-Domain and LicenseRef-Proprietary
    • Show the help text of the CLI when no subcommand is selected

    1.8.1 - 2022-08-25

    Fixed:

    • Fix default file inclusion for wheel build targets when both the project name and package directory name are not normalized

    1.8.0 - 2022-08-16

    Added:

    • Add get_known_classifiers method to metadata hooks

    Fixed:

    • Fix check for updating static versions with the version command when metadata hooks are in use

    1.7.1 - 2022-08-13

    Fixed:

    • Fix the value of the relative_path attribute of included files, that some build plugins may use, when selecting explicit paths

    1.7.0 - 2022-08-12

    Added:

    • Add require-runtime-features option for builders and build hooks
    • Check for unknown trove classifiers
    • Update SPDX license information to version 3.18

    Fixed:

    • Add better error message for wheel target dev mode installations that define path rewrites with the sources option
    • Note the allow-direct-references option in the relevant error messages

    1.6.0 - 2022-07-23

    Changed:

    • When no build targets are specified on the command line, now default to sdist and wheel targets rather than what happens to be defined in config
    • The code version source now only supports files with known extensions
    • Global build hooks now run before target-specific build hooks to better match expected behavior

    Added:

    • The code version source now supports loading extension modules
    • Add search-paths option for the code version source

    Fixed:

    • Fix removing sources using an empty string value in the mapping
    • The strict-naming option now also applies to the metadata directory of wheel targets

    1.5.0 - 2022-07-11

    Added:

    • Support the final draft of PEP 639
    • Add strict-naming option for sdist and wheel targets

    Fixed:

    • Project names are now stored in sdist and wheel target core metadata exactly as defined in pyproject.toml without normalization to allow control of how PyPI displays them

    1.4.1 - 2022-07-04

    Fixed:

    • Fix forced inclusion of important files like licenses for sdist targets when using the explicit selection options
    • Don't sort project URL metadata so that the rendered order on PyPI can be controlled

    1.4.0 - 2022-07-03

    Changed:

    • The packages option uses the new only-include option to provide targeted inclusion, since that is desired most of the time. You can retain the old behavior by using the include and sources options together.

    Added:

    • Support PEP 561 type hinting
    • Add version build hook
    • Add only-include option
    • The editable version of wheel targets now respects the force-include option by default
    • The force-include option now supports path rewriting with the sources option
    • The wheel target shared-data and extra-metadata options now respect file selection options
    • The wheel target now auto-detects single module layouts
    • Improve performance by never entering directories that are guaranteed to be undesirable like __pycache__ rather than excluding individual files within
    • Update SPDX license information to version 3.17

    Fixed:

    • Don't write empty entry points file for wheel targets if there are no entry points defined
    • Allow metadata hooks to set the version in all cases
    • Prevent duplicate file entries from inclusion when using the force-include option

    1.3.1 - 2022-05-30

    Fixed:

    • Better populate global variables for the code version source

    1.3.0 - 2022-05-22

    Removed:

    • Remove unused global args context string formatting field

    Added:

    • Improve error messages for the env context string formatting field

    Fixed:

    • Fix uri context string formatting modifier on Windows

    1.2.0 - 2022-05-20

    Added:

    • Allow context formatting for project.dependencies and project.optional-dependencies

    1.1.0 - 2022-05-19

    Added:

    • Add uri and real context string formatting modifiers for file system paths

    1.0.0 - 2022-05-17

    Changed:

    • Drop support for Python 2

    Added:

    • Improve error messaging for invalid versions
    • Update project metadata to reflect support for Python 3.11

    0.25.1 - 2022-06-14

    Fixed:

    • Fix support for Windows on Python 2 by removing its support for symlinks

    0.25.0 - 2022-05-15

    Added:

    • Add skip-excluded-dirs build option
    • Allow build data to add additional project dependencies for wheel and sdist build targets
    • Add force_include_editable build data for the wheel build target
    • Add build_hooks build data
    • Add support for Mercurial's .hgignore files when using glob syntax
    • Update project metadata to reflect the adoption by PyPA

    Fixed:

    • Properly use underscores for the name of force_include build data
    • No longer greedily skip excluded directories by default

    0.24.0 - 2022-04-28

    This is the initial public release of the Hatchling build system. Support for Python 2 will be dropped in version 1.

    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Hatchling history


    All notable changes to Hatchling will be documented in this file.

    The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

    Unreleased

    1.22.4 - 2024-03-23

    Fixed:

    • Only read source distribution metadata for fields that are explicitly defined as dynamic

    1.22.3 - 2024-03-19

    Fixed:

    • Fix the custom build hook when using dynamic dependencies

    1.22.2 - 2024-03-16

    Fixed:

    • Fix regression when loading metadata from source distributions
    • Fix metadata hooks when building wheels from source distributions

    1.22.1 - 2024-03-16

    Fixed:

    • Update the default version of core metadata to 2.3

    1.22.0 - 2024-03-16

    Deprecated:

    • The app build target has been renamed to binary to reduce ambiguity with the name of an upcoming feature. The former name will still be usable for several minor releases.

    Added:

    • Metadata for the wheel target now defaults to the PKG-INFO metadata within source distributions
    • Add dependencies method to the build hook interface so that hooks can themselves dynamically define dependencies
    • Update the default version of core metadata to 2.2
    • Update SPDX license information to version 3.23
    • Improve error message for when the default heuristics for wheel file inclusion fail

    Fixed:

    • Properly support core metadata version 2.2
    • Remove editables as a direct dependency
    • Fix default wheel tag when the supported Python version declaration is strict
    • Load VCS ignore patterns first so that whitelisted patterns can be excluded by project configuration
    • Don't consider VCS ignore files that are outside of the VCS boundary
    • The sdist build target now gracefully ignores UNIX socket files
    • Begin ignoring certain files ubiquitously, like .DS_Store on macOS

    1.21.1 - 2024-01-25

    Fixed:

    • Fix loading of local plugins to account for newly released versions of a dependency

    1.21.0 - 2023-12-18

    Added:

    • Add parent context modifier for path fields

    1.20.0 - 2023-12-13

    Added:

    • Add bypass-selection option to the wheel build target to allow for empty (metadata-only) wheels

    Fixed:

    • Fix regression in 1.19.1 that allowed exclude to count toward inclusion selection, thus bypassing the default inclusion selection heuristics
    • Fix writing optional dependency core metadata in situations where there are multiple environment markers

    1.19.1 - 2023-12-12

    Fixed:

    • Add better error message when the wheel build target cannot determine what to ship
    • Consider forced inclusion patterns and build-time artifacts as file selection since some build hooks generate the entire wheel contents without user configuration

    1.19.0 - 2023-12-11

    Changed:

    • An error will now be raised if a force-included path does not exist
    • An error will now be raised for the wheel build target if no file selection options are defined

    Added:

    • Officially support Python 3.12
    • Allow using an empty string for the sources option to add a prefix to distribution paths

    Fixed:

    • Properly handle non-zero version epoch for the standard version scheme
    • Fix the wheel build target for case insensitive file systems when the project metadata name does not match the directory name on disk
    • The app build target no longer has suppressed output
    • Prevent duplicate paths when projects require the sources option while build hooks overwrite included paths
    • Properly escape spaces for URI context formatting

    1.18.0 - 2023-06-12

    Changed:

    • Drop support for Python 3.7

    Added:

    • Update the list of directories that are always excluded for builds

    1.17.1 - 2023-06-03

    Fixed:

    • Fix dev mode when the project has symlinks and file inclusion is defined with the packages or only-include options
    • Change the name of generated PTH files for dev mode so they come first lexicographically and therefore load first

    1.17.0 - 2023-05-12

    Added:

    • The app build target now embeds the project version in the name of binaries

    1.16.1 - 2023-05-11

    Fixed:

    • Fix determining the built executable path for the app build target option when using a local copy of PyApp when there is an explicit target triple set

    1.16.0 - 2023-05-11

    Added:

    • Add app build target option to build using a local copy of the PyApp repository

    1.15.0 - 2023-05-09

    Added:

    • Add app build target

    1.14.1 - 2023-04-23

    Fixed:

    • Fix internal archive root naming for the sdist target when strict-naming is disabled to match the file name in order to support the expectation of some frontends

    1.14.0 - 2023-04-02

    Added:

    • Add trove-classifiers as a dependency

    Fixed:

    • Properly normalize metadata descriptions that contain line breaks

    1.13.0 - 2023-02-09

    Added:

    • Update the set of known trove classifiers to version 2023.2.8

    1.12.2 - 2023-01-05

    Fixed:

    • Add macos-max-compat option to the wheel target that is enabled by default to support the latest version 22.0 of the packaging library

    1.12.1 - 2022-12-31

    Fixed:

    • Fix minor regression in the PEP 517/660 function signatures that was discovered by Fedora

    1.12.0 - 2022-12-30

    Added:

    • Improve readability of exceptions
    • Add extra_metadata build data to the wheel target
    • Retroactively support License-Expression core metadata starting at version 2.1
    • Add more type hints
    • Update the set of known trove classifiers to version 2022.12.22
    • Update SPDX license information to version 3.19
    • Store Hatchling's metadata in pyproject.toml

    Fixed:

    • Acknowledge the ARCHFLAGS environment variable on macOS for the wheel target when build hooks set the infer_tag build data to true
    • Fix dependency checking when encountering broken distributions
    • Fix the support-legacy option for the sdist target when using a src-layout project structure
    • Remove unnecessary encoding declaration in the default template for the version build hook

    1.11.1 - 2022-10-19

    Fixed:

    • Fix default file selection behavior of the wheel target when there is a single top-level module

    1.11.0 - 2022-10-08

    Added:

    • Add env version source to retrieve the version from an environment variable
    • Add validate-bump option to the standard version scheme

    Fixed:

    • Use proper CSV formatting for the RECORD metadata file of the wheel target to avoid warnings during installation by pip if, for example, file names contain commas
    • Fix installations with pip for build hooks that modify runtime dependencies
    • Decreasing verbosity now has no affect on output that should always be displayed

    1.10.0 - 2022-09-18

    Added:

    • Add the following to the list of directories that cannot be traversed: __pypackages__, .hg, .hatch, .tox, .nox
    • Add deprecated option to allow ambiguous features

    Fixed:

    • Improve tracking of dynamic metadata
    • Fix core metadata for entries in project.optional-dependencies that use direct references

    1.9.0 - 2022-09-09

    Changed:

    • File pattern matching now more closely resembles Git's behavior

    Added:

    • Implement a minimal version of prepare_metadata_for_build_wheel and prepare_metadata_for_build_editable for non-frontend tools that only need to inspect a project's metadata
    • Add metadata command to view PEP 621 project metadata
    • Improve error messages for SPDX license errors
    • Retroactively support License-File for core metadata starting at version 2.1
    • Bump the minimum supported version of pathspec to 0.10.1

    Fixed:

    • Allow the valid non-SPDX license values LicenseRef-Public-Domain and LicenseRef-Proprietary
    • Show the help text of the CLI when no subcommand is selected

    1.8.1 - 2022-08-25

    Fixed:

    • Fix default file inclusion for wheel build targets when both the project name and package directory name are not normalized

    1.8.0 - 2022-08-16

    Added:

    • Add get_known_classifiers method to metadata hooks

    Fixed:

    • Fix check for updating static versions with the version command when metadata hooks are in use

    1.7.1 - 2022-08-13

    Fixed:

    • Fix the value of the relative_path attribute of included files, that some build plugins may use, when selecting explicit paths

    1.7.0 - 2022-08-12

    Added:

    • Add require-runtime-features option for builders and build hooks
    • Check for unknown trove classifiers
    • Update SPDX license information to version 3.18

    Fixed:

    • Add better error message for wheel target dev mode installations that define path rewrites with the sources option
    • Note the allow-direct-references option in the relevant error messages

    1.6.0 - 2022-07-23

    Changed:

    • When no build targets are specified on the command line, now default to sdist and wheel targets rather than what happens to be defined in config
    • The code version source now only supports files with known extensions
    • Global build hooks now run before target-specific build hooks to better match expected behavior

    Added:

    • The code version source now supports loading extension modules
    • Add search-paths option for the code version source

    Fixed:

    • Fix removing sources using an empty string value in the mapping
    • The strict-naming option now also applies to the metadata directory of wheel targets

    1.5.0 - 2022-07-11

    Added:

    • Support the final draft of PEP 639
    • Add strict-naming option for sdist and wheel targets

    Fixed:

    • Project names are now stored in sdist and wheel target core metadata exactly as defined in pyproject.toml without normalization to allow control of how PyPI displays them

    1.4.1 - 2022-07-04

    Fixed:

    • Fix forced inclusion of important files like licenses for sdist targets when using the explicit selection options
    • Don't sort project URL metadata so that the rendered order on PyPI can be controlled

    1.4.0 - 2022-07-03

    Changed:

    • The packages option uses the new only-include option to provide targeted inclusion, since that is desired most of the time. You can retain the old behavior by using the include and sources options together.

    Added:

    • Support PEP 561 type hinting
    • Add version build hook
    • Add only-include option
    • The editable version of wheel targets now respects the force-include option by default
    • The force-include option now supports path rewriting with the sources option
    • The wheel target shared-data and extra-metadata options now respect file selection options
    • The wheel target now auto-detects single module layouts
    • Improve performance by never entering directories that are guaranteed to be undesirable like __pycache__ rather than excluding individual files within
    • Update SPDX license information to version 3.17

    Fixed:

    • Don't write empty entry points file for wheel targets if there are no entry points defined
    • Allow metadata hooks to set the version in all cases
    • Prevent duplicate file entries from inclusion when using the force-include option

    1.3.1 - 2022-05-30

    Fixed:

    • Better populate global variables for the code version source

    1.3.0 - 2022-05-22

    Removed:

    • Remove unused global args context string formatting field

    Added:

    • Improve error messages for the env context string formatting field

    Fixed:

    • Fix uri context string formatting modifier on Windows

    1.2.0 - 2022-05-20

    Added:

    • Allow context formatting for project.dependencies and project.optional-dependencies

    1.1.0 - 2022-05-19

    Added:

    • Add uri and real context string formatting modifiers for file system paths

    1.0.0 - 2022-05-17

    Changed:

    • Drop support for Python 2

    Added:

    • Improve error messaging for invalid versions
    • Update project metadata to reflect support for Python 3.11

    0.25.1 - 2022-06-14

    Fixed:

    • Fix support for Windows on Python 2 by removing its support for symlinks

    0.25.0 - 2022-05-15

    Added:

    • Add skip-excluded-dirs build option
    • Allow build data to add additional project dependencies for wheel and sdist build targets
    • Add force_include_editable build data for the wheel build target
    • Add build_hooks build data
    • Add support for Mercurial's .hgignore files when using glob syntax
    • Update project metadata to reflect the adoption by PyPA

    Fixed:

    • Properly use underscores for the name of force_include build data
    • No longer greedily skip excluded directories by default

    0.24.0 - 2022-04-28

    This is the initial public release of the Hatchling build system. Support for Python 2 will be dropped in version 1.

    \ No newline at end of file diff --git a/1.9/how-to/config/dynamic-metadata/index.html b/1.9/how-to/config/dynamic-metadata/index.html new file mode 100644 index 000000000..77b890814 --- /dev/null +++ b/1.9/how-to/config/dynamic-metadata/index.html @@ -0,0 +1,30 @@ + How to configure custom dynamic metadata - Hatch

    How to configure custom dynamic metadata


    If you have project metadata that is not appropriate for static entry into pyproject.toml you will need to provide a custom metadata hook to apply such data during builds.

    Alternatives

    Dynamic metadata is a way to have a single source of truth that will be available at build time and at run time. Another way to achieve that is to enter the build data statically and then look up the same information dynamically in the program or package, using importlib.metadata.

    If the version field is the only metadata of concern, Hatchling provides a few built-in ways such as the regex version source and also third-party plugins. The approach here will also work, but is more complex.

    Update project metadata

    Change the [project] section of pyproject.toml:

    1. Define the dynamic field as an array of all the fields you will set dynamically e.g. dynamic = ["version", "license", "authors", "maintainers"]
    2. If any of those fields have static definitions in pyproject.toml, delete those definitions. It is verboten to define a field statically and dynamically.

    Add a section to trigger loading of dynamic metadata plugins: [tool.hatch.metadata.hooks.custom]. Use exactly that name, regardless of the name of the class you will use or its PLUGIN_NAME. There doesn't need to be anything in the section.

    If your plugin requires additional third-party packages to do its work, add them to the requires array in the [build-system] section of pyproject.toml.

    Implement hook

    The dynamic lookup must happen in a custom plugin that you write. The default expectation is that it is in a hatch_build.py file at the root of the project. Subclass MetadataHookInterface and implement update(); for example, here's plugin that reads metadata from a JSON file:

    import json
    +import os
    +
    +from hatchling.metadata.plugin.interface import MetadataHookInterface
    +
    +
    +class JSONMetaDataHook(MetadataHookInterface):
    +    def update(self, metadata):
    +        src_file = os.path.join(self.root, "gnumeric", ".constants.json")
    +        with open(src_file) as src:
    +            constants = json.load(src)
    +            metadata["version"] = constants["__version__"]
    +            metadata["license"] = constants["__license__"]
    +            metadata["authors"] = [
    +                {"name": constants["__author__"], "email": constants["__author_email__"]},
    +            ]
    +
    1. You must import the MetadataHookInterface to subclass it.
    2. Do your operations inside the update method.
    3. metadata refers to project metadata.
    4. When writing to metadata, use list for TOML arrays. Note that if a list is expected, it is required even if there is a single element.
    5. Use dict for TOML tables e.g. authors.

    If you want to store the hook in a different location, set the path option:

    [tool.hatch.metadata.hooks.custom]
    +path = "some/where.py"
    +
    [metadata.hooks.custom]
    +path = "some/where.py"
    +
    \ No newline at end of file diff --git a/1.9/how-to/environment/package-indices/index.html b/1.9/how-to/environment/package-indices/index.html index c6987637e..491b9ccf4 100644 --- a/1.9/how-to/environment/package-indices/index.html +++ b/1.9/how-to/environment/package-indices/index.html @@ -1,4 +1,4 @@ - Package indices - Hatch

    Package indices


    Most Hatch environment types, like the default virtual, simply use pip to install dependencies. Therefore, you can use the standard environment variables that influence pip's behavior to choose where to search for packages.

    Here's an example of setting up the default environment to look at 2 private indices (using context formatting for authentication) before finally falling back to PyPI:

    [tool.hatch.envs.default.env-vars]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    How to configure package indices


    Most Hatch environment types, like the default virtual, simply use pip to install dependencies. Therefore, you can use the standard environment variables that influence pip's behavior to choose where to search for packages.

    Here's an example of setting up the default environment to look at 2 private indices (using context formatting for authentication) before finally falling back to PyPI:

    [tool.hatch.envs.default.env-vars]
     PIP_INDEX_URL = "https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/"
     PIP_EXTRA_INDEX_URL = "https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/"
     
    [envs.default.env-vars]
     PIP_INDEX_URL = "https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/"
     PIP_EXTRA_INDEX_URL = "https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/"
    -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/1.9/how-to/meta/report-issues/index.html b/1.9/how-to/meta/report-issues/index.html new file mode 100644 index 000000000..c01f481aa --- /dev/null +++ b/1.9/how-to/meta/report-issues/index.html @@ -0,0 +1,13 @@ + How to report issues - Hatch

    How to report issues


    All reports regarding unexpected behavior should be generated with the self report command:

    $ hatch self report
    +

    By default, this will open a new tab in your default browser with pre-populated information about your environment.

    If Hatch is not installed alongside a web browser, you may also pass the --no-open/-n command which will output the URL with correct parameters for copying elsewhere:

    $ hatch self report -n
    +https://github.com/pypa/hatch/issues/new?body=%23%23+Current+behavior%0A%3C%21--+A+clear+and+concise+description+of+the+behavior.+--%3E%0A%0A%23%23+Expected+behavior%0A%3C%21--+A+clear+and+concise+description+of+what+you+expected+to+happen.+--%3E%0A%0A%23%23+Additional+context%0A%3C%21--+Add+any+other+context+about+the+problem+here.+If+applicable%2C+add+screenshots+to+help+explain.+--%3E%0A%0A%23%23+Debug%0A%0A%23%23%23+Installation%0A%0A-+Source%3A+pip%0A-+Version%3A+1.9.2.dev5%0A-+Platform%3A+Windows%0A-+Python+version%3A%0A++++%60%60%60%0A++++3.11.1+%28tags%2Fv3.11.1%3Aa7a450f%2C+Dec++6+2022%2C+19%3A58%3A39%29+%5BMSC+v.1934+64+bit+%28AMD64%29%5D%0A++++%60%60%60%0A%0A%23%23%23+Configuration%0A%0A%60%60%60toml%0Amode+%3D+%22local%22%0Ashell+%3D+%22nu%22%0A%60%60%60%0A
    +
    \ No newline at end of file diff --git a/1.9/how-to/plugins/testing-builds/index.html b/1.9/how-to/plugins/testing-builds/index.html index 75bde32e8..9ac8ce8ff 100644 --- a/1.9/how-to/plugins/testing-builds/index.html +++ b/1.9/how-to/plugins/testing-builds/index.html @@ -1,4 +1,4 @@ - Testing builds - Hatch

    Testing builds


    For testing Hatchling plugins, you'll usually want to generate a project to execute builds as a real user would. For example, as a minimal pytest fixture:

    from pathlib import Path
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Testing build plugins


    For testing Hatchling plugins, you'll usually want to generate a project to execute builds as a real user would. For example, as a minimal pytest fixture:

    from pathlib import Path
     
     import pytest
     
    @@ -68,4 +68,4 @@
             encoding='utf-8',
         )
         ...
    -

    Note

    This example chooses to ignore copying .git for performance reasons. You may want to ignore more patterns, or copy only specific paths like this plugin does.

    \ No newline at end of file +

    Note

    This example chooses to ignore copying .git for performance reasons. You may want to ignore more patterns, or copy only specific paths like this plugin does.

    \ No newline at end of file diff --git a/1.9/how-to/publish/auth/index.html b/1.9/how-to/publish/auth/index.html new file mode 100644 index 000000000..13cbd710b --- /dev/null +++ b/1.9/how-to/publish/auth/index.html @@ -0,0 +1,10 @@ + How to authenticate for index publishing - Hatch

    How to authenticate for index publishing


    The username is derived from the following sources, in order of precedence:

    1. The --user / -u cli option.
    2. The HATCH_INDEX_USER environment variable.
    3. The repos tables.
    4. The ~/.pypirc file.
    5. The input to an interactive prompt.

    As a fallback the value __token__ is applied.

    The password is looked up in these:

    1. The ~/.pypirc file if the username was provided by it.
    2. The --auth / -a cli option.
    3. The HATCH_INDEX_AUTH environment variable.
    4. The repos tables.
    5. A variety of OS-level credentials services backed by keyring.
    6. The input to an interactive prompt.

    If interactively provided credentials were used, the username will be stored in Hatch's cache and the password stored in the available keyring backed credentials stores.

    For automated releasing to PyPI, it is recommended to use "Trusted Publishing" with OIDC (e.g. PyPA's pypi-publish GitHub Action) or per-project API tokens.

    \ No newline at end of file diff --git a/1.9/how-to/publish/repo/index.html b/1.9/how-to/publish/repo/index.html new file mode 100644 index 000000000..db6f49e4e --- /dev/null +++ b/1.9/how-to/publish/repo/index.html @@ -0,0 +1,13 @@ + How to configure repositories for index publishing - Hatch

    How to configure repositories for index publishing


    You can select the repository with which to upload using the -r/--repo option or by setting the HATCH_INDEX_REPO environment variable.

    Rather than specifying the full URL of a repository, you can use a named repository from a publish.index.repos table defined in Hatch's config file:

    [publish.index.repos.private]
    +url = "..."
    +...
    +

    The following repository names are reserved by Hatch and cannot be overridden:

    Name Repository
    main https://upload.pypi.org/legacy/
    test https://test.pypi.org/legacy/

    The main repository is used by default.

    \ No newline at end of file diff --git a/1.9/how-to/static-analysis/behavior/index.html b/1.9/how-to/static-analysis/behavior/index.html new file mode 100644 index 000000000..7f75584af --- /dev/null +++ b/1.9/how-to/static-analysis/behavior/index.html @@ -0,0 +1,38 @@ + Customize static analysis behavior - Hatch

    Customize static analysis behavior


    You can fully alter the static analysis performed by the fmt command by modifing the reserved environment named hatch-static-analysis. For example, you could define the following if you wanted to replace the default behavior with a mix of Black, isort and basic flake8:

    [tool.hatch.envs.hatch-static-analysis]
    +dependencies = ["black", "flake8", "isort"]
    +
    +[tool.hatch.envs.hatch-static-analysis.scripts]
    +format-check = [
    +  "black --check --diff {args:.}",
    +  "isort --check-only --diff {args:.}",
    +]
    +format-fix = [
    +  "isort {args:.}",
    +  "black {args:.}",
    +]
    +lint-check = "flake8 {args:.}"
    +lint-fix = "lint-check"
    +
    [envs.hatch-static-analysis]
    +dependencies = ["black", "flake8", "isort"]
    +
    +[envs.hatch-static-analysis.scripts]
    +format-check = [
    +  "black --check --diff {args:.}",
    +  "isort --check-only --diff {args:.}",
    +]
    +format-fix = [
    +  "isort {args:.}",
    +  "black {args:.}",
    +]
    +lint-check = "flake8 {args:.}"
    +lint-fix = "lint-check"
    +

    The format-* scripts correspond to the --formatter/-f flag while the lint-* scripts correspond to the --linter/-l flag. The *-fix scripts run by default while the *-check scripts correspond to the --check flag. Based on this example, the following shows how the various scripts influence behavior:

    Command Expanded scripts
    hatch fmt
    • flake8 .
    • isort .
    • black .
    hatch fmt src tests
    • flake8 src tests
    • isort src tests
    • black src tests
    hatch fmt -f
    • isort .
    • black .
    hatch fmt -l
    • flake8 .
    hatch fmt --check
    • flake8 .
    • black --check --diff .
    • isort --check-only --diff .
    hatch fmt --check -f
    • black --check --diff .
    • isort --check-only --diff .
    hatch fmt --check -l
    • flake8 .
    \ No newline at end of file diff --git a/1.9/index.html b/1.9/index.html index b3835073c..6a322f66a 100644 --- a/1.9/index.html +++ b/1.9/index.html @@ -1,4 +1,4 @@ - About - Hatch

    Hatch

    Hatch logo

    CI/CD CI - Test CD - Build Hatch CD - Build Hatchling
    Docs Docs - Release Docs - Dev
    Package PyPI - Version PyPI - Downloads PyPI - Python Version
    Meta Hatch project linting - Ruff types - Mypy License - MIT GitHub Sponsors

    Hatch is a modern, extensible Python project manager. See the Why Hatch? page for more information.

    • Build system


      Reproducible builds by default with a rich ecosystem of plugins

      Configure builds

    • Environments


      Robust environment management with support for custom scripts

      Getting started

    • Python management


      Choose between easy manual installations or automatic as part of environments

      Try it

    • Static analysis


      Static analysis backed by Ruff with up-to-date, sane defaults

      Learn

    • Publishing


      Easily upload to PyPI or other indices

      See how

    • Versioning


      Streamlined workflow for bumping versions

      Managing versions

    • Project generation


      Create new projects from templates with known best practices

      Project setup

    • Responsive CLI


      Hatch is up to 3x faster than equivalent tools

      CLI reference

    License

    Hatch is distributed under the terms of the MIT license.

    Documentation for specific MAJOR.MINOR versions can be chosen by using the dropdown on the top of every page. The dev version reflects changes that have not yet been released.

    Also, desktop readers can use special keyboard shortcuts:

    Keys Action
    • , (comma)
    • p
    Navigate to the "previous" page
    • . (period)
    • n
    Navigate to the "next" page
    • /
    • s
    Display the search modal
    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Hatch

    Hatch logo

    CI/CD CI - Test CD - Build Hatch CD - Build Hatchling
    Docs Docs - Release Docs - Dev
    Package PyPI - Version PyPI - Downloads PyPI - Python Version
    Meta Hatch project linting - Ruff types - Mypy License - MIT GitHub Sponsors

    Hatch is a modern, extensible Python project manager. See the Why Hatch? page for more information.

    • Build system


      Reproducible builds by default with a rich ecosystem of plugins

      Configure builds

    • Environments


      Robust environment management with support for custom scripts

      Getting started

    • Python management


      Choose between easy manual installations or automatic as part of environments

      Try it

    • Static analysis


      Static analysis backed by Ruff with up-to-date, sane defaults

      Learn

    • Publishing


      Easily upload to PyPI or other indices

      See how

    • Versioning


      Streamlined workflow for bumping versions

      Managing versions

    • Project generation


      Create new projects from templates with known best practices

      Project setup

    • Responsive CLI


      Hatch is up to 3x faster than equivalent tools

      CLI reference

    License

    Hatch is distributed under the terms of the MIT license.

    Documentation for specific MAJOR.MINOR versions can be chosen by using the dropdown on the top of every page. The dev version reflects changes that have not yet been released.

    Also, desktop readers can use special keyboard shortcuts:

    Keys Action
    • , (comma)
    • p
    Navigate to the "previous" page
    • . (period)
    • n
    Navigate to the "next" page
    • /
    • s
    Display the search modal
    \ No newline at end of file diff --git a/1.9/install/index.html b/1.9/install/index.html index d738bfec7..d0a3c6fe5 100644 --- a/1.9/install/index.html +++ b/1.9/install/index.html @@ -7,18 +7,19 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Installation


    Installers

    1. In your browser, download the .pkg file: hatch-1.9.4.pkg
    2. Run your downloaded file and follow the on-screen instructions.
    3. Restart your terminal.
    4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

      $ hatch --version
      -1.9.4
      -
    1. Download the file using the curl command. The -o option specifies the file name that the downloaded package is written to. In this example, the file is written to hatch-1.9.4.pkg in the current directory.

      curl -o hatch-1.9.4.pkg https://github.com/pypa/hatch/releases/download/hatch-v1.9.4/hatch-1.9.4.pkg
      -
    2. Run the standard macOS installer program, specifying the downloaded .pkg file as the source. Use the -pkg parameter to specify the name of the package to install, and the -target / parameter for the drive in which to install the package. The files are installed to /usr/local/hatch, and an entry is created at /etc/paths.d/hatch that instructs shells to add the /usr/local/hatch directory to. You must include sudo on the command to grant write permissions to those folders.

      sudo installer -pkg ./hatch-1.9.4.pkg -target /
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Installation


      Installers

      1. In your browser, download the .pkg file: hatch-1.9.1.pkg
      2. Run your downloaded file and follow the on-screen instructions.
      3. Restart your terminal.
      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version
        +1.9.1
        +
      1. Download the file using the curl command. The -o option specifies the file name that the downloaded package is written to. In this example, the file is written to hatch-1.9.1.pkg in the current directory.

        curl -o hatch-1.9.1.pkg https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1.pkg
        +
      2. Run the standard macOS installer program, specifying the downloaded .pkg file as the source. Use the -pkg parameter to specify the name of the package to install, and the -target / parameter for the drive in which to install the package. The files are installed to /usr/local/hatch, and an entry is created at /etc/paths.d/hatch that instructs shells to add the /usr/local/hatch directory to. You must include sudo on the command to grant write permissions to those folders.

        sudo installer -pkg ./hatch-1.9.1.pkg -target /
         
      3. Restart your terminal.

      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version
        -1.9.4
        -
      1. In your browser, download one the .msi files:
      2. Run your downloaded file and follow the on-screen instructions.
      3. Restart your terminal.
      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version
        -1.9.4
        -
      1. Download and run the installer using the standard Windows msiexec program, specifying one of the .msi files as the source. Use the /passive and /i parameters to request an unattended, normal installation.

        msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.4/hatch-1.9.4-x64.msi
        +1.9.1
        +
      1. In your browser, download one the .msi files:
      2. Run your downloaded file and follow the on-screen instructions.
      3. Restart your terminal.
      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version
        +1.9.1
        +
      1. Download and run the installer using the standard Windows msiexec program, specifying one of the .msi files as the source. Use the /passive and /i parameters to request an unattended, normal installation.

        msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1-x64.msi
        +
        msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1-x86.msi
         
      2. Restart your terminal.

      3. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version
        -1.9.4
        -

      Standalone binaries

      After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to hatch.

      pip

      Hatch is available on PyPI and can be installed with pip.

      pip install hatch
      +1.9.1
      +

    Standalone binaries

    After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to hatch.

    pip

    Hatch is available on PyPI and can be installed with pip.

    pip install hatch
     

    Warning

    This method modifies the Python environment in which you choose to install. Consider instead using pipx to avoid dependency conflicts.

    pipx

    pipx allows for the global installation of Python applications in isolated environments.

    pipx install hatch
     

    Homebrew

    See the formula for more details.

    brew install hatch
     

    Conda

    See the feedstock for more details.

    conda install -c conda-forge hatch
    @@ -26,4 +27,4 @@
     

    Warning

    This method modifies the Conda environment in which you choose to install. Consider instead using pipx or condax to avoid dependency conflicts.

    MacPorts

    See the port for more details.

    sudo port install hatch
     

    Fedora

    The minimum supported version is 37, currently in development as Rawhide.

    sudo dnf install hatch
     

    Void Linux

    xbps-install hatch
    -

    Build system availability

    Hatchling is Hatch's build backend which you will never need to install manually. See its changelog for version information.

    Packaging status

    \ No newline at end of file +

    Build system availability

    Hatchling is Hatch's build backend which you will never need to install manually. See its changelog for version information.

    Packaging status

    \ No newline at end of file diff --git a/1.9/intro/index.html b/1.9/intro/index.html index 8ad713a3e..5408c51fe 100644 --- a/1.9/intro/index.html +++ b/1.9/intro/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Introduction


    Setup

    Projects can be set up for use by Hatch using the new command.

    New project

    Let's say you want to create a project named Hatch Demo. You would run:

    hatch new "Hatch Demo"
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Introduction


    Setup

    Projects can be set up for use by Hatch using the new command.

    New project

    Let's say you want to create a project named Hatch Demo. You would run:

    hatch new "Hatch Demo"
     

    This would create the following structure in your current working directory:

    hatch-demo
     ├── src
     │   └── hatch_demo
    diff --git a/1.9/meta/authors/index.html b/1.9/meta/authors/index.html
    index 057a836bf..1d62e8f64 100644
    --- a/1.9/meta/authors/index.html
    +++ b/1.9/meta/authors/index.html
    @@ -7,4 +7,4 @@
         .gdesc-inner { font-size: 0.75rem; }
         body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
         body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
    -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Authors


    Maintainers

    • Ofek Lev

    Contributors

    • Amjith Ramanujam
    • Arnaud Crowther
    • Chaojie
    • Chris Warrick
    • Lumír 'Frenzy' Balhar
    • Ofek Lev
    • Olga Matoula
    • Philip Blair
    • Robert Rosca
    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Authors


    Maintainers

    • Ofek Lev

    Contributors

    • Amjith Ramanujam
    • Arnaud Crowther
    • Chaojie
    • Chris Warrick
    • Lumír 'Frenzy' Balhar
    • Ofek Lev
    • Olga Matoula
    • Philip Blair
    • Robert Rosca
    \ No newline at end of file diff --git a/1.9/meta/faq/index.html b/1.9/meta/faq/index.html index 04e117653..3fb876c9a 100644 --- a/1.9/meta/faq/index.html +++ b/1.9/meta/faq/index.html @@ -1,4 +1,4 @@ - FAQ - Hatch

    FAQ


    Interoperability

    Q: What is the risk of lock-in?

    A: Not much! Other than the plugin system, everything uses Python's established standards by default. Project metadata is based entirely on the standard, the build system is compatible with PEP 517/PEP 660, versioning uses the scheme specified by PEP 440, dependencies are defined with PEP 508 strings, and environments use virtualenv.

    Q: Must one use all features?

    A: No, all features are optional! You can use just the build system, publish wheels and source distributions that were built by other tools, only use the environment management, etc.

    Libraries vs applications

    Q: Are workflows for both libraries and applications supported?

    A: Yes, mostly! Applications can utilize environment management just like libraries, and plugins can be used to build projects in arbitrary formats or publish artifacts to arbitrary destinations.

    The only caveat is that currently there is no support for re-creating an environment given a set of dependencies in a reproducible manner. Although a standard lock file format may be far off since [PEP 665][] was rejected, resolving capabilities are coming to pip. When that is stabilized, Hatch will add locking functionality and dedicated documentation for managing applications.

    Tool migration

    Q: How to migrate to Hatch?

    Build system

    import os
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    FAQ


    Interoperability

    Q: What is the risk of lock-in?

    A: Not much! Other than the plugin system, everything uses Python's established standards by default. Project metadata is based entirely on the standard, the build system is compatible with PEP 517/PEP 660, versioning uses the scheme specified by PEP 440, dependencies are defined with PEP 508 strings, and environments use virtualenv.

    Q: Must one use all features?

    A: No, all features are optional! You can use just the build system, publish wheels and source distributions that were built by other tools, only use the environment management, etc.

    Libraries vs applications

    Q: Are workflows for both libraries and applications supported?

    A: Yes, mostly! Applications can utilize environment management just like libraries, and plugins can be used to build projects in arbitrary formats or publish artifacts to arbitrary destinations.

    The only caveat is that currently there is no support for re-creating an environment given a set of dependencies in a reproducible manner. Although a standard lock file format may be far off since PEP 665 was rejected, resolving capabilities are coming to pip. When that is stabilized, Hatch will add locking functionality and dedicated documentation for managing applications.

    Tool migration

    Q: How to migrate to Hatch?

    Build system

    import os
     from io import open
     
     from setuptools import find_packages, setup
    @@ -174,4 +174,4 @@
     python = ["3.8", "3.9"]
     version = ["9000"]
     features = ["foo", "bar"]
    -

    Fast CLI?

    The claim about being faster than other tools is based on timings that are always checked in CI.

    Hatch achieves this by using lazy imports, lazily performing computation manually and with functools.cached_property, using hacks like not not ... instead of bool(...), etc.

    \ No newline at end of file +

    Fast CLI?

    The claim about being faster than other tools is based on timings that are always checked in CI.

    Hatch achieves this by using lazy imports, lazily performing computation manually and with functools.cached_property, using hacks like not not ... instead of bool(...), etc.

    \ No newline at end of file diff --git a/1.9/next-steps/index.html b/1.9/next-steps/index.html index a0857c59a..1c0dc622b 100644 --- a/1.9/next-steps/index.html +++ b/1.9/next-steps/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Next steps


    Learn more

    At this point you should have a basic understanding of how to use Hatch.

    Now you may want to check out advanced configuration for environments or builds, set up your preferred shell, or read more about Hatch's CLI.

    After that, check out the Hatch Showcase project to see examples of what is possible.

    Finally, if you see a need, feel free to write a plugin for extended functionality.

    Community

    For any projects using Hatch, you may add its official badge somewhere prominent like the README.

    Hatch project

    [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Next steps


    Learn more

    At this point you should have a basic understanding of how to use Hatch.

    Now you may want to check out advanced configuration for environments or builds, set up your preferred shell, or read more about Hatch's CLI.

    After that, check out the Hatch Showcase project to see examples of what is possible.

    Finally, if you see a need, feel free to write a plugin for extended functionality.

    Community

    For any projects using Hatch, you may add its official badge somewhere prominent like the README.

    Hatch project

    [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
     
    .. image:: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg
        :alt: Hatch project
        :target: https://github.com/pypa/hatch
    diff --git a/1.9/objects.inv b/1.9/objects.inv
    index daedd3f68ad49b92da47455de40e53e5c73cc48b..11ee19d74ee607034e3bc4754493b6980812bf23 100644
    GIT binary patch
    delta 1311
    zcmV+)1>pL|3Wp1jd4HQrZ`?Kz$M5|V2AZp7^qN~5q-}sEFi^Btf=i7gW+{^3L$>ni
    zOX{(!)T`Gn$?eIu9{(SQ9L@|$xx$828So|}f-xXQD4j`WOUg6K4X6SW$UgCgD#2^u
    z=HvL-=ke}?Y~K@xwSM^Jp?_09!TE*9lkk&*0u*opPd~qVcz^tKgML4M{fzaJ^Oyz|clnH$D2%9Dj^VV%z|hRE~2qA>Jp(1j#{tzsEML-OinTTvq81UAua{{
    zZ%9|bSp2?oPrB4Yn2m2$<6JNisKH7{r<_uEx(S`CNGNEEMB=w9l2rsAHn;{7GEE^n
    zVd^xr-hVP=TA8A79!rm5nUEZarU5xJSqr!PfgGi*O1=q~w8z>Rt1`ima$HA_&(igy
    z-&jjSi5!p>)S^k?er_EsSOcRoByfcFUE7-pmiH^Ce&;r_IS$s9RO!}9`gmTQ#qCL7
    z*T1Pkt}#y91Eacni+%2I!19Th9G|*beP#1HAb;rcmU2J6
    zn%!Lqi5gOT5>|g{X4V7*%>>mIf+`B|1%`}#He-`TQpNV?b32fJcC}SsY3Q*e~^jX52WoO
    z;D2~m;&zJ}<@WVfks1@BZx#``WpJ}h2siNcNm
    zCFs!Vi~F%xtM+?MzLXCsyRemXr6eu6aAjRX0ya~Ds~U1k=;bxWm8xz6Yd7TAwX+i9
    zc;RETj_`-Ox42a8R35#=#hUv{(#oz-MaMWPZ0cy7Z!7BaDk8-Mn1
    zVv!d@P$cB|>1H{dSHQo7UgR(0>}V!L{7GZmPjx@5yhC_%hsCEu2S*l@zj*v=Zne
    zL1#xO63-9hk&74J2QpgF`F|~m)Px!Lk3_RFpZ}zCBXfvLnI;v~@Rs~ffB&!U_M+u!=0OyW86wt9vvwajRp+fv-DO92oAjBv~lF
    VBDZ4Az2i{z+4if<{udBwwGLk8jjI3v
    
    delta 1245
    zcmV<31S0!~3&skNd4HNqkK`s0$M5+RBPG}IDA(LJt4*>}b~RFzToH}SHrp5w5BGFF
    zeZbh=olN`H4RlWPu>Jp0P!v^VH`tJ-0NxcuFb2d3r3=YyO?g4N0aalF#V6iTC3p+m
    zd>n84JYId0$DatpT0i~x6rR*CaDL$VB>bYF0tKAF%lAJ#J%4}K+|MpvfB*B>&tK8k
    z4_`j{abRQABZff)uW0?q5mc08M*jwM9!h07F;wt}4(EcXA3dlV45FMGirN2Unv@VG
    zhSxa3H}h{+|F2(!YMnNyYn#*>%G_jtzCo|3#^0t^by9t9iq-~|>A6^?zCLW+3&L(%
    zI&5Is(e5TmnSa<6DcKQKfQ?n4(;Kw2l$Dq9;{iwnZ&aHM#*zle-UX#rVncU+=NvOY
    zMcZOtqG7-104^Vs5g6JiOAHFDIT)G6xB)DwbmxpVn6Zp_1zF-ui48_2RsETCOuLpP
    zEx8t(VcHY=SmV>QI+8!@l{f`jKISN*FfSFE3z?l9$K&r
    znWM~+IFG4^RN|XErLzOkWk60$)`Ge0phP*dl5fHt+GFmFRh?l;Ic^ijXX)nA*YtTP
    zi375NR)2IE+|Sj)f^{%DLk34!ZW!H7usl>wp=p%Z90%)Ds(f{l-k+5-Mz&IhWc0S&~g+t}HX?Kur_V^6=gRxgSW|UBoqN#MKmUlLn*QzTGR*
    zVj}e2BBHbm?v|OzdpBwL93!Fw99$7D4r?uQD^eFbMa#NB(~1vLGD`4R=&lJAGZF>f
    z34gU^7u+j))Z0lTMo9bHxNc&Z(!ozTNu
    zr`3KP$^<>U*C~Due}6pX2J78>PU&E;q6->dTyS*_rmwjgqwH!lhyzi8xFJE`Mt%Euq)zf*V!c2G(xLZyRSL#Qw^+D?Q;i
    zcWt)3>{Xt<#MM0cM$$s5nFxBl>`Vk3-%n3eQi-U90iJ5Ir$S~naV`)fLXO|N<(=5!
    zW47$viGn#1&0ytUqD<5Ro1oWm3;na<=@{~BqFN-DbSI8g8pb5QL=|O_!_>K090@T5;0T)|
    zG*!IVWfqJKZ9yB{%B|H)3kG{nes9E=;mTtAI!Y`YAsa~xfj$v*a)lD{{6g-zIPeh2
    zXho;L2TwGF3HMJ#v$CB27;zsV>v%Z` About - Hatch      

    Plugins


    Hatch utilizes pluggy for its plugin functionality.

    Overview

    All plugins provide registration hooks that return one or more classes that inherit from a particular type interface.

    Each registration hook must be decorated by Hatch's hook marker. For example, if you wanted to create a new kind of environment you could do:

    from hatchling.plugin import hookimpl
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Plugins


    Hatch utilizes pluggy for its plugin functionality.

    Overview

    All plugins provide registration hooks that return one or more classes that inherit from a particular type interface.

    Each registration hook must be decorated by Hatch's hook marker. For example, if you wanted to create a new kind of environment you could do:

    from hatchling.plugin import hookimpl
     
     from .plugin import SpecialEnvironment
     
    diff --git a/1.9/plugins/build-hook/custom/index.html b/1.9/plugins/build-hook/custom/index.html
    index c32ff44b4..1b15bb555 100644
    --- a/1.9/plugins/build-hook/custom/index.html
    +++ b/1.9/plugins/build-hook/custom/index.html
    @@ -1,4 +1,4 @@
    - Custom - Hatch      

    Custom build hook


    This is a custom class in a given Python file that inherits from the BuildHookInterface.

    Configuration

    The build hook plugin name is custom.

    [tool.hatch.build.hooks.custom]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Custom build hook


    This is a custom class in a given Python file that inherits from the BuildHookInterface.

    Configuration

    The build hook plugin name is custom.

    [tool.hatch.build.hooks.custom]
     [tool.hatch.build.targets.<TARGET_NAME>.hooks.custom]
     
    [build.hooks.custom]
     [build.targets.<TARGET_NAME>.hooks.custom]
    diff --git a/1.9/plugins/build-hook/reference/index.html b/1.9/plugins/build-hook/reference/index.html
    index fc2b976e1..254b1d284 100644
    --- a/1.9/plugins/build-hook/reference/index.html
    +++ b/1.9/plugins/build-hook/reference/index.html
    @@ -1,4 +1,4 @@
    - Reference - Hatch      

    Build hook plugins


    A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.

    Known third-party

    Overview

    Build hooks run for every selected version of build targets.

    The initialization stage occurs immediately before each build and the finalization stage occurs immediately after. Each stage has the opportunity to view or modify build data.

    Build data

    Build data is a simple mapping whose contents can influence the behavior of builds. Which fields exist and are recognized depends on each build target.

    The following fields are always present and recognized by the build system itself:

    Field Type Description
    artifacts list[str] This is a list of extra artifact patterns and should generally only be appended to
    force_include dict[str, str] This is a mapping of extra forced inclusion paths, with this mapping taking precedence in case of conflicts
    build_hooks tuple[str, ...] This is an immutable sequence of the names of the configured build hooks and matches the order in which they run

    Attention

    While user-facing TOML options are hyphenated, build data fields should be named with underscores to allow plugins to use them as valid Python identifiers.

    Notes

    In some cases it may be necessary to use force_include rather than artifacts. For example, say that you want to install a lib.so directly at the root of site-packages and a project defines a package src/foo. If you create src/lib.so, there will never be a match because the directory traversal starts at src/foo rather than src. In that case you must do either:

    build_data['force_include']['src/lib.so'] = 'src/lib.so'
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Build hook plugins


    A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.

    Known third-party

    Overview

    Build hooks run for every selected version of build targets.

    The initialization stage occurs immediately before each build and the finalization stage occurs immediately after. Each stage has the opportunity to view or modify build data.

    Build data

    Build data is a simple mapping whose contents can influence the behavior of builds. Which fields exist and are recognized depends on each build target.

    The following fields are always present and recognized by the build system itself:

    Field Type Description
    artifacts list[str] This is a list of extra artifact patterns and should generally only be appended to
    force_include dict[str, str] This is a mapping of extra forced inclusion paths, with this mapping taking precedence in case of conflicts
    build_hooks tuple[str, ...] This is an immutable sequence of the names of the configured build hooks and matches the order in which they run

    Attention

    While user-facing TOML options are hyphenated, build data fields should be named with underscores to allow plugins to use them as valid Python identifiers.

    Notes

    In some cases it may be necessary to use force_include rather than artifacts. For example, say that you want to install a lib.so directly at the root of site-packages and a project defines a package src/foo. If you create src/lib.so, there will never be a match because the directory traversal starts at src/foo rather than src. In that case you must do either:

    build_data['force_include']['src/lib.so'] = 'src/lib.so'
     

    or

    build_data['force_include']['/absolute/path/to/src/lib.so'] = 'src/lib.so'
     

    BuildHookInterface

    Example usage:

    from hatchling.builders.hooks.plugin.interface import BuildHookInterface
     
    @@ -126,48 +126,73 @@
             """
             return self.__target_name
     
    -    def clean(self, versions: list[str]) -> None:
    +    def dependencies(self) -> list[str]:  # noqa: PLR6301
             """
    -        This occurs before the build process if the `-c`/`--clean` flag was passed to
    -        the [`build`](../../cli/reference.md#hatch-build) command, or when invoking
    -        the [`clean`](../../cli/reference.md#hatch-clean) command.
    -        """
    -
    -    def initialize(self, version: str, build_data: dict[str, Any]) -> None:
    -        """
    -        This occurs immediately before each build.
    -
    -        Any modifications to the build data will be seen by the build target.
    -        """
    -
    -    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
    -        """
    -        This occurs immediately after each build and will not run if the `--hooks-only` flag
    -        was passed to the [`build`](../../cli/reference.md#hatch-build) command.
    -
    -        The build data will reflect any modifications done by the target during the build.
    -        """
    +        A list of extra [dependencies](../../config/dependency.md) that must be installed
    +        prior to builds.
    +
    +        !!! warning
    +            - For this to have any effect the hook dependency itself cannot be dynamic and
    +                must always be defined in `build-system.requires`.
    +            - As the hook must be imported to call this method, imports that require these
    +                dependencies must be evaluated lazily.
    +        """
    +        return []
    +
    +    def clean(self, versions: list[str]) -> None:
    +        """
    +        This occurs before the build process if the `-c`/`--clean` flag was passed to
    +        the [`build`](../../cli/reference.md#hatch-build) command, or when invoking
    +        the [`clean`](../../cli/reference.md#hatch-clean) command.
    +        """
    +
    +    def initialize(self, version: str, build_data: dict[str, Any]) -> None:
    +        """
    +        This occurs immediately before each build.
    +
    +        Any modifications to the build data will be seen by the build target.
    +        """
    +
    +    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
    +        """
    +        This occurs immediately after each build and will not run if the `--hooks-only` flag
    +        was passed to the [`build`](../../cli/reference.md#hatch-build) command.
    +
    +        The build data will reflect any modifications done by the target during the build.
    +        """
     

    PLUGIN_NAME = '' class-attribute instance-attribute

    The name used for selection.

    app: Application property

    An instance of Application.

    root: str property

    The root of the project tree.

    config: dict[str, Any] property

    The cumulative hook configuration.

    [tool.hatch.build.hooks.<PLUGIN_NAME>]
     [tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]
     
    [build.hooks.<PLUGIN_NAME>]
     [build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]
    -

    build_config: BuilderConfigBound property

    An instance of BuilderConfig.

    target_name: str property

    The plugin name of the build target.

    directory: str property

    The build directory.

    clean(versions: list[str]) -> None

    This occurs before the build process if the -c/--clean flag was passed to the build command, or when invoking the clean command.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def clean(self, versions: list[str]) -> None:
    +

    build_config: BuilderConfigBound property

    An instance of BuilderConfig.

    target_name: str property

    The plugin name of the build target.

    directory: str property

    The build directory.

    dependencies() -> list[str]

    A list of extra dependencies that must be installed prior to builds.

    Warning

    • For this to have any effect the hook dependency itself cannot be dynamic and must always be defined in build-system.requires.
    • As the hook must be imported to call this method, imports that require these dependencies must be evaluated lazily.
    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def dependencies(self) -> list[str]:  # noqa: PLR6301
         """
    -    This occurs before the build process if the `-c`/`--clean` flag was passed to
    -    the [`build`](../../cli/reference.md#hatch-build) command, or when invoking
    -    the [`clean`](../../cli/reference.md#hatch-clean) command.
    -    """
    -

    initialize(version: str, build_data: dict[str, Any]) -> None

    This occurs immediately before each build.

    Any modifications to the build data will be seen by the build target.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def initialize(self, version: str, build_data: dict[str, Any]) -> None:
    -    """
    -    This occurs immediately before each build.
    -
    -    Any modifications to the build data will be seen by the build target.
    -    """
    -

    finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None

    This occurs immediately after each build and will not run if the --hooks-only flag was passed to the build command.

    The build data will reflect any modifications done by the target during the build.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
    -    """
    -    This occurs immediately after each build and will not run if the `--hooks-only` flag
    -    was passed to the [`build`](../../cli/reference.md#hatch-build) command.
    -
    -    The build data will reflect any modifications done by the target during the build.
    -    """
    -
    \ No newline at end of file + A list of extra [dependencies](../../config/dependency.md) that must be installed + prior to builds. + + !!! warning + - For this to have any effect the hook dependency itself cannot be dynamic and + must always be defined in `build-system.requires`. + - As the hook must be imported to call this method, imports that require these + dependencies must be evaluated lazily. + """ + return [] +

    clean(versions: list[str]) -> None

    This occurs before the build process if the -c/--clean flag was passed to the build command, or when invoking the clean command.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def clean(self, versions: list[str]) -> None:
    +    """
    +    This occurs before the build process if the `-c`/`--clean` flag was passed to
    +    the [`build`](../../cli/reference.md#hatch-build) command, or when invoking
    +    the [`clean`](../../cli/reference.md#hatch-clean) command.
    +    """
    +

    initialize(version: str, build_data: dict[str, Any]) -> None

    This occurs immediately before each build.

    Any modifications to the build data will be seen by the build target.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def initialize(self, version: str, build_data: dict[str, Any]) -> None:
    +    """
    +    This occurs immediately before each build.
    +
    +    Any modifications to the build data will be seen by the build target.
    +    """
    +

    finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None

    This occurs immediately after each build and will not run if the --hooks-only flag was passed to the build command.

    The build data will reflect any modifications done by the target during the build.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
    +    """
    +    This occurs immediately after each build and will not run if the `--hooks-only` flag
    +    was passed to the [`build`](../../cli/reference.md#hatch-build) command.
    +
    +    The build data will reflect any modifications done by the target during the build.
    +    """
    +
    \ No newline at end of file diff --git a/1.9/plugins/build-hook/version/index.html b/1.9/plugins/build-hook/version/index.html index e0b8d175e..0f60fe576 100644 --- a/1.9/plugins/build-hook/version/index.html +++ b/1.9/plugins/build-hook/version/index.html @@ -1,4 +1,4 @@ - Version - Hatch

    Version build hook


    This writes the project's version to a file.

    Configuration

    The build hook plugin name is version.

    [tool.hatch.build.hooks.version]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Version build hook


    This writes the project's version to a file.

    Configuration

    The build hook plugin name is version.

    [tool.hatch.build.hooks.version]
     [tool.hatch.build.targets.<TARGET_NAME>.hooks.version]
     
    [build.hooks.version]
     [build.targets.<TARGET_NAME>.hooks.version]
    diff --git a/1.9/plugins/builder/app/index.html b/1.9/plugins/builder/app/index.html
    index 9b9423f3d..ddc5927bf 100644
    --- a/1.9/plugins/builder/app/index.html
    +++ b/1.9/plugins/builder/app/index.html
    @@ -1,12 +1,15 @@
    - Application - Hatch      

    Application builder


    This uses PyApp to build an application that is able to bootstrap itself at runtime.

    Note

    This requires an installation of Rust.

    Configuration

    The builder plugin name is app.

    [tool.hatch.build.targets.app]
    -
    [build.targets.app]
    -

    Options

    Option Default Description
    scripts all defined An array of defined script names to limit what gets built
    python-version latest compatible Python minor version The Python version ID to use
    pyapp-version The version of PyApp to use

    Build behavior

    If any scripts are defined then each one will be built (limited by the scripts option). Otherwise, a single executable will be built based on the project name assuming there is an equivalently named module with a __main__.py file.

    Every executable will be built inside an app directory in the output directory.

    If the CARGO environment variable is set then that path will be used as the executable for performing builds.

    If the CARGO_BUILD_TARGET environment variable is set then its value will be appended to the file name stems.

    If the PYAPP_REPO environment variable is set then a local build will be performed inside that directory rather than installing from crates.io. Note that this is required if the CARGO environment variable refers to cross.

    \ No newline at end of file + + + + + + Redirecting... + + + + + + +Redirecting... + + diff --git a/1.9/plugins/builder/binary/index.html b/1.9/plugins/builder/binary/index.html new file mode 100644 index 000000000..891741ecf --- /dev/null +++ b/1.9/plugins/builder/binary/index.html @@ -0,0 +1,12 @@ + Binary builder - Hatch

    Binary builder


    This uses PyApp to build an application that is able to bootstrap itself at runtime.

    Note

    This requires an installation of Rust.

    Configuration

    The builder plugin name is binary.

    [tool.hatch.build.targets.binary]
    +
    [build.targets.binary]
    +

    Options

    Option Default Description
    scripts all defined An array of defined script names to limit what gets built
    python-version latest compatible Python minor version The Python version ID to use
    pyapp-version The version of PyApp to use

    Build behavior

    If any scripts are defined then each one will be built (limited by the scripts option). Otherwise, a single executable will be built based on the project name assuming there is an equivalently named module with a __main__.py file.

    Every executable will be built inside an app directory in the output directory.

    If the CARGO environment variable is set then that path will be used as the executable for performing builds.

    If the CARGO_BUILD_TARGET environment variable is set then its value will be appended to the file name stems.

    If the PYAPP_REPO environment variable is set then a local build will be performed inside that directory rather than installing from crates.io. Note that this is required if the CARGO environment variable refers to cross.

    \ No newline at end of file diff --git a/1.9/plugins/builder/custom/index.html b/1.9/plugins/builder/custom/index.html index 57506e279..df6732bd5 100644 --- a/1.9/plugins/builder/custom/index.html +++ b/1.9/plugins/builder/custom/index.html @@ -1,4 +1,4 @@ - Custom - Hatch

    Custom builder


    This is a custom class in a given Python file that inherits from the BuilderInterface.

    Configuration

    The builder plugin name is custom.

    [tool.hatch.build.targets.custom]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Custom builder


    This is a custom class in a given Python file that inherits from the BuilderInterface.

    Configuration

    The builder plugin name is custom.

    [tool.hatch.build.targets.custom]
     
    [build.targets.custom]
     

    Options

    Option Default Description
    path hatch_build.py The path of the Python file

    Example

    from hatchling.builders.plugin.interface import BuilderInterface
     
     
     class CustomBuilder(BuilderInterface):
         ...
    -

    If multiple subclasses are found, you must define a function named get_builder that returns the desired builder.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    \ No newline at end of file +

    If multiple subclasses are found, you must define a function named get_builder that returns the desired builder.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    \ No newline at end of file diff --git a/1.9/plugins/builder/reference/index.html b/1.9/plugins/builder/reference/index.html index 5e6d598ab..a244dbb46 100644 --- a/1.9/plugins/builder/reference/index.html +++ b/1.9/plugins/builder/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

    Builder plugins


    See the documentation for build configuration.

    Known third-party

    • hatch-aws - used for building AWS Lambda functions with SAM
    • hatch-zipped-directory - used for building ZIP archives for installation into various foreign package installation systems

    BuilderInterface

    Example usage:

    from hatchling.builders.plugin.interface import BuilderInterface
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Builder plugins


    See the documentation for build configuration.

    Known third-party

    • hatch-aws - used for building AWS Lambda functions with SAM
    • hatch-zipped-directory - used for building ZIP archives for installation into various foreign package installation systems

    BuilderInterface

    Example usage:

    from hatchling.builders.plugin.interface import BuilderInterface
     
     
     class SpecialBuilder(BuilderInterface):
    @@ -187,278 +187,287 @@
                 files.sort()
                 is_package = '__init__.py' in files
                 for f in files:
    -                relative_file_path = os.path.join(relative_path, f)
    -                distribution_path = self.config.get_distribution_path(relative_file_path)
    -                if self.config.path_is_reserved(distribution_path):
    -                    continue
    -
    -                if self.config.include_path(relative_file_path, is_package=is_package):
    -                    yield IncludedFile(
    -                        os.path.join(root, f), relative_file_path, self.config.get_distribution_path(relative_file_path)
    -                    )
    -
    -    def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:
    -        for source, target_path in inclusion_map.items():
    -            external = not source.startswith(self.root)
    -            if os.path.isfile(source):
    -                yield IncludedFile(
    -                    source,
    -                    '' if external else os.path.relpath(source, self.root),
    -                    self.config.get_distribution_path(target_path),
    -                )
    -            elif os.path.isdir(source):
    -                for root, dirs, files in safe_walk(source):
    -                    relative_directory = get_relative_path(root, source)
    -
    -                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)
    -
    -                    files.sort()
    -                    for f in files:
    -                        relative_file_path = os.path.join(target_path, relative_directory, f)
    -                        distribution_path = self.config.get_distribution_path(relative_file_path)
    -                        if not self.config.path_is_reserved(distribution_path):
    -                            yield IncludedFile(
    -                                os.path.join(root, f),
    -                                '' if external else relative_file_path,
    -                                distribution_path,
    -                            )
    -            else:
    -                msg = f'Forced include not found: {source}'
    -                raise FileNotFoundError(msg)
    -
    -    def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:
    -        for source, target_path in inclusion_map.items():
    -            external = not source.startswith(self.root)
    -            if os.path.isfile(source):
    -                distribution_path = self.config.get_distribution_path(target_path)
    -                if not self.config.path_is_reserved(distribution_path):
    -                    yield IncludedFile(
    -                        source,
    -                        '' if external else os.path.relpath(source, self.root),
    -                        self.config.get_distribution_path(target_path),
    -                    )
    -            elif os.path.isdir(source):
    -                for root, dirs, files in safe_walk(source):
    -                    relative_directory = get_relative_path(root, source)
    -
    -                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)
    -
    -                    files.sort()
    -                    is_package = '__init__.py' in files
    -                    for f in files:
    -                        relative_file_path = os.path.join(target_path, relative_directory, f)
    -                        distribution_path = self.config.get_distribution_path(relative_file_path)
    -                        if self.config.path_is_reserved(distribution_path):
    -                            continue
    -
    -                        if self.config.include_path(relative_file_path, explicit=True, is_package=is_package):
    -                            yield IncludedFile(
    -                                os.path.join(root, f), '' if external else relative_file_path, distribution_path
    -                            )
    -
    -    @property
    -    def root(self) -> str:
    -        """
    -        The root of the project tree.
    -        """
    -        return self.__root
    -
    -    @property
    -    def plugin_manager(self) -> PluginManagerBound:
    -        if self.__plugin_manager is None:
    -            from hatchling.plugin.manager import PluginManager
    -
    -            self.__plugin_manager = PluginManager()
    -
    -        return self.__plugin_manager
    +                if f in EXCLUDED_FILES:
    +                    continue
    +
    +                relative_file_path = os.path.join(relative_path, f)
    +                distribution_path = self.config.get_distribution_path(relative_file_path)
    +                if self.config.path_is_reserved(distribution_path):
    +                    continue
    +
    +                if self.config.include_path(relative_file_path, is_package=is_package):
    +                    yield IncludedFile(
    +                        os.path.join(root, f), relative_file_path, self.config.get_distribution_path(relative_file_path)
    +                    )
    +
    +    def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:
    +        for source, target_path in inclusion_map.items():
    +            external = not source.startswith(self.root)
    +            if os.path.isfile(source):
    +                yield IncludedFile(
    +                    source,
    +                    '' if external else os.path.relpath(source, self.root),
    +                    self.config.get_distribution_path(target_path),
    +                )
    +            elif os.path.isdir(source):
    +                for root, dirs, files in safe_walk(source):
    +                    relative_directory = get_relative_path(root, source)
    +
    +                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)
    +
    +                    files.sort()
    +                    for f in files:
    +                        if f in EXCLUDED_FILES:
    +                            continue
    +
    +                        relative_file_path = os.path.join(target_path, relative_directory, f)
    +                        distribution_path = self.config.get_distribution_path(relative_file_path)
    +                        if not self.config.path_is_reserved(distribution_path):
    +                            yield IncludedFile(
    +                                os.path.join(root, f),
    +                                '' if external else relative_file_path,
    +                                distribution_path,
    +                            )
    +            else:
    +                msg = f'Forced include not found: {source}'
    +                raise FileNotFoundError(msg)
    +
    +    def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:
    +        for source, target_path in inclusion_map.items():
    +            external = not source.startswith(self.root)
    +            if os.path.isfile(source):
    +                distribution_path = self.config.get_distribution_path(target_path)
    +                if not self.config.path_is_reserved(distribution_path):
    +                    yield IncludedFile(
    +                        source,
    +                        '' if external else os.path.relpath(source, self.root),
    +                        self.config.get_distribution_path(target_path),
    +                    )
    +            elif os.path.isdir(source):
    +                for root, dirs, files in safe_walk(source):
    +                    relative_directory = get_relative_path(root, source)
    +
    +                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)
    +
    +                    files.sort()
    +                    is_package = '__init__.py' in files
    +                    for f in files:
    +                        if f in EXCLUDED_FILES:
    +                            continue
    +
    +                        relative_file_path = os.path.join(target_path, relative_directory, f)
    +                        distribution_path = self.config.get_distribution_path(relative_file_path)
    +                        if self.config.path_is_reserved(distribution_path):
    +                            continue
    +
    +                        if self.config.include_path(relative_file_path, explicit=True, is_package=is_package):
    +                            yield IncludedFile(
    +                                os.path.join(root, f), '' if external else relative_file_path, distribution_path
    +                            )
    +
    +    @property
    +    def root(self) -> str:
    +        """
    +        The root of the project tree.
    +        """
    +        return self.__root
     
         @property
    -    def metadata(self) -> ProjectMetadata:
    -        if self.__metadata is None:
    -            from hatchling.metadata.core import ProjectMetadata
    +    def plugin_manager(self) -> PluginManagerBound:
    +        if self.__plugin_manager is None:
    +            from hatchling.plugin.manager import PluginManager
     
    -            self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)
    +            self.__plugin_manager = PluginManager()
     
    -        return self.__metadata
    +        return self.__plugin_manager
     
         @property
    -    def app(self) -> Application:
    -        """
    -        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).
    -        """
    -        if self.__app is None:
    -            from hatchling.bridge.app import Application
    -
    -            self.__app = cast(Application, Application().get_safe_application())
    -
    -        return self.__app
    -
    -    @property
    -    def raw_config(self) -> dict[str, Any]:
    -        if self.__raw_config is None:
    -            self.__raw_config = self.metadata.config
    +    def metadata(self) -> ProjectMetadata:
    +        if self.__metadata is None:
    +            from hatchling.metadata.core import ProjectMetadata
    +
    +            self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)
    +
    +        return self.__metadata
    +
    +    @property
    +    def app(self) -> Application:
    +        """
    +        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).
    +        """
    +        if self.__app is None:
    +            from hatchling.bridge.app import Application
     
    -        return self.__raw_config
    +            self.__app = cast(Application, Application().get_safe_application())
     
    -    @property
    -    def project_config(self) -> dict[str, Any]:
    -        if self.__project_config is None:
    -            self.__project_config = self.metadata.core.config
    -
    -        return self.__project_config
    +        return self.__app
    +
    +    @property
    +    def raw_config(self) -> dict[str, Any]:
    +        if self.__raw_config is None:
    +            self.__raw_config = self.metadata.config
     
    -    @property
    -    def hatch_config(self) -> dict[str, Any]:
    -        if self.__hatch_config is None:
    -            self.__hatch_config = self.metadata.hatch.config
    -
    -        return self.__hatch_config
    +        return self.__raw_config
    +
    +    @property
    +    def project_config(self) -> dict[str, Any]:
    +        if self.__project_config is None:
    +            self.__project_config = self.metadata.core.config
     
    -    @property
    -    def config(self) -> BuilderConfigBound:
    -        """
    -        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
    -        """
    -        if self.__config is None:
    -            self.__config = self.get_config_class()(
    -                self, self.root, self.PLUGIN_NAME, self.build_config, self.target_config
    -            )
    -
    -        return self.__config
    -
    -    @property
    -    def build_config(self) -> dict[str, Any]:
    -        """
    -        ```toml config-example
    -        [tool.hatch.build]
    -        ```
    -        """
    -        if self.__build_config is None:
    -            self.__build_config = self.metadata.hatch.build_config
    -
    -        return self.__build_config
    -
    -    @property
    -    def target_config(self) -> dict[str, Any]:
    -        """
    -        ```toml config-example
    -        [tool.hatch.build.targets.<PLUGIN_NAME>]
    -        ```
    -        """
    -        if self.__target_config is None:
    -            target_config: dict[str, Any] = self.metadata.hatch.build_targets.get(self.PLUGIN_NAME, {})
    -            if not isinstance(target_config, dict):
    -                message = f'Field `tool.hatch.build.targets.{self.PLUGIN_NAME}` must be a table'
    -                raise TypeError(message)
    -
    -            self.__target_config = target_config
    -
    -        return self.__target_config
    -
    -    @property
    -    def project_id(self) -> str:
    -        if self.__project_id is None:
    -            self.__project_id = f'{self.normalize_file_name_component(self.metadata.core.name)}-{self.metadata.version}'
    +        return self.__project_config
    +
    +    @property
    +    def hatch_config(self) -> dict[str, Any]:
    +        if self.__hatch_config is None:
    +            self.__hatch_config = self.metadata.hatch.config
    +
    +        return self.__hatch_config
    +
    +    @property
    +    def config(self) -> BuilderConfigBound:
    +        """
    +        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
    +        """
    +        if self.__config is None:
    +            self.__config = self.get_config_class()(
    +                self, self.root, self.PLUGIN_NAME, self.build_config, self.target_config
    +            )
    +
    +        return self.__config
    +
    +    @property
    +    def build_config(self) -> dict[str, Any]:
    +        """
    +        ```toml config-example
    +        [tool.hatch.build]
    +        ```
    +        """
    +        if self.__build_config is None:
    +            self.__build_config = self.metadata.hatch.build_config
    +
    +        return self.__build_config
    +
    +    @property
    +    def target_config(self) -> dict[str, Any]:
    +        """
    +        ```toml config-example
    +        [tool.hatch.build.targets.<PLUGIN_NAME>]
    +        ```
    +        """
    +        if self.__target_config is None:
    +            target_config: dict[str, Any] = self.metadata.hatch.build_targets.get(self.PLUGIN_NAME, {})
    +            if not isinstance(target_config, dict):
    +                message = f'Field `tool.hatch.build.targets.{self.PLUGIN_NAME}` must be a table'
    +                raise TypeError(message)
     
    -        return self.__project_id
    +            self.__target_config = target_config
     
    -    def get_build_hooks(self, directory: str) -> dict[str, BuildHookInterface]:
    -        configured_build_hooks = {}
    -        for hook_name, config in self.config.hook_config.items():
    -            build_hook = self.plugin_manager.build_hook.get(hook_name)
    -            if build_hook is None:
    -                from hatchling.plugin.exceptions import UnknownPluginError
    +        return self.__target_config
    +
    +    @property
    +    def project_id(self) -> str:
    +        if self.__project_id is None:
    +            self.__project_id = f'{self.normalize_file_name_component(self.metadata.core.name)}-{self.metadata.version}'
     
    -                message = f'Unknown build hook: {hook_name}'
    -                raise UnknownPluginError(message)
    -
    -            configured_build_hooks[hook_name] = build_hook(
    -                self.root, config, self.config, self.metadata, directory, self.PLUGIN_NAME, self.app
    -            )
    -
    -        return configured_build_hooks
    +        return self.__project_id
    +
    +    def get_build_hooks(self, directory: str) -> dict[str, BuildHookInterface]:
    +        configured_build_hooks = {}
    +        for hook_name, config in self.config.hook_config.items():
    +            build_hook = self.plugin_manager.build_hook.get(hook_name)
    +            if build_hook is None:
    +                from hatchling.plugin.exceptions import UnknownPluginError
     
    -    @abstractmethod
    -    def get_version_api(self) -> dict[str, Callable]:
    -        """
    -        A mapping of `str` versions to a callable that is used for building.
    -        Each callable must have the following signature:
    -
    -        ```python
    -        def ...(build_dir: str, build_data: dict) -> str:
    -        ```
    -
    -        The return value must be the absolute path to the built artifact.
    -        """
    -
    -    def get_default_versions(self) -> list[str]:
    -        """
    -        A list of versions to build when users do not specify any, defaulting to all versions.
    -        """
    -        return list(self.get_version_api())
    +                message = f'Unknown build hook: {hook_name}'
    +                raise UnknownPluginError(message)
    +
    +            configured_build_hooks[hook_name] = build_hook(
    +                self.root, config, self.config, self.metadata, directory, self.PLUGIN_NAME, self.app
    +            )
    +
    +        return configured_build_hooks
    +
    +    @abstractmethod
    +    def get_version_api(self) -> dict[str, Callable]:
    +        """
    +        A mapping of `str` versions to a callable that is used for building.
    +        Each callable must have the following signature:
    +
    +        ```python
    +        def ...(build_dir: str, build_data: dict) -> str:
    +        ```
     
    -    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301
    -        """
    -        A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.
    -        """
    -        return {}
    -
    -    def set_build_data_defaults(self, build_data: dict[str, Any]) -> None:  # noqa: PLR6301
    -        build_data.setdefault('artifacts', [])
    -        build_data.setdefault('force_include', {})
    -
    -    def clean(self, directory: str, versions: list[str]) -> None:
    -        """
    -        Called before builds if the `-c`/`--clean` flag was passed to the
    -        [`build`](../../cli/reference.md#hatch-build) command.
    -        """
    -
    -    @classmethod
    -    def get_config_class(cls) -> type[BuilderConfig]:
    -        """
    -        Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
    -        """
    -        return BuilderConfig
    -
    -    @staticmethod
    -    def normalize_file_name_component(file_name: str) -> str:
    -        """
    -        https://peps.python.org/pep-0427/#escaping-and-unicode
    -        """
    -        return re.sub(r'[^\w\d.]+', '_', file_name, flags=re.UNICODE)
    +        The return value must be the absolute path to the built artifact.
    +        """
    +
    +    def get_default_versions(self) -> list[str]:
    +        """
    +        A list of versions to build when users do not specify any, defaulting to all versions.
    +        """
    +        return list(self.get_version_api())
    +
    +    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301
    +        """
    +        A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.
    +        """
    +        return {}
    +
    +    def set_build_data_defaults(self, build_data: dict[str, Any]) -> None:  # noqa: PLR6301
    +        build_data.setdefault('artifacts', [])
    +        build_data.setdefault('force_include', {})
    +
    +    def clean(self, directory: str, versions: list[str]) -> None:
    +        """
    +        Called before builds if the `-c`/`--clean` flag was passed to the
    +        [`build`](../../cli/reference.md#hatch-build) command.
    +        """
    +
    +    @classmethod
    +    def get_config_class(cls) -> type[BuilderConfig]:
    +        """
    +        Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
    +        """
    +        return BuilderConfig
    +
    +    @staticmethod
    +    def normalize_file_name_component(file_name: str) -> str:
    +        """
    +        https://peps.python.org/pep-0427/#escaping-and-unicode
    +        """
    +        return re.sub(r'[^\w\d.]+', '_', file_name, flags=re.UNICODE)
     

    PLUGIN_NAME = '' class-attribute instance-attribute

    The name used for selection.

    app: Application property

    An instance of Application.

    root: str property

    The root of the project tree.

    build_config: dict[str, Any] property

    [tool.hatch.build]
     
    [build]
     

    target_config: dict[str, Any] property

    [tool.hatch.build.targets.<PLUGIN_NAME>]
     
    [build.targets.<PLUGIN_NAME>]
    -

    config: BuilderConfigBound property

    An instance of BuilderConfig.

    get_config_class() -> type[BuilderConfig] classmethod

    Must return a subclass of BuilderConfig.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    @classmethod
    -def get_config_class(cls) -> type[BuilderConfig]:
    -    """
    -    Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
    -    """
    -    return BuilderConfig
    +

    config: BuilderConfigBound property

    An instance of BuilderConfig.

    get_config_class() -> type[BuilderConfig] classmethod

    Must return a subclass of BuilderConfig.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    @classmethod
    +def get_config_class(cls) -> type[BuilderConfig]:
    +    """
    +    Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
    +    """
    +    return BuilderConfig
     

    get_version_api() -> dict[str, Callable] abstractmethod

    A mapping of str versions to a callable that is used for building. Each callable must have the following signature:

    def ...(build_dir: str, build_data: dict) -> str:
    -

    The return value must be the absolute path to the built artifact.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    @abstractmethod
    -def get_version_api(self) -> dict[str, Callable]:
    -    """
    -    A mapping of `str` versions to a callable that is used for building.
    -    Each callable must have the following signature:
    -
    -    ```python
    -    def ...(build_dir: str, build_data: dict) -> str:
    -    ```
    -
    -    The return value must be the absolute path to the built artifact.
    -    """
    -

    get_default_versions() -> list[str]

    A list of versions to build when users do not specify any, defaulting to all versions.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def get_default_versions(self) -> list[str]:
    -    """
    -    A list of versions to build when users do not specify any, defaulting to all versions.
    -    """
    -    return list(self.get_version_api())
    -

    clean(directory: str, versions: list[str]) -> None

    Called before builds if the -c/--clean flag was passed to the build command.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def clean(self, directory: str, versions: list[str]) -> None:
    -    """
    -    Called before builds if the `-c`/`--clean` flag was passed to the
    -    [`build`](../../cli/reference.md#hatch-build) command.
    -    """
    +

    The return value must be the absolute path to the built artifact.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    @abstractmethod
    +def get_version_api(self) -> dict[str, Callable]:
    +    """
    +    A mapping of `str` versions to a callable that is used for building.
    +    Each callable must have the following signature:
    +
    +    ```python
    +    def ...(build_dir: str, build_data: dict) -> str:
    +    ```
    +
    +    The return value must be the absolute path to the built artifact.
    +    """
    +

    get_default_versions() -> list[str]

    A list of versions to build when users do not specify any, defaulting to all versions.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def get_default_versions(self) -> list[str]:
    +    """
    +    A list of versions to build when users do not specify any, defaulting to all versions.
    +    """
    +    return list(self.get_version_api())
    +

    clean(directory: str, versions: list[str]) -> None

    Called before builds if the -c/--clean flag was passed to the build command.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def clean(self, directory: str, versions: list[str]) -> None:
    +    """
    +    Called before builds if the `-c`/`--clean` flag was passed to the
    +    [`build`](../../cli/reference.md#hatch-build) command.
    +    """
     

    recurse_included_files() -> Iterable[IncludedFile]

    Returns a consistently generated series of file objects for every file that should be distributed. Each file object has three str attributes:

    • path - the absolute path
    • relative_path - the path relative to the project root; will be an empty string for external files
    • distribution_path - the path to be distributed as
    Source code in backend/src/hatchling/builders/plugin/interface.py
    def recurse_included_files(self) -> Iterable[IncludedFile]:
         """
         Returns a consistently generated series of file objects for every file that should be distributed. Each file
    @@ -470,9 +479,9 @@
         """
         yield from self.recurse_selected_project_files()
         yield from self.recurse_forced_files(self.config.get_force_include())
    -

    get_default_build_data() -> dict[str, Any]

    A mapping that can be modified by build hooks to influence the behavior of builds.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301
    -    """
    -    A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.
    -    """
    -    return {}
    +

    get_default_build_data() -> dict[str, Any]

    A mapping that can be modified by build hooks to influence the behavior of builds.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301
    +    """
    +    A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.
    +    """
    +    return {}
     
    \ No newline at end of file diff --git a/1.9/plugins/builder/sdist/index.html b/1.9/plugins/builder/sdist/index.html index fd509346c..a790529c2 100644 --- a/1.9/plugins/builder/sdist/index.html +++ b/1.9/plugins/builder/sdist/index.html @@ -1,4 +1,4 @@ - Source distribution - Hatch

    Source distribution builder


    A source distribution, or sdist, is an archive of Python "source code". Although largely unspecified, by convention it should include everything that is required to build a wheel without making network requests.

    Configuration

    The builder plugin name is sdist.

    [tool.hatch.build.targets.sdist]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Source distribution builder


    A source distribution, or sdist, is an archive of Python "source code". Although largely unspecified, by convention it should include everything that is required to build a wheel without making network requests.

    Configuration

    The builder plugin name is sdist.

    [tool.hatch.build.targets.sdist]
     
    [build.targets.sdist]
    -

    Options

    Option Default Description
    core-metadata-version "2.1" The version of core metadata to use
    strict-naming true Whether or not file names should contain the normalized version of the project name
    support-legacy false Whether or not to include a setup.py file to support legacy installation mechanisms

    Versions

    Version Description
    standard (default) The latest conventional format

    Default file selection

    When the user has not set any file selection options, all files that are not ignored by your VCS will be included.

    Note

    The following files are always included and cannot be excluded:

    • /pyproject.toml
    • /hatch.toml
    • /hatch_build.py
    • /.gitignore or /.hgignore
    • Any defined readme file
    • All defined license-files

    Reproducibility

    Reproducible builds are supported.

    Build data

    This is data that can be modified by build hooks.

    Data Default Description
    dependencies Extra project dependencies
    \ No newline at end of file +

    Options

    Option Default Description
    core-metadata-version "2.3" The version of core metadata to use
    strict-naming true Whether or not file names should contain the normalized version of the project name
    support-legacy false Whether or not to include a setup.py file to support legacy installation mechanisms

    Versions

    Version Description
    standard (default) The latest conventional format

    Default file selection

    When the user has not set any file selection options, all files that are not ignored by your VCS will be included.

    Note

    The following files are always included and cannot be excluded:

    • /pyproject.toml
    • /hatch.toml
    • /hatch_build.py
    • /.gitignore or /.hgignore
    • Any defined readme file
    • All defined license-files

    Reproducibility

    Reproducible builds are supported.

    Build data

    This is data that can be modified by build hooks.

    Data Default Description
    dependencies Extra project dependencies
    \ No newline at end of file diff --git a/1.9/plugins/builder/wheel/index.html b/1.9/plugins/builder/wheel/index.html index 49451e528..d65381d07 100644 --- a/1.9/plugins/builder/wheel/index.html +++ b/1.9/plugins/builder/wheel/index.html @@ -1,4 +1,4 @@ - Wheel - Hatch

    Wheel builder


    A wheel is a binary distribution of a Python package that can be installed directly into an environment.

    Configuration

    The builder plugin name is wheel.

    [tool.hatch.build.targets.wheel]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Wheel builder


    A wheel is a binary distribution of a Python package that can be installed directly into an environment.

    Configuration

    The builder plugin name is wheel.

    [tool.hatch.build.targets.wheel]
     
    [build.targets.wheel]
    -

    Options

    Option Default Description
    core-metadata-version "2.1" The version of core metadata to use
    shared-data A mapping similar to the forced inclusion option corresponding to data that will be installed globally in a given Python environment, usually under sys.prefix
    extra-metadata A mapping similar to the forced inclusion option corresponding to extra metadata that will be shipped in a directory named extra_metadata
    strict-naming true Whether or not file names should contain the normalized version of the project name
    macos-max-compat true Whether or not on macOS, when build hooks have set the infer_tag build data, the wheel name should signal broad support rather than specific versions for newer SDK versions.

    Note: The default will become false, and this option eventually removed, sometime after consumers like pip start supporting these newer SDK versions.
    bypass-selection false Whether or not to suppress the error when one has not defined any file selection options and all heuristics have failed to determine what to ship

    Versions

    Version Description
    standard (default) The latest standardized format
    editable A wheel that only ships .pth files or import hooks for real-time development

    Default file selection

    When the user has not set any file selection options, the project name will be used to determine the package to ship in the following heuristic order:

    1. <NAME>/__init__.py
    2. src/<NAME>/__init__.py
    3. <NAME>.py
    4. <NAMESPACE>/<NAME>/__init__.py

    If none of these heuristics are satisfied, an error will be raised.

    Reproducibility

    Reproducible builds are supported.

    Build data

    This is data that can be modified by build hooks.

    Data Default Description
    tag The full tag part of the filename (e.g. py3-none-any), defaulting to a cross-platform wheel with the supported major versions of Python based on project metadata
    infer_tag False When tag is not set, this may be enabled to use the one most specific to the platform, Python interpreter, and ABI
    pure_python True Whether or not to write metadata indicating that the package does not contain any platform-specific files
    dependencies Extra project dependencies
    extra_metadata Additional extra-metadata entries, which take precedence in case of conflicts
    force_include_editable Similar to the force_include option but specifically for the editable version and takes precedence
    \ No newline at end of file +

    Options

    Option Default Description
    core-metadata-version "2.3" The version of core metadata to use
    shared-data A mapping similar to the forced inclusion option corresponding to data that will be installed globally in a given Python environment, usually under sys.prefix
    extra-metadata A mapping similar to the forced inclusion option corresponding to extra metadata that will be shipped in a directory named extra_metadata
    strict-naming true Whether or not file names should contain the normalized version of the project name
    macos-max-compat true Whether or not on macOS, when build hooks have set the infer_tag build data, the wheel name should signal broad support rather than specific versions for newer SDK versions.

    Note: The default will become false, and this option eventually removed, sometime after consumers like pip start supporting these newer SDK versions.
    bypass-selection false Whether or not to suppress the error when one has not defined any file selection options and all heuristics have failed to determine what to ship

    Versions

    Version Description
    standard (default) The latest standardized format
    editable A wheel that only ships .pth files or import hooks for real-time development

    Default file selection

    When the user has not set any file selection options, the project name will be used to determine the package to ship in the following heuristic order:

    1. <NAME>/__init__.py
    2. src/<NAME>/__init__.py
    3. <NAME>.py
    4. <NAMESPACE>/<NAME>/__init__.py

    If none of these heuristics are satisfied, an error will be raised.

    Reproducibility

    Reproducible builds are supported.

    Build data

    This is data that can be modified by build hooks.

    Data Default Description
    tag The full tag part of the filename (e.g. py3-none-any), defaulting to a cross-platform wheel with the supported major versions of Python based on project metadata
    infer_tag False When tag is not set, this may be enabled to use the one most specific to the platform, Python interpreter, and ABI
    pure_python True Whether or not to write metadata indicating that the package does not contain any platform-specific files
    dependencies Extra project dependencies
    extra_metadata Additional extra-metadata entries, which take precedence in case of conflicts
    force_include_editable Similar to the force_include option but specifically for the editable version and takes precedence
    \ No newline at end of file diff --git a/1.9/plugins/environment-collector/custom/index.html b/1.9/plugins/environment-collector/custom/index.html index fa339b66b..3b7213d06 100644 --- a/1.9/plugins/environment-collector/custom/index.html +++ b/1.9/plugins/environment-collector/custom/index.html @@ -1,4 +1,4 @@ - Custom - Hatch

    Custom environment collector


    This is a custom class in a given Python file that inherits from the EnvironmentCollectorInterface.

    Configuration

    The environment collector plugin name is custom.

    [tool.hatch.env.collectors.custom]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Custom environment collector


    This is a custom class in a given Python file that inherits from the EnvironmentCollectorInterface.

    Configuration

    The environment collector plugin name is custom.

    [tool.hatch.env.collectors.custom]
     
    [env.collectors.custom]
     

    Options

    Option Default Description
    path hatch_plugins.py The path of the Python file

    Example

        from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface
     
    diff --git a/1.9/plugins/environment-collector/default/index.html b/1.9/plugins/environment-collector/default/index.html
    index 4599dbb74..6f326b031 100644
    --- a/1.9/plugins/environment-collector/default/index.html
    +++ b/1.9/plugins/environment-collector/default/index.html
    @@ -1,4 +1,4 @@
    - Default - Hatch      

    Default environment collector


    This adds the default environment with type set to virtual and will always be applied.

    Configuration

    The environment collector plugin name is default.

    [tool.hatch.env.collectors.default]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Default environment collector


    This adds the default environment with type set to virtual and will always be applied.

    Configuration

    The environment collector plugin name is default.

    [tool.hatch.env.collectors.default]
     
    [env.collectors.default]
     

    Options

    There are no options available currently.

    \ No newline at end of file diff --git a/1.9/plugins/environment-collector/reference/index.html b/1.9/plugins/environment-collector/reference/index.html index 744a61467..12d490ccb 100644 --- a/1.9/plugins/environment-collector/reference/index.html +++ b/1.9/plugins/environment-collector/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

    Environment collector plugins


    Environment collectors allow for dynamically modifying environments or adding environments beyond those defined in config. Users can override default values provided by each environment.

    Known third-party

    Installation

    Any required environment collectors that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

    [tool.hatch.env]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Environment collector plugins


    Environment collectors allow for dynamically modifying environments or adding environments beyond those defined in config. Users can override default values provided by each environment.

    Known third-party

    Installation

    Any required environment collectors that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

    [tool.hatch.env]
     requires = [
       "...",
     ]
    diff --git a/1.9/plugins/environment/reference/index.html b/1.9/plugins/environment/reference/index.html
    index e04e66a46..a5648b4e5 100644
    --- a/1.9/plugins/environment/reference/index.html
    +++ b/1.9/plugins/environment/reference/index.html
    @@ -1,4 +1,4 @@
    - Reference - Hatch      

    Environment plugins


    See the documentation for environment configuration.

    Known third-party

    Installation

    Any required environment types that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

    [tool.hatch.env]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Environment plugins


    See the documentation for environment configuration.

    Known third-party

    Installation

    Any required environment types that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

    [tool.hatch.env]
     requires = [
       "...",
     ]
    @@ -19,37 +19,38 @@
         if not environment.exists():
             self.env_metadata.reset(environment)
     
    -        with self.status(f'Creating environment: {environment.name}'):
    +        with environment.app_status_creation():
                 environment.create()
     
             if not environment.skip_install:
                 if environment.pre_install_commands:
    -                with self.status('Running pre-installation commands'):
    +                with environment.app_status_pre_installation():
                         self.run_shell_commands(environment, environment.pre_install_commands, source='pre-install')
     
    -            if environment.dev_mode:
    -                with self.status('Installing project in development mode'):
    +            with environment.app_status_project_installation():
    +                if environment.dev_mode:
                         environment.install_project_dev_mode()
    -            else:
    -                with self.status('Installing project'):
    -                    environment.install_project()
    -
    -            if environment.post_install_commands:
    -                with self.status('Running post-installation commands'):
    -                    self.run_shell_commands(environment, environment.post_install_commands, source='post-install')
    -
    -    new_dep_hash = environment.dependency_hash()
    -    current_dep_hash = self.env_metadata.dependency_hash(environment)
    -    if new_dep_hash != current_dep_hash:
    -        with self.status('Checking dependencies'):
    -            dependencies_in_sync = environment.dependencies_in_sync()
    -
    -        if not dependencies_in_sync:
    -            with self.status('Syncing dependencies'):
    -                environment.sync_dependencies()
    -                new_dep_hash = environment.dependency_hash()
    -
    -        self.env_metadata.update_dependency_hash(environment, new_dep_hash)
    +                else:
    +                    environment.install_project()
    +
    +            if environment.post_install_commands:
    +                with environment.app_status_post_installation():
    +                    self.run_shell_commands(environment, environment.post_install_commands, source='post-install')
    +
    +    with environment.app_status_dependency_state_check():
    +        new_dep_hash = environment.dependency_hash()
    +
    +    current_dep_hash = self.env_metadata.dependency_hash(environment)
    +    if new_dep_hash != current_dep_hash:
    +        with environment.app_status_dependency_installation_check():
    +            dependencies_in_sync = environment.dependencies_in_sync()
    +
    +        if not dependencies_in_sync:
    +            with environment.app_status_dependency_synchronization():
    +                environment.sync_dependencies()
    +                new_dep_hash = environment.dependency_hash()
    +
    +        self.env_metadata.update_dependency_hash(environment, new_dep_hash)
     

    Build environments

    All environment types should offer support for a special sub-environment in which projects can be built. This environment is used in the following scenarios:

    EnvironmentInterface

    Example usage:

        from hatch.env.plugin.interface import EnvironmentInterface
     
     
    @@ -604,353 +605,421 @@
             A convenience method called when using the environment as a context manager:
     
             ```python
    -        with environment: ...
    -        ```
    -        """
    -
    -    def deactivate(self):
    -        """
    -        A convenience method called after using the environment as a context manager:
    -
    -        ```python
    -        with environment: ...
    -        ```
    -        """
    -
    -    @abstractmethod
    -    def find(self):
    -        """
    -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -        This should return information about how to locate the environment or represent its ID in
    -        some way. Additionally, this is expected to return something even if the environment is
    -        [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).
    -        """
    -
    -    @abstractmethod
    -    def create(self):
    -        """
    -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -        This should perform the necessary steps to set up the environment.
    -        """
    -
    -    @abstractmethod
    -    def remove(self):
    -        """
    -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -        This should perform the necessary steps to completely remove the environment from the system and will only
    -        be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or
    -        [`env prune`](../../cli/reference.md#hatch-env-prune) commands.
    -
    -        If the
    -        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    -        has a caching mechanism, this should remove that as well.
    -        """
    -
    -    @abstractmethod
    -    def exists(self) -> bool:
    -        """
    -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -        This should indicate whether or not the environment has already been created.
    -        """
    -
    -    @abstractmethod
    -    def install_project(self):
    -        """
    -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -        This should install the project in the environment.
    -        """
    -
    -    @abstractmethod
    -    def install_project_dev_mode(self):
    -        """
    -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -        This should install the project in the environment such that the environment
    -        always reflects the current state of the project.
    -        """
    -
    -    @abstractmethod
    -    def dependencies_in_sync(self) -> bool:
    -        """
    -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -        This should indicate whether or not the environment is compatible with the current
    -        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).
    -        """
    -
    -    @abstractmethod
    -    def sync_dependencies(self):
    -        """
    -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -        This should install the
    -        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
    -        in the environment.
    -        """
    -
    -    def dependency_hash(self):
    -        """
    -        This should return a hash of the environment's
    -        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
    -        and any other data that is handled by the
    -        [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)
    -        and
    -        [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)
    -        methods.
    -        """
    -        from hatch.utils.dep import hash_dependencies
    -
    -        return hash_dependencies(self.dependencies_complex)
    +        with environment:
    +            ...
    +        ```
    +        """
    +
    +    def deactivate(self):
    +        """
    +        A convenience method called after using the environment as a context manager:
    +
    +        ```python
    +        with environment:
    +            ...
    +        ```
    +        """
    +
    +    @abstractmethod
    +    def find(self):
    +        """
    +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +        This should return information about how to locate the environment or represent its ID in
    +        some way. Additionally, this is expected to return something even if the environment is
    +        [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).
    +        """
    +
    +    @abstractmethod
    +    def create(self):
    +        """
    +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +        This should perform the necessary steps to set up the environment.
    +        """
    +
    +    @abstractmethod
    +    def remove(self):
    +        """
    +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +        This should perform the necessary steps to completely remove the environment from the system and will only
    +        be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or
    +        [`env prune`](../../cli/reference.md#hatch-env-prune) commands.
    +
    +        If the
    +        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    +        has a caching mechanism, this should remove that as well.
    +        """
    +
    +    @abstractmethod
    +    def exists(self) -> bool:
    +        """
    +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +        This should indicate whether or not the environment has already been created.
    +        """
    +
    +    @abstractmethod
    +    def install_project(self):
    +        """
    +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +        This should install the project in the environment.
    +        """
    +
    +    @abstractmethod
    +    def install_project_dev_mode(self):
    +        """
    +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +        This should install the project in the environment such that the environment
    +        always reflects the current state of the project.
    +        """
    +
    +    @abstractmethod
    +    def dependencies_in_sync(self) -> bool:
    +        """
    +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +        This should indicate whether or not the environment is compatible with the current
    +        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).
    +        """
    +
    +    @abstractmethod
    +    def sync_dependencies(self):
    +        """
    +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +        This should install the
    +        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
    +        in the environment.
    +        """
    +
    +    def dependency_hash(self):
    +        """
    +        This should return a hash of the environment's
    +        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
    +        and any other data that is handled by the
    +        [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)
    +        and
    +        [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)
    +        methods.
    +        """
    +        from hatch.utils.dep import hash_dependencies
     
    -    @contextmanager
    -    def build_environment(
    -        self,
    -        dependencies: list[str],  # noqa: ARG002
    -    ):
    -        """
    -        This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project
    -        given a set of dependencies and must be a context manager:
    -
    -        ```python
    -        with environment.build_environment([...]): ...
    -        ```
    -
    -        The build environment should reflect any
    -        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
    -        the user defined either currently or at the time of
    -        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    -        """
    -        with self.get_env_vars():
    -            yield
    -
    -    def run_builder(
    -        self,
    -        build_environment,  # noqa: ARG002
    -        **kwargs,
    -    ):
    -        """
    -        This will be called when the
    -        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    -        is active:
    -
    -        ```python
    -        with environment.build_environment([...]) as build_env:
    -            process = environment.run_builder(build_env, ...)
    -        ```
    -
    -        This should return the standard library's
    -        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).
    -        The command is constructed by passing all keyword arguments to
    -        [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).
    -
    -        For an example, open the default implementation below:
    +        return hash_dependencies(self.dependencies_complex)
    +
    +    @contextmanager
    +    def app_status_creation(self):
    +        """
    +        See the [life cycle of environments](reference.md#life-cycle).
    +        """
    +        with self.app.status(f'Creating environment: {self.name}'):
    +            yield
    +
    +    @contextmanager
    +    def app_status_pre_installation(self):
    +        """
    +        See the [life cycle of environments](reference.md#life-cycle).
    +        """
    +        with self.app.status('Running pre-installation commands'):
    +            yield
    +
    +    @contextmanager
    +    def app_status_post_installation(self):
    +        """
    +        See the [life cycle of environments](reference.md#life-cycle).
    +        """
    +        with self.app.status('Running post-installation commands'):
    +            yield
    +
    +    @contextmanager
    +    def app_status_project_installation(self):
    +        """
    +        See the [life cycle of environments](reference.md#life-cycle).
    +        """
    +        if self.dev_mode:
    +            with self.app.status('Installing project in development mode'):
    +                yield
    +        else:
    +            with self.app.status('Installing project'):
    +                yield
    +
    +    @contextmanager
    +    def app_status_dependency_state_check(self):
    +        """
    +        See the [life cycle of environments](reference.md#life-cycle).
             """
    -        return self.platform.run_command(self.construct_build_command(**kwargs))
    -
    -    def build_environment_exists(self):  # noqa: PLR6301
    -        """
    -        If the
    -        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    -        has a caching mechanism, this should indicate whether or not it has already been created.
    -        """
    -        return False
    -
    -    def enter_shell(
    -        self,
    -        name: str,  # noqa: ARG002
    -        path: str,
    -        args: Iterable[str],
    -    ):
    -        """
    -        Spawn a [shell](../../config/hatch.md#shell) within the environment.
    -
    -        This should either use
    -        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
    -        directly or provide the same guarantee.
    -        """
    -        with self.command_context():
    -            self.platform.exit_with_command([path, *args])
    -
    -    def run_shell_command(self, command: str, **kwargs):
    -        """
    -        This should return the standard library's
    -        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)
    -        and will always be called when the
    -        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
    -        is active, with the expectation of providing the same guarantee.
    -        """
    -        kwargs.setdefault('shell', True)
    -        return self.platform.run_command(command, **kwargs)
    -
    -    @contextmanager
    -    def command_context(self):
    -        """
    -        A context manager that when active should make executed shell commands reflect any
    -        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
    -        the user defined either currently or at the time of
    -        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    -
    -        For an example, open the default implementation below:
    -        """
    -        with self.get_env_vars():
    -            yield
    -
    -    def resolve_commands(self, commands: list[str]):
    +        if not self.skip_install and (
    +            'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic
    +        ):
    +            with self.app.status('Polling dependency state'):
    +                yield
    +        else:
    +            yield
    +
    +    @contextmanager
    +    def app_status_dependency_installation_check(self):
    +        """
    +        See the [life cycle of environments](reference.md#life-cycle).
    +        """
    +        with self.app.status('Checking dependencies'):
    +            yield
    +
    +    @contextmanager
    +    def app_status_dependency_synchronization(self):
    +        """
    +        See the [life cycle of environments](reference.md#life-cycle).
    +        """
    +        with self.app.status('Syncing dependencies'):
    +            yield
    +
    +    @contextmanager
    +    def build_environment(
    +        self,
    +        dependencies: list[str],  # noqa: ARG002
    +    ):
    +        """
    +        This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project
    +        given a set of dependencies and must be a context manager:
    +
    +        ```python
    +        with environment.build_environment([...]):
    +            ...
    +        ```
    +
    +        The build environment should reflect any
    +        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
    +        the user defined either currently or at the time of
    +        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    +        """
    +        with self.get_env_vars():
    +            yield
    +
    +    def run_builder(
    +        self,
    +        build_environment,  # noqa: ARG002
    +        **kwargs,
    +    ):
             """
    -        This expands each command into one or more commands based on any
    -        [scripts](../../config/environment/overview.md#scripts) that the user defined.
    -        """
    -        for command in commands:
    -            yield from self.expand_command(command)
    -
    -    def expand_command(self, command):
    -        possible_script, args, _ignore_exit_code = parse_script_command(command)
    +        This will be called when the
    +        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    +        is active:
    +
    +        ```python
    +        with environment.build_environment([...]) as build_env:
    +            process = environment.run_builder(build_env, ...)
    +        ```
     
    -        # Indicate undefined
    -        if not args:
    -            args = None
    -
    -        with self.apply_context():
    -            if possible_script in self.scripts:
    -                for cmd in self.scripts[possible_script]:
    -                    yield self.metadata.context.format(cmd, args=args).strip()
    -            else:
    -                yield self.metadata.context.format(command, args=args).strip()
    -
    -    def construct_build_command(  # noqa: PLR6301
    -        self,
    -        *,
    -        directory=None,
    -        targets=(),
    -        hooks_only=False,
    -        no_hooks=False,
    -        clean=False,
    -        clean_hooks_after=False,
    -        clean_only=False,
    -    ):
    -        """
    -        This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to
    -        a subprocess command issued to [builders](../builder/reference.md).
    -        """
    -        command = ['python', '-u', '-m', 'hatchling', 'build']
    -
    -        if directory:
    -            command.extend(('--directory', directory))
    -
    -        if targets:
    -            for target in targets:
    -                command.extend(('--target', target))
    -
    -        if hooks_only:
    -            command.append('--hooks-only')
    -
    -        if no_hooks:
    -            command.append('--no-hooks')
    -
    -        if clean:
    -            command.append('--clean')
    +        This should return the standard library's
    +        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).
    +        The command is constructed by passing all keyword arguments to
    +        [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).
    +
    +        For an example, open the default implementation below:
    +        """
    +        return self.platform.run_command(self.construct_build_command(**kwargs))
    +
    +    def build_environment_exists(self):  # noqa: PLR6301
    +        """
    +        If the
    +        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    +        has a caching mechanism, this should indicate whether or not it has already been created.
    +        """
    +        return False
    +
    +    def enter_shell(
    +        self,
    +        name: str,  # noqa: ARG002
    +        path: str,
    +        args: Iterable[str],
    +    ):
    +        """
    +        Spawn a [shell](../../config/hatch.md#shell) within the environment.
    +
    +        This should either use
    +        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
    +        directly or provide the same guarantee.
    +        """
    +        with self.command_context():
    +            self.platform.exit_with_command([path, *args])
    +
    +    def run_shell_command(self, command: str, **kwargs):
    +        """
    +        This should return the standard library's
    +        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)
    +        and will always be called when the
    +        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
    +        is active, with the expectation of providing the same guarantee.
    +        """
    +        kwargs.setdefault('shell', True)
    +        return self.platform.run_command(command, **kwargs)
     
    -        if clean_hooks_after:
    -            command.append('--clean-hooks-after')
    -
    -        if clean_only:
    -            command.append('--clean-only')
    -
    -        return command
    +    @contextmanager
    +    def command_context(self):
    +        """
    +        A context manager that when active should make executed shell commands reflect any
    +        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
    +        the user defined either currently or at the time of
    +        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
     
    -    def construct_pip_install_command(self, args: list[str]):
    -        """
    -        A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)
    -        command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.
    -        """
    -        command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']
    -
    -        # Default to -1 verbosity
    -        add_verbosity_flag(command, self.verbosity, adjustment=-1)
    -
    -        command.extend(args)
    -        return command
    +        For an example, open the default implementation below:
    +        """
    +        with self.get_env_vars():
    +            yield
    +
    +    def resolve_commands(self, commands: list[str]):
    +        """
    +        This expands each command into one or more commands based on any
    +        [scripts](../../config/environment/overview.md#scripts) that the user defined.
    +        """
    +        for command in commands:
    +            yield from self.expand_command(command)
     
    -    def join_command_args(self, args: list[str]):
    -        """
    -        This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string
    -        from the received arguments.
    -        """
    -        return self.platform.join_command_args(args)
    +    def expand_command(self, command):
    +        possible_script, args, _ignore_exit_code = parse_script_command(command)
    +
    +        # Indicate undefined
    +        if not args:
    +            args = None
     
    -    def apply_features(self, requirement: str):
    -        """
    -        A convenience method that applies any user defined [features](../../config/environment/overview.md#features)
    -        to the given requirement.
    -        """
    -        if self.features:
    -            features = ','.join(self.features)
    -            return f'{requirement}[{features}]'
    -
    -        return requirement
    -
    -    def check_compatibility(self):
    -        """
    -        This raises an exception if the environment is not compatible with the user's setup. The default behavior
    -        checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)
    -        and any method override should keep this check.
    -
    -        This check is never performed if the environment has been
    -        [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    -        """
    -        if self.platforms and self.platform.name not in self.platforms:
    -            message = 'unsupported platform'
    -            raise OSError(message)
    +        with self.apply_context():
    +            if possible_script in self.scripts:
    +                for cmd in self.scripts[possible_script]:
    +                    yield self.metadata.context.format(cmd, args=args).strip()
    +            else:
    +                yield self.metadata.context.format(command, args=args).strip()
    +
    +    def construct_build_command(  # noqa: PLR6301
    +        self,
    +        *,
    +        directory=None,
    +        targets=(),
    +        hooks_only=False,
    +        no_hooks=False,
    +        clean=False,
    +        clean_hooks_after=False,
    +        clean_only=False,
    +    ):
    +        """
    +        This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to
    +        a subprocess command issued to [builders](../builder/reference.md).
    +        """
    +        command = ['python', '-u', '-m', 'hatchling', 'build']
     
    -    def get_env_vars(self) -> EnvVars:
    -        """
    -        Returns a mapping of environment variables that should be available to the environment. The object can
    -        be used as a context manager to temporarily apply the environment variables to the current process.
    -
    -        !!! note
    -            The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.
    -        """
    -        return EnvVars(self.env_vars, self.env_include, self.env_exclude)
    +        if directory:
    +            command.extend(('--directory', directory))
    +
    +        if targets:
    +            for target in targets:
    +                command.extend(('--target', target))
    +
    +        if hooks_only:
    +            command.append('--hooks-only')
     
    -    def get_env_var_option(self, option: str) -> str:
    -        """
    -        Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.
    -        """
    -        return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')
    +        if no_hooks:
    +            command.append('--no-hooks')
    +
    +        if clean:
    +            command.append('--clean')
     
    -    def get_context(self):
    -        """
    -        Returns a subclass of
    -        [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).
    -        """
    -        from hatch.env.context import EnvironmentContextFormatter
    -
    -        return EnvironmentContextFormatter(self)
    -
    -    @staticmethod
    -    def get_option_types() -> dict:
    -        """
    -        Returns a mapping of supported options to their respective types so that they can be used by
    -        [overrides](../../config/environment/advanced.md#option-overrides).
    -        """
    -        return {}
    -
    -    @contextmanager
    -    def apply_context(self):
    -        with self.get_env_vars(), self.metadata.context.apply_context(self.context):
    -            yield
    -
    -    def __enter__(self):
    -        self.activate()
    -        return self
    -
    -    def __exit__(self, exc_type, exc_value, traceback):
    -        self.deactivate()
    +        if clean_hooks_after:
    +            command.append('--clean-hooks-after')
    +
    +        if clean_only:
    +            command.append('--clean-only')
    +
    +        return command
    +
    +    def construct_pip_install_command(self, args: list[str]):
    +        """
    +        A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)
    +        command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.
    +        """
    +        command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']
    +
    +        # Default to -1 verbosity
    +        add_verbosity_flag(command, self.verbosity, adjustment=-1)
    +
    +        command.extend(args)
    +        return command
    +
    +    def join_command_args(self, args: list[str]):
    +        """
    +        This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string
    +        from the received arguments.
    +        """
    +        return self.platform.join_command_args(args)
    +
    +    def apply_features(self, requirement: str):
    +        """
    +        A convenience method that applies any user defined [features](../../config/environment/overview.md#features)
    +        to the given requirement.
    +        """
    +        if self.features:
    +            features = ','.join(self.features)
    +            return f'{requirement}[{features}]'
    +
    +        return requirement
    +
    +    def check_compatibility(self):
    +        """
    +        This raises an exception if the environment is not compatible with the user's setup. The default behavior
    +        checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)
    +        and any method override should keep this check.
    +
    +        This check is never performed if the environment has been
    +        [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    +        """
    +        if self.platforms and self.platform.name not in self.platforms:
    +            message = 'unsupported platform'
    +            raise OSError(message)
    +
    +    def get_env_vars(self) -> EnvVars:
    +        """
    +        Returns a mapping of environment variables that should be available to the environment. The object can
    +        be used as a context manager to temporarily apply the environment variables to the current process.
    +
    +        !!! note
    +            The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.
    +        """
    +        return EnvVars(self.env_vars, self.env_include, self.env_exclude)
    +
    +    def get_env_var_option(self, option: str) -> str:
    +        """
    +        Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.
    +        """
    +        return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')
    +
    +    def get_context(self):
    +        """
    +        Returns a subclass of
    +        [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).
    +        """
    +        from hatch.env.context import EnvironmentContextFormatter
    +
    +        return EnvironmentContextFormatter(self)
    +
    +    @staticmethod
    +    def get_option_types() -> dict:
    +        """
    +        Returns a mapping of supported options to their respective types so that they can be used by
    +        [overrides](../../config/environment/advanced.md#option-overrides).
    +        """
    +        return {}
    +
    +    @contextmanager
    +    def apply_context(self):
    +        with self.get_env_vars(), self.metadata.context.apply_context(self.context):
    +            yield
    +
    +    def __enter__(self):
    +        self.activate()
    +        return self
    +
    +    def __exit__(self, exc_type, exc_value, traceback):
    +        self.deactivate()
     

    PLUGIN_NAME = '' class-attribute instance-attribute

    The name used for selection.

    app property

    An instance of Application.

    root property

    The root of the project tree as a path-like object.

    name: str property

    The name of the environment.

    data_directory property

    The directory this plugin should use for storage as a path-like object. If the user has not configured one then this will be the same as the isolated data directory.

    isolated_data_directory property

    The default directory reserved exclusively for this plugin as a path-like object.

    config: dict property

    [tool.hatch.envs.<ENV_NAME>]
     
    [envs.<ENV_NAME>]
     

    platform property

    An instance of Platform.

    environment_dependencies: list[str] property

    The list of all environment dependencies.

    dependencies: list[str] property

    env_vars: dict property

    [tool.hatch.envs.<ENV_NAME>.env-vars]
    @@ -979,309 +1048,373 @@
     description = ...
     
    [envs.<ENV_NAME>]
     description = ...
    -

    activate()

    A convenience method called when using the environment as a context manager:

    with environment: ...
    +

    find() abstractmethod

    REQUIRED

    This should return information about how to locate the environment or represent its ID in some way. Additionally, this is expected to return something even if the environment is incompatible.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    +def find(self):
    +    """
    +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +    This should return information about how to locate the environment or represent its ID in
    +    some way. Additionally, this is expected to return something even if the environment is
    +    [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).
    +    """
    +

    create() abstractmethod

    REQUIRED

    This should perform the necessary steps to set up the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    +def create(self):
    +    """
    +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +    This should perform the necessary steps to set up the environment.
    +    """
    +

    remove() abstractmethod

    REQUIRED

    This should perform the necessary steps to completely remove the environment from the system and will only be triggered manually by users with the env remove or env prune commands.

    If the build environment has a caching mechanism, this should remove that as well.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    +def remove(self):
    +    """
    +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +    This should perform the necessary steps to completely remove the environment from the system and will only
    +    be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or
    +    [`env prune`](../../cli/reference.md#hatch-env-prune) commands.
    +
    +    If the
    +    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    +    has a caching mechanism, this should remove that as well.
    +    """
    +

    exists() -> bool abstractmethod

    REQUIRED

    This should indicate whether or not the environment has already been created.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    +def exists(self) -> bool:
    +    """
    +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +    This should indicate whether or not the environment has already been created.
    +    """
    +

    install_project() abstractmethod

    REQUIRED

    This should install the project in the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    +def install_project(self):
    +    """
    +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +    This should install the project in the environment.
    +    """
    +

    install_project_dev_mode() abstractmethod

    REQUIRED

    This should install the project in the environment such that the environment always reflects the current state of the project.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    +def install_project_dev_mode(self):
    +    """
    +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +    This should install the project in the environment such that the environment
    +    always reflects the current state of the project.
    +    """
    +

    dependencies_in_sync() -> bool abstractmethod

    REQUIRED

    This should indicate whether or not the environment is compatible with the current dependencies.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    +def dependencies_in_sync(self) -> bool:
    +    """
    +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +    This should indicate whether or not the environment is compatible with the current
    +    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).
    +    """
    +

    sync_dependencies() abstractmethod

    REQUIRED

    This should install the dependencies in the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    +def sync_dependencies(self):
    +    """
    +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    +
    +    This should install the
    +    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
    +    in the environment.
    +    """
    +

    dependency_hash()

    This should return a hash of the environment's dependencies and any other data that is handled by the sync_dependencies and dependencies_in_sync methods.

    Source code in src/hatch/env/plugin/interface.py
    def dependency_hash(self):
    +    """
    +    This should return a hash of the environment's
    +    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
    +    and any other data that is handled by the
    +    [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)
    +    and
    +    [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)
    +    methods.
    +    """
    +    from hatch.utils.dep import hash_dependencies
    +
    +    return hash_dependencies(self.dependencies_complex)
    +

    build_environment(dependencies: list[str])

    This should set up an isolated environment in which to build the project given a set of dependencies and must be a context manager:

    with environment.build_environment([...]):
    +    ...
    +

    The build environment should reflect any environment variables the user defined either currently or at the time of creation.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    +def build_environment(
    +    self,
    +    dependencies: list[str],  # noqa: ARG002
    +):
    +    """
    +    This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project
    +    given a set of dependencies and must be a context manager:
    +
    +    ```python
    +    with environment.build_environment([...]):
    +        ...
    +    ```
    +
    +    The build environment should reflect any
    +    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
    +    the user defined either currently or at the time of
    +    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    +    """
    +    with self.get_env_vars():
    +        yield
    +

    build_environment_exists()

    If the build environment has a caching mechanism, this should indicate whether or not it has already been created.

    Source code in src/hatch/env/plugin/interface.py
    def build_environment_exists(self):  # noqa: PLR6301
    +    """
    +    If the
    +    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    +    has a caching mechanism, this should indicate whether or not it has already been created.
    +    """
    +    return False
    +

    activate()

    A convenience method called when using the environment as a context manager:

    with environment:
    +    ...
     
    Source code in src/hatch/env/plugin/interface.py
    def activate(self):
         """
         A convenience method called when using the environment as a context manager:
     
         ```python
    -    with environment: ...
    -    ```
    -    """
    -

    deactivate()

    A convenience method called after using the environment as a context manager:

    with environment: ...
    -
    Source code in src/hatch/env/plugin/interface.py
    def deactivate(self):
    -    """
    -    A convenience method called after using the environment as a context manager:
    -
    -    ```python
    -    with environment: ...
    -    ```
    -    """
    -

    find() abstractmethod

    REQUIRED

    This should return information about how to locate the environment or represent its ID in some way. Additionally, this is expected to return something even if the environment is incompatible.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    -def find(self):
    -    """
    -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -    This should return information about how to locate the environment or represent its ID in
    -    some way. Additionally, this is expected to return something even if the environment is
    -    [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).
    -    """
    -

    create() abstractmethod

    REQUIRED

    This should perform the necessary steps to set up the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    -def create(self):
    -    """
    -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -    This should perform the necessary steps to set up the environment.
    -    """
    -

    remove() abstractmethod

    REQUIRED

    This should perform the necessary steps to completely remove the environment from the system and will only be triggered manually by users with the env remove or env prune commands.

    If the build environment has a caching mechanism, this should remove that as well.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    -def remove(self):
    -    """
    -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -    This should perform the necessary steps to completely remove the environment from the system and will only
    -    be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or
    -    [`env prune`](../../cli/reference.md#hatch-env-prune) commands.
    -
    -    If the
    -    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    -    has a caching mechanism, this should remove that as well.
    -    """
    -

    exists() -> bool abstractmethod

    REQUIRED

    This should indicate whether or not the environment has already been created.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    -def exists(self) -> bool:
    -    """
    -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -    This should indicate whether or not the environment has already been created.
    -    """
    -

    install_project() abstractmethod

    REQUIRED

    This should install the project in the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    -def install_project(self):
    -    """
    -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -    This should install the project in the environment.
    -    """
    -

    install_project_dev_mode() abstractmethod

    REQUIRED

    This should install the project in the environment such that the environment always reflects the current state of the project.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    -def install_project_dev_mode(self):
    -    """
    -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -    This should install the project in the environment such that the environment
    -    always reflects the current state of the project.
    -    """
    -

    dependencies_in_sync() -> bool abstractmethod

    REQUIRED

    This should indicate whether or not the environment is compatible with the current dependencies.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    -def dependencies_in_sync(self) -> bool:
    -    """
    -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -    This should indicate whether or not the environment is compatible with the current
    -    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).
    -    """
    -

    sync_dependencies() abstractmethod

    REQUIRED

    This should install the dependencies in the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod
    -def sync_dependencies(self):
    -    """
    -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
    -
    -    This should install the
    -    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
    -    in the environment.
    -    """
    -

    dependency_hash()

    This should return a hash of the environment's dependencies and any other data that is handled by the sync_dependencies and dependencies_in_sync methods.

    Source code in src/hatch/env/plugin/interface.py
    def dependency_hash(self):
    -    """
    -    This should return a hash of the environment's
    -    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
    -    and any other data that is handled by the
    -    [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)
    -    and
    -    [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)
    -    methods.
    -    """
    -    from hatch.utils.dep import hash_dependencies
    -
    -    return hash_dependencies(self.dependencies_complex)
    -

    build_environment(dependencies: list[str])

    This should set up an isolated environment in which to build the project given a set of dependencies and must be a context manager:

    with environment.build_environment([...]): ...
    -

    The build environment should reflect any environment variables the user defined either currently or at the time of creation.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    -def build_environment(
    -    self,
    -    dependencies: list[str],  # noqa: ARG002
    -):
    -    """
    -    This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project
    -    given a set of dependencies and must be a context manager:
    -
    -    ```python
    -    with environment.build_environment([...]): ...
    -    ```
    -
    -    The build environment should reflect any
    -    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
    -    the user defined either currently or at the time of
    -    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    -    """
    -    with self.get_env_vars():
    -        yield
    -

    build_environment_exists()

    If the build environment has a caching mechanism, this should indicate whether or not it has already been created.

    Source code in src/hatch/env/plugin/interface.py
    def build_environment_exists(self):  # noqa: PLR6301
    -    """
    -    If the
    -    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    -    has a caching mechanism, this should indicate whether or not it has already been created.
    -    """
    -    return False
    +    with environment:
    +        ...
    +    ```
    +    """
    +

    deactivate()

    A convenience method called after using the environment as a context manager:

    with environment:
    +    ...
    +
    Source code in src/hatch/env/plugin/interface.py
    def deactivate(self):
    +    """
    +    A convenience method called after using the environment as a context manager:
    +
    +    ```python
    +    with environment:
    +        ...
    +    ```
    +    """
    +

    app_status_creation()

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    +def app_status_creation(self):
    +    """
    +    See the [life cycle of environments](reference.md#life-cycle).
    +    """
    +    with self.app.status(f'Creating environment: {self.name}'):
    +        yield
    +

    app_status_pre_installation()

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    +def app_status_pre_installation(self):
    +    """
    +    See the [life cycle of environments](reference.md#life-cycle).
    +    """
    +    with self.app.status('Running pre-installation commands'):
    +        yield
    +

    app_status_post_installation()

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    +def app_status_post_installation(self):
    +    """
    +    See the [life cycle of environments](reference.md#life-cycle).
    +    """
    +    with self.app.status('Running post-installation commands'):
    +        yield
    +

    app_status_project_installation()

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    +def app_status_project_installation(self):
    +    """
    +    See the [life cycle of environments](reference.md#life-cycle).
    +    """
    +    if self.dev_mode:
    +        with self.app.status('Installing project in development mode'):
    +            yield
    +    else:
    +        with self.app.status('Installing project'):
    +            yield
    +

    app_status_dependency_state_check()

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    +def app_status_dependency_state_check(self):
    +    """
    +    See the [life cycle of environments](reference.md#life-cycle).
    +    """
    +    if not self.skip_install and (
    +        'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic
    +    ):
    +        with self.app.status('Polling dependency state'):
    +            yield
    +    else:
    +        yield
    +

    app_status_dependency_installation_check()

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    +def app_status_dependency_installation_check(self):
    +    """
    +    See the [life cycle of environments](reference.md#life-cycle).
    +    """
    +    with self.app.status('Checking dependencies'):
    +        yield
    +

    app_status_dependency_synchronization()

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    +def app_status_dependency_synchronization(self):
    +    """
    +    See the [life cycle of environments](reference.md#life-cycle).
    +    """
    +    with self.app.status('Syncing dependencies'):
    +        yield
     

    run_builder(build_environment, **kwargs)

    This will be called when the build environment is active:

    with environment.build_environment([...]) as build_env:
         process = environment.run_builder(build_env, ...)
    -

    This should return the standard library's subprocess.CompletedProcess. The command is constructed by passing all keyword arguments to construct_build_command.

    For an example, open the default implementation below:

    Source code in src/hatch/env/plugin/interface.py
    def run_builder(
    -    self,
    -    build_environment,  # noqa: ARG002
    -    **kwargs,
    -):
    -    """
    -    This will be called when the
    -    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
    -    is active:
    -
    -    ```python
    -    with environment.build_environment([...]) as build_env:
    -        process = environment.run_builder(build_env, ...)
    -    ```
    -
    -    This should return the standard library's
    -    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).
    -    The command is constructed by passing all keyword arguments to
    -    [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).
    -
    -    For an example, open the default implementation below:
    -    """
    -    return self.platform.run_command(self.construct_build_command(**kwargs))
    -

    construct_build_command(*, directory=None, targets=(), hooks_only=False, no_hooks=False, clean=False, clean_hooks_after=False, clean_only=False)

    This is the canonical way build command options are translated to a subprocess command issued to builders.

    Source code in src/hatch/env/plugin/interface.py
    def construct_build_command(  # noqa: PLR6301
    -    self,
    -    *,
    -    directory=None,
    -    targets=(),
    -    hooks_only=False,
    -    no_hooks=False,
    -    clean=False,
    -    clean_hooks_after=False,
    -    clean_only=False,
    -):
    -    """
    -    This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to
    -    a subprocess command issued to [builders](../builder/reference.md).
    -    """
    -    command = ['python', '-u', '-m', 'hatchling', 'build']
    -
    -    if directory:
    -        command.extend(('--directory', directory))
    -
    -    if targets:
    -        for target in targets:
    -            command.extend(('--target', target))
    -
    -    if hooks_only:
    -        command.append('--hooks-only')
    -
    -    if no_hooks:
    -        command.append('--no-hooks')
    -
    -    if clean:
    -        command.append('--clean')
    -
    -    if clean_hooks_after:
    -        command.append('--clean-hooks-after')
    -
    -    if clean_only:
    -        command.append('--clean-only')
    -
    -    return command
    -

    command_context()

    A context manager that when active should make executed shell commands reflect any environment variables the user defined either currently or at the time of creation.

    For an example, open the default implementation below:

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    -def command_context(self):
    -    """
    -    A context manager that when active should make executed shell commands reflect any
    -    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
    -    the user defined either currently or at the time of
    -    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    -
    -    For an example, open the default implementation below:
    -    """
    -    with self.get_env_vars():
    -        yield
    -

    enter_shell(name: str, path: str, args: Iterable[str])

    Spawn a shell within the environment.

    This should either use command_context directly or provide the same guarantee.

    Source code in src/hatch/env/plugin/interface.py
    def enter_shell(
    -    self,
    -    name: str,  # noqa: ARG002
    -    path: str,
    -    args: Iterable[str],
    -):
    -    """
    -    Spawn a [shell](../../config/hatch.md#shell) within the environment.
    -
    -    This should either use
    -    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
    -    directly or provide the same guarantee.
    -    """
    -    with self.command_context():
    -        self.platform.exit_with_command([path, *args])
    -

    run_shell_command(command: str, **kwargs)

    This should return the standard library's subprocess.CompletedProcess and will always be called when the command_context is active, with the expectation of providing the same guarantee.

    Source code in src/hatch/env/plugin/interface.py
    def run_shell_command(self, command: str, **kwargs):
    -    """
    -    This should return the standard library's
    -    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)
    -    and will always be called when the
    -    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
    -    is active, with the expectation of providing the same guarantee.
    -    """
    -    kwargs.setdefault('shell', True)
    -    return self.platform.run_command(command, **kwargs)
    -

    resolve_commands(commands: list[str])

    This expands each command into one or more commands based on any scripts that the user defined.

    Source code in src/hatch/env/plugin/interface.py
    def resolve_commands(self, commands: list[str]):
    +

    This should return the standard library's subprocess.CompletedProcess. The command is constructed by passing all keyword arguments to construct_build_command.

    For an example, open the default implementation below:

    Source code in src/hatch/env/plugin/interface.py
    def run_builder(
    +    self,
    +    build_environment,  # noqa: ARG002
    +    **kwargs,
    +):
         """
    -    This expands each command into one or more commands based on any
    -    [scripts](../../config/environment/overview.md#scripts) that the user defined.
    -    """
    -    for command in commands:
    -        yield from self.expand_command(command)
    -

    get_env_vars() -> EnvVars

    Returns a mapping of environment variables that should be available to the environment. The object can be used as a context manager to temporarily apply the environment variables to the current process.

    Note

    The environment variable HATCH_ENV_ACTIVE will always be set to the name of the environment.

    Source code in src/hatch/env/plugin/interface.py
    def get_env_vars(self) -> EnvVars:
    -    """
    -    Returns a mapping of environment variables that should be available to the environment. The object can
    -    be used as a context manager to temporarily apply the environment variables to the current process.
    -
    -    !!! note
    -        The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.
    -    """
    -    return EnvVars(self.env_vars, self.env_include, self.env_exclude)
    -

    apply_features(requirement: str)

    A convenience method that applies any user defined features to the given requirement.

    Source code in src/hatch/env/plugin/interface.py
    def apply_features(self, requirement: str):
    -    """
    -    A convenience method that applies any user defined [features](../../config/environment/overview.md#features)
    -    to the given requirement.
    -    """
    -    if self.features:
    -        features = ','.join(self.features)
    -        return f'{requirement}[{features}]'
    -
    -    return requirement
    -

    construct_pip_install_command(args: list[str])

    A convenience method for constructing a pip install command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.

    Source code in src/hatch/env/plugin/interface.py
    def construct_pip_install_command(self, args: list[str]):
    -    """
    -    A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)
    -    command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.
    -    """
    -    command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']
    -
    -    # Default to -1 verbosity
    -    add_verbosity_flag(command, self.verbosity, adjustment=-1)
    -
    -    command.extend(args)
    -    return command
    -

    join_command_args(args: list[str])

    This is used by the run command to construct the root command string from the received arguments.

    Source code in src/hatch/env/plugin/interface.py
    def join_command_args(self, args: list[str]):
    -    """
    -    This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string
    -    from the received arguments.
    -    """
    -    return self.platform.join_command_args(args)
    -

    check_compatibility()

    This raises an exception if the environment is not compatible with the user's setup. The default behavior checks for platform compatibility and any method override should keep this check.

    This check is never performed if the environment has been created.

    Source code in src/hatch/env/plugin/interface.py
    def check_compatibility(self):
    -    """
    -    This raises an exception if the environment is not compatible with the user's setup. The default behavior
    -    checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)
    -    and any method override should keep this check.
    -
    -    This check is never performed if the environment has been
    -    [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    -    """
    -    if self.platforms and self.platform.name not in self.platforms:
    -        message = 'unsupported platform'
    -        raise OSError(message)
    -

    get_option_types() -> dict staticmethod

    Returns a mapping of supported options to their respective types so that they can be used by overrides.

    Source code in src/hatch/env/plugin/interface.py
    @staticmethod
    -def get_option_types() -> dict:
    -    """
    -    Returns a mapping of supported options to their respective types so that they can be used by
    -    [overrides](../../config/environment/advanced.md#option-overrides).
    -    """
    -    return {}
    -

    get_env_var_option(option: str) -> str

    Returns the value of the upper-cased environment variable HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>.

    Source code in src/hatch/env/plugin/interface.py
    def get_env_var_option(self, option: str) -> str:
    -    """
    -    Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.
    -    """
    -    return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')
    -

    get_context()

    Returns a subclass of EnvironmentContextFormatter.

    Source code in src/hatch/env/plugin/interface.py
    def get_context(self):
    -    """
    -    Returns a subclass of
    -    [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).
    -    """
    -    from hatch.env.context import EnvironmentContextFormatter
    -
    -    return EnvironmentContextFormatter(self)
    -
    \ No newline at end of file + This will be called when the + [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment) + is active: + + ```python + with environment.build_environment([...]) as build_env: + process = environment.run_builder(build_env, ...) + ``` + + This should return the standard library's + [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess). + The command is constructed by passing all keyword arguments to + [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command). + + For an example, open the default implementation below: + """ + return self.platform.run_command(self.construct_build_command(**kwargs)) +

    construct_build_command(*, directory=None, targets=(), hooks_only=False, no_hooks=False, clean=False, clean_hooks_after=False, clean_only=False)

    This is the canonical way build command options are translated to a subprocess command issued to builders.

    Source code in src/hatch/env/plugin/interface.py
    def construct_build_command(  # noqa: PLR6301
    +    self,
    +    *,
    +    directory=None,
    +    targets=(),
    +    hooks_only=False,
    +    no_hooks=False,
    +    clean=False,
    +    clean_hooks_after=False,
    +    clean_only=False,
    +):
    +    """
    +    This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to
    +    a subprocess command issued to [builders](../builder/reference.md).
    +    """
    +    command = ['python', '-u', '-m', 'hatchling', 'build']
    +
    +    if directory:
    +        command.extend(('--directory', directory))
    +
    +    if targets:
    +        for target in targets:
    +            command.extend(('--target', target))
    +
    +    if hooks_only:
    +        command.append('--hooks-only')
    +
    +    if no_hooks:
    +        command.append('--no-hooks')
    +
    +    if clean:
    +        command.append('--clean')
    +
    +    if clean_hooks_after:
    +        command.append('--clean-hooks-after')
    +
    +    if clean_only:
    +        command.append('--clean-only')
    +
    +    return command
    +

    command_context()

    A context manager that when active should make executed shell commands reflect any environment variables the user defined either currently or at the time of creation.

    For an example, open the default implementation below:

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager
    +def command_context(self):
    +    """
    +    A context manager that when active should make executed shell commands reflect any
    +    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
    +    the user defined either currently or at the time of
    +    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    +
    +    For an example, open the default implementation below:
    +    """
    +    with self.get_env_vars():
    +        yield
    +

    enter_shell(name: str, path: str, args: Iterable[str])

    Spawn a shell within the environment.

    This should either use command_context directly or provide the same guarantee.

    Source code in src/hatch/env/plugin/interface.py
    def enter_shell(
    +    self,
    +    name: str,  # noqa: ARG002
    +    path: str,
    +    args: Iterable[str],
    +):
    +    """
    +    Spawn a [shell](../../config/hatch.md#shell) within the environment.
    +
    +    This should either use
    +    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
    +    directly or provide the same guarantee.
    +    """
    +    with self.command_context():
    +        self.platform.exit_with_command([path, *args])
    +

    run_shell_command(command: str, **kwargs)

    This should return the standard library's subprocess.CompletedProcess and will always be called when the command_context is active, with the expectation of providing the same guarantee.

    Source code in src/hatch/env/plugin/interface.py
    def run_shell_command(self, command: str, **kwargs):
    +    """
    +    This should return the standard library's
    +    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)
    +    and will always be called when the
    +    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
    +    is active, with the expectation of providing the same guarantee.
    +    """
    +    kwargs.setdefault('shell', True)
    +    return self.platform.run_command(command, **kwargs)
    +

    resolve_commands(commands: list[str])

    This expands each command into one or more commands based on any scripts that the user defined.

    Source code in src/hatch/env/plugin/interface.py
    def resolve_commands(self, commands: list[str]):
    +    """
    +    This expands each command into one or more commands based on any
    +    [scripts](../../config/environment/overview.md#scripts) that the user defined.
    +    """
    +    for command in commands:
    +        yield from self.expand_command(command)
    +

    get_env_vars() -> EnvVars

    Returns a mapping of environment variables that should be available to the environment. The object can be used as a context manager to temporarily apply the environment variables to the current process.

    Note

    The environment variable HATCH_ENV_ACTIVE will always be set to the name of the environment.

    Source code in src/hatch/env/plugin/interface.py
    def get_env_vars(self) -> EnvVars:
    +    """
    +    Returns a mapping of environment variables that should be available to the environment. The object can
    +    be used as a context manager to temporarily apply the environment variables to the current process.
    +
    +    !!! note
    +        The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.
    +    """
    +    return EnvVars(self.env_vars, self.env_include, self.env_exclude)
    +

    apply_features(requirement: str)

    A convenience method that applies any user defined features to the given requirement.

    Source code in src/hatch/env/plugin/interface.py
    def apply_features(self, requirement: str):
    +    """
    +    A convenience method that applies any user defined [features](../../config/environment/overview.md#features)
    +    to the given requirement.
    +    """
    +    if self.features:
    +        features = ','.join(self.features)
    +        return f'{requirement}[{features}]'
    +
    +    return requirement
    +

    construct_pip_install_command(args: list[str])

    A convenience method for constructing a pip install command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.

    Source code in src/hatch/env/plugin/interface.py
    def construct_pip_install_command(self, args: list[str]):
    +    """
    +    A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)
    +    command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.
    +    """
    +    command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']
    +
    +    # Default to -1 verbosity
    +    add_verbosity_flag(command, self.verbosity, adjustment=-1)
    +
    +    command.extend(args)
    +    return command
    +

    join_command_args(args: list[str])

    This is used by the run command to construct the root command string from the received arguments.

    Source code in src/hatch/env/plugin/interface.py
    def join_command_args(self, args: list[str]):
    +    """
    +    This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string
    +    from the received arguments.
    +    """
    +    return self.platform.join_command_args(args)
    +

    check_compatibility()

    This raises an exception if the environment is not compatible with the user's setup. The default behavior checks for platform compatibility and any method override should keep this check.

    This check is never performed if the environment has been created.

    Source code in src/hatch/env/plugin/interface.py
    def check_compatibility(self):
    +    """
    +    This raises an exception if the environment is not compatible with the user's setup. The default behavior
    +    checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)
    +    and any method override should keep this check.
    +
    +    This check is never performed if the environment has been
    +    [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
    +    """
    +    if self.platforms and self.platform.name not in self.platforms:
    +        message = 'unsupported platform'
    +        raise OSError(message)
    +

    get_option_types() -> dict staticmethod

    Returns a mapping of supported options to their respective types so that they can be used by overrides.

    Source code in src/hatch/env/plugin/interface.py
    @staticmethod
    +def get_option_types() -> dict:
    +    """
    +    Returns a mapping of supported options to their respective types so that they can be used by
    +    [overrides](../../config/environment/advanced.md#option-overrides).
    +    """
    +    return {}
    +

    get_env_var_option(option: str) -> str

    Returns the value of the upper-cased environment variable HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>.

    Source code in src/hatch/env/plugin/interface.py
    def get_env_var_option(self, option: str) -> str:
    +    """
    +    Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.
    +    """
    +    return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')
    +

    get_context()

    Returns a subclass of EnvironmentContextFormatter.

    Source code in src/hatch/env/plugin/interface.py
    def get_context(self):
    +    """
    +    Returns a subclass of
    +    [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).
    +    """
    +    from hatch.env.context import EnvironmentContextFormatter
    +
    +    return EnvironmentContextFormatter(self)
    +
    \ No newline at end of file diff --git a/1.9/plugins/environment/virtual/index.html b/1.9/plugins/environment/virtual/index.html index 002b4868b..a06148360 100644 --- a/1.9/plugins/environment/virtual/index.html +++ b/1.9/plugins/environment/virtual/index.html @@ -1,4 +1,4 @@ - Virtual - Hatch

    Virtual environment


    This uses virtual environments backed by the standard virtualenv tool.

    Configuration

    The environment plugin name is virtual.

    [tool.hatch.envs.<ENV_NAME>]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Virtual environment


    This uses virtual environments backed by the standard virtualenv tool.

    Configuration

    The environment plugin name is virtual.

    [tool.hatch.envs.<ENV_NAME>]
     type = "virtual"
     
    [envs.<ENV_NAME>]
     type = "virtual"
    diff --git a/1.9/plugins/metadata-hook/custom/index.html b/1.9/plugins/metadata-hook/custom/index.html
    index acd1efdbe..c3014bc25 100644
    --- a/1.9/plugins/metadata-hook/custom/index.html
    +++ b/1.9/plugins/metadata-hook/custom/index.html
    @@ -1,4 +1,4 @@
    - Custom - Hatch      

    Custom metadata hook


    This is a custom class in a given Python file that inherits from the MetadataHookInterface.

    Configuration

    The metadata hook plugin name is custom.

    [tool.hatch.metadata.hooks.custom]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Custom metadata hook


    This is a custom class in a given Python file that inherits from the MetadataHookInterface.

    Configuration

    The metadata hook plugin name is custom.

    [tool.hatch.metadata.hooks.custom]
     
    [metadata.hooks.custom]
    -

    Options

    Option Default Description
    path hatch_build.py The path of the Python file

    Example

        from hatchling.metadata.plugin.interface import MetadataHookInterface
    +

    Options

    Option Default Description
    path hatch_build.py The path of the Python file

    Example

    from hatchling.metadata.plugin.interface import MetadataHookInterface
     
     
    -    class CustomMetadataHook(MetadataHookInterface):
    -        ...
    -

    If multiple subclasses are found, you must define a function named get_metadata_hook that returns the desired build hook.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    \ No newline at end of file +class CustomMetadataHook(MetadataHookInterface): + ... +

    If multiple subclasses are found, you must define a function named get_metadata_hook that returns the desired build hook.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    \ No newline at end of file diff --git a/1.9/plugins/metadata-hook/reference/index.html b/1.9/plugins/metadata-hook/reference/index.html index 829ed1780..2e1f85bdf 100644 --- a/1.9/plugins/metadata-hook/reference/index.html +++ b/1.9/plugins/metadata-hook/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

    Metadata hook plugins


    Metadata hooks allow for the modification of project metadata after it has been loaded.

    Known third-party

    MetadataHookInterface

    Example usage:

    from hatchling.metadata.plugin.interface import MetadataHookInterface
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Metadata hook plugins


    Metadata hooks allow for the modification of project metadata after it has been loaded.

    Known third-party

    MetadataHookInterface

    Example usage:

    from hatchling.metadata.plugin.interface import MetadataHookInterface
     
     
     class SpecialMetadataHook(MetadataHookInterface):
    diff --git a/1.9/plugins/publisher/package-index/index.html b/1.9/plugins/publisher/package-index/index.html
    index 099f510b1..51d2084d4 100644
    --- a/1.9/plugins/publisher/package-index/index.html
    +++ b/1.9/plugins/publisher/package-index/index.html
    @@ -1,4 +1,4 @@
    - Index - Hatch      

    Index publisher


    See the documentation for publishing.

    Configuration

    The publisher plugin name is index.

    [publish.index]
    -

    Options

    Flag Config name Description
    -r/--repo repo The repository with which to publish artifacts
    -u/--user user The user with which to authenticate
    -a/--auth auth The credentials to use for authentication
    --ca-cert ca-cert The path to a CA bundle
    --client-cert client-cert The path to a client certificate, optionally containing the private key
    --client-key client-key The path to the client certificate's private key
    repos A table of named repositories to their respective options

    Repositories

    All top-level options can be overridden per repository using the repos table with a required url attribute for each repository. The following shows the default configuration:

    [publish.index.repos.main]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Index publisher


    See the documentation for publishing.

    Options

    Flag Config name Description
    -r/--repo repo The repository with which to publish artifacts
    -u/--user user The user with which to authenticate
    -a/--auth auth The credentials to use for authentication
    --ca-cert ca-cert The path to a CA bundle
    --client-cert client-cert The path to a client certificate, optionally containing the private key
    --client-key client-key The path to the client certificate's private key
    repos A table of named repositories to their respective options

    Configuration

    The publisher plugin name is index.

    [publish.index]
    +

    Repositories

    All top-level options can be overridden per repository using the repos table with a required url attribute for each repository. The following shows the default configuration:

    [publish.index.repos.main]
     url = "https://upload.pypi.org/legacy/"
     
     [publish.index.repos.test]
     url = "https://test.pypi.org/legacy/"
    -

    The repo and repos options have no effect.

    \ No newline at end of file +

    The repo and repos options have no effect.

    Confirmation prompt

    You can require a confirmation prompt or use of the -y/--yes flag by setting publishers' disable option to true in either Hatch's config file or project-specific configuration (which takes precedence):

    [publish.index]
    +disable = true
    +
    [tool.hatch.publish.index]
    +disable = true
    +
    [publish.index]
    +disable = true
    +
    \ No newline at end of file diff --git a/1.9/plugins/publisher/reference/index.html b/1.9/plugins/publisher/reference/index.html index fc0794bd3..b7e876f85 100644 --- a/1.9/plugins/publisher/reference/index.html +++ b/1.9/plugins/publisher/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

    Publisher plugins


    PublisherInterface

    Example usage:

        from hatch.publish.plugin.interface import PublisherInterface
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Publisher plugins


    PublisherInterface

    Example usage:

        from hatch.publish.plugin.interface import PublisherInterface
     
     
         class SpecialPublisher(PublisherInterface):
    diff --git a/1.9/plugins/utilities/index.html b/1.9/plugins/utilities/index.html
    index 1de1b0557..cb1c451fe 100644
    --- a/1.9/plugins/utilities/index.html
    +++ b/1.9/plugins/utilities/index.html
    @@ -1,4 +1,4 @@
    - Utilities - Hatch      

    Plugin utilities


    hatchling.builders.utils.get_reproducible_timestamp() -> int

    Returns an int derived from the SOURCE_DATE_EPOCH environment variable; see https://reproducible-builds.org/specs/source-date-epoch/.

    The default value will always be: 1580601600

    Source code in backend/src/hatchling/builders/utils.py
    def get_reproducible_timestamp() -> int:
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Plugin utilities


    hatchling.builders.utils.get_reproducible_timestamp() -> int

    Returns an int derived from the SOURCE_DATE_EPOCH environment variable; see https://reproducible-builds.org/specs/source-date-epoch/.

    The default value will always be: 1580601600

    Source code in backend/src/hatchling/builders/utils.py
    def get_reproducible_timestamp() -> int:
         """
         Returns an `int` derived from the `SOURCE_DATE_EPOCH` environment variable; see
         https://reproducible-builds.org/specs/source-date-epoch/.
    @@ -15,4 +15,4 @@
         The default value will always be: `1580601600`
         """
         return int(os.environ.get('SOURCE_DATE_EPOCH', '1580601600'))
    -

    BuilderConfig

    directory: str property

    ignore_vcs: bool property

    reproducible: bool property

    Whether or not the target should be built in a reproducible manner, defaulting to true.

    dev_mode_dirs: list[str] property

    Directories which must be added to Python's search path in dev mode.

    versions: list[str] property

    dependencies: list[str] property

    default_include() -> list

    default_exclude() -> list

    default_packages() -> list

    default_only_include() -> list

    Application

    The way output is displayed can be configured by users.

    Important

    Never import this directly; Hatch judiciously decides if a type of plugin requires the capabilities herein and will grant access via an attribute.

    verbosity: int property

    The verbosity level of the application, with 0 as the default.

    abort(message: str = '', code: int = 1, **kwargs: Any) -> None

    Terminate the program with the given return code.

    display_debug(message: str = '', level: int = 1, **kwargs: Any) -> None

    Meant to be used for messages that are not useful for most user experiences. The level option must be between 1 and 3 (inclusive).

    display_error(message: str = '', **kwargs: Any) -> None

    Meant to be used for messages indicating some unrecoverable error.

    display_info(message: str = '', **kwargs: Any) -> None

    Meant to be used for messages conveying basic information.

    display_success(message: str = '', **kwargs: Any) -> None

    Meant to be used for messages indicating some positive outcome.

    display_waiting(message: str = '', **kwargs: Any) -> None

    Meant to be used for messages shown before potentially time consuming operations.

    display_warning(message: str = '', **kwargs: Any) -> None

    Meant to be used for messages conveying important information.

    Platform

    default_shell: str property

    Returns the default shell of the system.

    On Windows systems first try the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

    modules: LazilyLoadedModules property

    Accessor for lazily loading modules that either take multiple milliseconds to import (like shutil and subprocess) or are not used on all platforms (like shlex).

    home: Path property

    The user's home directory as a path-like object.

    name: str property

    One of the following:

    • linux
    • windows
    • macos

    windows: bool property

    Indicates whether Hatch is running on Windows.

    macos: bool property

    Indicates whether Hatch is running on macOS.

    linux: bool property

    Indicates whether Hatch is running on neither Windows nor macOS.

    format_for_subprocess(command: str | list[str], *, shell: bool) -> str | list[str]

    Format the given command in a cross-platform manner for immediate consumption by subprocess utilities.

    run_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess

    Equivalent to the standard library's subprocess.run, with the command first being properly formatted.

    check_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess

    Equivalent to run_command, but non-zero exit codes will gracefully end program execution.

    check_command_output(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> str

    Equivalent to the output from the process returned by capture_process, but non-zero exit codes will gracefully end program execution.

    capture_process(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> Popen

    Equivalent to the standard library's subprocess.Popen, with all output captured by stdout and the command first being properly formatted.

    exit_with_command(command: list[str]) -> None

    Run the given command and exit with its exit code. On non-Windows systems, this uses the standard library's os.execvp.

    EnvironmentContextFormatter

    formatters()

    This returns a mapping of supported field names to their respective formatting functions. Each function accepts 2 arguments:

    • the value that was passed to the format call, defaulting to None
    • the modifier data, defaulting to an empty string
    \ No newline at end of file +

    BuilderConfig

    directory: str property

    ignore_vcs: bool property

    reproducible: bool property

    Whether or not the target should be built in a reproducible manner, defaulting to true.

    dev_mode_dirs: list[str] property

    Directories which must be added to Python's search path in dev mode.

    versions: list[str] property

    dependencies: list[str] property

    default_include() -> list

    default_exclude() -> list

    default_packages() -> list

    default_only_include() -> list

    Application

    The way output is displayed can be configured by users.

    Important

    Never import this directly; Hatch judiciously decides if a type of plugin requires the capabilities herein and will grant access via an attribute.

    verbosity: int property

    The verbosity level of the application, with 0 as the default.

    abort(message: str = '', code: int = 1, **kwargs: Any) -> None

    Terminate the program with the given return code.

    display_debug(message: str = '', level: int = 1, **kwargs: Any) -> None

    Meant to be used for messages that are not useful for most user experiences. The level option must be between 1 and 3 (inclusive).

    display_error(message: str = '', **kwargs: Any) -> None

    Meant to be used for messages indicating some unrecoverable error.

    display_info(message: str = '', **kwargs: Any) -> None

    Meant to be used for messages conveying basic information.

    display_success(message: str = '', **kwargs: Any) -> None

    Meant to be used for messages indicating some positive outcome.

    display_waiting(message: str = '', **kwargs: Any) -> None

    Meant to be used for messages shown before potentially time consuming operations.

    display_warning(message: str = '', **kwargs: Any) -> None

    Meant to be used for messages conveying important information.

    Platform

    default_shell: str property

    Returns the default shell of the system.

    On Windows systems first try the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

    modules: LazilyLoadedModules property

    Accessor for lazily loading modules that either take multiple milliseconds to import (like shutil and subprocess) or are not used on all platforms (like shlex).

    home: Path property

    The user's home directory as a path-like object.

    name: str property

    One of the following:

    • linux
    • windows
    • macos

    display_name: str property

    One of the following:

    • Linux
    • Windows
    • macOS

    windows: bool property

    Indicates whether Hatch is running on Windows.

    macos: bool property

    Indicates whether Hatch is running on macOS.

    linux: bool property

    Indicates whether Hatch is running on neither Windows nor macOS.

    format_for_subprocess(command: str | list[str], *, shell: bool) -> str | list[str]

    Format the given command in a cross-platform manner for immediate consumption by subprocess utilities.

    run_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess

    Equivalent to the standard library's subprocess.run, with the command first being properly formatted.

    check_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess

    Equivalent to run_command, but non-zero exit codes will gracefully end program execution.

    check_command_output(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> str

    Equivalent to the output from the process returned by capture_process, but non-zero exit codes will gracefully end program execution.

    capture_process(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> Popen

    Equivalent to the standard library's subprocess.Popen, with all output captured by stdout and the command first being properly formatted.

    exit_with_command(command: list[str]) -> None

    Run the given command and exit with its exit code. On non-Windows systems, this uses the standard library's os.execvp.

    EnvironmentContextFormatter

    formatters()

    This returns a mapping of supported field names to their respective formatting functions. Each function accepts 2 arguments:

    • the value that was passed to the format call, defaulting to None
    • the modifier data, defaulting to an empty string
    \ No newline at end of file diff --git a/1.9/plugins/version-scheme/reference/index.html b/1.9/plugins/version-scheme/reference/index.html index f242f940d..6bb20a782 100644 --- a/1.9/plugins/version-scheme/reference/index.html +++ b/1.9/plugins/version-scheme/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

    Version scheme plugins


    Known third-party

    VersionSchemeInterface

    Example usage:

    from hatchling.version.scheme.plugin.interface import VersionSchemeInterface
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Version scheme plugins


    Known third-party

    VersionSchemeInterface

    Example usage:

    from hatchling.version.scheme.plugin.interface import VersionSchemeInterface
     
     
     class SpecialVersionScheme(VersionSchemeInterface):
    diff --git a/1.9/plugins/version-scheme/standard/index.html b/1.9/plugins/version-scheme/standard/index.html
    index 838021bb6..26e698d9b 100644
    --- a/1.9/plugins/version-scheme/standard/index.html
    +++ b/1.9/plugins/version-scheme/standard/index.html
    @@ -1,4 +1,4 @@
    - Standard - Hatch      

    Standard version scheme


    See the documentation for versioning.

    Configuration

    The version scheme plugin name is standard.

    [tool.hatch.version]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Standard version scheme


    See the documentation for versioning.

    Configuration

    The version scheme plugin name is standard.

    [tool.hatch.version]
     scheme = "standard"
     
    [version]
     scheme = "standard"
    diff --git a/1.9/plugins/version-source/code/index.html b/1.9/plugins/version-source/code/index.html
    index 24b38400b..08bb7798d 100644
    --- a/1.9/plugins/version-source/code/index.html
    +++ b/1.9/plugins/version-source/code/index.html
    @@ -1,4 +1,4 @@
    - Code - Hatch      

    Code version source


    Updates

    Setting the version is not supported.

    Configuration

    The version source plugin name is code.

    [tool.hatch.version]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Code version source


    Updates

    Setting the version is not supported.

    Configuration

    The version source plugin name is code.

    [tool.hatch.version]
     source = "code"
     
    [version]
     source = "code"
    diff --git a/1.9/plugins/version-source/env/index.html b/1.9/plugins/version-source/env/index.html
    index b7910989e..f206e72a3 100644
    --- a/1.9/plugins/version-source/env/index.html
    +++ b/1.9/plugins/version-source/env/index.html
    @@ -1,4 +1,4 @@
    - Environment - Hatch      

    Environment version source


    Retrieves the version from an environment variable. This can be useful in build pipelines where the version is set by an external trigger.

    Updates

    Setting the version is not supported.

    Configuration

    The version source plugin name is env.

    [tool.hatch.version]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Environment version source


    Retrieves the version from an environment variable. This can be useful in build pipelines where the version is set by an external trigger.

    Updates

    Setting the version is not supported.

    Configuration

    The version source plugin name is env.

    [tool.hatch.version]
     source = "env"
     
    [version]
     source = "env"
    diff --git a/1.9/plugins/version-source/reference/index.html b/1.9/plugins/version-source/reference/index.html
    index c500b046f..14467916c 100644
    --- a/1.9/plugins/version-source/reference/index.html
    +++ b/1.9/plugins/version-source/reference/index.html
    @@ -1,4 +1,4 @@
    - Reference - Hatch      

    Version source plugins


    Known third-party

    • hatch-vcs - uses your preferred version control system (like Git)
    • hatch-nodejs-version - uses the version field of NodeJS package.json files
    • hatch-regex-commit - automatically creates a Git commit and tag after version bumping
    • versioningit - determines version from Git or Mercurial tags, with customizable version formatting

    VersionSourceInterface

    Example usage:

    from hatchling.version.source.plugin.interface import VersionSourceInterface
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Version source plugins


    Known third-party

    • hatch-vcs - uses your preferred version control system (like Git)
    • hatch-nodejs-version - uses the version field of NodeJS package.json files
    • hatch-regex-commit - automatically creates a Git commit and tag after version bumping
    • versioningit - determines version from Git or Mercurial tags, with customizable version formatting

    VersionSourceInterface

    Example usage:

    from hatchling.version.source.plugin.interface import VersionSourceInterface
     
     
     class SpecialVersionSource(VersionSourceInterface):
    diff --git a/1.9/plugins/version-source/regex/index.html b/1.9/plugins/version-source/regex/index.html
    index 3749d484a..40ca31822 100644
    --- a/1.9/plugins/version-source/regex/index.html
    +++ b/1.9/plugins/version-source/regex/index.html
    @@ -1,4 +1,4 @@
    - Regex - Hatch      

    Regex version source


    See the documentation for versioning.

    Updates

    Setting the version is supported.

    Configuration

    The version source plugin name is regex.

    [tool.hatch.version]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Regex version source


    See the documentation for versioning.

    Updates

    Setting the version is supported.

    Configuration

    The version source plugin name is regex.

    [tool.hatch.version]
     source = "regex"
     
    [version]
     source = "regex"
    diff --git a/1.9/publish/index.html b/1.9/publish/index.html
    index 4794b8365..0391468ae 100644
    --- a/1.9/publish/index.html
    +++ b/1.9/publish/index.html
    @@ -7,20 +7,11 @@
         .gdesc-inner { font-size: 0.75rem; }
         body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
         body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
    -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Publishing


    After your project is built, you can distribute it using the publish command.

    The -p/--publisher option controls which publisher to use, with the default being index.

    Artifact selection

    By default, the dist directory located at the root of your project will be used:

    $ hatch publish
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Publishing


    After your project is built, you can distribute it using the publish command.

    The -p/--publisher option controls which publisher to use, with the default being index.

    Artifact selection

    By default, the dist directory located at the root of your project will be used:

    $ hatch publish
     dist/hatch_demo-1rc0-py3-none-any.whl ... success
     dist/hatch_demo-1rc0.tar.gz ... success
     
     [hatch-demo]
     https://pypi.org/project/hatch-demo/1rc0/
     

    You can instead pass specific paths as arguments:

    hatch publish /path/to/artifacts foo-1.tar.gz
    -

    Only files ending with .whl or .tar.gz will be published.

    Repository

    You can select the repository with which to upload using the -r/--repo option or by setting the HATCH_INDEX_REPO environment variable.

    Rather than specifying the full URL of a repository, you can use a named repository from a publish.index.repos table defined in Hatch's config file:

    [publish.index.repos.private]
    -url = "..."
    -...
    -

    The following repository names are reserved by Hatch and cannot be overridden:

    Name Repository
    main https://upload.pypi.org/legacy/
    test https://test.pypi.org/legacy/

    The main repository is used by default.

    Authentication

    The first time you publish to a repository you need to authenticate using the -u/--user (environment variable HATCH_INDEX_USER) and -a/--auth (environment variable HATCH_INDEX_AUTH) options. You will be prompted if either option is not provided.

    The user that most recently published to the chosen repository is cached, with their credentials saved to the system keyring, so that they will no longer need to provide authentication information.

    For automated releasing to PyPI, it is recommended that you use per-project API tokens.

    Confirmation

    You can require a confirmation prompt or use of the -y/--yes flag by setting publishers' disable option to true in either Hatch's config file or project-specific configuration (which takes precedence):

    [publish.index]
    -disable = true
    -
    [tool.hatch.publish.index]
    -disable = true
    -
    [publish.index]
    -disable = true
    -
    \ No newline at end of file +

    Only files ending with .whl or .tar.gz will be published.

    Further resources

    Please refer to the publisher plugin reference for configuration options.

    There's a How-To on authentication and on options to select the target repository.

    The publish command is implemented as a built-in plugin, if you're planning your own plugin, read about the publisher plugin API.

    \ No newline at end of file diff --git a/1.9/search/search_index.json b/1.9/search/search_index.json index 26f267a67..a84569b41 100644 --- a/1.9/search/search_index.json +++ b/1.9/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Hatch","text":"CI/CD Docs Package Meta

    Hatch is a modern, extensible Python project manager. See the Why Hatch? page for more information.

    • Build system

      Reproducible builds by default with a rich ecosystem of plugins

      Configure builds

    • Environments

      Robust environment management with support for custom scripts

      Getting started

    • Python management

      Choose between easy manual installations or automatic as part of environments

      Try it

    • Static analysis

      Static analysis backed by Ruff with up-to-date, sane defaults

      Learn

    • Publishing

      Easily upload to PyPI or other indices

      See how

    • Versioning

      Streamlined workflow for bumping versions

      Managing versions

    • Project generation

      Create new projects from templates with known best practices

      Project setup

    • Responsive CLI

      Hatch is up to 3x faster than equivalent tools

      CLI reference

    "},{"location":"#license","title":"License","text":"

    Hatch is distributed under the terms of the MIT license.

    "},{"location":"#navigation","title":"Navigation","text":"

    Documentation for specific MAJOR.MINOR versions can be chosen by using the dropdown on the top of every page. The dev version reflects changes that have not yet been released.

    Also, desktop readers can use special keyboard shortcuts:

    Keys Action
    • , (comma)
    • p
    Navigate to the \"previous\" page
    • . (period)
    • n
    Navigate to the \"next\" page
    • /
    • s
    Display the search modal"},{"location":"build/","title":"Builds","text":""},{"location":"build/#configuration","title":"Configuration","text":"

    Builds are configured using the tool.hatch.build table. Every target is defined by a section within tool.hatch.build.targets, for example:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.sdist]\nexclude = [\n  \"/.github\",\n  \"/docs\",\n]\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
    [build.targets.sdist]\nexclude = [\n  \"/.github\",\n  \"/docs\",\n]\n\n[build.targets.wheel]\npackages = [\"src/foo\"]\n
    "},{"location":"build/#building","title":"Building","text":"

    Invoking the build command without any arguments will build the sdist and wheel targets:

    $ hatch build\n[sdist]\ndist/hatch_demo-1rc0.tar.gz\n\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n

    To only build specific targets, use the -t/--target option:

    $ hatch build -t wheel\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n

    If the target supports multiple versions, you can specify the exact versions to build by appending a colon followed by the desired versions separated by commas:

    $ hatch -v build -t wheel:standard\n[wheel]\nBuilding `wheel` version `standard`\ndist/hatch_demo-1rc0-py3-none-any.whl\n
    "},{"location":"build/#packaging-ecosystem","title":"Packaging ecosystem","text":"

    Hatch complies with modern Python packaging specs and therefore your projects can be used by other tools with Hatch serving as just the build backend.

    So you could use tox as an alternative to Hatch's environment management, or cibuildwheel to distribute packages for every platform, and they both will transparently use Hatch without any extra modification.

    "},{"location":"environment/","title":"Environments","text":"

    Environments are designed to allow for isolated workspaces for testing, building documentation, or anything else projects need.

    Unless an environment is chosen explicitly, Hatch will use the default environment.

    "},{"location":"environment/#creation","title":"Creation","text":"

    You can create environments by using the env create command. Let's enter the directory of the project we created in the setup phase:

    $ hatch env create\nCreating environment: default\nInstalling project in development mode\nSyncing dependencies\n

    Tip

    You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.

    "},{"location":"environment/#entering-environments","title":"Entering environments","text":"

    You can spawn a shell within an environment by using the shell command.

    $ hatch shell\n(hatch-demo) $\n

    Now confirm the project has been installed:

    (hatch-demo) $ pip show hatch-demo\nName: hatch-demo\nVersion: 0.0.1\n...\n

    Finally, see where your environment's Python is located:

    (hatch-demo) $ python -c \"import sys;print(sys.executable)\"\n...\n

    You can type exit to leave the environment.

    "},{"location":"environment/#command-execution","title":"Command execution","text":"

    The run command allows you to execute commands in an environment as if you had already entered it. For example, running the following command will output the same path as before:

    hatch run python -c \"import sys;print(sys.executable)\"\n
    "},{"location":"environment/#scripts","title":"Scripts","text":"

    You can also run any scripts that have been defined.

    You'll notice that in the pyproject.toml file there are already scripts defined in the default environment. Try running the test command, which invokes pytest with some default arguments:

    hatch run test\n

    All additional arguments are passed through to that script, so for example if you wanted to see the version of pytest and which plugins are installed you could do:

    hatch run test -VV\n
    "},{"location":"environment/#dependencies","title":"Dependencies","text":"

    Hatch ensures that environments are always compatible with the currently defined project dependencies (if installed and in dev mode) and environment dependencies.

    To add cowsay as a dependency, open pyproject.toml and add it to the dependencies array:

    pyproject.toml
    [project]\n...\ndependencies = [\n  \"cowsay\"\n]\n

    This dependency will be installed the next time you spawn a shell or run a command. For example:

    $ hatch run cowsay -t \"Hello, world!\"\nSyncing dependencies\n  _____________\n| Hello, world! |\n  =============\n             \\\n              \\\n                ^__^\n                (oo)\\_______\n                (__)\\       )\\/\\\n                    ||----w |\n                    ||     ||\n

    Note

    The Syncing dependencies status will display temporarily when Hatch updates environments in response to any dependency changes that you make.

    "},{"location":"environment/#selection","title":"Selection","text":"

    You can select which environment to enter or run commands in by using the -e/--env root option or by setting the HATCH_ENV environment variable.

    The run command allows for more explicit selection by prepending <ENV_NAME>: to commands. For example, if you had the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[tool.hatch.envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n
    [envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n

    you could then serve your documentation by running:

    hatch run docs:serve\n

    Tip

    If you've already entered an environment, commands will target it by default.

    "},{"location":"environment/#matrix","title":"Matrix","text":"

    Every environment can define its own set of matrices:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
    [envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n

    Using the env show command would then display:

    $ hatch env show --ascii\n     Standalone\n+---------+---------+\n| Name    | Type    |\n+=========+=========+\n| default | virtual |\n+---------+---------+\n                       Matrices\n+------+---------+---------------------+--------------+\n| Name | Type    | Envs                | Dependencies |\n+======+=========+=====================+==============+\n| test | virtual | test.py2.7-42       | pytest       |\n|      |         | test.py2.7-3.14     |              |\n|      |         | test.py3.8-42       |              |\n|      |         | test.py3.8-3.14     |              |\n|      |         | test.py3.8-9000-foo |              |\n|      |         | test.py3.8-9000-bar |              |\n|      |         | test.py3.9-9000-foo |              |\n|      |         | test.py3.9-9000-bar |              |\n+------+---------+---------------------+--------------+\n
    "},{"location":"environment/#removal","title":"Removal","text":"

    You can remove a single environment or environment matrix by using the env remove command or all of a project's environments by using the env prune command.

    "},{"location":"install/","title":"Installation","text":""},{"location":"install/#installers","title":"Installers","text":"macOSWindows GUI installerCommand line installer
    1. In your browser, download the .pkg file: hatch-1.9.4.pkg
    2. Run your downloaded file and follow the on-screen instructions.
    3. Restart your terminal.
    4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

      $ hatch --version\n1.9.4\n
    1. Download the file using the curl command. The -o option specifies the file name that the downloaded package is written to. In this example, the file is written to hatch-1.9.4.pkg in the current directory.

      curl -o hatch-1.9.4.pkg https://github.com/pypa/hatch/releases/download/hatch-v1.9.4/hatch-1.9.4.pkg\n
    2. Run the standard macOS installer program, specifying the downloaded .pkg file as the source. Use the -pkg parameter to specify the name of the package to install, and the -target / parameter for the drive in which to install the package. The files are installed to /usr/local/hatch, and an entry is created at /etc/paths.d/hatch that instructs shells to add the /usr/local/hatch directory to. You must include sudo on the command to grant write permissions to those folders.

      sudo installer -pkg ./hatch-1.9.4.pkg -target /\n
    3. Restart your terminal.

    4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

      $ hatch --version\n1.9.4\n
    GUI installerCommand line installer
    1. In your browser, download one the .msi files:
      • hatch-1.9.4-x64.msi
    2. Run your downloaded file and follow the on-screen instructions.
    3. Restart your terminal.
    4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

      $ hatch --version\n1.9.4\n
    1. Download and run the installer using the standard Windows msiexec program, specifying one of the .msi files as the source. Use the /passive and /i parameters to request an unattended, normal installation.

      x64
      msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.4/hatch-1.9.4-x64.msi\n
    2. Restart your terminal.

    3. To verify that the shell can find and run the hatch command in your PATH, use the following command.

      $ hatch --version\n1.9.4\n
    "},{"location":"install/#standalone-binaries","title":"Standalone binaries","text":"

    After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to hatch.

    LinuxmacOSWindows
    • hatch-1.9.4-aarch64-unknown-linux-gnu.tar.gz
    • hatch-1.9.4-x86_64-unknown-linux-gnu.tar.gz
    • hatch-1.9.4-x86_64-unknown-linux-musl.tar.gz
    • hatch-1.9.4-i686-unknown-linux-gnu.tar.gz
    • hatch-1.9.4-powerpc64le-unknown-linux-gnu.tar.gz
    • hatch-1.9.4-aarch64-apple-darwin.tar.gz
    • hatch-1.9.4-x86_64-apple-darwin.tar.gz
    • hatch-1.9.4-x86_64-pc-windows-msvc.zip
    "},{"location":"install/#pip","title":"pip","text":"

    Hatch is available on PyPI and can be installed with pip.

    pip install hatch\n

    Warning

    This method modifies the Python environment in which you choose to install. Consider instead using pipx to avoid dependency conflicts.

    "},{"location":"install/#pipx","title":"pipx","text":"

    pipx allows for the global installation of Python applications in isolated environments.

    pipx install hatch\n
    "},{"location":"install/#homebrew","title":"Homebrew","text":"

    See the formula for more details.

    brew install hatch\n
    "},{"location":"install/#conda","title":"Conda","text":"

    See the feedstock for more details.

    conda install -c conda-forge hatch\n

    or with mamba:

    mamba install hatch\n

    Warning

    This method modifies the Conda environment in which you choose to install. Consider instead using pipx or condax to avoid dependency conflicts.

    "},{"location":"install/#macports","title":"MacPorts","text":"

    See the port for more details.

    sudo port install hatch\n
    "},{"location":"install/#fedora","title":"Fedora","text":"

    The minimum supported version is 37, currently in development as Rawhide.

    sudo dnf install hatch\n
    "},{"location":"install/#void-linux","title":"Void Linux","text":"
    xbps-install hatch\n
    "},{"location":"install/#build-system-availability","title":"Build system availability","text":"

    Hatchling is Hatch's build backend which you will never need to install manually. See its changelog for version information.

    "},{"location":"intro/","title":"Introduction","text":""},{"location":"intro/#setup","title":"Setup","text":"

    Projects can be set up for use by Hatch using the new command.

    "},{"location":"intro/#new-project","title":"New project","text":"

    Let's say you want to create a project named Hatch Demo. You would run:

    hatch new \"Hatch Demo\"\n

    This would create the following structure in your current working directory:

    hatch-demo\n\u251c\u2500\u2500 src\n\u2502   \u2514\u2500\u2500 hatch_demo\n\u2502       \u251c\u2500\u2500 __about__.py\n\u2502       \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 tests\n\u2502   \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 LICENSE.txt\n\u251c\u2500\u2500 README.md\n\u2514\u2500\u2500 pyproject.toml\n

    Tip

    There are many ways to customize project generation.

    "},{"location":"intro/#existing-project","title":"Existing project","text":"

    To initialize an existing project, enter the directory containing the project and run the following:

    hatch new --init\n

    If your project has a setup.py file the command will automatically migrate setuptools configuration for you. Otherwise, this will interactively guide you through the setup process.

    "},{"location":"intro/#project-metadata","title":"Project metadata","text":"

    Next you'll want to define more of your project's metadata located in the pyproject.toml file. You can specify things like its license, the supported versions of Python, and URLs referring to various parts of your project, like documentation.

    "},{"location":"intro/#dependencies","title":"Dependencies","text":"

    The last step of the setup process is to define any dependencies that you'd like your project to begin with.

    "},{"location":"intro/#configuration","title":"Configuration","text":"

    All project-specific configuration recognized by Hatch can be defined in either the pyproject.toml file, or a file named hatch.toml where options are not contained within the tool.hatch table:

    pyproject.toml hatch.toml
    [tool.hatch]\noption = \"...\"\n\n[tool.hatch.table1]\noption = \"...\"\n\n[tool.hatch.table2]\noption = \"...\"\n
    option = \"...\"\n\n[table1]\noption = \"...\"\n\n[table2]\noption = \"...\"\n

    Top level keys in the latter file take precedence when defined in both.

    Tip

    If you want to make your file more compact, you can use dotted keys, turning the above example into:

    pyproject.toml hatch.toml
    [tool.hatch]\noption = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
    option = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
    "},{"location":"next-steps/","title":"Next steps","text":""},{"location":"next-steps/#learn-more","title":"Learn more","text":"

    At this point you should have a basic understanding of how to use Hatch.

    Now you may want to check out advanced configuration for environments or builds, set up your preferred shell, or read more about Hatch's CLI.

    After that, check out the Hatch Showcase project to see examples of what is possible.

    Finally, if you see a need, feel free to write a plugin for extended functionality.

    "},{"location":"next-steps/#community","title":"Community","text":"

    For any projects using Hatch, you may add its official badge somewhere prominent like the README.

    MarkdownreStructuredText
    [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)\n
    .. image:: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg\n   :alt: Hatch project\n   :target: https://github.com/pypa/hatch\n
    "},{"location":"publish/","title":"Publishing","text":"

    After your project is built, you can distribute it using the publish command.

    The -p/--publisher option controls which publisher to use, with the default being index.

    "},{"location":"publish/#artifact-selection","title":"Artifact selection","text":"

    By default, the dist directory located at the root of your project will be used:

    $ hatch publish\ndist/hatch_demo-1rc0-py3-none-any.whl ... success\ndist/hatch_demo-1rc0.tar.gz ... success\n\n[hatch-demo]\nhttps://pypi.org/project/hatch-demo/1rc0/\n

    You can instead pass specific paths as arguments:

    hatch publish /path/to/artifacts foo-1.tar.gz\n

    Only files ending with .whl or .tar.gz will be published.

    "},{"location":"publish/#repository","title":"Repository","text":"

    You can select the repository with which to upload using the -r/--repo option or by setting the HATCH_INDEX_REPO environment variable.

    Rather than specifying the full URL of a repository, you can use a named repository from a publish.index.repos table defined in Hatch's config file:

    config.toml
    [publish.index.repos.private]\nurl = \"...\"\n...\n

    The following repository names are reserved by Hatch and cannot be overridden:

    Name Repository main https://upload.pypi.org/legacy/ test https://test.pypi.org/legacy/

    The main repository is used by default.

    "},{"location":"publish/#authentication","title":"Authentication","text":"

    The first time you publish to a repository you need to authenticate using the -u/--user (environment variable HATCH_INDEX_USER) and -a/--auth (environment variable HATCH_INDEX_AUTH) options. You will be prompted if either option is not provided.

    The user that most recently published to the chosen repository is cached, with their credentials saved to the system keyring, so that they will no longer need to provide authentication information.

    For automated releasing to PyPI, it is recommended that you use per-project API tokens.

    "},{"location":"publish/#confirmation","title":"Confirmation","text":"

    You can require a confirmation prompt or use of the -y/--yes flag by setting publishers' disable option to true in either Hatch's config file or project-specific configuration (which takes precedence):

    config.toml pyproject.toml hatch.toml
    [publish.index]\ndisable = true\n
    [tool.hatch.publish.index]\ndisable = true\n
    [publish.index]\ndisable = true\n
    "},{"location":"version/","title":"Versioning","text":""},{"location":"version/#configuration","title":"Configuration","text":"

    When the version is not statically set, configuration is defined in the tool.hatch.version table. The source option determines the source to use for retrieving and updating the version. The regex source is used by default.

    The regex source requires an option path that represents a relative path to a file containing the project's version:

    pyproject.toml hatch.toml
    [tool.hatch.version]\npath = \"src/hatch_demo/__about__.py\"\n
    [version]\npath = \"src/hatch_demo/__about__.py\"\n

    The default pattern looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v.

    If this doesn't reflect how you store the version, you can define a different regular expression using the pattern option:

    pyproject.toml hatch.toml
    [tool.hatch.version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n
    [version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n

    The pattern must have a named group called version that represents the version.

    "},{"location":"version/#display","title":"Display","text":"

    Invoking the version command without any arguments will display the current version of the project:

    $ hatch version\n0.0.1\n
    "},{"location":"version/#updating","title":"Updating","text":"

    You can update the version like so:

    $ hatch version \"0.1.0\"\nOld: 0.0.1\nNew: 0.1.0\n

    The scheme option determines the scheme to use for parsing both the existing and new versions. The standard scheme is used by default, which is based on PEP 440.

    Rather than setting the version explicitly, you can select the name of a segment used to increment the version:

    $ hatch version minor\nOld: 0.1.0\nNew: 0.2.0\n

    You can chain multiple segment updates with a comma. For example, if you wanted to release a preview of your project's first major version, you could do:

    $ hatch version major,rc\nOld: 0.2.0\nNew: 1.0.0rc0\n

    When you want to release the final version, you would do:

    $ hatch version release\nOld: 1.0.0rc0\nNew: 1.0.0\n
    "},{"location":"version/#supported-segments","title":"Supported segments","text":"

    Here are the supported segments and how they would influence an existing version of 1.0.0:

    Segments New version release 1.0.0 major 2.0.0 minor 1.1.0 micropatchfix 1.0.1 aalpha 1.0.0a0 bbeta 1.0.0b0 crcprepreview 1.0.0rc0 rrevpost 1.0.0.post0 dev 1.0.0.dev0"},{"location":"why/","title":"Why Hatch?","text":"

    The high level value proposition of Hatch is that if one adopts all functionality then many other tools become unnecessary since there is support for everything one might require. Further, if one chooses to use only specific features then there are still benefits compared to alternatives.

    "},{"location":"why/#build-backend","title":"Build backend","text":"

    Hatchling, the build backend sister project, has many benefits compared to setuptools. Here we only compare setuptools as that is the one most people are familiar with.

    • Better defaults: The default behavior for setuptools is often not desirable for the average user.
      • For source distributions, setuptools has a custom enumeration of files that get included and excluded by default. Hatchling takes the defaults from your version control system such as Git's .gitignore file.
      • For wheels, setuptools attempts to find every directory that looks like a Python package. This is often undesirable as you might ship files to the end-user unintentionally such as test or tooling directories. Hatchling defaults to very specific inclusion based on the project name and errors if no heuristic is satisfied.
    • Ease of configurability: Hatchling was designed based on a history of significant challenges when configuring setuptools.
      • Hatchling uses the same glob pattern syntax as Git itself for every option which is what most users are familiar with. On the other hand, setuptools uses shell-style glob patterns for source distributions while wheels use a mix of shell-style globs and Python package syntax.
      • Configuring what gets included in source distributions requires a separate MANIFEST.in file. The custom syntax and directives must be learned and it is difficult knowing which options in the main files like setup.py influence the behavior and under what conditions. For Hatchling, everything gets configured in a single file under dedicated sections for specific targets like [tool.hatch.build.targets.wheel].
      • By default, non-Python files are excluded from wheels. Including such files requires usually verbose rules for every nested package directory. Hatchling makes no such distinction between file types and acts more like a general build system one might already be familiar with.
    • Editable installations: The default behavior of Hatchling allows for proper static analysis by external tools such as IDEs. With setuptools, you must provide additional configuration which means that by default, for example, you would not get autocompletion in Visual Studio Code. This is marked as a legacy feature and may in fact be removed in future versions of setuptools.
    • Reproducibility: Hatchling builds reproducible wheels and source distributions by default. setuptools does not support this for source distributions and there is no guarantee that wheels are reproducible.
    • Extensibility: Although it is possible to extend setuptools, the API is quite low level. Hatchling has the concept of plugins that are separated into discrete types and only expose what is necessary, leading to an easier developer experience.

    Why not?:

    If building extension modules is required then it is recommended that you continue using setuptools, or even other backends that specialize in interfacing with compilers.

    "},{"location":"why/#environment-management","title":"Environment management","text":"

    Here we compare to both tox and nox. At a high level, there are a few common advantages:

    • Python management: Hatch is able to automatically download Python distributions on the fly when specific versions that environments request cannot be found. The alternatives will raise an error, with the option to ignore unknown distributions.
    • Philosophy: In the alternatives, environments are for the most part treated as executable units where a dependency set is associated with an action. If you are familiar with container ecosystems, this would be like defining a CMD at the end of a Dockerfile but without the ability to change the action at runtime. This involves significant wasted disk space usually because one often requires slight modifications to the actions and therefore will define entirely different environments inherited from a base config just to perform different logic. Additionally, this can be confusing to users not just configuration-wise but also for execution of the different environments.

      In Hatch, environments are treated as isolated areas where you can execute arbitrary commands at runtime. For example, you can define a single test environment with named scripts that runs unit vs non-unit tests, each command being potentially very long but named however you wish so you get to control the interface. Since environments are treated as places where work is performed, you can also spawn a shell into any which will execute a subprocess that automatically drops into your shell of choice. Your shell will be configured appropriately like python on PATH being updated and the prompt being changed to reflect the chosen environment.

    • Configuration:

      • tox only supports INI configuration and if one desires putting that in the standard pyproject.toml file then it must be a multi-line string containing the INI config which would preclude syntax highlighting. Hatch allows for TOML-based config just like most other tools in the Python ecosystem.
      • nox config is defined in Python which often leads to increased verbosity and makes it challenging to onboard folks compared to a standardized format with known behaviors.
    • Extensibility:
      • tox allows for extending most aspects of its functionality however the API is so low-level and attached to internals that creating plugins may be challenging. For example, here is a tox plugin that was migrated to an equivalent Hatch environment collector plugin.
      • nox is configured with Python so for the local project you can do whatever you want, however there is no concept of third-party plugins per se. To achieve that, you must usually use a package that wraps nox and use that package's imports instead (example).

    Why not?:

    If you are using nox and you wish to migrate, and for some reason you notify sessions, then migration wouldn't be a straight translation but rather you might have to redesign that conditional step.

    "},{"location":"why/#python-management","title":"Python management","text":"

    Here we compare Python management to that of pyenv.

    • Cross-platform: Hatch allows for the same experience no matter the system whereas pyenv does not support Windows so you must use an entirely different project that tries to emulate the functionality.
    • No build dependencies: Hatch guarantees that every available distribution is prebuilt whereas the alternative requires one to maintain a precise build environment which differs by platform and potentially Python version. Another benefit to this is extremely fast installations since the distributions are simply downloaded and unpacked.
    • Optimized by default: The CPython distributions are built with profile guided optimization and link-time optimization, resulting in a 10-30% performance improvement depending on the workload. These distributions have seen wide adoption throughout the industry and are even used by the build system Bazel.
    • Simplicity: Hatch treats Python installations as just another directory that one would add to PATH. It can do this for you or you can manage PATH yourself, even allowing for custom install locations. On the other hand, pyenv operates by adding shims which then act as wrappers around the actual underlying binaries. This has many unfortunate side effects:
      • It is incumbent upon the user to manage which specific Python comes first via the CLI, switch when necessary, and/or have a mental model of which versions are exposed globally and locally per-project. This can become confusing quite quickly. When working with Hatch, your global Python installations are only important insofar as they are on PATH somewhere since environments do not use them directly but rather create virtual environments from them, always using a version that is compatible with your project.
      • Configuration is required for each shell to properly set up pyenv on start, leading to inconsistencies when running processes that do not spawn a shell.
      • Debugging issues with Python search paths can be extremely difficult, especially for users of software. If you or users have ever ran into an issue where code was being executed that you did not anticipate, the issue is almost always pyenv influencing the python on PATH.

    Why not?:

    Currently, Hatch does not allow for the installation of specific patch release versions but rather only uses minor release granularity that tracks the latest patch release. If specific patch releases are important to you then it is best to use an alternative installation mechanism.

    "},{"location":"blog/","title":"Blog","text":""},{"location":"blog/2022/10/08/hatch-v160/","title":"Hatch v1.6.0","text":"

    Hatch v1.6.0 brings improvements to build environments, better handling of dynamic metadata, and support for tools like Visual Studio Code.

    "},{"location":"blog/2022/10/08/hatch-v160/#build-environments","title":"Build environments","text":"

    Originally, the environment interface method for providing builder sub-environments was intended to be used in conjunction with some cleanup logic in order to provide a fresh setup every time. However, this is unnecessary in practice because build dependencies rarely change.

    Without caching, repeat build environment use is slow which affects the following scenarios:

    • the build command
    • commands that read project metadata, like dep hash, if any fields are set dynamically

    Now a new environment interface method build_environment_exists is used by Hatch to determine whether or not it has already been created, for implementations that have a caching mechanism.

    The virtual environment type now uses this method to cache build environments.

    "},{"location":"blog/2022/10/08/hatch-v160/#project-metadata","title":"Project metadata","text":"

    Dynamically defined metadata is now supported everywhere, thanks to the new caching of virtual build environments.

    A project metadata command is introduced that displays the fully resolved metadata. The output format is JSON unless a field is specified as an argument.

    For example, if you checkout a project that is built by Hatch, like FastAPI, and run:

    hatch project metadata readme\n

    only the readme text will be displayed. If the content is in Markdown, then Rich will render it directly in your terminal:

    "},{"location":"blog/2022/10/08/hatch-v160/#virtual-environment-location","title":"Virtual environment location","text":"

    The virtual environment type now uses a flat layout for storage in the configured virtual environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory.

    For example, if you define the following Hatch configuration:

    config.toml
    [dirs.env]\nvirtual = \".hatch\"\n

    and the following matrix:

    pyproject.toml hatch.toml
    [[tool.hatch.envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n
    [[envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n

    then locating environments with the following command:

    hatch env find test\n

    will show that the general directory structure is:

    .hatch\n\u251c\u2500\u2500 test.py3.7\n\u251c\u2500\u2500 test.py3.8\n\u251c\u2500\u2500 test.py3.9\n\u251c\u2500\u2500 test.py3.10\n\u2514\u2500\u2500 test.py3.11\n

    This flat structure is required for detection of virtual environments by tools like Visual Studio Code and PyCharm.

    Additionally, the virtual environment type now supports a path option to specify an explicit path that all inherited environments will share, such as the common .venv.

    "},{"location":"blog/2022/10/08/hatch-v160/#migration-script-improvements","title":"Migration script improvements","text":"

    The script used to migrate existing projects from setuptools has been improved to handle more edge cases that were encountered in the wild and now no longer modifies the formatting of existing pyproject.toml configuration.

    "},{"location":"blog/2022/10/08/hatch-v160/#hatchling","title":"Hatchling","text":"

    Hatch now depends on Hatchling v1.11.0, which was also just released.

    "},{"location":"blog/2022/10/08/hatch-v160/#environment-version-source","title":"Environment version source","text":"

    A new env version source is available that allows for the project version to be defined by an environment variable.

    "},{"location":"blog/2022/10/08/hatch-v160/#relaxed-version-bumping","title":"Relaxed version bumping","text":"

    The standard version scheme now supports a validate-bump option that when set to false will forego the check when updating the version that the desired version is higher than the current version.

    This use case comes from Project Jupyter:

    A common pattern we use in Jupyter is to bump to a .dev0 minor version bump after making a release. If we have a bug fix that needs to go out in the interim, we'd rather not be forced to create a branch every time.

    "},{"location":"blog/2023/12/11/hatch-v180/","title":"Hatch v1.8.0","text":"

    Hatch v1.8.0 brings Python distribution management, static analysis and formatting backed by Ruff, and binaries for every platform.

    "},{"location":"blog/2023/12/11/hatch-v180/#installation-made-easy","title":"Installation made easy","text":"

    One thing that has been a perpetual problem for Hatch and other Python applications is that Python itself is a dependency. You, and more importantly your users, need to in some way get Python before your software can even be used. The recommended way to go about that is platform-dependent and even differs based on your target audience. I viewed this as a central UX problem for Hatch and so severe that I took a bit of a hiatus to solve it.

    Luckily, I have to my satisfaction solved this problem in the form of PyApp. It is a runtime installer for Python projects written in Rust. Apps are distributed as standalone executables as users have come to expect and bootstrapping occurs upon the first invocation. Here is an example of what you would see the first time you run a binary from this release:

    Now that we have binaries, creating installers for different platforms becomes trivial. Starting with this release not only are binaries available for every platform but also we have installers for Windows and macOS. The installer for macOS is signed using a certificate from the same account used to sign the official distributions from https://www.python.org, so users will not get any security pop-ups. Shout out to @ewdurbin for their extreme generosity in setting up multiple certificates in their free time!

    These installers and binaries are now the recommended way to install and update Hatch. These binaries have built-in management so you can update to the latest version by running hatch self update.

    Windows signing

    In future we will sign the installers for Windows but I did not have time to look into how that works. macOS signing took way longer than I anticipated

    "},{"location":"blog/2023/12/11/hatch-v180/#python-management","title":"Python management","text":"

    For a long time I and other users have desired that Hatch gain the ability to manage Python distributions. In my mind this was always blocked on a better installation experience because there was sort of a chicken-or-egg problem where you want a Python manager but you first need Python. No longer is that the case!

    The new python command group allows for easy installation of various distributions to arbitrary locations which are then added to your PATH by default. Hatch supports CPython and PyPy distributions:

    "},{"location":"blog/2023/12/11/hatch-v180/#virtual-environment-python-resolution","title":"Virtual environment Python resolution","text":"

    The virtual environment type is now far more intelligent when resolving the parent distribution to use and guarantees that, when no specific version is requested, the resolved distribution will always be compatible with the project.

    Additionally, when a requested version cannot be found on PATH it will automatically be downloaded and managed internally.

    "},{"location":"blog/2023/12/11/hatch-v180/#static-analysis","title":"Static analysis","text":"

    There is a new fmt command, backed entirely by Ruff, that checks and fixes your code for formatting and linting issues.

    Starting with this release, Hatch maintains default settings that are guaranteed to be up-to-date and represent best practices for programming in modern Python. The idea is to provide defaults that are so broadly applicable that the majority of users will maintain little if any of their own overrides.

    The default behavior is internal management of settings to provide an OOTB experience that works. It is recommended however that you persist the default config file in version control so that other tools like IDEs can utilize your full configuration.

    Since Ruff is now provided as a built-in feature, new project templates no longer have such configuration and are much less verbose.

    "},{"location":"blog/2023/12/11/hatch-v180/#build-improvements","title":"Build improvements","text":"

    Building projects that do not use Hatchling as a backend is now supported and such builds are managed with the standard build tool.

    The bridge between Hatch and the Hatchling CLI has been removed. Previously, the builder would send serialized messages to Hatch that would contain the desired content and style for each line of output. This was done in an effort to allow builder and build hook plugins to output pretty messages without actually requiring a dependency like Rich. A problem that arises with this is that builders that invoke subprocesses will not display ANSI codes as one might expect and will lose out on the interactive experience of such invocations, like the built-in app builder plugin calling cargo build. So now everything is simpler at the expense of no colored output without manual logic, or adding a dependency if you're a third-party plugin.

    "},{"location":"blog/2023/12/11/hatch-v180/#faster-environment-usage","title":"Faster environment usage","text":"

    Spawning a shell or running commands within environments always first checks that your project's dependencies are satisfied and if not synchronizes the environment with what is defined. Previously, this had the potential to be quite slow for projects that have many dependencies.

    Now the set of dependency definitions is hashed and no check is performed if the hash is the same as before, significantly speeding up environment usage in most cases.

    "},{"location":"blog/2023/12/11/hatch-v180/#hatchling","title":"Hatchling","text":"

    Hatch now depends on Hatchling v1.19.0, which was also just released.

    "},{"location":"blog/2023/12/11/hatch-v180/#better-defaults","title":"Better defaults","text":"

    Hatchling is all about providing the best possible defaults, even at the expense of backward compatibility. In this release, there are two breaking changes that provide a much better user experience and were in fact requested by users.

    • Both the force-include option and the force_include_editable wheel build data setting now raise errors if source paths do not exist.
    • The wheel build target now raises an error when no file inclusion options have been defined and none of its heuristics to determine what to ship are satisfied.
    "},{"location":"blog/2023/12/11/hatch-v180/#app-build-target","title":"App build target","text":"

    A new app build target is now stable that allows for the building of standalone binaries for projects. This is what Hatch itself uses for its binaries.

    "},{"location":"blog/2023/12/11/hatch-v180/#meta","title":"Meta","text":""},{"location":"blog/2023/12/11/hatch-v180/#why-hatch","title":"Why Hatch?","text":"

    A new page has been introduced that discusses the value proposition of Hatch and Hatchling in comparison to alternatives. Currently, it only addresses a few features but in future this page will become more comprehensive.

    "},{"location":"blog/2023/12/11/hatch-v180/#future","title":"Future","text":"

    Upcoming features include a test command, commands to manage dependencies, and workspaces functionality similar to Cargo that will make managing monorepos far easier.

    Next year there will be two large efforts that you should expect to see:

    1. A significant amount of my free time (and some at work) will be devoted to introducing lock file functionality in Hatch and trying to get whatever that happens to be standardized.

      I met with @brettcannon about his thoughts post-PEP 665 and about mousebender. I also met with the prefix.dev team about rip and was fortunate enough to be shown a demo before its official announcement.

      At the moment, the two options I see are to either go all in and contribute to mousebender or rely on the Prefix folks and use rip. The latter has the benefit of potentially supporting Conda as a side effect with the downside of being quite new with the spec firmly out of our control. The former has the benefit of being able to easily gain institutional support from the Python packaging team and each of our employers with the downside being a significant amount of work needing to be done.

    2. When @henryiii is able to get some free time away from teaching I plan to work with him once again and push very hard for the Python build ecosystem to adopt the extensionlib approach.

      I am of the opinion that the Python community has not fully completed the expressed outcome of PEP 517 in that build backends are still (for the most part) reliant on setuptools for building non-Python code bases.

      Basically, there are components that interact with compilers to produce extension modules and components that pack files into an archive which we call a build backend. These are two distinct pieces of functionality and my view is that there should be an API that allows backends to consume extension module builders to find out where things got created and where they should be shipped inside archives.

      In this hypothetical future any build backend would be able to trigger the building of extension modules based on user configuration.

    "},{"location":"blog/2023/12/11/hatch-v180/#support","title":"Support","text":"

    If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!

    "},{"location":"blog/2023/12/18/hatch-v190/","title":"Hatch v1.9.0","text":"

    Hatch v1.9.0 brings improvements to static analysis and important bug fixes.

    "},{"location":"blog/2023/12/18/hatch-v190/#static-analysis","title":"Static analysis","text":"

    The default version of Ruff has been increased to v0.1.8. This release brings formatting capabilities to docstrings and Hatch enables this by default with line length set to 80. This length was chosen as the default because it plays nicely with the rendering of the most popular themes for Python documentation, such as Material for MkDocs and Furo.

    Additionally, it is now possible for projects to pin to specific versions of Ruff for upgrading at a later time:

    pyproject.toml hatch.toml
    [tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
    [envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
    "},{"location":"blog/2023/12/18/hatch-v190/#notable-fixes","title":"Notable fixes","text":"
    • Python resolution for environments that do not install the project is no longer bound by the project's Python requirement.
    • Fixed an edge case for out-of-the-box static analysis when there was existing configuration.
    • Compatibility checks for environments no longer occur if the environment is already created. This significantly increases the responsiveness of environment usage.
    "},{"location":"cli/about/","title":"About","text":""},{"location":"cli/about/#verbosity","title":"Verbosity","text":"

    The amount of displayed output is controlled solely by the -v/--verbose (environment variable HATCH_VERBOSE) and -q/--quiet (environment variable HATCH_QUIET) root options.

    The levels are documented here.

    "},{"location":"cli/about/#project-awareness","title":"Project awareness","text":"

    No matter the mode, Hatch will always change to the project's root directory for entering or running commands in environments.

    "},{"location":"cli/about/#tab-completion","title":"Tab completion","text":"

    Completion is achieved by saving a script and then executing it as a part of your shell's startup sequence.

    Afterward, you'll need to start a new shell in order for the changes to take effect.

    BashZ shellfish

    Save the script somewhere:

    _HATCH_COMPLETE=bash_source hatch > ~/.hatch-complete.bash\n

    Source the file in ~/.bashrc (or ~/.bash_profile if on macOS):

    . ~/.hatch-complete.bash\n

    Save the script somewhere:

    _HATCH_COMPLETE=zsh_source hatch > ~/.hatch-complete.zsh\n

    Source the file in ~/.zshrc:

    . ~/.hatch-complete.zsh\n

    Save the script in ~/.config/fish/completions:

    _HATCH_COMPLETE=fish_source hatch > ~/.config/fish/completions/hatch.fish\n
    "},{"location":"cli/reference/","title":"hatch","text":"

    Usage:

    hatch [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --env, -e text The name of the environment to use [env var: HATCH_ENV] default --project, -p text The name of the project to work on [env var: HATCH_PROJECT] None --verbose, -v integer range (0 and above) Increase verbosity (can be used additively) [env var: HATCH_VERBOSE] 0 --quiet, -q integer range (0 and above) Decrease verbosity (can be used additively) [env var: HATCH_QUIET] 0 --color / --no-color boolean Whether or not to display colored output (default is auto-detection) [env vars: FORCE_COLOR/NO_COLOR] None --interactive / --no-interactive boolean Whether or not to allow features like prompts and progress bars (default is auto-detection) [env var: HATCH_INTERACTIVE] None --data-dir text The path to a custom directory used to persist data [env var: HATCH_DATA_DIR] None --cache-dir text The path to a custom directory used to cache data [env var: HATCH_CACHE_DIR] None --config text The path to a custom config file to use [env var: HATCH_CONFIG] None --version boolean Show the version and exit. False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-build","title":"hatch build","text":"

    Build a project.

    Usage:

    hatch build [OPTIONS] [LOCATION]\n

    Options:

    Name Type Description Default --target, -t text The target to build, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None --hooks-only boolean Whether or not to only execute build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False --no-hooks boolean Whether or not to disable build hooks [env var: HATCH_BUILD_NO_HOOKS] False --ext boolean Whether or not to only execute build hooks for distributing binary Python packages, such as compiling extensions. Equivalent to --hooks-only -t wheel False --clean, -c boolean Whether or not existing artifacts should first be removed [env var: HATCH_BUILD_CLEAN] False --clean-hooks-after boolean Whether or not build hook artifacts should be removed after each build [env var: HATCH_BUILD_CLEAN_HOOKS_AFTER] False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-clean","title":"hatch clean","text":"

    Remove build artifacts.

    Usage:

    hatch clean [OPTIONS] [LOCATION]\n

    Options:

    Name Type Description Default --target, -t text The target with which to remove artifacts, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None --hooks-only boolean Whether or not to only remove artifacts from build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False --no-hooks boolean Whether or not to ignore artifacts from build hooks [env var: HATCH_BUILD_NO_HOOKS] False --ext boolean Whether or not to only remove artifacts from build hooks for distributing binary Python packages, such as compiled extensions. Equivalent to --hooks-only -t wheel False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config","title":"hatch config","text":"

    Manage the config file

    Usage:

    hatch config [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-explore","title":"hatch config explore","text":"

    Open the config location in your file manager.

    Usage:

    hatch config explore [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-find","title":"hatch config find","text":"

    Show the location of the config file.

    Usage:

    hatch config find [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-restore","title":"hatch config restore","text":"

    Restore the config file to default settings.

    Usage:

    hatch config restore [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-set","title":"hatch config set","text":"

    Assign values to config file entries. If the value is omitted, you will be prompted, with the input hidden if it is sensitive.

    Usage:

    hatch config set [OPTIONS] KEY [VALUE]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-show","title":"hatch config show","text":"

    Show the contents of the config file.

    Usage:

    hatch config show [OPTIONS]\n

    Options:

    Name Type Description Default --all, -a boolean Do not scrub secret fields False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-update","title":"hatch config update","text":"

    Update the config file with any new fields.

    Usage:

    hatch config update [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep","title":"hatch dep","text":"

    Manage environment dependencies

    Usage:

    hatch dep [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-hash","title":"hatch dep hash","text":"

    Output a hash of the currently defined dependencies.

    Usage:

    hatch dep hash [OPTIONS]\n

    Options:

    Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show","title":"hatch dep show","text":"

    Display dependencies in various formats

    Usage:

    hatch dep show [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show-requirements","title":"hatch dep show requirements","text":"

    Enumerate dependencies as a list of requirements.

    Usage:

    hatch dep show requirements [OPTIONS]\n

    Options:

    Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --feature, -f text Whether or not to only show the dependencies of the specified features None --all boolean Whether or not to include the dependencies of all features False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show-table","title":"hatch dep show table","text":"

    Enumerate dependencies in a tabular format.

    Usage:

    hatch dep show table [OPTIONS]\n

    Options:

    Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --lines, -l boolean Whether or not to show lines between table rows False --ascii boolean Whether or not to only use ASCII characters False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env","title":"hatch env","text":"

    Manage project environments

    Usage:

    hatch env [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-create","title":"hatch env create","text":"

    Create environments.

    Usage:

    hatch env create [OPTIONS] [ENV_NAME]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-find","title":"hatch env find","text":"

    Locate environments.

    Usage:

    hatch env find [OPTIONS] [ENV_NAME]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-prune","title":"hatch env prune","text":"

    Remove all environments.

    Usage:

    hatch env prune [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-remove","title":"hatch env remove","text":"

    Remove environments.

    Usage:

    hatch env remove [OPTIONS] [ENV_NAME]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-run","title":"hatch env run","text":"

    Run commands within project environments.

    The -e/--env option overrides the equivalent root option and the HATCH_ENV environment variable.

    If environments provide matrices, then you may use the -i/--include and -x/--exclude options to select or exclude certain variables, optionally followed by specific comma-separated values. For example, if you have the following configuration:

    pyproject.toml hatch.toml
    [[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
    [[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n

    then running:

    hatch env run -i py=3.10 -x version=9000 test:pytest\n

    would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

    Usage:

    hatch env run [OPTIONS] ARGS...\n

    Options:

    Name Type Description Default --env, -e text The environments to target None --include, -i text The matrix variables to include None --exclude, -x text The matrix variables to exclude None --filter, -f text The JSON data used to select environments None --force-continue boolean Run every command and if there were any errors exit with the first code False --ignore-compat boolean Ignore incompatibility when selecting specific environments False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-show","title":"hatch env show","text":"

    Show the available environments.

    Usage:

    hatch env show [OPTIONS] [ENVS]...\n

    Options:

    Name Type Description Default --ascii boolean Whether or not to only use ASCII characters False --json boolean Whether or not to output in JSON format False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-fmt","title":"hatch fmt","text":"

    Format and lint source code.

    Usage:

    hatch fmt [OPTIONS] [ARGS]...\n

    Options:

    Name Type Description Default --check boolean Only check for errors rather than fixing them False --preview / --no-preview boolean Preview new rules and formatting None --linter, -l boolean Only run the linter False --formatter, -f boolean Only run the formatter False --sync boolean Sync the default config file with the current version of Hatch False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-new","title":"hatch new","text":"

    Create or initialize a project.

    Usage:

    hatch new [OPTIONS] [NAME] [LOCATION]\n

    Options:

    Name Type Description Default --interactive, -i boolean Interactively choose details about the project False --cli boolean Give the project a command line interface False --init boolean Initialize an existing project False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-project","title":"hatch project","text":"

    View project information

    Usage:

    hatch project [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-project-metadata","title":"hatch project metadata","text":"

    Display project metadata.

    If you want to view the raw readme file without rendering, you can use a JSON parser like jq:

    hatch project metadata | jq -r .readme\n

    Usage:

    hatch project metadata [OPTIONS] [FIELD]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-publish","title":"hatch publish","text":"

    Publish build artifacts.

    Usage:

    hatch publish [OPTIONS] [ARTIFACTS]...\n

    Options:

    Name Type Description Default --repo, -r text The repository with which to publish artifacts [env var: HATCH_INDEX_REPO] None --user, -u text The user with which to authenticate [env var: HATCH_INDEX_USER] None --auth, -a text The credentials to use for authentication [env var: HATCH_INDEX_AUTH] None --ca-cert text The path to a CA bundle [env var: HATCH_INDEX_CA_CERT] None --client-cert text The path to a client certificate, optionally containing the private key [env var: HATCH_INDEX_CLIENT_CERT] None --client-key text The path to the client certificate's private key [env var: HATCH_INDEX_CLIENT_KEY] None --no-prompt, -n boolean Disable prompts, such as for missing required fields False --initialize-auth boolean Save first-time authentication information even if nothing was published False --publisher, -p text The publisher plugin to use (default is index) [env var: HATCH_PUBLISHER] index --option, -o text Options to pass to the publisher plugin. This may be selected multiple times e.g. -o foo=bar -o baz=23 [env var: HATCH_PUBLISHER_OPTIONS] None --yes, -y boolean Confirm without prompting when the plugin is disabled False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python","title":"hatch python","text":"

    Manage Python installations

    Usage:

    hatch python [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-find","title":"hatch python find","text":"

    Locate Python binaries.

    Usage:

    hatch python find [OPTIONS] NAME\n

    Options:

    Name Type Description Default -p, --parent boolean Show the parent directory of the Python binary False --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-install","title":"hatch python install","text":"

    Install Python distributions.

    You may select all to install all compatible distributions:

    hatch python install all\n

    Usage:

    hatch python install [OPTIONS] NAMES...\n

    Options:

    Name Type Description Default --private boolean Do not add distributions to the user PATH False --update, -u boolean Update existing installations False --dir, -d text The directory in which to install distributions, overriding configuration None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-remove","title":"hatch python remove","text":"

    Remove Python distributions.

    You may select all to remove all installed distributions:

    hatch python remove all\n

    Usage:

    hatch python remove [OPTIONS] NAMES...\n

    Options:

    Name Type Description Default --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-show","title":"hatch python show","text":"

    Show the available Python distributions.

    Usage:

    hatch python show [OPTIONS]\n

    Options:

    Name Type Description Default --ascii boolean Whether or not to only use ASCII characters False --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-update","title":"hatch python update","text":"

    Update Python distributions.

    You may select all to update all installed distributions:

    hatch python update all\n

    Usage:

    hatch python update [OPTIONS] NAMES...\n

    Options:

    Name Type Description Default --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-run","title":"hatch run","text":"

    Run commands within project environments. This is a convenience wrapper around the env run command.

    If the first argument contains a colon, then the preceding component will be interpreted as the name of the environment to target, overriding the -e/--env root option and the HATCH_ENV environment variable.

    If the environment provides matrices, then you may also provide leading arguments starting with a + or - to select or exclude certain variables, optionally followed by specific comma-separated values. For example, if you have the following configuration:

    pyproject.toml hatch.toml
    [[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
    [[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n

    then running:

    hatch run +py=3.10 -version=9000 test:pytest\n

    would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

    Usage:

    hatch run [OPTIONS] [ENV:]ARGS...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-shell","title":"hatch shell","text":"

    Enter a shell within a project's environment.

    Usage:

    hatch shell [OPTIONS] [SHELL_NAME] [SHELL_PATH] [SHELL_ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-status","title":"hatch status","text":"

    Show information about the current environment.

    Usage:

    hatch status [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-version","title":"hatch version","text":"

    View or set a project's version.

    Usage:

    hatch version [OPTIONS] [DESIRED_VERSION]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"community/contributing/","title":"Contributing","text":"

    The usual process to make a contribution is to:

    1. Check for existing related issues
    2. Fork the repository and create a new branch
    3. Make your changes
    4. Make sure formatting, linting and tests passes.
    5. Add tests if possible to cover the lines you added.
    6. Commit, and send a Pull Request.
    "},{"location":"community/contributing/#clone-the-repository","title":"Clone the repository","text":"

    Clone the hatch repository, cd into it, and create a new branch for your contribution:

    cd hatch\ngit checkout -b add-my-contribution\n
    "},{"location":"community/contributing/#run-the-tests","title":"Run the tests","text":"

    Run the test suite while developing:

    hatch run dev\n

    Run the test suite with coverage report:

    hatch run cov\n

    Run the extended test suite with coverage:

    hatch run full\n
    "},{"location":"community/contributing/#lint","title":"Lint","text":"

    Run automated formatting:

    hatch run lint:fmt\n

    Run full linting and type checking:

    hatch run lint:all\n
    "},{"location":"community/contributing/#docs","title":"Docs","text":"

    Start the documentation in development:

    hatch run docs:serve\n

    Build and validate the documentation website:

    hatch run build-check\n
    "},{"location":"community/highlights/","title":"Highlights","text":""},{"location":"community/highlights/#integration","title":"Integration","text":"
    • Project Jupyter - https://blog.jupyter.org/packaging-for-jupyter-in-2022-c7be64c38926
    "},{"location":"community/highlights/#adoption","title":"Adoption","text":"
    • Black - https://ichard26.github.io/blog/2022/10/black-22.10.0/#goodbye-python-36-and-hello-hatchling
    • \"Switching to Hatch\" - https://andrich.me/2023/08/switching-to-hatch/
    "},{"location":"community/users/","title":"Users","text":"

    The following is not intended to be a complete enumeration. Be sure to view the development version of this page for an up-to-date listing.

    "},{"location":"community/users/#projects","title":"Projects","text":"

    aiogram | argon2-cffi | attrs | Black | coffea | Colorama | Django Anymail | Django Debug Toolbar | Django Wiki | FastAPI | filelock | github3.py | Gradio | HTTPX | iCalendar for Humans | LinkChecker | Material for MkDocs | MkDocs | openSUSE | Nox | Packit | pipx | platformdirs | Pydantic | Pygments | PyHamcrest | PyMdown Extensions | Python JSON Schema | Rye | SALib | Spack | Starlette | structlog | tox | Twisted | urllib3 | Uvicorn | virtualenv | Voil\u00e0 | XGBoost | Ypy

    "},{"location":"community/users/#industry","title":"Industry","text":"
    • Anaconda [1|2|3|4|5|6]
    • Astronomer [1]
    • Bloomberg [1|2]
    • Blue Robotics [1]
    • Cars.com [1]
    • Databricks [1|2]
    • Datadog [1|2|3|4]
    • deepset [1|2]
    • Elastic [1|2|3]
    • Google [1|2|3|4|5]
    • IBM [1]
    • JPMorgan Chase [1]
    • Intel Corporation [1|2|3]
    • Meta [1|2]
    • Microsoft [1|2|3|4|5]
    • OpenAI [1]
    • Oracle [1]
    • Palo Alto Networks [1]
    • Red Hat [1|2|3|4|5]
    • Snowflake [1]
    • Splunk [1]
    • Virtru [1|2]
    • VMware [1|2|3]
    • Volvo Group [1]
    "},{"location":"community/users/#organizations","title":"Organizations","text":"
    • Greater Paris University Hospitals (AP-HP) [1]
    • OpenTelemetry [1|2]
    • Smithsonian Institution [1]
    • The New York Public Library [1]
    "},{"location":"community/users/#government","title":"Government","text":"
    • European Molecular Biology Laboratory
      • European Bioinformatics Institute [1]
    • Germany
      • Berlin Institute of Health [1]
      • Helmholtz Munich [1|2]
    • Norway
      • Statistics Norway [1]
    • United Kingdom
      • The Alan Turing Institute [1]
      • Department for Business and Trade [1]
      • The National Archives [1]
    • United States
      • NASA [1]
      • National Security Agency [1|2]
      • National Telecommunications and Information Administration [1|2|3|4]
    "},{"location":"community/users/#academia","title":"Academia","text":"
    • Brown University
      • Carney Institute for Brain Science [1]
    • Chinese Academy of Sciences
      • Academy of Mathematics and Systems Science [1]
    • Georgia Institute of Technology
      • Georgia Tech Database Group [1]
    • Harvard University
      • Department of Molecular and Cellular Biology [1]
    • Heidelberg University
      • Center for Molecular Biology [1]
    • Leiden University
      • Leiden University Libraries [1|2]
    • Maastricht University
      • Institute of Data Science [1|2|3|4|5|6|7]
    • Massachusetts Institute of Technology
      • Computer Science and Artificial Intelligence Laboratory [1]
      • Digital Humanities [1]
    • Medical University of Innsbruck
      • Institute of Bioinformatics [1]
    • Polytechnique Montr\u00e9al
      • Department of Computer Engineering and Software Engineering [1]
    • Siberian Branch of the Russian Academy of Sciences
      • Institute of Cytology and Genetics [1|2|3|4]
    • Stanford University
      • Empirical Security Research Group [1]
    • University of British Columbia
      • Department of Earth, Ocean and Atmospheric Sciences [1|2|3]
    • University of California, Berkeley
      • Center for Computational Biology [1]
    • University of Freiburg
      • Freiburg Center for Data Analysis and Modeling [1]
    • University of Illinois Urbana-Champaign
      • Grainger College of Engineering [1]
    • University of Lausanne
      • Department of Computational Biology [1]
    • University of Ljubljana
      • Faculty of Mechanical Engineering [1]
    • University of Oxford
      • Oxford Research Software Engineering [1]
    • University of Pennsylvania
      • Lifespan Informatics and Neuroimaging Center [1]
    • University of Sussex
      • Predictive Analytics Lab [1]
    • University of Toronto Scarborough
      • utsc-networking [1|2|3|4]
    • University of Washington
      • Interactive Data Lab [1]
      • Virtual Brain Lab [1]
    • Waseda University
      • Tackeuchi Laboratory [1|2|3|4|5]
    • Wellcome Sanger Institute [1]
    "},{"location":"community/users/#research","title":"Research","text":"
    • Clariah [1]
    • CloudDrift [1]
    • GAMA [1]
    • IPython [1|2|3]
    • MNE [1|2|3]
    • NIPY [1|2]
    • Project Jupyter
      • Jupyter [1|2|3|4]
      • JupyterLab [1|2|3|4|5]
      • Jupyter Server [1|2|3|4]
    • Scikit-HEP [1|2|3|4|5|6|7|8|9|10]
    • scverse [1|2|3]
    • Spyder [1]
    "},{"location":"community/users/#security","title":"Security","text":"
    • Armory
    • in-toto
    • The Update Framework
    "},{"location":"community/users/#crypto","title":"Crypto","text":"
    • Ocean Protocol [1]
    "},{"location":"config/build/","title":"Build configuration","text":"

    Build targets are defined as sections within tool.hatch.build.targets:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.<TARGET_NAME>]\n
    [build.targets.<TARGET_NAME>]\n

    Tip

    Although not recommended, you may define global configuration in the tool.hatch.build table. Keys may then be overridden by target config.

    "},{"location":"config/build/#build-system","title":"Build system","text":"

    To be compatible with the broader Python packaging ecosystem, you must define the build system as follows:

    pyproject.toml
    [build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n

    The version of hatchling defined here will be used to build all targets.

    Hatchling is a standards-compliant1 build backend and is a dependency of Hatch itself.

    "},{"location":"config/build/#file-selection","title":"File selection","text":""},{"location":"config/build/#vcs","title":"VCS","text":"

    By default, Hatch will respect the first .gitignore or .hgignore file found in your project's root directory or parent directories. Set ignore-vcs to true to disable this behavior:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.sdist]\nignore-vcs = true\n
    [build.targets.sdist]\nignore-vcs = true\n

    Note

    For .hgignore files only glob syntax is supported.

    "},{"location":"config/build/#patterns","title":"Patterns","text":"

    You can set the include and exclude options to select exactly which files will be shipped in each build, with exclude taking precedence. Every entry represents a Git-style glob pattern.

    For example, the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.sdist]\ninclude = [\n  \"pkg/*.py\",\n  \"/tests\",\n]\nexclude = [\n  \"*.json\",\n  \"pkg/_compat.py\",\n]\n
    [build.targets.sdist]\ninclude = [\n  \"pkg/*.py\",\n  \"/tests\",\n]\nexclude = [\n  \"*.json\",\n  \"pkg/_compat.py\",\n]\n

    will exclude every file with a .json extension, and will include everything under a tests directory located at the root and every file with a .py extension that is directly under a pkg directory located at the root except for _compat.py.

    "},{"location":"config/build/#artifacts","title":"Artifacts","text":"

    If you want to include files that are ignored by your VCS, such as those that might be created by build hooks, you can use the artifacts option. This option is semantically equivalent to include.

    Note that artifacts are not affected by the exclude option. Artifacts can be excluded by using more explicit paths or by using the ! negation operator. When using the ! operator, the negated pattern(s) must come after the more generic ones.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\nartifacts = [\n  \"*.so\",\n  \"*.dll\",\n  \"!/foo/*.so\",\n]\n
    [build.targets.wheel]\nartifacts = [\n  \"*.so\",\n  \"*.dll\",\n  \"!/foo/*.so\",\n]\n
    "},{"location":"config/build/#explicit-selection","title":"Explicit selection","text":""},{"location":"config/build/#generic","title":"Generic","text":"

    You can use the only-include option to prevent directory traversal starting at the project root and only select specific relative paths to directories or files. Using this option ignores any defined include patterns.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
    [build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
    "},{"location":"config/build/#packages","title":"Packages","text":"

    The packages option is semantically equivalent to only-include (which takes precedence) except that the shipped path will be collapsed to only include the final component.

    So for example, if you want to ship a package foo that is stored in a directory src you would do:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
    [build.targets.wheel]\npackages = [\"src/foo\"]\n
    "},{"location":"config/build/#forced-inclusion","title":"Forced inclusion","text":"

    The force-include option allows you to select specific files or directories from anywhere on the file system that should be included and map them to the desired relative distribution path.

    For example, if there was a directory alongside the project root named artifacts containing a file named lib.so and a file named lib.h in your home directory, you could ship both files in a pkg directory with the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n
    [build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n

    Note

    • Files must be mapped exactly to their desired paths, not to directories.
    • The contents of directory sources are recursively included.
    • To map directory contents directly to the root use / (a forward slash).
    • Sources that do not exist will raise an error.

    Warning

    Files included using this option will overwrite any file path that was already included by other file selection options.

    "},{"location":"config/build/#default-file-selection","title":"Default file selection","text":"

    If no file selection options are provided, then what gets included is determined by each build target.

    "},{"location":"config/build/#excluding-files-outside-packages","title":"Excluding files outside packages","text":"

    If you want to exclude non-artifact files that do not reside within a Python package, set only-packages to true:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\nonly-packages = true\n
    [build.targets.wheel]\nonly-packages = true\n
    "},{"location":"config/build/#rewriting-paths","title":"Rewriting paths","text":"

    You can rewrite relative paths to directories with the sources option. For example, the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n
    [build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n

    would distribute the file src/foo/file.ext as bar/file.ext.

    If you want to remove path prefixes entirely, rather than setting each to an empty string, you can define sources as an array:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\nsources = [\"src\"]\n
    [build.targets.wheel]\nsources = [\"src\"]\n

    If you want to add a prefix to paths, you can use an empty string. For example, the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel.sources]\n\"\" = \"foo\"\n
    [build.targets.wheel.sources]\n\"\" = \"foo\"\n

    would distribute the file bar/file.ext as foo/bar/file.ext.

    The packages option itself relies on sources. Defining packages = [\"src/foo\"] for the wheel target is equivalent to the following:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
    [build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
    "},{"location":"config/build/#performance","title":"Performance","text":"

    All encountered directories are traversed by default. To skip non-artifact directories that are excluded, set skip-excluded-dirs to true:

    pyproject.toml hatch.toml
    [tool.hatch.build]\nskip-excluded-dirs = true\n
    [build]\nskip-excluded-dirs = true\n

    Warning

    This may result in not shipping desired files. For example, if you want to include the file a/b/c.txt but your VCS ignores a/b, the file c.txt will not be seen because its parent directory will not be entered. In such cases you can use the force-include option.

    "},{"location":"config/build/#reproducible-builds","title":"Reproducible builds","text":"

    By default, build targets will build in a reproducible manner provided that they support that behavior. To disable this, set reproducible to false:

    pyproject.toml hatch.toml
    [tool.hatch.build]\nreproducible = false\n
    [build]\nreproducible = false\n

    When enabled, the SOURCE_DATE_EPOCH environment variable will be used for all build timestamps. If not set, then Hatch will use an unchanging default value.

    "},{"location":"config/build/#output-directory","title":"Output directory","text":"

    When the output directory is not provided to the build command, the dist directory will be used by default. You can change the default to a different directory using a relative or absolute path like so:

    pyproject.toml hatch.toml
    [tool.hatch.build]\ndirectory = \"<PATH>\"\n
    [build]\ndirectory = \"<PATH>\"\n
    "},{"location":"config/build/#dev-mode","title":"Dev mode","text":"

    By default for dev mode environment installations or editable installs, the wheel target will determine which directories should be added to Python's search path based on the selected files.

    If you want to override this detection or perhaps instruct other build targets as well, you can use the dev-mode-dirs option:

    pyproject.toml hatch.toml
    [tool.hatch.build]\ndev-mode-dirs = [\".\"]\n
    [build]\ndev-mode-dirs = [\".\"]\n

    If you don't want to add entire directories to Python's search path, you can enable a more targeted mechanism with the mutually exclusive dev-mode-exact option:

    pyproject.toml hatch.toml
    [tool.hatch.build]\ndev-mode-exact = true\n
    [build]\ndev-mode-exact = true\n

    Warning

    The dev-mode-exact mechanism is not supported by static analysis tools & IDEs, therefore functionality such as autocompletion is unlikely to work.

    "},{"location":"config/build/#build-targets","title":"Build targets","text":"

    A build target can be provided by any builder plugin. There are three built-in build targets: wheel, sdist, and custom.

    "},{"location":"config/build/#dependencies","title":"Dependencies","text":"

    You can specify additional dependencies that will be installed in each build environment, such as for third party builders:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.your-target-name]\ndependencies = [\n  \"your-builder-plugin\"\n]\n
    [build.targets.your-target-name]\ndependencies = [\n  \"your-builder-plugin\"\n]\n

    You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies option:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.your-target-name]\nrequire-runtime-dependencies = true\n
    [build.targets.your-target-name]\nrequire-runtime-dependencies = true\n

    Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features option:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.your-target-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
    [build.targets.your-target-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
    "},{"location":"config/build/#versions","title":"Versions","text":"

    If a build target supports multiple build strategies or if there are major changes over time, you can specify exactly which versions you want to build using the versions option:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.<TARGET_NAME>]\nversions = [\n  \"v1\",\n  \"beta-feature\",\n]\n
    [build.targets.<TARGET_NAME>]\nversions = [\n  \"v1\",\n  \"beta-feature\",\n]\n

    See the wheel target for a real world example.

    "},{"location":"config/build/#build-hooks","title":"Build hooks","text":"

    A build hook defines code that will be executed at various stages of the build process and can be provided by any build hook plugin. There is one built-in build hook: custom.

    Build hooks can be applied either globally:

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.<HOOK_NAME>]\n
    [build.hooks.<HOOK_NAME>]\n

    or to specific build targets:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
    [build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
    "},{"location":"config/build/#dependencies_1","title":"Dependencies","text":"

    You can specify additional dependencies that will be installed in each build environment, such as for third party build hooks:

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.your-hook-name]\ndependencies = [\n  \"your-build-hook-plugin\"\n]\n
    [build.hooks.your-hook-name]\ndependencies = [\n  \"your-build-hook-plugin\"\n]\n

    You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies option:

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n
    [build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n

    Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features option:

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
    [build.hooks.your-hook-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
    "},{"location":"config/build/#order-of-execution","title":"Order of execution","text":"

    For each build target, build hooks execute in the order in which they are defined, starting with global hooks.

    As an example, for the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.foo.hooks.hook2]\n\n[tool.hatch.build.hooks.hook3]\n[tool.hatch.build.hooks.hook1]\n
    [build.targets.foo.hooks.hook2]\n\n[build.hooks.hook3]\n[build.hooks.hook1]\n

    When target foo is built, build hook hook3 will be executed first, followed by hook1, and then finally hook2.

    "},{"location":"config/build/#conditional-execution","title":"Conditional execution","text":"

    If you want to disable a build hook by default and control its use by environment variables, you can do so by setting the enable-by-default option to false:

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
    [build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
    "},{"location":"config/build/#environment-variables","title":"Environment variables","text":"Variable Default Description HATCH_BUILD_CLEAN false Whether or not existing artifacts should first be removed HATCH_BUILD_CLEAN_HOOKS_AFTER false Whether or not build hook artifacts should be removed after each build HATCH_BUILD_HOOKS_ONLY false Whether or not to only execute build hooks HATCH_BUILD_NO_HOOKS false Whether or not to disable all build hooks; this takes precedence over other options HATCH_BUILD_HOOKS_ENABLE false Whether or not to enable all build hooks HATCH_BUILD_HOOK_ENABLE_<HOOK_NAME> false Whether or not to enable the build hook named <HOOK_NAME> HATCH_BUILD_LOCATION dist The location with which to build the targets; only used by the build command
    1. Support for PEP 517 and PEP 660 guarantees interoperability with other build tools.\u00a0\u21a9

    "},{"location":"config/context/","title":"Context formatting","text":"

    You can populate configuration with the values of certain supported fields using the syntax of Python's format strings. Each field interprets the modifier part after the colon differently, if at all.

    "},{"location":"config/context/#global-fields","title":"Global fields","text":"

    Any configuration that declares support for context formatting will always support these fields.

    "},{"location":"config/context/#paths","title":"Paths","text":"Field Description root The root project directory home The user's home directory

    All paths support the following modifiers:

    Modifier Description uri The normalized absolute URI path prefixed by file: real The path with all symbolic links resolved parent The parent of the preceding path

    Tip

    The parent modifier can be chained and may be combined with either the uri or real modifier, with the latter placed at the end. For example:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n    \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
    [envs.test]\ndependencies = [\n    \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
    "},{"location":"config/context/#system-separators","title":"System separators","text":"Field Description / \\ on Windows, / otherwise ; ; on Windows, : otherwise"},{"location":"config/context/#environment-variables","title":"Environment variables","text":"

    The env field and its modifier allow you to select the value of an environment variable. If the environment variable is not set, you must specify a default value as an additional modifier e.g. {env:PATH:DEFAULT}.

    "},{"location":"config/context/#field-nesting","title":"Field nesting","text":"

    You can insert fields within others. For example, if you wanted a script that displays the value of the environment variable FOO, with a fallback to the environment variable BAR, with its own fallback to the user's home directory, you could do the following:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
    [envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
    "},{"location":"config/dependency/","title":"Dependency configuration","text":"

    Project dependencies are defined with PEP 508 strings using optional PEP 440 version specifiers.

    "},{"location":"config/dependency/#version-specifiers","title":"Version specifiers","text":"

    A version specifier consists of a series of version clauses, separated by commas. For example:

    pyproject.toml
    [project]\n...\ndependencies = [\n  \"cryptography\",\n  \"click>=7, <9, != 8.0.0\",\n  \"python-dateutil==2.8.*\",\n  \"numpy~=1.21.4\",\n]\n

    The comma is equivalent to a logical AND operator: a candidate version must match all given version clauses in order to match the specifier as a whole.

    "},{"location":"config/dependency/#operators","title":"Operators","text":"Operators Function ~= Compatible release == Version matching != Version exclusion <=, >= Inclusive ordered comparison <, > Exclusive ordered comparison === Arbitrary equality"},{"location":"config/dependency/#version-matching","title":"Version matching","text":"

    A version matching clause includes the version matching operator == and a version identifier.

    By default, the version matching operator is based on a strict equality comparison: the specified version must be exactly the same as the requested version.

    Clause Allowed versions ==1 1.0.0 ==1.2 1.2.0

    Prefix matching may be requested instead of strict comparison, by appending a trailing .* to the version identifier in the version matching clause. This means that additional trailing segments will be ignored when determining whether or not a version identifier matches the clause.

    Clause Allowed versions ==1.* >=1.0.0, <2.0.0 ==1.2.* >=1.2.0, <1.3.0"},{"location":"config/dependency/#compatible-release","title":"Compatible release","text":"

    A compatible release clause consists of the compatible release operator ~= and a version identifier. It matches any candidate version that is expected to be compatible with the specified version.

    For a given release identifier V.N, the compatible release clause is approximately equivalent to the following pair of comparison clauses:

    >= V.N, == V.*\n

    This operator cannot be used with a single segment version number such as ~=1.

    Clause Allowed versions ~=1.2 >=1.2.0, <2.0.0 ~=1.2.3 >=1.2.3, <1.3.0"},{"location":"config/dependency/#version-exclusion","title":"Version exclusion","text":"

    A version exclusion clause includes the version exclusion operator != and a version identifier.

    The allowed version identifiers and comparison semantics are the same as those of the Version matching operator, except that the sense of any match is inverted.

    "},{"location":"config/dependency/#ordered-comparison","title":"Ordered comparison","text":"

    Inclusive comparisons allow for the version identifier part of clauses whereas exclusive comparisons do not. For example, >=1.2 allows for version 1.2.0 while >1.2 does not.

    Unlike the inclusive ordered comparisons <= and >=, the exclusive ordered comparisons < and > specifically exclude pre-releases, post-releases, and local versions of the specified version.

    "},{"location":"config/dependency/#arbitrary-equality","title":"Arbitrary equality","text":"

    Though heavily discouraged, arbitrary equality comparisons allow for simple string matching without any version semantics, for example ===foobar.

    "},{"location":"config/dependency/#environment-markers","title":"Environment markers","text":"

    Environment markers allow for dependencies to only be installed when certain conditions are met.

    For example, if you need to install the latest version of cryptography that is available for a given Python major version you could define the following:

    cryptography==3.3.2; python_version < \"3\"\ncryptography>=35.0; python_version > \"3\"\n

    Alternatively, if you only need it on Python 3 when running on Windows you could do:

    cryptography; python_version ~= \"3.0\" and platform_system == \"Windows\"\n

    The available environment markers are as follows.

    Marker Python equivalent Examples os_name import osos.name
    • posix
    • java
    sys_platform import syssys.platform
    • linux
    • win32
    • darwin
    platform_machine import platformplatform.machine()
    • x86_64
    platform_python_implementation import platformplatform.python_implementation()
    • CPython
    • Jython
    platform_release import platformplatform.release()
    • 1.8.0_51
    • 3.14.1-x86_64-linode39
    platform_system import platformplatform.system()
    • Linux
    • Windows
    • Darwin
    platform_version import platformplatform.version()
    • 10.0.19041
    • #1 SMP Fri Apr 2 22:23:49 UTC 2021
    python_version import platform'.'.join(platform.python_version_tuple()[:2])
    • 2.7
    • 3.10
    python_full_version import platformplatform.python_version()
    • 2.7.18
    • 3.11.0b1
    implementation_name import syssys.implementation.name
    • cpython
    implementation_version See here
    • 2.7.18
    • 3.11.0b1
    "},{"location":"config/dependency/#features","title":"Features","text":"

    You can select groups of optional dependencies to install using the extras syntax. For example, if a dependency named foo defined the following:

    pyproject.toml
    [project.optional-dependencies]\ncrypto = [\n  \"PyJWT\",\n  \"cryptography\",\n]\nfastjson = [\n  \"orjson\",\n]\ncli = [\n  \"prompt-toolkit\",\n  \"colorama; platform_system == 'Windows'\",\n]\n

    You can select the cli and crypto features like so:

    foo[cli,crypto]==1.*\n

    Note that the features come immediately after the package name, before any version specifiers.

    "},{"location":"config/dependency/#self-referential","title":"Self-referential","text":"

    Feature groups can self-referentially extend others. For example, for a project called awesome-project, the dev feature group in the following pyproject.toml file would select everything in the crypto feature group, plus black:

    pyproject.toml
    [project]\nname = \"awesome-project\"\n\n[project.optional-dependencies]\ncrypto = [\n  \"PyJWT\",\n  \"cryptography\",\n]\ndev = [\n  \"awesome-project[crypto]\",\n  \"black\",\n]\n
    "},{"location":"config/dependency/#direct-references","title":"Direct references","text":"

    Instead of using normal version specifiers and fetching packages from an index like PyPI, you can define exact sources using direct references with an explicit URI.

    Direct references are usually not meant to be used for dependencies of a published project but rather are used for defining dependencies for an environment.

    All direct reference types are prefixed by the package name like:

    <NAME> @ <REFERENCE>\n
    "},{"location":"config/dependency/#version-control-systems","title":"Version control systems","text":"

    Various version control systems (VCS) are supported as long as the associated executable is available along your PATH.

    VCS direct references are defined using one of the following formats:

    <NAME> @ <SCHEME>://<PATH>\n<NAME> @ <SCHEME>://<PATH>@<REVISION>\n

    You may also append a #subdirectory=<PATH> component for specifying the relative path to the Python package when it is not located at the root e.g. #subdirectory=lib/foo.

    For more information, refer to this.

    "},{"location":"config/dependency/#supported-vcs","title":"Supported VCS","text":"GitMercurialSubversionBazaar Executable Schemes Revisions Example git
    • git+file
    • git+https
    • git+ssh
    • git+http
    • git+git
    • git
    • Commit hash
    • Tag name
    • Branch name
    proj @ git+https://github.com/org/proj.git@v1 Executable Schemes Revisions Example hg
    • hg+file
    • hg+https
    • hg+ssh
    • hg+http
    • hg+static-http
    • Revision hash
    • Revision number
    • Tag name
    • Branch name
    proj @ hg+file:///path/to/proj@v1 Executable Schemes Revisions Example svn
    • svn+https
    • svn+ssh
    • svn+http
    • svn+svn
    • svn
    • Revision number
    proj @ svn+file:///path/to/proj Executable Schemes Revisions Example bzr
    • bzr+https
    • bzr+ssh
    • bzr+sftp
    • bzr+lp
    • bzr+http
    • bzr+ftp
    • Revision number
    • Tag name
    proj @ bzr+lp:proj@v1"},{"location":"config/dependency/#local","title":"Local","text":"

    You can install local packages with the file scheme in the following format:

    <NAME> @ file://<HOST>/<PATH>\n

    The <HOST> is only used on Windows systems, where it can refer to a network share. If omitted it is assumed to be localhost and the third slash must still be present.

    The <PATH> can refer to a source archive, a wheel, or a directory containing a Python package.

    Type Unix Windows Source archive proj @ file:///path/to/pkg.tar.gz proj @ file:///c:/path/to/pkg.tar.gz Wheel proj @ file:///path/to/pkg.whl proj @ file:///c:/path/to/pkg.whl Directory proj @ file:///path/to/pkg proj @ file:///c:/path/to/pkg

    Tip

    You may also specify paths relative to your project's root directory on all platforms by using context formatting:

    <NAME> @ {root:uri}/pkg_inside_project\n<NAME> @ {root:uri}/../pkg_alongside_project\n
    "},{"location":"config/dependency/#remote","title":"Remote","text":"

    You can install source archives and wheels by simply referring to a URL:

    black @ https://github.com/psf/black/archive/refs/tags/21.10b0.zip\npytorch @ https://download.pytorch.org/whl/cu102/torch-1.10.0%2Bcu102-cp39-cp39-linux_x86_64.whl\n

    An expected hash value may be specified by appending a #<HASH_ALGORITHM>=<EXPECTED_HASH> component:

    requests @ https://github.com/psf/requests/archive/refs/tags/v2.26.0.zip#sha256=eb729a757f01c10546ebd179ae2aec852dd0d7f8ada2328ccf4558909d859985\n

    If the hash differs from the expected hash, the installation will fail.

    It is recommended that only hashes which are unconditionally provided by the latest version of the standard library's hashlib module be used for hashes. As of Python 3.10, that list consists of:

    • md5
    • sha1
    • sha224
    • sha256
    • sha384
    • sha512
    • blake2b
    • blake2s
    "},{"location":"config/dependency/#complex-syntax","title":"Complex syntax","text":"

    The following is an example that uses features and environment markers:

    pkg[feature1,feature2] @ <REFERENCE> ; python_version < \"3.7\"\n

    Note that the space before the semicolon is required.

    "},{"location":"config/hatch/","title":"Hatch configuration","text":"

    Configuration for Hatch itself is stored in a config.toml file located by default in one of the following platform-specific directories.

    Platform Path macOS ~/Library/Application Support/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch Unix $XDG_CONFIG_HOME/hatch (the XDG_CONFIG_HOME environment variable default is ~/.config)

    You can select a custom path to the file using the --config root option or by setting the HATCH_CONFIG environment variable.

    The file can be managed by the config command group.

    "},{"location":"config/hatch/#mode","title":"Mode","text":"

    The mode key controls how Hatch selects the project to work on.

    "},{"location":"config/hatch/#local","title":"Local","text":"config.toml
    mode = \"local\"\n

    By default, Hatch will look for a pyproject.toml file in the current working directory and any parent directories. The directory storing the first found file will be considered the project root.

    "},{"location":"config/hatch/#project","title":"Project","text":"config.toml
    mode = \"project\"\nproject = \"proj1\"\n\n[projects]\nproj1 = \"/path/to/project1\"\nproj2 = {\"location\": \"/path/to/project2\"}\n\n[dirs]\nproject = [\"/path/to/monorepo1\", \"/path/to/monorepo2\"]\n

    In this mode, Hatch will only work on the selected project. The project is located using multiple heuristics:

    1. If the project is defined in the projects table then it must be a string, or an inline table with a location key, that is the full path to the project.
    2. If the project matches a subdirectory in any of the directories listed in dirs.project, then that will be used as the project root.

    An error will occur if the project cannot be found.

    You can use the config set command to change the project you are working on:

    $ hatch config set project proj2\nNew setting:\nproject = \"proj2\"\n

    The project can be selected on a per-command basis with the -p/--project (environment variable HATCH_PROJECT) root option.

    "},{"location":"config/hatch/#aware","title":"Aware","text":"config.toml
    mode = \"aware\"\n

    This is essentially the local mode with a fallback to the project mode.

    "},{"location":"config/hatch/#shell","title":"Shell","text":"

    You can control the shell used to enter environments with the shell key.

    If defined as a string, it must be the name of one of the supported shells and be available along your PATH.

    config.toml
    shell = \"fish\"\n

    If the executable name of your shell differs from the supported name, you can define the shell as a table with name and path keys.

    config.toml
    [shell]\nname = \"bash\"\npath = \"/bin/ash\"\n

    You can change the default arguments used to spawn most shells with the args key. The default for such supported shells is usually [\"-i\"].

    config.toml
    [shell]\nname = \"bash\"\nargs = [\"--login\"]\n
    "},{"location":"config/hatch/#supported","title":"Supported","text":"Shell Name Arguments macOS Windows Unix Almquist shell ash [\"-i\"] Bash bash [\"-i\"] Command Prompt cmd C shell csh [\"-i\"] fish fish [\"-i\"] Nushell nu [] PowerShell pwsh, powershell tcsh tcsh [\"-i\"] xonsh xonsh [\"-i\"] Z shell zsh [\"-i\"]"},{"location":"config/hatch/#default","title":"Default","text":"

    Hatch will attempt to use the current shell based on parent processes. If the shell cannot be determined, then on Windows systems Hatch will use the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

    "},{"location":"config/hatch/#directories","title":"Directories","text":""},{"location":"config/hatch/#data","title":"Data","text":"config.toml
    [dirs]\ndata = \"...\"\n

    This is the directory that is used to persist data. By default it is set to one of the following platform-specific directories.

    Platform Path macOS ~/Library/Application Support/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch Unix $XDG_DATA_HOME/hatch (the XDG_DATA_HOME environment variable default is ~/.local/share)

    You can select a custom path to the directory using the --data-dir root option or by setting the HATCH_DATA_DIR environment variable.

    "},{"location":"config/hatch/#cache","title":"Cache","text":"config.toml
    [dirs]\ncache = \"...\"\n

    This is the directory that is used to cache data. By default it is set to one of the following platform-specific directories.

    Platform Path macOS ~/Library/Caches/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch\\Cache Unix $XDG_CACHE_HOME/hatch (the XDG_CACHE_HOME environment variable default is ~/.cache)

    You can select a custom path to the directory using the --cache-dir root option or by setting the HATCH_CACHE_DIR environment variable.

    "},{"location":"config/hatch/#environments","title":"Environments","text":"config.toml
    [dirs.env]\n<ENV_TYPE> = \"...\"\n

    This determines where to store environments, with every key being the type of environment and the value being the desired storage location.

    For example, if you wanted to store virtual environments in a .virtualenvs directory within your home directory, you could specify the following:

    config.toml
    [dirs.env]\nvirtual = \"~/.virtualenvs\"\n

    Any environment variables are also expanded.

    If the path is not absolute, then it will be relative to the project root. So if you wanted to use a directory named .hatch in each project directory, you could do:

    config.toml
    [dirs.env]\nvirtual = \".hatch\"\n

    Any type of environment that is not explicitly defined will default to <DATA_DIR>/env/<ENV_TYPE>.

    "},{"location":"config/hatch/#python-installations","title":"Python installations","text":"config.toml
    [dirs]\npython = \"...\"\n

    This determines where to install specific versions of Python.

    The following values have special meanings:

    Value Path isolated (default) <DATA_DIR>/pythons"},{"location":"config/hatch/#terminal","title":"Terminal","text":"

    You can configure how all output is displayed using the terminal.styles table. These settings are also applied to all plugins.

    config.toml
    [terminal.styles]\nerror = \"...\"\n...\n

    Cross-platform terminal capabilities are provided by Rich.

    "},{"location":"config/hatch/#output-levels","title":"Output levels","text":"

    The levels of output are as follows. Note that the verbosity indicates the minimum level at which the output is displayed.

    Level Default Verbosity Description debug bold 1 - 3 Messages that are not useful for most user experiences error bold red -2 Messages indicating some unrecoverable error info bold 0 Messages conveying basic information success bold cyan 0 Messages indicating some positive outcome waiting bold magenta 0 Messages shown before potentially time consuming operations warning bold yellow -1 Messages conveying important information

    See the documentation and color reference for guidance on valid values.

    "},{"location":"config/hatch/#spinner","title":"Spinner","text":"

    You can select the sequence used for waiting animations with the spinner option.

    config.toml
    [terminal.styles]\nspinner = \"...\"\n
    "},{"location":"config/metadata/","title":"Project metadata","text":"

    Project metadata is stored in a pyproject.toml file located at the root of a project's tree and is based entirely on the standard.

    "},{"location":"config/metadata/#name","title":"Name (required)","text":"

    The name of the project.

    pyproject.toml
    [project]\nname = \"your-app\"\n
    "},{"location":"config/metadata/#version","title":"Version (required)","text":"pyproject.toml DynamicStatic

    See the dedicated versioning section.

    [project]\n...\ndynamic = [\"version\"]\n\n[tool.hatch.version]\npath = \"...\"\n
    [project]\n...\nversion = \"0.0.1\"\n
    "},{"location":"config/metadata/#description","title":"Description","text":"

    A brief summary of the project.

    pyproject.toml
    [project]\n...\ndescription = '...'\n
    "},{"location":"config/metadata/#readme","title":"Readme","text":"

    The full description of the project.

    pyproject.toml SimpleComplex

    The file extension must be .md, .rst, or .txt.

    [project]\n...\nreadme = \"README.md\"\n

    The content-type field must be set to text/markdown, text/x-rst, or text/plain.

    FileText

    A charset field may also be set to instruct which encoding to use for reading the file, defaulting to utf-8.

    [project]\n...\nreadme = {\"file\" = \"README.md\", \"content-type\" = \"text/markdown\"}\n

    The content-type field must be set to text/markdown or text/x-rst.

    [project]\n...\nreadme = {\"text\" = \"...\", \"content-type\" = \"text/markdown\"}\n

    Note

    If this is defined as a file, then it will always be included in source distributions for consistent builds.

    "},{"location":"config/metadata/#python-support","title":"Python support","text":"

    The Python version requirements of the project.

    pyproject.toml
    [project]\n...\nrequires-python = \">=3.8\"\n
    "},{"location":"config/metadata/#license","title":"License","text":"

    For more information, see PEP 639.

    pyproject.toml SPDX expressionFiles
    [project]\n...\nlicense = \"Apache-2.0 OR MIT\"\n
    PathsGlobs
    [project]\n...\nlicense-files = { paths = [\"LICENSE.txt\"] }\n
    [project]\n...\nlicense-files = { globs = [\"LICENSES/*\"] }\n
    "},{"location":"config/metadata/#ownership","title":"Ownership","text":"

    The people or organizations considered to be the authors or maintainers of the project. The exact meaning is open to interpretation; it may list the original or primary authors, current maintainers, or owners of the package. If the values are the same, prefer only the use of the authors field.

    pyproject.toml
    [project]\n...\nauthors = [\n  { name = \"...\", email = \"...\" },\n]\nmaintainers = [\n  { name = \"...\", email = \"...\" },\n]\n
    "},{"location":"config/metadata/#keywords","title":"Keywords","text":"

    The keywords used to assist in the discovery of the project.

    pyproject.toml
    [project]\n...\nkeywords = [\n  \"...\",\n]\n
    "},{"location":"config/metadata/#classifiers","title":"Classifiers","text":"

    The trove classifiers that apply to the project.

    pyproject.toml
    [project]\n...\nclassifiers = [\n  \"...\",\n]\n
    "},{"location":"config/metadata/#urls","title":"URLs","text":"

    A table of URLs where the key is the URL label and the value is the URL itself.

    pyproject.toml
    [project.urls]\nDocumentation = \"...\"\n\"Source code\" = \"...\"\n
    "},{"location":"config/metadata/#dependencies","title":"Dependencies","text":"

    See the dependency specification page for more information.

    Entries support context formatting and disallow direct references by default.

    "},{"location":"config/metadata/#required","title":"Required","text":"pyproject.toml
    [project]\n...\ndependencies = [\n  \"...\",\n]\n
    "},{"location":"config/metadata/#optional","title":"Optional","text":"pyproject.toml
    [project.optional-dependencies]\noption1 = [\n  \"...\",\n]\noption2 = [\n  \"...\",\n]\n
    "},{"location":"config/metadata/#entry-points","title":"Entry points","text":"

    Entry points are a mechanism for the project to advertise components it provides to be discovered and used by other code.

    "},{"location":"config/metadata/#cli","title":"CLI","text":"

    After installing projects that define CLI scripts, each key will be available along your PATH as a command that will call its associated object.

    pyproject.toml
    [project.scripts]\ncli-name = \"pkg.subpkg:func\"\n

    Using the above example, running cli-name would essentially execute the following Python script:

    import sys\n\nfrom pkg.subpkg import func\n\nsys.exit(func())\n
    "},{"location":"config/metadata/#gui","title":"GUI","text":"

    GUI scripts are exactly the same as CLI scripts except on Windows, where they are handled specially so that they can be started without a console.

    pyproject.toml
    [project.gui-scripts]\ngui-name = \"pkg.subpkg:func\"\n
    "},{"location":"config/metadata/#plugins","title":"Plugins","text":"pyproject.toml
    [project.entry-points.plugin-namespace]\nplugin-name1 = \"pkg.subpkg1\"\nplugin-name2 = \"pkg.subpkg2:func\"\n
    "},{"location":"config/metadata/#dynamic","title":"Dynamic","text":"

    If any metadata fields are set dynamically, like the version may be, then they must be listed here.

    pyproject.toml
    [project]\n...\ndynamic = [\n  \"...\",\n]\n
    "},{"location":"config/metadata/#metadata-options","title":"Metadata options","text":""},{"location":"config/metadata/#allowing-direct-references","title":"Allowing direct references","text":"

    By default, dependencies are not allowed to define direct references. To disable this check, set allow-direct-references to true:

    pyproject.toml hatch.toml
    [tool.hatch.metadata]\nallow-direct-references = true\n
    [metadata]\nallow-direct-references = true\n
    "},{"location":"config/metadata/#allowing-ambiguous-features","title":"Allowing ambiguous features","text":"

    By default, names of optional dependencies are normalized to prevent ambiguity. To disable this normalization, set allow-ambiguous-features to true:

    pyproject.toml hatch.toml
    [tool.hatch.metadata]\nallow-ambiguous-features = true\n
    [metadata]\nallow-ambiguous-features = true\n

    Deprecated

    This option temporarily exists to provide better interoperability with tools that do not yet support PEP 685 and will be removed in the first minor release after Jan 1, 2024.

    "},{"location":"config/project-templates/","title":"Project templates","text":"

    You can control how new projects are created by the new command using Hatch's config file.

    "},{"location":"config/project-templates/#author","title":"Author","text":"config.toml
    [template]\nname = \"...\"\nemail = \"...\"\n
    "},{"location":"config/project-templates/#licenses","title":"Licenses","text":"config.toml
    [template.licenses]\nheaders = true\ndefault = [\n  \"MIT\",\n]\n

    The list of licenses should be composed of SPDX identifiers. If multiple licenses are specified, then they will be placed in a LICENSES directory.

    "},{"location":"config/project-templates/#options","title":"Options","text":""},{"location":"config/project-templates/#tests","title":"Tests","text":"

    This adds a tests directory with environments for testing and linting.

    config.toml
    [template.plugins.default]\ntests = true\n
    "},{"location":"config/project-templates/#ci","title":"CI","text":"

    This adds a GitHub Actions workflow that runs tests on all platforms using modern versions of Python.

    config.toml
    [template.plugins.default]\nci = false\n
    "},{"location":"config/project-templates/#src-layout","title":"src layout","text":"

    See this blog post.

    config.toml
    [template.plugins.default]\nsrc-layout = true\n
    "},{"location":"config/project-templates/#feature-flags","title":"Feature flags","text":""},{"location":"config/project-templates/#command-line-interface","title":"Command line interface","text":"

    The --cli flag adds a CLI backed by Click that can also be invoked with python -m <PKG_NAME>.

    "},{"location":"config/static-analysis/","title":"Static analysis configuration","text":"

    Static analysis performed by the fmt command is backed entirely by Ruff.

    Hatch provides default settings that user configuration can extend.

    "},{"location":"config/static-analysis/#extending-config","title":"Extending config","text":"

    When defining your configuration, be sure to use options that are prefixed by extend- such as extend-select, for example:

    pyproject.toml ruff.toml
    [tool.ruff.format]\npreview = true\nquote-style = \"single\"\n\n[tool.ruff.lint]\npreview = true\nextend-select = [\"C901\"]\n\n[tool.ruff.lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[tool.ruff.lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n
    [format]\npreview = true\nquote-style = \"single\"\n\n[lint]\npreview = true\nextend-select = [\"C901\"]\n\n[lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n

    Note

    When not persisting config, there is no need to explicitly extend the defaults as Hatch automatically handles that.

    "},{"location":"config/static-analysis/#persistent-config","title":"Persistent config","text":"

    If you want to store the default configuration in the project, set an explicit path like so:

    pyproject.toml hatch.toml
    [tool.hatch.envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n
    [envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n

    Then instruct Ruff to consider your configuration as an extension of the default file:

    pyproject.toml ruff.toml
    [tool.ruff]\nextend = \"ruff_defaults.toml\"\n
    extend = \"ruff_defaults.toml\"\n

    Anytime you wish to update the defaults (such as when upgrading Hatch), you must run the fmt command once with the --sync flag e.g.:

    hatch fmt --check --sync\n

    Tip

    This is the recommended approach since it allows other tools like IDEs to use the default configuration.

    "},{"location":"config/static-analysis/#versioning","title":"Versioning","text":"

    You can pin the particular version of Ruff by explicitly defining the environment dependencies:

    pyproject.toml hatch.toml
    [tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
    [envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
    "},{"location":"config/static-analysis/#default-settings","title":"Default settings","text":""},{"location":"config/static-analysis/#non-rule-settings","title":"Non-rule settings","text":"
    • Line length set to 120
    • Docstring formatting enabled with line length set to 80
    • Only absolute imports are allowed, except for tests
    • The normalized project name is a known first party import
    "},{"location":"config/static-analysis/#per-file-ignored-rules","title":"Per-file ignored rules","text":"
    • **/scripts/*: INP001, T201
    • **/tests/**/*: PLC1901, PLR2004, PLR6301, S, TID252
    "},{"location":"config/static-analysis/#selected-rules","title":"Selected rules","text":"

    The following rules are based on version 0.1.8 of Ruff. Rules with a P are only selected when preview mode is enabled.

    • A001, A002, A003
    • ARG001, ARG002, ARG003, ARG004, ARG005
    • ASYNC100, ASYNC101, ASYNC102
    • B002, B003, B004, B005, B006, B007, B008, B009, B010, B011, B012, B013, B014, B015, B016, B017, B018, B019, B020, B021, B022, B023, B024, B025, B026, B028, B029, B030, B031, B032, B033, B034, B904, B905
    • BLE001
    • C400, C401, C402, C403, C404, C405, C406, C408, C409, C410, C411, C413, C414, C415, C416, C417, C418, C419
    • COM818
    • DTZ001, DTZ002, DTZ003, DTZ004, DTZ005, DTZ006, DTZ007, DTZ011, DTZ012
    • E101, E112P, E113P, E115P, E116P, E201P, E202P, E203P, E211P, E221P, E222P, E223P, E224P, E225P, E226P, E227P, E228P, E231P, E241P, E242P, E251P, E252P, E261P, E262P, E265P, E266P, E271P, E272P, E273P, E274P, E275P, E401, E402, E501, E701, E702, E703, E711, E712, E713, E714, E721, E722, E731, E741, E742, E743, E902, E999
    • EM101, EM102, EM103
    • EXE001, EXE002, EXE003, EXE004, EXE005
    • F401, F402, F403, F404, F405, F406, F407, F501, F502, F503, F504, F505, F506, F507, F508, F509, F521, F522, F523, F524, F525, F541, F601, F602, F621, F622, F631, F632, F633, F634, F701, F702, F704, F706, F707, F722, F811, F821, F822, F823, F841, F842, F901
    • FA100, FA102
    • FBT001, FBT002
    • FLY002
    • FURB105P, FURB113P, FURB131P, FURB132P, FURB136P, FURB145P, FURB148P, FURB152P, FURB163P, FURB168P, FURB169P, FURB171P, FURB177P, FURB181P
    • G001, G002, G003, G004, G010, G101, G201, G202
    • I001, I002
    • ICN001, ICN002, ICN003
    • INP001
    • INT001, INT002, INT003
    • ISC003
    • LOG001P, LOG002P, LOG007P, LOG009P
    • N801, N802, N803, N804, N805, N806, N807, N811, N812, N813, N814, N815, N816, N817, N818, N999
    • PERF101, PERF102, PERF401, PERF402, PERF403P
    • PGH001, PGH002, PGH005
    • PIE790, PIE794, PIE796, PIE800, PIE804, PIE807, PIE808, PIE810
    • PLC0105, PLC0131, PLC0132, PLC0205, PLC0208, PLC0414, PLC0415P, PLC1901P, PLC2401P, PLC2403P, PLC3002
    • PLE0100, PLE0101, PLE0116, PLE0117, PLE0118, PLE0241, PLE0302, PLE0307, PLE0604, PLE0605, PLE0704P, PLE1132P, PLE1142, PLE1205, PLE1206, PLE1300, PLE1307, PLE1310, PLE1507, PLE1700, PLE2502, PLE2510, PLE2512, PLE2513, PLE2514, PLE2515
    • PLR0124, PLR0133, PLR0202P, PLR0203P, PLR0206, PLR0402, PLR1701, PLR1704P, PLR1706P, PLR1711, PLR1714, PLR1722, PLR1733P, PLR1736P, PLR2004, PLR5501, PLR6201P, PLR6301P
    • PLW0108P, PLW0120, PLW0127, PLW0129, PLW0131, PLW0406, PLW0602, PLW0603, PLW0604P, PLW0711, PLW1501P, PLW1508, PLW1509, PLW1510, PLW1514P, PLW1641P, PLW2101P, PLW2901, PLW3201P, PLW3301
    • PT001, PT002, PT003, PT006, PT007, PT008, PT009, PT010, PT011, PT012, PT013, PT014, PT015, PT016, PT017, PT018, PT019, PT020, PT021, PT022, PT023, PT024, PT025, PT026, PT027
    • PYI001, PYI002, PYI003, PYI004, PYI005, PYI006, PYI007, PYI008, PYI009, PYI010, PYI011, PYI012, PYI013, PYI014, PYI015, PYI016, PYI017, PYI018, PYI019, PYI020, PYI021, PYI024, PYI025, PYI026, PYI029, PYI030, PYI032, PYI033, PYI034, PYI035, PYI036, PYI041, PYI042, PYI043, PYI044, PYI045, PYI046, PYI047, PYI048, PYI049, PYI050, PYI051, PYI052, PYI053, PYI054, PYI055, PYI056
    • RET503, RET504, RET505, RET506, RET507, RET508
    • RSE102
    • RUF001, RUF002, RUF003, RUF005, RUF006, RUF007, RUF008, RUF009, RUF010, RUF011, RUF012, RUF013, RUF015, RUF016, RUF017P, RUF018P, RUF019P, RUF100, RUF200
    • S101, S102, S103, S104, S105, S106, S107, S108, S110, S112, S113, S201P, S202P, S301, S302, S303, S304, S305, S306, S307, S308, S310, S311, S312, S313, S314, S315, S316, S317, S318, S319, S320, S321, S323, S324, S501, S505P, S506, S507P, S508, S509, S601, S602, S604, S605, S606, S607, S608, S609, S611P, S612, S701, S702P
    • SIM101, SIM102, SIM103, SIM105, SIM107, SIM108, SIM109, SIM110, SIM112, SIM114, SIM115, SIM116, SIM117, SIM118, SIM201, SIM202, SIM208, SIM210, SIM211, SIM212, SIM220, SIM221, SIM222, SIM223, SIM300, SIM910
    • SLF001
    • SLOT000, SLOT001, SLOT002
    • T100, T201, T203
    • TCH001, TCH002, TCH003, TCH004, TCH005
    • TD004, TD005, TD006, TD007
    • TID251, TID252, TID253
    • TRIO100P, TRIO105P, TRIO109P, TRIO110P, TRIO115P
    • TRY002, TRY003, TRY004, TRY200, TRY201, TRY300, TRY301, TRY302, TRY400, TRY401
    • UP001, UP003, UP004, UP005, UP006, UP007, UP008, UP009, UP010, UP011, UP012, UP013, UP014, UP015, UP017, UP018, UP019, UP020, UP021, UP022, UP023, UP024, UP025, UP026, UP027, UP028, UP029, UP030, UP031, UP032, UP033, UP034, UP035, UP036, UP037, UP038, UP039, UP040, UP041P
    • W291, W292, W293, W505, W605
    • YTT101, YTT102, YTT103, YTT201, YTT202, YTT203, YTT204, YTT301, YTT302, YTT303
    "},{"location":"config/environment/advanced/","title":"Advanced environment configuration","text":""},{"location":"config/environment/advanced/#context-formatting","title":"Context formatting","text":"

    All environments support the following extra context formatting fields:

    Field Description env_name The name of the environment env_type The type of environment matrix Its modifier selects the value of that matrix variable. If the environment is not part of a matrix or was not generated with the variable, you must specify a default value as an additional modifier e.g. {matrix:version:v1.0.0}. verbosity The integer verbosity value of Hatch. A flag modifier is supported that will render the value as a CLI flag e.g. -2 becomes -qq, 1 becomes -v, and 0 becomes an empty string. An additional flag integer modifier may be used to adjust the verbosity level. For example, if you wanted to make a command quiet by default, you could use {verbosity:flag:-1} within the command. args For executed commands only, any extra command line arguments with an optional default modifier if none were provided"},{"location":"config/environment/advanced/#matrix","title":"Matrix","text":"

    Environments can define a series of matrices with the matrix option:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
    [envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n

    Doing so will result in the product of each variable combination being its own environment.

    "},{"location":"config/environment/advanced/#naming","title":"Naming","text":"

    The name of the generated environments will be the variable values of each combination separated by hyphens, altogether prefixed by <ENV_NAME>.. For example, the following configuration:

    pyproject.toml hatch.toml
    [[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
    [[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n

    would indicate the following unique environments:

    test.42-foo\ntest.42-bar\n

    The exceptions to this format are described below.

    "},{"location":"config/environment/advanced/#python-variables","title":"Python variables","text":"

    If the variables py or python are specified, then they will rank first in the product result and will be prefixed by py if the value is not. For example, the following configuration:

    pyproject.toml hatch.toml
    [[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n
    [[envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n

    would generate the following environments:

    test.py3.9-42\ntest.pypy3-42\n

    Note

    The value of this variable sets the Python version.

    "},{"location":"config/environment/advanced/#name-formatting","title":"Name formatting","text":"

    You can set the matrix-name-format option to modify how each variable part is formatted which recognizes the placeholders {variable} and {value}. For example, the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
    [envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n

    would produce the following environments:

    test.version_42-feature_foo\ntest.version_42-feature_bar\n

    By default this option is set to {value}.

    "},{"location":"config/environment/advanced/#default-environment","title":"Default environment","text":"

    If the default environment defines matrices, then the generated names will not be prefixed by the environment name. This can be useful for projects that only need a single series of matrices without any standalone environments.

    "},{"location":"config/environment/advanced/#selection","title":"Selection","text":"

    Rather than selecting a single generated environment, you can select the root environment to target all of them. For example, if you have the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[tool.hatch.envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n
    [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n

    you could then run your tests consecutively in all 4 environments with:

    hatch run test:cov\n
    "},{"location":"config/environment/advanced/#option-overrides","title":"Option overrides","text":"

    You can modify options based on the conditions of different sources like matrix variables with the overrides table, using dotted key syntax for each declaration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n
    [envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n

    The type of the selected option determines the types of values.

    "},{"location":"config/environment/advanced/#platform-overrides","title":"Platform overrides","text":"

    Options can be modified based on the current platform using the platform source.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nplatform.windows.scripts = [\n  'run=pytest -m \"not io_uring\"',\n]\n
    [envs.test.overrides]\nplatform.windows.scripts = [\n  'run=pytest -m \"not io_uring\"',\n]\n

    The following platforms are supported:

    • linux
    • windows
    • macos
    "},{"location":"config/environment/advanced/#environment-variable-overrides","title":"Environment variable overrides","text":"

    Environment variables can modify options using the env source.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
    [envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
    "},{"location":"config/environment/advanced/#matrix-variable-overrides","title":"Matrix variable overrides","text":"

    The matrix variables used to generate each environment can be used to modify options within using the matrix source.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n  { value = \"oauth\", if = [\"oauth2\"] },\n  { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
    [envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n  { value = \"oauth\", if = [\"oauth2\"] },\n  { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
    "},{"location":"config/environment/advanced/#name-overrides","title":"Name overrides","text":"

    When a matrix is defined, the name source can be used for regular expression matching on the generated name, minus the prefix for non-default environments.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
    [envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
    "},{"location":"config/environment/advanced/#types","title":"Types","text":"
    • Literal types like strings for the Python version or booleans for skipping installation can be set using the value itself, an inline table, or an array. For example:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n  { value = false, if = [\"...\"] },\n  true,\n]\n
      [envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n  { value = false, if = [\"...\"] },\n  true,\n]\n

      For arrays, the first allowed value will be used.

    • Array types like dependencies or commands can be appended to using an array of strings or inline tables. For example:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.foo.dependencies = [\n  \"httpx\",\n  { value = \"cryptography\" },\n]\n
      [envs.test.overrides]\nmatrix.foo.dependencies = [\n  \"httpx\",\n  { value = \"cryptography\" },\n]\n
    • Mapping types like environment variables or scripts can have keys set using a string, or an array of strings or inline tables. For example:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n  \"KEY1=VALUE1\",\n  { key = \"KEY2\", value = \"VALUE2\" },\n]\n
      [envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n  \"KEY1=VALUE1\",\n  { key = \"KEY2\", value = \"VALUE2\" },\n]\n

      If the value is missing (no = for strings, no value key for inline tables), then the value will be set to the value of the source condition.

    "},{"location":"config/environment/advanced/#overwriting","title":"Overwriting","text":"

    Rather than supplementing the values within mapping types or array types, you can overwrite the option as a whole by prefixing the name with set-:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n
    [envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n

    When overwriting entire options or keys within mappings, override sources are applied in the following order:

    1. platform
    2. environment variables
    3. matrix variables
    4. names
    "},{"location":"config/environment/advanced/#conditions","title":"Conditions","text":"

    You may specify certain extra keys for any inline table that will determine whether or not to apply that entry. These modifiers may be combined with others and any negative evaluation will immediately cause the entry to be skipped.

    "},{"location":"config/environment/advanced/#allowed-values","title":"Allowed values","text":"

    The if key represents the allowed values for that condition. If the value of the condition is not listed, then that entry will not be applied:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    [envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    "},{"location":"config/environment/advanced/#specific-platforms","title":"Specific platforms","text":"

    The platform key represents the desired platforms. If the current platform is not listed, then that entry will not be applied:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    [envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    "},{"location":"config/environment/advanced/#required-environment-variables","title":"Required environment variables","text":"

    The env key represents the required environment variables. If any of the listed environment variables are not set or the defined value does not match, then that entry will not be applied:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    [envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    "},{"location":"config/environment/overview/","title":"Environment configuration","text":"

    All environments are defined as sections within the tool.hatch.envs table.

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\n
    [envs.<ENV_NAME>]\n

    The storage location for environments is completely configurable.

    Unless an environment is explicitly selected on the command line, the default environment will be used. The type of this environment defaults to virtual.

    Info

    Environments prefixed by hatch- are used for special purposes e.g. static analysis.

    "},{"location":"config/environment/overview/#inheritance","title":"Inheritance","text":"

    All environments inherit from the environment defined by its template option, which defaults to default.

    So for the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[tool.hatch.envs.bar]\ntemplate = \"foo\"\nskip-install = false\n
    [envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[envs.bar]\ntemplate = \"foo\"\nskip-install = false\n

    the environment bar will be of type baz with skip-install set to false.

    Note

    Environments do not inherit matrices.

    "},{"location":"config/environment/overview/#self-referential-environments","title":"Self-referential environments","text":"

    You can disable inheritance by setting template to the environment's own name:

    pyproject.toml hatch.toml
    [tool.hatch.envs.foo]\ntemplate = \"foo\"\n
    [envs.foo]\ntemplate = \"foo\"\n
    "},{"location":"config/environment/overview/#detached-environments","title":"Detached environments","text":"

    A common use case is standalone environments that do not require inheritance nor the installation of the project, such as for linting or sometimes building documentation. Enabling the detached option will make the environment self-referential and will skip project installation:

    pyproject.toml hatch.toml
    [tool.hatch.envs.lint]\ndetached = true\n
    [envs.lint]\ndetached = true\n
    "},{"location":"config/environment/overview/#dependencies","title":"Dependencies","text":"

    You can install dependencies in addition to the ones defined by your project's metadata. Entries support context formatting.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n
    [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n

    If you define environments with dependencies that only slightly differ from their inherited environments, you can use the extra-dependencies option to avoid redeclaring the dependencies option:

    pyproject.toml hatch.toml
    [tool.hatch.envs.default]\ndependencies = [\n  \"foo\",\n  \"bar\",\n]\n\n[tool.hatch.envs.experimental]\nextra-dependencies = [\n  \"baz\",\n]\n
    [envs.default]\ndependencies = [\n  \"foo\",\n  \"bar\",\n]\n\n[envs.experimental]\nextra-dependencies = [\n  \"baz\",\n]\n

    Tip

    Hatch uses pip to install dependencies so any configuration it supports Hatch does as well. For example, if you wanted to only use a private repository you could set the PIP_INDEX_URL environment variable.

    "},{"location":"config/environment/overview/#installation","title":"Installation","text":""},{"location":"config/environment/overview/#features","title":"Features (extras)","text":"

    If your project defines optional dependencies, you can select which groups to install using the features option:

    pyproject.toml hatch.toml
    [tool.hatch.envs.nightly]\nfeatures = [\n  \"server\",\n  \"grpc\",\n]\n
    [envs.nightly]\nfeatures = [\n  \"server\",\n  \"grpc\",\n]\n

    Note

    Features/optional dependencies are also known as extras in other tools.

    "},{"location":"config/environment/overview/#dev-mode","title":"Dev mode","text":"

    By default, environments will always reflect the current state of your project on disk. Set dev-mode to false to disable this behavior:

    pyproject.toml hatch.toml
    [tool.hatch.envs.static]\ndev-mode = false\n
    [envs.static]\ndev-mode = false\n
    "},{"location":"config/environment/overview/#skip-install","title":"Skip install","text":"

    By default, environments will install your project during creation. To ignore this step, set skip-install to true:

    pyproject.toml hatch.toml
    [tool.hatch.envs.lint]\nskip-install = true\n
    [envs.lint]\nskip-install = true\n
    "},{"location":"config/environment/overview/#environment-variables","title":"Environment variables","text":""},{"location":"config/environment/overview/#defined","title":"Defined","text":"

    You can define environment variables with the env-vars option:

    pyproject.toml hatch.toml
    [tool.hatch.envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[tool.hatch.envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
    [envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n

    Values support context formatting.

    "},{"location":"config/environment/overview/#filters","title":"Filters","text":"

    By default, environments will have access to all environment variables. You can filter with wildcard patterns using the env-include/env-exclude options:

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nenv-include = [\n  \"FOO*\",\n]\nenv-exclude = [\n  \"BAR\",\n]\n
    [envs.<ENV_NAME>]\nenv-include = [\n  \"FOO*\",\n]\nenv-exclude = [\n  \"BAR\",\n]\n

    Exclusion patterns take precedence but will never affect defined environment variables.

    "},{"location":"config/environment/overview/#scripts","title":"Scripts","text":"

    You can define named scripts that may be executed or referenced at the beginning of other scripts. Context formatting is supported.

    For example, in the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n[tool.hatch.envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n
    [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n[envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n

    the run script would be expanded to:

    pytest --cov-config=pyproject.toml --cov=pkg --cov=tests --no-cov\n

    Scripts can also be defined as an array of strings.

    pyproject.toml hatch.toml
    [tool.hatch.envs.style]\ndetached = true\ndependencies = [\n  \"flake8\",\n  \"black\",\n  \"isort\",\n]\n[tool.hatch.envs.style.scripts]\ncheck = [\n  \"flake8 .\",\n  \"black --check --diff .\",\n  \"isort --check-only --diff .\",\n]\nfmt = [\n  \"isort .\",\n  \"black .\",\n  \"check\",\n]\n
    [envs.style]\ndetached = true\ndependencies = [\n  \"flake8\",\n  \"black\",\n  \"isort\",\n]\n[envs.style.scripts]\ncheck = [\n  \"flake8 .\",\n  \"black --check --diff .\",\n  \"isort --check-only --diff .\",\n]\nfmt = [\n  \"isort .\",\n  \"black .\",\n  \"check\",\n]\n

    Similar to make, you can ignore the exit code of commands that start with - (a hyphen). For example, the script error defined by the following configuration would halt after the second command with 3 as the exit code:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.scripts]\nerror = [\n  \"- exit 1\",\n  \"exit 3\",\n  \"exit 0\",\n]\n
    [envs.test.scripts]\nerror = [\n  \"- exit 1\",\n  \"exit 3\",\n  \"exit 0\",\n]\n

    Tip

    Individual scripts inherit from parent environments just like options.

    "},{"location":"config/environment/overview/#commands","title":"Commands","text":"

    All commands are able to use any defined scripts. Also like scripts, context formatting is supported and the exit code of commands that start with a hyphen will be ignored.

    "},{"location":"config/environment/overview/#pre-install","title":"Pre-install","text":"

    You can run commands immediately before environments install your project.

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\npre-install-commands = [\n  \"...\",\n]\n
    [envs.<ENV_NAME>]\npre-install-commands = [\n  \"...\",\n]\n
    "},{"location":"config/environment/overview/#post-install","title":"Post-install","text":"

    You can run commands immediately after environments install your project.

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\npost-install-commands = [\n  \"...\",\n]\n
    [envs.<ENV_NAME>]\npost-install-commands = [\n  \"...\",\n]\n
    "},{"location":"config/environment/overview/#python-version","title":"Python version","text":"

    The python option specifies which version of Python to use, or an absolute path to a Python interpreter:

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\npython = \"3.10\"\n
    [envs.<ENV_NAME>]\npython = \"3.10\"\n

    All environment types should respect this option.

    "},{"location":"config/environment/overview/#supported-platforms","title":"Supported platforms","text":"

    The platforms option indicates the operating systems with which the environment is compatible:

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n
    [envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n

    The following platforms are supported:

    • linux
    • windows
    • macos

    If unspecified, the environment is assumed to be compatible with all platforms.

    "},{"location":"config/environment/overview/#description","title":"Description","text":"

    The description option is purely informational and is displayed in the output of the env show command:

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
    [envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
    "},{"location":"config/environment/overview/#type","title":"Type","text":"

    An environment's type determines which environment plugin will be used for management. The only built-in environment type is virtual, which uses virtual Python environments.

    "},{"location":"history/hatch/","title":"Hatch history","text":"

    All notable changes to Hatch will be documented in this file.

    The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

    "},{"location":"history/hatch/#unreleased","title":"Unreleased","text":""},{"location":"history/hatch/#hatch-v1.9.4","title":"1.9.4 - 2024-03-12","text":"

    Fixed:

    • Limit the maximum version of Hatchling in anticipation of backward incompatible changes
    "},{"location":"history/hatch/#hatch-v1.9.3","title":"1.9.3 - 2024-01-25","text":"

    Fixed:

    • Fix loading of local plugins to account for newly released versions of a dependency
    "},{"location":"history/hatch/#hatch-v1.9.2","title":"1.9.2 - 2024-01-21","text":"

    Fixed:

    • Fix the default token variable name for publishing to PyPI
    "},{"location":"history/hatch/#hatch-v1.9.1","title":"1.9.1 - 2023-12-25","text":"

    Fixed:

    • Ensure that the dependency_hash method of the environment interface is called after sync_dependencies for cases where the hash is only known at that point, such as for dependency lockers
    • Only acknowledge the HATCH_PYTHON_VARIANT_* environment variables for Python resolution for supported platforms and architectures
    • Fix Python resolution when there are metadata hooks with unsatisfied dependencies
    "},{"location":"history/hatch/#hatch-v1.9.0","title":"1.9.0 - 2023-12-19","text":"

    Changed:

    • Environments prefixed by hatch- are now considered internal and used for special purposes such as configuration for static analysis

    Added:

    • Enable docstring formatting by default for static analysis
    • Allow for overriding config of internal environments
    • Concretely state the expected API contract for the environment interface methods find and check_compatibility
    • Upgrade Ruff to 0.1.8
    • Bump the minimum supported version of Hatchling to 1.21.0

    Fixed:

    • Ignore a project's Python requirement for environments where the project is not installed
    • When not persisting config for static analysis, properly manage internal settings when Ruff's top level table already exists
    • Ignore compatibility checks when environments have already been created, significantly improving performance of environment usage
    • Properly allow overriding of the path option for the virtual environment type
    • Fix nushell activation on non-Windows systems
    "},{"location":"history/hatch/#hatch-v1.8.1","title":"1.8.1 - 2023-12-14","text":"

    Fixed:

    • Fix regression in calling subprocesses with updated PATH
    • Fix automatic installation of environment plugins when running as a standalone binary
    • Change default location of Python installations
    "},{"location":"history/hatch/#hatch-v1.8.0","title":"1.8.0 - 2023-12-11","text":"

    Changed:

    • Drop support for Python 3.7
    • The get_build_process method of the environment interface has been removed; plugins should use the new run_builder method instead
    • Remove pyperclip dependency and the --copy flag of the config find command
    • When running the build command all output from builders is now displayed as-is in real time without the stripping of ANSI codes
    • Version information (for Hatch itself) is now derived from Git

    Added:

    • Support Python 3.12
    • Add installers and standalone binaries
    • Add the ability to manage Python installations
    • Add fmt command
    • The virtual environment type can now automatically download requested versions of Python that are not installed
    • Add dependency_hash method to the environment interface
    • The state of installed dependencies for environments is saved as metadata so if dependency definitions have not changed then no checking is performed, which can be computationally expensive
    • The build command now supports backends other than Hatchling
    • Allow the use of features for environments when skip-install is enabled
    • The default is now __token__ when prompting for a username for the publish command
    • Add a new run_builder method to the environment interface
    • Bump the minimum supported version of Hatchling to 1.19.0
    • Bump the minimum supported version of click to 8.0.6

    Fixed:

    • Fix nushell activation
    • Better handling of flat storage directory hierarchies for the virtual environment type
    • Display useful information when running the version command outside of a project rather than erroring
    • Fix the project metadata command by only capturing stdout from the backend
    • Properly support Google Artifact Registry
    • Fix parsing dependencies for environments when warnings are emitted
    "},{"location":"history/hatch/#hatch-v1.7.0","title":"1.7.0 - 2023-04-03","text":"

    Changed:

    • The src-layout project template option is now enabled by default
    • Non-critical output now goes to stderr

    Added:

    • Add tool.hatch.env.requires configuration to automatically install dependencies for environment and environment collector plugins
    • Add custom environment collector
    • Improve syncing of dependencies provided through Git direct references
    • Add isolated_data_directory attribute to the environment interface
    • Increase the timeout for and add retries to the index publisher
    • Expand home and environment variables in configured cache and data directories
    • Improve readability of exceptions
    • Update project templates
    • Bump the minimum supported version of Hatchling to 1.14.0

    Fixed:

    • Fix displaying the version with the version command when the version is static and build dependencies are unmet
    • Fix build environments for the virtual environment type when storing within a relative path
    • Work around System Integrity Protection on macOS when running commands
    • Allow setuptools metadata migration for projects without setup.py if setup.cfg is present
    • Handle additional edge cases for setuptools metadata migration
    • Support boolean values for the config set command
    "},{"location":"history/hatch/#hatch-v1.6.3","title":"1.6.3 - 2022-10-24","text":"

    Fixed:

    • Fix version command when the version is dynamic and build dependencies are unmet
    "},{"location":"history/hatch/#hatch-v1.6.2","title":"1.6.2 - 2022-10-20","text":"

    Fixed:

    • Fix getting dynamic metadata from hooks for environments when dependencies are not dynamic
    "},{"location":"history/hatch/#hatch-v1.6.1","title":"1.6.1 - 2022-10-16","text":"

    Fixed:

    • Computing the path to the user's home directory now gracefully falls back to ~ when it cannot be determined
    "},{"location":"history/hatch/#hatch-v1.6.0","title":"1.6.0 - 2022-10-08","text":"

    Changed:

    • The run_shell_command environment interface method now accepts arbitrary subprocess.Popen keyword arguments. This is not strictly breaking, but will be utilized in upcoming features.
    • The internal directory structure for storing virtual environments is now more nested. This is not breaking, but any local environments will be created anew.

    Added:

    • Add project command group to view details about the project like PEP 621 metadata
    • Better support for auto-detection of environments by tools like Visual Studio Code now that the storage directory of virtual environments will be flat if Hatch's configured virtual environment directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
    • Build environments for the virtual environment type are now cached for improved performance
    • Add build_environment_exists method to the environment interface for implementations that cache the build environment
    • Add path option to the virtual environment type
    • Add --initialize-auth flag to the index publisher to allow for the saving of authentication information before publishing
    • Support Bash on Windows for the shell command
    • The setuptools migration script no longer modifies the formatting of existing pyproject.toml configuration
    • Bump the minimum supported version of Hatchling to 1.11.0

    Fixed:

    • Environments now respect dynamically defined project dependencies
    • The dep hash and all dep show commands now respect dynamically defined project dependencies
    • The env show, dep hash, and all dep show commands now honor context formatting
    • Fix matrix variable inclusion filtering of the run and env run commands when there are multiple possible variables
    • Build environment compatibility is now checked before use
    • Decreasing verbosity now has no affect on output that should always be displayed
    • Handle more edge cases in the setuptools migration script
    • Environments now respect user defined environment variables for context formatting
    • Update the scripts in the generated test environment template for new projects to reflect the documentation
    • Allow extra-dependencies in environment overrides
    • Depend on packaging explicitly rather than relying on it being a transitive dependency of Hatchling
    "},{"location":"history/hatch/#hatch-v1.5.0","title":"1.5.0 - 2022-08-28","text":"

    Added:

    • The index publisher now recognizes repository-specific options
    • Add the --ignore-compat flag to the env run command
    • Setting the HATCH_PYTHON environment variable to self will now force the use of the Python executable Hatch is running on for virtual environment creation

    Fixed:

    • Fix the --force-continue flag of the env run command
    • Handle more edge cases in the setuptools migration script
    "},{"location":"history/hatch/#hatch-v1.4.2","title":"1.4.2 - 2022-08-16","text":"

    Fixed:

    • Fix check for updating static versions with the version command when metadata hooks are in use
    "},{"location":"history/hatch/#hatch-v1.4.1","title":"1.4.1 - 2022-08-13","text":"

    Fixed:

    • Fix non-detached inheritance disabling for environments
    "},{"location":"history/hatch/#hatch-v1.4.0","title":"1.4.0 - 2022-08-06","text":"

    Added:

    • The default Python for virtual environments now checks PATH before using the one Hatch is running on
    • Values for environment env-vars now support context formatting
    • Add name override for environments to allow for regular expression matching
    • The index publisher now better supports non-PyPI indices
    • Add certificate options to the index publisher
    • Display waiting text when checking dependencies and removing environments
    • Display help text the first time the shell command is executed
    • Update project templates with Python 3.11 and the latest versions of various GitHub Actions
    • Add support for Almquist (ash) shells
    • Add hyperlink as a dependency for better handling of package index URLs
    • Bump the minimum supported version of virtualenv to 20.16.2
    • Bump the minimum supported version of tomlkit to 0.11.1

    Fixed:

    • Acknowledge extra-dependencies for the env show command
    • Fix locating executables within virtual environments on Debian
    • Fix managing the terminal size inside the shell command
    • Fix default code coverage file omission for the src-layout project template option
    "},{"location":"history/hatch/#hatch-v1.3.1","title":"1.3.1 - 2022-07-11","text":"

    Fixed:

    • Support -h/--help flag for the run command
    "},{"location":"history/hatch/#hatch-v1.3.0","title":"1.3.0 - 2022-07-10","text":"

    Changed:

    • Rename the default publishing plugin from pypi to the more generic index

    Added:

    • Support the absence of pyproject.toml files, as is the case for apps and non-Python projects
    • Hide scripts that start with an underscore for the env show command by default
    • Ignoring the exit codes of commands by prefixing with hyphens now works with entire named scripts
    • Add a way to require confirmation for publishing
    • Add --force-continue flag to the env run command
    • Make tracebacks colorful and less verbose
    • When shell configuration has not been defined, attempt to use the current shell based on parent processes before resorting to the defaults
    • The shell name pwsh is now an alias for powershell
    • Remove atomicwrites dependency
    • Relax constraint on userpath dependency
    • Bump the minimum supported version of Hatchling to 1.4.1

    Fixed:

    • Keep environments in sync with the dependencies of the selected features
    • Use utf-8 for all files generated for new projects
    • Escape special characters Git may return in the user name when writing generated files for new projects
    • Normalize the package name to lowercase in setuptools migration script
    • Fix parsing of source distributions during publishing
    "},{"location":"history/hatch/#hatch-v1.2.1","title":"1.2.1 - 2022-05-30","text":"

    Fixed:

    • Fix handling of top level data_files in setuptools migration script
    "},{"location":"history/hatch/#hatch-v1.2.0","title":"1.2.0 - 2022-05-22","text":"

    Changed:

    • The enter_shell environment plugin method now accepts an additional args parameter

    Added:

    • Allow context string formatting for environment dependencies
    • Add environment context string formatting fields env_name, env_type, matrix, verbosity, and args
    • Support overriding the default arguments used to spawn shells on non-Windows systems
    • Bump the minimum supported version of Hatchling to 1.3.0

    Fixed:

    • Improve setuptools migration script
    "},{"location":"history/hatch/#hatch-v1.1.2","title":"1.1.2 - 2022-05-20","text":"

    Fixed:

    • Bump the minimum supported version of Hatchling to 1.2.0
    • Update project metadata to reflect support for Python 3.11
    "},{"location":"history/hatch/#hatch-v1.1.1","title":"1.1.1 - 2022-05-12","text":"

    Fixed:

    • Fix setuptools migration script for non-Windows systems
    "},{"location":"history/hatch/#hatch-v1.1.0","title":"1.1.0 - 2022-05-12","text":"

    Changed:

    • In order to simplify the implementation of command execution for environment plugins, the run_shell_commands method has been replaced by the singular run_shell_command. A new command_context method has been added to more easily satisfy complex use cases.
    • The finalize_command environment plugin method has been removed in favor of the newly introduced context formatting functionality.

    Added:

    • Add context formatting functionality i.e. the ability to insert values into configuration like environment variables and command line arguments
    • Any verbosity for command execution will now always display headers, even for single environments
    • Every executed command is now displayed when running multiple commands or when verbosity is enabled
    • Similar to make, ignore the exit code of executed commands that start with - (a hyphen)
    • Add ability for the --init flag of the new command to automatically migrate setuptools configuration
    • Update project metadata to reflect the adoption by PyPA and production stability
    "},{"location":"history/hatch/#hatch-v1.0.0","title":"1.0.0 - 2022-04-28","text":"

    This is the first stable release of Hatch v1, a complete rewrite. Enjoy!

    "},{"location":"history/hatchling/","title":"Hatchling history","text":"

    All notable changes to Hatchling will be documented in this file.

    The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

    "},{"location":"history/hatchling/#unreleased","title":"Unreleased","text":""},{"location":"history/hatchling/#hatchling-v1.21.0","title":"1.21.0 - 2023-12-18","text":"

    Added:

    • Add parent context modifier for path fields
    "},{"location":"history/hatchling/#hatchling-v1.20.0","title":"1.20.0 - 2023-12-13","text":"

    Added:

    • Add bypass-selection option to the wheel build target to allow for empty (metadata-only) wheels

    Fixed:

    • Fix regression in 1.19.1 that allowed exclude to count toward inclusion selection, thus bypassing the default inclusion selection heuristics
    • Fix writing optional dependency core metadata in situations where there are multiple environment markers
    "},{"location":"history/hatchling/#hatchling-v1.19.1","title":"1.19.1 - 2023-12-12","text":"

    Fixed:

    • Add better error message when the wheel build target cannot determine what to ship
    • Consider forced inclusion patterns and build-time artifacts as file selection since some build hooks generate the entire wheel contents without user configuration
    "},{"location":"history/hatchling/#hatchling-v1.19.0","title":"1.19.0 - 2023-12-11","text":"

    Changed:

    • An error will now be raised if a force-included path does not exist
    • An error will now be raised for the wheel build target if no file selection options are defined

    Added:

    • Officially support Python 3.12
    • Allow using an empty string for the sources option to add a prefix to distribution paths

    Fixed:

    • Properly handle non-zero version epoch for the standard version scheme
    • Fix the wheel build target for case insensitive file systems when the project metadata name does not match the directory name on disk
    • The app build target no longer has suppressed output
    • Prevent duplicate paths when projects require the sources option while build hooks overwrite included paths
    • Properly escape spaces for URI context formatting
    "},{"location":"history/hatchling/#hatchling-v1.18.0","title":"1.18.0 - 2023-06-12","text":"

    Changed:

    • Drop support for Python 3.7

    Added:

    • Update the list of directories that are always excluded for builds
    "},{"location":"history/hatchling/#hatchling-v1.17.1","title":"1.17.1 - 2023-06-03","text":"

    Fixed:

    • Fix dev mode when the project has symlinks and file inclusion is defined with the packages or only-include options
    • Change the name of generated PTH files for dev mode so they come first lexicographically and therefore load first
    "},{"location":"history/hatchling/#hatchling-v1.17.0","title":"1.17.0 - 2023-05-12","text":"

    Added:

    • The app build target now embeds the project version in the name of binaries
    "},{"location":"history/hatchling/#hatchling-v1.16.1","title":"1.16.1 - 2023-05-11","text":"

    Fixed:

    • Fix determining the built executable path for the app build target option when using a local copy of PyApp when there is an explicit target triple set
    "},{"location":"history/hatchling/#hatchling-v1.16.0","title":"1.16.0 - 2023-05-11","text":"

    Added:

    • Add app build target option to build using a local copy of the PyApp repository
    "},{"location":"history/hatchling/#hatchling-v1.15.0","title":"1.15.0 - 2023-05-09","text":"

    Added:

    • Add app build target
    "},{"location":"history/hatchling/#hatchling-v1.14.1","title":"1.14.1 - 2023-04-23","text":"

    Fixed:

    • Fix internal archive root naming for the sdist target when strict-naming is disabled to match the file name in order to support the expectation of some frontends
    "},{"location":"history/hatchling/#hatchling-v1.14.0","title":"1.14.0 - 2023-04-02","text":"

    Added:

    • Add trove-classifiers as a dependency

    Fixed:

    • Properly normalize metadata descriptions that contain line breaks
    "},{"location":"history/hatchling/#hatchling-v1.13.0","title":"1.13.0 - 2023-02-09","text":"

    Added:

    • Update the set of known trove classifiers to version 2023.2.8
    "},{"location":"history/hatchling/#hatchling-v1.12.2","title":"1.12.2 - 2023-01-05","text":"

    Fixed:

    • Add macos-max-compat option to the wheel target that is enabled by default to support the latest version 22.0 of the packaging library
    "},{"location":"history/hatchling/#hatchling-v1.12.1","title":"1.12.1 - 2022-12-31","text":"

    Fixed:

    • Fix minor regression in the PEP 517/660 function signatures that was discovered by Fedora
    "},{"location":"history/hatchling/#hatchling-v1.12.0","title":"1.12.0 - 2022-12-30","text":"

    Added:

    • Improve readability of exceptions
    • Add extra_metadata build data to the wheel target
    • Retroactively support License-Expression core metadata starting at version 2.1
    • Add more type hints
    • Update the set of known trove classifiers to version 2022.12.22
    • Update SPDX license information to version 3.19
    • Store Hatchling's metadata in pyproject.toml

    Fixed:

    • Acknowledge the ARCHFLAGS environment variable on macOS for the wheel target when build hooks set the infer_tag build data to true
    • Fix dependency checking when encountering broken distributions
    • Fix the support-legacy option for the sdist target when using a src-layout project structure
    • Remove unnecessary encoding declaration in the default template for the version build hook
    "},{"location":"history/hatchling/#hatchling-v1.11.1","title":"1.11.1 - 2022-10-19","text":"

    Fixed:

    • Fix default file selection behavior of the wheel target when there is a single top-level module
    "},{"location":"history/hatchling/#hatchling-v1.11.0","title":"1.11.0 - 2022-10-08","text":"

    Added:

    • Add env version source to retrieve the version from an environment variable
    • Add validate-bump option to the standard version scheme

    Fixed:

    • Use proper CSV formatting for the RECORD metadata file of the wheel target to avoid warnings during installation by pip if, for example, file names contain commas
    • Fix installations with pip for build hooks that modify runtime dependencies
    • Decreasing verbosity now has no affect on output that should always be displayed
    "},{"location":"history/hatchling/#hatchling-v1.10.0","title":"1.10.0 - 2022-09-18","text":"

    Added:

    • Add the following to the list of directories that cannot be traversed: __pypackages__, .hg, .hatch, .tox, .nox
    • Add deprecated option to allow ambiguous features

    Fixed:

    • Improve tracking of dynamic metadata
    • Fix core metadata for entries in project.optional-dependencies that use direct references
    "},{"location":"history/hatchling/#hatchling-v1.9.0","title":"1.9.0 - 2022-09-09","text":"

    Changed:

    • File pattern matching now more closely resembles Git's behavior

    Added:

    • Implement a minimal version of prepare_metadata_for_build_wheel and prepare_metadata_for_build_editable for non-frontend tools that only need to inspect a project's metadata
    • Add metadata command to view PEP 621 project metadata
    • Improve error messages for SPDX license errors
    • Retroactively support License-File for core metadata starting at version 2.1
    • Bump the minimum supported version of pathspec to 0.10.1

    Fixed:

    • Allow the valid non-SPDX license values LicenseRef-Public-Domain and LicenseRef-Proprietary
    • Show the help text of the CLI when no subcommand is selected
    "},{"location":"history/hatchling/#hatchling-v1.8.1","title":"1.8.1 - 2022-08-25","text":"

    Fixed:

    • Fix default file inclusion for wheel build targets when both the project name and package directory name are not normalized
    "},{"location":"history/hatchling/#hatchling-v1.8.0","title":"1.8.0 - 2022-08-16","text":"

    Added:

    • Add get_known_classifiers method to metadata hooks

    Fixed:

    • Fix check for updating static versions with the version command when metadata hooks are in use
    "},{"location":"history/hatchling/#hatchling-v1.7.1","title":"1.7.1 - 2022-08-13","text":"

    Fixed:

    • Fix the value of the relative_path attribute of included files, that some build plugins may use, when selecting explicit paths
    "},{"location":"history/hatchling/#hatchling-v1.7.0","title":"1.7.0 - 2022-08-12","text":"

    Added:

    • Add require-runtime-features option for builders and build hooks
    • Check for unknown trove classifiers
    • Update SPDX license information to version 3.18

    Fixed:

    • Add better error message for wheel target dev mode installations that define path rewrites with the sources option
    • Note the allow-direct-references option in the relevant error messages
    "},{"location":"history/hatchling/#hatchling-v1.6.0","title":"1.6.0 - 2022-07-23","text":"

    Changed:

    • When no build targets are specified on the command line, now default to sdist and wheel targets rather than what happens to be defined in config
    • The code version source now only supports files with known extensions
    • Global build hooks now run before target-specific build hooks to better match expected behavior

    Added:

    • The code version source now supports loading extension modules
    • Add search-paths option for the code version source

    Fixed:

    • Fix removing sources using an empty string value in the mapping
    • The strict-naming option now also applies to the metadata directory of wheel targets
    "},{"location":"history/hatchling/#hatchling-v1.5.0","title":"1.5.0 - 2022-07-11","text":"

    Added:

    • Support the final draft of PEP 639
    • Add strict-naming option for sdist and wheel targets

    Fixed:

    • Project names are now stored in sdist and wheel target core metadata exactly as defined in pyproject.toml without normalization to allow control of how PyPI displays them
    "},{"location":"history/hatchling/#hatchling-v1.4.1","title":"1.4.1 - 2022-07-04","text":"

    Fixed:

    • Fix forced inclusion of important files like licenses for sdist targets when using the explicit selection options
    • Don't sort project URL metadata so that the rendered order on PyPI can be controlled
    "},{"location":"history/hatchling/#hatchling-v1.4.0","title":"1.4.0 - 2022-07-03","text":"

    Changed:

    • The packages option uses the new only-include option to provide targeted inclusion, since that is desired most of the time. You can retain the old behavior by using the include and sources options together.

    Added:

    • Support PEP 561 type hinting
    • Add version build hook
    • Add only-include option
    • The editable version of wheel targets now respects the force-include option by default
    • The force-include option now supports path rewriting with the sources option
    • The wheel target shared-data and extra-metadata options now respect file selection options
    • The wheel target now auto-detects single module layouts
    • Improve performance by never entering directories that are guaranteed to be undesirable like __pycache__ rather than excluding individual files within
    • Update SPDX license information to version 3.17

    Fixed:

    • Don't write empty entry points file for wheel targets if there are no entry points defined
    • Allow metadata hooks to set the version in all cases
    • Prevent duplicate file entries from inclusion when using the force-include option
    "},{"location":"history/hatchling/#hatchling-v1.3.1","title":"1.3.1 - 2022-05-30","text":"

    Fixed:

    • Better populate global variables for the code version source
    "},{"location":"history/hatchling/#hatchling-v1.3.0","title":"1.3.0 - 2022-05-22","text":"

    Removed:

    • Remove unused global args context string formatting field

    Added:

    • Improve error messages for the env context string formatting field

    Fixed:

    • Fix uri context string formatting modifier on Windows
    "},{"location":"history/hatchling/#hatchling-v1.2.0","title":"1.2.0 - 2022-05-20","text":"

    Added:

    • Allow context formatting for project.dependencies and project.optional-dependencies
    "},{"location":"history/hatchling/#hatchling-v1.1.0","title":"1.1.0 - 2022-05-19","text":"

    Added:

    • Add uri and real context string formatting modifiers for file system paths
    "},{"location":"history/hatchling/#hatchling-v1.0.0","title":"1.0.0 - 2022-05-17","text":"

    Changed:

    • Drop support for Python 2

    Added:

    • Improve error messaging for invalid versions
    • Update project metadata to reflect support for Python 3.11
    "},{"location":"history/hatchling/#hatchling-v0.25.1","title":"0.25.1 - 2022-06-14","text":"

    Fixed:

    • Fix support for Windows on Python 2 by removing its support for symlinks
    "},{"location":"history/hatchling/#hatchling-v0.25.0","title":"0.25.0 - 2022-05-15","text":"

    Added:

    • Add skip-excluded-dirs build option
    • Allow build data to add additional project dependencies for wheel and sdist build targets
    • Add force_include_editable build data for the wheel build target
    • Add build_hooks build data
    • Add support for Mercurial's .hgignore files when using glob syntax
    • Update project metadata to reflect the adoption by PyPA

    Fixed:

    • Properly use underscores for the name of force_include build data
    • No longer greedily skip excluded directories by default
    "},{"location":"history/hatchling/#hatchling-v0.24.0","title":"0.24.0 - 2022-04-28","text":"

    This is the initial public release of the Hatchling build system. Support for Python 2 will be dropped in version 1.

    "},{"location":"how-to/environment/package-indices/","title":"Package indices","text":"

    Most Hatch environment types, like the default virtual, simply use pip to install dependencies. Therefore, you can use the standard environment variables that influence pip's behavior to choose where to search for packages.

    Here's an example of setting up the default environment to look at 2 private indices (using context formatting for authentication) before finally falling back to PyPI:

    pyproject.toml hatch.toml
    [tool.hatch.envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
    [envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
    "},{"location":"how-to/plugins/testing-builds/","title":"Testing builds","text":"

    For testing Hatchling plugins, you'll usually want to generate a project to execute builds as a real user would. For example, as a minimal pytest fixture:

    from pathlib import Path\n\nimport pytest\n\n\n@pytest.fixture\ndef new_project(tmp_path):\n    project_dir = tmp_path / 'my-app'\n    project_dir.mkdir()\n\n    project_file = project_dir / 'pyproject.toml'\n    project_file.write_text(\n        f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {Path.cwd().as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n        encoding='utf-8',\n    )\n    ...\n

    The issue with this is that after the first test session, the project will be forever cached by pip based on the file path. Therefore, subsequent tests runs will never use updated code.

    To invalidate the cache, copy your code to a new path for every test session:

    import shutil\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\n\nimport pytest\n\n\n@pytest.fixture(scope='session')\ndef plugin_dir():\n    with TemporaryDirectory() as d:\n        directory = Path(d, 'plugin')\n        shutil.copytree(\n            Path.cwd(), directory, ignore=shutil.ignore_patterns('.git')\n        )\n\n        yield directory.resolve()\n\n\n@pytest.fixture\ndef new_project(tmp_path, plugin_dir):\n    project_dir = tmp_path / 'my-app'\n    project_dir.mkdir()\n\n    project_file = project_dir / 'pyproject.toml'\n    project_file.write_text(\n        f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {plugin_dir.as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n        encoding='utf-8',\n    )\n    ...\n

    Note

    This example chooses to ignore copying .git for performance reasons. You may want to ignore more patterns, or copy only specific paths like this plugin does.

    "},{"location":"meta/authors/","title":"Authors","text":""},{"location":"meta/authors/#maintainers","title":"Maintainers","text":"
    • Ofek Lev
    "},{"location":"meta/authors/#contributors","title":"Contributors","text":"
    • Amjith Ramanujam
    • Arnaud Crowther
    • Chaojie
    • Chris Warrick
    • Lum\u00edr 'Frenzy' Balhar
    • Ofek Lev
    • Olga Matoula
    • Philip Blair
    • Robert Rosca
    "},{"location":"meta/faq/","title":"FAQ","text":""},{"location":"meta/faq/#interoperability","title":"Interoperability","text":"

    Q: What is the risk of lock-in?

    A: Not much! Other than the plugin system, everything uses Python's established standards by default. Project metadata is based entirely on the standard, the build system is compatible with PEP 517/PEP 660, versioning uses the scheme specified by PEP 440, dependencies are defined with PEP 508 strings, and environments use virtualenv.

    Q: Must one use all features?

    A: No, all features are optional! You can use just the build system, publish wheels and source distributions that were built by other tools, only use the environment management, etc.

    "},{"location":"meta/faq/#libraries-vs-applications","title":"Libraries vs applications","text":"

    Q: Are workflows for both libraries and applications supported?

    A: Yes, mostly! Applications can utilize environment management just like libraries, and plugins can be used to build projects in arbitrary formats or publish artifacts to arbitrary destinations.

    The only caveat is that currently there is no support for re-creating an environment given a set of dependencies in a reproducible manner. Although a standard lock file format may be far off since [PEP 665][] was rejected, resolving capabilities are coming to pip. When that is stabilized, Hatch will add locking functionality and dedicated documentation for managing applications.

    "},{"location":"meta/faq/#tool-migration","title":"Tool migration","text":"

    Q: How to migrate to Hatch?

    "},{"location":"meta/faq/#build-system","title":"Build system","text":"SetuptoolsHatch setup.py MANIFEST.in
    import os\nfrom io import open\n\nfrom setuptools import find_packages, setup\n\nabout = {}\nwith open(os.path.join('src', 'foo', '__about__.py'), 'r', 'utf-8') as f:\n    exec(f.read(), about)\n\nwith open('README.md', 'r', 'utf-8') as f:\n    readme = f.read()\n\nsetup(\n    # Metadata\n    name='foo',\n    version=about['__version__'],\n    description='...',\n    long_description=readme,\n    long_description_content_type='text/markdown',\n    author='...',\n    author_email='...',\n    project_urls={\n        'Documentation': '...',\n        'Source': '...',\n    },\n    classifiers=[\n        '...',\n    ],\n    keywords=[\n        '...',\n    ],\n    python_requires='>=3.8',\n    install_requires=[\n        '...',\n    ],\n    extras_require={\n        'feature': ['...'],\n    },\n\n    # Packaging\n    packages=find_packages(where='src'),\n    package_dir={'': 'src'},\n    package_data={\n        'foo': ['py.typed'],\n    },\n    zip_safe=False,\n    entry_points={\n        'console_scripts': [\n            'foo = foo.cli:main',\n        ],\n    },\n)\n
    graft tests\n\nglobal-exclude *.py[cod] __pycache__\n
    pyproject.toml
    [build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"foo\"\ndescription = \"...\"\nreadme = \"README.md\"\nauthors = [\n  { name = \"...\", email = \"...\" },\n]\nclassifiers = [\n  \"...\",\n]\nkeywords = [\n  \"...\",\n]\nrequires-python = \">=3.8\"\ndependencies = [\n  \"...\",\n]\ndynamic = [\"version\"]\n\n[project.urls]\nDocumentation = \"...\"\nSource = \"...\"\n\n[project.optional-dependencies]\nfeature = [\"...\"]\n\n[project.scripts]\nfoo = \"foo.cli:main\"\n\n[tool.hatch.version]\npath = \"src/foo/__about__.py\"\n\n[tool.hatch.build.targets.sdist]\ninclude = [\n  \"/src\",\n  \"/tests\",\n]\n
    "},{"location":"meta/faq/#environments","title":"Environments","text":"ToxHatch

    Invocation:

    tox\n
    tox.ini
    [tox]\nenvlist =\n    py{27,38}-{42,3.14}\n    py{38,39}-{9000}-{foo,bar}\n\n[testenv]\nusedevelop = true\ndeps =\n    coverage[toml]\n    pytest\n    pytest-cov\n    foo: cryptography\ncommands =\n    pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests {posargs}\nsetenv =\n    3.14: PRODUCT_VERSION=3.14\n    42: PRODUCT_VERSION=42\n    9000: PRODUCT_VERSION=9000\n    {foo,bar}: EXPERIMENTAL=true\n

    Invocation:

    hatch run test\n
    pyproject.toml hatch.toml
    [tool.hatch.envs.default]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[tool.hatch.envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[tool.hatch.envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.features.env-vars = \"EXPERIMENTAL=true\"\nmatrix.features.dependencies = [\n  { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
    [envs.default]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.features.env-vars = \"EXPERIMENTAL=true\"\nmatrix.features.dependencies = [\n  { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[envs.default.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
    "},{"location":"meta/faq/#fast-cli","title":"Fast CLI?","text":"

    The claim about being faster than other tools is based on timings that are always checked in CI.

    Hatch achieves this by using lazy imports, lazily performing computation manually and with functools.cached_property, using hacks like not not ... instead of bool(...), etc.

    "},{"location":"plugins/about/","title":"Plugins","text":"

    Hatch utilizes pluggy for its plugin functionality.

    "},{"location":"plugins/about/#overview","title":"Overview","text":"

    All plugins provide registration hooks that return one or more classes that inherit from a particular type interface.

    Each registration hook must be decorated by Hatch's hook marker. For example, if you wanted to create a new kind of environment you could do:

    hooks.py
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialEnvironment\n\n\n@hookimpl\ndef hatch_register_environment():\n    return SpecialEnvironment\n

    The hooks can return a single class or a list of classes.

    Every class must define an attribute called PLUGIN_NAME that users will select when they wish to use the plugin. So in the example above, the class might be defined like:

    plugin.py
    ...\nclass SpecialEnvironment(...):\n    PLUGIN_NAME = 'special'\n    ...\n
    "},{"location":"plugins/about/#project-configuration","title":"Project configuration","text":""},{"location":"plugins/about/#naming","title":"Naming","text":"

    It is recommended that plugin project names are prefixed with hatch-. For example, if you wanted to make a plugin that provides some functionality for a product named foo you might do:

    pyproject.toml
    [project]\nname = \"hatch-foo\"\n
    "},{"location":"plugins/about/#discovery","title":"Discovery","text":"

    You'll need to define your project as a Python plugin for Hatch:

    pyproject.toml
    [project.entry-points.hatch]\nfoo = \"pkg.hooks\"\n

    The name of the plugin should be the project name (excluding any hatch- prefix) and the path should represent the module that contains the registration hooks.

    "},{"location":"plugins/about/#classifier","title":"Classifier","text":"

    Add Framework :: Hatch to your project's classifiers to make it easy to search for Hatch plugins:

    pyproject.toml
    [project]\nclassifiers = [\n  ...\n  \"Framework :: Hatch\",\n  ...\n]\n
    "},{"location":"plugins/about/#types","title":"Types","text":""},{"location":"plugins/about/#hatchling","title":"Hatchling","text":"

    These are all involved in building projects and therefore any defined dependencies are automatically installed in each build environment.

    • Builder
    • Build hook
    • Metadata hook
    • Version source
    • Version scheme
    "},{"location":"plugins/about/#hatch","title":"Hatch","text":"

    These must be installed in the same environment as Hatch itself.

    • Environment
    • Environment collector
    • Publisher
    "},{"location":"plugins/utilities/","title":"Plugin utilities","text":""},{"location":"plugins/utilities/#hatchling.builders.utils.get_reproducible_timestamp","title":"hatchling.builders.utils.get_reproducible_timestamp() -> int","text":"

    Returns an int derived from the SOURCE_DATE_EPOCH environment variable; see https://reproducible-builds.org/specs/source-date-epoch/.

    The default value will always be: 1580601600

    Source code in backend/src/hatchling/builders/utils.py
    def get_reproducible_timestamp() -> int:\n    \"\"\"\n    Returns an `int` derived from the `SOURCE_DATE_EPOCH` environment variable; see\n    https://reproducible-builds.org/specs/source-date-epoch/.\n\n    The default value will always be: `1580601600`\n    \"\"\"\n    return int(os.environ.get('SOURCE_DATE_EPOCH', '1580601600'))\n
    "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig","title":"BuilderConfig","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.directory","title":"directory: str property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.ignore_vcs","title":"ignore_vcs: bool property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.reproducible","title":"reproducible: bool property","text":"

    Whether or not the target should be built in a reproducible manner, defaulting to true.

    "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dev_mode_dirs","title":"dev_mode_dirs: list[str] property","text":"

    Directories which must be added to Python's search path in dev mode.

    "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.versions","title":"versions: list[str] property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dependencies","title":"dependencies: list[str] property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_include","title":"default_include() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_exclude","title":"default_exclude() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_packages","title":"default_packages() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_only_include","title":"default_only_include() -> list","text":""},{"location":"plugins/utilities/#hatchling.bridge.app.Application","title":"Application","text":"

    The way output is displayed can be configured by users.

    Important

    Never import this directly; Hatch judiciously decides if a type of plugin requires the capabilities herein and will grant access via an attribute.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.verbosity","title":"verbosity: int property","text":"

    The verbosity level of the application, with 0 as the default.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.abort","title":"abort(message: str = '', code: int = 1, **kwargs: Any) -> None","text":"

    Terminate the program with the given return code.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_debug","title":"display_debug(message: str = '', level: int = 1, **kwargs: Any) -> None","text":"

    Meant to be used for messages that are not useful for most user experiences. The level option must be between 1 and 3 (inclusive).

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_error","title":"display_error(message: str = '', **kwargs: Any) -> None","text":"

    Meant to be used for messages indicating some unrecoverable error.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_info","title":"display_info(message: str = '', **kwargs: Any) -> None","text":"

    Meant to be used for messages conveying basic information.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_success","title":"display_success(message: str = '', **kwargs: Any) -> None","text":"

    Meant to be used for messages indicating some positive outcome.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_waiting","title":"display_waiting(message: str = '', **kwargs: Any) -> None","text":"

    Meant to be used for messages shown before potentially time consuming operations.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_warning","title":"display_warning(message: str = '', **kwargs: Any) -> None","text":"

    Meant to be used for messages conveying important information.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform","title":"Platform","text":""},{"location":"plugins/utilities/#hatch.utils.platform.Platform.default_shell","title":"default_shell: str property","text":"

    Returns the default shell of the system.

    On Windows systems first try the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.modules","title":"modules: LazilyLoadedModules property","text":"

    Accessor for lazily loading modules that either take multiple milliseconds to import (like shutil and subprocess) or are not used on all platforms (like shlex).

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.home","title":"home: Path property","text":"

    The user's home directory as a path-like object.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.name","title":"name: str property","text":"

    One of the following:

    • linux
    • windows
    • macos
    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.windows","title":"windows: bool property","text":"

    Indicates whether Hatch is running on Windows.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.macos","title":"macos: bool property","text":"

    Indicates whether Hatch is running on macOS.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.linux","title":"linux: bool property","text":"

    Indicates whether Hatch is running on neither Windows nor macOS.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.format_for_subprocess","title":"format_for_subprocess(command: str | list[str], *, shell: bool) -> str | list[str]","text":"

    Format the given command in a cross-platform manner for immediate consumption by subprocess utilities.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.run_command","title":"run_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess","text":"

    Equivalent to the standard library's subprocess.run, with the command first being properly formatted.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command","title":"check_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess","text":"

    Equivalent to run_command, but non-zero exit codes will gracefully end program execution.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command_output","title":"check_command_output(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> str","text":"

    Equivalent to the output from the process returned by capture_process, but non-zero exit codes will gracefully end program execution.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.capture_process","title":"capture_process(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> Popen","text":"

    Equivalent to the standard library's subprocess.Popen, with all output captured by stdout and the command first being properly formatted.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.exit_with_command","title":"exit_with_command(command: list[str]) -> None","text":"

    Run the given command and exit with its exit code. On non-Windows systems, this uses the standard library's os.execvp.

    "},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter","title":"EnvironmentContextFormatter","text":""},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter.formatters","title":"formatters()","text":"

    This returns a mapping of supported field names to their respective formatting functions. Each function accepts 2 arguments:

    • the value that was passed to the format call, defaulting to None
    • the modifier data, defaulting to an empty string
    "},{"location":"plugins/build-hook/custom/","title":"Custom build hook","text":"

    This is a custom class in a given Python file that inherits from the BuildHookInterface.

    "},{"location":"plugins/build-hook/custom/#configuration","title":"Configuration","text":"

    The build hook plugin name is custom.

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.custom]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.custom]\n
    [build.hooks.custom]\n[build.targets.<TARGET_NAME>.hooks.custom]\n
    "},{"location":"plugins/build-hook/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/build-hook/custom/#example","title":"Example","text":"hatch_build.py
    from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass CustomBuildHook(BuildHookInterface):\n    ...\n

    If multiple subclasses are found, you must define a function named get_build_hook that returns the desired build hook.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    "},{"location":"plugins/build-hook/reference/","title":"Build hook plugins","text":"

    A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.

    "},{"location":"plugins/build-hook/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-autorun - used to inject code into an installation that will automatically run before the first import
    • hatch-build-scripts - run arbitrary shell commands that create artifacts
    • hatch-jupyter-builder - used for packages in the Project Jupyter ecosystem
    • hatch-mypyc - compiles code with Mypyc
    • hatch-odoo - package Odoo add-ons into the appropriate namespace
    "},{"location":"plugins/build-hook/reference/#overview","title":"Overview","text":"

    Build hooks run for every selected version of build targets.

    The initialization stage occurs immediately before each build and the finalization stage occurs immediately after. Each stage has the opportunity to view or modify build data.

    "},{"location":"plugins/build-hook/reference/#build-data","title":"Build data","text":"

    Build data is a simple mapping whose contents can influence the behavior of builds. Which fields exist and are recognized depends on each build target.

    The following fields are always present and recognized by the build system itself:

    Field Type Description artifacts list[str] This is a list of extra artifact patterns and should generally only be appended to force_include dict[str, str] This is a mapping of extra forced inclusion paths, with this mapping taking precedence in case of conflicts build_hooks tuple[str, ...] This is an immutable sequence of the names of the configured build hooks and matches the order in which they run

    Attention

    While user-facing TOML options are hyphenated, build data fields should be named with underscores to allow plugins to use them as valid Python identifiers.

    "},{"location":"plugins/build-hook/reference/#notes","title":"Notes","text":"

    In some cases it may be necessary to use force_include rather than artifacts. For example, say that you want to install a lib.so directly at the root of site-packages and a project defines a package src/foo. If you create src/lib.so, there will never be a match because the directory traversal starts at src/foo rather than src. In that case you must do either:

    build_data['force_include']['src/lib.so'] = 'src/lib.so'\n

    or

    build_data['force_include']['/absolute/path/to/src/lib.so'] = 'src/lib.so'\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface","title":"BuildHookInterface","text":"

    Example usage:

    plugin.py hooks.py
    from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass SpecialBuildHook(BuildHookInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuildHook\n\n\n@hookimpl\ndef hatch_register_build_hook():\n    return SpecialBuildHook\n
    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    class BuildHookInterface(Generic[BuilderConfigBound]):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\n    class SpecialBuildHook(BuildHookInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialBuildHook\n\n\n    @hookimpl\n    def hatch_register_build_hook():\n        return SpecialBuildHook\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root: str,\n        config: dict[str, Any],\n        build_config: BuilderConfigBound,\n        metadata: ProjectMetadata,\n        directory: str,\n        target_name: str,\n        app: Application | None = None,\n    ) -> None:\n        self.__root = root\n        self.__config = config\n        self.__build_config = build_config\n        self.__metadata = metadata\n        self.__directory = directory\n        self.__target_name = target_name\n        self.__app = app\n\n    @property\n    def app(self) -> Application:\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = cast(Application, Application().get_safe_application())\n\n        return self.__app\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict[str, Any]:\n        \"\"\"\n        The cumulative hook configuration.\n\n        ```toml config-example\n        [tool.hatch.build.hooks.<PLUGIN_NAME>]\n        [tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @property\n    def metadata(self) -> ProjectMetadata:\n        # Undocumented for now\n        return self.__metadata\n\n    @property\n    def build_config(self) -> BuilderConfigBound:\n        \"\"\"\n        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        return self.__build_config\n\n    @property\n    def directory(self) -> str:\n        \"\"\"\n        The build directory.\n        \"\"\"\n        return self.__directory\n\n    @property\n    def target_name(self) -> str:\n        \"\"\"\n        The plugin name of the build target.\n        \"\"\"\n        return self.__target_name\n\n    def clean(self, versions: list[str]) -> None:\n        \"\"\"\n        This occurs before the build process if the `-c`/`--clean` flag was passed to\n        the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n        the [`clean`](../../cli/reference.md#hatch-clean) command.\n        \"\"\"\n\n    def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n        \"\"\"\n        This occurs immediately before each build.\n\n        Any modifications to the build data will be seen by the build target.\n        \"\"\"\n\n    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n        \"\"\"\n        This occurs immediately after each build and will not run if the `--hooks-only` flag\n        was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n        The build data will reflect any modifications done by the target during the build.\n        \"\"\"\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.app","title":"app: Application property","text":"

    An instance of Application.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.root","title":"root: str property","text":"

    The root of the project tree.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.config","title":"config: dict[str, Any] property","text":"

    The cumulative hook configuration.

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.<PLUGIN_NAME>]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
    [build.hooks.<PLUGIN_NAME>]\n[build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.build_config","title":"build_config: BuilderConfigBound property","text":"

    An instance of BuilderConfig.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.target_name","title":"target_name: str property","text":"

    The plugin name of the build target.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.directory","title":"directory: str property","text":"

    The build directory.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.clean","title":"clean(versions: list[str]) -> None","text":"

    This occurs before the build process if the -c/--clean flag was passed to the build command, or when invoking the clean command.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def clean(self, versions: list[str]) -> None:\n    \"\"\"\n    This occurs before the build process if the `-c`/`--clean` flag was passed to\n    the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n    the [`clean`](../../cli/reference.md#hatch-clean) command.\n    \"\"\"\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.initialize","title":"initialize(version: str, build_data: dict[str, Any]) -> None","text":"

    This occurs immediately before each build.

    Any modifications to the build data will be seen by the build target.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n    \"\"\"\n    This occurs immediately before each build.\n\n    Any modifications to the build data will be seen by the build target.\n    \"\"\"\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.finalize","title":"finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None","text":"

    This occurs immediately after each build and will not run if the --hooks-only flag was passed to the build command.

    The build data will reflect any modifications done by the target during the build.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n    \"\"\"\n    This occurs immediately after each build and will not run if the `--hooks-only` flag\n    was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n    The build data will reflect any modifications done by the target during the build.\n    \"\"\"\n
    "},{"location":"plugins/build-hook/version/","title":"Version build hook","text":"

    This writes the project's version to a file.

    "},{"location":"plugins/build-hook/version/#configuration","title":"Configuration","text":"

    The build hook plugin name is version.

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.version]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.version]\n
    [build.hooks.version]\n[build.targets.<TARGET_NAME>.hooks.version]\n
    "},{"location":"plugins/build-hook/version/#options","title":"Options","text":"Option Description path (required) A relative path to the desired file template A string representing the entire contents of path that will be formatted with a version variable pattern Rather than updating the entire file, a regular expression may be used that has a named group called version that represents the version. If set to true, a pattern will be used that looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v."},{"location":"plugins/builder/app/","title":"Application builder","text":"

    This uses PyApp to build an application that is able to bootstrap itself at runtime.

    Note

    This requires an installation of Rust.

    "},{"location":"plugins/builder/app/#configuration","title":"Configuration","text":"

    The builder plugin name is app.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.app]\n
    [build.targets.app]\n
    "},{"location":"plugins/builder/app/#options","title":"Options","text":"Option Default Description scripts all defined An array of defined script names to limit what gets built python-version latest compatible Python minor version The Python version ID to use pyapp-version The version of PyApp to use"},{"location":"plugins/builder/app/#build-behavior","title":"Build behavior","text":"

    If any scripts are defined then each one will be built (limited by the scripts option). Otherwise, a single executable will be built based on the project name assuming there is an equivalently named module with a __main__.py file.

    Every executable will be built inside an app directory in the output directory.

    If the CARGO environment variable is set then that path will be used as the executable for performing builds.

    If the CARGO_BUILD_TARGET environment variable is set then its value will be appended to the file name stems.

    If the PYAPP_REPO environment variable is set then a local build will be performed inside that directory rather than installing from crates.io. Note that this is required if the CARGO environment variable refers to cross.

    "},{"location":"plugins/builder/custom/","title":"Custom builder","text":"

    This is a custom class in a given Python file that inherits from the BuilderInterface.

    "},{"location":"plugins/builder/custom/#configuration","title":"Configuration","text":"

    The builder plugin name is custom.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.custom]\n
    [build.targets.custom]\n
    "},{"location":"plugins/builder/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/builder/custom/#example","title":"Example","text":"hatch_build.py
    from hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass CustomBuilder(BuilderInterface):\n    ...\n

    If multiple subclasses are found, you must define a function named get_builder that returns the desired builder.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    "},{"location":"plugins/builder/reference/","title":"Builder plugins","text":"

    See the documentation for build configuration.

    "},{"location":"plugins/builder/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-aws - used for building AWS Lambda functions with SAM
    • hatch-zipped-directory - used for building ZIP archives for installation into various foreign package installation systems
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface","title":"BuilderInterface","text":"

    Example usage:

    plugin.py hooks.py
    from hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass SpecialBuilder(BuilderInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuilder\n\n\n@hookimpl\ndef hatch_register_builder():\n    return SpecialBuilder\n
    Source code in backend/src/hatchling/builders/plugin/interface.py
    class BuilderInterface(ABC, Generic[BuilderConfigBound, PluginManagerBound]):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.builders.plugin.interface import BuilderInterface\n\n\n    class SpecialBuilder(BuilderInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialBuilder\n\n\n    @hookimpl\n    def hatch_register_builder():\n        return SpecialBuilder\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root: str,\n        plugin_manager: PluginManagerBound | None = None,\n        config: dict[str, Any] | None = None,\n        metadata: ProjectMetadata | None = None,\n        app: Application | None = None,\n    ) -> None:\n        self.__root = root\n        self.__plugin_manager = cast(PluginManagerBound, plugin_manager)\n        self.__raw_config = config\n        self.__metadata = metadata\n        self.__app = app\n        self.__config = cast(BuilderConfigBound, None)\n        self.__project_config: dict[str, Any] | None = None\n        self.__hatch_config: dict[str, Any] | None = None\n        self.__build_config: dict[str, Any] | None = None\n        self.__build_targets: list[str] | None = None\n        self.__target_config: dict[str, Any] | None = None\n\n        # Metadata\n        self.__project_id: str | None = None\n\n    def build(\n        self,\n        *,\n        directory: str | None = None,\n        versions: list[str] | None = None,\n        hooks_only: bool | None = None,\n        clean: bool | None = None,\n        clean_hooks_after: bool | None = None,\n        clean_only: bool | None = False,\n    ) -> Generator[str, None, None]:\n        # Fail early for invalid project metadata\n        self.metadata.validate_fields()\n\n        if directory is None:\n            directory = (\n                self.config.normalize_build_directory(os.environ[BuildEnvVars.LOCATION])\n                if BuildEnvVars.LOCATION in os.environ\n                else self.config.directory\n            )\n\n        if not os.path.isdir(directory):\n            os.makedirs(directory)\n\n        version_api = self.get_version_api()\n\n        versions = versions or self.config.versions\n        if versions:\n            unknown_versions = set(versions) - set(version_api)\n            if unknown_versions:\n                message = (\n                    f'Unknown versions for target `{self.PLUGIN_NAME}`: {\", \".join(map(str, sorted(unknown_versions)))}'\n                )\n                raise ValueError(message)\n\n        if hooks_only is None:\n            hooks_only = env_var_enabled(BuildEnvVars.HOOKS_ONLY)\n\n        configured_build_hooks = self.get_build_hooks(directory)\n        build_hooks = list(configured_build_hooks.values())\n\n        if clean_only:\n            clean = True\n        elif clean is None:\n            clean = env_var_enabled(BuildEnvVars.CLEAN)\n        if clean:\n            if not hooks_only:\n                self.clean(directory, versions)\n\n            for build_hook in build_hooks:\n                build_hook.clean(versions)\n\n            if clean_only:\n                return\n\n        if clean_hooks_after is None:\n            clean_hooks_after = env_var_enabled(BuildEnvVars.CLEAN_HOOKS_AFTER)\n\n        for version in versions:\n            self.app.display_debug(f'Building `{self.PLUGIN_NAME}` version `{version}`')\n\n            build_data = self.get_default_build_data()\n            self.set_build_data_defaults(build_data)\n\n            # Allow inspection of configured build hooks and the order in which they run\n            build_data['build_hooks'] = tuple(configured_build_hooks)\n\n            # Execute all `initialize` build hooks\n            for build_hook in build_hooks:\n                build_hook.initialize(version, build_data)\n\n            if hooks_only:\n                self.app.display_debug(f'Only ran build hooks for `{self.PLUGIN_NAME}` version `{version}`')\n                continue\n\n            # Build the artifact\n            with self.config.set_build_data(build_data):\n                artifact = version_api[version](directory, **build_data)\n\n            # Execute all `finalize` build hooks\n            for build_hook in build_hooks:\n                build_hook.finalize(version, build_data, artifact)\n\n            if clean_hooks_after:\n                for build_hook in build_hooks:\n                    build_hook.clean([version])\n\n            yield artifact\n\n    def recurse_included_files(self) -> Iterable[IncludedFile]:\n        \"\"\"\n        Returns a consistently generated series of file objects for every file that should be distributed. Each file\n        object has three `str` attributes:\n\n        - `path` - the absolute path\n        - `relative_path` - the path relative to the project root; will be an empty string for external files\n        - `distribution_path` - the path to be distributed as\n        \"\"\"\n        yield from self.recurse_selected_project_files()\n        yield from self.recurse_forced_files(self.config.get_force_include())\n\n    def recurse_selected_project_files(self) -> Iterable[IncludedFile]:\n        if self.config.only_include:\n            yield from self.recurse_explicit_files(self.config.only_include)\n        else:\n            yield from self.recurse_project_files()\n\n    def recurse_project_files(self) -> Iterable[IncludedFile]:\n        for root, dirs, files in safe_walk(self.root):\n            relative_path = get_relative_path(root, self.root)\n\n            dirs[:] = sorted(d for d in dirs if not self.config.directory_is_excluded(d, relative_path))\n\n            files.sort()\n            is_package = '__init__.py' in files\n            for f in files:\n                relative_file_path = os.path.join(relative_path, f)\n                distribution_path = self.config.get_distribution_path(relative_file_path)\n                if self.config.path_is_reserved(distribution_path):\n                    continue\n\n                if self.config.include_path(relative_file_path, is_package=is_package):\n                    yield IncludedFile(\n                        os.path.join(root, f), relative_file_path, self.config.get_distribution_path(relative_file_path)\n                    )\n\n    def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n        for source, target_path in inclusion_map.items():\n            external = not source.startswith(self.root)\n            if os.path.isfile(source):\n                yield IncludedFile(\n                    source,\n                    '' if external else os.path.relpath(source, self.root),\n                    self.config.get_distribution_path(target_path),\n                )\n            elif os.path.isdir(source):\n                for root, dirs, files in safe_walk(source):\n                    relative_directory = get_relative_path(root, source)\n\n                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n                    files.sort()\n                    for f in files:\n                        relative_file_path = os.path.join(target_path, relative_directory, f)\n                        distribution_path = self.config.get_distribution_path(relative_file_path)\n                        if not self.config.path_is_reserved(distribution_path):\n                            yield IncludedFile(\n                                os.path.join(root, f),\n                                '' if external else relative_file_path,\n                                distribution_path,\n                            )\n            else:\n                msg = f'Forced include not found: {source}'\n                raise FileNotFoundError(msg)\n\n    def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n        for source, target_path in inclusion_map.items():\n            external = not source.startswith(self.root)\n            if os.path.isfile(source):\n                distribution_path = self.config.get_distribution_path(target_path)\n                if not self.config.path_is_reserved(distribution_path):\n                    yield IncludedFile(\n                        source,\n                        '' if external else os.path.relpath(source, self.root),\n                        self.config.get_distribution_path(target_path),\n                    )\n            elif os.path.isdir(source):\n                for root, dirs, files in safe_walk(source):\n                    relative_directory = get_relative_path(root, source)\n\n                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n                    files.sort()\n                    is_package = '__init__.py' in files\n                    for f in files:\n                        relative_file_path = os.path.join(target_path, relative_directory, f)\n                        distribution_path = self.config.get_distribution_path(relative_file_path)\n                        if self.config.path_is_reserved(distribution_path):\n                            continue\n\n                        if self.config.include_path(relative_file_path, explicit=True, is_package=is_package):\n                            yield IncludedFile(\n                                os.path.join(root, f), '' if external else relative_file_path, distribution_path\n                            )\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def plugin_manager(self) -> PluginManagerBound:\n        if self.__plugin_manager is None:\n            from hatchling.plugin.manager import PluginManager\n\n            self.__plugin_manager = PluginManager()\n\n        return self.__plugin_manager\n\n    @property\n    def metadata(self) -> ProjectMetadata:\n        if self.__metadata is None:\n            from hatchling.metadata.core import ProjectMetadata\n\n            self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)\n\n        return self.__metadata\n\n    @property\n    def app(self) -> Application:\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = cast(Application, Application().get_safe_application())\n\n        return self.__app\n\n    @property\n    def raw_config(self) -> dict[str, Any]:\n        if self.__raw_config is None:\n            self.__raw_config = self.metadata.config\n\n        return self.__raw_config\n\n    @property\n    def project_config(self) -> dict[str, Any]:\n        if self.__project_config is None:\n            self.__project_config = self.metadata.core.config\n\n        return self.__project_config\n\n    @property\n    def hatch_config(self) -> dict[str, Any]:\n        if self.__hatch_config is None:\n            self.__hatch_config = self.metadata.hatch.config\n\n        return self.__hatch_config\n\n    @property\n    def config(self) -> BuilderConfigBound:\n        \"\"\"\n        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        if self.__config is None:\n            self.__config = self.get_config_class()(\n                self, self.root, self.PLUGIN_NAME, self.build_config, self.target_config\n            )\n\n        return self.__config\n\n    @property\n    def build_config(self) -> dict[str, Any]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.build]\n        ```\n        \"\"\"\n        if self.__build_config is None:\n            self.__build_config = self.metadata.hatch.build_config\n\n        return self.__build_config\n\n    @property\n    def target_config(self) -> dict[str, Any]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.build.targets.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        if self.__target_config is None:\n            target_config: dict[str, Any] = self.metadata.hatch.build_targets.get(self.PLUGIN_NAME, {})\n            if not isinstance(target_config, dict):\n                message = f'Field `tool.hatch.build.targets.{self.PLUGIN_NAME}` must be a table'\n                raise TypeError(message)\n\n            self.__target_config = target_config\n\n        return self.__target_config\n\n    @property\n    def project_id(self) -> str:\n        if self.__project_id is None:\n            self.__project_id = f'{self.normalize_file_name_component(self.metadata.core.name)}-{self.metadata.version}'\n\n        return self.__project_id\n\n    def get_build_hooks(self, directory: str) -> dict[str, BuildHookInterface]:\n        configured_build_hooks = {}\n        for hook_name, config in self.config.hook_config.items():\n            build_hook = self.plugin_manager.build_hook.get(hook_name)\n            if build_hook is None:\n                from hatchling.plugin.exceptions import UnknownPluginError\n\n                message = f'Unknown build hook: {hook_name}'\n                raise UnknownPluginError(message)\n\n            configured_build_hooks[hook_name] = build_hook(\n                self.root, config, self.config, self.metadata, directory, self.PLUGIN_NAME, self.app\n            )\n\n        return configured_build_hooks\n\n    @abstractmethod\n    def get_version_api(self) -> dict[str, Callable]:\n        \"\"\"\n        A mapping of `str` versions to a callable that is used for building.\n        Each callable must have the following signature:\n\n        ```python\n        def ...(build_dir: str, build_data: dict) -> str:\n        ```\n\n        The return value must be the absolute path to the built artifact.\n        \"\"\"\n\n    def get_default_versions(self) -> list[str]:\n        \"\"\"\n        A list of versions to build when users do not specify any, defaulting to all versions.\n        \"\"\"\n        return list(self.get_version_api())\n\n    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301\n        \"\"\"\n        A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n        \"\"\"\n        return {}\n\n    def set_build_data_defaults(self, build_data: dict[str, Any]) -> None:  # noqa: PLR6301\n        build_data.setdefault('artifacts', [])\n        build_data.setdefault('force_include', {})\n\n    def clean(self, directory: str, versions: list[str]) -> None:\n        \"\"\"\n        Called before builds if the `-c`/`--clean` flag was passed to the\n        [`build`](../../cli/reference.md#hatch-build) command.\n        \"\"\"\n\n    @classmethod\n    def get_config_class(cls) -> type[BuilderConfig]:\n        \"\"\"\n        Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        return BuilderConfig\n\n    @staticmethod\n    def normalize_file_name_component(file_name: str) -> str:\n        \"\"\"\n        https://peps.python.org/pep-0427/#escaping-and-unicode\n        \"\"\"\n        return re.sub(r'[^\\w\\d.]+', '_', file_name, flags=re.UNICODE)\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.app","title":"app: Application property","text":"

    An instance of Application.

    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.root","title":"root: str property","text":"

    The root of the project tree.

    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.build_config","title":"build_config: dict[str, Any] property","text":"pyproject.toml hatch.toml
    [tool.hatch.build]\n
    [build]\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.target_config","title":"target_config: dict[str, Any] property","text":"pyproject.toml hatch.toml
    [tool.hatch.build.targets.<PLUGIN_NAME>]\n
    [build.targets.<PLUGIN_NAME>]\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.config","title":"config: BuilderConfigBound property","text":"

    An instance of BuilderConfig.

    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_config_class","title":"get_config_class() -> type[BuilderConfig] classmethod","text":"

    Must return a subclass of BuilderConfig.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    @classmethod\ndef get_config_class(cls) -> type[BuilderConfig]:\n    \"\"\"\n    Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n    \"\"\"\n    return BuilderConfig\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_version_api","title":"get_version_api() -> dict[str, Callable] abstractmethod","text":"

    A mapping of str versions to a callable that is used for building. Each callable must have the following signature:

    def ...(build_dir: str, build_data: dict) -> str:\n

    The return value must be the absolute path to the built artifact.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    @abstractmethod\ndef get_version_api(self) -> dict[str, Callable]:\n    \"\"\"\n    A mapping of `str` versions to a callable that is used for building.\n    Each callable must have the following signature:\n\n    ```python\n    def ...(build_dir: str, build_data: dict) -> str:\n    ```\n\n    The return value must be the absolute path to the built artifact.\n    \"\"\"\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_versions","title":"get_default_versions() -> list[str]","text":"

    A list of versions to build when users do not specify any, defaulting to all versions.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def get_default_versions(self) -> list[str]:\n    \"\"\"\n    A list of versions to build when users do not specify any, defaulting to all versions.\n    \"\"\"\n    return list(self.get_version_api())\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.clean","title":"clean(directory: str, versions: list[str]) -> None","text":"

    Called before builds if the -c/--clean flag was passed to the build command.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def clean(self, directory: str, versions: list[str]) -> None:\n    \"\"\"\n    Called before builds if the `-c`/`--clean` flag was passed to the\n    [`build`](../../cli/reference.md#hatch-build) command.\n    \"\"\"\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.recurse_included_files","title":"recurse_included_files() -> Iterable[IncludedFile]","text":"

    Returns a consistently generated series of file objects for every file that should be distributed. Each file object has three str attributes:

    • path - the absolute path
    • relative_path - the path relative to the project root; will be an empty string for external files
    • distribution_path - the path to be distributed as
    Source code in backend/src/hatchling/builders/plugin/interface.py
    def recurse_included_files(self) -> Iterable[IncludedFile]:\n    \"\"\"\n    Returns a consistently generated series of file objects for every file that should be distributed. Each file\n    object has three `str` attributes:\n\n    - `path` - the absolute path\n    - `relative_path` - the path relative to the project root; will be an empty string for external files\n    - `distribution_path` - the path to be distributed as\n    \"\"\"\n    yield from self.recurse_selected_project_files()\n    yield from self.recurse_forced_files(self.config.get_force_include())\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_build_data","title":"get_default_build_data() -> dict[str, Any]","text":"

    A mapping that can be modified by build hooks to influence the behavior of builds.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301\n    \"\"\"\n    A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n    \"\"\"\n    return {}\n
    "},{"location":"plugins/builder/sdist/","title":"Source distribution builder","text":"

    A source distribution, or sdist, is an archive of Python \"source code\". Although largely unspecified, by convention it should include everything that is required to build a wheel without making network requests.

    "},{"location":"plugins/builder/sdist/#configuration","title":"Configuration","text":"

    The builder plugin name is sdist.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.sdist]\n
    [build.targets.sdist]\n
    "},{"location":"plugins/builder/sdist/#options","title":"Options","text":"Option Default Description core-metadata-version \"2.1\" The version of core metadata to use strict-naming true Whether or not file names should contain the normalized version of the project name support-legacy false Whether or not to include a setup.py file to support legacy installation mechanisms"},{"location":"plugins/builder/sdist/#versions","title":"Versions","text":"Version Description standard (default) The latest conventional format"},{"location":"plugins/builder/sdist/#default-file-selection","title":"Default file selection","text":"

    When the user has not set any file selection options, all files that are not ignored by your VCS will be included.

    Note

    The following files are always included and cannot be excluded:

    • /pyproject.toml
    • /hatch.toml
    • /hatch_build.py
    • /.gitignore or /.hgignore
    • Any defined readme file
    • All defined license-files
    "},{"location":"plugins/builder/sdist/#reproducibility","title":"Reproducibility","text":"

    Reproducible builds are supported.

    "},{"location":"plugins/builder/sdist/#build-data","title":"Build data","text":"

    This is data that can be modified by build hooks.

    Data Default Description dependencies Extra project dependencies"},{"location":"plugins/builder/wheel/","title":"Wheel builder","text":"

    A wheel is a binary distribution of a Python package that can be installed directly into an environment.

    "},{"location":"plugins/builder/wheel/#configuration","title":"Configuration","text":"

    The builder plugin name is wheel.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\n
    [build.targets.wheel]\n
    "},{"location":"plugins/builder/wheel/#options","title":"Options","text":"Option Default Description core-metadata-version \"2.1\" The version of core metadata to use shared-data A mapping similar to the forced inclusion option corresponding to data that will be installed globally in a given Python environment, usually under sys.prefix extra-metadata A mapping similar to the forced inclusion option corresponding to extra metadata that will be shipped in a directory named extra_metadata strict-naming true Whether or not file names should contain the normalized version of the project name macos-max-compat true Whether or not on macOS, when build hooks have set the infer_tag build data, the wheel name should signal broad support rather than specific versions for newer SDK versions.Note: The default will become false, and this option eventually removed, sometime after consumers like pip start supporting these newer SDK versions. bypass-selection false Whether or not to suppress the error when one has not defined any file selection options and all heuristics have failed to determine what to ship"},{"location":"plugins/builder/wheel/#versions","title":"Versions","text":"Version Description standard (default) The latest standardized format editable A wheel that only ships .pth files or import hooks for real-time development"},{"location":"plugins/builder/wheel/#default-file-selection","title":"Default file selection","text":"

    When the user has not set any file selection options, the project name will be used to determine the package to ship in the following heuristic order:

    1. <NAME>/__init__.py
    2. src/<NAME>/__init__.py
    3. <NAME>.py
    4. <NAMESPACE>/<NAME>/__init__.py

    If none of these heuristics are satisfied, an error will be raised.

    "},{"location":"plugins/builder/wheel/#reproducibility","title":"Reproducibility","text":"

    Reproducible builds are supported.

    "},{"location":"plugins/builder/wheel/#build-data","title":"Build data","text":"

    This is data that can be modified by build hooks.

    Data Default Description tag The full tag part of the filename (e.g. py3-none-any), defaulting to a cross-platform wheel with the supported major versions of Python based on project metadata infer_tag False When tag is not set, this may be enabled to use the one most specific to the platform, Python interpreter, and ABI pure_python True Whether or not to write metadata indicating that the package does not contain any platform-specific files dependencies Extra project dependencies extra_metadata Additional extra-metadata entries, which take precedence in case of conflicts force_include_editable Similar to the force_include option but specifically for the editable version and takes precedence"},{"location":"plugins/environment/reference/","title":"Environment plugins","text":"

    See the documentation for environment configuration.

    "},{"location":"plugins/environment/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-conda - environments backed by Conda/Mamba
    • hatch-containers - environments run inside containers
    • hatch-pip-compile - use pip-compile to manage project dependencies and lockfiles
    • hatch-pip-deepfreeze - virtual environments with dependency locking by pip-deepfreeze
    "},{"location":"plugins/environment/reference/#installation","title":"Installation","text":"

    Any required environment types that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

    pyproject.toml hatch.toml
    [tool.hatch.env]\nrequires = [\n  \"...\",\n]\n
    [env]\nrequires = [\n  \"...\",\n]\n
    "},{"location":"plugins/environment/reference/#life-cycle","title":"Life cycle","text":"

    Whenever an environment is used, the following logic is performed:

    Source code in src/hatch/cli/application.py
    def prepare_environment(self, environment: EnvironmentInterface):\n    if not environment.exists():\n        self.env_metadata.reset(environment)\n\n        with self.status(f'Creating environment: {environment.name}'):\n            environment.create()\n\n        if not environment.skip_install:\n            if environment.pre_install_commands:\n                with self.status('Running pre-installation commands'):\n                    self.run_shell_commands(environment, environment.pre_install_commands, source='pre-install')\n\n            if environment.dev_mode:\n                with self.status('Installing project in development mode'):\n                    environment.install_project_dev_mode()\n            else:\n                with self.status('Installing project'):\n                    environment.install_project()\n\n            if environment.post_install_commands:\n                with self.status('Running post-installation commands'):\n                    self.run_shell_commands(environment, environment.post_install_commands, source='post-install')\n\n    new_dep_hash = environment.dependency_hash()\n    current_dep_hash = self.env_metadata.dependency_hash(environment)\n    if new_dep_hash != current_dep_hash:\n        with self.status('Checking dependencies'):\n            dependencies_in_sync = environment.dependencies_in_sync()\n\n        if not dependencies_in_sync:\n            with self.status('Syncing dependencies'):\n                environment.sync_dependencies()\n                new_dep_hash = environment.dependency_hash()\n\n        self.env_metadata.update_dependency_hash(environment, new_dep_hash)\n
    "},{"location":"plugins/environment/reference/#build-environments","title":"Build environments","text":"

    All environment types should offer support for a special sub-environment in which projects can be built. This environment is used in the following scenarios:

    • the build command
    • commands that read dependencies, like dep hash, if any project dependencies are set dynamically
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface","title":"EnvironmentInterface","text":"

    Example usage:

    plugin.py hooks.py
        from hatch.env.plugin.interface import EnvironmentInterface\n\n\n    class SpecialEnvironment(EnvironmentInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
        from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialEnvironment\n\n\n    @hookimpl\n    def hatch_register_environment():\n        return SpecialEnvironment\n
    Source code in src/hatch/env/plugin/interface.py
    class EnvironmentInterface(ABC):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.env.plugin.interface import EnvironmentInterface\n\n\n        class SpecialEnvironment(EnvironmentInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialEnvironment\n\n\n        @hookimpl\n        def hatch_register_environment():\n            return SpecialEnvironment\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root,\n        metadata,\n        name,\n        config,\n        matrix_variables,\n        data_directory,\n        isolated_data_directory,\n        platform,\n        verbosity,\n        app=None,\n    ):\n        self.__root = root\n        self.__metadata = metadata\n        self.__name = name\n        self.__config = config\n        self.__matrix_variables = matrix_variables\n        self.__data_directory = data_directory\n        self.__isolated_data_directory = isolated_data_directory\n        self.__platform = platform\n        self.__verbosity = verbosity\n        self.__app = app\n        self.__context = None\n\n        self._system_python = None\n        self._env_vars = None\n        self._env_include = None\n        self._env_exclude = None\n        self._environment_dependencies_complex = None\n        self._environment_dependencies = None\n        self._dependencies_complex = None\n        self._dependencies = None\n        self._platforms = None\n        self._skip_install = None\n        self._dev_mode = None\n        self._features = None\n        self._description = None\n        self._scripts = None\n        self._pre_install_commands = None\n        self._post_install_commands = None\n\n    @property\n    def matrix_variables(self):\n        return self.__matrix_variables\n\n    @property\n    def app(self):\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = Application().get_safe_application()\n\n        return self.__app\n\n    @property\n    def context(self):\n        if self.__context is None:\n            self.__context = self.get_context()\n\n        return self.__context\n\n    @property\n    def verbosity(self):\n        return self.__verbosity\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def metadata(self):\n        return self.__metadata\n\n    @property\n    def name(self) -> str:\n        \"\"\"\n        The name of the environment.\n        \"\"\"\n        return self.__name\n\n    @property\n    def platform(self):\n        \"\"\"\n        An instance of [Platform](../utilities.md#hatch.utils.platform.Platform).\n        \"\"\"\n        return self.__platform\n\n    @property\n    def data_directory(self):\n        \"\"\"\n        The [directory](../../config/hatch.md#environments) this plugin should use for storage as a path-like object.\n        If the user has not configured one then this will be the same as the\n        [isolated data directory](reference.md#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory).\n        \"\"\"\n        return self.__data_directory\n\n    @property\n    def isolated_data_directory(self):\n        \"\"\"\n        The default [directory](../../config/hatch.md#environments) reserved exclusively for this plugin as a path-like\n        object.\n        \"\"\"\n        return self.__isolated_data_directory\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @property\n    def system_python(self):\n        if self._system_python is None:\n            system_python = os.environ.get(AppEnvVars.PYTHON)\n            if system_python == 'self':\n                system_python = sys.executable\n\n            system_python = (\n                system_python\n                or self.platform.modules.shutil.which('python')\n                or self.platform.modules.shutil.which('python3')\n                or sys.executable\n            )\n            if not isabs(system_python):\n                system_python = self.platform.modules.shutil.which(system_python)\n\n            self._system_python = system_python\n\n        return self._system_python\n\n    @property\n    def env_vars(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>.env-vars]\n        ```\n        \"\"\"\n        if self._env_vars is None:\n            env_vars = self.config.get('env-vars', {})\n            if not isinstance(env_vars, dict):\n                message = f'Field `tool.hatch.envs.{self.name}.env-vars` must be a mapping'\n                raise TypeError(message)\n\n            for key, value in env_vars.items():\n                if not isinstance(value, str):\n                    message = (\n                        f'Environment variable `{key}` of field `tool.hatch.envs.{self.name}.env-vars` must be a string'\n                    )\n                    raise TypeError(message)\n\n            new_env_vars = {}\n            with self.metadata.context.apply_context(self.context):\n                for key, value in env_vars.items():\n                    new_env_vars[key] = self.metadata.context.format(value)\n\n            new_env_vars[AppEnvVars.ENV_ACTIVE] = self.name\n            self._env_vars = new_env_vars\n\n        return self._env_vars\n\n    @property\n    def env_include(self) -> list[str]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        env-include = [...]\n        ```\n        \"\"\"\n        if self._env_include is None:\n            env_include = self.config.get('env-include', [])\n            if not isinstance(env_include, list):\n                message = f'Field `tool.hatch.envs.{self.name}.env-include` must be an array'\n                raise TypeError(message)\n\n            for i, pattern in enumerate(env_include, 1):\n                if not isinstance(pattern, str):\n                    message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-include` must be a string'\n                    raise TypeError(message)\n\n            if env_include:\n                self._env_include = ['HATCH_BUILD_*', *env_include]\n            else:\n                self._env_include = env_include\n\n        return self._env_include\n\n    @property\n    def env_exclude(self) -> list[str]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        env-exclude = [...]\n        ```\n        \"\"\"\n        if self._env_exclude is None:\n            env_exclude = self.config.get('env-exclude', [])\n            if not isinstance(env_exclude, list):\n                message = f'Field `tool.hatch.envs.{self.name}.env-exclude` must be an array'\n                raise TypeError(message)\n\n            for i, pattern in enumerate(env_exclude, 1):\n                if not isinstance(pattern, str):\n                    message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-exclude` must be a string'\n                    raise TypeError(message)\n\n            self._env_exclude = env_exclude\n\n        return self._env_exclude\n\n    @property\n    def environment_dependencies_complex(self):\n        if self._environment_dependencies_complex is None:\n            from packaging.requirements import InvalidRequirement, Requirement\n\n            dependencies_complex = []\n            with self.apply_context():\n                for option in ('dependencies', 'extra-dependencies'):\n                    dependencies = self.config.get(option, [])\n                    if not isinstance(dependencies, list):\n                        message = f'Field `tool.hatch.envs.{self.name}.{option}` must be an array'\n                        raise TypeError(message)\n\n                    for i, entry in enumerate(dependencies, 1):\n                        if not isinstance(entry, str):\n                            message = (\n                                f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` must be a string'\n                            )\n                            raise TypeError(message)\n\n                        try:\n                            dependencies_complex.append(Requirement(self.metadata.context.format(entry)))\n                        except InvalidRequirement as e:\n                            message = f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` is invalid: {e}'\n                            raise ValueError(message) from None\n\n            self._environment_dependencies_complex = dependencies_complex\n\n        return self._environment_dependencies_complex\n\n    @property\n    def environment_dependencies(self) -> list[str]:\n        \"\"\"\n        The list of all [environment dependencies](../../config/environment/overview.md#dependencies).\n        \"\"\"\n        if self._environment_dependencies is None:\n            self._environment_dependencies = [str(dependency) for dependency in self.environment_dependencies_complex]\n\n        return self._environment_dependencies\n\n    @property\n    def dependencies_complex(self):\n        if self._dependencies_complex is None:\n            all_dependencies_complex = list(self.environment_dependencies_complex)\n\n            # Ensure these are checked last to speed up initial environment creation since\n            # they will already be installed along with the project\n            if (not self.skip_install and self.dev_mode) or self.features:\n                from hatch.utils.dep import get_project_dependencies_complex\n\n                dependencies_complex, optional_dependencies_complex = get_project_dependencies_complex(self)\n\n                if not self.skip_install and self.dev_mode:\n                    all_dependencies_complex.extend(dependencies_complex.values())\n\n                for feature in self.features:\n                    if feature not in optional_dependencies_complex:\n                        message = (\n                            f'Feature `{feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n                            f'defined in the dynamic field `project.optional-dependencies`'\n                        )\n                        raise ValueError(message)\n\n                    all_dependencies_complex.extend(optional_dependencies_complex[feature].values())\n\n            self._dependencies_complex = all_dependencies_complex\n\n        return self._dependencies_complex\n\n    @property\n    def dependencies(self) -> list[str]:\n        \"\"\"\n        The list of all [project dependencies](../../config/metadata.md#dependencies) (if\n        [installed](../../config/environment/overview.md#skip-install) and in\n        [dev mode](../../config/environment/overview.md#dev-mode)), selected\n        [optional dependencies](../../config/environment/overview.md#features), and\n        [environment dependencies](../../config/environment/overview.md#dependencies).\n        \"\"\"\n        if self._dependencies is None:\n            self._dependencies = [str(dependency) for dependency in self.dependencies_complex]\n\n        return self._dependencies\n\n    @property\n    def platforms(self) -> list[str]:\n        \"\"\"\n        All names are stored as their lower-cased version.\n\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        platforms = [...]\n        ```\n        \"\"\"\n        if self._platforms is None:\n            platforms = self.config.get('platforms', [])\n            if not isinstance(platforms, list):\n                message = f'Field `tool.hatch.envs.{self.name}.platforms` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(platforms, 1):\n                if not isinstance(command, str):\n                    message = f'Platform #{i} of field `tool.hatch.envs.{self.name}.platforms` must be a string'\n                    raise TypeError(message)\n\n            self._platforms = [platform.lower() for platform in platforms]\n\n        return self._platforms\n\n    @property\n    def skip_install(self) -> bool:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        skip-install = ...\n        ```\n        \"\"\"\n        if self._skip_install is None:\n            skip_install = self.config.get('skip-install', not self.metadata.has_project_file())\n            if not isinstance(skip_install, bool):\n                message = f'Field `tool.hatch.envs.{self.name}.skip-install` must be a boolean'\n                raise TypeError(message)\n\n            self._skip_install = skip_install\n\n        return self._skip_install\n\n    @property\n    def dev_mode(self) -> bool:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        dev-mode = ...\n        ```\n        \"\"\"\n        if self._dev_mode is None:\n            dev_mode = self.config.get('dev-mode', True)\n            if not isinstance(dev_mode, bool):\n                message = f'Field `tool.hatch.envs.{self.name}.dev-mode` must be a boolean'\n                raise TypeError(message)\n\n            self._dev_mode = dev_mode\n\n        return self._dev_mode\n\n    @property\n    def features(self):\n        if self._features is None:\n            from hatchling.metadata.utils import normalize_project_name\n\n            features = self.config.get('features', [])\n            if not isinstance(features, list):\n                message = f'Field `tool.hatch.envs.{self.name}.features` must be an array of strings'\n                raise TypeError(message)\n\n            all_features = set()\n            for i, feature in enumerate(features, 1):\n                if not isinstance(feature, str):\n                    message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` must be a string'\n                    raise TypeError(message)\n\n                if not feature:\n                    message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` cannot be an empty string'\n                    raise ValueError(message)\n\n                normalized_feature = (\n                    feature\n                    if self.metadata.hatch.metadata.allow_ambiguous_features\n                    else normalize_project_name(feature)\n                )\n                if (\n                    not self.metadata.hatch.metadata.hook_config\n                    and normalized_feature not in self.metadata.core.optional_dependencies\n                ):\n                    message = (\n                        f'Feature `{normalized_feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n                        f'defined in field `project.optional-dependencies`'\n                    )\n                    raise ValueError(message)\n\n                all_features.add(normalized_feature)\n\n            self._features = sorted(all_features)\n\n        return self._features\n\n    @property\n    def description(self) -> str:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        description = ...\n        ```\n        \"\"\"\n        if self._description is None:\n            description = self.config.get('description', '')\n            if not isinstance(description, str):\n                message = f'Field `tool.hatch.envs.{self.name}.description` must be a string'\n                raise TypeError(message)\n\n            self._description = description\n\n        return self._description\n\n    @property\n    def scripts(self):\n        if self._scripts is None:\n            script_config = self.config.get('scripts', {})\n            if not isinstance(script_config, dict):\n                message = f'Field `tool.hatch.envs.{self.name}.scripts` must be a table'\n                raise TypeError(message)\n\n            config = {}\n\n            for name, data in script_config.items():\n                if ' ' in name:\n                    message = (\n                        f'Script name `{name}` in field `tool.hatch.envs.{self.name}.scripts` must not contain spaces'\n                    )\n                    raise ValueError(message)\n\n                commands = []\n\n                if isinstance(data, str):\n                    commands.append(data)\n                elif isinstance(data, list):\n                    for i, command in enumerate(data, 1):\n                        if not isinstance(command, str):\n                            message = (\n                                f'Command #{i} in field `tool.hatch.envs.{self.name}.scripts.{name}` must be a string'\n                            )\n                            raise TypeError(message)\n\n                        commands.append(command)\n                else:\n                    message = (\n                        f'Field `tool.hatch.envs.{self.name}.scripts.{name}` must be a string or an array of strings'\n                    )\n                    raise TypeError(message)\n\n                config[name] = commands\n\n            seen = {}\n            active = []\n            for script_name, commands in config.items():\n                commands[:] = expand_script_commands(self.name, script_name, commands, config, seen, active)\n\n            self._scripts = config\n\n        return self._scripts\n\n    @property\n    def pre_install_commands(self):\n        if self._pre_install_commands is None:\n            pre_install_commands = self.config.get('pre-install-commands', [])\n            if not isinstance(pre_install_commands, list):\n                message = f'Field `tool.hatch.envs.{self.name}.pre-install-commands` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(pre_install_commands, 1):\n                if not isinstance(command, str):\n                    message = (\n                        f'Command #{i} of field `tool.hatch.envs.{self.name}.pre-install-commands` must be a string'\n                    )\n                    raise TypeError(message)\n\n            self._pre_install_commands = list(pre_install_commands)\n\n        return self._pre_install_commands\n\n    @property\n    def post_install_commands(self):\n        if self._post_install_commands is None:\n            post_install_commands = self.config.get('post-install-commands', [])\n            if not isinstance(post_install_commands, list):\n                message = f'Field `tool.hatch.envs.{self.name}.post-install-commands` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(post_install_commands, 1):\n                if not isinstance(command, str):\n                    message = (\n                        f'Command #{i} of field `tool.hatch.envs.{self.name}.post-install-commands` must be a string'\n                    )\n                    raise TypeError(message)\n\n            self._post_install_commands = list(post_install_commands)\n\n        return self._post_install_commands\n\n    def activate(self):\n        \"\"\"\n        A convenience method called when using the environment as a context manager:\n\n        ```python\n        with environment: ...\n        ```\n        \"\"\"\n\n    def deactivate(self):\n        \"\"\"\n        A convenience method called after using the environment as a context manager:\n\n        ```python\n        with environment: ...\n        ```\n        \"\"\"\n\n    @abstractmethod\n    def find(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should return information about how to locate the environment or represent its ID in\n        some way. Additionally, this is expected to return something even if the environment is\n        [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n        \"\"\"\n\n    @abstractmethod\n    def create(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should perform the necessary steps to set up the environment.\n        \"\"\"\n\n    @abstractmethod\n    def remove(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should perform the necessary steps to completely remove the environment from the system and will only\n        be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n        [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n\n        If the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        has a caching mechanism, this should remove that as well.\n        \"\"\"\n\n    @abstractmethod\n    def exists(self) -> bool:\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should indicate whether or not the environment has already been created.\n        \"\"\"\n\n    @abstractmethod\n    def install_project(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the project in the environment.\n        \"\"\"\n\n    @abstractmethod\n    def install_project_dev_mode(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the project in the environment such that the environment\n        always reflects the current state of the project.\n        \"\"\"\n\n    @abstractmethod\n    def dependencies_in_sync(self) -> bool:\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should indicate whether or not the environment is compatible with the current\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n        \"\"\"\n\n    @abstractmethod\n    def sync_dependencies(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n        in the environment.\n        \"\"\"\n\n    def dependency_hash(self):\n        \"\"\"\n        This should return a hash of the environment's\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n        and any other data that is handled by the\n        [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n        and\n        [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n        methods.\n        \"\"\"\n        from hatch.utils.dep import hash_dependencies\n\n        return hash_dependencies(self.dependencies_complex)\n\n    @contextmanager\n    def build_environment(\n        self,\n        dependencies: list[str],  # noqa: ARG002\n    ):\n        \"\"\"\n        This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project\n        given a set of dependencies and must be a context manager:\n\n        ```python\n        with environment.build_environment([...]): ...\n        ```\n\n        The build environment should reflect any\n        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n        the user defined either currently or at the time of\n        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n        \"\"\"\n        with self.get_env_vars():\n            yield\n\n    def run_builder(\n        self,\n        build_environment,  # noqa: ARG002\n        **kwargs,\n    ):\n        \"\"\"\n        This will be called when the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        is active:\n\n        ```python\n        with environment.build_environment([...]) as build_env:\n            process = environment.run_builder(build_env, ...)\n        ```\n\n        This should return the standard library's\n        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).\n        The command is constructed by passing all keyword arguments to\n        [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).\n\n        For an example, open the default implementation below:\n        \"\"\"\n        return self.platform.run_command(self.construct_build_command(**kwargs))\n\n    def build_environment_exists(self):  # noqa: PLR6301\n        \"\"\"\n        If the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        has a caching mechanism, this should indicate whether or not it has already been created.\n        \"\"\"\n        return False\n\n    def enter_shell(\n        self,\n        name: str,  # noqa: ARG002\n        path: str,\n        args: Iterable[str],\n    ):\n        \"\"\"\n        Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n        This should either use\n        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n        directly or provide the same guarantee.\n        \"\"\"\n        with self.command_context():\n            self.platform.exit_with_command([path, *args])\n\n    def run_shell_command(self, command: str, **kwargs):\n        \"\"\"\n        This should return the standard library's\n        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n        and will always be called when the\n        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n        is active, with the expectation of providing the same guarantee.\n        \"\"\"\n        kwargs.setdefault('shell', True)\n        return self.platform.run_command(command, **kwargs)\n\n    @contextmanager\n    def command_context(self):\n        \"\"\"\n        A context manager that when active should make executed shell commands reflect any\n        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n        the user defined either currently or at the time of\n        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n        For an example, open the default implementation below:\n        \"\"\"\n        with self.get_env_vars():\n            yield\n\n    def resolve_commands(self, commands: list[str]):\n        \"\"\"\n        This expands each command into one or more commands based on any\n        [scripts](../../config/environment/overview.md#scripts) that the user defined.\n        \"\"\"\n        for command in commands:\n            yield from self.expand_command(command)\n\n    def expand_command(self, command):\n        possible_script, args, _ignore_exit_code = parse_script_command(command)\n\n        # Indicate undefined\n        if not args:\n            args = None\n\n        with self.apply_context():\n            if possible_script in self.scripts:\n                for cmd in self.scripts[possible_script]:\n                    yield self.metadata.context.format(cmd, args=args).strip()\n            else:\n                yield self.metadata.context.format(command, args=args).strip()\n\n    def construct_build_command(  # noqa: PLR6301\n        self,\n        *,\n        directory=None,\n        targets=(),\n        hooks_only=False,\n        no_hooks=False,\n        clean=False,\n        clean_hooks_after=False,\n        clean_only=False,\n    ):\n        \"\"\"\n        This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to\n        a subprocess command issued to [builders](../builder/reference.md).\n        \"\"\"\n        command = ['python', '-u', '-m', 'hatchling', 'build']\n\n        if directory:\n            command.extend(('--directory', directory))\n\n        if targets:\n            for target in targets:\n                command.extend(('--target', target))\n\n        if hooks_only:\n            command.append('--hooks-only')\n\n        if no_hooks:\n            command.append('--no-hooks')\n\n        if clean:\n            command.append('--clean')\n\n        if clean_hooks_after:\n            command.append('--clean-hooks-after')\n\n        if clean_only:\n            command.append('--clean-only')\n\n        return command\n\n    def construct_pip_install_command(self, args: list[str]):\n        \"\"\"\n        A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n        command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n        \"\"\"\n        command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n        # Default to -1 verbosity\n        add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n        command.extend(args)\n        return command\n\n    def join_command_args(self, args: list[str]):\n        \"\"\"\n        This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n        from the received arguments.\n        \"\"\"\n        return self.platform.join_command_args(args)\n\n    def apply_features(self, requirement: str):\n        \"\"\"\n        A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n        to the given requirement.\n        \"\"\"\n        if self.features:\n            features = ','.join(self.features)\n            return f'{requirement}[{features}]'\n\n        return requirement\n\n    def check_compatibility(self):\n        \"\"\"\n        This raises an exception if the environment is not compatible with the user's setup. The default behavior\n        checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n        and any method override should keep this check.\n\n        This check is never performed if the environment has been\n        [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n        \"\"\"\n        if self.platforms and self.platform.name not in self.platforms:\n            message = 'unsupported platform'\n            raise OSError(message)\n\n    def get_env_vars(self) -> EnvVars:\n        \"\"\"\n        Returns a mapping of environment variables that should be available to the environment. The object can\n        be used as a context manager to temporarily apply the environment variables to the current process.\n\n        !!! note\n            The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n        \"\"\"\n        return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n\n    def get_env_var_option(self, option: str) -> str:\n        \"\"\"\n        Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n        \"\"\"\n        return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')\n\n    def get_context(self):\n        \"\"\"\n        Returns a subclass of\n        [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n        \"\"\"\n        from hatch.env.context import EnvironmentContextFormatter\n\n        return EnvironmentContextFormatter(self)\n\n    @staticmethod\n    def get_option_types() -> dict:\n        \"\"\"\n        Returns a mapping of supported options to their respective types so that they can be used by\n        [overrides](../../config/environment/advanced.md#option-overrides).\n        \"\"\"\n        return {}\n\n    @contextmanager\n    def apply_context(self):\n        with self.get_env_vars(), self.metadata.context.apply_context(self.context):\n            yield\n\n    def __enter__(self):\n        self.activate()\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        self.deactivate()\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app","title":"app property","text":"

    An instance of Application.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.root","title":"root property","text":"

    The root of the project tree as a path-like object.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.name","title":"name: str property","text":"

    The name of the environment.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.data_directory","title":"data_directory property","text":"

    The directory this plugin should use for storage as a path-like object. If the user has not configured one then this will be the same as the isolated data directory.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory","title":"isolated_data_directory property","text":"

    The default directory reserved exclusively for this plugin as a path-like object.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\n
    [envs.<ENV_NAME>]\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platform","title":"platform property","text":"

    An instance of Platform.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.environment_dependencies","title":"environment_dependencies: list[str] property","text":"

    The list of all environment dependencies.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies","title":"dependencies: list[str] property","text":"

    The list of all project dependencies (if installed and in dev mode), selected optional dependencies, and environment dependencies.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_vars","title":"env_vars: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>.env-vars]\n
    [envs.<ENV_NAME>.env-vars]\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_include","title":"env_include: list[str] property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nenv-include = [...]\n
    [envs.<ENV_NAME>]\nenv-include = [...]\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_exclude","title":"env_exclude: list[str] property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nenv-exclude = [...]\n
    [envs.<ENV_NAME>]\nenv-exclude = [...]\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platforms","title":"platforms: list[str] property","text":"

    All names are stored as their lower-cased version.

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nplatforms = [...]\n
    [envs.<ENV_NAME>]\nplatforms = [...]\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.skip_install","title":"skip_install: bool property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nskip-install = ...\n
    [envs.<ENV_NAME>]\nskip-install = ...\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dev_mode","title":"dev_mode: bool property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\ndev-mode = ...\n
    [envs.<ENV_NAME>]\ndev-mode = ...\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.description","title":"description: str property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\ndescription = ...\n
    [envs.<ENV_NAME>]\ndescription = ...\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.activate","title":"activate()","text":"

    A convenience method called when using the environment as a context manager:

    with environment: ...\n
    Source code in src/hatch/env/plugin/interface.py
    def activate(self):\n    \"\"\"\n    A convenience method called when using the environment as a context manager:\n\n    ```python\n    with environment: ...\n    ```\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.deactivate","title":"deactivate()","text":"

    A convenience method called after using the environment as a context manager:

    with environment: ...\n
    Source code in src/hatch/env/plugin/interface.py
    def deactivate(self):\n    \"\"\"\n    A convenience method called after using the environment as a context manager:\n\n    ```python\n    with environment: ...\n    ```\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.find","title":"find() abstractmethod","text":"

    REQUIRED

    This should return information about how to locate the environment or represent its ID in some way. Additionally, this is expected to return something even if the environment is incompatible.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef find(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should return information about how to locate the environment or represent its ID in\n    some way. Additionally, this is expected to return something even if the environment is\n    [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.create","title":"create() abstractmethod","text":"

    REQUIRED

    This should perform the necessary steps to set up the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef create(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should perform the necessary steps to set up the environment.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.remove","title":"remove() abstractmethod","text":"

    REQUIRED

    This should perform the necessary steps to completely remove the environment from the system and will only be triggered manually by users with the env remove or env prune commands.

    If the build environment has a caching mechanism, this should remove that as well.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef remove(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should perform the necessary steps to completely remove the environment from the system and will only\n    be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n    [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n\n    If the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    has a caching mechanism, this should remove that as well.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.exists","title":"exists() -> bool abstractmethod","text":"

    REQUIRED

    This should indicate whether or not the environment has already been created.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef exists(self) -> bool:\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should indicate whether or not the environment has already been created.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project","title":"install_project() abstractmethod","text":"

    REQUIRED

    This should install the project in the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef install_project(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the project in the environment.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project_dev_mode","title":"install_project_dev_mode() abstractmethod","text":"

    REQUIRED

    This should install the project in the environment such that the environment always reflects the current state of the project.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef install_project_dev_mode(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the project in the environment such that the environment\n    always reflects the current state of the project.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync","title":"dependencies_in_sync() -> bool abstractmethod","text":"

    REQUIRED

    This should indicate whether or not the environment is compatible with the current dependencies.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef dependencies_in_sync(self) -> bool:\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should indicate whether or not the environment is compatible with the current\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies","title":"sync_dependencies() abstractmethod","text":"

    REQUIRED

    This should install the dependencies in the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef sync_dependencies(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n    in the environment.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependency_hash","title":"dependency_hash()","text":"

    This should return a hash of the environment's dependencies and any other data that is handled by the sync_dependencies and dependencies_in_sync methods.

    Source code in src/hatch/env/plugin/interface.py
    def dependency_hash(self):\n    \"\"\"\n    This should return a hash of the environment's\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n    and any other data that is handled by the\n    [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n    and\n    [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n    methods.\n    \"\"\"\n    from hatch.utils.dep import hash_dependencies\n\n    return hash_dependencies(self.dependencies_complex)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.build_environment","title":"build_environment(dependencies: list[str])","text":"

    This should set up an isolated environment in which to build the project given a set of dependencies and must be a context manager:

    with environment.build_environment([...]): ...\n

    The build environment should reflect any environment variables the user defined either currently or at the time of creation.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef build_environment(\n    self,\n    dependencies: list[str],  # noqa: ARG002\n):\n    \"\"\"\n    This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project\n    given a set of dependencies and must be a context manager:\n\n    ```python\n    with environment.build_environment([...]): ...\n    ```\n\n    The build environment should reflect any\n    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n    the user defined either currently or at the time of\n    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n    \"\"\"\n    with self.get_env_vars():\n        yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.build_environment_exists","title":"build_environment_exists()","text":"

    If the build environment has a caching mechanism, this should indicate whether or not it has already been created.

    Source code in src/hatch/env/plugin/interface.py
    def build_environment_exists(self):  # noqa: PLR6301\n    \"\"\"\n    If the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    has a caching mechanism, this should indicate whether or not it has already been created.\n    \"\"\"\n    return False\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.run_builder","title":"run_builder(build_environment, **kwargs)","text":"

    This will be called when the build environment is active:

    with environment.build_environment([...]) as build_env:\n    process = environment.run_builder(build_env, ...)\n

    This should return the standard library's subprocess.CompletedProcess. The command is constructed by passing all keyword arguments to construct_build_command.

    For an example, open the default implementation below:

    Source code in src/hatch/env/plugin/interface.py
    def run_builder(\n    self,\n    build_environment,  # noqa: ARG002\n    **kwargs,\n):\n    \"\"\"\n    This will be called when the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    is active:\n\n    ```python\n    with environment.build_environment([...]) as build_env:\n        process = environment.run_builder(build_env, ...)\n    ```\n\n    This should return the standard library's\n    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).\n    The command is constructed by passing all keyword arguments to\n    [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).\n\n    For an example, open the default implementation below:\n    \"\"\"\n    return self.platform.run_command(self.construct_build_command(**kwargs))\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command","title":"construct_build_command(*, directory=None, targets=(), hooks_only=False, no_hooks=False, clean=False, clean_hooks_after=False, clean_only=False)","text":"

    This is the canonical way build command options are translated to a subprocess command issued to builders.

    Source code in src/hatch/env/plugin/interface.py
    def construct_build_command(  # noqa: PLR6301\n    self,\n    *,\n    directory=None,\n    targets=(),\n    hooks_only=False,\n    no_hooks=False,\n    clean=False,\n    clean_hooks_after=False,\n    clean_only=False,\n):\n    \"\"\"\n    This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to\n    a subprocess command issued to [builders](../builder/reference.md).\n    \"\"\"\n    command = ['python', '-u', '-m', 'hatchling', 'build']\n\n    if directory:\n        command.extend(('--directory', directory))\n\n    if targets:\n        for target in targets:\n            command.extend(('--target', target))\n\n    if hooks_only:\n        command.append('--hooks-only')\n\n    if no_hooks:\n        command.append('--no-hooks')\n\n    if clean:\n        command.append('--clean')\n\n    if clean_hooks_after:\n        command.append('--clean-hooks-after')\n\n    if clean_only:\n        command.append('--clean-only')\n\n    return command\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.command_context","title":"command_context()","text":"

    A context manager that when active should make executed shell commands reflect any environment variables the user defined either currently or at the time of creation.

    For an example, open the default implementation below:

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef command_context(self):\n    \"\"\"\n    A context manager that when active should make executed shell commands reflect any\n    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n    the user defined either currently or at the time of\n    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n    For an example, open the default implementation below:\n    \"\"\"\n    with self.get_env_vars():\n        yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.enter_shell","title":"enter_shell(name: str, path: str, args: Iterable[str])","text":"

    Spawn a shell within the environment.

    This should either use command_context directly or provide the same guarantee.

    Source code in src/hatch/env/plugin/interface.py
    def enter_shell(\n    self,\n    name: str,  # noqa: ARG002\n    path: str,\n    args: Iterable[str],\n):\n    \"\"\"\n    Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n    This should either use\n    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n    directly or provide the same guarantee.\n    \"\"\"\n    with self.command_context():\n        self.platform.exit_with_command([path, *args])\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.run_shell_command","title":"run_shell_command(command: str, **kwargs)","text":"

    This should return the standard library's subprocess.CompletedProcess and will always be called when the command_context is active, with the expectation of providing the same guarantee.

    Source code in src/hatch/env/plugin/interface.py
    def run_shell_command(self, command: str, **kwargs):\n    \"\"\"\n    This should return the standard library's\n    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n    and will always be called when the\n    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n    is active, with the expectation of providing the same guarantee.\n    \"\"\"\n    kwargs.setdefault('shell', True)\n    return self.platform.run_command(command, **kwargs)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.resolve_commands","title":"resolve_commands(commands: list[str])","text":"

    This expands each command into one or more commands based on any scripts that the user defined.

    Source code in src/hatch/env/plugin/interface.py
    def resolve_commands(self, commands: list[str]):\n    \"\"\"\n    This expands each command into one or more commands based on any\n    [scripts](../../config/environment/overview.md#scripts) that the user defined.\n    \"\"\"\n    for command in commands:\n        yield from self.expand_command(command)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars","title":"get_env_vars() -> EnvVars","text":"

    Returns a mapping of environment variables that should be available to the environment. The object can be used as a context manager to temporarily apply the environment variables to the current process.

    Note

    The environment variable HATCH_ENV_ACTIVE will always be set to the name of the environment.

    Source code in src/hatch/env/plugin/interface.py
    def get_env_vars(self) -> EnvVars:\n    \"\"\"\n    Returns a mapping of environment variables that should be available to the environment. The object can\n    be used as a context manager to temporarily apply the environment variables to the current process.\n\n    !!! note\n        The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n    \"\"\"\n    return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.apply_features","title":"apply_features(requirement: str)","text":"

    A convenience method that applies any user defined features to the given requirement.

    Source code in src/hatch/env/plugin/interface.py
    def apply_features(self, requirement: str):\n    \"\"\"\n    A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n    to the given requirement.\n    \"\"\"\n    if self.features:\n        features = ','.join(self.features)\n        return f'{requirement}[{features}]'\n\n    return requirement\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.construct_pip_install_command","title":"construct_pip_install_command(args: list[str])","text":"

    A convenience method for constructing a pip install command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.

    Source code in src/hatch/env/plugin/interface.py
    def construct_pip_install_command(self, args: list[str]):\n    \"\"\"\n    A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n    command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n    \"\"\"\n    command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n    # Default to -1 verbosity\n    add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n    command.extend(args)\n    return command\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.join_command_args","title":"join_command_args(args: list[str])","text":"

    This is used by the run command to construct the root command string from the received arguments.

    Source code in src/hatch/env/plugin/interface.py
    def join_command_args(self, args: list[str]):\n    \"\"\"\n    This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n    from the received arguments.\n    \"\"\"\n    return self.platform.join_command_args(args)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility","title":"check_compatibility()","text":"

    This raises an exception if the environment is not compatible with the user's setup. The default behavior checks for platform compatibility and any method override should keep this check.

    This check is never performed if the environment has been created.

    Source code in src/hatch/env/plugin/interface.py
    def check_compatibility(self):\n    \"\"\"\n    This raises an exception if the environment is not compatible with the user's setup. The default behavior\n    checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n    and any method override should keep this check.\n\n    This check is never performed if the environment has been\n    [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n    \"\"\"\n    if self.platforms and self.platform.name not in self.platforms:\n        message = 'unsupported platform'\n        raise OSError(message)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_option_types","title":"get_option_types() -> dict staticmethod","text":"

    Returns a mapping of supported options to their respective types so that they can be used by overrides.

    Source code in src/hatch/env/plugin/interface.py
    @staticmethod\ndef get_option_types() -> dict:\n    \"\"\"\n    Returns a mapping of supported options to their respective types so that they can be used by\n    [overrides](../../config/environment/advanced.md#option-overrides).\n    \"\"\"\n    return {}\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_var_option","title":"get_env_var_option(option: str) -> str","text":"

    Returns the value of the upper-cased environment variable HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>.

    Source code in src/hatch/env/plugin/interface.py
    def get_env_var_option(self, option: str) -> str:\n    \"\"\"\n    Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n    \"\"\"\n    return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_context","title":"get_context()","text":"

    Returns a subclass of EnvironmentContextFormatter.

    Source code in src/hatch/env/plugin/interface.py
    def get_context(self):\n    \"\"\"\n    Returns a subclass of\n    [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n    \"\"\"\n    from hatch.env.context import EnvironmentContextFormatter\n\n    return EnvironmentContextFormatter(self)\n
    "},{"location":"plugins/environment/virtual/","title":"Virtual environment","text":"

    This uses virtual environments backed by the standard virtualenv tool.

    "},{"location":"plugins/environment/virtual/#configuration","title":"Configuration","text":"

    The environment plugin name is virtual.

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\ntype = \"virtual\"\n
    [envs.<ENV_NAME>]\ntype = \"virtual\"\n
    "},{"location":"plugins/environment/virtual/#options","title":"Options","text":"Option Default Description python The version of Python to find on your system and subsequently use to create the environment, defaulting to the HATCH_PYTHON environment variable, followed by the normal resolution logic. Setting the HATCH_PYTHON environment variable to self will force the use of the Python executable Hatch is running on. For more information, see the documentation. python-sources ['external', 'internal'] This may be set to an array of strings that are either the literal internal or external. External considers only Python executables that are already on PATH. Internal considers only internally managed Python distributions. path An explicit path to the virtual environment. The path may be absolute or relative to the project root. Any environments that inherit this option will also use this path. The environment variable HATCH_ENV_TYPE_VIRTUAL_PATH may be used, which will take precedence. system-packages false Whether or not to give the virtual environment access to the system site-packages directory"},{"location":"plugins/environment/virtual/#location","title":"Location","text":"

    The location of environments is determined in the following heuristic order:

    1. The path option
    2. A directory named after the environment within the configured virtual environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
    3. Otherwise, environments are stored within the configured virtual environment directory in a deeply nested structure in order to support multiple projects

    Additionally, when the path option is not used, the name of the directory for the default environment will be the normalized project name to provide a more meaningful default shell prompt.

    "},{"location":"plugins/environment/virtual/#python-resolution","title":"Python resolution","text":"

    Virtual environments necessarily require a parent installation of Python. The following rules determine how the parent is resolved.

    The Python choice is determined by the python option followed by the HATCH_PYTHON environment variable. If the choice is via the environment variable, then resolution stops and that path is used unconditionally.

    The resolvers will be based on the python-sources option and all resolved interpreters will ensure compatibility with the project's defined Python support.

    If a Python version has been chosen then each resolver will try to find an interpreter that satisfies that version.

    If no version has been chosen, then each resolver will try to find a version that matches the version of Python that Hatch is currently running on. If not found then each resolver will try to find the highest compatible version.

    Note

    Some external Python paths are considered unstable and are ignored during resolution. For example, if Hatch is installed via Homebrew then sys.executable will be ignored because the interpreter could change or be removed at any time.

    Note

    When resolution finds a match using an internally managed distribution and an update is available, the latest distribution will automatically be downloaded before environment creation.

    "},{"location":"plugins/environment/virtual/#internal-distributions","title":"Internal distributions","text":"

    The following options are recognized for internal Python resolution.

    "},{"location":"plugins/environment/virtual/#cpython","title":"CPython","text":"ID 3.7 3.8 3.9 3.10 3.11 3.12

    The source of distributions is the python-build-standalone project.

    Some distributions have variants that may be configured with the HATCH_PYTHON_VARIANT_<PLATFORM> environment variable where <PLATFORM> is the uppercase version of one of the following:

    Platform Options Linux
    • v1
    • v2
    • v3 (default)
    • v4
    Windows
    • shared (default)
    • static
    "},{"location":"plugins/environment/virtual/#pypy","title":"PyPy","text":"ID pypy2.7 pypy3.9 pypy3.10

    The source of distributions is the PyPy project.

    "},{"location":"plugins/environment/virtual/#troubleshooting","title":"Troubleshooting","text":""},{"location":"plugins/environment/virtual/#macos-sip","title":"macOS SIP","text":"

    If you need to set linker environment variables like those starting with DYLD_ or LD_, any executable secured by System Integrity Protection that is invoked when running commands will not see those environment variable modifications as macOS strips those.

    Hatch interprets such commands as shell commands but deliberately ignores such paths to protected shells. This workaround suffices for the majority of use cases but there are 2 situations in which it may not:

    1. There are no unprotected sh, bash, zsh, nor fish executables found along PATH.
    2. The desired executable is a project's script, and the location of environments contains spaces or is longer than 1241 characters. In this case pip and other installers will create such an entry point with a shebang pointing to /bin/sh (which is protected) to avoid shebang limitations. Rather than changing the location, you could invoke the script as e.g. python -m pytest (if the project supports that method of invocation by shipping a __main__.py).
    1. The shebang length limit is usually 127 but 3 characters surround the executable path: #!<EXE_PATH>\\n \u21a9

    "},{"location":"plugins/environment-collector/custom/","title":"Custom environment collector","text":"

    This is a custom class in a given Python file that inherits from the EnvironmentCollectorInterface.

    "},{"location":"plugins/environment-collector/custom/#configuration","title":"Configuration","text":"

    The environment collector plugin name is custom.

    pyproject.toml hatch.toml
    [tool.hatch.env.collectors.custom]\n
    [env.collectors.custom]\n
    "},{"location":"plugins/environment-collector/custom/#options","title":"Options","text":"Option Default Description path hatch_plugins.py The path of the Python file"},{"location":"plugins/environment-collector/custom/#example","title":"Example","text":"hatch_plugins.py
        from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n    class CustomEnvironmentCollector(EnvironmentCollectorInterface):\n        ...\n

    If multiple subclasses are found, you must define a function named get_environment_collector that returns the desired environment collector.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    "},{"location":"plugins/environment-collector/default/","title":"Default environment collector","text":"

    This adds the default environment with type set to virtual and will always be applied.

    "},{"location":"plugins/environment-collector/default/#configuration","title":"Configuration","text":"

    The environment collector plugin name is default.

    pyproject.toml hatch.toml
    [tool.hatch.env.collectors.default]\n
    [env.collectors.default]\n
    "},{"location":"plugins/environment-collector/default/#options","title":"Options","text":"

    There are no options available currently.

    "},{"location":"plugins/environment-collector/reference/","title":"Environment collector plugins","text":"

    Environment collectors allow for dynamically modifying environments or adding environments beyond those defined in config. Users can override default values provided by each environment.

    "},{"location":"plugins/environment-collector/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-mkdocs - integrate MkDocs and infer dependencies into an env
    "},{"location":"plugins/environment-collector/reference/#installation","title":"Installation","text":"

    Any required environment collectors that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

    pyproject.toml hatch.toml
    [tool.hatch.env]\nrequires = [\n  \"...\",\n]\n
    [env]\nrequires = [\n  \"...\",\n]\n
    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface","title":"EnvironmentCollectorInterface","text":"

    Example usage:

    plugin.py hooks.py
        from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n    class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
        from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialEnvironmentCollector\n\n\n    @hookimpl\n    def hatch_register_environment_collector():\n        return SpecialEnvironmentCollector\n
    Source code in src/hatch/env/collectors/plugin/interface.py
    class EnvironmentCollectorInterface:\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n        class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialEnvironmentCollector\n\n\n        @hookimpl\n        def hatch_register_environment_collector():\n            return SpecialEnvironmentCollector\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root, config):\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.env.collectors.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    def get_initial_config(self) -> dict[str, dict]:  # noqa: PLR6301\n        \"\"\"\n        Returns configuration for environments keyed by the environment or matrix name.\n        \"\"\"\n        return {}\n\n    def finalize_config(self, config: dict[str, dict]):\n        \"\"\"\n        Finalizes configuration for environments keyed by the environment or matrix name. This will override\n        any user-defined settings and any collectors that ran before this call.\n\n        This is called before matrices are turned into concrete environments.\n        \"\"\"\n\n    def finalize_environments(self, config: dict[str, dict]):\n        \"\"\"\n        Finalizes configuration for environments keyed by the environment name. This will override\n        any user-defined settings and any collectors that ran before this call.\n\n        This is called after matrices are turned into concrete environments.\n        \"\"\"\n
    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.root","title":"root property","text":"

    The root of the project tree as a path-like object.

    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.env.collectors.<PLUGIN_NAME>]\n
    [env.collectors.<PLUGIN_NAME>]\n
    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.get_initial_config","title":"get_initial_config() -> dict[str, dict]","text":"

    Returns configuration for environments keyed by the environment or matrix name.

    Source code in src/hatch/env/collectors/plugin/interface.py
    def get_initial_config(self) -> dict[str, dict]:  # noqa: PLR6301\n    \"\"\"\n    Returns configuration for environments keyed by the environment or matrix name.\n    \"\"\"\n    return {}\n
    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_config","title":"finalize_config(config: dict[str, dict])","text":"

    Finalizes configuration for environments keyed by the environment or matrix name. This will override any user-defined settings and any collectors that ran before this call.

    This is called before matrices are turned into concrete environments.

    Source code in src/hatch/env/collectors/plugin/interface.py
    def finalize_config(self, config: dict[str, dict]):\n    \"\"\"\n    Finalizes configuration for environments keyed by the environment or matrix name. This will override\n    any user-defined settings and any collectors that ran before this call.\n\n    This is called before matrices are turned into concrete environments.\n    \"\"\"\n
    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_environments","title":"finalize_environments(config: dict[str, dict])","text":"

    Finalizes configuration for environments keyed by the environment name. This will override any user-defined settings and any collectors that ran before this call.

    This is called after matrices are turned into concrete environments.

    Source code in src/hatch/env/collectors/plugin/interface.py
    def finalize_environments(self, config: dict[str, dict]):\n    \"\"\"\n    Finalizes configuration for environments keyed by the environment name. This will override\n    any user-defined settings and any collectors that ran before this call.\n\n    This is called after matrices are turned into concrete environments.\n    \"\"\"\n
    "},{"location":"plugins/metadata-hook/custom/","title":"Custom metadata hook","text":"

    This is a custom class in a given Python file that inherits from the MetadataHookInterface.

    "},{"location":"plugins/metadata-hook/custom/#configuration","title":"Configuration","text":"

    The metadata hook plugin name is custom.

    pyproject.toml hatch.toml
    [tool.hatch.metadata.hooks.custom]\n
    [metadata.hooks.custom]\n
    "},{"location":"plugins/metadata-hook/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/metadata-hook/custom/#example","title":"Example","text":"hatch_build.py
        from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\n    class CustomMetadataHook(MetadataHookInterface):\n        ...\n

    If multiple subclasses are found, you must define a function named get_metadata_hook that returns the desired build hook.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    "},{"location":"plugins/metadata-hook/reference/","title":"Metadata hook plugins","text":"

    Metadata hooks allow for the modification of project metadata after it has been loaded.

    "},{"location":"plugins/metadata-hook/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-docstring-description - set the project description using docstrings
    • hatch-fancy-pypi-readme - dynamically construct the README
    • hatch-nodejs-version - uses fields from NodeJS package.json files
    • hatch-odoo - determine dependencies based on manifests of Odoo add-ons
    • hatch-requirements-txt - read project dependencies from requirements.txt files
    • UniDep - for unified pip and conda dependency management using a single requirements.yaml file for both
    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface","title":"MetadataHookInterface","text":"

    Example usage:

    plugin.py hooks.py
    from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass SpecialMetadataHook(MetadataHookInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialMetadataHook\n\n\n@hookimpl\ndef hatch_register_metadata_hook():\n    return SpecialMetadataHook\n
    Source code in backend/src/hatchling/metadata/plugin/interface.py
    class MetadataHookInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\n    class SpecialMetadataHook(MetadataHookInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialMetadataHook\n\n\n    @hookimpl\n    def hatch_register_metadata_hook():\n        return SpecialMetadataHook\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        The hook configuration.\n\n        ```toml config-example\n        [tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def update(self, metadata: dict) -> None:\n        \"\"\"\n        This updates the metadata mapping of the `project` table in-place.\n        \"\"\"\n\n    def get_known_classifiers(self) -> list[str]:  # noqa: PLR6301\n        \"\"\"\n        This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n        \"\"\"\n        return []\n
    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.root","title":"root: str property","text":"

    The root of the project tree.

    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.config","title":"config: dict property","text":"

    The hook configuration.

    pyproject.toml hatch.toml
    [tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n
    [metadata.hooks.<PLUGIN_NAME>]\n
    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.update","title":"update(metadata: dict) -> None abstractmethod","text":"

    This updates the metadata mapping of the project table in-place.

    Source code in backend/src/hatchling/metadata/plugin/interface.py
    @abstractmethod\ndef update(self, metadata: dict) -> None:\n    \"\"\"\n    This updates the metadata mapping of the `project` table in-place.\n    \"\"\"\n
    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.get_known_classifiers","title":"get_known_classifiers() -> list[str]","text":"

    This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.

    Source code in backend/src/hatchling/metadata/plugin/interface.py
    def get_known_classifiers(self) -> list[str]:  # noqa: PLR6301\n    \"\"\"\n    This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n    \"\"\"\n    return []\n
    "},{"location":"plugins/publisher/package-index/","title":"Index publisher","text":"

    See the documentation for publishing.

    "},{"location":"plugins/publisher/package-index/#configuration","title":"Configuration","text":"

    The publisher plugin name is index.

    config.toml
    [publish.index]\n
    "},{"location":"plugins/publisher/package-index/#options","title":"Options","text":"Flag Config name Description -r/--repo repo The repository with which to publish artifacts -u/--user user The user with which to authenticate -a/--auth auth The credentials to use for authentication --ca-cert ca-cert The path to a CA bundle --client-cert client-cert The path to a client certificate, optionally containing the private key --client-key client-key The path to the client certificate's private key repos A table of named repositories to their respective options"},{"location":"plugins/publisher/package-index/#repositories","title":"Repositories","text":"

    All top-level options can be overridden per repository using the repos table with a required url attribute for each repository. The following shows the default configuration:

    config.toml
    [publish.index.repos.main]\nurl = \"https://upload.pypi.org/legacy/\"\n\n[publish.index.repos.test]\nurl = \"https://test.pypi.org/legacy/\"\n

    The repo and repos options have no effect.

    "},{"location":"plugins/publisher/reference/","title":"Publisher plugins","text":""},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface","title":"PublisherInterface","text":"

    Example usage:

    plugin.py hooks.py
        from hatch.publish.plugin.interface import PublisherInterface\n\n\n    class SpecialPublisher(PublisherInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
        from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialPublisher\n\n\n    @hookimpl\n    def hatch_register_publisher():\n        return SpecialPublisher\n
    Source code in src/hatch/publish/plugin/interface.py
    class PublisherInterface(ABC):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.publish.plugin.interface import PublisherInterface\n\n\n        class SpecialPublisher(PublisherInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialPublisher\n\n\n        @hookimpl\n        def hatch_register_publisher():\n            return SpecialPublisher\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, app, root, cache_dir, project_config, plugin_config):\n        self.__app = app\n        self.__root = root\n        self.__cache_dir = cache_dir\n        self.__project_config = project_config\n        self.__plugin_config = plugin_config\n\n        self.__disable = None\n\n    @property\n    def app(self):\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        return self.__app\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def cache_dir(self):\n        \"\"\"\n        The directory reserved exclusively for this plugin as a path-like object.\n        \"\"\"\n        return self.__cache_dir\n\n    @property\n    def project_config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.publish.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__project_config\n\n    @property\n    def plugin_config(self) -> dict:\n        \"\"\"\n        This is defined in Hatch's [config file](../../config/hatch.md).\n\n        ```toml tab=\"config.toml\"\n        [publish.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__plugin_config\n\n    @property\n    def disable(self):\n        \"\"\"\n        Whether this plugin is disabled, thus requiring confirmation when publishing. Local\n        [project configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.project_config)\n        takes precedence over global\n        [plugin configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.plugin_config).\n        \"\"\"\n        if self.__disable is None:\n            if 'disable' in self.project_config:\n                disable = self.project_config['disable']\n                if not isinstance(disable, bool):\n                    message = f'Field `tool.hatch.publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n                    raise TypeError(message)\n            else:\n                disable = self.plugin_config.get('disable', False)\n                if not isinstance(disable, bool):\n                    message = f'Global plugin configuration `publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n                    raise TypeError(message)\n\n            self.__disable = disable\n\n        return self.__disable\n\n    @abstractmethod\n    def publish(self, artifacts: list[str], options: dict):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n        with the arguments and options it receives.\n        \"\"\"\n
    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.app","title":"app property","text":"

    An instance of Application.

    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.root","title":"root property","text":"

    The root of the project tree as a path-like object.

    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.cache_dir","title":"cache_dir property","text":"

    The directory reserved exclusively for this plugin as a path-like object.

    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.project_config","title":"project_config: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.publish.<PLUGIN_NAME>]\n
    [publish.<PLUGIN_NAME>]\n
    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.plugin_config","title":"plugin_config: dict property","text":"

    This is defined in Hatch's config file.

    config.toml
    [publish.<PLUGIN_NAME>]\n
    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.disable","title":"disable property","text":"

    Whether this plugin is disabled, thus requiring confirmation when publishing. Local project configuration takes precedence over global plugin configuration.

    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.publish","title":"publish(artifacts: list[str], options: dict) abstractmethod","text":"

    REQUIRED

    This is called directly by the publish command with the arguments and options it receives.

    Source code in src/hatch/publish/plugin/interface.py
    @abstractmethod\ndef publish(self, artifacts: list[str], options: dict):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n    with the arguments and options it receives.\n    \"\"\"\n
    "},{"location":"plugins/version-scheme/reference/","title":"Version scheme plugins","text":""},{"location":"plugins/version-scheme/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-semver - uses semantic versioning
    "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface","title":"VersionSchemeInterface","text":"

    Example usage:

    plugin.py hooks.py
    from hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\nclass SpecialVersionScheme(VersionSchemeInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionScheme\n\n\n@hookimpl\ndef hatch_register_version_scheme():\n    return SpecialVersionScheme\n
    Source code in backend/src/hatchling/version/scheme/plugin/interface.py
    class VersionSchemeInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\n    class SpecialVersionScheme(VersionSchemeInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialVersionScheme\n\n\n    @hookimpl\n    def hatch_register_version_scheme():\n        return SpecialVersionScheme\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree as a string.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.version]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n        \"\"\"\n        This should return a normalized form of the desired version and verify that it\n        is higher than the original version.\n        \"\"\"\n
    "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.root","title":"root: str property","text":"

    The root of the project tree as a string.

    "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.version]\n
    [version]\n
    "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.update","title":"update(desired_version: str, original_version: str, version_data: dict) -> str abstractmethod","text":"

    This should return a normalized form of the desired version and verify that it is higher than the original version.

    Source code in backend/src/hatchling/version/scheme/plugin/interface.py
    @abstractmethod\ndef update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n    \"\"\"\n    This should return a normalized form of the desired version and verify that it\n    is higher than the original version.\n    \"\"\"\n
    "},{"location":"plugins/version-scheme/standard/","title":"Standard version scheme","text":"

    See the documentation for versioning.

    "},{"location":"plugins/version-scheme/standard/#configuration","title":"Configuration","text":"

    The version scheme plugin name is standard.

    pyproject.toml hatch.toml
    [tool.hatch.version]\nscheme = \"standard\"\n
    [version]\nscheme = \"standard\"\n
    "},{"location":"plugins/version-scheme/standard/#options","title":"Options","text":"Option Description validate-bump When setting a specific version, this determines whether to check that the new version is higher than the original. The default is true."},{"location":"plugins/version-source/code/","title":"Code version source","text":""},{"location":"plugins/version-source/code/#updates","title":"Updates","text":"

    Setting the version is not supported.

    "},{"location":"plugins/version-source/code/#configuration","title":"Configuration","text":"

    The version source plugin name is code.

    pyproject.toml hatch.toml
    [tool.hatch.version]\nsource = \"code\"\n
    [version]\nsource = \"code\"\n
    "},{"location":"plugins/version-source/code/#options","title":"Options","text":"Option Description path (required) A relative path to a Python file or extension module that will be loaded expression A Python expression that when evaluated in the context of the loaded file returns the version. The default expression is simply __version__. search-paths A list of relative paths to directories that will be prepended to Python's search path"},{"location":"plugins/version-source/code/#missing-imports","title":"Missing imports","text":"

    If the chosen path imports another module in your project, then you'll need to use absolute imports coupled with the search-paths option. For example, say you need to load the following file:

    src/pkg/__init__.py
        from ._version import get_version\n\n    __version__ = get_version()\n

    You should change it to:

    src/pkg/__init__.py
        from pkg._version import get_version\n\n    __version__ = get_version()\n

    and the configuration would become:

    pyproject.toml hatch.toml
    [tool.hatch.version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
    [version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
    "},{"location":"plugins/version-source/env/","title":"Environment version source","text":"

    Retrieves the version from an environment variable. This can be useful in build pipelines where the version is set by an external trigger.

    "},{"location":"plugins/version-source/env/#updates","title":"Updates","text":"

    Setting the version is not supported.

    "},{"location":"plugins/version-source/env/#configuration","title":"Configuration","text":"

    The version source plugin name is env.

    pyproject.toml hatch.toml
    [tool.hatch.version]\nsource = \"env\"\n
    [version]\nsource = \"env\"\n
    "},{"location":"plugins/version-source/env/#options","title":"Options","text":"Option Description variable (required) The name of the environment variable"},{"location":"plugins/version-source/reference/","title":"Version source plugins","text":""},{"location":"plugins/version-source/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-vcs - uses your preferred version control system (like Git)
    • hatch-nodejs-version - uses the version field of NodeJS package.json files
    • hatch-regex-commit - automatically creates a Git commit and tag after version bumping
    • versioningit - determines version from Git or Mercurial tags, with customizable version formatting
    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface","title":"VersionSourceInterface","text":"

    Example usage:

    plugin.py hooks.py
    from hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\nclass SpecialVersionSource(VersionSourceInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionSource\n\n\n@hookimpl\ndef hatch_register_version_source():\n    return SpecialVersionSource\n
    Source code in backend/src/hatchling/version/source/plugin/interface.py
    class VersionSourceInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\n    class SpecialVersionSource(VersionSourceInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialVersionSource\n\n\n    @hookimpl\n    def hatch_register_version_source():\n        return SpecialVersionSource\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree as a string.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.version]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def get_version_data(self) -> dict:\n        \"\"\"\n        This should return a mapping with a `version` key representing the current version of the project and will be\n        displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n        The mapping can contain anything else and will be passed to\n        [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n        when updating the version.\n        \"\"\"\n\n    def set_version(self, version: str, version_data: dict) -> None:\n        \"\"\"\n        This should update the version to the first argument with the data provided during retrieval.\n        \"\"\"\n        raise NotImplementedError\n
    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.root","title":"root: str property","text":"

    The root of the project tree as a string.

    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.version]\n
    [version]\n
    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.get_version_data","title":"get_version_data() -> dict abstractmethod","text":"

    This should return a mapping with a version key representing the current version of the project and will be displayed when invoking the version command without any arguments.

    The mapping can contain anything else and will be passed to set_version when updating the version.

    Source code in backend/src/hatchling/version/source/plugin/interface.py
    @abstractmethod\ndef get_version_data(self) -> dict:\n    \"\"\"\n    This should return a mapping with a `version` key representing the current version of the project and will be\n    displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n    The mapping can contain anything else and will be passed to\n    [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n    when updating the version.\n    \"\"\"\n
    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version","title":"set_version(version: str, version_data: dict) -> None","text":"

    This should update the version to the first argument with the data provided during retrieval.

    Source code in backend/src/hatchling/version/source/plugin/interface.py
    def set_version(self, version: str, version_data: dict) -> None:\n    \"\"\"\n    This should update the version to the first argument with the data provided during retrieval.\n    \"\"\"\n    raise NotImplementedError\n
    "},{"location":"plugins/version-source/regex/","title":"Regex version source","text":"

    See the documentation for versioning.

    "},{"location":"plugins/version-source/regex/#updates","title":"Updates","text":"

    Setting the version is supported.

    "},{"location":"plugins/version-source/regex/#configuration","title":"Configuration","text":"

    The version source plugin name is regex.

    pyproject.toml hatch.toml
    [tool.hatch.version]\nsource = \"regex\"\n
    [version]\nsource = \"regex\"\n
    "},{"location":"plugins/version-source/regex/#options","title":"Options","text":"Option Description path (required) A relative path to a file containing the project's version pattern A regular expression that has a named group called version that represents the version. The default pattern looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v."},{"location":"blog/archive/2023/","title":"2023","text":""},{"location":"blog/archive/2022/","title":"2022","text":""},{"location":"blog/category/release/","title":"Release","text":""}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Hatch","text":"CI/CD Docs Package Meta

    Hatch is a modern, extensible Python project manager. See the Why Hatch? page for more information.

    • Build system

      Reproducible builds by default with a rich ecosystem of plugins

      Configure builds

    • Environments

      Robust environment management with support for custom scripts

      Getting started

    • Python management

      Choose between easy manual installations or automatic as part of environments

      Try it

    • Static analysis

      Static analysis backed by Ruff with up-to-date, sane defaults

      Learn

    • Publishing

      Easily upload to PyPI or other indices

      See how

    • Versioning

      Streamlined workflow for bumping versions

      Managing versions

    • Project generation

      Create new projects from templates with known best practices

      Project setup

    • Responsive CLI

      Hatch is up to 3x faster than equivalent tools

      CLI reference

    "},{"location":"#license","title":"License","text":"

    Hatch is distributed under the terms of the MIT license.

    "},{"location":"#navigation","title":"Navigation","text":"

    Documentation for specific MAJOR.MINOR versions can be chosen by using the dropdown on the top of every page. The dev version reflects changes that have not yet been released.

    Also, desktop readers can use special keyboard shortcuts:

    Keys Action
    • , (comma)
    • p
    Navigate to the \"previous\" page
    • . (period)
    • n
    Navigate to the \"next\" page
    • /
    • s
    Display the search modal"},{"location":"build/","title":"Builds","text":""},{"location":"build/#configuration","title":"Configuration","text":"

    Builds are configured using the tool.hatch.build table. Every target is defined by a section within tool.hatch.build.targets, for example:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.sdist]\nexclude = [\n  \"/.github\",\n  \"/docs\",\n]\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
    [build.targets.sdist]\nexclude = [\n  \"/.github\",\n  \"/docs\",\n]\n\n[build.targets.wheel]\npackages = [\"src/foo\"]\n
    "},{"location":"build/#building","title":"Building","text":"

    Invoking the build command without any arguments will build the sdist and wheel targets:

    $ hatch build\n[sdist]\ndist/hatch_demo-1rc0.tar.gz\n\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n

    To only build specific targets, use the -t/--target option:

    $ hatch build -t wheel\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n

    If the target supports multiple versions, you can specify the exact versions to build by appending a colon followed by the desired versions separated by commas:

    $ hatch -v build -t wheel:standard\n[wheel]\nBuilding `wheel` version `standard`\ndist/hatch_demo-1rc0-py3-none-any.whl\n
    "},{"location":"build/#packaging-ecosystem","title":"Packaging ecosystem","text":"

    Hatch complies with modern Python packaging specs and therefore your projects can be used by other tools with Hatch serving as just the build backend.

    So you could use tox as an alternative to Hatch's environment management, or cibuildwheel to distribute packages for every platform, and they both will transparently use Hatch without any extra modification.

    "},{"location":"environment/","title":"Environments","text":"

    Environments are designed to allow for isolated workspaces for testing, building documentation, or anything else projects need.

    Unless an environment is chosen explicitly, Hatch will use the default environment.

    Tip

    For a more comprehensive walk-through, see the Basic usage tutorial.

    "},{"location":"environment/#creation","title":"Creation","text":"

    You can create environments by using the env create command. Let's enter the directory of the project we created in the setup phase:

    $ hatch env create\nCreating environment: default\nInstalling project in development mode\nSyncing dependencies\n

    Tip

    You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.

    "},{"location":"environment/#entering-environments","title":"Entering environments","text":"

    You can spawn a shell within an environment by using the shell command.

    $ hatch shell\n(hatch-demo) $\n

    Now confirm the project has been installed:

    (hatch-demo) $ pip show hatch-demo\nName: hatch-demo\nVersion: 0.0.1\n...\n

    Finally, see where your environment's Python is located:

    (hatch-demo) $ python -c \"import sys;print(sys.executable)\"\n...\n

    You can type exit to leave the environment.

    "},{"location":"environment/#command-execution","title":"Command execution","text":"

    The run command allows you to execute commands in an environment as if you had already entered it. For example, running the following command will output the same path as before:

    hatch run python -c \"import sys;print(sys.executable)\"\n
    "},{"location":"environment/#scripts","title":"Scripts","text":"

    You can also run any scripts that have been defined.

    You'll notice that in the pyproject.toml file there are already scripts defined in the default environment. Try running the test command, which invokes pytest with some default arguments:

    hatch run test\n

    All additional arguments are passed through to that script, so for example if you wanted to see the version of pytest and which plugins are installed you could do:

    hatch run test -VV\n
    "},{"location":"environment/#dependencies","title":"Dependencies","text":"

    Hatch ensures that environments are always compatible with the currently defined project dependencies (if installed and in dev mode) and environment dependencies.

    To add cowsay as a dependency, open pyproject.toml and add it to the dependencies array:

    pyproject.toml
    [project]\n...\ndependencies = [\n  \"cowsay\"\n]\n

    This dependency will be installed the next time you spawn a shell or run a command. For example:

    $ hatch run cowsay -t \"Hello, world!\"\nSyncing dependencies\n  _____________\n| Hello, world! |\n  =============\n             \\\n              \\\n                ^__^\n                (oo)\\_______\n                (__)\\       )\\/\\\n                    ||----w |\n                    ||     ||\n

    Note

    The Syncing dependencies status will display temporarily when Hatch updates environments in response to any dependency changes that you make.

    "},{"location":"environment/#selection","title":"Selection","text":"

    You can select which environment to enter or run commands in by using the -e/--env root option or by setting the HATCH_ENV environment variable.

    The run command allows for more explicit selection by prepending <ENV_NAME>: to commands. For example, if you had the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[tool.hatch.envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n
    [envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n

    you could then serve your documentation by running:

    hatch run docs:serve\n

    Tip

    If you've already entered an environment, commands will target it by default.

    "},{"location":"environment/#matrix","title":"Matrix","text":"

    Every environment can define its own set of matrices:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
    [envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n

    Using the env show command would then display:

    $ hatch env show --ascii\n     Standalone\n+---------+---------+\n| Name    | Type    |\n+=========+=========+\n| default | virtual |\n+---------+---------+\n                       Matrices\n+------+---------+---------------------+--------------+\n| Name | Type    | Envs                | Dependencies |\n+======+=========+=====================+==============+\n| test | virtual | test.py2.7-42       | pytest       |\n|      |         | test.py2.7-3.14     |              |\n|      |         | test.py3.8-42       |              |\n|      |         | test.py3.8-3.14     |              |\n|      |         | test.py3.8-9000-foo |              |\n|      |         | test.py3.8-9000-bar |              |\n|      |         | test.py3.9-9000-foo |              |\n|      |         | test.py3.9-9000-bar |              |\n+------+---------+---------------------+--------------+\n
    "},{"location":"environment/#removal","title":"Removal","text":"

    You can remove a single environment or environment matrix by using the env remove command or all of a project's environments by using the env prune command.

    "},{"location":"install/","title":"Installation","text":""},{"location":"install/#installers","title":"Installers","text":"macOSWindows GUI installerCommand line installer
    1. In your browser, download the .pkg file: hatch-1.9.1.pkg
    2. Run your downloaded file and follow the on-screen instructions.
    3. Restart your terminal.
    4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

      $ hatch --version\n1.9.1\n
    1. Download the file using the curl command. The -o option specifies the file name that the downloaded package is written to. In this example, the file is written to hatch-1.9.1.pkg in the current directory.

      curl -o hatch-1.9.1.pkg https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1.pkg\n
    2. Run the standard macOS installer program, specifying the downloaded .pkg file as the source. Use the -pkg parameter to specify the name of the package to install, and the -target / parameter for the drive in which to install the package. The files are installed to /usr/local/hatch, and an entry is created at /etc/paths.d/hatch that instructs shells to add the /usr/local/hatch directory to. You must include sudo on the command to grant write permissions to those folders.

      sudo installer -pkg ./hatch-1.9.1.pkg -target /\n
    3. Restart your terminal.

    4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

      $ hatch --version\n1.9.1\n
    GUI installerCommand line installer
    1. In your browser, download one the .msi files:
      • hatch-1.9.1-x64.msi
    2. Run your downloaded file and follow the on-screen instructions.
    3. Restart your terminal.
    4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

      $ hatch --version\n1.9.1\n
    1. Download and run the installer using the standard Windows msiexec program, specifying one of the .msi files as the source. Use the /passive and /i parameters to request an unattended, normal installation.

      x64x86
      msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1-x64.msi\n
      msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1-x86.msi\n
    2. Restart your terminal.

    3. To verify that the shell can find and run the hatch command in your PATH, use the following command.

      $ hatch --version\n1.9.1\n
    "},{"location":"install/#standalone-binaries","title":"Standalone binaries","text":"

    After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to hatch.

    LinuxmacOSWindows
    • hatch-1.9.1-aarch64-unknown-linux-gnu.tar.gz
    • hatch-1.9.1-x86_64-unknown-linux-gnu.tar.gz
    • hatch-1.9.1-x86_64-unknown-linux-musl.tar.gz
    • hatch-1.9.1-i686-unknown-linux-gnu.tar.gz
    • hatch-1.9.1-powerpc64le-unknown-linux-gnu.tar.gz
    • hatch-1.9.1-aarch64-apple-darwin.tar.gz
    • hatch-1.9.1-x86_64-apple-darwin.tar.gz
    • hatch-1.9.1-x86_64-pc-windows-msvc.zip
    • hatch-1.9.1-i686-pc-windows-msvc.zip
    "},{"location":"install/#pip","title":"pip","text":"

    Hatch is available on PyPI and can be installed with pip.

    pip install hatch\n

    Warning

    This method modifies the Python environment in which you choose to install. Consider instead using pipx to avoid dependency conflicts.

    "},{"location":"install/#pipx","title":"pipx","text":"

    pipx allows for the global installation of Python applications in isolated environments.

    pipx install hatch\n
    "},{"location":"install/#homebrew","title":"Homebrew","text":"

    See the formula for more details.

    brew install hatch\n
    "},{"location":"install/#conda","title":"Conda","text":"

    See the feedstock for more details.

    conda install -c conda-forge hatch\n

    or with mamba:

    mamba install hatch\n

    Warning

    This method modifies the Conda environment in which you choose to install. Consider instead using pipx or condax to avoid dependency conflicts.

    "},{"location":"install/#macports","title":"MacPorts","text":"

    See the port for more details.

    sudo port install hatch\n
    "},{"location":"install/#fedora","title":"Fedora","text":"

    The minimum supported version is 37, currently in development as Rawhide.

    sudo dnf install hatch\n
    "},{"location":"install/#void-linux","title":"Void Linux","text":"
    xbps-install hatch\n
    "},{"location":"install/#build-system-availability","title":"Build system availability","text":"

    Hatchling is Hatch's build backend which you will never need to install manually. See its changelog for version information.

    "},{"location":"intro/","title":"Introduction","text":""},{"location":"intro/#setup","title":"Setup","text":"

    Projects can be set up for use by Hatch using the new command.

    "},{"location":"intro/#new-project","title":"New project","text":"

    Let's say you want to create a project named Hatch Demo. You would run:

    hatch new \"Hatch Demo\"\n

    This would create the following structure in your current working directory:

    hatch-demo\n\u251c\u2500\u2500 src\n\u2502   \u2514\u2500\u2500 hatch_demo\n\u2502       \u251c\u2500\u2500 __about__.py\n\u2502       \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 tests\n\u2502   \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 LICENSE.txt\n\u251c\u2500\u2500 README.md\n\u2514\u2500\u2500 pyproject.toml\n

    Tip

    There are many ways to customize project generation.

    "},{"location":"intro/#existing-project","title":"Existing project","text":"

    To initialize an existing project, enter the directory containing the project and run the following:

    hatch new --init\n

    If your project has a setup.py file the command will automatically migrate setuptools configuration for you. Otherwise, this will interactively guide you through the setup process.

    "},{"location":"intro/#project-metadata","title":"Project metadata","text":"

    Next you'll want to define more of your project's metadata located in the pyproject.toml file. You can specify things like its license, the supported versions of Python, and URLs referring to various parts of your project, like documentation.

    "},{"location":"intro/#dependencies","title":"Dependencies","text":"

    The last step of the setup process is to define any dependencies that you'd like your project to begin with.

    "},{"location":"intro/#configuration","title":"Configuration","text":"

    All project-specific configuration recognized by Hatch can be defined in either the pyproject.toml file, or a file named hatch.toml where options are not contained within the tool.hatch table:

    pyproject.toml hatch.toml
    [tool.hatch]\noption = \"...\"\n\n[tool.hatch.table1]\noption = \"...\"\n\n[tool.hatch.table2]\noption = \"...\"\n
    option = \"...\"\n\n[table1]\noption = \"...\"\n\n[table2]\noption = \"...\"\n

    Top level keys in the latter file take precedence when defined in both.

    Tip

    If you want to make your file more compact, you can use dotted keys, turning the above example into:

    pyproject.toml hatch.toml
    [tool.hatch]\noption = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
    option = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
    "},{"location":"next-steps/","title":"Next steps","text":""},{"location":"next-steps/#learn-more","title":"Learn more","text":"

    At this point you should have a basic understanding of how to use Hatch.

    Now you may want to check out advanced configuration for environments or builds, set up your preferred shell, or read more about Hatch's CLI.

    After that, check out the Hatch Showcase project to see examples of what is possible.

    Finally, if you see a need, feel free to write a plugin for extended functionality.

    "},{"location":"next-steps/#community","title":"Community","text":"

    For any projects using Hatch, you may add its official badge somewhere prominent like the README.

    MarkdownreStructuredText
    [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)\n
    .. image:: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg\n   :alt: Hatch project\n   :target: https://github.com/pypa/hatch\n
    "},{"location":"publish/","title":"Publishing","text":"

    After your project is built, you can distribute it using the publish command.

    The -p/--publisher option controls which publisher to use, with the default being index.

    "},{"location":"publish/#artifact-selection","title":"Artifact selection","text":"

    By default, the dist directory located at the root of your project will be used:

    $ hatch publish\ndist/hatch_demo-1rc0-py3-none-any.whl ... success\ndist/hatch_demo-1rc0.tar.gz ... success\n\n[hatch-demo]\nhttps://pypi.org/project/hatch-demo/1rc0/\n

    You can instead pass specific paths as arguments:

    hatch publish /path/to/artifacts foo-1.tar.gz\n

    Only files ending with .whl or .tar.gz will be published.

    "},{"location":"publish/#further-resources","title":"Further resources","text":"

    Please refer to the publisher plugin reference for configuration options.

    There's a How-To on authentication and on options to select the target repository.

    The publish command is implemented as a built-in plugin, if you're planning your own plugin, read about the publisher plugin API.

    "},{"location":"version/","title":"Versioning","text":""},{"location":"version/#configuration","title":"Configuration","text":"

    When the version is not statically set, configuration is defined in the tool.hatch.version table. The source option determines the source to use for retrieving and updating the version. The regex source is used by default.

    The regex source requires an option path that represents a relative path to a file containing the project's version:

    pyproject.toml hatch.toml
    [tool.hatch.version]\npath = \"src/hatch_demo/__about__.py\"\n
    [version]\npath = \"src/hatch_demo/__about__.py\"\n

    The default pattern looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v.

    If this doesn't reflect how you store the version, you can define a different regular expression using the pattern option:

    pyproject.toml hatch.toml
    [tool.hatch.version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n
    [version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n

    The pattern must have a named group called version that represents the version.

    "},{"location":"version/#display","title":"Display","text":"

    Invoking the version command without any arguments will display the current version of the project:

    $ hatch version\n0.0.1\n
    "},{"location":"version/#updating","title":"Updating","text":"

    You can update the version like so:

    $ hatch version \"0.1.0\"\nOld: 0.0.1\nNew: 0.1.0\n

    The scheme option determines the scheme to use for parsing both the existing and new versions. The standard scheme is used by default, which is based on PEP 440.

    Rather than setting the version explicitly, you can select the name of a segment used to increment the version:

    $ hatch version minor\nOld: 0.1.0\nNew: 0.2.0\n

    You can chain multiple segment updates with a comma. For example, if you wanted to release a preview of your project's first major version, you could do:

    $ hatch version major,rc\nOld: 0.2.0\nNew: 1.0.0rc0\n

    When you want to release the final version, you would do:

    $ hatch version release\nOld: 1.0.0rc0\nNew: 1.0.0\n
    "},{"location":"version/#supported-segments","title":"Supported segments","text":"

    Here are the supported segments and how they would influence an existing version of 1.0.0:

    Segments New version release 1.0.0 major 2.0.0 minor 1.1.0 micropatchfix 1.0.1 aalpha 1.0.0a0 bbeta 1.0.0b0 crcprepreview 1.0.0rc0 rrevpost 1.0.0.post0 dev 1.0.0.dev0"},{"location":"why/","title":"Why Hatch?","text":"

    The high level value proposition of Hatch is that if one adopts all functionality then many other tools become unnecessary since there is support for everything one might require. Further, if one chooses to use only specific features then there are still benefits compared to alternatives.

    "},{"location":"why/#build-backend","title":"Build backend","text":"

    Hatchling, the build backend sister project, has many benefits compared to setuptools. Here we only compare setuptools as that is the one most people are familiar with.

    • Better defaults: The default behavior for setuptools is often not desirable for the average user.
      • For source distributions, setuptools has a custom enumeration of files that get included and excluded by default. Hatchling takes the defaults from your version control system such as Git's .gitignore file.
      • For wheels, setuptools attempts to find every directory that looks like a Python package. This is often undesirable as you might ship files to the end-user unintentionally such as test or tooling directories. Hatchling defaults to very specific inclusion based on the project name and errors if no heuristic is satisfied.
    • Ease of configurability: Hatchling was designed based on a history of significant challenges when configuring setuptools.
      • Hatchling uses the same glob pattern syntax as Git itself for every option which is what most users are familiar with. On the other hand, setuptools uses shell-style glob patterns for source distributions while wheels use a mix of shell-style globs and Python package syntax.
      • Configuring what gets included in source distributions requires a separate MANIFEST.in file. The custom syntax and directives must be learned and it is difficult knowing which options in the main files like setup.py influence the behavior and under what conditions. For Hatchling, everything gets configured in a single file under dedicated sections for specific targets like [tool.hatch.build.targets.wheel].
      • By default, non-Python files are excluded from wheels. Including such files requires usually verbose rules for every nested package directory. Hatchling makes no such distinction between file types and acts more like a general build system one might already be familiar with.
    • Editable installations: The default behavior of Hatchling allows for proper static analysis by external tools such as IDEs. With setuptools, you must provide additional configuration which means that by default, for example, you would not get autocompletion in Visual Studio Code. This is marked as a legacy feature and may in fact be removed in future versions of setuptools.
    • Reproducibility: Hatchling builds reproducible wheels and source distributions by default. setuptools does not support this for source distributions and there is no guarantee that wheels are reproducible.
    • Extensibility: Although it is possible to extend setuptools, the API is quite low level. Hatchling has the concept of plugins that are separated into discrete types and only expose what is necessary, leading to an easier developer experience.

    Why not?:

    If building extension modules is required then it is recommended that you continue using setuptools, or even other backends that specialize in interfacing with compilers.

    "},{"location":"why/#environment-management","title":"Environment management","text":"

    Here we compare to both tox and nox. At a high level, there are a few common advantages:

    • Python management: Hatch is able to automatically download Python distributions on the fly when specific versions that environments request cannot be found. The alternatives will raise an error, with the option to ignore unknown distributions.
    • Philosophy: In the alternatives, environments are for the most part treated as executable units where a dependency set is associated with an action. If you are familiar with container ecosystems, this would be like defining a CMD at the end of a Dockerfile but without the ability to change the action at runtime. This involves significant wasted disk space usually because one often requires slight modifications to the actions and therefore will define entirely different environments inherited from a base config just to perform different logic. Additionally, this can be confusing to users not just configuration-wise but also for execution of the different environments.

      In Hatch, environments are treated as isolated areas where you can execute arbitrary commands at runtime. For example, you can define a single test environment with named scripts that runs unit vs non-unit tests, each command being potentially very long but named however you wish so you get to control the interface. Since environments are treated as places where work is performed, you can also spawn a shell into any which will execute a subprocess that automatically drops into your shell of choice. Your shell will be configured appropriately like python on PATH being updated and the prompt being changed to reflect the chosen environment.

    • Configuration:

      • tox only supports INI configuration and if one desires putting that in the standard pyproject.toml file then it must be a multi-line string containing the INI config which would preclude syntax highlighting. Hatch allows for TOML-based config just like most other tools in the Python ecosystem.
      • nox config is defined in Python which often leads to increased verbosity and makes it challenging to onboard folks compared to a standardized format with known behaviors.
    • Extensibility:
      • tox allows for extending most aspects of its functionality however the API is so low-level and attached to internals that creating plugins may be challenging. For example, here is a tox plugin that was migrated to an equivalent Hatch environment collector plugin.
      • nox is configured with Python so for the local project you can do whatever you want, however there is no concept of third-party plugins per se. To achieve that, you must usually use a package that wraps nox and use that package's imports instead (example).

    Why not?:

    If you are using nox and you wish to migrate, and for some reason you notify sessions, then migration wouldn't be a straight translation but rather you might have to redesign that conditional step.

    "},{"location":"why/#python-management","title":"Python management","text":"

    Here we compare Python management to that of pyenv.

    • Cross-platform: Hatch allows for the same experience no matter the system whereas pyenv does not support Windows so you must use an entirely different project that tries to emulate the functionality.
    • No build dependencies: Hatch guarantees that every available distribution is prebuilt whereas the alternative requires one to maintain a precise build environment which differs by platform and potentially Python version. Another benefit to this is extremely fast installations since the distributions are simply downloaded and unpacked.
    • Optimized by default: The CPython distributions are built with profile guided optimization and link-time optimization, resulting in a 10-30% performance improvement depending on the workload. These distributions have seen wide adoption throughout the industry and are even used by the build system Bazel.
    • Simplicity: Hatch treats Python installations as just another directory that one would add to PATH. It can do this for you or you can manage PATH yourself, even allowing for custom install locations. On the other hand, pyenv operates by adding shims which then act as wrappers around the actual underlying binaries. This has many unfortunate side effects:
      • It is incumbent upon the user to manage which specific Python comes first via the CLI, switch when necessary, and/or have a mental model of which versions are exposed globally and locally per-project. This can become confusing quite quickly. When working with Hatch, your global Python installations are only important insofar as they are on PATH somewhere since environments do not use them directly but rather create virtual environments from them, always using a version that is compatible with your project.
      • Configuration is required for each shell to properly set up pyenv on start, leading to inconsistencies when running processes that do not spawn a shell.
      • Debugging issues with Python search paths can be extremely difficult, especially for users of software. If you or users have ever ran into an issue where code was being executed that you did not anticipate, the issue is almost always pyenv influencing the python on PATH.

    Why not?:

    Currently, Hatch does not allow for the installation of specific patch release versions but rather only uses minor release granularity that tracks the latest patch release. If specific patch releases are important to you then it is best to use an alternative installation mechanism.

    "},{"location":"blog/","title":"Blog","text":""},{"location":"blog/2022/10/08/hatch-v160/","title":"Hatch v1.6.0","text":"

    Hatch v1.6.0 brings improvements to build environments, better handling of dynamic metadata, and support for tools like Visual Studio Code.

    "},{"location":"blog/2022/10/08/hatch-v160/#build-environments","title":"Build environments","text":"

    Originally, the environment interface method for providing builder sub-environments was intended to be used in conjunction with some cleanup logic in order to provide a fresh setup every time. However, this is unnecessary in practice because build dependencies rarely change.

    Without caching, repeat build environment use is slow which affects the following scenarios:

    • the build command
    • commands that read project metadata, like dep hash, if any fields are set dynamically

    Now a new environment interface method build_environment_exists is used by Hatch to determine whether or not it has already been created, for implementations that have a caching mechanism.

    The virtual environment type now uses this method to cache build environments.

    "},{"location":"blog/2022/10/08/hatch-v160/#project-metadata","title":"Project metadata","text":"

    Dynamically defined metadata is now supported everywhere, thanks to the new caching of virtual build environments.

    A project metadata command is introduced that displays the fully resolved metadata. The output format is JSON unless a field is specified as an argument.

    For example, if you checkout a project that is built by Hatch, like FastAPI, and run:

    hatch project metadata readme\n

    only the readme text will be displayed. If the content is in Markdown, then Rich will render it directly in your terminal:

    "},{"location":"blog/2022/10/08/hatch-v160/#virtual-environment-location","title":"Virtual environment location","text":"

    The virtual environment type now uses a flat layout for storage in the configured virtual environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory.

    For example, if you define the following Hatch configuration:

    config.toml
    [dirs.env]\nvirtual = \".hatch\"\n

    and the following matrix:

    pyproject.toml hatch.toml
    [[tool.hatch.envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n
    [[envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n

    then locating environments with the following command:

    hatch env find test\n

    will show that the general directory structure is:

    .hatch\n\u251c\u2500\u2500 test.py3.7\n\u251c\u2500\u2500 test.py3.8\n\u251c\u2500\u2500 test.py3.9\n\u251c\u2500\u2500 test.py3.10\n\u2514\u2500\u2500 test.py3.11\n

    This flat structure is required for detection of virtual environments by tools like Visual Studio Code and PyCharm.

    Additionally, the virtual environment type now supports a path option to specify an explicit path that all inherited environments will share, such as the common .venv.

    "},{"location":"blog/2022/10/08/hatch-v160/#migration-script-improvements","title":"Migration script improvements","text":"

    The script used to migrate existing projects from setuptools has been improved to handle more edge cases that were encountered in the wild and now no longer modifies the formatting of existing pyproject.toml configuration.

    "},{"location":"blog/2022/10/08/hatch-v160/#hatchling","title":"Hatchling","text":"

    Hatch now depends on Hatchling v1.11.0, which was also just released.

    "},{"location":"blog/2022/10/08/hatch-v160/#environment-version-source","title":"Environment version source","text":"

    A new env version source is available that allows for the project version to be defined by an environment variable.

    "},{"location":"blog/2022/10/08/hatch-v160/#relaxed-version-bumping","title":"Relaxed version bumping","text":"

    The standard version scheme now supports a validate-bump option that when set to false will forego the check when updating the version that the desired version is higher than the current version.

    This use case comes from Project Jupyter:

    A common pattern we use in Jupyter is to bump to a .dev0 minor version bump after making a release. If we have a bug fix that needs to go out in the interim, we'd rather not be forced to create a branch every time.

    "},{"location":"blog/2023/12/11/hatch-v180/","title":"Hatch v1.8.0","text":"

    Hatch v1.8.0 brings Python distribution management, static analysis and formatting backed by Ruff, and binaries for every platform.

    "},{"location":"blog/2023/12/11/hatch-v180/#installation-made-easy","title":"Installation made easy","text":"

    One thing that has been a perpetual problem for Hatch and other Python applications is that Python itself is a dependency. You, and more importantly your users, need to in some way get Python before your software can even be used. The recommended way to go about that is platform-dependent and even differs based on your target audience. I viewed this as a central UX problem for Hatch and so severe that I took a bit of a hiatus to solve it.

    Luckily, I have to my satisfaction solved this problem in the form of PyApp. It is a runtime installer for Python projects written in Rust. Apps are distributed as standalone executables as users have come to expect and bootstrapping occurs upon the first invocation. Here is an example of what you would see the first time you run a binary from this release:

    Now that we have binaries, creating installers for different platforms becomes trivial. Starting with this release not only are binaries available for every platform but also we have installers for Windows and macOS. The installer for macOS is signed using a certificate from the same account used to sign the official distributions from https://www.python.org, so users will not get any security pop-ups. Shout out to @ewdurbin for their extreme generosity in setting up multiple certificates in their free time!

    These installers and binaries are now the recommended way to install and update Hatch. These binaries have built-in management so you can update to the latest version by running hatch self update.

    Windows signing

    In future we will sign the installers for Windows but I did not have time to look into how that works. macOS signing took way longer than I anticipated

    "},{"location":"blog/2023/12/11/hatch-v180/#python-management","title":"Python management","text":"

    For a long time I and other users have desired that Hatch gain the ability to manage Python distributions. In my mind this was always blocked on a better installation experience because there was sort of a chicken-or-egg problem where you want a Python manager but you first need Python. No longer is that the case!

    The new python command group allows for easy installation of various distributions to arbitrary locations which are then added to your PATH by default. Hatch supports CPython and PyPy distributions:

    "},{"location":"blog/2023/12/11/hatch-v180/#virtual-environment-python-resolution","title":"Virtual environment Python resolution","text":"

    The virtual environment type is now far more intelligent when resolving the parent distribution to use and guarantees that, when no specific version is requested, the resolved distribution will always be compatible with the project.

    Additionally, when a requested version cannot be found on PATH it will automatically be downloaded and managed internally.

    "},{"location":"blog/2023/12/11/hatch-v180/#static-analysis","title":"Static analysis","text":"

    There is a new fmt command, backed entirely by Ruff, that checks and fixes your code for formatting and linting issues.

    Starting with this release, Hatch maintains default settings that are guaranteed to be up-to-date and represent best practices for programming in modern Python. The idea is to provide defaults that are so broadly applicable that the majority of users will maintain little if any of their own overrides.

    The default behavior is internal management of settings to provide an OOTB experience that works. It is recommended however that you persist the default config file in version control so that other tools like IDEs can utilize your full configuration.

    Since Ruff is now provided as a built-in feature, new project templates no longer have such configuration and are much less verbose.

    "},{"location":"blog/2023/12/11/hatch-v180/#build-improvements","title":"Build improvements","text":"

    Building projects that do not use Hatchling as a backend is now supported and such builds are managed with the standard build tool.

    The bridge between Hatch and the Hatchling CLI has been removed. Previously, the builder would send serialized messages to Hatch that would contain the desired content and style for each line of output. This was done in an effort to allow builder and build hook plugins to output pretty messages without actually requiring a dependency like Rich. A problem that arises with this is that builders that invoke subprocesses will not display ANSI codes as one might expect and will lose out on the interactive experience of such invocations, like the built-in binary builder plugin calling cargo build. So now everything is simpler at the expense of no colored output without manual logic, or adding a dependency if you're a third-party plugin.

    "},{"location":"blog/2023/12/11/hatch-v180/#faster-environment-usage","title":"Faster environment usage","text":"

    Spawning a shell or running commands within environments always first checks that your project's dependencies are satisfied and if not synchronizes the environment with what is defined. Previously, this had the potential to be quite slow for projects that have many dependencies.

    Now the set of dependency definitions is hashed and no check is performed if the hash is the same as before, significantly speeding up environment usage in most cases.

    "},{"location":"blog/2023/12/11/hatch-v180/#hatchling","title":"Hatchling","text":"

    Hatch now depends on Hatchling v1.19.0, which was also just released.

    "},{"location":"blog/2023/12/11/hatch-v180/#better-defaults","title":"Better defaults","text":"

    Hatchling is all about providing the best possible defaults, even at the expense of backward compatibility. In this release, there are two breaking changes that provide a much better user experience and were in fact requested by users.

    • Both the force-include option and the force_include_editable wheel build data setting now raise errors if source paths do not exist.
    • The wheel build target now raises an error when no file inclusion options have been defined and none of its heuristics to determine what to ship are satisfied.
    "},{"location":"blog/2023/12/11/hatch-v180/#binary-build-target","title":"Binary build target","text":"

    A new binary build target is now stable that allows for the building of standalone binaries for projects. This is what Hatch itself uses for its binaries.

    "},{"location":"blog/2023/12/11/hatch-v180/#meta","title":"Meta","text":""},{"location":"blog/2023/12/11/hatch-v180/#why-hatch","title":"Why Hatch?","text":"

    A new page has been introduced that discusses the value proposition of Hatch and Hatchling in comparison to alternatives. Currently, it only addresses a few features but in future this page will become more comprehensive.

    "},{"location":"blog/2023/12/11/hatch-v180/#future","title":"Future","text":"

    Upcoming features include a test command, commands to manage dependencies, and workspaces functionality similar to Cargo that will make managing monorepos far easier.

    Next year there will be two large efforts that you should expect to see:

    1. A significant amount of my free time (and some at work) will be devoted to introducing lock file functionality in Hatch and trying to get whatever that happens to be standardized.

      I met with @brettcannon about his thoughts post-PEP 665 and about mousebender. I also met with the prefix.dev team about rip and was fortunate enough to be shown a demo before its official announcement.

      At the moment, the two options I see are to either go all in and contribute to mousebender or rely on the Prefix folks and use rip. The latter has the benefit of potentially supporting Conda as a side effect with the downside of being quite new with the spec firmly out of our control. The former has the benefit of being able to easily gain institutional support from the Python packaging team and each of our employers with the downside being a significant amount of work needing to be done.

    2. When @henryiii is able to get some free time away from teaching I plan to work with him once again and push very hard for the Python build ecosystem to adopt the extensionlib approach.

      I am of the opinion that the Python community has not fully completed the expressed outcome of PEP 517 in that build backends are still (for the most part) reliant on setuptools for building non-Python code bases.

      Basically, there are components that interact with compilers to produce extension modules and components that pack files into an archive which we call a build backend. These are two distinct pieces of functionality and my view is that there should be an API that allows backends to consume extension module builders to find out where things got created and where they should be shipped inside archives.

      In this hypothetical future any build backend would be able to trigger the building of extension modules based on user configuration.

    "},{"location":"blog/2023/12/11/hatch-v180/#support","title":"Support","text":"

    If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!

    "},{"location":"blog/2023/12/18/hatch-v190/","title":"Hatch v1.9.0","text":"

    Hatch v1.9.0 brings improvements to static analysis and important bug fixes.

    "},{"location":"blog/2023/12/18/hatch-v190/#static-analysis","title":"Static analysis","text":"

    The default version of Ruff has been increased to v0.1.8. This release brings formatting capabilities to docstrings and Hatch enables this by default with line length set to 80. This length was chosen as the default because it plays nicely with the rendering of the most popular themes for Python documentation, such as Material for MkDocs and Furo.

    Additionally, it is now possible for projects to pin to specific versions of Ruff for upgrading at a later time:

    pyproject.toml hatch.toml
    [tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
    [envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
    "},{"location":"blog/2023/12/18/hatch-v190/#notable-fixes","title":"Notable fixes","text":"
    • Python resolution for environments that do not install the project is no longer bound by the project's Python requirement.
    • Fixed an edge case for out-of-the-box static analysis when there was existing configuration.
    • Compatibility checks for environments no longer occur if the environment is already created. This significantly increases the responsiveness of environment usage.
    "},{"location":"cli/about/","title":"CLI usage","text":""},{"location":"cli/about/#verbosity","title":"Verbosity","text":"

    The amount of displayed output is controlled solely by the -v/--verbose (environment variable HATCH_VERBOSE) and -q/--quiet (environment variable HATCH_QUIET) root options.

    The levels are documented here.

    "},{"location":"cli/about/#project-awareness","title":"Project awareness","text":"

    No matter the mode, Hatch will always change to the project's root directory for entering or running commands in environments.

    "},{"location":"cli/about/#tab-completion","title":"Tab completion","text":"

    Completion is achieved by saving a script and then executing it as a part of your shell's startup sequence.

    Afterward, you'll need to start a new shell in order for the changes to take effect.

    BashZ shellfish

    Save the script somewhere:

    _HATCH_COMPLETE=bash_source hatch > ~/.hatch-complete.bash\n

    Source the file in ~/.bashrc (or ~/.bash_profile if on macOS):

    . ~/.hatch-complete.bash\n

    Save the script somewhere:

    _HATCH_COMPLETE=zsh_source hatch > ~/.hatch-complete.zsh\n

    Source the file in ~/.zshrc:

    . ~/.hatch-complete.zsh\n

    Save the script in ~/.config/fish/completions:

    _HATCH_COMPLETE=fish_source hatch > ~/.config/fish/completions/hatch.fish\n
    "},{"location":"cli/reference/","title":"hatch","text":"

    Usage:

    hatch [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --env, -e text The name of the environment to use [env var: HATCH_ENV] default --project, -p text The name of the project to work on [env var: HATCH_PROJECT] None --verbose, -v integer range (0 and above) Increase verbosity (can be used additively) [env var: HATCH_VERBOSE] 0 --quiet, -q integer range (0 and above) Decrease verbosity (can be used additively) [env var: HATCH_QUIET] 0 --color / --no-color boolean Whether or not to display colored output (default is auto-detection) [env vars: FORCE_COLOR/NO_COLOR] None --interactive / --no-interactive boolean Whether or not to allow features like prompts and progress bars (default is auto-detection) [env var: HATCH_INTERACTIVE] None --data-dir text The path to a custom directory used to persist data [env var: HATCH_DATA_DIR] None --cache-dir text The path to a custom directory used to cache data [env var: HATCH_CACHE_DIR] None --config text The path to a custom config file to use [env var: HATCH_CONFIG] None --version boolean Show the version and exit. False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-build","title":"hatch build","text":"

    Build a project.

    Usage:

    hatch build [OPTIONS] [LOCATION]\n

    Options:

    Name Type Description Default --target, -t text The target to build, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None --hooks-only boolean Whether or not to only execute build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False --no-hooks boolean Whether or not to disable build hooks [env var: HATCH_BUILD_NO_HOOKS] False --ext boolean Whether or not to only execute build hooks for distributing binary Python packages, such as compiling extensions. Equivalent to --hooks-only -t wheel False --clean, -c boolean Whether or not existing artifacts should first be removed [env var: HATCH_BUILD_CLEAN] False --clean-hooks-after boolean Whether or not build hook artifacts should be removed after each build [env var: HATCH_BUILD_CLEAN_HOOKS_AFTER] False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-clean","title":"hatch clean","text":"

    Remove build artifacts.

    Usage:

    hatch clean [OPTIONS] [LOCATION]\n

    Options:

    Name Type Description Default --target, -t text The target with which to remove artifacts, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None --hooks-only boolean Whether or not to only remove artifacts from build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False --no-hooks boolean Whether or not to ignore artifacts from build hooks [env var: HATCH_BUILD_NO_HOOKS] False --ext boolean Whether or not to only remove artifacts from build hooks for distributing binary Python packages, such as compiled extensions. Equivalent to --hooks-only -t wheel False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config","title":"hatch config","text":"

    Manage the config file

    Usage:

    hatch config [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-explore","title":"hatch config explore","text":"

    Open the config location in your file manager.

    Usage:

    hatch config explore [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-find","title":"hatch config find","text":"

    Show the location of the config file.

    Usage:

    hatch config find [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-restore","title":"hatch config restore","text":"

    Restore the config file to default settings.

    Usage:

    hatch config restore [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-set","title":"hatch config set","text":"

    Assign values to config file entries. If the value is omitted, you will be prompted, with the input hidden if it is sensitive.

    Usage:

    hatch config set [OPTIONS] KEY [VALUE]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-show","title":"hatch config show","text":"

    Show the contents of the config file.

    Usage:

    hatch config show [OPTIONS]\n

    Options:

    Name Type Description Default --all, -a boolean Do not scrub secret fields False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-update","title":"hatch config update","text":"

    Update the config file with any new fields.

    Usage:

    hatch config update [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep","title":"hatch dep","text":"

    Manage environment dependencies

    Usage:

    hatch dep [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-hash","title":"hatch dep hash","text":"

    Output a hash of the currently defined dependencies.

    Usage:

    hatch dep hash [OPTIONS]\n

    Options:

    Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show","title":"hatch dep show","text":"

    Display dependencies in various formats

    Usage:

    hatch dep show [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show-requirements","title":"hatch dep show requirements","text":"

    Enumerate dependencies as a list of requirements.

    Usage:

    hatch dep show requirements [OPTIONS]\n

    Options:

    Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --feature, -f text Whether or not to only show the dependencies of the specified features None --all boolean Whether or not to include the dependencies of all features False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show-table","title":"hatch dep show table","text":"

    Enumerate dependencies in a tabular format.

    Usage:

    hatch dep show table [OPTIONS]\n

    Options:

    Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --lines, -l boolean Whether or not to show lines between table rows False --ascii boolean Whether or not to only use ASCII characters False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env","title":"hatch env","text":"

    Manage project environments

    Usage:

    hatch env [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-create","title":"hatch env create","text":"

    Create environments.

    Usage:

    hatch env create [OPTIONS] [ENV_NAME]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-find","title":"hatch env find","text":"

    Locate environments.

    Usage:

    hatch env find [OPTIONS] [ENV_NAME]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-prune","title":"hatch env prune","text":"

    Remove all environments.

    Usage:

    hatch env prune [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-remove","title":"hatch env remove","text":"

    Remove environments.

    Usage:

    hatch env remove [OPTIONS] [ENV_NAME]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-run","title":"hatch env run","text":"

    Run commands within project environments.

    The -e/--env option overrides the equivalent root option and the HATCH_ENV environment variable.

    If environments provide matrices, then you may use the -i/--include and -x/--exclude options to select or exclude certain variables, optionally followed by specific comma-separated values. For example, if you have the following configuration:

    pyproject.toml hatch.toml
    [[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
    [[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n

    then running:

    hatch env run -i py=3.10 -x version=9000 test:pytest\n

    would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

    Usage:

    hatch env run [OPTIONS] ARGS...\n

    Options:

    Name Type Description Default --env, -e text The environments to target None --include, -i text The matrix variables to include None --exclude, -x text The matrix variables to exclude None --filter, -f text The JSON data used to select environments None --force-continue boolean Run every command and if there were any errors exit with the first code False --ignore-compat boolean Ignore incompatibility when selecting specific environments False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-show","title":"hatch env show","text":"

    Show the available environments.

    Usage:

    hatch env show [OPTIONS] [ENVS]...\n

    Options:

    Name Type Description Default --ascii boolean Whether or not to only use ASCII characters False --json boolean Whether or not to output in JSON format False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-fmt","title":"hatch fmt","text":"

    Format and lint source code.

    Usage:

    hatch fmt [OPTIONS] [ARGS]...\n

    Options:

    Name Type Description Default --check boolean Only check for errors rather than fixing them False --linter, -l boolean Only run the linter False --formatter, -f boolean Only run the formatter False --sync boolean Sync the default config file with the current version of Hatch False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-new","title":"hatch new","text":"

    Create or initialize a project.

    Usage:

    hatch new [OPTIONS] [NAME] [LOCATION]\n

    Options:

    Name Type Description Default --interactive, -i boolean Interactively choose details about the project False --cli boolean Give the project a command line interface False --init boolean Initialize an existing project False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-project","title":"hatch project","text":"

    View project information

    Usage:

    hatch project [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-project-metadata","title":"hatch project metadata","text":"

    Display project metadata.

    If you want to view the raw readme file without rendering, you can use a JSON parser like jq:

    hatch project metadata | jq -r .readme\n

    Usage:

    hatch project metadata [OPTIONS] [FIELD]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-publish","title":"hatch publish","text":"

    Publish build artifacts.

    Usage:

    hatch publish [OPTIONS] [ARTIFACTS]...\n

    Options:

    Name Type Description Default --repo, -r text The repository with which to publish artifacts [env var: HATCH_INDEX_REPO] None --user, -u text The user with which to authenticate [env var: HATCH_INDEX_USER] None --auth, -a text The credentials to use for authentication [env var: HATCH_INDEX_AUTH] None --ca-cert text The path to a CA bundle [env var: HATCH_INDEX_CA_CERT] None --client-cert text The path to a client certificate, optionally containing the private key [env var: HATCH_INDEX_CLIENT_CERT] None --client-key text The path to the client certificate's private key [env var: HATCH_INDEX_CLIENT_KEY] None --no-prompt, -n boolean Disable prompts, such as for missing required fields False --initialize-auth boolean Save first-time authentication information even if nothing was published False --publisher, -p text The publisher plugin to use (default is index) [env var: HATCH_PUBLISHER] index --option, -o text Options to pass to the publisher plugin. This may be selected multiple times e.g. -o foo=bar -o baz=23 [env var: HATCH_PUBLISHER_OPTIONS] None --yes, -y boolean Confirm without prompting when the plugin is disabled False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python","title":"hatch python","text":"

    Manage Python installations

    Usage:

    hatch python [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-find","title":"hatch python find","text":"

    Locate Python binaries.

    Usage:

    hatch python find [OPTIONS] NAME\n

    Options:

    Name Type Description Default -p, --parent boolean Show the parent directory of the Python binary False --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-install","title":"hatch python install","text":"

    Install Python distributions.

    You may select all to install all compatible distributions:

    hatch python install all\n

    Usage:

    hatch python install [OPTIONS] NAMES...\n

    Options:

    Name Type Description Default --private boolean Do not add distributions to the user PATH False --update, -u boolean Update existing installations False --dir, -d text The directory in which to install distributions, overriding configuration None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-remove","title":"hatch python remove","text":"

    Remove Python distributions.

    You may select all to remove all installed distributions:

    hatch python remove all\n

    Usage:

    hatch python remove [OPTIONS] NAMES...\n

    Options:

    Name Type Description Default --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-show","title":"hatch python show","text":"

    Show the available Python distributions.

    Usage:

    hatch python show [OPTIONS]\n

    Options:

    Name Type Description Default --ascii boolean Whether or not to only use ASCII characters False --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-update","title":"hatch python update","text":"

    Update Python distributions.

    You may select all to update all installed distributions:

    hatch python update all\n

    Usage:

    hatch python update [OPTIONS] NAMES...\n

    Options:

    Name Type Description Default --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-run","title":"hatch run","text":"

    Run commands within project environments. This is a convenience wrapper around the env run command.

    If the first argument contains a colon, then the preceding component will be interpreted as the name of the environment to target, overriding the -e/--env root option and the HATCH_ENV environment variable.

    If the environment provides matrices, then you may also provide leading arguments starting with a + or - to select or exclude certain variables, optionally followed by specific comma-separated values. For example, if you have the following configuration:

    pyproject.toml hatch.toml
    [[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
    [[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n

    then running:

    hatch run +py=3.10 -version=9000 test:pytest\n

    would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

    Usage:

    hatch run [OPTIONS] [ENV:]ARGS...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-self","title":"hatch self","text":"

    Manage Hatch

    Usage:

    hatch self [OPTIONS] COMMAND [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-self-report","title":"hatch self report","text":"

    Generate a pre-populated GitHub issue.

    Usage:

    hatch self report [OPTIONS]\n

    Options:

    Name Type Description Default --no-open, -n boolean Show the URL instead of opening it False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-self-restore","title":"hatch self restore","text":"

    Restore the installation

    Usage:

    hatch self restore [OPTIONS] [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-self-update","title":"hatch self update","text":"

    Install the latest version

    Usage:

    hatch self update [OPTIONS] [ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-shell","title":"hatch shell","text":"

    Enter a shell within a project's environment.

    Usage:

    hatch shell [OPTIONS] [SHELL_NAME] [SHELL_PATH] [SHELL_ARGS]...\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-status","title":"hatch status","text":"

    Show information about the current environment.

    Usage:

    hatch status [OPTIONS]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-version","title":"hatch version","text":"

    View or set a project's version.

    Usage:

    hatch version [OPTIONS] [DESIRED_VERSION]\n

    Options:

    Name Type Description Default --help boolean Show this message and exit. False"},{"location":"community/contributing/","title":"Contributing","text":"

    The usual process to make a contribution is to:

    1. Check for existing related issues
    2. Fork the repository and create a new branch
    3. Make your changes
    4. Make sure formatting, linting and tests passes.
    5. Add tests if possible to cover the lines you added.
    6. Commit, and send a Pull Request.
    "},{"location":"community/contributing/#clone-the-repository","title":"Clone the repository","text":"

    Clone the hatch repository, cd into it, and create a new branch for your contribution:

    cd hatch\ngit checkout -b add-my-contribution\n
    "},{"location":"community/contributing/#run-the-tests","title":"Run the tests","text":"

    Run the test suite while developing:

    hatch run dev\n

    Run the test suite with coverage report:

    hatch run cov\n

    Run the extended test suite with coverage:

    hatch run full\n
    "},{"location":"community/contributing/#lint","title":"Lint","text":"

    Run automated formatting:

    hatch run lint:fmt\n

    Run full linting and type checking:

    hatch run lint:all\n
    "},{"location":"community/contributing/#docs","title":"Docs","text":"

    Start the documentation in development:

    hatch run docs:serve\n

    Build and validate the documentation website:

    hatch run docs:build-check\n
    "},{"location":"community/highlights/","title":"Community highlights","text":""},{"location":"community/highlights/#integration","title":"Integration","text":"
    • Project Jupyter - https://blog.jupyter.org/packaging-for-jupyter-in-2022-c7be64c38926
    "},{"location":"community/highlights/#adoption","title":"Adoption","text":"
    • Black - https://ichard26.github.io/blog/2022/10/black-22.10.0/#goodbye-python-36-and-hello-hatchling
    • \"Switching to Hatch\" - https://andrich.me/2023/08/switching-to-hatch/
    "},{"location":"community/users/","title":"Users","text":"

    The following is not intended to be a complete enumeration. Be sure to view the development version of this page for an up-to-date listing.

    "},{"location":"community/users/#projects","title":"Projects","text":"

    aiogram | Apache Airflow | argon2-cffi | attrs | Black | coffea | Colorama | Django Anymail | Django Debug Toolbar | Django Wiki | FastAPI | filelock | github3.py | Gradio | HTTPX | iCalendar for Humans | LinkChecker | Material for MkDocs | MkDocs | openSUSE | Nox | Packit | pipx | platformdirs | Pydantic | Pygments | PyHamcrest | PyMdown Extensions | Python JSON Schema | Rye | SALib | Spack | Starlette | structlog | tox | Twisted | urllib3 | Uvicorn | virtualenv | Voil\u00e0 | XGBoost | Ypy

    "},{"location":"community/users/#industry","title":"Industry","text":"
    • Anaconda [1|2|3|4|5|6]
    • Astronomer [1]
    • Bloomberg [1|2]
    • Blue Robotics [1]
    • Cars.com [1]
    • Databricks [1|2]
    • Datadog [1|2|3|4]
    • deepset [1|2]
    • Elastic [1|2|3]
    • Google [1|2|3|4|5]
    • IBM [1]
    • JPMorgan Chase [1]
    • Intel Corporation [1|2|3]
    • Meta [1|2]
    • Microsoft [1|2|3|4|5]
    • OpenAI [1]
    • Oracle [1]
    • Palo Alto Networks [1]
    • Red Hat [1|2|3|4|5]
    • Snowflake [1]
    • Splunk [1]
    • Virtru [1|2]
    • VMware [1|2|3]
    • Volvo Group [1]
    "},{"location":"community/users/#organizations","title":"Organizations","text":"
    • Greater Paris University Hospitals (AP-HP) [1]
    • OpenTelemetry [1|2]
    • Smithsonian Institution [1]
    • The New York Public Library [1]
    "},{"location":"community/users/#government","title":"Government","text":"
    • European Molecular Biology Laboratory
      • European Bioinformatics Institute [1]
    • Germany
      • Berlin Institute of Health [1]
      • Helmholtz Munich [1|2]
    • Norway
      • Statistics Norway [1]
    • United Kingdom
      • The Alan Turing Institute [1]
      • Department for Business and Trade [1]
      • The National Archives [1]
    • United States
      • NASA [1]
      • National Security Agency [1|2]
      • National Telecommunications and Information Administration [1|2|3|4]
    "},{"location":"community/users/#academia","title":"Academia","text":"
    • Brown University
      • Carney Institute for Brain Science [1]
    • Chinese Academy of Sciences
      • Academy of Mathematics and Systems Science [1]
    • Georgia Institute of Technology
      • Georgia Tech Database Group [1]
    • Harvard University
      • Department of Molecular and Cellular Biology [1]
    • Heidelberg University
      • Center for Molecular Biology [1]
    • Leiden University
      • Leiden University Libraries [1|2]
    • Maastricht University
      • Institute of Data Science [1|2|3|4|5|6|7]
    • Massachusetts Institute of Technology
      • Computer Science and Artificial Intelligence Laboratory [1]
      • Digital Humanities [1]
    • Medical University of Innsbruck
      • Institute of Bioinformatics [1]
    • Polytechnique Montr\u00e9al
      • Department of Computer Engineering and Software Engineering [1]
    • Siberian Branch of the Russian Academy of Sciences
      • Institute of Cytology and Genetics [1|2|3|4]
    • Stanford University
      • Empirical Security Research Group [1]
    • University of British Columbia
      • Department of Earth, Ocean and Atmospheric Sciences [1|2|3]
    • University of California, Berkeley
      • Center for Computational Biology [1]
    • University of Freiburg
      • Freiburg Center for Data Analysis and Modeling [1]
    • University of Illinois Urbana-Champaign
      • Grainger College of Engineering [1]
    • University of Lausanne
      • Department of Computational Biology [1]
    • University of Ljubljana
      • Faculty of Mechanical Engineering [1]
    • University of Oxford
      • Oxford Research Software Engineering [1]
    • University of Pennsylvania
      • Lifespan Informatics and Neuroimaging Center [1]
    • University of Sussex
      • Predictive Analytics Lab [1]
    • University of Toronto Scarborough
      • utsc-networking [1|2|3|4]
    • University of Washington
      • Interactive Data Lab [1]
      • Virtual Brain Lab [1]
    • Waseda University
      • Tackeuchi Laboratory [1|2|3|4|5]
    • Wellcome Sanger Institute [1]
    "},{"location":"community/users/#research","title":"Research","text":"
    • Clariah [1]
    • CloudDrift [1]
    • GAMA [1]
    • IPython [1|2|3]
    • MNE [1|2|3]
    • NIPY [1|2]
    • Project Jupyter
      • Jupyter [1|2|3|4]
      • JupyterLab [1|2|3|4|5]
      • Jupyter Server [1|2|3|4]
    • Scikit-HEP [1|2|3|4|5|6|7|8|9|10]
    • scverse [1|2|3]
    • Spyder [1]
    "},{"location":"community/users/#security","title":"Security","text":"
    • Armory
    • in-toto
    • The Update Framework
    "},{"location":"community/users/#crypto","title":"Crypto","text":"
    • Ocean Protocol [1]
    "},{"location":"config/build/","title":"Build configuration","text":"

    Build targets are defined as sections within tool.hatch.build.targets:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.<TARGET_NAME>]\n
    [build.targets.<TARGET_NAME>]\n

    Tip

    Although not recommended, you may define global configuration in the tool.hatch.build table. Keys may then be overridden by target config.

    "},{"location":"config/build/#build-system","title":"Build system","text":"

    To be compatible with the broader Python packaging ecosystem, you must define the build system as follows:

    pyproject.toml
    [build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n

    The version of hatchling defined here will be used to build all targets.

    Hatchling is a standards-compliant1 build backend and is a dependency of Hatch itself.

    "},{"location":"config/build/#file-selection","title":"File selection","text":""},{"location":"config/build/#vcs","title":"VCS","text":"

    By default, Hatch will respect the first .gitignore or .hgignore file found in your project's root directory or parent directories. Set ignore-vcs to true to disable this behavior:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.sdist]\nignore-vcs = true\n
    [build.targets.sdist]\nignore-vcs = true\n

    Note

    For .hgignore files only glob syntax is supported.

    "},{"location":"config/build/#patterns","title":"Patterns","text":"

    You can set the include and exclude options to select exactly which files will be shipped in each build, with exclude taking precedence. Every entry represents a Git-style glob pattern.

    For example, the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.sdist]\ninclude = [\n  \"pkg/*.py\",\n  \"/tests\",\n]\nexclude = [\n  \"*.json\",\n  \"pkg/_compat.py\",\n]\n
    [build.targets.sdist]\ninclude = [\n  \"pkg/*.py\",\n  \"/tests\",\n]\nexclude = [\n  \"*.json\",\n  \"pkg/_compat.py\",\n]\n

    will exclude every file with a .json extension, and will include everything under a tests directory located at the root and every file with a .py extension that is directly under a pkg directory located at the root except for _compat.py.

    "},{"location":"config/build/#artifacts","title":"Artifacts","text":"

    If you want to include files that are ignored by your VCS, such as those that might be created by build hooks, you can use the artifacts option. This option is semantically equivalent to include.

    Note that artifacts are not affected by the exclude option. Artifacts can be excluded by using more explicit paths or by using the ! negation operator. When using the ! operator, the negated pattern(s) must come after the more generic ones.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\nartifacts = [\n  \"*.so\",\n  \"*.dll\",\n  \"!/foo/*.so\",\n]\n
    [build.targets.wheel]\nartifacts = [\n  \"*.so\",\n  \"*.dll\",\n  \"!/foo/*.so\",\n]\n
    "},{"location":"config/build/#explicit-selection","title":"Explicit selection","text":""},{"location":"config/build/#generic","title":"Generic","text":"

    You can use the only-include option to prevent directory traversal starting at the project root and only select specific relative paths to directories or files. Using this option ignores any defined include patterns.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
    [build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
    "},{"location":"config/build/#packages","title":"Packages","text":"

    The packages option is semantically equivalent to only-include (which takes precedence) except that the shipped path will be collapsed to only include the final component.

    So for example, if you want to ship a package foo that is stored in a directory src you would do:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
    [build.targets.wheel]\npackages = [\"src/foo\"]\n
    "},{"location":"config/build/#forced-inclusion","title":"Forced inclusion","text":"

    The force-include option allows you to select specific files or directories from anywhere on the file system that should be included and map them to the desired relative distribution path.

    For example, if there was a directory alongside the project root named artifacts containing a file named lib.so and a file named lib.h in your home directory, you could ship both files in a pkg directory with the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n
    [build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n

    Note

    • Files must be mapped exactly to their desired paths, not to directories.
    • The contents of directory sources are recursively included.
    • To map directory contents directly to the root use / (a forward slash).
    • Sources that do not exist will raise an error.

    Warning

    Files included using this option will overwrite any file path that was already included by other file selection options.

    "},{"location":"config/build/#default-file-selection","title":"Default file selection","text":"

    If no file selection options are provided, then what gets included is determined by each build target.

    "},{"location":"config/build/#excluding-files-outside-packages","title":"Excluding files outside packages","text":"

    If you want to exclude non-artifact files that do not reside within a Python package, set only-packages to true:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\nonly-packages = true\n
    [build.targets.wheel]\nonly-packages = true\n
    "},{"location":"config/build/#rewriting-paths","title":"Rewriting paths","text":"

    You can rewrite relative paths to directories with the sources option. For example, the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n
    [build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n

    would distribute the file src/foo/file.ext as bar/file.ext.

    If you want to remove path prefixes entirely, rather than setting each to an empty string, you can define sources as an array:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\nsources = [\"src\"]\n
    [build.targets.wheel]\nsources = [\"src\"]\n

    If you want to add a prefix to paths, you can use an empty string. For example, the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel.sources]\n\"\" = \"foo\"\n
    [build.targets.wheel.sources]\n\"\" = \"foo\"\n

    would distribute the file bar/file.ext as foo/bar/file.ext.

    The packages option itself relies on sources. Defining packages = [\"src/foo\"] for the wheel target is equivalent to the following:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
    [build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
    "},{"location":"config/build/#performance","title":"Performance","text":"

    All encountered directories are traversed by default. To skip non-artifact directories that are excluded, set skip-excluded-dirs to true:

    pyproject.toml hatch.toml
    [tool.hatch.build]\nskip-excluded-dirs = true\n
    [build]\nskip-excluded-dirs = true\n

    Warning

    This may result in not shipping desired files. For example, if you want to include the file a/b/c.txt but your VCS ignores a/b, the file c.txt will not be seen because its parent directory will not be entered. In such cases you can use the force-include option.

    "},{"location":"config/build/#reproducible-builds","title":"Reproducible builds","text":"

    By default, build targets will build in a reproducible manner provided that they support that behavior. To disable this, set reproducible to false:

    pyproject.toml hatch.toml
    [tool.hatch.build]\nreproducible = false\n
    [build]\nreproducible = false\n

    When enabled, the SOURCE_DATE_EPOCH environment variable will be used for all build timestamps. If not set, then Hatch will use an unchanging default value.

    "},{"location":"config/build/#output-directory","title":"Output directory","text":"

    When the output directory is not provided to the build command, the dist directory will be used by default. You can change the default to a different directory using a relative or absolute path like so:

    pyproject.toml hatch.toml
    [tool.hatch.build]\ndirectory = \"<PATH>\"\n
    [build]\ndirectory = \"<PATH>\"\n
    "},{"location":"config/build/#dev-mode","title":"Dev mode","text":"

    By default for dev mode environment installations or editable installs, the wheel target will determine which directories should be added to Python's search path based on the selected files.

    If you want to override this detection or perhaps instruct other build targets as well, you can use the dev-mode-dirs option:

    pyproject.toml hatch.toml
    [tool.hatch.build]\ndev-mode-dirs = [\".\"]\n
    [build]\ndev-mode-dirs = [\".\"]\n

    If you don't want to add entire directories to Python's search path, you can enable a more targeted mechanism with the mutually exclusive dev-mode-exact option:

    pyproject.toml hatch.toml
    [tool.hatch.build]\ndev-mode-exact = true\n
    [build]\ndev-mode-exact = true\n

    Warning

    The dev-mode-exact mechanism is not supported by static analysis tools & IDEs, therefore functionality such as autocompletion is unlikely to work.

    "},{"location":"config/build/#build-targets","title":"Build targets","text":"

    A build target can be provided by any builder plugin. There are three built-in build targets: wheel, sdist, and custom.

    "},{"location":"config/build/#dependencies","title":"Dependencies","text":"

    You can specify additional dependencies that will be installed in each build environment, such as for third party builders:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.your-target-name]\ndependencies = [\n  \"your-builder-plugin\"\n]\n
    [build.targets.your-target-name]\ndependencies = [\n  \"your-builder-plugin\"\n]\n

    You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies option:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.your-target-name]\nrequire-runtime-dependencies = true\n
    [build.targets.your-target-name]\nrequire-runtime-dependencies = true\n

    Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features option:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.your-target-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
    [build.targets.your-target-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
    "},{"location":"config/build/#versions","title":"Versions","text":"

    If a build target supports multiple build strategies or if there are major changes over time, you can specify exactly which versions you want to build using the versions option:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.<TARGET_NAME>]\nversions = [\n  \"v1\",\n  \"beta-feature\",\n]\n
    [build.targets.<TARGET_NAME>]\nversions = [\n  \"v1\",\n  \"beta-feature\",\n]\n

    See the wheel target for a real world example.

    "},{"location":"config/build/#build-hooks","title":"Build hooks","text":"

    A build hook defines code that will be executed at various stages of the build process and can be provided by any build hook plugin. There is one built-in build hook: custom.

    Build hooks can be applied either globally:

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.<HOOK_NAME>]\n
    [build.hooks.<HOOK_NAME>]\n

    or to specific build targets:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
    [build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
    "},{"location":"config/build/#dependencies_1","title":"Dependencies","text":"

    You can specify additional dependencies that will be installed in each build environment, such as for third party build hooks:

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.your-hook-name]\ndependencies = [\n  \"your-build-hook-plugin\"\n]\n
    [build.hooks.your-hook-name]\ndependencies = [\n  \"your-build-hook-plugin\"\n]\n

    You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies option:

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n
    [build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n

    Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features option:

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
    [build.hooks.your-hook-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
    "},{"location":"config/build/#order-of-execution","title":"Order of execution","text":"

    For each build target, build hooks execute in the order in which they are defined, starting with global hooks.

    As an example, for the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.foo.hooks.hook2]\n\n[tool.hatch.build.hooks.hook3]\n[tool.hatch.build.hooks.hook1]\n
    [build.targets.foo.hooks.hook2]\n\n[build.hooks.hook3]\n[build.hooks.hook1]\n

    When target foo is built, build hook hook3 will be executed first, followed by hook1, and then finally hook2.

    "},{"location":"config/build/#conditional-execution","title":"Conditional execution","text":"

    If you want to disable a build hook by default and control its use by environment variables, you can do so by setting the enable-by-default option to false:

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
    [build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
    "},{"location":"config/build/#environment-variables","title":"Environment variables","text":"Variable Default Description HATCH_BUILD_CLEAN false Whether or not existing artifacts should first be removed HATCH_BUILD_CLEAN_HOOKS_AFTER false Whether or not build hook artifacts should be removed after each build HATCH_BUILD_HOOKS_ONLY false Whether or not to only execute build hooks HATCH_BUILD_NO_HOOKS false Whether or not to disable all build hooks; this takes precedence over other options HATCH_BUILD_HOOKS_ENABLE false Whether or not to enable all build hooks HATCH_BUILD_HOOK_ENABLE_<HOOK_NAME> false Whether or not to enable the build hook named <HOOK_NAME> HATCH_BUILD_LOCATION dist The location with which to build the targets; only used by the build command
    1. Support for PEP 517 and PEP 660 guarantees interoperability with other build tools.\u00a0\u21a9

    "},{"location":"config/context/","title":"Context formatting","text":"

    You can populate configuration with the values of certain supported fields using the syntax of Python's format strings. Each field interprets the modifier part after the colon differently, if at all.

    "},{"location":"config/context/#global-fields","title":"Global fields","text":"

    Any configuration that declares support for context formatting will always support these fields.

    "},{"location":"config/context/#paths","title":"Paths","text":"Field Description root The root project directory home The user's home directory

    All paths support the following modifiers:

    Modifier Description uri The normalized absolute URI path prefixed by file: real The path with all symbolic links resolved parent The parent of the preceding path

    Tip

    The parent modifier can be chained and may be combined with either the uri or real modifier, with the latter placed at the end. For example:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n    \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
    [envs.test]\ndependencies = [\n    \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
    "},{"location":"config/context/#system-separators","title":"System separators","text":"Field Description / \\ on Windows, / otherwise ; ; on Windows, : otherwise"},{"location":"config/context/#environment-variables","title":"Environment variables","text":"

    The env field and its modifier allow you to select the value of an environment variable. If the environment variable is not set, you must specify a default value as an additional modifier e.g. {env:PATH:DEFAULT}.

    "},{"location":"config/context/#field-nesting","title":"Field nesting","text":"

    You can insert fields within others. For example, if you wanted a script that displays the value of the environment variable FOO, with a fallback to the environment variable BAR, with its own fallback to the user's home directory, you could do the following:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
    [envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
    "},{"location":"config/dependency/","title":"Dependency configuration","text":"

    Project dependencies are defined with PEP 508 strings using optional PEP 440 version specifiers.

    "},{"location":"config/dependency/#version-specifiers","title":"Version specifiers","text":"

    A version specifier consists of a series of version clauses, separated by commas. For example:

    pyproject.toml
    [project]\n...\ndependencies = [\n  \"cryptography\",\n  \"click>=7, <9, != 8.0.0\",\n  \"python-dateutil==2.8.*\",\n  \"numpy~=1.21.4\",\n]\n

    The comma is equivalent to a logical AND operator: a candidate version must match all given version clauses in order to match the specifier as a whole.

    "},{"location":"config/dependency/#operators","title":"Operators","text":"Operators Function ~= Compatible release == Version matching != Version exclusion <=, >= Inclusive ordered comparison <, > Exclusive ordered comparison === Arbitrary equality"},{"location":"config/dependency/#version-matching","title":"Version matching","text":"

    A version matching clause includes the version matching operator == and a version identifier.

    By default, the version matching operator is based on a strict equality comparison: the specified version must be exactly the same as the requested version.

    Clause Allowed versions ==1 1.0.0 ==1.2 1.2.0

    Prefix matching may be requested instead of strict comparison, by appending a trailing .* to the version identifier in the version matching clause. This means that additional trailing segments will be ignored when determining whether or not a version identifier matches the clause.

    Clause Allowed versions ==1.* >=1.0.0, <2.0.0 ==1.2.* >=1.2.0, <1.3.0"},{"location":"config/dependency/#compatible-release","title":"Compatible release","text":"

    A compatible release clause consists of the compatible release operator ~= and a version identifier. It matches any candidate version that is expected to be compatible with the specified version.

    For a given release identifier V.N, the compatible release clause is approximately equivalent to the following pair of comparison clauses:

    >= V.N, == V.*\n

    This operator cannot be used with a single segment version number such as ~=1.

    Clause Allowed versions ~=1.2 >=1.2.0, <2.0.0 ~=1.2.3 >=1.2.3, <1.3.0"},{"location":"config/dependency/#version-exclusion","title":"Version exclusion","text":"

    A version exclusion clause includes the version exclusion operator != and a version identifier.

    The allowed version identifiers and comparison semantics are the same as those of the Version matching operator, except that the sense of any match is inverted.

    "},{"location":"config/dependency/#ordered-comparison","title":"Ordered comparison","text":"

    Inclusive comparisons allow for the version identifier part of clauses whereas exclusive comparisons do not. For example, >=1.2 allows for version 1.2.0 while >1.2 does not.

    Unlike the inclusive ordered comparisons <= and >=, the exclusive ordered comparisons < and > specifically exclude pre-releases, post-releases, and local versions of the specified version.

    "},{"location":"config/dependency/#arbitrary-equality","title":"Arbitrary equality","text":"

    Though heavily discouraged, arbitrary equality comparisons allow for simple string matching without any version semantics, for example ===foobar.

    "},{"location":"config/dependency/#environment-markers","title":"Environment markers","text":"

    Environment markers allow for dependencies to only be installed when certain conditions are met.

    For example, if you need to install the latest version of cryptography that is available for a given Python major version you could define the following:

    cryptography==3.3.2; python_version < \"3\"\ncryptography>=35.0; python_version > \"3\"\n

    Alternatively, if you only need it on Python 3 when running on Windows you could do:

    cryptography; python_version ~= \"3.0\" and platform_system == \"Windows\"\n

    The available environment markers are as follows.

    Marker Python equivalent Examples os_name import osos.name
    • posix
    • java
    sys_platform import syssys.platform
    • linux
    • win32
    • darwin
    platform_machine import platformplatform.machine()
    • x86_64
    platform_python_implementation import platformplatform.python_implementation()
    • CPython
    • Jython
    platform_release import platformplatform.release()
    • 1.8.0_51
    • 3.14.1-x86_64-linode39
    platform_system import platformplatform.system()
    • Linux
    • Windows
    • Darwin
    platform_version import platformplatform.version()
    • 10.0.19041
    • #1 SMP Fri Apr 2 22:23:49 UTC 2021
    python_version import platform'.'.join(platform.python_version_tuple()[:2])
    • 2.7
    • 3.10
    python_full_version import platformplatform.python_version()
    • 2.7.18
    • 3.11.0b1
    implementation_name import syssys.implementation.name
    • cpython
    implementation_version See here
    • 2.7.18
    • 3.11.0b1
    "},{"location":"config/dependency/#features","title":"Features","text":"

    You can select groups of optional dependencies to install using the extras syntax. For example, if a dependency named foo defined the following:

    pyproject.toml
    [project.optional-dependencies]\ncrypto = [\n  \"PyJWT\",\n  \"cryptography\",\n]\nfastjson = [\n  \"orjson\",\n]\ncli = [\n  \"prompt-toolkit\",\n  \"colorama; platform_system == 'Windows'\",\n]\n

    You can select the cli and crypto features like so:

    foo[cli,crypto]==1.*\n

    Note that the features come immediately after the package name, before any version specifiers.

    "},{"location":"config/dependency/#self-referential","title":"Self-referential","text":"

    Feature groups can self-referentially extend others. For example, for a project called awesome-project, the dev feature group in the following pyproject.toml file would select everything in the crypto feature group, plus black:

    pyproject.toml
    [project]\nname = \"awesome-project\"\n\n[project.optional-dependencies]\ncrypto = [\n  \"PyJWT\",\n  \"cryptography\",\n]\ndev = [\n  \"awesome-project[crypto]\",\n  \"black\",\n]\n
    "},{"location":"config/dependency/#direct-references","title":"Direct references","text":"

    Instead of using normal version specifiers and fetching packages from an index like PyPI, you can define exact sources using direct references with an explicit URI.

    Direct references are usually not meant to be used for dependencies of a published project but rather are used for defining dependencies for an environment.

    All direct reference types are prefixed by the package name like:

    <NAME> @ <REFERENCE>\n
    "},{"location":"config/dependency/#version-control-systems","title":"Version control systems","text":"

    Various version control systems (VCS) are supported as long as the associated executable is available along your PATH.

    VCS direct references are defined using one of the following formats:

    <NAME> @ <SCHEME>://<PATH>\n<NAME> @ <SCHEME>://<PATH>@<REVISION>\n

    You may also append a #subdirectory=<PATH> component for specifying the relative path to the Python package when it is not located at the root e.g. #subdirectory=lib/foo.

    For more information, refer to this.

    "},{"location":"config/dependency/#supported-vcs","title":"Supported VCS","text":"GitMercurialSubversionBazaar Executable Schemes Revisions Example git
    • git+file
    • git+https
    • git+ssh
    • git+http
    • git+git
    • git
    • Commit hash
    • Tag name
    • Branch name
    proj @ git+https://github.com/org/proj.git@v1 Executable Schemes Revisions Example hg
    • hg+file
    • hg+https
    • hg+ssh
    • hg+http
    • hg+static-http
    • Revision hash
    • Revision number
    • Tag name
    • Branch name
    proj @ hg+file:///path/to/proj@v1 Executable Schemes Revisions Example svn
    • svn+https
    • svn+ssh
    • svn+http
    • svn+svn
    • svn
    • Revision number
    proj @ svn+file:///path/to/proj Executable Schemes Revisions Example bzr
    • bzr+https
    • bzr+ssh
    • bzr+sftp
    • bzr+lp
    • bzr+http
    • bzr+ftp
    • Revision number
    • Tag name
    proj @ bzr+lp:proj@v1"},{"location":"config/dependency/#local","title":"Local","text":"

    You can install local packages with the file scheme in the following format:

    <NAME> @ file://<HOST>/<PATH>\n

    The <HOST> is only used on Windows systems, where it can refer to a network share. If omitted it is assumed to be localhost and the third slash must still be present.

    The <PATH> can refer to a source archive, a wheel, or a directory containing a Python package.

    Type Unix Windows Source archive proj @ file:///path/to/pkg.tar.gz proj @ file:///c:/path/to/pkg.tar.gz Wheel proj @ file:///path/to/pkg.whl proj @ file:///c:/path/to/pkg.whl Directory proj @ file:///path/to/pkg proj @ file:///c:/path/to/pkg

    Tip

    You may also specify paths relative to your project's root directory on all platforms by using context formatting:

    <NAME> @ {root:uri}/pkg_inside_project\n<NAME> @ {root:uri}/../pkg_alongside_project\n
    "},{"location":"config/dependency/#remote","title":"Remote","text":"

    You can install source archives and wheels by simply referring to a URL:

    black @ https://github.com/psf/black/archive/refs/tags/21.10b0.zip\npytorch @ https://download.pytorch.org/whl/cu102/torch-1.10.0%2Bcu102-cp39-cp39-linux_x86_64.whl\n

    An expected hash value may be specified by appending a #<HASH_ALGORITHM>=<EXPECTED_HASH> component:

    requests @ https://github.com/psf/requests/archive/refs/tags/v2.26.0.zip#sha256=eb729a757f01c10546ebd179ae2aec852dd0d7f8ada2328ccf4558909d859985\n

    If the hash differs from the expected hash, the installation will fail.

    It is recommended that only hashes which are unconditionally provided by the latest version of the standard library's hashlib module be used for hashes. As of Python 3.10, that list consists of:

    • md5
    • sha1
    • sha224
    • sha256
    • sha384
    • sha512
    • blake2b
    • blake2s
    "},{"location":"config/dependency/#complex-syntax","title":"Complex syntax","text":"

    The following is an example that uses features and environment markers:

    pkg[feature1,feature2] @ <REFERENCE> ; python_version < \"3.7\"\n

    Note that the space before the semicolon is required.

    "},{"location":"config/hatch/","title":"Hatch configuration","text":"

    Configuration for Hatch itself is stored in a config.toml file located by default in one of the following platform-specific directories.

    Platform Path macOS ~/Library/Application Support/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch Unix $XDG_CONFIG_HOME/hatch (the XDG_CONFIG_HOME environment variable default is ~/.config)

    You can select a custom path to the file using the --config root option or by setting the HATCH_CONFIG environment variable.

    The file can be managed by the config command group.

    "},{"location":"config/hatch/#mode","title":"Mode","text":"

    The mode key controls how Hatch selects the project to work on.

    "},{"location":"config/hatch/#local","title":"Local","text":"config.toml
    mode = \"local\"\n

    By default, Hatch will look for a pyproject.toml file in the current working directory and any parent directories. The directory storing the first found file will be considered the project root.

    "},{"location":"config/hatch/#project","title":"Project","text":"config.toml
    mode = \"project\"\nproject = \"proj1\"\n\n[projects]\nproj1 = \"/path/to/project1\"\nproj2 = {\"location\": \"/path/to/project2\"}\n\n[dirs]\nproject = [\"/path/to/monorepo1\", \"/path/to/monorepo2\"]\n

    In this mode, Hatch will only work on the selected project. The project is located using multiple heuristics:

    1. If the project is defined in the projects table then it must be a string, or an inline table with a location key, that is the full path to the project.
    2. If the project matches a subdirectory in any of the directories listed in dirs.project, then that will be used as the project root.

    An error will occur if the project cannot be found.

    You can use the config set command to change the project you are working on:

    $ hatch config set project proj2\nNew setting:\nproject = \"proj2\"\n

    The project can be selected on a per-command basis with the -p/--project (environment variable HATCH_PROJECT) root option.

    "},{"location":"config/hatch/#aware","title":"Aware","text":"config.toml
    mode = \"aware\"\n

    This is essentially the local mode with a fallback to the project mode.

    "},{"location":"config/hatch/#shell","title":"Shell","text":"

    You can control the shell used to enter environments with the shell key.

    If defined as a string, it must be the name of one of the supported shells and be available along your PATH.

    config.toml
    shell = \"fish\"\n

    If the executable name of your shell differs from the supported name, you can define the shell as a table with name and path keys.

    config.toml
    [shell]\nname = \"bash\"\npath = \"/bin/ash\"\n

    You can change the default arguments used to spawn most shells with the args key. The default for such supported shells is usually [\"-i\"].

    config.toml
    [shell]\nname = \"bash\"\nargs = [\"--login\"]\n
    "},{"location":"config/hatch/#supported","title":"Supported","text":"Shell Name Arguments macOS Windows Unix Almquist shell ash [\"-i\"] Bash bash [\"-i\"] Command Prompt cmd C shell csh [\"-i\"] fish fish [\"-i\"] Nushell nu [] PowerShell pwsh, powershell tcsh tcsh [\"-i\"] xonsh xonsh [\"-i\"] Z shell zsh [\"-i\"]"},{"location":"config/hatch/#default","title":"Default","text":"

    Hatch will attempt to use the current shell based on parent processes. If the shell cannot be determined, then on Windows systems Hatch will use the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

    "},{"location":"config/hatch/#directories","title":"Directories","text":""},{"location":"config/hatch/#data","title":"Data","text":"config.toml
    [dirs]\ndata = \"...\"\n

    This is the directory that is used to persist data. By default it is set to one of the following platform-specific directories.

    Platform Path macOS ~/Library/Application Support/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch Unix $XDG_DATA_HOME/hatch (the XDG_DATA_HOME environment variable default is ~/.local/share)

    You can select a custom path to the directory using the --data-dir root option or by setting the HATCH_DATA_DIR environment variable.

    "},{"location":"config/hatch/#cache","title":"Cache","text":"config.toml
    [dirs]\ncache = \"...\"\n

    This is the directory that is used to cache data. By default it is set to one of the following platform-specific directories.

    Platform Path macOS ~/Library/Caches/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch\\Cache Unix $XDG_CACHE_HOME/hatch (the XDG_CACHE_HOME environment variable default is ~/.cache)

    You can select a custom path to the directory using the --cache-dir root option or by setting the HATCH_CACHE_DIR environment variable.

    "},{"location":"config/hatch/#environments","title":"Environments","text":"config.toml
    [dirs.env]\n<ENV_TYPE> = \"...\"\n

    This determines where to store environments, with every key being the type of environment and the value being the desired storage location.

    For example, if you wanted to store virtual environments in a .virtualenvs directory within your home directory, you could specify the following:

    config.toml
    [dirs.env]\nvirtual = \"~/.virtualenvs\"\n

    Any environment variables are also expanded.

    If the path is not absolute, then it will be relative to the project root. So if you wanted to use a directory named .hatch in each project directory, you could do:

    config.toml
    [dirs.env]\nvirtual = \".hatch\"\n

    Any type of environment that is not explicitly defined will default to <DATA_DIR>/env/<ENV_TYPE>.

    "},{"location":"config/hatch/#python-installations","title":"Python installations","text":"config.toml
    [dirs]\npython = \"...\"\n

    This determines where to install specific versions of Python.

    The following values have special meanings:

    Value Path isolated (default) <DATA_DIR>/pythons"},{"location":"config/hatch/#terminal","title":"Terminal","text":"

    You can configure how all output is displayed using the terminal.styles table. These settings are also applied to all plugins.

    config.toml
    [terminal.styles]\nerror = \"...\"\n...\n

    Cross-platform terminal capabilities are provided by Rich.

    "},{"location":"config/hatch/#output-levels","title":"Output levels","text":"

    The levels of output are as follows. Note that the verbosity indicates the minimum level at which the output is displayed.

    Level Default Verbosity Description debug bold 1 - 3 Messages that are not useful for most user experiences error bold red -2 Messages indicating some unrecoverable error info bold 0 Messages conveying basic information success bold cyan 0 Messages indicating some positive outcome waiting bold magenta 0 Messages shown before potentially time consuming operations warning bold yellow -1 Messages conveying important information

    See the documentation and color reference for guidance on valid values.

    "},{"location":"config/hatch/#spinner","title":"Spinner","text":"

    You can select the sequence used for waiting animations with the spinner option.

    config.toml
    [terminal.styles]\nspinner = \"...\"\n
    "},{"location":"config/metadata/","title":"Configuring project metadata","text":"

    Project metadata is stored in a pyproject.toml file located at the root of a project's tree and is based entirely on the standard.

    "},{"location":"config/metadata/#name","title":"Name (required)","text":"

    The name of the project.

    pyproject.toml
    [project]\nname = \"your-app\"\n
    "},{"location":"config/metadata/#version","title":"Version (required)","text":"pyproject.toml DynamicStatic

    See the dedicated versioning section.

    [project]\n...\ndynamic = [\"version\"]\n\n[tool.hatch.version]\npath = \"...\"\n
    [project]\n...\nversion = \"0.0.1\"\n
    "},{"location":"config/metadata/#description","title":"Description","text":"

    A brief summary of the project.

    pyproject.toml
    [project]\n...\ndescription = '...'\n
    "},{"location":"config/metadata/#readme","title":"Readme","text":"

    The full description of the project.

    pyproject.toml SimpleComplex

    The file extension must be .md, .rst, or .txt.

    [project]\n...\nreadme = \"README.md\"\n

    The content-type field must be set to text/markdown, text/x-rst, or text/plain.

    FileText

    A charset field may also be set to instruct which encoding to use for reading the file, defaulting to utf-8.

    [project]\n...\nreadme = {\"file\" = \"README.md\", \"content-type\" = \"text/markdown\"}\n

    The content-type field must be set to text/markdown or text/x-rst.

    [project]\n...\nreadme = {\"text\" = \"...\", \"content-type\" = \"text/markdown\"}\n

    Note

    If this is defined as a file, then it will always be included in source distributions for consistent builds.

    "},{"location":"config/metadata/#python-support","title":"Python support","text":"

    The Python version requirements of the project.

    pyproject.toml
    [project]\n...\nrequires-python = \">=3.8\"\n
    "},{"location":"config/metadata/#license","title":"License","text":"

    For more information, see PEP 639.

    pyproject.toml SPDX expressionFiles
    [project]\n...\nlicense = \"Apache-2.0 OR MIT\"\n
    PathsGlobs
    [project]\n...\nlicense-files = { paths = [\"LICENSE.txt\"] }\n
    [project]\n...\nlicense-files = { globs = [\"LICENSES/*\"] }\n
    "},{"location":"config/metadata/#ownership","title":"Ownership","text":"

    The people or organizations considered to be the authors or maintainers of the project. The exact meaning is open to interpretation; it may list the original or primary authors, current maintainers, or owners of the package. If the values are the same, prefer only the use of the authors field.

    pyproject.toml
    [project]\n...\nauthors = [\n  { name = \"...\", email = \"...\" },\n]\nmaintainers = [\n  { name = \"...\", email = \"...\" },\n]\n
    "},{"location":"config/metadata/#keywords","title":"Keywords","text":"

    The keywords used to assist in the discovery of the project.

    pyproject.toml
    [project]\n...\nkeywords = [\n  \"...\",\n]\n
    "},{"location":"config/metadata/#classifiers","title":"Classifiers","text":"

    The trove classifiers that apply to the project.

    pyproject.toml
    [project]\n...\nclassifiers = [\n  \"...\",\n]\n
    "},{"location":"config/metadata/#urls","title":"URLs","text":"

    A table of URLs where the key is the URL label and the value is the URL itself.

    pyproject.toml
    [project.urls]\nDocumentation = \"...\"\n\"Source code\" = \"...\"\n
    "},{"location":"config/metadata/#dependencies","title":"Dependencies","text":"

    See the dependency specification page for more information.

    Entries support context formatting and disallow direct references by default.

    "},{"location":"config/metadata/#required","title":"Required","text":"pyproject.toml
    [project]\n...\ndependencies = [\n  \"...\",\n]\n
    "},{"location":"config/metadata/#optional","title":"Optional","text":"pyproject.toml
    [project.optional-dependencies]\noption1 = [\n  \"...\",\n]\noption2 = [\n  \"...\",\n]\n
    "},{"location":"config/metadata/#entry-points","title":"Entry points","text":"

    Entry points are a mechanism for the project to advertise components it provides to be discovered and used by other code.

    "},{"location":"config/metadata/#cli","title":"CLI","text":"

    After installing projects that define CLI scripts, each key will be available along your PATH as a command that will call its associated object.

    pyproject.toml
    [project.scripts]\ncli-name = \"pkg.subpkg:func\"\n

    Using the above example, running cli-name would essentially execute the following Python script:

    import sys\n\nfrom pkg.subpkg import func\n\nsys.exit(func())\n
    "},{"location":"config/metadata/#gui","title":"GUI","text":"

    GUI scripts are exactly the same as CLI scripts except on Windows, where they are handled specially so that they can be started without a console.

    pyproject.toml
    [project.gui-scripts]\ngui-name = \"pkg.subpkg:func\"\n
    "},{"location":"config/metadata/#plugins","title":"Plugins","text":"pyproject.toml
    [project.entry-points.plugin-namespace]\nplugin-name1 = \"pkg.subpkg1\"\nplugin-name2 = \"pkg.subpkg2:func\"\n
    "},{"location":"config/metadata/#dynamic","title":"Dynamic","text":"

    If any metadata fields are set dynamically, like the version may be, then they must be listed here.

    pyproject.toml
    [project]\n...\ndynamic = [\n  \"...\",\n]\n
    "},{"location":"config/metadata/#metadata-options","title":"Metadata options","text":""},{"location":"config/metadata/#allowing-direct-references","title":"Allowing direct references","text":"

    By default, dependencies are not allowed to define direct references. To disable this check, set allow-direct-references to true:

    pyproject.toml hatch.toml
    [tool.hatch.metadata]\nallow-direct-references = true\n
    [metadata]\nallow-direct-references = true\n
    "},{"location":"config/metadata/#allowing-ambiguous-features","title":"Allowing ambiguous features","text":"

    By default, names of optional dependencies are normalized to prevent ambiguity. To disable this normalization, set allow-ambiguous-features to true:

    pyproject.toml hatch.toml
    [tool.hatch.metadata]\nallow-ambiguous-features = true\n
    [metadata]\nallow-ambiguous-features = true\n

    Deprecated

    This option temporarily exists to provide better interoperability with tools that do not yet support PEP 685 and will be removed in the first minor release after Jan 1, 2024.

    "},{"location":"config/project-templates/","title":"Project templates","text":"

    You can control how new projects are created by the new command using Hatch's config file.

    "},{"location":"config/project-templates/#author","title":"Author","text":"config.toml
    [template]\nname = \"...\"\nemail = \"...\"\n
    "},{"location":"config/project-templates/#licenses","title":"Licenses","text":"config.toml
    [template.licenses]\nheaders = true\ndefault = [\n  \"MIT\",\n]\n

    The list of licenses should be composed of SPDX identifiers. If multiple licenses are specified, then they will be placed in a LICENSES directory.

    "},{"location":"config/project-templates/#options","title":"Options","text":""},{"location":"config/project-templates/#tests","title":"Tests","text":"

    This adds a tests directory with environments for testing and linting.

    config.toml
    [template.plugins.default]\ntests = true\n
    "},{"location":"config/project-templates/#ci","title":"CI","text":"

    This adds a GitHub Actions workflow that runs tests on all platforms using modern versions of Python.

    config.toml
    [template.plugins.default]\nci = false\n
    "},{"location":"config/project-templates/#src-layout","title":"src layout","text":"

    See this blog post.

    config.toml
    [template.plugins.default]\nsrc-layout = true\n
    "},{"location":"config/project-templates/#feature-flags","title":"Feature flags","text":""},{"location":"config/project-templates/#command-line-interface","title":"Command line interface","text":"

    The --cli flag adds a CLI backed by Click that can also be invoked with python -m <PKG_NAME>.

    "},{"location":"config/static-analysis/","title":"Static analysis configuration","text":"

    Static analysis performed by the fmt command is (by default) backed entirely by Ruff.

    Hatch provides default settings that user configuration can extend.

    "},{"location":"config/static-analysis/#extending-config","title":"Extending config","text":"

    When defining your configuration, be sure to use options that are prefixed by extend- such as extend-select, for example:

    pyproject.toml ruff.toml
    [tool.ruff.format]\npreview = true\nquote-style = \"single\"\n\n[tool.ruff.lint]\npreview = true\nextend-select = [\"C901\"]\n\n[tool.ruff.lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[tool.ruff.lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n
    [format]\npreview = true\nquote-style = \"single\"\n\n[lint]\npreview = true\nextend-select = [\"C901\"]\n\n[lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n

    Note

    When not persisting config, there is no need to explicitly extend the defaults as Hatch automatically handles that.

    "},{"location":"config/static-analysis/#persistent-config","title":"Persistent config","text":"

    If you want to store the default configuration in the project, set an explicit path like so:

    pyproject.toml hatch.toml
    [tool.hatch.envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n
    [envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n

    Then instruct Ruff to consider your configuration as an extension of the default file:

    pyproject.toml ruff.toml
    [tool.ruff]\nextend = \"ruff_defaults.toml\"\n
    extend = \"ruff_defaults.toml\"\n

    Anytime you wish to update the defaults (such as when upgrading Hatch), you must run the fmt command once with the --sync flag e.g.:

    hatch fmt --check --sync\n

    Tip

    This is the recommended approach since it allows other tools like IDEs to use the default configuration.

    "},{"location":"config/static-analysis/#no-config","title":"No config","text":"

    If you don't want Hatch to use any of its default configuration and rely entirely on yours, set the path to anything and then simply don't extend in your Ruff config:

    pyproject.toml hatch.toml
    [tool.hatch.envs.hatch-static-analysis]\nconfig-path = \"none\"\n
    [envs.hatch-static-analysis]\nconfig-path = \"none\"\n
    "},{"location":"config/static-analysis/#customize-behavior","title":"Customize behavior","text":"

    You can fully alter the behavior of the environment used by the fmt command. See the how-to for a detailed example.

    "},{"location":"config/static-analysis/#dependencies","title":"Dependencies","text":"

    Pin the particular version of Ruff by explicitly defining the environment dependencies:

    pyproject.toml hatch.toml
    [tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
    [envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
    "},{"location":"config/static-analysis/#scripts","title":"Scripts","text":"

    If you want to change the default commands that are executed, you can override the scripts. The following four scripts must be defined:

    pyproject.toml hatch.toml
    [tool.hatch.envs.hatch-static-analysis.scripts]\nformat-check = \"...\"\nformat-fix = \"...\"\nlint-check = \"...\"\nlint-fix = \"...\"\n
    [envs.hatch-static-analysis.scripts]\nformat-check = \"...\"\nformat-fix = \"...\"\nlint-check = \"...\"\nlint-fix = \"...\"\n

    The format-* scripts correspond to the --formatter/-f flag while the lint-* scripts correspond to the --linter/-l flag. The *-fix scripts run by default while the *-check scripts correspond to the --check flag.

    Reminder

    If you choose to use different tools for static analysis, be sure to update the required dependencies.

    "},{"location":"config/static-analysis/#default-settings","title":"Default settings","text":""},{"location":"config/static-analysis/#non-rule-settings","title":"Non-rule settings","text":"
    • Line length set to 120
    • Docstring formatting enabled with line length set to 80
    • Only absolute imports are allowed, except for tests
    • The normalized project name is a known first party import
    "},{"location":"config/static-analysis/#per-file-ignored-rules","title":"Per-file ignored rules","text":"
    • **/scripts/*: INP001, T201
    • **/tests/**/*: PLC1901, PLR2004, PLR6301, S, TID252
    "},{"location":"config/static-analysis/#selected-rules","title":"Selected rules","text":"

    The following rules are based on version 0.3.1 of Ruff. Rules with a P are only selected when preview mode is enabled.

    • A001, A002, A003
    • ARG001, ARG002, ARG003, ARG004, ARG005
    • ASYNC100, ASYNC101, ASYNC102
    • B002, B003, B004, B005, B006, B007, B008, B009, B010, B011, B012, B013, B014, B015, B016, B017, B018, B019, B020, B021, B022, B023, B024, B025, B026, B028, B029, B030, B031, B032, B033, B034, B035, B904, B905
    • BLE001
    • C400, C401, C402, C403, C404, C405, C406, C408, C409, C410, C411, C413, C414, C415, C416, C417, C418, C419
    • COM818
    • DTZ001, DTZ002, DTZ003, DTZ004, DTZ005, DTZ006, DTZ007, DTZ011, DTZ012
    • E101, E112P, E113P, E115P, E116P, E201P, E202P, E203P, E211P, E221P, E222P, E223P, E224P, E225P, E226P, E227P, E228P, E231P, E241P, E242P, E251P, E252P, E261P, E262P, E265P, E266P, E271P, E272P, E273P, E274P, E275P, E401, E402, E501, E701, E702, E703, E711, E712, E713, E714, E721, E722, E731, E741, E742, E743, E902, E999
    • EM101, EM102, EM103
    • EXE001, EXE002, EXE003, EXE004, EXE005
    • F401, F402, F403, F404, F405, F406, F407, F501, F502, F503, F504, F505, F506, F507, F508, F509, F521, F522, F523, F524, F525, F541, F601, F602, F621, F622, F631, F632, F633, F634, F701, F702, F704, F706, F707, F722, F811, F821, F822, F823, F841, F842, F901
    • FA100, FA102
    • FBT001, FBT002
    • FLY002
    • FURB105P, FURB113P, FURB118P, FURB129P, FURB131P, FURB132P, FURB136P, FURB145P, FURB148P, FURB152P, FURB161P, FURB163P, FURB167P, FURB168P, FURB169P, FURB171P, FURB177P, FURB180P, FURB181P
    • G001, G002, G003, G004, G010, G101, G201, G202
    • I001, I002
    • ICN001, ICN002, ICN003
    • INP001
    • INT001, INT002, INT003
    • ISC003
    • LOG001, LOG002, LOG007, LOG009
    • N801, N802, N803, N804, N805, N806, N807, N811, N812, N813, N814, N815, N816, N817, N818, N999
    • PERF101, PERF102, PERF401, PERF402, PERF403P
    • PGH005
    • PIE790, PIE794, PIE796, PIE800, PIE804, PIE807, PIE808, PIE810
    • PLC0105, PLC0131, PLC0132, PLC0205, PLC0208, PLC0414, PLC0415P, PLC1901P, PLC2401P, PLC2403P, PLC2701P, PLC2801P, PLC3002
    • PLE0100, PLE0101, PLE0116, PLE0117, PLE0118, PLE0237, PLE0241, PLE0302, PLE0307, PLE0604, PLE0605, PLE0643P, PLE0704P, PLE1132P, PLE1141P, PLE1142, PLE1205, PLE1206, PLE1300, PLE1307, PLE1310, PLE1507, PLE1519P, PLE1700, PLE2502, PLE2510, PLE2512, PLE2513, PLE2514, PLE2515
    • PLR0124, PLR0133, PLR0202P, PLR0203P, PLR0206, PLR0402, PLR1701, PLR1704P, PLR1711, PLR1714, PLR1722, PLR1733P, PLR1736P, PLR2004, PLR2044P, PLR5501, PLR6201P, PLR6301P
    • PLW0108P, PLW0120, PLW0127, PLW0129, PLW0131, PLW0133P, PLW0245P, PLW0406, PLW0602, PLW0603, PLW0604P, PLW0711, PLW1501P, PLW1508, PLW1509, PLW1510, PLW1514P, PLW1641P, PLW2101P, PLW2901, PLW3201P, PLW3301
    • PT001, PT002, PT003, PT006, PT007, PT008, PT009, PT010, PT011, PT012, PT013, PT014, PT015, PT016, PT017, PT018, PT019, PT020, PT021, PT022, PT023, PT024, PT025, PT026, PT027
    • PYI001, PYI002, PYI003, PYI004, PYI005, PYI006, PYI007, PYI008, PYI009, PYI010, PYI011, PYI012, PYI013, PYI014, PYI015, PYI016, PYI017, PYI018, PYI019, PYI020, PYI021, PYI024, PYI025, PYI026, PYI029, PYI030, PYI032, PYI033, PYI034, PYI035, PYI036, PYI041, PYI042, PYI043, PYI044, PYI045, PYI046, PYI047, PYI048, PYI049, PYI050, PYI051, PYI052, PYI053, PYI054, PYI055, PYI056, PYI058
    • RET503, RET504, RET505, RET506, RET507, RET508
    • RSE102
    • RUF001, RUF002, RUF003, RUF005, RUF006, RUF007, RUF008, RUF009, RUF010, RUF012, RUF013, RUF015, RUF016, RUF017, RUF018, RUF019, RUF020, RUF021P, RUF022P, RUF023P, RUF024P, RUF025P, RUF026P, RUF027P, RUF028P, RUF100, RUF200
    • S101, S102, S103, S104, S105, S106, S107, S108, S110, S112, S113, S201, S202, S301, S302, S303, S304, S305, S306, S307, S308, S310, S311, S312, S313, S314, S315, S316, S317, S318, S319, S320, S321, S323, S324, S401P, S402P, S403P, S405P, S406P, S407P, S408P, S409P, S411P, S412P, S413P, S415P, S501, S502, S503, S504, S505, S506, S507, S508, S509, S601, S602, S604, S605, S606, S607, S608, S609, S611, S612, S701, S702
    • SIM101, SIM102, SIM103, SIM105, SIM107, SIM108, SIM109, SIM110, SIM112, SIM113, SIM114, SIM115, SIM116, SIM117, SIM118, SIM201, SIM202, SIM208, SIM210, SIM211, SIM212, SIM220, SIM221, SIM222, SIM223, SIM300, SIM910, SIM911
    • SLF001
    • SLOT000, SLOT001, SLOT002
    • T100, T201, T203
    • TCH001, TCH002, TCH003, TCH004, TCH005, TCH010
    • TD004, TD005, TD006, TD007
    • TID251, TID252, TID253
    • TRIO100, TRIO105, TRIO109, TRIO110, TRIO115
    • TRY002, TRY003, TRY004, TRY201, TRY300, TRY301, TRY302, TRY400, TRY401
    • UP001, UP003, UP004, UP005, UP006, UP007, UP008, UP009, UP010, UP011, UP012, UP013, UP014, UP015, UP017, UP018, UP019, UP020, UP021, UP022, UP023, UP024, UP025, UP026, UP027, UP028, UP029, UP030, UP031, UP032, UP033, UP034, UP035, UP036, UP037, UP038, UP039, UP040, UP041
    • W291, W292, W293, W505, W605
    • YTT101, YTT102, YTT103, YTT201, YTT202, YTT203, YTT204, YTT301, YTT302, YTT303
    "},{"location":"config/environment/advanced/","title":"Advanced environment configuration","text":""},{"location":"config/environment/advanced/#context-formatting","title":"Context formatting","text":"

    All environments support the following extra context formatting fields:

    Field Description env_name The name of the environment env_type The type of environment matrix Its modifier selects the value of that matrix variable. If the environment is not part of a matrix or was not generated with the variable, you must specify a default value as an additional modifier e.g. {matrix:version:v1.0.0}. verbosity The integer verbosity value of Hatch. A flag modifier is supported that will render the value as a CLI flag e.g. -2 becomes -qq, 1 becomes -v, and 0 becomes an empty string. An additional flag integer modifier may be used to adjust the verbosity level. For example, if you wanted to make a command quiet by default, you could use {verbosity:flag:-1} within the command. args For executed commands only, any extra command line arguments with an optional default modifier if none were provided"},{"location":"config/environment/advanced/#matrix","title":"Matrix","text":"

    Environments can define a series of matrices with the matrix option:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
    [envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n

    Doing so will result in the product of each variable combination being its own environment.

    "},{"location":"config/environment/advanced/#naming","title":"Naming","text":"

    The name of the generated environments will be the variable values of each combination separated by hyphens, altogether prefixed by <ENV_NAME>.. For example, the following configuration:

    pyproject.toml hatch.toml
    [[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
    [[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n

    would indicate the following unique environments:

    test.42-foo\ntest.42-bar\n

    The exceptions to this format are described below.

    "},{"location":"config/environment/advanced/#python-variables","title":"Python variables","text":"

    If the variables py or python are specified, then they will rank first in the product result and will be prefixed by py if the value is not. For example, the following configuration:

    pyproject.toml hatch.toml
    [[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n
    [[envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n

    would generate the following environments:

    test.py3.9-42\ntest.pypy3-42\n

    Note

    The value of this variable sets the Python version.

    "},{"location":"config/environment/advanced/#name-formatting","title":"Name formatting","text":"

    You can set the matrix-name-format option to modify how each variable part is formatted which recognizes the placeholders {variable} and {value}. For example, the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
    [envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n

    would produce the following environments:

    test.version_42-feature_foo\ntest.version_42-feature_bar\n

    By default this option is set to {value}.

    "},{"location":"config/environment/advanced/#default-environment","title":"Default environment","text":"

    If the default environment defines matrices, then the generated names will not be prefixed by the environment name. This can be useful for projects that only need a single series of matrices without any standalone environments.

    "},{"location":"config/environment/advanced/#selection","title":"Selection","text":"

    Rather than selecting a single generated environment, you can select the root environment to target all of them. For example, if you have the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[tool.hatch.envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n
    [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n

    you could then run your tests consecutively in all 4 environments with:

    hatch run test:cov\n
    "},{"location":"config/environment/advanced/#option-overrides","title":"Option overrides","text":"

    You can modify options based on the conditions of different sources like matrix variables with the overrides table, using dotted key syntax for each declaration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n
    [envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n

    The type of the selected option determines the types of values.

    "},{"location":"config/environment/advanced/#platform-overrides","title":"Platform overrides","text":"

    Options can be modified based on the current platform using the platform source.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nplatform.windows.scripts = [\n  'run=pytest -m \"not io_uring\"',\n]\n
    [envs.test.overrides]\nplatform.windows.scripts = [\n  'run=pytest -m \"not io_uring\"',\n]\n

    The following platforms are supported:

    • linux
    • windows
    • macos
    "},{"location":"config/environment/advanced/#environment-variable-overrides","title":"Environment variable overrides","text":"

    Environment variables can modify options using the env source.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
    [envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
    "},{"location":"config/environment/advanced/#matrix-variable-overrides","title":"Matrix variable overrides","text":"

    The matrix variables used to generate each environment can be used to modify options within using the matrix source.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n  { value = \"oauth\", if = [\"oauth2\"] },\n  { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
    [envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n  { value = \"oauth\", if = [\"oauth2\"] },\n  { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
    "},{"location":"config/environment/advanced/#name-overrides","title":"Name overrides","text":"

    When a matrix is defined, the name source can be used for regular expression matching on the generated name, minus the prefix for non-default environments.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
    [envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
    "},{"location":"config/environment/advanced/#types","title":"Types","text":"
    • Literal types like strings for the Python version or booleans for skipping installation can be set using the value itself, an inline table, or an array. For example:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n  { value = false, if = [\"...\"] },\n  true,\n]\n
      [envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n  { value = false, if = [\"...\"] },\n  true,\n]\n

      For arrays, the first allowed value will be used.

    • Array types like dependencies or commands can be appended to using an array of strings or inline tables. For example:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.foo.dependencies = [\n  \"httpx\",\n  { value = \"cryptography\" },\n]\n
      [envs.test.overrides]\nmatrix.foo.dependencies = [\n  \"httpx\",\n  { value = \"cryptography\" },\n]\n
    • Mapping types like environment variables or scripts can have keys set using a string, or an array of strings or inline tables. For example:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n  \"KEY1=VALUE1\",\n  { key = \"KEY2\", value = \"VALUE2\" },\n]\n
      [envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n  \"KEY1=VALUE1\",\n  { key = \"KEY2\", value = \"VALUE2\" },\n]\n

      If the value is missing (no = for strings, no value key for inline tables), then the value will be set to the value of the source condition.

    "},{"location":"config/environment/advanced/#overwriting","title":"Overwriting","text":"

    Rather than supplementing the values within mapping types or array types, you can overwrite the option as a whole by prefixing the name with set-:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n
    [envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n

    When overwriting entire options or keys within mappings, override sources are applied in the following order:

    1. platform
    2. environment variables
    3. matrix variables
    4. names
    "},{"location":"config/environment/advanced/#conditions","title":"Conditions","text":"

    You may specify certain extra keys for any inline table that will determine whether or not to apply that entry. These modifiers may be combined with others and any negative evaluation will immediately cause the entry to be skipped.

    "},{"location":"config/environment/advanced/#allowed-values","title":"Allowed values","text":"

    The if key represents the allowed values for that condition. If the value of the condition is not listed, then that entry will not be applied:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    [envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    "},{"location":"config/environment/advanced/#specific-platforms","title":"Specific platforms","text":"

    The platform key represents the desired platforms. If the current platform is not listed, then that entry will not be applied:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    [envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    "},{"location":"config/environment/advanced/#required-environment-variables","title":"Required environment variables","text":"

    The env key represents the required environment variables. If any of the listed environment variables are not set or the defined value does not match, then that entry will not be applied:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    [envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
    "},{"location":"config/environment/overview/","title":"Environment configuration","text":"

    All environments are defined as sections within the tool.hatch.envs table.

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\n
    [envs.<ENV_NAME>]\n

    The storage location for environments is completely configurable.

    Unless an environment is explicitly selected on the command line, the default environment will be used. The type of this environment defaults to virtual.

    Info

    Environments prefixed by hatch- are used for special purposes e.g. static analysis.

    "},{"location":"config/environment/overview/#inheritance","title":"Inheritance","text":"

    All environments inherit from the environment defined by its template option, which defaults to default.

    So for the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[tool.hatch.envs.bar]\ntemplate = \"foo\"\nskip-install = false\n
    [envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[envs.bar]\ntemplate = \"foo\"\nskip-install = false\n

    the environment bar will be of type baz with skip-install set to false.

    Note

    Environments do not inherit matrices.

    "},{"location":"config/environment/overview/#self-referential-environments","title":"Self-referential environments","text":"

    You can disable inheritance by setting template to the environment's own name:

    pyproject.toml hatch.toml
    [tool.hatch.envs.foo]\ntemplate = \"foo\"\n
    [envs.foo]\ntemplate = \"foo\"\n
    "},{"location":"config/environment/overview/#detached-environments","title":"Detached environments","text":"

    A common use case is standalone environments that do not require inheritance nor the installation of the project, such as for linting or sometimes building documentation. Enabling the detached option will make the environment self-referential and will skip project installation:

    pyproject.toml hatch.toml
    [tool.hatch.envs.lint]\ndetached = true\n
    [envs.lint]\ndetached = true\n
    "},{"location":"config/environment/overview/#dependencies","title":"Dependencies","text":"

    You can install dependencies in addition to the ones defined by your project's metadata. Entries support context formatting.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n
    [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n

    If you define environments with dependencies that only slightly differ from their inherited environments, you can use the extra-dependencies option to avoid redeclaring the dependencies option:

    pyproject.toml hatch.toml
    [tool.hatch.envs.default]\ndependencies = [\n  \"foo\",\n  \"bar\",\n]\n\n[tool.hatch.envs.experimental]\nextra-dependencies = [\n  \"baz\",\n]\n
    [envs.default]\ndependencies = [\n  \"foo\",\n  \"bar\",\n]\n\n[envs.experimental]\nextra-dependencies = [\n  \"baz\",\n]\n

    Tip

    Hatch uses pip to install dependencies so any configuration it supports Hatch does as well. For example, if you wanted to only use a private repository you could set the PIP_INDEX_URL environment variable.

    "},{"location":"config/environment/overview/#installation","title":"Installation","text":""},{"location":"config/environment/overview/#features","title":"Features (extras)","text":"

    If your project defines optional dependencies, you can select which groups to install using the features option:

    pyproject.toml hatch.toml
    [tool.hatch.envs.nightly]\nfeatures = [\n  \"server\",\n  \"grpc\",\n]\n
    [envs.nightly]\nfeatures = [\n  \"server\",\n  \"grpc\",\n]\n

    Note

    Features/optional dependencies are also known as extras in other tools.

    "},{"location":"config/environment/overview/#dev-mode","title":"Dev mode","text":"

    By default, environments will always reflect the current state of your project on disk. Set dev-mode to false to disable this behavior:

    pyproject.toml hatch.toml
    [tool.hatch.envs.static]\ndev-mode = false\n
    [envs.static]\ndev-mode = false\n
    "},{"location":"config/environment/overview/#skip-install","title":"Skip install","text":"

    By default, environments will install your project during creation. To ignore this step, set skip-install to true:

    pyproject.toml hatch.toml
    [tool.hatch.envs.lint]\nskip-install = true\n
    [envs.lint]\nskip-install = true\n
    "},{"location":"config/environment/overview/#environment-variables","title":"Environment variables","text":""},{"location":"config/environment/overview/#defined","title":"Defined","text":"

    You can define environment variables with the env-vars option:

    pyproject.toml hatch.toml
    [tool.hatch.envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[tool.hatch.envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
    [envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n

    Values support context formatting.

    "},{"location":"config/environment/overview/#filters","title":"Filters","text":"

    By default, environments will have access to all environment variables. You can filter with wildcard patterns using the env-include/env-exclude options:

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nenv-include = [\n  \"FOO*\",\n]\nenv-exclude = [\n  \"BAR\",\n]\n
    [envs.<ENV_NAME>]\nenv-include = [\n  \"FOO*\",\n]\nenv-exclude = [\n  \"BAR\",\n]\n

    Exclusion patterns take precedence but will never affect defined environment variables.

    "},{"location":"config/environment/overview/#scripts","title":"Scripts","text":"

    You can define named scripts that may be executed or referenced at the beginning of other scripts. Context formatting is supported.

    For example, in the following configuration:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n[tool.hatch.envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n
    [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n[envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n

    the run script would be expanded to:

    pytest --cov-config=pyproject.toml --cov=pkg --cov=tests --no-cov\n

    Scripts can also be defined as an array of strings.

    pyproject.toml hatch.toml
    [tool.hatch.envs.style]\ndetached = true\ndependencies = [\n  \"flake8\",\n  \"black\",\n  \"isort\",\n]\n[tool.hatch.envs.style.scripts]\ncheck = [\n  \"flake8 .\",\n  \"black --check --diff .\",\n  \"isort --check-only --diff .\",\n]\nfmt = [\n  \"isort .\",\n  \"black .\",\n  \"check\",\n]\n
    [envs.style]\ndetached = true\ndependencies = [\n  \"flake8\",\n  \"black\",\n  \"isort\",\n]\n[envs.style.scripts]\ncheck = [\n  \"flake8 .\",\n  \"black --check --diff .\",\n  \"isort --check-only --diff .\",\n]\nfmt = [\n  \"isort .\",\n  \"black .\",\n  \"check\",\n]\n

    Similar to make, you can ignore the exit code of commands that start with - (a hyphen). For example, the script error defined by the following configuration would halt after the second command with 3 as the exit code:

    pyproject.toml hatch.toml
    [tool.hatch.envs.test.scripts]\nerror = [\n  \"- exit 1\",\n  \"exit 3\",\n  \"exit 0\",\n]\n
    [envs.test.scripts]\nerror = [\n  \"- exit 1\",\n  \"exit 3\",\n  \"exit 0\",\n]\n

    Tip

    Individual scripts inherit from parent environments just like options.

    "},{"location":"config/environment/overview/#commands","title":"Commands","text":"

    All commands are able to use any defined scripts. Also like scripts, context formatting is supported and the exit code of commands that start with a hyphen will be ignored.

    "},{"location":"config/environment/overview/#pre-install","title":"Pre-install","text":"

    You can run commands immediately before environments install your project.

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\npre-install-commands = [\n  \"...\",\n]\n
    [envs.<ENV_NAME>]\npre-install-commands = [\n  \"...\",\n]\n
    "},{"location":"config/environment/overview/#post-install","title":"Post-install","text":"

    You can run commands immediately after environments install your project.

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\npost-install-commands = [\n  \"...\",\n]\n
    [envs.<ENV_NAME>]\npost-install-commands = [\n  \"...\",\n]\n
    "},{"location":"config/environment/overview/#python-version","title":"Python version","text":"

    The python option specifies which version of Python to use, or an absolute path to a Python interpreter:

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\npython = \"3.10\"\n
    [envs.<ENV_NAME>]\npython = \"3.10\"\n

    All environment types should respect this option.

    "},{"location":"config/environment/overview/#supported-platforms","title":"Supported platforms","text":"

    The platforms option indicates the operating systems with which the environment is compatible:

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n
    [envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n

    The following platforms are supported:

    • linux
    • windows
    • macos

    If unspecified, the environment is assumed to be compatible with all platforms.

    "},{"location":"config/environment/overview/#description","title":"Description","text":"

    The description option is purely informational and is displayed in the output of the env show command:

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
    [envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
    "},{"location":"config/environment/overview/#type","title":"Type","text":"

    An environment's type determines which environment plugin will be used for management. The only built-in environment type is virtual, which uses virtual Python environments.

    "},{"location":"history/hatch/","title":"Hatch history","text":"

    All notable changes to Hatch will be documented in this file.

    The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

    "},{"location":"history/hatch/#unreleased","title":"Unreleased","text":"

    Added:

    • Add self report command for submitting pre-populated bug reports to GitHub
    • The reserved environment used for static analysis is now completely configurable
    • Add the following methods to the environment interface for complete control over output during life cycle management: app_status_creation, app_status_pre_installation, app_status_post_installation, app_status_project_installation, app_status_dependency_state_check, app_status_dependency_installation_check, app_status_dependency_synchronization
    • Add binaries for 32-bit versions of Windows
    • Read configuration from any ~/.pypirc file for the index publisher
    • Use the Git user as the default username for new project URL metadata
    • Add HATCH_DEBUG environment variable that when enabled will show local variables in the case of unhandled tracebacks
    • Upgrade default CPython distributions to 20240224
    • Upgrade Ruff to 0.3.1
    • Upgrade PyApp to 0.15.1 for binary builds
    • Bump the minimum supported version of Hatchling to 1.22.2

    Fixed:

    • When projects derive dependencies from metadata hooks, there is now by default a status indicator for when the hooks are executed for better responsiveness
    • Fix dependency inheritance for the template of the types environment for new projects
    "},{"location":"history/hatch/#hatch-v1.9.4","title":"1.9.4 - 2024-03-12","text":"

    Fixed:

    • Limit the maximum version of Hatchling in anticipation of backward incompatible changes
    "},{"location":"history/hatch/#hatch-v1.9.3","title":"1.9.3 - 2024-01-25","text":"

    Fixed:

    • Fix loading of local plugins to account for newly released versions of a dependency
    "},{"location":"history/hatch/#hatch-v1.9.2","title":"1.9.2 - 2024-01-21","text":"

    Fixed:

    • Fix the default token variable name for publishing to PyPI
    "},{"location":"history/hatch/#hatch-v1.9.1","title":"1.9.1 - 2023-12-25","text":"

    Fixed:

    • Ensure that the dependency_hash method of the environment interface is called after sync_dependencies for cases where the hash is only known at that point, such as for dependency lockers
    • Only acknowledge the HATCH_PYTHON_VARIANT_* environment variables for Python resolution for supported platforms and architectures
    • Fix Python resolution when there are metadata hooks with unsatisfied dependencies
    "},{"location":"history/hatch/#hatch-v1.9.0","title":"1.9.0 - 2023-12-19","text":"

    Changed:

    • Environments prefixed by hatch- are now considered internal and used for special purposes such as configuration for static analysis

    Added:

    • Enable docstring formatting by default for static analysis
    • Allow for overriding config of internal environments
    • Concretely state the expected API contract for the environment interface methods find and check_compatibility
    • Upgrade Ruff to 0.1.8
    • Bump the minimum supported version of Hatchling to 1.21.0

    Fixed:

    • Ignore a project's Python requirement for environments where the project is not installed
    • When not persisting config for static analysis, properly manage internal settings when Ruff's top level table already exists
    • Ignore compatibility checks when environments have already been created, significantly improving performance of environment usage
    • Properly allow overriding of the path option for the virtual environment type
    • Fix nushell activation on non-Windows systems
    "},{"location":"history/hatch/#hatch-v1.8.1","title":"1.8.1 - 2023-12-14","text":"

    Fixed:

    • Fix regression in calling subprocesses with updated PATH
    • Fix automatic installation of environment plugins when running as a standalone binary
    • Change default location of Python installations
    "},{"location":"history/hatch/#hatch-v1.8.0","title":"1.8.0 - 2023-12-11","text":"

    Changed:

    • Drop support for Python 3.7
    • The get_build_process method of the environment interface has been removed; plugins should use the new run_builder method instead
    • Remove pyperclip dependency and the --copy flag of the config find command
    • When running the build command all output from builders is now displayed as-is in real time without the stripping of ANSI codes
    • Version information (for Hatch itself) is now derived from Git

    Added:

    • Support Python 3.12
    • Add installers and standalone binaries
    • Add the ability to manage Python installations
    • Add fmt command
    • The virtual environment type can now automatically download requested versions of Python that are not installed
    • Add dependency_hash method to the environment interface
    • The state of installed dependencies for environments is saved as metadata so if dependency definitions have not changed then no checking is performed, which can be computationally expensive
    • The build command now supports backends other than Hatchling
    • Allow the use of features for environments when skip-install is enabled
    • The default is now __token__ when prompting for a username for the publish command
    • Add a new run_builder method to the environment interface
    • Bump the minimum supported version of Hatchling to 1.19.0
    • Bump the minimum supported version of click to 8.0.6

    Fixed:

    • Fix nushell activation
    • Better handling of flat storage directory hierarchies for the virtual environment type
    • Display useful information when running the version command outside of a project rather than erroring
    • Fix the project metadata command by only capturing stdout from the backend
    • Properly support Google Artifact Registry
    • Fix parsing dependencies for environments when warnings are emitted
    "},{"location":"history/hatch/#hatch-v1.7.0","title":"1.7.0 - 2023-04-03","text":"

    Changed:

    • The src-layout project template option is now enabled by default
    • Non-critical output now goes to stderr

    Added:

    • Add tool.hatch.env.requires configuration to automatically install dependencies for environment and environment collector plugins
    • Add custom environment collector
    • Improve syncing of dependencies provided through Git direct references
    • Add isolated_data_directory attribute to the environment interface
    • Increase the timeout for and add retries to the index publisher
    • Expand home and environment variables in configured cache and data directories
    • Improve readability of exceptions
    • Update project templates
    • Bump the minimum supported version of Hatchling to 1.14.0

    Fixed:

    • Fix displaying the version with the version command when the version is static and build dependencies are unmet
    • Fix build environments for the virtual environment type when storing within a relative path
    • Work around System Integrity Protection on macOS when running commands
    • Allow setuptools metadata migration for projects without setup.py if setup.cfg is present
    • Handle additional edge cases for setuptools metadata migration
    • Support boolean values for the config set command
    "},{"location":"history/hatch/#hatch-v1.6.3","title":"1.6.3 - 2022-10-24","text":"

    Fixed:

    • Fix version command when the version is dynamic and build dependencies are unmet
    "},{"location":"history/hatch/#hatch-v1.6.2","title":"1.6.2 - 2022-10-20","text":"

    Fixed:

    • Fix getting dynamic metadata from hooks for environments when dependencies are not dynamic
    "},{"location":"history/hatch/#hatch-v1.6.1","title":"1.6.1 - 2022-10-16","text":"

    Fixed:

    • Computing the path to the user's home directory now gracefully falls back to ~ when it cannot be determined
    "},{"location":"history/hatch/#hatch-v1.6.0","title":"1.6.0 - 2022-10-08","text":"

    Changed:

    • The run_shell_command environment interface method now accepts arbitrary subprocess.Popen keyword arguments. This is not strictly breaking, but will be utilized in upcoming features.
    • The internal directory structure for storing virtual environments is now more nested. This is not breaking, but any local environments will be created anew.

    Added:

    • Add project command group to view details about the project like PEP 621 metadata
    • Better support for auto-detection of environments by tools like Visual Studio Code now that the storage directory of virtual environments will be flat if Hatch's configured virtual environment directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
    • Build environments for the virtual environment type are now cached for improved performance
    • Add build_environment_exists method to the environment interface for implementations that cache the build environment
    • Add path option to the virtual environment type
    • Add --initialize-auth flag to the index publisher to allow for the saving of authentication information before publishing
    • Support Bash on Windows for the shell command
    • The setuptools migration script no longer modifies the formatting of existing pyproject.toml configuration
    • Bump the minimum supported version of Hatchling to 1.11.0

    Fixed:

    • Environments now respect dynamically defined project dependencies
    • The dep hash and all dep show commands now respect dynamically defined project dependencies
    • The env show, dep hash, and all dep show commands now honor context formatting
    • Fix matrix variable inclusion filtering of the run and env run commands when there are multiple possible variables
    • Build environment compatibility is now checked before use
    • Decreasing verbosity now has no affect on output that should always be displayed
    • Handle more edge cases in the setuptools migration script
    • Environments now respect user defined environment variables for context formatting
    • Update the scripts in the generated test environment template for new projects to reflect the documentation
    • Allow extra-dependencies in environment overrides
    • Depend on packaging explicitly rather than relying on it being a transitive dependency of Hatchling
    "},{"location":"history/hatch/#hatch-v1.5.0","title":"1.5.0 - 2022-08-28","text":"

    Added:

    • The index publisher now recognizes repository-specific options
    • Add the --ignore-compat flag to the env run command
    • Setting the HATCH_PYTHON environment variable to self will now force the use of the Python executable Hatch is running on for virtual environment creation

    Fixed:

    • Fix the --force-continue flag of the env run command
    • Handle more edge cases in the setuptools migration script
    "},{"location":"history/hatch/#hatch-v1.4.2","title":"1.4.2 - 2022-08-16","text":"

    Fixed:

    • Fix check for updating static versions with the version command when metadata hooks are in use
    "},{"location":"history/hatch/#hatch-v1.4.1","title":"1.4.1 - 2022-08-13","text":"

    Fixed:

    • Fix non-detached inheritance disabling for environments
    "},{"location":"history/hatch/#hatch-v1.4.0","title":"1.4.0 - 2022-08-06","text":"

    Added:

    • The default Python for virtual environments now checks PATH before using the one Hatch is running on
    • Values for environment env-vars now support context formatting
    • Add name override for environments to allow for regular expression matching
    • The index publisher now better supports non-PyPI indices
    • Add certificate options to the index publisher
    • Display waiting text when checking dependencies and removing environments
    • Display help text the first time the shell command is executed
    • Update project templates with Python 3.11 and the latest versions of various GitHub Actions
    • Add support for Almquist (ash) shells
    • Add hyperlink as a dependency for better handling of package index URLs
    • Bump the minimum supported version of virtualenv to 20.16.2
    • Bump the minimum supported version of tomlkit to 0.11.1

    Fixed:

    • Acknowledge extra-dependencies for the env show command
    • Fix locating executables within virtual environments on Debian
    • Fix managing the terminal size inside the shell command
    • Fix default code coverage file omission for the src-layout project template option
    "},{"location":"history/hatch/#hatch-v1.3.1","title":"1.3.1 - 2022-07-11","text":"

    Fixed:

    • Support -h/--help flag for the run command
    "},{"location":"history/hatch/#hatch-v1.3.0","title":"1.3.0 - 2022-07-10","text":"

    Changed:

    • Rename the default publishing plugin from pypi to the more generic index

    Added:

    • Support the absence of pyproject.toml files, as is the case for apps and non-Python projects
    • Hide scripts that start with an underscore for the env show command by default
    • Ignoring the exit codes of commands by prefixing with hyphens now works with entire named scripts
    • Add a way to require confirmation for publishing
    • Add --force-continue flag to the env run command
    • Make tracebacks colorful and less verbose
    • When shell configuration has not been defined, attempt to use the current shell based on parent processes before resorting to the defaults
    • The shell name pwsh is now an alias for powershell
    • Remove atomicwrites dependency
    • Relax constraint on userpath dependency
    • Bump the minimum supported version of Hatchling to 1.4.1

    Fixed:

    • Keep environments in sync with the dependencies of the selected features
    • Use utf-8 for all files generated for new projects
    • Escape special characters Git may return in the user name when writing generated files for new projects
    • Normalize the package name to lowercase in setuptools migration script
    • Fix parsing of source distributions during publishing
    "},{"location":"history/hatch/#hatch-v1.2.1","title":"1.2.1 - 2022-05-30","text":"

    Fixed:

    • Fix handling of top level data_files in setuptools migration script
    "},{"location":"history/hatch/#hatch-v1.2.0","title":"1.2.0 - 2022-05-22","text":"

    Changed:

    • The enter_shell environment plugin method now accepts an additional args parameter

    Added:

    • Allow context string formatting for environment dependencies
    • Add environment context string formatting fields env_name, env_type, matrix, verbosity, and args
    • Support overriding the default arguments used to spawn shells on non-Windows systems
    • Bump the minimum supported version of Hatchling to 1.3.0

    Fixed:

    • Improve setuptools migration script
    "},{"location":"history/hatch/#hatch-v1.1.2","title":"1.1.2 - 2022-05-20","text":"

    Fixed:

    • Bump the minimum supported version of Hatchling to 1.2.0
    • Update project metadata to reflect support for Python 3.11
    "},{"location":"history/hatch/#hatch-v1.1.1","title":"1.1.1 - 2022-05-12","text":"

    Fixed:

    • Fix setuptools migration script for non-Windows systems
    "},{"location":"history/hatch/#hatch-v1.1.0","title":"1.1.0 - 2022-05-12","text":"

    Changed:

    • In order to simplify the implementation of command execution for environment plugins, the run_shell_commands method has been replaced by the singular run_shell_command. A new command_context method has been added to more easily satisfy complex use cases.
    • The finalize_command environment plugin method has been removed in favor of the newly introduced context formatting functionality.

    Added:

    • Add context formatting functionality i.e. the ability to insert values into configuration like environment variables and command line arguments
    • Any verbosity for command execution will now always display headers, even for single environments
    • Every executed command is now displayed when running multiple commands or when verbosity is enabled
    • Similar to make, ignore the exit code of executed commands that start with - (a hyphen)
    • Add ability for the --init flag of the new command to automatically migrate setuptools configuration
    • Update project metadata to reflect the adoption by PyPA and production stability
    "},{"location":"history/hatch/#hatch-v1.0.0","title":"1.0.0 - 2022-04-28","text":"

    This is the first stable release of Hatch v1, a complete rewrite. Enjoy!

    "},{"location":"history/hatchling/","title":"Hatchling history","text":"

    All notable changes to Hatchling will be documented in this file.

    The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

    "},{"location":"history/hatchling/#unreleased","title":"Unreleased","text":""},{"location":"history/hatchling/#hatchling-v1.22.4","title":"1.22.4 - 2024-03-23","text":"

    Fixed:

    • Only read source distribution metadata for fields that are explicitly defined as dynamic
    "},{"location":"history/hatchling/#hatchling-v1.22.3","title":"1.22.3 - 2024-03-19","text":"

    Fixed:

    • Fix the custom build hook when using dynamic dependencies
    "},{"location":"history/hatchling/#hatchling-v1.22.2","title":"1.22.2 - 2024-03-16","text":"

    Fixed:

    • Fix regression when loading metadata from source distributions
    • Fix metadata hooks when building wheels from source distributions
    "},{"location":"history/hatchling/#hatchling-v1.22.1","title":"1.22.1 - 2024-03-16","text":"

    Fixed:

    • Update the default version of core metadata to 2.3
    "},{"location":"history/hatchling/#hatchling-v1.22.0","title":"1.22.0 - 2024-03-16","text":"

    Deprecated:

    • The app build target has been renamed to binary to reduce ambiguity with the name of an upcoming feature. The former name will still be usable for several minor releases.

    Added:

    • Metadata for the wheel target now defaults to the PKG-INFO metadata within source distributions
    • Add dependencies method to the build hook interface so that hooks can themselves dynamically define dependencies
    • Update the default version of core metadata to 2.2
    • Update SPDX license information to version 3.23
    • Improve error message for when the default heuristics for wheel file inclusion fail

    Fixed:

    • Properly support core metadata version 2.2
    • Remove editables as a direct dependency
    • Fix default wheel tag when the supported Python version declaration is strict
    • Load VCS ignore patterns first so that whitelisted patterns can be excluded by project configuration
    • Don't consider VCS ignore files that are outside of the VCS boundary
    • The sdist build target now gracefully ignores UNIX socket files
    • Begin ignoring certain files ubiquitously, like .DS_Store on macOS
    "},{"location":"history/hatchling/#hatchling-v1.21.1","title":"1.21.1 - 2024-01-25","text":"

    Fixed:

    • Fix loading of local plugins to account for newly released versions of a dependency
    "},{"location":"history/hatchling/#hatchling-v1.21.0","title":"1.21.0 - 2023-12-18","text":"

    Added:

    • Add parent context modifier for path fields
    "},{"location":"history/hatchling/#hatchling-v1.20.0","title":"1.20.0 - 2023-12-13","text":"

    Added:

    • Add bypass-selection option to the wheel build target to allow for empty (metadata-only) wheels

    Fixed:

    • Fix regression in 1.19.1 that allowed exclude to count toward inclusion selection, thus bypassing the default inclusion selection heuristics
    • Fix writing optional dependency core metadata in situations where there are multiple environment markers
    "},{"location":"history/hatchling/#hatchling-v1.19.1","title":"1.19.1 - 2023-12-12","text":"

    Fixed:

    • Add better error message when the wheel build target cannot determine what to ship
    • Consider forced inclusion patterns and build-time artifacts as file selection since some build hooks generate the entire wheel contents without user configuration
    "},{"location":"history/hatchling/#hatchling-v1.19.0","title":"1.19.0 - 2023-12-11","text":"

    Changed:

    • An error will now be raised if a force-included path does not exist
    • An error will now be raised for the wheel build target if no file selection options are defined

    Added:

    • Officially support Python 3.12
    • Allow using an empty string for the sources option to add a prefix to distribution paths

    Fixed:

    • Properly handle non-zero version epoch for the standard version scheme
    • Fix the wheel build target for case insensitive file systems when the project metadata name does not match the directory name on disk
    • The app build target no longer has suppressed output
    • Prevent duplicate paths when projects require the sources option while build hooks overwrite included paths
    • Properly escape spaces for URI context formatting
    "},{"location":"history/hatchling/#hatchling-v1.18.0","title":"1.18.0 - 2023-06-12","text":"

    Changed:

    • Drop support for Python 3.7

    Added:

    • Update the list of directories that are always excluded for builds
    "},{"location":"history/hatchling/#hatchling-v1.17.1","title":"1.17.1 - 2023-06-03","text":"

    Fixed:

    • Fix dev mode when the project has symlinks and file inclusion is defined with the packages or only-include options
    • Change the name of generated PTH files for dev mode so they come first lexicographically and therefore load first
    "},{"location":"history/hatchling/#hatchling-v1.17.0","title":"1.17.0 - 2023-05-12","text":"

    Added:

    • The app build target now embeds the project version in the name of binaries
    "},{"location":"history/hatchling/#hatchling-v1.16.1","title":"1.16.1 - 2023-05-11","text":"

    Fixed:

    • Fix determining the built executable path for the app build target option when using a local copy of PyApp when there is an explicit target triple set
    "},{"location":"history/hatchling/#hatchling-v1.16.0","title":"1.16.0 - 2023-05-11","text":"

    Added:

    • Add app build target option to build using a local copy of the PyApp repository
    "},{"location":"history/hatchling/#hatchling-v1.15.0","title":"1.15.0 - 2023-05-09","text":"

    Added:

    • Add app build target
    "},{"location":"history/hatchling/#hatchling-v1.14.1","title":"1.14.1 - 2023-04-23","text":"

    Fixed:

    • Fix internal archive root naming for the sdist target when strict-naming is disabled to match the file name in order to support the expectation of some frontends
    "},{"location":"history/hatchling/#hatchling-v1.14.0","title":"1.14.0 - 2023-04-02","text":"

    Added:

    • Add trove-classifiers as a dependency

    Fixed:

    • Properly normalize metadata descriptions that contain line breaks
    "},{"location":"history/hatchling/#hatchling-v1.13.0","title":"1.13.0 - 2023-02-09","text":"

    Added:

    • Update the set of known trove classifiers to version 2023.2.8
    "},{"location":"history/hatchling/#hatchling-v1.12.2","title":"1.12.2 - 2023-01-05","text":"

    Fixed:

    • Add macos-max-compat option to the wheel target that is enabled by default to support the latest version 22.0 of the packaging library
    "},{"location":"history/hatchling/#hatchling-v1.12.1","title":"1.12.1 - 2022-12-31","text":"

    Fixed:

    • Fix minor regression in the PEP 517/660 function signatures that was discovered by Fedora
    "},{"location":"history/hatchling/#hatchling-v1.12.0","title":"1.12.0 - 2022-12-30","text":"

    Added:

    • Improve readability of exceptions
    • Add extra_metadata build data to the wheel target
    • Retroactively support License-Expression core metadata starting at version 2.1
    • Add more type hints
    • Update the set of known trove classifiers to version 2022.12.22
    • Update SPDX license information to version 3.19
    • Store Hatchling's metadata in pyproject.toml

    Fixed:

    • Acknowledge the ARCHFLAGS environment variable on macOS for the wheel target when build hooks set the infer_tag build data to true
    • Fix dependency checking when encountering broken distributions
    • Fix the support-legacy option for the sdist target when using a src-layout project structure
    • Remove unnecessary encoding declaration in the default template for the version build hook
    "},{"location":"history/hatchling/#hatchling-v1.11.1","title":"1.11.1 - 2022-10-19","text":"

    Fixed:

    • Fix default file selection behavior of the wheel target when there is a single top-level module
    "},{"location":"history/hatchling/#hatchling-v1.11.0","title":"1.11.0 - 2022-10-08","text":"

    Added:

    • Add env version source to retrieve the version from an environment variable
    • Add validate-bump option to the standard version scheme

    Fixed:

    • Use proper CSV formatting for the RECORD metadata file of the wheel target to avoid warnings during installation by pip if, for example, file names contain commas
    • Fix installations with pip for build hooks that modify runtime dependencies
    • Decreasing verbosity now has no affect on output that should always be displayed
    "},{"location":"history/hatchling/#hatchling-v1.10.0","title":"1.10.0 - 2022-09-18","text":"

    Added:

    • Add the following to the list of directories that cannot be traversed: __pypackages__, .hg, .hatch, .tox, .nox
    • Add deprecated option to allow ambiguous features

    Fixed:

    • Improve tracking of dynamic metadata
    • Fix core metadata for entries in project.optional-dependencies that use direct references
    "},{"location":"history/hatchling/#hatchling-v1.9.0","title":"1.9.0 - 2022-09-09","text":"

    Changed:

    • File pattern matching now more closely resembles Git's behavior

    Added:

    • Implement a minimal version of prepare_metadata_for_build_wheel and prepare_metadata_for_build_editable for non-frontend tools that only need to inspect a project's metadata
    • Add metadata command to view PEP 621 project metadata
    • Improve error messages for SPDX license errors
    • Retroactively support License-File for core metadata starting at version 2.1
    • Bump the minimum supported version of pathspec to 0.10.1

    Fixed:

    • Allow the valid non-SPDX license values LicenseRef-Public-Domain and LicenseRef-Proprietary
    • Show the help text of the CLI when no subcommand is selected
    "},{"location":"history/hatchling/#hatchling-v1.8.1","title":"1.8.1 - 2022-08-25","text":"

    Fixed:

    • Fix default file inclusion for wheel build targets when both the project name and package directory name are not normalized
    "},{"location":"history/hatchling/#hatchling-v1.8.0","title":"1.8.0 - 2022-08-16","text":"

    Added:

    • Add get_known_classifiers method to metadata hooks

    Fixed:

    • Fix check for updating static versions with the version command when metadata hooks are in use
    "},{"location":"history/hatchling/#hatchling-v1.7.1","title":"1.7.1 - 2022-08-13","text":"

    Fixed:

    • Fix the value of the relative_path attribute of included files, that some build plugins may use, when selecting explicit paths
    "},{"location":"history/hatchling/#hatchling-v1.7.0","title":"1.7.0 - 2022-08-12","text":"

    Added:

    • Add require-runtime-features option for builders and build hooks
    • Check for unknown trove classifiers
    • Update SPDX license information to version 3.18

    Fixed:

    • Add better error message for wheel target dev mode installations that define path rewrites with the sources option
    • Note the allow-direct-references option in the relevant error messages
    "},{"location":"history/hatchling/#hatchling-v1.6.0","title":"1.6.0 - 2022-07-23","text":"

    Changed:

    • When no build targets are specified on the command line, now default to sdist and wheel targets rather than what happens to be defined in config
    • The code version source now only supports files with known extensions
    • Global build hooks now run before target-specific build hooks to better match expected behavior

    Added:

    • The code version source now supports loading extension modules
    • Add search-paths option for the code version source

    Fixed:

    • Fix removing sources using an empty string value in the mapping
    • The strict-naming option now also applies to the metadata directory of wheel targets
    "},{"location":"history/hatchling/#hatchling-v1.5.0","title":"1.5.0 - 2022-07-11","text":"

    Added:

    • Support the final draft of PEP 639
    • Add strict-naming option for sdist and wheel targets

    Fixed:

    • Project names are now stored in sdist and wheel target core metadata exactly as defined in pyproject.toml without normalization to allow control of how PyPI displays them
    "},{"location":"history/hatchling/#hatchling-v1.4.1","title":"1.4.1 - 2022-07-04","text":"

    Fixed:

    • Fix forced inclusion of important files like licenses for sdist targets when using the explicit selection options
    • Don't sort project URL metadata so that the rendered order on PyPI can be controlled
    "},{"location":"history/hatchling/#hatchling-v1.4.0","title":"1.4.0 - 2022-07-03","text":"

    Changed:

    • The packages option uses the new only-include option to provide targeted inclusion, since that is desired most of the time. You can retain the old behavior by using the include and sources options together.

    Added:

    • Support PEP 561 type hinting
    • Add version build hook
    • Add only-include option
    • The editable version of wheel targets now respects the force-include option by default
    • The force-include option now supports path rewriting with the sources option
    • The wheel target shared-data and extra-metadata options now respect file selection options
    • The wheel target now auto-detects single module layouts
    • Improve performance by never entering directories that are guaranteed to be undesirable like __pycache__ rather than excluding individual files within
    • Update SPDX license information to version 3.17

    Fixed:

    • Don't write empty entry points file for wheel targets if there are no entry points defined
    • Allow metadata hooks to set the version in all cases
    • Prevent duplicate file entries from inclusion when using the force-include option
    "},{"location":"history/hatchling/#hatchling-v1.3.1","title":"1.3.1 - 2022-05-30","text":"

    Fixed:

    • Better populate global variables for the code version source
    "},{"location":"history/hatchling/#hatchling-v1.3.0","title":"1.3.0 - 2022-05-22","text":"

    Removed:

    • Remove unused global args context string formatting field

    Added:

    • Improve error messages for the env context string formatting field

    Fixed:

    • Fix uri context string formatting modifier on Windows
    "},{"location":"history/hatchling/#hatchling-v1.2.0","title":"1.2.0 - 2022-05-20","text":"

    Added:

    • Allow context formatting for project.dependencies and project.optional-dependencies
    "},{"location":"history/hatchling/#hatchling-v1.1.0","title":"1.1.0 - 2022-05-19","text":"

    Added:

    • Add uri and real context string formatting modifiers for file system paths
    "},{"location":"history/hatchling/#hatchling-v1.0.0","title":"1.0.0 - 2022-05-17","text":"

    Changed:

    • Drop support for Python 2

    Added:

    • Improve error messaging for invalid versions
    • Update project metadata to reflect support for Python 3.11
    "},{"location":"history/hatchling/#hatchling-v0.25.1","title":"0.25.1 - 2022-06-14","text":"

    Fixed:

    • Fix support for Windows on Python 2 by removing its support for symlinks
    "},{"location":"history/hatchling/#hatchling-v0.25.0","title":"0.25.0 - 2022-05-15","text":"

    Added:

    • Add skip-excluded-dirs build option
    • Allow build data to add additional project dependencies for wheel and sdist build targets
    • Add force_include_editable build data for the wheel build target
    • Add build_hooks build data
    • Add support for Mercurial's .hgignore files when using glob syntax
    • Update project metadata to reflect the adoption by PyPA

    Fixed:

    • Properly use underscores for the name of force_include build data
    • No longer greedily skip excluded directories by default
    "},{"location":"history/hatchling/#hatchling-v0.24.0","title":"0.24.0 - 2022-04-28","text":"

    This is the initial public release of the Hatchling build system. Support for Python 2 will be dropped in version 1.

    "},{"location":"how-to/config/dynamic-metadata/","title":"How to configure custom dynamic metadata","text":"

    If you have project metadata that is not appropriate for static entry into pyproject.toml you will need to provide a custom metadata hook to apply such data during builds.

    Alternatives

    Dynamic metadata is a way to have a single source of truth that will be available at build time and at run time. Another way to achieve that is to enter the build data statically and then look up the same information dynamically in the program or package, using importlib.metadata.

    If the version field is the only metadata of concern, Hatchling provides a few built-in ways such as the regex version source and also third-party plugins. The approach here will also work, but is more complex.

    "},{"location":"how-to/config/dynamic-metadata/#update-project-metadata","title":"Update project metadata","text":"

    Change the [project] section of pyproject.toml:

    1. Define the dynamic field as an array of all the fields you will set dynamically e.g. dynamic = [\"version\", \"license\", \"authors\", \"maintainers\"]
    2. If any of those fields have static definitions in pyproject.toml, delete those definitions. It is verboten to define a field statically and dynamically.

    Add a section to trigger loading of dynamic metadata plugins: [tool.hatch.metadata.hooks.custom]. Use exactly that name, regardless of the name of the class you will use or its PLUGIN_NAME. There doesn't need to be anything in the section.

    If your plugin requires additional third-party packages to do its work, add them to the requires array in the [build-system] section of pyproject.toml.

    "},{"location":"how-to/config/dynamic-metadata/#implement-hook","title":"Implement hook","text":"

    The dynamic lookup must happen in a custom plugin that you write. The default expectation is that it is in a hatch_build.py file at the root of the project. Subclass MetadataHookInterface and implement update(); for example, here's plugin that reads metadata from a JSON file:

    hatch_build.py
    import json\nimport os\n\nfrom hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass JSONMetaDataHook(MetadataHookInterface):\n    def update(self, metadata):\n        src_file = os.path.join(self.root, \"gnumeric\", \".constants.json\")\n        with open(src_file) as src:\n            constants = json.load(src)\n            metadata[\"version\"] = constants[\"__version__\"]\n            metadata[\"license\"] = constants[\"__license__\"]\n            metadata[\"authors\"] = [\n                {\"name\": constants[\"__author__\"], \"email\": constants[\"__author_email__\"]},\n            ]\n
    1. You must import the MetadataHookInterface to subclass it.
    2. Do your operations inside the update method.
    3. metadata refers to project metadata.
    4. When writing to metadata, use list for TOML arrays. Note that if a list is expected, it is required even if there is a single element.
    5. Use dict for TOML tables e.g. authors.

    If you want to store the hook in a different location, set the path option:

    pyproject.toml hatch.toml
    [tool.hatch.metadata.hooks.custom]\npath = \"some/where.py\"\n
    [metadata.hooks.custom]\npath = \"some/where.py\"\n
    "},{"location":"how-to/environment/package-indices/","title":"How to configure package indices","text":"

    Most Hatch environment types, like the default virtual, simply use pip to install dependencies. Therefore, you can use the standard environment variables that influence pip's behavior to choose where to search for packages.

    Here's an example of setting up the default environment to look at 2 private indices (using context formatting for authentication) before finally falling back to PyPI:

    pyproject.toml hatch.toml
    [tool.hatch.envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
    [envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
    "},{"location":"how-to/meta/report-issues/","title":"How to report issues","text":"

    All reports regarding unexpected behavior should be generated with the self report command:

    $ hatch self report\n

    By default, this will open a new tab in your default browser with pre-populated information about your environment.

    If Hatch is not installed alongside a web browser, you may also pass the --no-open/-n command which will output the URL with correct parameters for copying elsewhere:

    $ hatch self report -n\nhttps://github.com/pypa/hatch/issues/new?body=%23%23+Current+behavior%0A%3C%21--+A+clear+and+concise+description+of+the+behavior.+--%3E%0A%0A%23%23+Expected+behavior%0A%3C%21--+A+clear+and+concise+description+of+what+you+expected+to+happen.+--%3E%0A%0A%23%23+Additional+context%0A%3C%21--+Add+any+other+context+about+the+problem+here.+If+applicable%2C+add+screenshots+to+help+explain.+--%3E%0A%0A%23%23+Debug%0A%0A%23%23%23+Installation%0A%0A-+Source%3A+pip%0A-+Version%3A+1.9.2.dev5%0A-+Platform%3A+Windows%0A-+Python+version%3A%0A++++%60%60%60%0A++++3.11.1+%28tags%2Fv3.11.1%3Aa7a450f%2C+Dec++6+2022%2C+19%3A58%3A39%29+%5BMSC+v.1934+64+bit+%28AMD64%29%5D%0A++++%60%60%60%0A%0A%23%23%23+Configuration%0A%0A%60%60%60toml%0Amode+%3D+%22local%22%0Ashell+%3D+%22nu%22%0A%60%60%60%0A\n
    "},{"location":"how-to/plugins/testing-builds/","title":"Testing build plugins","text":"

    For testing Hatchling plugins, you'll usually want to generate a project to execute builds as a real user would. For example, as a minimal pytest fixture:

    from pathlib import Path\n\nimport pytest\n\n\n@pytest.fixture\ndef new_project(tmp_path):\n    project_dir = tmp_path / 'my-app'\n    project_dir.mkdir()\n\n    project_file = project_dir / 'pyproject.toml'\n    project_file.write_text(\n        f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {Path.cwd().as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n        encoding='utf-8',\n    )\n    ...\n

    The issue with this is that after the first test session, the project will be forever cached by pip based on the file path. Therefore, subsequent tests runs will never use updated code.

    To invalidate the cache, copy your code to a new path for every test session:

    import shutil\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\n\nimport pytest\n\n\n@pytest.fixture(scope='session')\ndef plugin_dir():\n    with TemporaryDirectory() as d:\n        directory = Path(d, 'plugin')\n        shutil.copytree(\n            Path.cwd(), directory, ignore=shutil.ignore_patterns('.git')\n        )\n\n        yield directory.resolve()\n\n\n@pytest.fixture\ndef new_project(tmp_path, plugin_dir):\n    project_dir = tmp_path / 'my-app'\n    project_dir.mkdir()\n\n    project_file = project_dir / 'pyproject.toml'\n    project_file.write_text(\n        f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {plugin_dir.as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n        encoding='utf-8',\n    )\n    ...\n

    Note

    This example chooses to ignore copying .git for performance reasons. You may want to ignore more patterns, or copy only specific paths like this plugin does.

    "},{"location":"how-to/publish/auth/","title":"How to authenticate for index publishing","text":"

    The username is derived from the following sources, in order of precedence:

    1. The --user / -u cli option.
    2. The HATCH_INDEX_USER environment variable.
    3. The repos tables.
    4. The ~/.pypirc file.
    5. The input to an interactive prompt.

    As a fallback the value __token__ is applied.

    The password is looked up in these:

    1. The ~/.pypirc file if the username was provided by it.
    2. The --auth / -a cli option.
    3. The HATCH_INDEX_AUTH environment variable.
    4. The repos tables.
    5. A variety of OS-level credentials services backed by keyring.
    6. The input to an interactive prompt.

    If interactively provided credentials were used, the username will be stored in Hatch's cache and the password stored in the available keyring backed credentials stores.

    For automated releasing to PyPI, it is recommended to use \"Trusted Publishing\" with OIDC (e.g. PyPA's pypi-publish GitHub Action) or per-project API tokens.

    "},{"location":"how-to/publish/repo/","title":"How to configure repositories for index publishing","text":"

    You can select the repository with which to upload using the -r/--repo option or by setting the HATCH_INDEX_REPO environment variable.

    Rather than specifying the full URL of a repository, you can use a named repository from a publish.index.repos table defined in Hatch's config file:

    config.toml
    [publish.index.repos.private]\nurl = \"...\"\n...\n

    The following repository names are reserved by Hatch and cannot be overridden:

    Name Repository main https://upload.pypi.org/legacy/ test https://test.pypi.org/legacy/

    The main repository is used by default.

    "},{"location":"how-to/static-analysis/behavior/","title":"Customize static analysis behavior","text":"

    You can fully alter the static analysis performed by the fmt command by modifing the reserved environment named hatch-static-analysis. For example, you could define the following if you wanted to replace the default behavior with a mix of Black, isort and basic flake8:

    pyproject.toml hatch.toml
    [tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"black\", \"flake8\", \"isort\"]\n\n[tool.hatch.envs.hatch-static-analysis.scripts]\nformat-check = [\n  \"black --check --diff {args:.}\",\n  \"isort --check-only --diff {args:.}\",\n]\nformat-fix = [\n  \"isort {args:.}\",\n  \"black {args:.}\",\n]\nlint-check = \"flake8 {args:.}\"\nlint-fix = \"lint-check\"\n
    [envs.hatch-static-analysis]\ndependencies = [\"black\", \"flake8\", \"isort\"]\n\n[envs.hatch-static-analysis.scripts]\nformat-check = [\n  \"black --check --diff {args:.}\",\n  \"isort --check-only --diff {args:.}\",\n]\nformat-fix = [\n  \"isort {args:.}\",\n  \"black {args:.}\",\n]\nlint-check = \"flake8 {args:.}\"\nlint-fix = \"lint-check\"\n

    The format-* scripts correspond to the --formatter/-f flag while the lint-* scripts correspond to the --linter/-l flag. The *-fix scripts run by default while the *-check scripts correspond to the --check flag. Based on this example, the following shows how the various scripts influence behavior:

    Command Expanded scripts hatch fmt
    • flake8 .
    • isort .
    • black .
    hatch fmt src tests
    • flake8 src tests
    • isort src tests
    • black src tests
    hatch fmt -f
    • isort .
    • black .
    hatch fmt -l
    • flake8 .
    hatch fmt --check
    • flake8 .
    • black --check --diff .
    • isort --check-only --diff .
    hatch fmt --check -f
    • black --check --diff .
    • isort --check-only --diff .
    hatch fmt --check -l
    • flake8 .
    "},{"location":"meta/authors/","title":"Authors","text":""},{"location":"meta/authors/#maintainers","title":"Maintainers","text":"
    • Ofek Lev
    "},{"location":"meta/authors/#contributors","title":"Contributors","text":"
    • Amjith Ramanujam
    • Arnaud Crowther
    • Chaojie
    • Chris Warrick
    • Lum\u00edr 'Frenzy' Balhar
    • Ofek Lev
    • Olga Matoula
    • Philip Blair
    • Robert Rosca
    "},{"location":"meta/faq/","title":"FAQ","text":""},{"location":"meta/faq/#interoperability","title":"Interoperability","text":"

    Q: What is the risk of lock-in?

    A: Not much! Other than the plugin system, everything uses Python's established standards by default. Project metadata is based entirely on the standard, the build system is compatible with PEP 517/PEP 660, versioning uses the scheme specified by PEP 440, dependencies are defined with PEP 508 strings, and environments use virtualenv.

    Q: Must one use all features?

    A: No, all features are optional! You can use just the build system, publish wheels and source distributions that were built by other tools, only use the environment management, etc.

    "},{"location":"meta/faq/#libraries-vs-applications","title":"Libraries vs applications","text":"

    Q: Are workflows for both libraries and applications supported?

    A: Yes, mostly! Applications can utilize environment management just like libraries, and plugins can be used to build projects in arbitrary formats or publish artifacts to arbitrary destinations.

    The only caveat is that currently there is no support for re-creating an environment given a set of dependencies in a reproducible manner. Although a standard lock file format may be far off since PEP 665 was rejected, resolving capabilities are coming to pip. When that is stabilized, Hatch will add locking functionality and dedicated documentation for managing applications.

    "},{"location":"meta/faq/#tool-migration","title":"Tool migration","text":"

    Q: How to migrate to Hatch?

    "},{"location":"meta/faq/#build-system","title":"Build system","text":"SetuptoolsHatch setup.py MANIFEST.in
    import os\nfrom io import open\n\nfrom setuptools import find_packages, setup\n\nabout = {}\nwith open(os.path.join('src', 'foo', '__about__.py'), 'r', 'utf-8') as f:\n    exec(f.read(), about)\n\nwith open('README.md', 'r', 'utf-8') as f:\n    readme = f.read()\n\nsetup(\n    # Metadata\n    name='foo',\n    version=about['__version__'],\n    description='...',\n    long_description=readme,\n    long_description_content_type='text/markdown',\n    author='...',\n    author_email='...',\n    project_urls={\n        'Documentation': '...',\n        'Source': '...',\n    },\n    classifiers=[\n        '...',\n    ],\n    keywords=[\n        '...',\n    ],\n    python_requires='>=3.8',\n    install_requires=[\n        '...',\n    ],\n    extras_require={\n        'feature': ['...'],\n    },\n\n    # Packaging\n    packages=find_packages(where='src'),\n    package_dir={'': 'src'},\n    package_data={\n        'foo': ['py.typed'],\n    },\n    zip_safe=False,\n    entry_points={\n        'console_scripts': [\n            'foo = foo.cli:main',\n        ],\n    },\n)\n
    graft tests\n\nglobal-exclude *.py[cod] __pycache__\n
    pyproject.toml
    [build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"foo\"\ndescription = \"...\"\nreadme = \"README.md\"\nauthors = [\n  { name = \"...\", email = \"...\" },\n]\nclassifiers = [\n  \"...\",\n]\nkeywords = [\n  \"...\",\n]\nrequires-python = \">=3.8\"\ndependencies = [\n  \"...\",\n]\ndynamic = [\"version\"]\n\n[project.urls]\nDocumentation = \"...\"\nSource = \"...\"\n\n[project.optional-dependencies]\nfeature = [\"...\"]\n\n[project.scripts]\nfoo = \"foo.cli:main\"\n\n[tool.hatch.version]\npath = \"src/foo/__about__.py\"\n\n[tool.hatch.build.targets.sdist]\ninclude = [\n  \"/src\",\n  \"/tests\",\n]\n
    "},{"location":"meta/faq/#environments","title":"Environments","text":"ToxHatch

    Invocation:

    tox\n
    tox.ini
    [tox]\nenvlist =\n    py{27,38}-{42,3.14}\n    py{38,39}-{9000}-{foo,bar}\n\n[testenv]\nusedevelop = true\ndeps =\n    coverage[toml]\n    pytest\n    pytest-cov\n    foo: cryptography\ncommands =\n    pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests {posargs}\nsetenv =\n    3.14: PRODUCT_VERSION=3.14\n    42: PRODUCT_VERSION=42\n    9000: PRODUCT_VERSION=9000\n    {foo,bar}: EXPERIMENTAL=true\n

    Invocation:

    hatch run test\n
    pyproject.toml hatch.toml
    [tool.hatch.envs.default]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[tool.hatch.envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[tool.hatch.envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.features.env-vars = \"EXPERIMENTAL=true\"\nmatrix.features.dependencies = [\n  { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
    [envs.default]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.features.env-vars = \"EXPERIMENTAL=true\"\nmatrix.features.dependencies = [\n  { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[envs.default.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
    "},{"location":"meta/faq/#fast-cli","title":"Fast CLI?","text":"

    The claim about being faster than other tools is based on timings that are always checked in CI.

    Hatch achieves this by using lazy imports, lazily performing computation manually and with functools.cached_property, using hacks like not not ... instead of bool(...), etc.

    "},{"location":"plugins/about/","title":"Plugins","text":"

    Hatch utilizes pluggy for its plugin functionality.

    "},{"location":"plugins/about/#overview","title":"Overview","text":"

    All plugins provide registration hooks that return one or more classes that inherit from a particular type interface.

    Each registration hook must be decorated by Hatch's hook marker. For example, if you wanted to create a new kind of environment you could do:

    hooks.py
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialEnvironment\n\n\n@hookimpl\ndef hatch_register_environment():\n    return SpecialEnvironment\n

    The hooks can return a single class or a list of classes.

    Every class must define an attribute called PLUGIN_NAME that users will select when they wish to use the plugin. So in the example above, the class might be defined like:

    plugin.py
    ...\nclass SpecialEnvironment(...):\n    PLUGIN_NAME = 'special'\n    ...\n
    "},{"location":"plugins/about/#project-configuration","title":"Project configuration","text":""},{"location":"plugins/about/#naming","title":"Naming","text":"

    It is recommended that plugin project names are prefixed with hatch-. For example, if you wanted to make a plugin that provides some functionality for a product named foo you might do:

    pyproject.toml
    [project]\nname = \"hatch-foo\"\n
    "},{"location":"plugins/about/#discovery","title":"Discovery","text":"

    You'll need to define your project as a Python plugin for Hatch:

    pyproject.toml
    [project.entry-points.hatch]\nfoo = \"pkg.hooks\"\n

    The name of the plugin should be the project name (excluding any hatch- prefix) and the path should represent the module that contains the registration hooks.

    "},{"location":"plugins/about/#classifier","title":"Classifier","text":"

    Add Framework :: Hatch to your project's classifiers to make it easy to search for Hatch plugins:

    pyproject.toml
    [project]\nclassifiers = [\n  ...\n  \"Framework :: Hatch\",\n  ...\n]\n
    "},{"location":"plugins/about/#types","title":"Types","text":""},{"location":"plugins/about/#hatchling","title":"Hatchling","text":"

    These are all involved in building projects and therefore any defined dependencies are automatically installed in each build environment.

    • Builder
    • Build hook
    • Metadata hook
    • Version source
    • Version scheme
    "},{"location":"plugins/about/#hatch","title":"Hatch","text":"

    These must be installed in the same environment as Hatch itself.

    • Environment
    • Environment collector
    • Publisher
    "},{"location":"plugins/utilities/","title":"Plugin utilities","text":""},{"location":"plugins/utilities/#hatchling.builders.utils.get_reproducible_timestamp","title":"hatchling.builders.utils.get_reproducible_timestamp() -> int","text":"

    Returns an int derived from the SOURCE_DATE_EPOCH environment variable; see https://reproducible-builds.org/specs/source-date-epoch/.

    The default value will always be: 1580601600

    Source code in backend/src/hatchling/builders/utils.py
    def get_reproducible_timestamp() -> int:\n    \"\"\"\n    Returns an `int` derived from the `SOURCE_DATE_EPOCH` environment variable; see\n    https://reproducible-builds.org/specs/source-date-epoch/.\n\n    The default value will always be: `1580601600`\n    \"\"\"\n    return int(os.environ.get('SOURCE_DATE_EPOCH', '1580601600'))\n
    "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig","title":"BuilderConfig","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.directory","title":"directory: str property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.ignore_vcs","title":"ignore_vcs: bool property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.reproducible","title":"reproducible: bool property","text":"

    Whether or not the target should be built in a reproducible manner, defaulting to true.

    "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dev_mode_dirs","title":"dev_mode_dirs: list[str] property","text":"

    Directories which must be added to Python's search path in dev mode.

    "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.versions","title":"versions: list[str] property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dependencies","title":"dependencies: list[str] property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_include","title":"default_include() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_exclude","title":"default_exclude() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_packages","title":"default_packages() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_only_include","title":"default_only_include() -> list","text":""},{"location":"plugins/utilities/#hatchling.bridge.app.Application","title":"Application","text":"

    The way output is displayed can be configured by users.

    Important

    Never import this directly; Hatch judiciously decides if a type of plugin requires the capabilities herein and will grant access via an attribute.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.verbosity","title":"verbosity: int property","text":"

    The verbosity level of the application, with 0 as the default.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.abort","title":"abort(message: str = '', code: int = 1, **kwargs: Any) -> None","text":"

    Terminate the program with the given return code.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_debug","title":"display_debug(message: str = '', level: int = 1, **kwargs: Any) -> None","text":"

    Meant to be used for messages that are not useful for most user experiences. The level option must be between 1 and 3 (inclusive).

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_error","title":"display_error(message: str = '', **kwargs: Any) -> None","text":"

    Meant to be used for messages indicating some unrecoverable error.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_info","title":"display_info(message: str = '', **kwargs: Any) -> None","text":"

    Meant to be used for messages conveying basic information.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_success","title":"display_success(message: str = '', **kwargs: Any) -> None","text":"

    Meant to be used for messages indicating some positive outcome.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_waiting","title":"display_waiting(message: str = '', **kwargs: Any) -> None","text":"

    Meant to be used for messages shown before potentially time consuming operations.

    "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_warning","title":"display_warning(message: str = '', **kwargs: Any) -> None","text":"

    Meant to be used for messages conveying important information.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform","title":"Platform","text":""},{"location":"plugins/utilities/#hatch.utils.platform.Platform.default_shell","title":"default_shell: str property","text":"

    Returns the default shell of the system.

    On Windows systems first try the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.modules","title":"modules: LazilyLoadedModules property","text":"

    Accessor for lazily loading modules that either take multiple milliseconds to import (like shutil and subprocess) or are not used on all platforms (like shlex).

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.home","title":"home: Path property","text":"

    The user's home directory as a path-like object.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.name","title":"name: str property","text":"

    One of the following:

    • linux
    • windows
    • macos
    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.display_name","title":"display_name: str property","text":"

    One of the following:

    • Linux
    • Windows
    • macOS
    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.windows","title":"windows: bool property","text":"

    Indicates whether Hatch is running on Windows.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.macos","title":"macos: bool property","text":"

    Indicates whether Hatch is running on macOS.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.linux","title":"linux: bool property","text":"

    Indicates whether Hatch is running on neither Windows nor macOS.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.format_for_subprocess","title":"format_for_subprocess(command: str | list[str], *, shell: bool) -> str | list[str]","text":"

    Format the given command in a cross-platform manner for immediate consumption by subprocess utilities.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.run_command","title":"run_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess","text":"

    Equivalent to the standard library's subprocess.run, with the command first being properly formatted.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command","title":"check_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess","text":"

    Equivalent to run_command, but non-zero exit codes will gracefully end program execution.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command_output","title":"check_command_output(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> str","text":"

    Equivalent to the output from the process returned by capture_process, but non-zero exit codes will gracefully end program execution.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.capture_process","title":"capture_process(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> Popen","text":"

    Equivalent to the standard library's subprocess.Popen, with all output captured by stdout and the command first being properly formatted.

    "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.exit_with_command","title":"exit_with_command(command: list[str]) -> None","text":"

    Run the given command and exit with its exit code. On non-Windows systems, this uses the standard library's os.execvp.

    "},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter","title":"EnvironmentContextFormatter","text":""},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter.formatters","title":"formatters()","text":"

    This returns a mapping of supported field names to their respective formatting functions. Each function accepts 2 arguments:

    • the value that was passed to the format call, defaulting to None
    • the modifier data, defaulting to an empty string
    "},{"location":"plugins/build-hook/custom/","title":"Custom build hook","text":"

    This is a custom class in a given Python file that inherits from the BuildHookInterface.

    "},{"location":"plugins/build-hook/custom/#configuration","title":"Configuration","text":"

    The build hook plugin name is custom.

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.custom]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.custom]\n
    [build.hooks.custom]\n[build.targets.<TARGET_NAME>.hooks.custom]\n
    "},{"location":"plugins/build-hook/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/build-hook/custom/#example","title":"Example","text":"hatch_build.py
    from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass CustomBuildHook(BuildHookInterface):\n    ...\n

    If multiple subclasses are found, you must define a function named get_build_hook that returns the desired build hook.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    "},{"location":"plugins/build-hook/reference/","title":"Build hook plugins","text":"

    A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.

    "},{"location":"plugins/build-hook/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-autorun - used to inject code into an installation that will automatically run before the first import
    • hatch-build-scripts - run arbitrary shell commands that create artifacts
    • hatch-jupyter-builder - used for packages in the Project Jupyter ecosystem
    • hatch-mypyc - compiles code with Mypyc
    • hatch-odoo - package Odoo add-ons into the appropriate namespace
    "},{"location":"plugins/build-hook/reference/#overview","title":"Overview","text":"

    Build hooks run for every selected version of build targets.

    The initialization stage occurs immediately before each build and the finalization stage occurs immediately after. Each stage has the opportunity to view or modify build data.

    "},{"location":"plugins/build-hook/reference/#build-data","title":"Build data","text":"

    Build data is a simple mapping whose contents can influence the behavior of builds. Which fields exist and are recognized depends on each build target.

    The following fields are always present and recognized by the build system itself:

    Field Type Description artifacts list[str] This is a list of extra artifact patterns and should generally only be appended to force_include dict[str, str] This is a mapping of extra forced inclusion paths, with this mapping taking precedence in case of conflicts build_hooks tuple[str, ...] This is an immutable sequence of the names of the configured build hooks and matches the order in which they run

    Attention

    While user-facing TOML options are hyphenated, build data fields should be named with underscores to allow plugins to use them as valid Python identifiers.

    "},{"location":"plugins/build-hook/reference/#notes","title":"Notes","text":"

    In some cases it may be necessary to use force_include rather than artifacts. For example, say that you want to install a lib.so directly at the root of site-packages and a project defines a package src/foo. If you create src/lib.so, there will never be a match because the directory traversal starts at src/foo rather than src. In that case you must do either:

    build_data['force_include']['src/lib.so'] = 'src/lib.so'\n

    or

    build_data['force_include']['/absolute/path/to/src/lib.so'] = 'src/lib.so'\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface","title":"BuildHookInterface","text":"

    Example usage:

    plugin.py hooks.py
    from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass SpecialBuildHook(BuildHookInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuildHook\n\n\n@hookimpl\ndef hatch_register_build_hook():\n    return SpecialBuildHook\n
    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    class BuildHookInterface(Generic[BuilderConfigBound]):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\n    class SpecialBuildHook(BuildHookInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialBuildHook\n\n\n    @hookimpl\n    def hatch_register_build_hook():\n        return SpecialBuildHook\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root: str,\n        config: dict[str, Any],\n        build_config: BuilderConfigBound,\n        metadata: ProjectMetadata,\n        directory: str,\n        target_name: str,\n        app: Application | None = None,\n    ) -> None:\n        self.__root = root\n        self.__config = config\n        self.__build_config = build_config\n        self.__metadata = metadata\n        self.__directory = directory\n        self.__target_name = target_name\n        self.__app = app\n\n    @property\n    def app(self) -> Application:\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = cast(Application, Application().get_safe_application())\n\n        return self.__app\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict[str, Any]:\n        \"\"\"\n        The cumulative hook configuration.\n\n        ```toml config-example\n        [tool.hatch.build.hooks.<PLUGIN_NAME>]\n        [tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @property\n    def metadata(self) -> ProjectMetadata:\n        # Undocumented for now\n        return self.__metadata\n\n    @property\n    def build_config(self) -> BuilderConfigBound:\n        \"\"\"\n        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        return self.__build_config\n\n    @property\n    def directory(self) -> str:\n        \"\"\"\n        The build directory.\n        \"\"\"\n        return self.__directory\n\n    @property\n    def target_name(self) -> str:\n        \"\"\"\n        The plugin name of the build target.\n        \"\"\"\n        return self.__target_name\n\n    def dependencies(self) -> list[str]:  # noqa: PLR6301\n        \"\"\"\n        A list of extra [dependencies](../../config/dependency.md) that must be installed\n        prior to builds.\n\n        !!! warning\n            - For this to have any effect the hook dependency itself cannot be dynamic and\n                must always be defined in `build-system.requires`.\n            - As the hook must be imported to call this method, imports that require these\n                dependencies must be evaluated lazily.\n        \"\"\"\n        return []\n\n    def clean(self, versions: list[str]) -> None:\n        \"\"\"\n        This occurs before the build process if the `-c`/`--clean` flag was passed to\n        the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n        the [`clean`](../../cli/reference.md#hatch-clean) command.\n        \"\"\"\n\n    def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n        \"\"\"\n        This occurs immediately before each build.\n\n        Any modifications to the build data will be seen by the build target.\n        \"\"\"\n\n    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n        \"\"\"\n        This occurs immediately after each build and will not run if the `--hooks-only` flag\n        was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n        The build data will reflect any modifications done by the target during the build.\n        \"\"\"\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.app","title":"app: Application property","text":"

    An instance of Application.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.root","title":"root: str property","text":"

    The root of the project tree.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.config","title":"config: dict[str, Any] property","text":"

    The cumulative hook configuration.

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.<PLUGIN_NAME>]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
    [build.hooks.<PLUGIN_NAME>]\n[build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.build_config","title":"build_config: BuilderConfigBound property","text":"

    An instance of BuilderConfig.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.target_name","title":"target_name: str property","text":"

    The plugin name of the build target.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.directory","title":"directory: str property","text":"

    The build directory.

    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.dependencies","title":"dependencies() -> list[str]","text":"

    A list of extra dependencies that must be installed prior to builds.

    Warning

    • For this to have any effect the hook dependency itself cannot be dynamic and must always be defined in build-system.requires.
    • As the hook must be imported to call this method, imports that require these dependencies must be evaluated lazily.
    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def dependencies(self) -> list[str]:  # noqa: PLR6301\n    \"\"\"\n    A list of extra [dependencies](../../config/dependency.md) that must be installed\n    prior to builds.\n\n    !!! warning\n        - For this to have any effect the hook dependency itself cannot be dynamic and\n            must always be defined in `build-system.requires`.\n        - As the hook must be imported to call this method, imports that require these\n            dependencies must be evaluated lazily.\n    \"\"\"\n    return []\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.clean","title":"clean(versions: list[str]) -> None","text":"

    This occurs before the build process if the -c/--clean flag was passed to the build command, or when invoking the clean command.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def clean(self, versions: list[str]) -> None:\n    \"\"\"\n    This occurs before the build process if the `-c`/`--clean` flag was passed to\n    the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n    the [`clean`](../../cli/reference.md#hatch-clean) command.\n    \"\"\"\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.initialize","title":"initialize(version: str, build_data: dict[str, Any]) -> None","text":"

    This occurs immediately before each build.

    Any modifications to the build data will be seen by the build target.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n    \"\"\"\n    This occurs immediately before each build.\n\n    Any modifications to the build data will be seen by the build target.\n    \"\"\"\n
    "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.finalize","title":"finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None","text":"

    This occurs immediately after each build and will not run if the --hooks-only flag was passed to the build command.

    The build data will reflect any modifications done by the target during the build.

    Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n    \"\"\"\n    This occurs immediately after each build and will not run if the `--hooks-only` flag\n    was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n    The build data will reflect any modifications done by the target during the build.\n    \"\"\"\n
    "},{"location":"plugins/build-hook/version/","title":"Version build hook","text":"

    This writes the project's version to a file.

    "},{"location":"plugins/build-hook/version/#configuration","title":"Configuration","text":"

    The build hook plugin name is version.

    pyproject.toml hatch.toml
    [tool.hatch.build.hooks.version]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.version]\n
    [build.hooks.version]\n[build.targets.<TARGET_NAME>.hooks.version]\n
    "},{"location":"plugins/build-hook/version/#options","title":"Options","text":"Option Description path (required) A relative path to the desired file template A string representing the entire contents of path that will be formatted with a version variable pattern Rather than updating the entire file, a regular expression may be used that has a named group called version that represents the version. If set to true, a pattern will be used that looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v."},{"location":"plugins/builder/binary/","title":"Binary builder","text":"

    This uses PyApp to build an application that is able to bootstrap itself at runtime.

    Note

    This requires an installation of Rust.

    "},{"location":"plugins/builder/binary/#configuration","title":"Configuration","text":"

    The builder plugin name is binary.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.binary]\n
    [build.targets.binary]\n
    "},{"location":"plugins/builder/binary/#options","title":"Options","text":"Option Default Description scripts all defined An array of defined script names to limit what gets built python-version latest compatible Python minor version The Python version ID to use pyapp-version The version of PyApp to use"},{"location":"plugins/builder/binary/#build-behavior","title":"Build behavior","text":"

    If any scripts are defined then each one will be built (limited by the scripts option). Otherwise, a single executable will be built based on the project name assuming there is an equivalently named module with a __main__.py file.

    Every executable will be built inside an app directory in the output directory.

    If the CARGO environment variable is set then that path will be used as the executable for performing builds.

    If the CARGO_BUILD_TARGET environment variable is set then its value will be appended to the file name stems.

    If the PYAPP_REPO environment variable is set then a local build will be performed inside that directory rather than installing from crates.io. Note that this is required if the CARGO environment variable refers to cross.

    "},{"location":"plugins/builder/custom/","title":"Custom builder","text":"

    This is a custom class in a given Python file that inherits from the BuilderInterface.

    "},{"location":"plugins/builder/custom/#configuration","title":"Configuration","text":"

    The builder plugin name is custom.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.custom]\n
    [build.targets.custom]\n
    "},{"location":"plugins/builder/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/builder/custom/#example","title":"Example","text":"hatch_build.py
    from hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass CustomBuilder(BuilderInterface):\n    ...\n

    If multiple subclasses are found, you must define a function named get_builder that returns the desired builder.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    "},{"location":"plugins/builder/reference/","title":"Builder plugins","text":"

    See the documentation for build configuration.

    "},{"location":"plugins/builder/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-aws - used for building AWS Lambda functions with SAM
    • hatch-zipped-directory - used for building ZIP archives for installation into various foreign package installation systems
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface","title":"BuilderInterface","text":"

    Example usage:

    plugin.py hooks.py
    from hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass SpecialBuilder(BuilderInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuilder\n\n\n@hookimpl\ndef hatch_register_builder():\n    return SpecialBuilder\n
    Source code in backend/src/hatchling/builders/plugin/interface.py
    class BuilderInterface(ABC, Generic[BuilderConfigBound, PluginManagerBound]):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.builders.plugin.interface import BuilderInterface\n\n\n    class SpecialBuilder(BuilderInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialBuilder\n\n\n    @hookimpl\n    def hatch_register_builder():\n        return SpecialBuilder\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root: str,\n        plugin_manager: PluginManagerBound | None = None,\n        config: dict[str, Any] | None = None,\n        metadata: ProjectMetadata | None = None,\n        app: Application | None = None,\n    ) -> None:\n        self.__root = root\n        self.__plugin_manager = cast(PluginManagerBound, plugin_manager)\n        self.__raw_config = config\n        self.__metadata = metadata\n        self.__app = app\n        self.__config = cast(BuilderConfigBound, None)\n        self.__project_config: dict[str, Any] | None = None\n        self.__hatch_config: dict[str, Any] | None = None\n        self.__build_config: dict[str, Any] | None = None\n        self.__build_targets: list[str] | None = None\n        self.__target_config: dict[str, Any] | None = None\n\n        # Metadata\n        self.__project_id: str | None = None\n\n    def build(\n        self,\n        *,\n        directory: str | None = None,\n        versions: list[str] | None = None,\n        hooks_only: bool | None = None,\n        clean: bool | None = None,\n        clean_hooks_after: bool | None = None,\n        clean_only: bool | None = False,\n    ) -> Generator[str, None, None]:\n        # Fail early for invalid project metadata\n        self.metadata.validate_fields()\n\n        if directory is None:\n            directory = (\n                self.config.normalize_build_directory(os.environ[BuildEnvVars.LOCATION])\n                if BuildEnvVars.LOCATION in os.environ\n                else self.config.directory\n            )\n\n        if not os.path.isdir(directory):\n            os.makedirs(directory)\n\n        version_api = self.get_version_api()\n\n        versions = versions or self.config.versions\n        if versions:\n            unknown_versions = set(versions) - set(version_api)\n            if unknown_versions:\n                message = (\n                    f'Unknown versions for target `{self.PLUGIN_NAME}`: {\", \".join(map(str, sorted(unknown_versions)))}'\n                )\n                raise ValueError(message)\n\n        if hooks_only is None:\n            hooks_only = env_var_enabled(BuildEnvVars.HOOKS_ONLY)\n\n        configured_build_hooks = self.get_build_hooks(directory)\n        build_hooks = list(configured_build_hooks.values())\n\n        if clean_only:\n            clean = True\n        elif clean is None:\n            clean = env_var_enabled(BuildEnvVars.CLEAN)\n        if clean:\n            if not hooks_only:\n                self.clean(directory, versions)\n\n            for build_hook in build_hooks:\n                build_hook.clean(versions)\n\n            if clean_only:\n                return\n\n        if clean_hooks_after is None:\n            clean_hooks_after = env_var_enabled(BuildEnvVars.CLEAN_HOOKS_AFTER)\n\n        for version in versions:\n            self.app.display_debug(f'Building `{self.PLUGIN_NAME}` version `{version}`')\n\n            build_data = self.get_default_build_data()\n            self.set_build_data_defaults(build_data)\n\n            # Allow inspection of configured build hooks and the order in which they run\n            build_data['build_hooks'] = tuple(configured_build_hooks)\n\n            # Execute all `initialize` build hooks\n            for build_hook in build_hooks:\n                build_hook.initialize(version, build_data)\n\n            if hooks_only:\n                self.app.display_debug(f'Only ran build hooks for `{self.PLUGIN_NAME}` version `{version}`')\n                continue\n\n            # Build the artifact\n            with self.config.set_build_data(build_data):\n                artifact = version_api[version](directory, **build_data)\n\n            # Execute all `finalize` build hooks\n            for build_hook in build_hooks:\n                build_hook.finalize(version, build_data, artifact)\n\n            if clean_hooks_after:\n                for build_hook in build_hooks:\n                    build_hook.clean([version])\n\n            yield artifact\n\n    def recurse_included_files(self) -> Iterable[IncludedFile]:\n        \"\"\"\n        Returns a consistently generated series of file objects for every file that should be distributed. Each file\n        object has three `str` attributes:\n\n        - `path` - the absolute path\n        - `relative_path` - the path relative to the project root; will be an empty string for external files\n        - `distribution_path` - the path to be distributed as\n        \"\"\"\n        yield from self.recurse_selected_project_files()\n        yield from self.recurse_forced_files(self.config.get_force_include())\n\n    def recurse_selected_project_files(self) -> Iterable[IncludedFile]:\n        if self.config.only_include:\n            yield from self.recurse_explicit_files(self.config.only_include)\n        else:\n            yield from self.recurse_project_files()\n\n    def recurse_project_files(self) -> Iterable[IncludedFile]:\n        for root, dirs, files in safe_walk(self.root):\n            relative_path = get_relative_path(root, self.root)\n\n            dirs[:] = sorted(d for d in dirs if not self.config.directory_is_excluded(d, relative_path))\n\n            files.sort()\n            is_package = '__init__.py' in files\n            for f in files:\n                if f in EXCLUDED_FILES:\n                    continue\n\n                relative_file_path = os.path.join(relative_path, f)\n                distribution_path = self.config.get_distribution_path(relative_file_path)\n                if self.config.path_is_reserved(distribution_path):\n                    continue\n\n                if self.config.include_path(relative_file_path, is_package=is_package):\n                    yield IncludedFile(\n                        os.path.join(root, f), relative_file_path, self.config.get_distribution_path(relative_file_path)\n                    )\n\n    def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n        for source, target_path in inclusion_map.items():\n            external = not source.startswith(self.root)\n            if os.path.isfile(source):\n                yield IncludedFile(\n                    source,\n                    '' if external else os.path.relpath(source, self.root),\n                    self.config.get_distribution_path(target_path),\n                )\n            elif os.path.isdir(source):\n                for root, dirs, files in safe_walk(source):\n                    relative_directory = get_relative_path(root, source)\n\n                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n                    files.sort()\n                    for f in files:\n                        if f in EXCLUDED_FILES:\n                            continue\n\n                        relative_file_path = os.path.join(target_path, relative_directory, f)\n                        distribution_path = self.config.get_distribution_path(relative_file_path)\n                        if not self.config.path_is_reserved(distribution_path):\n                            yield IncludedFile(\n                                os.path.join(root, f),\n                                '' if external else relative_file_path,\n                                distribution_path,\n                            )\n            else:\n                msg = f'Forced include not found: {source}'\n                raise FileNotFoundError(msg)\n\n    def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n        for source, target_path in inclusion_map.items():\n            external = not source.startswith(self.root)\n            if os.path.isfile(source):\n                distribution_path = self.config.get_distribution_path(target_path)\n                if not self.config.path_is_reserved(distribution_path):\n                    yield IncludedFile(\n                        source,\n                        '' if external else os.path.relpath(source, self.root),\n                        self.config.get_distribution_path(target_path),\n                    )\n            elif os.path.isdir(source):\n                for root, dirs, files in safe_walk(source):\n                    relative_directory = get_relative_path(root, source)\n\n                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n                    files.sort()\n                    is_package = '__init__.py' in files\n                    for f in files:\n                        if f in EXCLUDED_FILES:\n                            continue\n\n                        relative_file_path = os.path.join(target_path, relative_directory, f)\n                        distribution_path = self.config.get_distribution_path(relative_file_path)\n                        if self.config.path_is_reserved(distribution_path):\n                            continue\n\n                        if self.config.include_path(relative_file_path, explicit=True, is_package=is_package):\n                            yield IncludedFile(\n                                os.path.join(root, f), '' if external else relative_file_path, distribution_path\n                            )\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def plugin_manager(self) -> PluginManagerBound:\n        if self.__plugin_manager is None:\n            from hatchling.plugin.manager import PluginManager\n\n            self.__plugin_manager = PluginManager()\n\n        return self.__plugin_manager\n\n    @property\n    def metadata(self) -> ProjectMetadata:\n        if self.__metadata is None:\n            from hatchling.metadata.core import ProjectMetadata\n\n            self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)\n\n        return self.__metadata\n\n    @property\n    def app(self) -> Application:\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = cast(Application, Application().get_safe_application())\n\n        return self.__app\n\n    @property\n    def raw_config(self) -> dict[str, Any]:\n        if self.__raw_config is None:\n            self.__raw_config = self.metadata.config\n\n        return self.__raw_config\n\n    @property\n    def project_config(self) -> dict[str, Any]:\n        if self.__project_config is None:\n            self.__project_config = self.metadata.core.config\n\n        return self.__project_config\n\n    @property\n    def hatch_config(self) -> dict[str, Any]:\n        if self.__hatch_config is None:\n            self.__hatch_config = self.metadata.hatch.config\n\n        return self.__hatch_config\n\n    @property\n    def config(self) -> BuilderConfigBound:\n        \"\"\"\n        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        if self.__config is None:\n            self.__config = self.get_config_class()(\n                self, self.root, self.PLUGIN_NAME, self.build_config, self.target_config\n            )\n\n        return self.__config\n\n    @property\n    def build_config(self) -> dict[str, Any]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.build]\n        ```\n        \"\"\"\n        if self.__build_config is None:\n            self.__build_config = self.metadata.hatch.build_config\n\n        return self.__build_config\n\n    @property\n    def target_config(self) -> dict[str, Any]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.build.targets.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        if self.__target_config is None:\n            target_config: dict[str, Any] = self.metadata.hatch.build_targets.get(self.PLUGIN_NAME, {})\n            if not isinstance(target_config, dict):\n                message = f'Field `tool.hatch.build.targets.{self.PLUGIN_NAME}` must be a table'\n                raise TypeError(message)\n\n            self.__target_config = target_config\n\n        return self.__target_config\n\n    @property\n    def project_id(self) -> str:\n        if self.__project_id is None:\n            self.__project_id = f'{self.normalize_file_name_component(self.metadata.core.name)}-{self.metadata.version}'\n\n        return self.__project_id\n\n    def get_build_hooks(self, directory: str) -> dict[str, BuildHookInterface]:\n        configured_build_hooks = {}\n        for hook_name, config in self.config.hook_config.items():\n            build_hook = self.plugin_manager.build_hook.get(hook_name)\n            if build_hook is None:\n                from hatchling.plugin.exceptions import UnknownPluginError\n\n                message = f'Unknown build hook: {hook_name}'\n                raise UnknownPluginError(message)\n\n            configured_build_hooks[hook_name] = build_hook(\n                self.root, config, self.config, self.metadata, directory, self.PLUGIN_NAME, self.app\n            )\n\n        return configured_build_hooks\n\n    @abstractmethod\n    def get_version_api(self) -> dict[str, Callable]:\n        \"\"\"\n        A mapping of `str` versions to a callable that is used for building.\n        Each callable must have the following signature:\n\n        ```python\n        def ...(build_dir: str, build_data: dict) -> str:\n        ```\n\n        The return value must be the absolute path to the built artifact.\n        \"\"\"\n\n    def get_default_versions(self) -> list[str]:\n        \"\"\"\n        A list of versions to build when users do not specify any, defaulting to all versions.\n        \"\"\"\n        return list(self.get_version_api())\n\n    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301\n        \"\"\"\n        A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n        \"\"\"\n        return {}\n\n    def set_build_data_defaults(self, build_data: dict[str, Any]) -> None:  # noqa: PLR6301\n        build_data.setdefault('artifacts', [])\n        build_data.setdefault('force_include', {})\n\n    def clean(self, directory: str, versions: list[str]) -> None:\n        \"\"\"\n        Called before builds if the `-c`/`--clean` flag was passed to the\n        [`build`](../../cli/reference.md#hatch-build) command.\n        \"\"\"\n\n    @classmethod\n    def get_config_class(cls) -> type[BuilderConfig]:\n        \"\"\"\n        Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        return BuilderConfig\n\n    @staticmethod\n    def normalize_file_name_component(file_name: str) -> str:\n        \"\"\"\n        https://peps.python.org/pep-0427/#escaping-and-unicode\n        \"\"\"\n        return re.sub(r'[^\\w\\d.]+', '_', file_name, flags=re.UNICODE)\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.app","title":"app: Application property","text":"

    An instance of Application.

    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.root","title":"root: str property","text":"

    The root of the project tree.

    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.build_config","title":"build_config: dict[str, Any] property","text":"pyproject.toml hatch.toml
    [tool.hatch.build]\n
    [build]\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.target_config","title":"target_config: dict[str, Any] property","text":"pyproject.toml hatch.toml
    [tool.hatch.build.targets.<PLUGIN_NAME>]\n
    [build.targets.<PLUGIN_NAME>]\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.config","title":"config: BuilderConfigBound property","text":"

    An instance of BuilderConfig.

    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_config_class","title":"get_config_class() -> type[BuilderConfig] classmethod","text":"

    Must return a subclass of BuilderConfig.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    @classmethod\ndef get_config_class(cls) -> type[BuilderConfig]:\n    \"\"\"\n    Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n    \"\"\"\n    return BuilderConfig\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_version_api","title":"get_version_api() -> dict[str, Callable] abstractmethod","text":"

    A mapping of str versions to a callable that is used for building. Each callable must have the following signature:

    def ...(build_dir: str, build_data: dict) -> str:\n

    The return value must be the absolute path to the built artifact.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    @abstractmethod\ndef get_version_api(self) -> dict[str, Callable]:\n    \"\"\"\n    A mapping of `str` versions to a callable that is used for building.\n    Each callable must have the following signature:\n\n    ```python\n    def ...(build_dir: str, build_data: dict) -> str:\n    ```\n\n    The return value must be the absolute path to the built artifact.\n    \"\"\"\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_versions","title":"get_default_versions() -> list[str]","text":"

    A list of versions to build when users do not specify any, defaulting to all versions.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def get_default_versions(self) -> list[str]:\n    \"\"\"\n    A list of versions to build when users do not specify any, defaulting to all versions.\n    \"\"\"\n    return list(self.get_version_api())\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.clean","title":"clean(directory: str, versions: list[str]) -> None","text":"

    Called before builds if the -c/--clean flag was passed to the build command.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def clean(self, directory: str, versions: list[str]) -> None:\n    \"\"\"\n    Called before builds if the `-c`/`--clean` flag was passed to the\n    [`build`](../../cli/reference.md#hatch-build) command.\n    \"\"\"\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.recurse_included_files","title":"recurse_included_files() -> Iterable[IncludedFile]","text":"

    Returns a consistently generated series of file objects for every file that should be distributed. Each file object has three str attributes:

    • path - the absolute path
    • relative_path - the path relative to the project root; will be an empty string for external files
    • distribution_path - the path to be distributed as
    Source code in backend/src/hatchling/builders/plugin/interface.py
    def recurse_included_files(self) -> Iterable[IncludedFile]:\n    \"\"\"\n    Returns a consistently generated series of file objects for every file that should be distributed. Each file\n    object has three `str` attributes:\n\n    - `path` - the absolute path\n    - `relative_path` - the path relative to the project root; will be an empty string for external files\n    - `distribution_path` - the path to be distributed as\n    \"\"\"\n    yield from self.recurse_selected_project_files()\n    yield from self.recurse_forced_files(self.config.get_force_include())\n
    "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_build_data","title":"get_default_build_data() -> dict[str, Any]","text":"

    A mapping that can be modified by build hooks to influence the behavior of builds.

    Source code in backend/src/hatchling/builders/plugin/interface.py
    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301\n    \"\"\"\n    A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n    \"\"\"\n    return {}\n
    "},{"location":"plugins/builder/sdist/","title":"Source distribution builder","text":"

    A source distribution, or sdist, is an archive of Python \"source code\". Although largely unspecified, by convention it should include everything that is required to build a wheel without making network requests.

    "},{"location":"plugins/builder/sdist/#configuration","title":"Configuration","text":"

    The builder plugin name is sdist.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.sdist]\n
    [build.targets.sdist]\n
    "},{"location":"plugins/builder/sdist/#options","title":"Options","text":"Option Default Description core-metadata-version \"2.3\" The version of core metadata to use strict-naming true Whether or not file names should contain the normalized version of the project name support-legacy false Whether or not to include a setup.py file to support legacy installation mechanisms"},{"location":"plugins/builder/sdist/#versions","title":"Versions","text":"Version Description standard (default) The latest conventional format"},{"location":"plugins/builder/sdist/#default-file-selection","title":"Default file selection","text":"

    When the user has not set any file selection options, all files that are not ignored by your VCS will be included.

    Note

    The following files are always included and cannot be excluded:

    • /pyproject.toml
    • /hatch.toml
    • /hatch_build.py
    • /.gitignore or /.hgignore
    • Any defined readme file
    • All defined license-files
    "},{"location":"plugins/builder/sdist/#reproducibility","title":"Reproducibility","text":"

    Reproducible builds are supported.

    "},{"location":"plugins/builder/sdist/#build-data","title":"Build data","text":"

    This is data that can be modified by build hooks.

    Data Default Description dependencies Extra project dependencies"},{"location":"plugins/builder/wheel/","title":"Wheel builder","text":"

    A wheel is a binary distribution of a Python package that can be installed directly into an environment.

    "},{"location":"plugins/builder/wheel/#configuration","title":"Configuration","text":"

    The builder plugin name is wheel.

    pyproject.toml hatch.toml
    [tool.hatch.build.targets.wheel]\n
    [build.targets.wheel]\n
    "},{"location":"plugins/builder/wheel/#options","title":"Options","text":"Option Default Description core-metadata-version \"2.3\" The version of core metadata to use shared-data A mapping similar to the forced inclusion option corresponding to data that will be installed globally in a given Python environment, usually under sys.prefix extra-metadata A mapping similar to the forced inclusion option corresponding to extra metadata that will be shipped in a directory named extra_metadata strict-naming true Whether or not file names should contain the normalized version of the project name macos-max-compat true Whether or not on macOS, when build hooks have set the infer_tag build data, the wheel name should signal broad support rather than specific versions for newer SDK versions.Note: The default will become false, and this option eventually removed, sometime after consumers like pip start supporting these newer SDK versions. bypass-selection false Whether or not to suppress the error when one has not defined any file selection options and all heuristics have failed to determine what to ship"},{"location":"plugins/builder/wheel/#versions","title":"Versions","text":"Version Description standard (default) The latest standardized format editable A wheel that only ships .pth files or import hooks for real-time development"},{"location":"plugins/builder/wheel/#default-file-selection","title":"Default file selection","text":"

    When the user has not set any file selection options, the project name will be used to determine the package to ship in the following heuristic order:

    1. <NAME>/__init__.py
    2. src/<NAME>/__init__.py
    3. <NAME>.py
    4. <NAMESPACE>/<NAME>/__init__.py

    If none of these heuristics are satisfied, an error will be raised.

    "},{"location":"plugins/builder/wheel/#reproducibility","title":"Reproducibility","text":"

    Reproducible builds are supported.

    "},{"location":"plugins/builder/wheel/#build-data","title":"Build data","text":"

    This is data that can be modified by build hooks.

    Data Default Description tag The full tag part of the filename (e.g. py3-none-any), defaulting to a cross-platform wheel with the supported major versions of Python based on project metadata infer_tag False When tag is not set, this may be enabled to use the one most specific to the platform, Python interpreter, and ABI pure_python True Whether or not to write metadata indicating that the package does not contain any platform-specific files dependencies Extra project dependencies extra_metadata Additional extra-metadata entries, which take precedence in case of conflicts force_include_editable Similar to the force_include option but specifically for the editable version and takes precedence"},{"location":"plugins/environment/reference/","title":"Environment plugins","text":"

    See the documentation for environment configuration.

    "},{"location":"plugins/environment/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-conda - environments backed by Conda/Mamba
    • hatch-containers - environments run inside containers
    • hatch-pip-compile - use pip-compile to manage project dependencies and lockfiles
    • hatch-pip-deepfreeze - virtual environments with dependency locking by pip-deepfreeze
    "},{"location":"plugins/environment/reference/#installation","title":"Installation","text":"

    Any required environment types that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

    pyproject.toml hatch.toml
    [tool.hatch.env]\nrequires = [\n  \"...\",\n]\n
    [env]\nrequires = [\n  \"...\",\n]\n
    "},{"location":"plugins/environment/reference/#life-cycle","title":"Life cycle","text":"

    Whenever an environment is used, the following logic is performed:

    Source code in src/hatch/cli/application.py
    def prepare_environment(self, environment: EnvironmentInterface):\n    if not environment.exists():\n        self.env_metadata.reset(environment)\n\n        with environment.app_status_creation():\n            environment.create()\n\n        if not environment.skip_install:\n            if environment.pre_install_commands:\n                with environment.app_status_pre_installation():\n                    self.run_shell_commands(environment, environment.pre_install_commands, source='pre-install')\n\n            with environment.app_status_project_installation():\n                if environment.dev_mode:\n                    environment.install_project_dev_mode()\n                else:\n                    environment.install_project()\n\n            if environment.post_install_commands:\n                with environment.app_status_post_installation():\n                    self.run_shell_commands(environment, environment.post_install_commands, source='post-install')\n\n    with environment.app_status_dependency_state_check():\n        new_dep_hash = environment.dependency_hash()\n\n    current_dep_hash = self.env_metadata.dependency_hash(environment)\n    if new_dep_hash != current_dep_hash:\n        with environment.app_status_dependency_installation_check():\n            dependencies_in_sync = environment.dependencies_in_sync()\n\n        if not dependencies_in_sync:\n            with environment.app_status_dependency_synchronization():\n                environment.sync_dependencies()\n                new_dep_hash = environment.dependency_hash()\n\n        self.env_metadata.update_dependency_hash(environment, new_dep_hash)\n
    "},{"location":"plugins/environment/reference/#build-environments","title":"Build environments","text":"

    All environment types should offer support for a special sub-environment in which projects can be built. This environment is used in the following scenarios:

    • the build command
    • commands that read dependencies, like dep hash, if any project dependencies are set dynamically
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface","title":"EnvironmentInterface","text":"

    Example usage:

    plugin.py hooks.py
        from hatch.env.plugin.interface import EnvironmentInterface\n\n\n    class SpecialEnvironment(EnvironmentInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
        from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialEnvironment\n\n\n    @hookimpl\n    def hatch_register_environment():\n        return SpecialEnvironment\n
    Source code in src/hatch/env/plugin/interface.py
    class EnvironmentInterface(ABC):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.env.plugin.interface import EnvironmentInterface\n\n\n        class SpecialEnvironment(EnvironmentInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialEnvironment\n\n\n        @hookimpl\n        def hatch_register_environment():\n            return SpecialEnvironment\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root,\n        metadata,\n        name,\n        config,\n        matrix_variables,\n        data_directory,\n        isolated_data_directory,\n        platform,\n        verbosity,\n        app=None,\n    ):\n        self.__root = root\n        self.__metadata = metadata\n        self.__name = name\n        self.__config = config\n        self.__matrix_variables = matrix_variables\n        self.__data_directory = data_directory\n        self.__isolated_data_directory = isolated_data_directory\n        self.__platform = platform\n        self.__verbosity = verbosity\n        self.__app = app\n        self.__context = None\n\n        self._system_python = None\n        self._env_vars = None\n        self._env_include = None\n        self._env_exclude = None\n        self._environment_dependencies_complex = None\n        self._environment_dependencies = None\n        self._dependencies_complex = None\n        self._dependencies = None\n        self._platforms = None\n        self._skip_install = None\n        self._dev_mode = None\n        self._features = None\n        self._description = None\n        self._scripts = None\n        self._pre_install_commands = None\n        self._post_install_commands = None\n\n    @property\n    def matrix_variables(self):\n        return self.__matrix_variables\n\n    @property\n    def app(self):\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = Application().get_safe_application()\n\n        return self.__app\n\n    @property\n    def context(self):\n        if self.__context is None:\n            self.__context = self.get_context()\n\n        return self.__context\n\n    @property\n    def verbosity(self):\n        return self.__verbosity\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def metadata(self):\n        return self.__metadata\n\n    @property\n    def name(self) -> str:\n        \"\"\"\n        The name of the environment.\n        \"\"\"\n        return self.__name\n\n    @property\n    def platform(self):\n        \"\"\"\n        An instance of [Platform](../utilities.md#hatch.utils.platform.Platform).\n        \"\"\"\n        return self.__platform\n\n    @property\n    def data_directory(self):\n        \"\"\"\n        The [directory](../../config/hatch.md#environments) this plugin should use for storage as a path-like object.\n        If the user has not configured one then this will be the same as the\n        [isolated data directory](reference.md#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory).\n        \"\"\"\n        return self.__data_directory\n\n    @property\n    def isolated_data_directory(self):\n        \"\"\"\n        The default [directory](../../config/hatch.md#environments) reserved exclusively for this plugin as a path-like\n        object.\n        \"\"\"\n        return self.__isolated_data_directory\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @property\n    def system_python(self):\n        if self._system_python is None:\n            system_python = os.environ.get(AppEnvVars.PYTHON)\n            if system_python == 'self':\n                system_python = sys.executable\n\n            system_python = (\n                system_python\n                or self.platform.modules.shutil.which('python')\n                or self.platform.modules.shutil.which('python3')\n                or sys.executable\n            )\n            if not isabs(system_python):\n                system_python = self.platform.modules.shutil.which(system_python)\n\n            self._system_python = system_python\n\n        return self._system_python\n\n    @property\n    def env_vars(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>.env-vars]\n        ```\n        \"\"\"\n        if self._env_vars is None:\n            env_vars = self.config.get('env-vars', {})\n            if not isinstance(env_vars, dict):\n                message = f'Field `tool.hatch.envs.{self.name}.env-vars` must be a mapping'\n                raise TypeError(message)\n\n            for key, value in env_vars.items():\n                if not isinstance(value, str):\n                    message = (\n                        f'Environment variable `{key}` of field `tool.hatch.envs.{self.name}.env-vars` must be a string'\n                    )\n                    raise TypeError(message)\n\n            new_env_vars = {}\n            with self.metadata.context.apply_context(self.context):\n                for key, value in env_vars.items():\n                    new_env_vars[key] = self.metadata.context.format(value)\n\n            new_env_vars[AppEnvVars.ENV_ACTIVE] = self.name\n            self._env_vars = new_env_vars\n\n        return self._env_vars\n\n    @property\n    def env_include(self) -> list[str]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        env-include = [...]\n        ```\n        \"\"\"\n        if self._env_include is None:\n            env_include = self.config.get('env-include', [])\n            if not isinstance(env_include, list):\n                message = f'Field `tool.hatch.envs.{self.name}.env-include` must be an array'\n                raise TypeError(message)\n\n            for i, pattern in enumerate(env_include, 1):\n                if not isinstance(pattern, str):\n                    message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-include` must be a string'\n                    raise TypeError(message)\n\n            if env_include:\n                self._env_include = ['HATCH_BUILD_*', *env_include]\n            else:\n                self._env_include = env_include\n\n        return self._env_include\n\n    @property\n    def env_exclude(self) -> list[str]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        env-exclude = [...]\n        ```\n        \"\"\"\n        if self._env_exclude is None:\n            env_exclude = self.config.get('env-exclude', [])\n            if not isinstance(env_exclude, list):\n                message = f'Field `tool.hatch.envs.{self.name}.env-exclude` must be an array'\n                raise TypeError(message)\n\n            for i, pattern in enumerate(env_exclude, 1):\n                if not isinstance(pattern, str):\n                    message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-exclude` must be a string'\n                    raise TypeError(message)\n\n            self._env_exclude = env_exclude\n\n        return self._env_exclude\n\n    @property\n    def environment_dependencies_complex(self):\n        if self._environment_dependencies_complex is None:\n            from packaging.requirements import InvalidRequirement, Requirement\n\n            dependencies_complex = []\n            with self.apply_context():\n                for option in ('dependencies', 'extra-dependencies'):\n                    dependencies = self.config.get(option, [])\n                    if not isinstance(dependencies, list):\n                        message = f'Field `tool.hatch.envs.{self.name}.{option}` must be an array'\n                        raise TypeError(message)\n\n                    for i, entry in enumerate(dependencies, 1):\n                        if not isinstance(entry, str):\n                            message = (\n                                f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` must be a string'\n                            )\n                            raise TypeError(message)\n\n                        try:\n                            dependencies_complex.append(Requirement(self.metadata.context.format(entry)))\n                        except InvalidRequirement as e:\n                            message = f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` is invalid: {e}'\n                            raise ValueError(message) from None\n\n            self._environment_dependencies_complex = dependencies_complex\n\n        return self._environment_dependencies_complex\n\n    @property\n    def environment_dependencies(self) -> list[str]:\n        \"\"\"\n        The list of all [environment dependencies](../../config/environment/overview.md#dependencies).\n        \"\"\"\n        if self._environment_dependencies is None:\n            self._environment_dependencies = [str(dependency) for dependency in self.environment_dependencies_complex]\n\n        return self._environment_dependencies\n\n    @property\n    def dependencies_complex(self):\n        if self._dependencies_complex is None:\n            all_dependencies_complex = list(self.environment_dependencies_complex)\n\n            # Ensure these are checked last to speed up initial environment creation since\n            # they will already be installed along with the project\n            if (not self.skip_install and self.dev_mode) or self.features:\n                from hatch.utils.dep import get_project_dependencies_complex\n\n                dependencies_complex, optional_dependencies_complex = get_project_dependencies_complex(self)\n\n                if not self.skip_install and self.dev_mode:\n                    all_dependencies_complex.extend(dependencies_complex.values())\n\n                for feature in self.features:\n                    if feature not in optional_dependencies_complex:\n                        message = (\n                            f'Feature `{feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n                            f'defined in the dynamic field `project.optional-dependencies`'\n                        )\n                        raise ValueError(message)\n\n                    all_dependencies_complex.extend(optional_dependencies_complex[feature].values())\n\n            self._dependencies_complex = all_dependencies_complex\n\n        return self._dependencies_complex\n\n    @property\n    def dependencies(self) -> list[str]:\n        \"\"\"\n        The list of all [project dependencies](../../config/metadata.md#dependencies) (if\n        [installed](../../config/environment/overview.md#skip-install) and in\n        [dev mode](../../config/environment/overview.md#dev-mode)), selected\n        [optional dependencies](../../config/environment/overview.md#features), and\n        [environment dependencies](../../config/environment/overview.md#dependencies).\n        \"\"\"\n        if self._dependencies is None:\n            self._dependencies = [str(dependency) for dependency in self.dependencies_complex]\n\n        return self._dependencies\n\n    @property\n    def platforms(self) -> list[str]:\n        \"\"\"\n        All names are stored as their lower-cased version.\n\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        platforms = [...]\n        ```\n        \"\"\"\n        if self._platforms is None:\n            platforms = self.config.get('platforms', [])\n            if not isinstance(platforms, list):\n                message = f'Field `tool.hatch.envs.{self.name}.platforms` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(platforms, 1):\n                if not isinstance(command, str):\n                    message = f'Platform #{i} of field `tool.hatch.envs.{self.name}.platforms` must be a string'\n                    raise TypeError(message)\n\n            self._platforms = [platform.lower() for platform in platforms]\n\n        return self._platforms\n\n    @property\n    def skip_install(self) -> bool:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        skip-install = ...\n        ```\n        \"\"\"\n        if self._skip_install is None:\n            skip_install = self.config.get('skip-install', not self.metadata.has_project_file())\n            if not isinstance(skip_install, bool):\n                message = f'Field `tool.hatch.envs.{self.name}.skip-install` must be a boolean'\n                raise TypeError(message)\n\n            self._skip_install = skip_install\n\n        return self._skip_install\n\n    @property\n    def dev_mode(self) -> bool:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        dev-mode = ...\n        ```\n        \"\"\"\n        if self._dev_mode is None:\n            dev_mode = self.config.get('dev-mode', True)\n            if not isinstance(dev_mode, bool):\n                message = f'Field `tool.hatch.envs.{self.name}.dev-mode` must be a boolean'\n                raise TypeError(message)\n\n            self._dev_mode = dev_mode\n\n        return self._dev_mode\n\n    @property\n    def features(self):\n        if self._features is None:\n            from hatchling.metadata.utils import normalize_project_name\n\n            features = self.config.get('features', [])\n            if not isinstance(features, list):\n                message = f'Field `tool.hatch.envs.{self.name}.features` must be an array of strings'\n                raise TypeError(message)\n\n            all_features = set()\n            for i, feature in enumerate(features, 1):\n                if not isinstance(feature, str):\n                    message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` must be a string'\n                    raise TypeError(message)\n\n                if not feature:\n                    message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` cannot be an empty string'\n                    raise ValueError(message)\n\n                normalized_feature = (\n                    feature\n                    if self.metadata.hatch.metadata.allow_ambiguous_features\n                    else normalize_project_name(feature)\n                )\n                if (\n                    not self.metadata.hatch.metadata.hook_config\n                    and normalized_feature not in self.metadata.core.optional_dependencies\n                ):\n                    message = (\n                        f'Feature `{normalized_feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n                        f'defined in field `project.optional-dependencies`'\n                    )\n                    raise ValueError(message)\n\n                all_features.add(normalized_feature)\n\n            self._features = sorted(all_features)\n\n        return self._features\n\n    @property\n    def description(self) -> str:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        description = ...\n        ```\n        \"\"\"\n        if self._description is None:\n            description = self.config.get('description', '')\n            if not isinstance(description, str):\n                message = f'Field `tool.hatch.envs.{self.name}.description` must be a string'\n                raise TypeError(message)\n\n            self._description = description\n\n        return self._description\n\n    @property\n    def scripts(self):\n        if self._scripts is None:\n            script_config = self.config.get('scripts', {})\n            if not isinstance(script_config, dict):\n                message = f'Field `tool.hatch.envs.{self.name}.scripts` must be a table'\n                raise TypeError(message)\n\n            config = {}\n\n            for name, data in script_config.items():\n                if ' ' in name:\n                    message = (\n                        f'Script name `{name}` in field `tool.hatch.envs.{self.name}.scripts` must not contain spaces'\n                    )\n                    raise ValueError(message)\n\n                commands = []\n\n                if isinstance(data, str):\n                    commands.append(data)\n                elif isinstance(data, list):\n                    for i, command in enumerate(data, 1):\n                        if not isinstance(command, str):\n                            message = (\n                                f'Command #{i} in field `tool.hatch.envs.{self.name}.scripts.{name}` must be a string'\n                            )\n                            raise TypeError(message)\n\n                        commands.append(command)\n                else:\n                    message = (\n                        f'Field `tool.hatch.envs.{self.name}.scripts.{name}` must be a string or an array of strings'\n                    )\n                    raise TypeError(message)\n\n                config[name] = commands\n\n            seen = {}\n            active = []\n            for script_name, commands in config.items():\n                commands[:] = expand_script_commands(self.name, script_name, commands, config, seen, active)\n\n            self._scripts = config\n\n        return self._scripts\n\n    @property\n    def pre_install_commands(self):\n        if self._pre_install_commands is None:\n            pre_install_commands = self.config.get('pre-install-commands', [])\n            if not isinstance(pre_install_commands, list):\n                message = f'Field `tool.hatch.envs.{self.name}.pre-install-commands` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(pre_install_commands, 1):\n                if not isinstance(command, str):\n                    message = (\n                        f'Command #{i} of field `tool.hatch.envs.{self.name}.pre-install-commands` must be a string'\n                    )\n                    raise TypeError(message)\n\n            self._pre_install_commands = list(pre_install_commands)\n\n        return self._pre_install_commands\n\n    @property\n    def post_install_commands(self):\n        if self._post_install_commands is None:\n            post_install_commands = self.config.get('post-install-commands', [])\n            if not isinstance(post_install_commands, list):\n                message = f'Field `tool.hatch.envs.{self.name}.post-install-commands` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(post_install_commands, 1):\n                if not isinstance(command, str):\n                    message = (\n                        f'Command #{i} of field `tool.hatch.envs.{self.name}.post-install-commands` must be a string'\n                    )\n                    raise TypeError(message)\n\n            self._post_install_commands = list(post_install_commands)\n\n        return self._post_install_commands\n\n    def activate(self):\n        \"\"\"\n        A convenience method called when using the environment as a context manager:\n\n        ```python\n        with environment:\n            ...\n        ```\n        \"\"\"\n\n    def deactivate(self):\n        \"\"\"\n        A convenience method called after using the environment as a context manager:\n\n        ```python\n        with environment:\n            ...\n        ```\n        \"\"\"\n\n    @abstractmethod\n    def find(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should return information about how to locate the environment or represent its ID in\n        some way. Additionally, this is expected to return something even if the environment is\n        [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n        \"\"\"\n\n    @abstractmethod\n    def create(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should perform the necessary steps to set up the environment.\n        \"\"\"\n\n    @abstractmethod\n    def remove(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should perform the necessary steps to completely remove the environment from the system and will only\n        be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n        [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n\n        If the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        has a caching mechanism, this should remove that as well.\n        \"\"\"\n\n    @abstractmethod\n    def exists(self) -> bool:\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should indicate whether or not the environment has already been created.\n        \"\"\"\n\n    @abstractmethod\n    def install_project(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the project in the environment.\n        \"\"\"\n\n    @abstractmethod\n    def install_project_dev_mode(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the project in the environment such that the environment\n        always reflects the current state of the project.\n        \"\"\"\n\n    @abstractmethod\n    def dependencies_in_sync(self) -> bool:\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should indicate whether or not the environment is compatible with the current\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n        \"\"\"\n\n    @abstractmethod\n    def sync_dependencies(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n        in the environment.\n        \"\"\"\n\n    def dependency_hash(self):\n        \"\"\"\n        This should return a hash of the environment's\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n        and any other data that is handled by the\n        [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n        and\n        [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n        methods.\n        \"\"\"\n        from hatch.utils.dep import hash_dependencies\n\n        return hash_dependencies(self.dependencies_complex)\n\n    @contextmanager\n    def app_status_creation(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        with self.app.status(f'Creating environment: {self.name}'):\n            yield\n\n    @contextmanager\n    def app_status_pre_installation(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        with self.app.status('Running pre-installation commands'):\n            yield\n\n    @contextmanager\n    def app_status_post_installation(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        with self.app.status('Running post-installation commands'):\n            yield\n\n    @contextmanager\n    def app_status_project_installation(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        if self.dev_mode:\n            with self.app.status('Installing project in development mode'):\n                yield\n        else:\n            with self.app.status('Installing project'):\n                yield\n\n    @contextmanager\n    def app_status_dependency_state_check(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        if not self.skip_install and (\n            'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic\n        ):\n            with self.app.status('Polling dependency state'):\n                yield\n        else:\n            yield\n\n    @contextmanager\n    def app_status_dependency_installation_check(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        with self.app.status('Checking dependencies'):\n            yield\n\n    @contextmanager\n    def app_status_dependency_synchronization(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        with self.app.status('Syncing dependencies'):\n            yield\n\n    @contextmanager\n    def build_environment(\n        self,\n        dependencies: list[str],  # noqa: ARG002\n    ):\n        \"\"\"\n        This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project\n        given a set of dependencies and must be a context manager:\n\n        ```python\n        with environment.build_environment([...]):\n            ...\n        ```\n\n        The build environment should reflect any\n        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n        the user defined either currently or at the time of\n        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n        \"\"\"\n        with self.get_env_vars():\n            yield\n\n    def run_builder(\n        self,\n        build_environment,  # noqa: ARG002\n        **kwargs,\n    ):\n        \"\"\"\n        This will be called when the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        is active:\n\n        ```python\n        with environment.build_environment([...]) as build_env:\n            process = environment.run_builder(build_env, ...)\n        ```\n\n        This should return the standard library's\n        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).\n        The command is constructed by passing all keyword arguments to\n        [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).\n\n        For an example, open the default implementation below:\n        \"\"\"\n        return self.platform.run_command(self.construct_build_command(**kwargs))\n\n    def build_environment_exists(self):  # noqa: PLR6301\n        \"\"\"\n        If the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        has a caching mechanism, this should indicate whether or not it has already been created.\n        \"\"\"\n        return False\n\n    def enter_shell(\n        self,\n        name: str,  # noqa: ARG002\n        path: str,\n        args: Iterable[str],\n    ):\n        \"\"\"\n        Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n        This should either use\n        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n        directly or provide the same guarantee.\n        \"\"\"\n        with self.command_context():\n            self.platform.exit_with_command([path, *args])\n\n    def run_shell_command(self, command: str, **kwargs):\n        \"\"\"\n        This should return the standard library's\n        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n        and will always be called when the\n        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n        is active, with the expectation of providing the same guarantee.\n        \"\"\"\n        kwargs.setdefault('shell', True)\n        return self.platform.run_command(command, **kwargs)\n\n    @contextmanager\n    def command_context(self):\n        \"\"\"\n        A context manager that when active should make executed shell commands reflect any\n        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n        the user defined either currently or at the time of\n        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n        For an example, open the default implementation below:\n        \"\"\"\n        with self.get_env_vars():\n            yield\n\n    def resolve_commands(self, commands: list[str]):\n        \"\"\"\n        This expands each command into one or more commands based on any\n        [scripts](../../config/environment/overview.md#scripts) that the user defined.\n        \"\"\"\n        for command in commands:\n            yield from self.expand_command(command)\n\n    def expand_command(self, command):\n        possible_script, args, _ignore_exit_code = parse_script_command(command)\n\n        # Indicate undefined\n        if not args:\n            args = None\n\n        with self.apply_context():\n            if possible_script in self.scripts:\n                for cmd in self.scripts[possible_script]:\n                    yield self.metadata.context.format(cmd, args=args).strip()\n            else:\n                yield self.metadata.context.format(command, args=args).strip()\n\n    def construct_build_command(  # noqa: PLR6301\n        self,\n        *,\n        directory=None,\n        targets=(),\n        hooks_only=False,\n        no_hooks=False,\n        clean=False,\n        clean_hooks_after=False,\n        clean_only=False,\n    ):\n        \"\"\"\n        This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to\n        a subprocess command issued to [builders](../builder/reference.md).\n        \"\"\"\n        command = ['python', '-u', '-m', 'hatchling', 'build']\n\n        if directory:\n            command.extend(('--directory', directory))\n\n        if targets:\n            for target in targets:\n                command.extend(('--target', target))\n\n        if hooks_only:\n            command.append('--hooks-only')\n\n        if no_hooks:\n            command.append('--no-hooks')\n\n        if clean:\n            command.append('--clean')\n\n        if clean_hooks_after:\n            command.append('--clean-hooks-after')\n\n        if clean_only:\n            command.append('--clean-only')\n\n        return command\n\n    def construct_pip_install_command(self, args: list[str]):\n        \"\"\"\n        A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n        command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n        \"\"\"\n        command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n        # Default to -1 verbosity\n        add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n        command.extend(args)\n        return command\n\n    def join_command_args(self, args: list[str]):\n        \"\"\"\n        This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n        from the received arguments.\n        \"\"\"\n        return self.platform.join_command_args(args)\n\n    def apply_features(self, requirement: str):\n        \"\"\"\n        A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n        to the given requirement.\n        \"\"\"\n        if self.features:\n            features = ','.join(self.features)\n            return f'{requirement}[{features}]'\n\n        return requirement\n\n    def check_compatibility(self):\n        \"\"\"\n        This raises an exception if the environment is not compatible with the user's setup. The default behavior\n        checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n        and any method override should keep this check.\n\n        This check is never performed if the environment has been\n        [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n        \"\"\"\n        if self.platforms and self.platform.name not in self.platforms:\n            message = 'unsupported platform'\n            raise OSError(message)\n\n    def get_env_vars(self) -> EnvVars:\n        \"\"\"\n        Returns a mapping of environment variables that should be available to the environment. The object can\n        be used as a context manager to temporarily apply the environment variables to the current process.\n\n        !!! note\n            The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n        \"\"\"\n        return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n\n    def get_env_var_option(self, option: str) -> str:\n        \"\"\"\n        Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n        \"\"\"\n        return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')\n\n    def get_context(self):\n        \"\"\"\n        Returns a subclass of\n        [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n        \"\"\"\n        from hatch.env.context import EnvironmentContextFormatter\n\n        return EnvironmentContextFormatter(self)\n\n    @staticmethod\n    def get_option_types() -> dict:\n        \"\"\"\n        Returns a mapping of supported options to their respective types so that they can be used by\n        [overrides](../../config/environment/advanced.md#option-overrides).\n        \"\"\"\n        return {}\n\n    @contextmanager\n    def apply_context(self):\n        with self.get_env_vars(), self.metadata.context.apply_context(self.context):\n            yield\n\n    def __enter__(self):\n        self.activate()\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        self.deactivate()\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app","title":"app property","text":"

    An instance of Application.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.root","title":"root property","text":"

    The root of the project tree as a path-like object.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.name","title":"name: str property","text":"

    The name of the environment.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.data_directory","title":"data_directory property","text":"

    The directory this plugin should use for storage as a path-like object. If the user has not configured one then this will be the same as the isolated data directory.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory","title":"isolated_data_directory property","text":"

    The default directory reserved exclusively for this plugin as a path-like object.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\n
    [envs.<ENV_NAME>]\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platform","title":"platform property","text":"

    An instance of Platform.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.environment_dependencies","title":"environment_dependencies: list[str] property","text":"

    The list of all environment dependencies.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies","title":"dependencies: list[str] property","text":"

    The list of all project dependencies (if installed and in dev mode), selected optional dependencies, and environment dependencies.

    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_vars","title":"env_vars: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>.env-vars]\n
    [envs.<ENV_NAME>.env-vars]\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_include","title":"env_include: list[str] property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nenv-include = [...]\n
    [envs.<ENV_NAME>]\nenv-include = [...]\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_exclude","title":"env_exclude: list[str] property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nenv-exclude = [...]\n
    [envs.<ENV_NAME>]\nenv-exclude = [...]\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platforms","title":"platforms: list[str] property","text":"

    All names are stored as their lower-cased version.

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nplatforms = [...]\n
    [envs.<ENV_NAME>]\nplatforms = [...]\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.skip_install","title":"skip_install: bool property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\nskip-install = ...\n
    [envs.<ENV_NAME>]\nskip-install = ...\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dev_mode","title":"dev_mode: bool property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\ndev-mode = ...\n
    [envs.<ENV_NAME>]\ndev-mode = ...\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.description","title":"description: str property","text":"pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\ndescription = ...\n
    [envs.<ENV_NAME>]\ndescription = ...\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.find","title":"find() abstractmethod","text":"

    REQUIRED

    This should return information about how to locate the environment or represent its ID in some way. Additionally, this is expected to return something even if the environment is incompatible.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef find(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should return information about how to locate the environment or represent its ID in\n    some way. Additionally, this is expected to return something even if the environment is\n    [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.create","title":"create() abstractmethod","text":"

    REQUIRED

    This should perform the necessary steps to set up the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef create(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should perform the necessary steps to set up the environment.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.remove","title":"remove() abstractmethod","text":"

    REQUIRED

    This should perform the necessary steps to completely remove the environment from the system and will only be triggered manually by users with the env remove or env prune commands.

    If the build environment has a caching mechanism, this should remove that as well.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef remove(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should perform the necessary steps to completely remove the environment from the system and will only\n    be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n    [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n\n    If the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    has a caching mechanism, this should remove that as well.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.exists","title":"exists() -> bool abstractmethod","text":"

    REQUIRED

    This should indicate whether or not the environment has already been created.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef exists(self) -> bool:\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should indicate whether or not the environment has already been created.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project","title":"install_project() abstractmethod","text":"

    REQUIRED

    This should install the project in the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef install_project(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the project in the environment.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project_dev_mode","title":"install_project_dev_mode() abstractmethod","text":"

    REQUIRED

    This should install the project in the environment such that the environment always reflects the current state of the project.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef install_project_dev_mode(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the project in the environment such that the environment\n    always reflects the current state of the project.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync","title":"dependencies_in_sync() -> bool abstractmethod","text":"

    REQUIRED

    This should indicate whether or not the environment is compatible with the current dependencies.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef dependencies_in_sync(self) -> bool:\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should indicate whether or not the environment is compatible with the current\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies","title":"sync_dependencies() abstractmethod","text":"

    REQUIRED

    This should install the dependencies in the environment.

    Source code in src/hatch/env/plugin/interface.py
    @abstractmethod\ndef sync_dependencies(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n    in the environment.\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependency_hash","title":"dependency_hash()","text":"

    This should return a hash of the environment's dependencies and any other data that is handled by the sync_dependencies and dependencies_in_sync methods.

    Source code in src/hatch/env/plugin/interface.py
    def dependency_hash(self):\n    \"\"\"\n    This should return a hash of the environment's\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n    and any other data that is handled by the\n    [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n    and\n    [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n    methods.\n    \"\"\"\n    from hatch.utils.dep import hash_dependencies\n\n    return hash_dependencies(self.dependencies_complex)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.build_environment","title":"build_environment(dependencies: list[str])","text":"

    This should set up an isolated environment in which to build the project given a set of dependencies and must be a context manager:

    with environment.build_environment([...]):\n    ...\n

    The build environment should reflect any environment variables the user defined either currently or at the time of creation.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef build_environment(\n    self,\n    dependencies: list[str],  # noqa: ARG002\n):\n    \"\"\"\n    This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project\n    given a set of dependencies and must be a context manager:\n\n    ```python\n    with environment.build_environment([...]):\n        ...\n    ```\n\n    The build environment should reflect any\n    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n    the user defined either currently or at the time of\n    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n    \"\"\"\n    with self.get_env_vars():\n        yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.build_environment_exists","title":"build_environment_exists()","text":"

    If the build environment has a caching mechanism, this should indicate whether or not it has already been created.

    Source code in src/hatch/env/plugin/interface.py
    def build_environment_exists(self):  # noqa: PLR6301\n    \"\"\"\n    If the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    has a caching mechanism, this should indicate whether or not it has already been created.\n    \"\"\"\n    return False\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.activate","title":"activate()","text":"

    A convenience method called when using the environment as a context manager:

    with environment:\n    ...\n
    Source code in src/hatch/env/plugin/interface.py
    def activate(self):\n    \"\"\"\n    A convenience method called when using the environment as a context manager:\n\n    ```python\n    with environment:\n        ...\n    ```\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.deactivate","title":"deactivate()","text":"

    A convenience method called after using the environment as a context manager:

    with environment:\n    ...\n
    Source code in src/hatch/env/plugin/interface.py
    def deactivate(self):\n    \"\"\"\n    A convenience method called after using the environment as a context manager:\n\n    ```python\n    with environment:\n        ...\n    ```\n    \"\"\"\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_creation","title":"app_status_creation()","text":"

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef app_status_creation(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    with self.app.status(f'Creating environment: {self.name}'):\n        yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_pre_installation","title":"app_status_pre_installation()","text":"

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef app_status_pre_installation(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    with self.app.status('Running pre-installation commands'):\n        yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_post_installation","title":"app_status_post_installation()","text":"

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef app_status_post_installation(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    with self.app.status('Running post-installation commands'):\n        yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_project_installation","title":"app_status_project_installation()","text":"

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef app_status_project_installation(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    if self.dev_mode:\n        with self.app.status('Installing project in development mode'):\n            yield\n    else:\n        with self.app.status('Installing project'):\n            yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_state_check","title":"app_status_dependency_state_check()","text":"

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef app_status_dependency_state_check(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    if not self.skip_install and (\n        'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic\n    ):\n        with self.app.status('Polling dependency state'):\n            yield\n    else:\n        yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_installation_check","title":"app_status_dependency_installation_check()","text":"

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef app_status_dependency_installation_check(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    with self.app.status('Checking dependencies'):\n        yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_synchronization","title":"app_status_dependency_synchronization()","text":"

    See the life cycle of environments.

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef app_status_dependency_synchronization(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    with self.app.status('Syncing dependencies'):\n        yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.run_builder","title":"run_builder(build_environment, **kwargs)","text":"

    This will be called when the build environment is active:

    with environment.build_environment([...]) as build_env:\n    process = environment.run_builder(build_env, ...)\n

    This should return the standard library's subprocess.CompletedProcess. The command is constructed by passing all keyword arguments to construct_build_command.

    For an example, open the default implementation below:

    Source code in src/hatch/env/plugin/interface.py
    def run_builder(\n    self,\n    build_environment,  # noqa: ARG002\n    **kwargs,\n):\n    \"\"\"\n    This will be called when the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    is active:\n\n    ```python\n    with environment.build_environment([...]) as build_env:\n        process = environment.run_builder(build_env, ...)\n    ```\n\n    This should return the standard library's\n    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).\n    The command is constructed by passing all keyword arguments to\n    [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).\n\n    For an example, open the default implementation below:\n    \"\"\"\n    return self.platform.run_command(self.construct_build_command(**kwargs))\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command","title":"construct_build_command(*, directory=None, targets=(), hooks_only=False, no_hooks=False, clean=False, clean_hooks_after=False, clean_only=False)","text":"

    This is the canonical way build command options are translated to a subprocess command issued to builders.

    Source code in src/hatch/env/plugin/interface.py
    def construct_build_command(  # noqa: PLR6301\n    self,\n    *,\n    directory=None,\n    targets=(),\n    hooks_only=False,\n    no_hooks=False,\n    clean=False,\n    clean_hooks_after=False,\n    clean_only=False,\n):\n    \"\"\"\n    This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to\n    a subprocess command issued to [builders](../builder/reference.md).\n    \"\"\"\n    command = ['python', '-u', '-m', 'hatchling', 'build']\n\n    if directory:\n        command.extend(('--directory', directory))\n\n    if targets:\n        for target in targets:\n            command.extend(('--target', target))\n\n    if hooks_only:\n        command.append('--hooks-only')\n\n    if no_hooks:\n        command.append('--no-hooks')\n\n    if clean:\n        command.append('--clean')\n\n    if clean_hooks_after:\n        command.append('--clean-hooks-after')\n\n    if clean_only:\n        command.append('--clean-only')\n\n    return command\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.command_context","title":"command_context()","text":"

    A context manager that when active should make executed shell commands reflect any environment variables the user defined either currently or at the time of creation.

    For an example, open the default implementation below:

    Source code in src/hatch/env/plugin/interface.py
    @contextmanager\ndef command_context(self):\n    \"\"\"\n    A context manager that when active should make executed shell commands reflect any\n    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n    the user defined either currently or at the time of\n    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n    For an example, open the default implementation below:\n    \"\"\"\n    with self.get_env_vars():\n        yield\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.enter_shell","title":"enter_shell(name: str, path: str, args: Iterable[str])","text":"

    Spawn a shell within the environment.

    This should either use command_context directly or provide the same guarantee.

    Source code in src/hatch/env/plugin/interface.py
    def enter_shell(\n    self,\n    name: str,  # noqa: ARG002\n    path: str,\n    args: Iterable[str],\n):\n    \"\"\"\n    Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n    This should either use\n    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n    directly or provide the same guarantee.\n    \"\"\"\n    with self.command_context():\n        self.platform.exit_with_command([path, *args])\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.run_shell_command","title":"run_shell_command(command: str, **kwargs)","text":"

    This should return the standard library's subprocess.CompletedProcess and will always be called when the command_context is active, with the expectation of providing the same guarantee.

    Source code in src/hatch/env/plugin/interface.py
    def run_shell_command(self, command: str, **kwargs):\n    \"\"\"\n    This should return the standard library's\n    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n    and will always be called when the\n    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n    is active, with the expectation of providing the same guarantee.\n    \"\"\"\n    kwargs.setdefault('shell', True)\n    return self.platform.run_command(command, **kwargs)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.resolve_commands","title":"resolve_commands(commands: list[str])","text":"

    This expands each command into one or more commands based on any scripts that the user defined.

    Source code in src/hatch/env/plugin/interface.py
    def resolve_commands(self, commands: list[str]):\n    \"\"\"\n    This expands each command into one or more commands based on any\n    [scripts](../../config/environment/overview.md#scripts) that the user defined.\n    \"\"\"\n    for command in commands:\n        yield from self.expand_command(command)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars","title":"get_env_vars() -> EnvVars","text":"

    Returns a mapping of environment variables that should be available to the environment. The object can be used as a context manager to temporarily apply the environment variables to the current process.

    Note

    The environment variable HATCH_ENV_ACTIVE will always be set to the name of the environment.

    Source code in src/hatch/env/plugin/interface.py
    def get_env_vars(self) -> EnvVars:\n    \"\"\"\n    Returns a mapping of environment variables that should be available to the environment. The object can\n    be used as a context manager to temporarily apply the environment variables to the current process.\n\n    !!! note\n        The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n    \"\"\"\n    return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.apply_features","title":"apply_features(requirement: str)","text":"

    A convenience method that applies any user defined features to the given requirement.

    Source code in src/hatch/env/plugin/interface.py
    def apply_features(self, requirement: str):\n    \"\"\"\n    A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n    to the given requirement.\n    \"\"\"\n    if self.features:\n        features = ','.join(self.features)\n        return f'{requirement}[{features}]'\n\n    return requirement\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.construct_pip_install_command","title":"construct_pip_install_command(args: list[str])","text":"

    A convenience method for constructing a pip install command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.

    Source code in src/hatch/env/plugin/interface.py
    def construct_pip_install_command(self, args: list[str]):\n    \"\"\"\n    A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n    command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n    \"\"\"\n    command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n    # Default to -1 verbosity\n    add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n    command.extend(args)\n    return command\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.join_command_args","title":"join_command_args(args: list[str])","text":"

    This is used by the run command to construct the root command string from the received arguments.

    Source code in src/hatch/env/plugin/interface.py
    def join_command_args(self, args: list[str]):\n    \"\"\"\n    This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n    from the received arguments.\n    \"\"\"\n    return self.platform.join_command_args(args)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility","title":"check_compatibility()","text":"

    This raises an exception if the environment is not compatible with the user's setup. The default behavior checks for platform compatibility and any method override should keep this check.

    This check is never performed if the environment has been created.

    Source code in src/hatch/env/plugin/interface.py
    def check_compatibility(self):\n    \"\"\"\n    This raises an exception if the environment is not compatible with the user's setup. The default behavior\n    checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n    and any method override should keep this check.\n\n    This check is never performed if the environment has been\n    [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n    \"\"\"\n    if self.platforms and self.platform.name not in self.platforms:\n        message = 'unsupported platform'\n        raise OSError(message)\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_option_types","title":"get_option_types() -> dict staticmethod","text":"

    Returns a mapping of supported options to their respective types so that they can be used by overrides.

    Source code in src/hatch/env/plugin/interface.py
    @staticmethod\ndef get_option_types() -> dict:\n    \"\"\"\n    Returns a mapping of supported options to their respective types so that they can be used by\n    [overrides](../../config/environment/advanced.md#option-overrides).\n    \"\"\"\n    return {}\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_var_option","title":"get_env_var_option(option: str) -> str","text":"

    Returns the value of the upper-cased environment variable HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>.

    Source code in src/hatch/env/plugin/interface.py
    def get_env_var_option(self, option: str) -> str:\n    \"\"\"\n    Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n    \"\"\"\n    return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')\n
    "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_context","title":"get_context()","text":"

    Returns a subclass of EnvironmentContextFormatter.

    Source code in src/hatch/env/plugin/interface.py
    def get_context(self):\n    \"\"\"\n    Returns a subclass of\n    [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n    \"\"\"\n    from hatch.env.context import EnvironmentContextFormatter\n\n    return EnvironmentContextFormatter(self)\n
    "},{"location":"plugins/environment/virtual/","title":"Virtual environment","text":"

    This uses virtual environments backed by the standard virtualenv tool.

    "},{"location":"plugins/environment/virtual/#configuration","title":"Configuration","text":"

    The environment plugin name is virtual.

    pyproject.toml hatch.toml
    [tool.hatch.envs.<ENV_NAME>]\ntype = \"virtual\"\n
    [envs.<ENV_NAME>]\ntype = \"virtual\"\n
    "},{"location":"plugins/environment/virtual/#options","title":"Options","text":"Option Default Description python The version of Python to find on your system and subsequently use to create the environment, defaulting to the HATCH_PYTHON environment variable, followed by the normal resolution logic. Setting the HATCH_PYTHON environment variable to self will force the use of the Python executable Hatch is running on. For more information, see the documentation. python-sources ['external', 'internal'] This may be set to an array of strings that are either the literal internal or external. External considers only Python executables that are already on PATH. Internal considers only internally managed Python distributions. path An explicit path to the virtual environment. The path may be absolute or relative to the project root. Any environments that inherit this option will also use this path. The environment variable HATCH_ENV_TYPE_VIRTUAL_PATH may be used, which will take precedence. system-packages false Whether or not to give the virtual environment access to the system site-packages directory"},{"location":"plugins/environment/virtual/#location","title":"Location","text":"

    The location of environments is determined in the following heuristic order:

    1. The path option
    2. A directory named after the environment within the configured virtual environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
    3. Otherwise, environments are stored within the configured virtual environment directory in a deeply nested structure in order to support multiple projects

    Additionally, when the path option is not used, the name of the directory for the default environment will be the normalized project name to provide a more meaningful default shell prompt.

    "},{"location":"plugins/environment/virtual/#python-resolution","title":"Python resolution","text":"

    Virtual environments necessarily require a parent installation of Python. The following rules determine how the parent is resolved.

    The Python choice is determined by the python option followed by the HATCH_PYTHON environment variable. If the choice is via the environment variable, then resolution stops and that path is used unconditionally.

    The resolvers will be based on the python-sources option and all resolved interpreters will ensure compatibility with the project's defined Python support.

    If a Python version has been chosen then each resolver will try to find an interpreter that satisfies that version.

    If no version has been chosen, then each resolver will try to find a version that matches the version of Python that Hatch is currently running on. If not found then each resolver will try to find the highest compatible version.

    Note

    Some external Python paths are considered unstable and are ignored during resolution. For example, if Hatch is installed via Homebrew then sys.executable will be ignored because the interpreter could change or be removed at any time.

    Note

    When resolution finds a match using an internally managed distribution and an update is available, the latest distribution will automatically be downloaded before environment creation.

    "},{"location":"plugins/environment/virtual/#internal-distributions","title":"Internal distributions","text":"

    The following options are recognized for internal Python resolution.

    "},{"location":"plugins/environment/virtual/#cpython","title":"CPython","text":"ID 3.7 3.8 3.9 3.10 3.11 3.12

    The source of distributions is the python-build-standalone project.

    Some distributions have variants that may be configured with the HATCH_PYTHON_VARIANT_<PLATFORM> environment variable where <PLATFORM> is the uppercase version of one of the following:

    Platform Options Linux
    • v1
    • v2
    • v3 (default)
    • v4
    Windows
    • shared (default)
    • static
    "},{"location":"plugins/environment/virtual/#pypy","title":"PyPy","text":"ID pypy2.7 pypy3.9 pypy3.10

    The source of distributions is the PyPy project.

    "},{"location":"plugins/environment/virtual/#troubleshooting","title":"Troubleshooting","text":""},{"location":"plugins/environment/virtual/#macos-sip","title":"macOS SIP","text":"

    If you need to set linker environment variables like those starting with DYLD_ or LD_, any executable secured by System Integrity Protection that is invoked when running commands will not see those environment variable modifications as macOS strips those.

    Hatch interprets such commands as shell commands but deliberately ignores such paths to protected shells. This workaround suffices for the majority of use cases but there are 2 situations in which it may not:

    1. There are no unprotected sh, bash, zsh, nor fish executables found along PATH.
    2. The desired executable is a project's script, and the location of environments contains spaces or is longer than 1241 characters. In this case pip and other installers will create such an entry point with a shebang pointing to /bin/sh (which is protected) to avoid shebang limitations. Rather than changing the location, you could invoke the script as e.g. python -m pytest (if the project supports that method of invocation by shipping a __main__.py).
    1. The shebang length limit is usually 127 but 3 characters surround the executable path: #!<EXE_PATH>\\n \u21a9

    "},{"location":"plugins/environment-collector/custom/","title":"Custom environment collector","text":"

    This is a custom class in a given Python file that inherits from the EnvironmentCollectorInterface.

    "},{"location":"plugins/environment-collector/custom/#configuration","title":"Configuration","text":"

    The environment collector plugin name is custom.

    pyproject.toml hatch.toml
    [tool.hatch.env.collectors.custom]\n
    [env.collectors.custom]\n
    "},{"location":"plugins/environment-collector/custom/#options","title":"Options","text":"Option Default Description path hatch_plugins.py The path of the Python file"},{"location":"plugins/environment-collector/custom/#example","title":"Example","text":"hatch_plugins.py
        from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n    class CustomEnvironmentCollector(EnvironmentCollectorInterface):\n        ...\n

    If multiple subclasses are found, you must define a function named get_environment_collector that returns the desired environment collector.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    "},{"location":"plugins/environment-collector/default/","title":"Default environment collector","text":"

    This adds the default environment with type set to virtual and will always be applied.

    "},{"location":"plugins/environment-collector/default/#configuration","title":"Configuration","text":"

    The environment collector plugin name is default.

    pyproject.toml hatch.toml
    [tool.hatch.env.collectors.default]\n
    [env.collectors.default]\n
    "},{"location":"plugins/environment-collector/default/#options","title":"Options","text":"

    There are no options available currently.

    "},{"location":"plugins/environment-collector/reference/","title":"Environment collector plugins","text":"

    Environment collectors allow for dynamically modifying environments or adding environments beyond those defined in config. Users can override default values provided by each environment.

    "},{"location":"plugins/environment-collector/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-mkdocs - integrate MkDocs and infer dependencies into an env
    "},{"location":"plugins/environment-collector/reference/#installation","title":"Installation","text":"

    Any required environment collectors that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

    pyproject.toml hatch.toml
    [tool.hatch.env]\nrequires = [\n  \"...\",\n]\n
    [env]\nrequires = [\n  \"...\",\n]\n
    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface","title":"EnvironmentCollectorInterface","text":"

    Example usage:

    plugin.py hooks.py
        from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n    class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
        from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialEnvironmentCollector\n\n\n    @hookimpl\n    def hatch_register_environment_collector():\n        return SpecialEnvironmentCollector\n
    Source code in src/hatch/env/collectors/plugin/interface.py
    class EnvironmentCollectorInterface:\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n        class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialEnvironmentCollector\n\n\n        @hookimpl\n        def hatch_register_environment_collector():\n            return SpecialEnvironmentCollector\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root, config):\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.env.collectors.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    def get_initial_config(self) -> dict[str, dict]:  # noqa: PLR6301\n        \"\"\"\n        Returns configuration for environments keyed by the environment or matrix name.\n        \"\"\"\n        return {}\n\n    def finalize_config(self, config: dict[str, dict]):\n        \"\"\"\n        Finalizes configuration for environments keyed by the environment or matrix name. This will override\n        any user-defined settings and any collectors that ran before this call.\n\n        This is called before matrices are turned into concrete environments.\n        \"\"\"\n\n    def finalize_environments(self, config: dict[str, dict]):\n        \"\"\"\n        Finalizes configuration for environments keyed by the environment name. This will override\n        any user-defined settings and any collectors that ran before this call.\n\n        This is called after matrices are turned into concrete environments.\n        \"\"\"\n
    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.root","title":"root property","text":"

    The root of the project tree as a path-like object.

    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.env.collectors.<PLUGIN_NAME>]\n
    [env.collectors.<PLUGIN_NAME>]\n
    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.get_initial_config","title":"get_initial_config() -> dict[str, dict]","text":"

    Returns configuration for environments keyed by the environment or matrix name.

    Source code in src/hatch/env/collectors/plugin/interface.py
    def get_initial_config(self) -> dict[str, dict]:  # noqa: PLR6301\n    \"\"\"\n    Returns configuration for environments keyed by the environment or matrix name.\n    \"\"\"\n    return {}\n
    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_config","title":"finalize_config(config: dict[str, dict])","text":"

    Finalizes configuration for environments keyed by the environment or matrix name. This will override any user-defined settings and any collectors that ran before this call.

    This is called before matrices are turned into concrete environments.

    Source code in src/hatch/env/collectors/plugin/interface.py
    def finalize_config(self, config: dict[str, dict]):\n    \"\"\"\n    Finalizes configuration for environments keyed by the environment or matrix name. This will override\n    any user-defined settings and any collectors that ran before this call.\n\n    This is called before matrices are turned into concrete environments.\n    \"\"\"\n
    "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_environments","title":"finalize_environments(config: dict[str, dict])","text":"

    Finalizes configuration for environments keyed by the environment name. This will override any user-defined settings and any collectors that ran before this call.

    This is called after matrices are turned into concrete environments.

    Source code in src/hatch/env/collectors/plugin/interface.py
    def finalize_environments(self, config: dict[str, dict]):\n    \"\"\"\n    Finalizes configuration for environments keyed by the environment name. This will override\n    any user-defined settings and any collectors that ran before this call.\n\n    This is called after matrices are turned into concrete environments.\n    \"\"\"\n
    "},{"location":"plugins/metadata-hook/custom/","title":"Custom metadata hook","text":"

    This is a custom class in a given Python file that inherits from the MetadataHookInterface.

    "},{"location":"plugins/metadata-hook/custom/#configuration","title":"Configuration","text":"

    The metadata hook plugin name is custom.

    pyproject.toml hatch.toml
    [tool.hatch.metadata.hooks.custom]\n
    [metadata.hooks.custom]\n
    "},{"location":"plugins/metadata-hook/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/metadata-hook/custom/#example","title":"Example","text":"hatch_build.py
    from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass CustomMetadataHook(MetadataHookInterface):\n    ...\n

    If multiple subclasses are found, you must define a function named get_metadata_hook that returns the desired build hook.

    Note

    Any defined PLUGIN_NAME is ignored and will always be custom.

    "},{"location":"plugins/metadata-hook/reference/","title":"Metadata hook plugins","text":"

    Metadata hooks allow for the modification of project metadata after it has been loaded.

    "},{"location":"plugins/metadata-hook/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-docstring-description - set the project description using docstrings
    • hatch-fancy-pypi-readme - dynamically construct the README
    • hatch-nodejs-version - uses fields from NodeJS package.json files
    • hatch-odoo - determine dependencies based on manifests of Odoo add-ons
    • hatch-requirements-txt - read project dependencies from requirements.txt files
    • UniDep - for unified pip and conda dependency management using a single requirements.yaml file for both
    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface","title":"MetadataHookInterface","text":"

    Example usage:

    plugin.py hooks.py
    from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass SpecialMetadataHook(MetadataHookInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialMetadataHook\n\n\n@hookimpl\ndef hatch_register_metadata_hook():\n    return SpecialMetadataHook\n
    Source code in backend/src/hatchling/metadata/plugin/interface.py
    class MetadataHookInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\n    class SpecialMetadataHook(MetadataHookInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialMetadataHook\n\n\n    @hookimpl\n    def hatch_register_metadata_hook():\n        return SpecialMetadataHook\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        The hook configuration.\n\n        ```toml config-example\n        [tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def update(self, metadata: dict) -> None:\n        \"\"\"\n        This updates the metadata mapping of the `project` table in-place.\n        \"\"\"\n\n    def get_known_classifiers(self) -> list[str]:  # noqa: PLR6301\n        \"\"\"\n        This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n        \"\"\"\n        return []\n
    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.root","title":"root: str property","text":"

    The root of the project tree.

    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.config","title":"config: dict property","text":"

    The hook configuration.

    pyproject.toml hatch.toml
    [tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n
    [metadata.hooks.<PLUGIN_NAME>]\n
    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.update","title":"update(metadata: dict) -> None abstractmethod","text":"

    This updates the metadata mapping of the project table in-place.

    Source code in backend/src/hatchling/metadata/plugin/interface.py
    @abstractmethod\ndef update(self, metadata: dict) -> None:\n    \"\"\"\n    This updates the metadata mapping of the `project` table in-place.\n    \"\"\"\n
    "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.get_known_classifiers","title":"get_known_classifiers() -> list[str]","text":"

    This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.

    Source code in backend/src/hatchling/metadata/plugin/interface.py
    def get_known_classifiers(self) -> list[str]:  # noqa: PLR6301\n    \"\"\"\n    This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n    \"\"\"\n    return []\n
    "},{"location":"plugins/publisher/package-index/","title":"Index publisher","text":"

    See the documentation for publishing.

    "},{"location":"plugins/publisher/package-index/#options","title":"Options","text":"Flag Config name Description -r/--repo repo The repository with which to publish artifacts -u/--user user The user with which to authenticate -a/--auth auth The credentials to use for authentication --ca-cert ca-cert The path to a CA bundle --client-cert client-cert The path to a client certificate, optionally containing the private key --client-key client-key The path to the client certificate's private key repos A table of named repositories to their respective options"},{"location":"plugins/publisher/package-index/#configuration","title":"Configuration","text":"

    The publisher plugin name is index.

    config.toml
    [publish.index]\n
    "},{"location":"plugins/publisher/package-index/#repositories","title":"Repositories","text":"

    All top-level options can be overridden per repository using the repos table with a required url attribute for each repository. The following shows the default configuration:

    config.toml
    [publish.index.repos.main]\nurl = \"https://upload.pypi.org/legacy/\"\n\n[publish.index.repos.test]\nurl = \"https://test.pypi.org/legacy/\"\n

    The repo and repos options have no effect.

    "},{"location":"plugins/publisher/package-index/#confirmation-prompt","title":"Confirmation prompt","text":"

    You can require a confirmation prompt or use of the -y/--yes flag by setting publishers' disable option to true in either Hatch's config file or project-specific configuration (which takes precedence):

    config.toml pyproject.toml hatch.toml
    [publish.index]\ndisable = true\n
    [tool.hatch.publish.index]\ndisable = true\n
    [publish.index]\ndisable = true\n
    "},{"location":"plugins/publisher/reference/","title":"Publisher plugins","text":""},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface","title":"PublisherInterface","text":"

    Example usage:

    plugin.py hooks.py
        from hatch.publish.plugin.interface import PublisherInterface\n\n\n    class SpecialPublisher(PublisherInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
        from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialPublisher\n\n\n    @hookimpl\n    def hatch_register_publisher():\n        return SpecialPublisher\n
    Source code in src/hatch/publish/plugin/interface.py
    class PublisherInterface(ABC):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.publish.plugin.interface import PublisherInterface\n\n\n        class SpecialPublisher(PublisherInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialPublisher\n\n\n        @hookimpl\n        def hatch_register_publisher():\n            return SpecialPublisher\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, app, root, cache_dir, project_config, plugin_config):\n        self.__app = app\n        self.__root = root\n        self.__cache_dir = cache_dir\n        self.__project_config = project_config\n        self.__plugin_config = plugin_config\n\n        self.__disable = None\n\n    @property\n    def app(self):\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        return self.__app\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def cache_dir(self):\n        \"\"\"\n        The directory reserved exclusively for this plugin as a path-like object.\n        \"\"\"\n        return self.__cache_dir\n\n    @property\n    def project_config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.publish.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__project_config\n\n    @property\n    def plugin_config(self) -> dict:\n        \"\"\"\n        This is defined in Hatch's [config file](../../config/hatch.md).\n\n        ```toml tab=\"config.toml\"\n        [publish.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__plugin_config\n\n    @property\n    def disable(self):\n        \"\"\"\n        Whether this plugin is disabled, thus requiring confirmation when publishing. Local\n        [project configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.project_config)\n        takes precedence over global\n        [plugin configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.plugin_config).\n        \"\"\"\n        if self.__disable is None:\n            if 'disable' in self.project_config:\n                disable = self.project_config['disable']\n                if not isinstance(disable, bool):\n                    message = f'Field `tool.hatch.publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n                    raise TypeError(message)\n            else:\n                disable = self.plugin_config.get('disable', False)\n                if not isinstance(disable, bool):\n                    message = f'Global plugin configuration `publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n                    raise TypeError(message)\n\n            self.__disable = disable\n\n        return self.__disable\n\n    @abstractmethod\n    def publish(self, artifacts: list[str], options: dict):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n        with the arguments and options it receives.\n        \"\"\"\n
    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.app","title":"app property","text":"

    An instance of Application.

    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.root","title":"root property","text":"

    The root of the project tree as a path-like object.

    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.cache_dir","title":"cache_dir property","text":"

    The directory reserved exclusively for this plugin as a path-like object.

    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.project_config","title":"project_config: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.publish.<PLUGIN_NAME>]\n
    [publish.<PLUGIN_NAME>]\n
    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.plugin_config","title":"plugin_config: dict property","text":"

    This is defined in Hatch's config file.

    config.toml
    [publish.<PLUGIN_NAME>]\n
    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.disable","title":"disable property","text":"

    Whether this plugin is disabled, thus requiring confirmation when publishing. Local project configuration takes precedence over global plugin configuration.

    "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.publish","title":"publish(artifacts: list[str], options: dict) abstractmethod","text":"

    REQUIRED

    This is called directly by the publish command with the arguments and options it receives.

    Source code in src/hatch/publish/plugin/interface.py
    @abstractmethod\ndef publish(self, artifacts: list[str], options: dict):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n    with the arguments and options it receives.\n    \"\"\"\n
    "},{"location":"plugins/version-scheme/reference/","title":"Version scheme plugins","text":""},{"location":"plugins/version-scheme/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-semver - uses semantic versioning
    "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface","title":"VersionSchemeInterface","text":"

    Example usage:

    plugin.py hooks.py
    from hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\nclass SpecialVersionScheme(VersionSchemeInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionScheme\n\n\n@hookimpl\ndef hatch_register_version_scheme():\n    return SpecialVersionScheme\n
    Source code in backend/src/hatchling/version/scheme/plugin/interface.py
    class VersionSchemeInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\n    class SpecialVersionScheme(VersionSchemeInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialVersionScheme\n\n\n    @hookimpl\n    def hatch_register_version_scheme():\n        return SpecialVersionScheme\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree as a string.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.version]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n        \"\"\"\n        This should return a normalized form of the desired version and verify that it\n        is higher than the original version.\n        \"\"\"\n
    "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.root","title":"root: str property","text":"

    The root of the project tree as a string.

    "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.version]\n
    [version]\n
    "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.update","title":"update(desired_version: str, original_version: str, version_data: dict) -> str abstractmethod","text":"

    This should return a normalized form of the desired version and verify that it is higher than the original version.

    Source code in backend/src/hatchling/version/scheme/plugin/interface.py
    @abstractmethod\ndef update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n    \"\"\"\n    This should return a normalized form of the desired version and verify that it\n    is higher than the original version.\n    \"\"\"\n
    "},{"location":"plugins/version-scheme/standard/","title":"Standard version scheme","text":"

    See the documentation for versioning.

    "},{"location":"plugins/version-scheme/standard/#configuration","title":"Configuration","text":"

    The version scheme plugin name is standard.

    pyproject.toml hatch.toml
    [tool.hatch.version]\nscheme = \"standard\"\n
    [version]\nscheme = \"standard\"\n
    "},{"location":"plugins/version-scheme/standard/#options","title":"Options","text":"Option Description validate-bump When setting a specific version, this determines whether to check that the new version is higher than the original. The default is true."},{"location":"plugins/version-source/code/","title":"Code version source","text":""},{"location":"plugins/version-source/code/#updates","title":"Updates","text":"

    Setting the version is not supported.

    "},{"location":"plugins/version-source/code/#configuration","title":"Configuration","text":"

    The version source plugin name is code.

    pyproject.toml hatch.toml
    [tool.hatch.version]\nsource = \"code\"\n
    [version]\nsource = \"code\"\n
    "},{"location":"plugins/version-source/code/#options","title":"Options","text":"Option Description path (required) A relative path to a Python file or extension module that will be loaded expression A Python expression that when evaluated in the context of the loaded file returns the version. The default expression is simply __version__. search-paths A list of relative paths to directories that will be prepended to Python's search path"},{"location":"plugins/version-source/code/#missing-imports","title":"Missing imports","text":"

    If the chosen path imports another module in your project, then you'll need to use absolute imports coupled with the search-paths option. For example, say you need to load the following file:

    src/pkg/__init__.py
        from ._version import get_version\n\n    __version__ = get_version()\n

    You should change it to:

    src/pkg/__init__.py
        from pkg._version import get_version\n\n    __version__ = get_version()\n

    and the configuration would become:

    pyproject.toml hatch.toml
    [tool.hatch.version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
    [version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
    "},{"location":"plugins/version-source/env/","title":"Environment version source","text":"

    Retrieves the version from an environment variable. This can be useful in build pipelines where the version is set by an external trigger.

    "},{"location":"plugins/version-source/env/#updates","title":"Updates","text":"

    Setting the version is not supported.

    "},{"location":"plugins/version-source/env/#configuration","title":"Configuration","text":"

    The version source plugin name is env.

    pyproject.toml hatch.toml
    [tool.hatch.version]\nsource = \"env\"\n
    [version]\nsource = \"env\"\n
    "},{"location":"plugins/version-source/env/#options","title":"Options","text":"Option Description variable (required) The name of the environment variable"},{"location":"plugins/version-source/reference/","title":"Version source plugins","text":""},{"location":"plugins/version-source/reference/#known-third-party","title":"Known third-party","text":"
    • hatch-vcs - uses your preferred version control system (like Git)
    • hatch-nodejs-version - uses the version field of NodeJS package.json files
    • hatch-regex-commit - automatically creates a Git commit and tag after version bumping
    • versioningit - determines version from Git or Mercurial tags, with customizable version formatting
    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface","title":"VersionSourceInterface","text":"

    Example usage:

    plugin.py hooks.py
    from hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\nclass SpecialVersionSource(VersionSourceInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
    from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionSource\n\n\n@hookimpl\ndef hatch_register_version_source():\n    return SpecialVersionSource\n
    Source code in backend/src/hatchling/version/source/plugin/interface.py
    class VersionSourceInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\n    class SpecialVersionSource(VersionSourceInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialVersionSource\n\n\n    @hookimpl\n    def hatch_register_version_source():\n        return SpecialVersionSource\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree as a string.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.version]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def get_version_data(self) -> dict:\n        \"\"\"\n        This should return a mapping with a `version` key representing the current version of the project and will be\n        displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n        The mapping can contain anything else and will be passed to\n        [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n        when updating the version.\n        \"\"\"\n\n    def set_version(self, version: str, version_data: dict) -> None:\n        \"\"\"\n        This should update the version to the first argument with the data provided during retrieval.\n        \"\"\"\n        raise NotImplementedError\n
    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

    The name used for selection.

    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.root","title":"root: str property","text":"

    The root of the project tree as a string.

    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
    [tool.hatch.version]\n
    [version]\n
    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.get_version_data","title":"get_version_data() -> dict abstractmethod","text":"

    This should return a mapping with a version key representing the current version of the project and will be displayed when invoking the version command without any arguments.

    The mapping can contain anything else and will be passed to set_version when updating the version.

    Source code in backend/src/hatchling/version/source/plugin/interface.py
    @abstractmethod\ndef get_version_data(self) -> dict:\n    \"\"\"\n    This should return a mapping with a `version` key representing the current version of the project and will be\n    displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n    The mapping can contain anything else and will be passed to\n    [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n    when updating the version.\n    \"\"\"\n
    "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version","title":"set_version(version: str, version_data: dict) -> None","text":"

    This should update the version to the first argument with the data provided during retrieval.

    Source code in backend/src/hatchling/version/source/plugin/interface.py
    def set_version(self, version: str, version_data: dict) -> None:\n    \"\"\"\n    This should update the version to the first argument with the data provided during retrieval.\n    \"\"\"\n    raise NotImplementedError\n
    "},{"location":"plugins/version-source/regex/","title":"Regex version source","text":"

    See the documentation for versioning.

    "},{"location":"plugins/version-source/regex/#updates","title":"Updates","text":"

    Setting the version is supported.

    "},{"location":"plugins/version-source/regex/#configuration","title":"Configuration","text":"

    The version source plugin name is regex.

    pyproject.toml hatch.toml
    [tool.hatch.version]\nsource = \"regex\"\n
    [version]\nsource = \"regex\"\n
    "},{"location":"plugins/version-source/regex/#options","title":"Options","text":"Option Description path (required) A relative path to a file containing the project's version pattern A regular expression that has a named group called version that represents the version. The default pattern looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v."},{"location":"tutorials/environment/basic-usage/","title":"Managing environments","text":"

    Hatch environments are isolated workspaces that can be used for project tasks including running tests, building documentation and running code formatters and linters.

    "},{"location":"tutorials/environment/basic-usage/#the-default-environment","title":"The default environment","text":"

    When you start using Hatch, you can create the default environment. To do this use the env create command:

    hatch env create\n

    This will not only create will the default environment for you to work in but will also install your project in dev mode in this default environment.

    Tip

    You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.

    "},{"location":"tutorials/environment/basic-usage/#using-the-default-environment","title":"Using the default environment","text":"

    Hatch will always use the default environment if an environment is not chosen explicitly when running a command.

    For instance, the following shows how to get version information for the Python in use.

    $ hatch run python -V\nPython 3.12.1\n
    "},{"location":"tutorials/environment/basic-usage/#configure-the-default-environment","title":"Configure the default environment","text":"

    You can customize the tools that are installed into the default environment by adding a table called tool.hatch.envs.default to your pyproject.toml file. Below is an example of adding the dependencies pydantic and numpy to the default environment.

    pyproject.toml hatch.toml
    [tool.hatch.envs.default]\ndependencies = [\n  \"pydantic\",\n  \"numpy\",\n]\n
    [envs.default]\ndependencies = [\n  \"pydantic\",\n  \"numpy\",\n]\n

    You can declare versions for your dependencies as well within this configuration.

    pyproject.toml hatch.toml
    [tool.hatch.envs.default]\ndependencies = [\n  \"pydantic>=2.0\",\n  \"numpy\",\n]\n
    [envs.default]\ndependencies = [\n  \"pydantic>=2.0\",\n  \"numpy\",\n]\n
    "},{"location":"tutorials/environment/basic-usage/#create-custom-environment","title":"Create custom environment","text":"

    You can create custom environments in Hatch by adding a section to your pyproject.toml file [tool.hatch.envs.<ENV_NAME>]. Below you define an environment called test and you add the pytest and pytest-cov dependencies to that environment's configuration.

    pyproject.toml hatch.toml
    [tool.hatch.envs.test]\ndependencies = [\n  \"pytest\",\n  \"pytest-cov\"\n]\n
    [envs.test]\ndependencies = [\n  \"pytest\",\n  \"pytest-cov\"\n]\n

    The first time that you call the test environment, Hatch will:

    1. Create the environment
    2. Install your project into that environment in dev mode (by default) along with its dependencies.
    3. Install the environment's dependencies
    "},{"location":"tutorials/environment/basic-usage/#run-commands-within-a-specific-environment","title":"Run commands within a specific environment","text":"

    Hatch offers a unique environment feature that allows you run a specific command within a specific environment rather than needing to activate the environment as you would using a tool such as Conda or venv.

    For instance, if you define an environment called test that contains the dependencies from the previous section, you can run the pytest command from the test environment using the syntax:

    hatch run <ENV_NAME>:command\n

    To access the test environment and run pytest, you can run:

    $ hatch run test:pytest\n============================== test session starts ===============================\nplatform darwin -- Python 3.12.1, pytest-7.4.4, pluggy-1.3.0\nrootdir: /your/path/to/yourproject\ncollected 0 items\n

    Note

    test:pytest represents the name of the environment to call (test) and the command to run (pytest).

    "},{"location":"tutorials/environment/basic-usage/#view-current-environments","title":"View current environments","text":"

    Above you defined and created a new test environment in your pyproject.toml file. You can now use the env show command to see both the currently created environments and the dependencies in each environment.

    $ hatch env show\n             Standalone\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Name    \u2503 Type    \u2503 Dependencies \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 default \u2502 virtual \u2502              \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 test    \u2502 virtual \u2502 pytest       \u2502\n\u2502         \u2502         \u2502 pytest-cov   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n

    Note

    The output may have more columns depending on your environment configuration.

    "},{"location":"tutorials/environment/basic-usage/#locating-environments","title":"Locating environments","text":"

    To see where your current environment is located you can use the env find command.

    $ hatch env find test\n/your/path/Application Support/hatch/env/virtual/yourproject/twO2iQR3/test\n

    Note

    That path is what you would see on macOS but differs for each platform, and is configurable.

    "},{"location":"tutorials/environment/basic-usage/#launching-a-shell-within-a-specific-environment","title":"Launching a shell within a specific environment","text":"

    If you wish to launch a shell for a specific environment that you have created, like the previous test environment, you can use:

    hatch -e test shell\n

    Once the environment is active, you can run commands like you would in any Python environment.

    Notice below that when running pip list in the test environment, you can see:

    1. That you package is installed in editable mode.
    2. That the environment contains both pytest and pytest-cov as specified above in the pyproject.toml file.
    $ pip list\nPackage     Version Editable project location\n----------- ------- ----------------------------------------------------\ncoverage    7.4.1\niniconfig   2.0.0\npackaging   23.2\npip         23.3.1\npluggy      1.4.0\npytest      8.0.0\npytest-cov  4.1.0\nyourproject 0.1.0  /your/path/to/yourproject\n
    "},{"location":"tutorials/environment/basic-usage/#conda-environments","title":"Conda environments","text":"

    If you prefer to use Conda environments with Hatch, you can check out the hatch-conda plugin.

    "},{"location":"blog/archive/2023/","title":"2023","text":""},{"location":"blog/archive/2022/","title":"2022","text":""},{"location":"blog/category/release/","title":"Release","text":""}]} \ No newline at end of file diff --git a/1.9/sitemap.xml b/1.9/sitemap.xml index ccc97a147..8b4ea4bf2 100644 --- a/1.9/sitemap.xml +++ b/1.9/sitemap.xml @@ -145,16 +145,41 @@ 2020-02-02 daily + + https://hatch.pypa.io/1.9/how-to/config/dynamic-metadata/ + 2020-02-02 + daily + https://hatch.pypa.io/1.9/how-to/environment/package-indices/ 2020-02-02 daily + + https://hatch.pypa.io/1.9/how-to/meta/report-issues/ + 2020-02-02 + daily + https://hatch.pypa.io/1.9/how-to/plugins/testing-builds/ 2020-02-02 daily + + https://hatch.pypa.io/1.9/how-to/publish/auth/ + 2020-02-02 + daily + + + https://hatch.pypa.io/1.9/how-to/publish/repo/ + 2020-02-02 + daily + + + https://hatch.pypa.io/1.9/how-to/static-analysis/behavior/ + 2020-02-02 + daily + https://hatch.pypa.io/1.9/meta/authors/ 2020-02-02 @@ -191,7 +216,7 @@ daily - https://hatch.pypa.io/1.9/plugins/builder/app/ + https://hatch.pypa.io/1.9/plugins/builder/binary/ 2020-02-02 daily @@ -290,6 +315,11 @@ 2020-02-02 daily + + https://hatch.pypa.io/1.9/tutorials/environment/basic-usage/ + 2020-02-02 + daily + https://hatch.pypa.io/1.9/blog/archive/2023/ 2020-02-02 diff --git a/1.9/sitemap.xml.gz b/1.9/sitemap.xml.gz index b6f8e3c049fa5f3443ddd9654e7c4ccfe57e5d38..4abbd34024141182b14b56f1e853dc48f9025167 100644 GIT binary patch delta 741 zcmVIw1{g9?t>yxq~iU{d*@bXjL8Q7yxwl=^$NWXjrHyG`sa`D)#Li*@UYL(C8QNM z_UU#_P-Gkf;mIVOQ_!s^0MrH<`~ZnrQ>R#Z$z$Lj%?gd$l-ob*K-> zzmbmFx<(=l{n^IgJM<)xXMG}YP9}|FkO=emPE{i8lSEygkIp6|kv7LMiL{FuM20mN zTCpzv_dB(%Re$|>ZBd=KUu((QFKWx+?T7ZU0PUZ?eG;kF&MG*DOj2LQNG{t-S+6$+McvDYCi(4{k_SvVU}0nL=|0ULu=9xPdE)v&D-< zuCa+i9OTaXJD?MqZkTYXD0~F^!9&NhN^-24#miyZgMNh;E9)DpWk#)8J$5W-%6*7b z*_5(qZ0~YweNwy-jM;KEB~qfn^Og)`G6gWlaUhua_X>MN17{neMDjGR#*aP7EJY^Y z3Eo6*WPi@nT^!CjsUcr0ZcUp|OMw!g7lY^|Lzh{95kp`J<|E2bO8-_mIER``*aE`B=k5kikR6o= zFJfrlHVH~ecJ94Jbn#p%a%5g?ao~Fy5(lg(#&p1)?_gjMpbz3PA3}A~g`U<2N}G X9YXpKANll_kPg2AnLcQym@EJQ8xm`1 delta 673 zcmV;S0$%;|1+N8=8h_$25CG77zXEYj99U`9t|-0r3wA$Xu!q=N$4>1Dl)v9e2;Cs{ zvX|930ud4`JURAcCSmvT(fQR0Q+6>tuQzqGUSZJDxX?bYfBk%|9@j7Xhux5TMp|*> zke}CX4_QFmS5at-nM9_Erb@23E%eyoWJbUV$0Q`J|X`` zIt*Al^s!gMs$A4>!>a_XZNY;K+8wPJawT}g8|Mu;ZNUiox!66PL6_@aciE}0t35;Dg z1Vj^7@pe~!N_Tc zU|)v>1_%Tb`xJkpri!c9-UFfJS0C8k=|zIa;ICjH z8Ijx0`zPVy=3Szi7H|UEWx}+1C-Lgm5$zXsTxZN3tzhp9%1lQ z9=wR5eY@LIN~Uw~EuxF(2cR687ZoFZltC_{hvyu!n*L9MMVd1~Fpx|Uq@ HfG7X}tb9`c diff --git a/1.9/tutorials/environment/basic-usage/index.html b/1.9/tutorials/environment/basic-usage/index.html new file mode 100644 index 000000000..29707a5e5 --- /dev/null +++ b/1.9/tutorials/environment/basic-usage/index.html @@ -0,0 +1,73 @@ + Managing environments - Hatch

    Managing environments


    Hatch environments are isolated workspaces that can be used for project tasks including running tests, building documentation and running code formatters and linters.

    The default environment

    When you start using Hatch, you can create the default environment. To do this use the env create command:

    hatch env create
    +

    This will not only create will the default environment for you to work in but will also install your project in dev mode in this default environment.

    Tip

    You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.

    Using the default environment

    Hatch will always use the default environment if an environment is not chosen explicitly when running a command.

    For instance, the following shows how to get version information for the Python in use.

    $ hatch run python -V
    +Python 3.12.1
    +

    Configure the default environment

    You can customize the tools that are installed into the default environment by adding a table called tool.hatch.envs.default to your pyproject.toml file. Below is an example of adding the dependencies pydantic and numpy to the default environment.

    [tool.hatch.envs.default]
    +dependencies = [
    +  "pydantic",
    +  "numpy",
    +]
    +
    [envs.default]
    +dependencies = [
    +  "pydantic",
    +  "numpy",
    +]
    +

    You can declare versions for your dependencies as well within this configuration.

    [tool.hatch.envs.default]
    +dependencies = [
    +  "pydantic>=2.0",
    +  "numpy",
    +]
    +
    [envs.default]
    +dependencies = [
    +  "pydantic>=2.0",
    +  "numpy",
    +]
    +

    Create custom environment

    You can create custom environments in Hatch by adding a section to your pyproject.toml file [tool.hatch.envs.<ENV_NAME>]. Below you define an environment called test and you add the pytest and pytest-cov dependencies to that environment's configuration.

    [tool.hatch.envs.test]
    +dependencies = [
    +  "pytest",
    +  "pytest-cov"
    +]
    +
    [envs.test]
    +dependencies = [
    +  "pytest",
    +  "pytest-cov"
    +]
    +

    The first time that you call the test environment, Hatch will:

    1. Create the environment
    2. Install your project into that environment in dev mode (by default) along with its dependencies.
    3. Install the environment's dependencies

    Run commands within a specific environment

    Hatch offers a unique environment feature that allows you run a specific command within a specific environment rather than needing to activate the environment as you would using a tool such as Conda or venv.

    For instance, if you define an environment called test that contains the dependencies from the previous section, you can run the pytest command from the test environment using the syntax:

    hatch run <ENV_NAME>:command
    +

    To access the test environment and run pytest, you can run:

    $ hatch run test:pytest
    +============================== test session starts ===============================
    +platform darwin -- Python 3.12.1, pytest-7.4.4, pluggy-1.3.0
    +rootdir: /your/path/to/yourproject
    +collected 0 items
    +

    Note

    test:pytest represents the name of the environment to call (test) and the command to run (pytest).

    View current environments

    Above you defined and created a new test environment in your pyproject.toml file. You can now use the env show command to see both the currently created environments and the dependencies in each environment.

    $ hatch env show
    +             Standalone
    +┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┓
    +┃ Name    ┃ Type    ┃ Dependencies ┃
    +┡━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━┩
    +│ default │ virtual │              │
    +├─────────┼─────────┼──────────────┤
    +│ test    │ virtual │ pytest       │
    +│         │         │ pytest-cov   │
    +└─────────┴─────────┴──────────────┘
    +

    Note

    The output may have more columns depending on your environment configuration.

    Locating environments

    To see where your current environment is located you can use the env find command.

    $ hatch env find test
    +/your/path/Application Support/hatch/env/virtual/yourproject/twO2iQR3/test
    +

    Note

    That path is what you would see on macOS but differs for each platform, and is configurable.

    Launching a shell within a specific environment

    If you wish to launch a shell for a specific environment that you have created, like the previous test environment, you can use:

    hatch -e test shell
    +

    Once the environment is active, you can run commands like you would in any Python environment.

    Notice below that when running pip list in the test environment, you can see:

    1. That you package is installed in editable mode.
    2. That the environment contains both pytest and pytest-cov as specified above in the pyproject.toml file.
    $ pip list
    +Package     Version Editable project location
    +----------- ------- ----------------------------------------------------
    +coverage    7.4.1
    +iniconfig   2.0.0
    +packaging   23.2
    +pip         23.3.1
    +pluggy      1.4.0
    +pytest      8.0.0
    +pytest-cov  4.1.0
    +yourproject 0.1.0  /your/path/to/yourproject
    +

    Conda environments

    If you prefer to use Conda environments with Hatch, you can check out the hatch-conda plugin.

    \ No newline at end of file diff --git a/1.9/version/index.html b/1.9/version/index.html index 77554020b..e53d28844 100644 --- a/1.9/version/index.html +++ b/1.9/version/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Versioning


    Configuration

    When the version is not statically set, configuration is defined in the tool.hatch.version table. The source option determines the source to use for retrieving and updating the version. The regex source is used by default.

    The regex source requires an option path that represents a relative path to a file containing the project's version:

    [tool.hatch.version]
    +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Versioning


    Configuration

    When the version is not statically set, configuration is defined in the tool.hatch.version table. The source option determines the source to use for retrieving and updating the version. The regex source is used by default.

    The regex source requires an option path that represents a relative path to a file containing the project's version:

    [tool.hatch.version]
     path = "src/hatch_demo/__about__.py"
     
    [version]
     path = "src/hatch_demo/__about__.py"
    diff --git a/1.9/why/index.html b/1.9/why/index.html
    index d819a4425..c405e8232 100644
    --- a/1.9/why/index.html
    +++ b/1.9/why/index.html
    @@ -7,4 +7,4 @@
         .gdesc-inner { font-size: 0.75rem; }
         body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
         body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
    -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

    Why Hatch?


    The high level value proposition of Hatch is that if one adopts all functionality then many other tools become unnecessary since there is support for everything one might require. Further, if one chooses to use only specific features then there are still benefits compared to alternatives.

    Build backend

    Hatchling, the build backend sister project, has many benefits compared to setuptools. Here we only compare setuptools as that is the one most people are familiar with.

    • Better defaults: The default behavior for setuptools is often not desirable for the average user.
      • For source distributions, setuptools has a custom enumeration of files that get included and excluded by default. Hatchling takes the defaults from your version control system such as Git's .gitignore file.
      • For wheels, setuptools attempts to find every directory that looks like a Python package. This is often undesirable as you might ship files to the end-user unintentionally such as test or tooling directories. Hatchling defaults to very specific inclusion based on the project name and errors if no heuristic is satisfied.
    • Ease of configurability: Hatchling was designed based on a history of significant challenges when configuring setuptools.
      • Hatchling uses the same glob pattern syntax as Git itself for every option which is what most users are familiar with. On the other hand, setuptools uses shell-style glob patterns for source distributions while wheels use a mix of shell-style globs and Python package syntax.
      • Configuring what gets included in source distributions requires a separate MANIFEST.in file. The custom syntax and directives must be learned and it is difficult knowing which options in the main files like setup.py influence the behavior and under what conditions. For Hatchling, everything gets configured in a single file under dedicated sections for specific targets like [tool.hatch.build.targets.wheel].
      • By default, non-Python files are excluded from wheels. Including such files requires usually verbose rules for every nested package directory. Hatchling makes no such distinction between file types and acts more like a general build system one might already be familiar with.
    • Editable installations: The default behavior of Hatchling allows for proper static analysis by external tools such as IDEs. With setuptools, you must provide additional configuration which means that by default, for example, you would not get autocompletion in Visual Studio Code. This is marked as a legacy feature and may in fact be removed in future versions of setuptools.
    • Reproducibility: Hatchling builds reproducible wheels and source distributions by default. setuptools does not support this for source distributions and there is no guarantee that wheels are reproducible.
    • Extensibility: Although it is possible to extend setuptools, the API is quite low level. Hatchling has the concept of plugins that are separated into discrete types and only expose what is necessary, leading to an easier developer experience.

    Why not?:

    If building extension modules is required then it is recommended that you continue using setuptools, or even other backends that specialize in interfacing with compilers.

    Environment management

    Here we compare to both tox and nox. At a high level, there are a few common advantages:

    • Python management: Hatch is able to automatically download Python distributions on the fly when specific versions that environments request cannot be found. The alternatives will raise an error, with the option to ignore unknown distributions.
    • Philosophy: In the alternatives, environments are for the most part treated as executable units where a dependency set is associated with an action. If you are familiar with container ecosystems, this would be like defining a CMD at the end of a Dockerfile but without the ability to change the action at runtime. This involves significant wasted disk space usually because one often requires slight modifications to the actions and therefore will define entirely different environments inherited from a base config just to perform different logic. Additionally, this can be confusing to users not just configuration-wise but also for execution of the different environments.

      In Hatch, environments are treated as isolated areas where you can execute arbitrary commands at runtime. For example, you can define a single test environment with named scripts that runs unit vs non-unit tests, each command being potentially very long but named however you wish so you get to control the interface. Since environments are treated as places where work is performed, you can also spawn a shell into any which will execute a subprocess that automatically drops into your shell of choice. Your shell will be configured appropriately like python on PATH being updated and the prompt being changed to reflect the chosen environment.

    • Configuration:

      • tox only supports INI configuration and if one desires putting that in the standard pyproject.toml file then it must be a multi-line string containing the INI config which would preclude syntax highlighting. Hatch allows for TOML-based config just like most other tools in the Python ecosystem.
      • nox config is defined in Python which often leads to increased verbosity and makes it challenging to onboard folks compared to a standardized format with known behaviors.
    • Extensibility:
      • tox allows for extending most aspects of its functionality however the API is so low-level and attached to internals that creating plugins may be challenging. For example, here is a tox plugin that was migrated to an equivalent Hatch environment collector plugin.
      • nox is configured with Python so for the local project you can do whatever you want, however there is no concept of third-party plugins per se. To achieve that, you must usually use a package that wraps nox and use that package's imports instead (example).

    Why not?:

    If you are using nox and you wish to migrate, and for some reason you notify sessions, then migration wouldn't be a straight translation but rather you might have to redesign that conditional step.

    Python management

    Here we compare Python management to that of pyenv.

    • Cross-platform: Hatch allows for the same experience no matter the system whereas pyenv does not support Windows so you must use an entirely different project that tries to emulate the functionality.
    • No build dependencies: Hatch guarantees that every available distribution is prebuilt whereas the alternative requires one to maintain a precise build environment which differs by platform and potentially Python version. Another benefit to this is extremely fast installations since the distributions are simply downloaded and unpacked.
    • Optimized by default: The CPython distributions are built with profile guided optimization and link-time optimization, resulting in a 10-30% performance improvement depending on the workload. These distributions have seen wide adoption throughout the industry and are even used by the build system Bazel.
    • Simplicity: Hatch treats Python installations as just another directory that one would add to PATH. It can do this for you or you can manage PATH yourself, even allowing for custom install locations. On the other hand, pyenv operates by adding shims which then act as wrappers around the actual underlying binaries. This has many unfortunate side effects:
      • It is incumbent upon the user to manage which specific Python comes first via the CLI, switch when necessary, and/or have a mental model of which versions are exposed globally and locally per-project. This can become confusing quite quickly. When working with Hatch, your global Python installations are only important insofar as they are on PATH somewhere since environments do not use them directly but rather create virtual environments from them, always using a version that is compatible with your project.
      • Configuration is required for each shell to properly set up pyenv on start, leading to inconsistencies when running processes that do not spawn a shell.
      • Debugging issues with Python search paths can be extremely difficult, especially for users of software. If you or users have ever ran into an issue where code was being executed that you did not anticipate, the issue is almost always pyenv influencing the python on PATH.

    Why not?:

    Currently, Hatch does not allow for the installation of specific patch release versions but rather only uses minor release granularity that tracks the latest patch release. If specific patch releases are important to you then it is best to use an alternative installation mechanism.

    \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

    Why Hatch?


    The high level value proposition of Hatch is that if one adopts all functionality then many other tools become unnecessary since there is support for everything one might require. Further, if one chooses to use only specific features then there are still benefits compared to alternatives.

    Build backend

    Hatchling, the build backend sister project, has many benefits compared to setuptools. Here we only compare setuptools as that is the one most people are familiar with.

    • Better defaults: The default behavior for setuptools is often not desirable for the average user.
      • For source distributions, setuptools has a custom enumeration of files that get included and excluded by default. Hatchling takes the defaults from your version control system such as Git's .gitignore file.
      • For wheels, setuptools attempts to find every directory that looks like a Python package. This is often undesirable as you might ship files to the end-user unintentionally such as test or tooling directories. Hatchling defaults to very specific inclusion based on the project name and errors if no heuristic is satisfied.
    • Ease of configurability: Hatchling was designed based on a history of significant challenges when configuring setuptools.
      • Hatchling uses the same glob pattern syntax as Git itself for every option which is what most users are familiar with. On the other hand, setuptools uses shell-style glob patterns for source distributions while wheels use a mix of shell-style globs and Python package syntax.
      • Configuring what gets included in source distributions requires a separate MANIFEST.in file. The custom syntax and directives must be learned and it is difficult knowing which options in the main files like setup.py influence the behavior and under what conditions. For Hatchling, everything gets configured in a single file under dedicated sections for specific targets like [tool.hatch.build.targets.wheel].
      • By default, non-Python files are excluded from wheels. Including such files requires usually verbose rules for every nested package directory. Hatchling makes no such distinction between file types and acts more like a general build system one might already be familiar with.
    • Editable installations: The default behavior of Hatchling allows for proper static analysis by external tools such as IDEs. With setuptools, you must provide additional configuration which means that by default, for example, you would not get autocompletion in Visual Studio Code. This is marked as a legacy feature and may in fact be removed in future versions of setuptools.
    • Reproducibility: Hatchling builds reproducible wheels and source distributions by default. setuptools does not support this for source distributions and there is no guarantee that wheels are reproducible.
    • Extensibility: Although it is possible to extend setuptools, the API is quite low level. Hatchling has the concept of plugins that are separated into discrete types and only expose what is necessary, leading to an easier developer experience.

    Why not?:

    If building extension modules is required then it is recommended that you continue using setuptools, or even other backends that specialize in interfacing with compilers.

    Environment management

    Here we compare to both tox and nox. At a high level, there are a few common advantages:

    • Python management: Hatch is able to automatically download Python distributions on the fly when specific versions that environments request cannot be found. The alternatives will raise an error, with the option to ignore unknown distributions.
    • Philosophy: In the alternatives, environments are for the most part treated as executable units where a dependency set is associated with an action. If you are familiar with container ecosystems, this would be like defining a CMD at the end of a Dockerfile but without the ability to change the action at runtime. This involves significant wasted disk space usually because one often requires slight modifications to the actions and therefore will define entirely different environments inherited from a base config just to perform different logic. Additionally, this can be confusing to users not just configuration-wise but also for execution of the different environments.

      In Hatch, environments are treated as isolated areas where you can execute arbitrary commands at runtime. For example, you can define a single test environment with named scripts that runs unit vs non-unit tests, each command being potentially very long but named however you wish so you get to control the interface. Since environments are treated as places where work is performed, you can also spawn a shell into any which will execute a subprocess that automatically drops into your shell of choice. Your shell will be configured appropriately like python on PATH being updated and the prompt being changed to reflect the chosen environment.

    • Configuration:

      • tox only supports INI configuration and if one desires putting that in the standard pyproject.toml file then it must be a multi-line string containing the INI config which would preclude syntax highlighting. Hatch allows for TOML-based config just like most other tools in the Python ecosystem.
      • nox config is defined in Python which often leads to increased verbosity and makes it challenging to onboard folks compared to a standardized format with known behaviors.
    • Extensibility:
      • tox allows for extending most aspects of its functionality however the API is so low-level and attached to internals that creating plugins may be challenging. For example, here is a tox plugin that was migrated to an equivalent Hatch environment collector plugin.
      • nox is configured with Python so for the local project you can do whatever you want, however there is no concept of third-party plugins per se. To achieve that, you must usually use a package that wraps nox and use that package's imports instead (example).

    Why not?:

    If you are using nox and you wish to migrate, and for some reason you notify sessions, then migration wouldn't be a straight translation but rather you might have to redesign that conditional step.

    Python management

    Here we compare Python management to that of pyenv.

    • Cross-platform: Hatch allows for the same experience no matter the system whereas pyenv does not support Windows so you must use an entirely different project that tries to emulate the functionality.
    • No build dependencies: Hatch guarantees that every available distribution is prebuilt whereas the alternative requires one to maintain a precise build environment which differs by platform and potentially Python version. Another benefit to this is extremely fast installations since the distributions are simply downloaded and unpacked.
    • Optimized by default: The CPython distributions are built with profile guided optimization and link-time optimization, resulting in a 10-30% performance improvement depending on the workload. These distributions have seen wide adoption throughout the industry and are even used by the build system Bazel.
    • Simplicity: Hatch treats Python installations as just another directory that one would add to PATH. It can do this for you or you can manage PATH yourself, even allowing for custom install locations. On the other hand, pyenv operates by adding shims which then act as wrappers around the actual underlying binaries. This has many unfortunate side effects:
      • It is incumbent upon the user to manage which specific Python comes first via the CLI, switch when necessary, and/or have a mental model of which versions are exposed globally and locally per-project. This can become confusing quite quickly. When working with Hatch, your global Python installations are only important insofar as they are on PATH somewhere since environments do not use them directly but rather create virtual environments from them, always using a version that is compatible with your project.
      • Configuration is required for each shell to properly set up pyenv on start, leading to inconsistencies when running processes that do not spawn a shell.
      • Debugging issues with Python search paths can be extremely difficult, especially for users of software. If you or users have ever ran into an issue where code was being executed that you did not anticipate, the issue is almost always pyenv influencing the python on PATH.

    Why not?:

    Currently, Hatch does not allow for the installation of specific patch release versions but rather only uses minor release granularity that tracks the latest patch release. If specific patch releases are important to you then it is best to use an alternative installation mechanism.

    \ No newline at end of file diff --git a/latest/404.html b/latest/404.html index 1f63cdd52..7d42c48de 100644 --- a/latest/404.html +++ b/latest/404.html @@ -1 +1 @@ - Hatch

    404 - Not found

    \ No newline at end of file + Hatch

    404 - Not found

    \ No newline at end of file diff --git a/latest/assets/images/social/community/highlights.png b/latest/assets/images/social/community/highlights.png index 9e70dacdcb2a98374d1b527d9ebc2f14fb86c1db..48ad26a6d8e31668c3a4aa8845dc9f2115fce517 100644 GIT binary patch literal 41461 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 A&;S4c literal 33969 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 U%q_kwqhCK&Wvxe*icjDCKZ|Vi^Z)<= literal 0 HcmV?d00001 diff --git a/latest/assets/images/social/how-to/meta/report-issues.png b/latest/assets/images/social/how-to/meta/report-issues.png new file mode 100644 index 0000000000000000000000000000000000000000..7f2ada32e06f404c529c073b3c3b5f042b2341fa GIT binary patch literal 37808 zcmeFZcUM!}_dRSw6a_34rCv2i2L%D?DguVyLJ3Wz69K8AqavUpAdw=yw}cRS3suAj zNKc5AfPl1w4xyLlaP@w^Z{Yd!mob1d7?88}I(x4&=UjQGqoqnu$3}PJ#0h%vlgD}| zPMj$@apIKsxwF7;v>*7JojCCc4u1U5z$aya zx+8H)=+D(>wv#M>t~4S~T=;X9r}F>a?*IAj-@Wkv`$pM|SvnD*I-YjfZ>O}hGD_I8 z+_GA+X8#=Z+`sqRzkccI!BQOV8&bRHEfmM)XBQb{{;|)7wCBp1)jo9v#_501fZqKT z5gWg7^WXo-oAs83Kx2_>2%)$*8)W@GbrJg*A!MvF1c?-iZwfBqh&o|XbXX?+XnG|& zzKtvYWyTqru!>Kl%kDYcXEnl3bgJ@vr6IQ(@e*a?%TPK-V`aboTC-yR+Z!U_dc-zu zk1+xt8Z!TO{?uvWYwY~3jhA1h7*ljoo{4GDw8aW6j5pmD_s#PA0r`xK7y1V-xd%Hiv41(DkxW%F2oYQaaexi?>V>N=O0CXNLA#M zwT=?#h=4_nEP6+>NvK(W`_T9KuJt|l-%ofzAbiS}kDNrhJXiFn3%rX+8~l5A7SJ`Y@e zhlaU8q09%mbLV>B@un4A7q@d5u5f(+{yn1YS>et{P(+)aV7<(*<{hQz@bGZh*SDA1 z6as3Bu}d<(a$L@&I>>nNQA6X=p+DLjYdCF7qej}y)vG?x?pqCs?cK3y14R`QZbvEn zjaC^JJfYawI;yj6?m_8ZKu?;ygvX4Axz9xC`>3e+wr4Q}C|qs4<>6o^1ARH$UZZ_a z8hNY%>ryv=+t$WrZoNm5h+S?(;qeC33+CA=4KOCQm>jJJ5rgO0QpCBkD3vqDs!y86 zVr1+zUWaW&8)_K5eDsJzK+r=#9%TTN{5^+F*Nclc(aRq*?a?-vjiN4p>qUEfo(Z_C zi7DPhcEz-o4*%l#+WzjIA<*1VrIZ%ZFlU(r1*b-Ev#0*&S-@&nphk_foJ zH&e-L#JPGt=aUwq%MRxGbs+OrDFZ_egX*(qSuQmbXU#pjBz708$2XR+%VeTuFhuvz z#o284?U(GjLVZjGbLyQe;9U&Y@*!h^HdSu>Upe}J0kC9rvy7|pF z#%B5b_Ofj%dzWjwKM$H1S>V-Qovec5lwNbvo%b#WwXYDVUML4}y04K>r`Og`P#?4RjMrv4D`nafWP(tGIgeo*uf z`|OG;3YS5d=DtRnBz}u&DLZiHlazVTBY&@MY=x|2h*C~SA(<1+`mxHzfdu6S&w;o= z${VBbGUJ?qe4hESWZKT;`PK%k>RddG7Egy^AY{X8TpFsH`b172dwy64qWr3=Xggn0 zIM^(gXNQiFk$5XwF00mKmRvIxg@SDM>L43whS*Ju8cM4^kV)8Ti$E$QaA!Ip>5kQF z5WlR)JHvf`cH&VZTZ9~(!p)EgzX+%e!_u$XNXccNo0?Ut20L2bDMlDY+Uld$lNP#VUyf$8X0OB z?j%qlQ=<`xW8Z7Mar*4VUQ^eG+}ZSCi@SI4B9Q`ws!EIl=?m7tBxV`Hen&L#lH_Eg z=~)W!RsF;?bvWDs-}@7aQ&UT=nD8W zhMk9HApRR7I#+QZypyY?cOsX+n>pH=B|@2KKAf)=JR{oGpUe#s6h|2>UJdcu*^!qB zG6+D6v8MECD()i&e_M~lreKKUBgo&JG<0+&u#FO9(w%b5DTeEd5`M-hdINCDA+F

    ^+i|Y~+c?31dmOBUFS>X^%yzya>FNv3 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

      i!jc?~!&jwjzN1YQfd}jz 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 literal 0 HcmV?d00001 diff --git a/latest/assets/images/social/how-to/publish/auth.png b/latest/assets/images/social/how-to/publish/auth.png new file mode 100644 index 0000000000000000000000000000000000000000..fe37a49598bf809681b953f9fc81278f59447b7c GIT binary patch literal 38429 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

      `XO!2OwbLN@`S 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 Aq5uE@ literal 0 HcmV?d00001 diff --git a/latest/assets/images/social/how-to/static-analysis/behavior.png b/latest/assets/images/social/how-to/static-analysis/behavior.png new file mode 100644 index 0000000000000000000000000000000000000000..9e5ca8aa30aadb503c49ae4a9e0b0c07b2da962a GIT binary patch literal 42416 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

      Zik*MgMqUWEv-v9N|-{kO1g`rggUuxJOD>++ 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 D^E6#X literal 0 HcmV?d00001 diff --git a/latest/assets/images/social/plugins/builder/app.png b/latest/assets/images/social/plugins/builder/app.png deleted file mode 100644 index 8f5fd45740da6e5879d422c68dc22a21bbdcb81d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37264 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 >y?_1nD-6R( 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 Dp#B+AR00&kMkxpq{vi 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 literal 0 HcmV?d00001 diff --git a/latest/assets/images/social/tutorials/environment/basic-usage.png b/latest/assets/images/social/tutorials/environment/basic-usage.png new file mode 100644 index 0000000000000000000000000000000000000000..018a6cc2c5ca4871e47dbbac1659fe88c0d16b1d GIT binary patch literal 38785 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 A9smFU literal 0 HcmV?d00001 diff --git a/latest/blog/2022/10/08/hatch-v160/index.html b/latest/blog/2022/10/08/hatch-v160/index.html index b0089c3b2..2c833d07b 100644 --- a/latest/blog/2022/10/08/hatch-v160/index.html +++ b/latest/blog/2022/10/08/hatch-v160/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Hatch v1.6.0

      Hatch v1.6.0 brings improvements to build environments, better handling of dynamic metadata, and support for tools like Visual Studio Code.

      Build environments

      Originally, the environment interface method for providing builder sub-environments was intended to be used in conjunction with some cleanup logic in order to provide a fresh setup every time. However, this is unnecessary in practice because build dependencies rarely change.

      Without caching, repeat build environment use is slow which affects the following scenarios:

      Now a new environment interface method build_environment_exists is used by Hatch to determine whether or not it has already been created, for implementations that have a caching mechanism.

      The virtual environment type now uses this method to cache build environments.

      Project metadata

      Dynamically defined metadata is now supported everywhere, thanks to the new caching of virtual build environments.

      A project metadata command is introduced that displays the fully resolved metadata. The output format is JSON unless a field is specified as an argument.

      For example, if you checkout a project that is built by Hatch, like FastAPI, and run:

      hatch project metadata readme
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Hatch v1.6.0

      Hatch v1.6.0 brings improvements to build environments, better handling of dynamic metadata, and support for tools like Visual Studio Code.

      Build environments

      Originally, the environment interface method for providing builder sub-environments was intended to be used in conjunction with some cleanup logic in order to provide a fresh setup every time. However, this is unnecessary in practice because build dependencies rarely change.

      Without caching, repeat build environment use is slow which affects the following scenarios:

      Now a new environment interface method build_environment_exists is used by Hatch to determine whether or not it has already been created, for implementations that have a caching mechanism.

      The virtual environment type now uses this method to cache build environments.

      Project metadata

      Dynamically defined metadata is now supported everywhere, thanks to the new caching of virtual build environments.

      A project metadata command is introduced that displays the fully resolved metadata. The output format is JSON unless a field is specified as an argument.

      For example, if you checkout a project that is built by Hatch, like FastAPI, and run:

      hatch project metadata readme
       

      only the readme text will be displayed. If the content is in Markdown, then Rich will render it directly in your terminal:

      FastAPI readme

      Virtual environment location

      The virtual environment type now uses a flat layout for storage in the configured virtual environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory.

      For example, if you define the following Hatch configuration:

      [dirs.env]
       virtual = ".hatch"
       

      and the following matrix:

      [[tool.hatch.envs.test.matrix]]
      diff --git a/latest/blog/2023/12/11/hatch-v180/index.html b/latest/blog/2023/12/11/hatch-v180/index.html
      index 5b4b2de57..ccabfedfa 100644
      --- a/latest/blog/2023/12/11/hatch-v180/index.html
      +++ b/latest/blog/2023/12/11/hatch-v180/index.html
      @@ -7,4 +7,4 @@
           .gdesc-inner { font-size: 0.75rem; }
           body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
           body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
      -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Hatch v1.8.0

      Hatch v1.8.0 brings Python distribution management, static analysis and formatting backed by Ruff, and binaries for every platform.

      Installation made easy

      One thing that has been a perpetual problem for Hatch and other Python applications is that Python itself is a dependency. You, and more importantly your users, need to in some way get Python before your software can even be used. The recommended way to go about that is platform-dependent and even differs based on your target audience. I viewed this as a central UX problem for Hatch and so severe that I took a bit of a hiatus to solve it.

      Luckily, I have to my satisfaction solved this problem in the form of PyApp. It is a runtime installer for Python projects written in Rust. Apps are distributed as standalone executables as users have come to expect and bootstrapping occurs upon the first invocation. Here is an example of what you would see the first time you run a binary from this release:

      Installation example

      Now that we have binaries, creating installers for different platforms becomes trivial. Starting with this release not only are binaries available for every platform but also we have installers for Windows and macOS. The installer for macOS is signed using a certificate from the same account used to sign the official distributions from https://www.python.org, so users will not get any security pop-ups. Shout out to @ewdurbin for their extreme generosity in setting up multiple certificates in their free time!

      These installers and binaries are now the recommended way to install and update Hatch. These binaries have built-in management so you can update to the latest version by running hatch self update.

      Windows signing

      In future we will sign the installers for Windows but I did not have time to look into how that works. macOS signing took way longer than I anticipated 😅

      Python management

      For a long time I and other users have desired that Hatch gain the ability to manage Python distributions. In my mind this was always blocked on a better installation experience because there was sort of a chicken-or-egg problem where you want a Python manager but you first need Python. No longer is that the case!

      The new python command group allows for easy installation of various distributions to arbitrary locations which are then added to your PATH by default. Hatch supports CPython and PyPy distributions:

      Available Python distributions

      Virtual environment Python resolution

      The virtual environment type is now far more intelligent when resolving the parent distribution to use and guarantees that, when no specific version is requested, the resolved distribution will always be compatible with the project.

      Additionally, when a requested version cannot be found on PATH it will automatically be downloaded and managed internally.

      Static analysis

      There is a new fmt command, backed entirely by Ruff, that checks and fixes your code for formatting and linting issues.

      Starting with this release, Hatch maintains default settings that are guaranteed to be up-to-date and represent best practices for programming in modern Python. The idea is to provide defaults that are so broadly applicable that the majority of users will maintain little if any of their own overrides.

      The default behavior is internal management of settings to provide an OOTB experience that works. It is recommended however that you persist the default config file in version control so that other tools like IDEs can utilize your full configuration.

      Since Ruff is now provided as a built-in feature, new project templates no longer have such configuration and are much less verbose.

      Build improvements

      Building projects that do not use Hatchling as a backend is now supported and such builds are managed with the standard build tool.

      The bridge between Hatch and the Hatchling CLI has been removed. Previously, the builder would send serialized messages to Hatch that would contain the desired content and style for each line of output. This was done in an effort to allow builder and build hook plugins to output pretty messages without actually requiring a dependency like Rich. A problem that arises with this is that builders that invoke subprocesses will not display ANSI codes as one might expect and will lose out on the interactive experience of such invocations, like the built-in app builder plugin calling cargo build. So now everything is simpler at the expense of no colored output without manual logic, or adding a dependency if you're a third-party plugin.

      Faster environment usage

      Spawning a shell or running commands within environments always first checks that your project's dependencies are satisfied and if not synchronizes the environment with what is defined. Previously, this had the potential to be quite slow for projects that have many dependencies.

      Now the set of dependency definitions is hashed and no check is performed if the hash is the same as before, significantly speeding up environment usage in most cases.

      Hatchling

      Hatch now depends on Hatchling v1.19.0, which was also just released.

      Better defaults

      Hatchling is all about providing the best possible defaults, even at the expense of backward compatibility. In this release, there are two breaking changes that provide a much better user experience and were in fact requested by users.

      • Both the force-include option and the force_include_editable wheel build data setting now raise errors if source paths do not exist.
      • The wheel build target now raises an error when no file inclusion options have been defined and none of its heuristics to determine what to ship are satisfied.

      App build target

      A new app build target is now stable that allows for the building of standalone binaries for projects. This is what Hatch itself uses for its binaries.

      Meta

      Why Hatch?

      A new page has been introduced that discusses the value proposition of Hatch and Hatchling in comparison to alternatives. Currently, it only addresses a few features but in future this page will become more comprehensive.

      Future

      Upcoming features include a test command, commands to manage dependencies, and workspaces functionality similar to Cargo that will make managing monorepos far easier.

      Next year there will be two large efforts that you should expect to see:

      1. A significant amount of my free time (and some at work) will be devoted to introducing lock file functionality in Hatch and trying to get whatever that happens to be standardized.

        I met with @brettcannon about his thoughts post-PEP 665 and about mousebender. I also met with the prefix.dev team about rip and was fortunate enough to be shown a demo before its official announcement.

        At the moment, the two options I see are to either go all in and contribute to mousebender or rely on the Prefix folks and use rip. The latter has the benefit of potentially supporting Conda as a side effect with the downside of being quite new with the spec firmly out of our control. The former has the benefit of being able to easily gain institutional support from the Python packaging team and each of our employers with the downside being a significant amount of work needing to be done.

      2. When @henryiii is able to get some free time away from teaching I plan to work with him once again and push very hard for the Python build ecosystem to adopt the extensionlib approach.

        I am of the opinion that the Python community has not fully completed the expressed outcome of PEP 517 in that build backends are still (for the most part) reliant on setuptools for building non-Python code bases.

        Basically, there are components that interact with compilers to produce extension modules and components that pack files into an archive which we call a build backend. These are two distinct pieces of functionality and my view is that there should be an API that allows backends to consume extension module builders to find out where things got created and where they should be shipped inside archives.

        In this hypothetical future any build backend would be able to trigger the building of extension modules based on user configuration.

      Support

      If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!

      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Hatch v1.8.0

      Hatch v1.8.0 brings Python distribution management, static analysis and formatting backed by Ruff, and binaries for every platform.

      Installation made easy

      One thing that has been a perpetual problem for Hatch and other Python applications is that Python itself is a dependency. You, and more importantly your users, need to in some way get Python before your software can even be used. The recommended way to go about that is platform-dependent and even differs based on your target audience. I viewed this as a central UX problem for Hatch and so severe that I took a bit of a hiatus to solve it.

      Luckily, I have to my satisfaction solved this problem in the form of PyApp. It is a runtime installer for Python projects written in Rust. Apps are distributed as standalone executables as users have come to expect and bootstrapping occurs upon the first invocation. Here is an example of what you would see the first time you run a binary from this release:

      Installation example

      Now that we have binaries, creating installers for different platforms becomes trivial. Starting with this release not only are binaries available for every platform but also we have installers for Windows and macOS. The installer for macOS is signed using a certificate from the same account used to sign the official distributions from https://www.python.org, so users will not get any security pop-ups. Shout out to @ewdurbin for their extreme generosity in setting up multiple certificates in their free time!

      These installers and binaries are now the recommended way to install and update Hatch. These binaries have built-in management so you can update to the latest version by running hatch self update.

      Windows signing

      In future we will sign the installers for Windows but I did not have time to look into how that works. macOS signing took way longer than I anticipated 😅

      Python management

      For a long time I and other users have desired that Hatch gain the ability to manage Python distributions. In my mind this was always blocked on a better installation experience because there was sort of a chicken-or-egg problem where you want a Python manager but you first need Python. No longer is that the case!

      The new python command group allows for easy installation of various distributions to arbitrary locations which are then added to your PATH by default. Hatch supports CPython and PyPy distributions:

      Available Python distributions

      Virtual environment Python resolution

      The virtual environment type is now far more intelligent when resolving the parent distribution to use and guarantees that, when no specific version is requested, the resolved distribution will always be compatible with the project.

      Additionally, when a requested version cannot be found on PATH it will automatically be downloaded and managed internally.

      Static analysis

      There is a new fmt command, backed entirely by Ruff, that checks and fixes your code for formatting and linting issues.

      Starting with this release, Hatch maintains default settings that are guaranteed to be up-to-date and represent best practices for programming in modern Python. The idea is to provide defaults that are so broadly applicable that the majority of users will maintain little if any of their own overrides.

      The default behavior is internal management of settings to provide an OOTB experience that works. It is recommended however that you persist the default config file in version control so that other tools like IDEs can utilize your full configuration.

      Since Ruff is now provided as a built-in feature, new project templates no longer have such configuration and are much less verbose.

      Build improvements

      Building projects that do not use Hatchling as a backend is now supported and such builds are managed with the standard build tool.

      The bridge between Hatch and the Hatchling CLI has been removed. Previously, the builder would send serialized messages to Hatch that would contain the desired content and style for each line of output. This was done in an effort to allow builder and build hook plugins to output pretty messages without actually requiring a dependency like Rich. A problem that arises with this is that builders that invoke subprocesses will not display ANSI codes as one might expect and will lose out on the interactive experience of such invocations, like the built-in binary builder plugin calling cargo build. So now everything is simpler at the expense of no colored output without manual logic, or adding a dependency if you're a third-party plugin.

      Faster environment usage

      Spawning a shell or running commands within environments always first checks that your project's dependencies are satisfied and if not synchronizes the environment with what is defined. Previously, this had the potential to be quite slow for projects that have many dependencies.

      Now the set of dependency definitions is hashed and no check is performed if the hash is the same as before, significantly speeding up environment usage in most cases.

      Hatchling

      Hatch now depends on Hatchling v1.19.0, which was also just released.

      Better defaults

      Hatchling is all about providing the best possible defaults, even at the expense of backward compatibility. In this release, there are two breaking changes that provide a much better user experience and were in fact requested by users.

      • Both the force-include option and the force_include_editable wheel build data setting now raise errors if source paths do not exist.
      • The wheel build target now raises an error when no file inclusion options have been defined and none of its heuristics to determine what to ship are satisfied.

      Binary build target

      A new binary build target is now stable that allows for the building of standalone binaries for projects. This is what Hatch itself uses for its binaries.

      Meta

      Why Hatch?

      A new page has been introduced that discusses the value proposition of Hatch and Hatchling in comparison to alternatives. Currently, it only addresses a few features but in future this page will become more comprehensive.

      Future

      Upcoming features include a test command, commands to manage dependencies, and workspaces functionality similar to Cargo that will make managing monorepos far easier.

      Next year there will be two large efforts that you should expect to see:

      1. A significant amount of my free time (and some at work) will be devoted to introducing lock file functionality in Hatch and trying to get whatever that happens to be standardized.

        I met with @brettcannon about his thoughts post-PEP 665 and about mousebender. I also met with the prefix.dev team about rip and was fortunate enough to be shown a demo before its official announcement.

        At the moment, the two options I see are to either go all in and contribute to mousebender or rely on the Prefix folks and use rip. The latter has the benefit of potentially supporting Conda as a side effect with the downside of being quite new with the spec firmly out of our control. The former has the benefit of being able to easily gain institutional support from the Python packaging team and each of our employers with the downside being a significant amount of work needing to be done.

      2. When @henryiii is able to get some free time away from teaching I plan to work with him once again and push very hard for the Python build ecosystem to adopt the extensionlib approach.

        I am of the opinion that the Python community has not fully completed the expressed outcome of PEP 517 in that build backends are still (for the most part) reliant on setuptools for building non-Python code bases.

        Basically, there are components that interact with compilers to produce extension modules and components that pack files into an archive which we call a build backend. These are two distinct pieces of functionality and my view is that there should be an API that allows backends to consume extension module builders to find out where things got created and where they should be shipped inside archives.

        In this hypothetical future any build backend would be able to trigger the building of extension modules based on user configuration.

      Support

      If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!

      \ No newline at end of file diff --git a/latest/blog/2023/12/18/hatch-v190/index.html b/latest/blog/2023/12/18/hatch-v190/index.html index 04b9e0f9d..fed2e3e79 100644 --- a/latest/blog/2023/12/18/hatch-v190/index.html +++ b/latest/blog/2023/12/18/hatch-v190/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Hatch v1.9.0

      Hatch v1.9.0 brings improvements to static analysis and important bug fixes.

      Static analysis

      The default version of Ruff has been increased to v0.1.8. This release brings formatting capabilities to docstrings and Hatch enables this by default with line length set to 80. This length was chosen as the default because it plays nicely with the rendering of the most popular themes for Python documentation, such as Material for MkDocs and Furo.

      Additionally, it is now possible for projects to pin to specific versions of Ruff for upgrading at a later time:

      [tool.hatch.envs.hatch-static-analysis]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Hatch v1.9.0

      Hatch v1.9.0 brings improvements to static analysis and important bug fixes.

      Static analysis

      The default version of Ruff has been increased to v0.1.8. This release brings formatting capabilities to docstrings and Hatch enables this by default with line length set to 80. This length was chosen as the default because it plays nicely with the rendering of the most popular themes for Python documentation, such as Material for MkDocs and Furo.

      Additionally, it is now possible for projects to pin to specific versions of Ruff for upgrading at a later time:

      [tool.hatch.envs.hatch-static-analysis]
       dependencies = ["ruff==X.Y.Z"]
       
      [envs.hatch-static-analysis]
       dependencies = ["ruff==X.Y.Z"]
      diff --git a/latest/blog/archive/2022/index.html b/latest/blog/archive/2022/index.html
      index c58a2a8bd..6842b953b 100644
      --- a/latest/blog/archive/2022/index.html
      +++ b/latest/blog/archive/2022/index.html
      @@ -7,4 +7,4 @@
           .gdesc-inner { font-size: 0.75rem; }
           body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
           body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
      -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      2022

      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      2022

      \ No newline at end of file diff --git a/latest/blog/archive/2023/index.html b/latest/blog/archive/2023/index.html index fcec05e24..1e32ce997 100644 --- a/latest/blog/archive/2023/index.html +++ b/latest/blog/archive/2023/index.html @@ -7,4 +7,4 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      2023

      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      2023

      \ No newline at end of file diff --git a/latest/blog/category/release/index.html b/latest/blog/category/release/index.html index 01977bf03..397d658ed 100644 --- a/latest/blog/category/release/index.html +++ b/latest/blog/category/release/index.html @@ -7,4 +7,4 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Release

      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Release

      \ No newline at end of file diff --git a/latest/blog/index.html b/latest/blog/index.html index 85c3fa458..d4c81c7a2 100644 --- a/latest/blog/index.html +++ b/latest/blog/index.html @@ -7,4 +7,4 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Blog

      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Blog

      \ No newline at end of file diff --git a/latest/build/index.html b/latest/build/index.html index bf0501711..4079b781a 100644 --- a/latest/build/index.html +++ b/latest/build/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Builds


      Configuration

      Builds are configured using the tool.hatch.build table. Every target is defined by a section within tool.hatch.build.targets, for example:

      [tool.hatch.build.targets.sdist]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Builds


      Configuration

      Builds are configured using the tool.hatch.build table. Every target is defined by a section within tool.hatch.build.targets, for example:

      [tool.hatch.build.targets.sdist]
       exclude = [
         "/.github",
         "/docs",
      diff --git a/latest/cli/about/index.html b/latest/cli/about/index.html
      index 0da8ce722..32ceef340 100644
      --- a/latest/cli/about/index.html
      +++ b/latest/cli/about/index.html
      @@ -1,4 +1,4 @@
      - About - Hatch      

      About


      Verbosity

      The amount of displayed output is controlled solely by the -v/--verbose (environment variable HATCH_VERBOSE) and -q/--quiet (environment variable HATCH_QUIET) root options.

      The levels are documented here.

      Project awareness

      No matter the mode, Hatch will always change to the project's root directory for entering or running commands in environments.

      Tab completion

      Completion is achieved by saving a script and then executing it as a part of your shell's startup sequence.

      Afterward, you'll need to start a new shell in order for the changes to take effect.

      Save the script somewhere:

      _HATCH_COMPLETE=bash_source hatch > ~/.hatch-complete.bash
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      CLI usage


      Verbosity

      The amount of displayed output is controlled solely by the -v/--verbose (environment variable HATCH_VERBOSE) and -q/--quiet (environment variable HATCH_QUIET) root options.

      The levels are documented here.

      Project awareness

      No matter the mode, Hatch will always change to the project's root directory for entering or running commands in environments.

      Tab completion

      Completion is achieved by saving a script and then executing it as a part of your shell's startup sequence.

      Afterward, you'll need to start a new shell in order for the changes to take effect.

      Save the script somewhere:

      _HATCH_COMPLETE=bash_source hatch > ~/.hatch-complete.bash
       

      Source the file in ~/.bashrc (or ~/.bash_profile if on macOS):

      . ~/.hatch-complete.bash
       

      Save the script somewhere:

      _HATCH_COMPLETE=zsh_source hatch > ~/.hatch-complete.zsh
       

      Source the file in ~/.zshrc:

      . ~/.hatch-complete.zsh
       

      Save the script in ~/.config/fish/completions:

      _HATCH_COMPLETE=fish_source hatch > ~/.config/fish/completions/hatch.fish
      -
      \ No newline at end of file +
      \ No newline at end of file diff --git a/latest/cli/reference/index.html b/latest/cli/reference/index.html index a4fbf2af1..59cab860f 100644 --- a/latest/cli/reference/index.html +++ b/latest/cli/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

      hatch

      Usage:

      hatch [OPTIONS] COMMAND [ARGS]...
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      hatch

      Usage:

      hatch [OPTIONS] COMMAND [ARGS]...
       

      Options:

      Name Type Description Default
      --env, -e text The name of the environment to use [env var: HATCH_ENV] default
      --project, -p text The name of the project to work on [env var: HATCH_PROJECT] None
      --verbose, -v integer range (0 and above) Increase verbosity (can be used additively) [env var: HATCH_VERBOSE] 0
      --quiet, -q integer range (0 and above) Decrease verbosity (can be used additively) [env var: HATCH_QUIET] 0
      --color / --no-color boolean Whether or not to display colored output (default is auto-detection) [env vars: FORCE_COLOR/NO_COLOR] None
      --interactive / --no-interactive boolean Whether or not to allow features like prompts and progress bars (default is auto-detection) [env var: HATCH_INTERACTIVE] None
      --data-dir text The path to a custom directory used to persist data [env var: HATCH_DATA_DIR] None
      --cache-dir text The path to a custom directory used to cache data [env var: HATCH_CACHE_DIR] None
      --config text The path to a custom config file to use [env var: HATCH_CONFIG] None
      --version boolean Show the version and exit. False
      --help boolean Show this message and exit. False

      hatch build

      Build a project.

      Usage:

      hatch build [OPTIONS] [LOCATION]
       

      Options:

      Name Type Description Default
      --target, -t text The target to build, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None
      --hooks-only boolean Whether or not to only execute build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False
      --no-hooks boolean Whether or not to disable build hooks [env var: HATCH_BUILD_NO_HOOKS] False
      --ext boolean Whether or not to only execute build hooks for distributing binary Python packages, such as compiling extensions. Equivalent to --hooks-only -t wheel False
      --clean, -c boolean Whether or not existing artifacts should first be removed [env var: HATCH_BUILD_CLEAN] False
      --clean-hooks-after boolean Whether or not build hook artifacts should be removed after each build [env var: HATCH_BUILD_CLEAN_HOOKS_AFTER] False
      --help boolean Show this message and exit. False

      hatch clean

      Remove build artifacts.

      Usage:

      hatch clean [OPTIONS] [LOCATION]
       

      Options:

      Name Type Description Default
      --target, -t text The target with which to remove artifacts, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None
      --hooks-only boolean Whether or not to only remove artifacts from build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False
      --no-hooks boolean Whether or not to ignore artifacts from build hooks [env var: HATCH_BUILD_NO_HOOKS] False
      --ext boolean Whether or not to only remove artifacts from build hooks for distributing binary Python packages, such as compiled extensions. Equivalent to --hooks-only -t wheel False
      --help boolean Show this message and exit. False

      hatch config

      Manage the config file

      Usage:

      hatch config [OPTIONS] COMMAND [ARGS]...
      @@ -37,7 +37,7 @@
       

      would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

      Usage:

      hatch env run [OPTIONS] ARGS...
       

      Options:

      Name Type Description Default
      --env, -e text The environments to target None
      --include, -i text The matrix variables to include None
      --exclude, -x text The matrix variables to exclude None
      --filter, -f text The JSON data used to select environments None
      --force-continue boolean Run every command and if there were any errors exit with the first code False
      --ignore-compat boolean Ignore incompatibility when selecting specific environments False
      --help boolean Show this message and exit. False

      hatch env show

      Show the available environments.

      Usage:

      hatch env show [OPTIONS] [ENVS]...
       

      Options:

      Name Type Description Default
      --ascii boolean Whether or not to only use ASCII characters False
      --json boolean Whether or not to output in JSON format False
      --help boolean Show this message and exit. False

      hatch fmt

      Format and lint source code.

      Usage:

      hatch fmt [OPTIONS] [ARGS]...
      -

      Options:

      Name Type Description Default
      --check boolean Only check for errors rather than fixing them False
      --preview / --no-preview boolean Preview new rules and formatting None
      --linter, -l boolean Only run the linter False
      --formatter, -f boolean Only run the formatter False
      --sync boolean Sync the default config file with the current version of Hatch False
      --help boolean Show this message and exit. False

      hatch new

      Create or initialize a project.

      Usage:

      hatch new [OPTIONS] [NAME] [LOCATION]
      +

      Options:

      Name Type Description Default
      --check boolean Only check for errors rather than fixing them False
      --linter, -l boolean Only run the linter False
      --formatter, -f boolean Only run the formatter False
      --sync boolean Sync the default config file with the current version of Hatch False
      --help boolean Show this message and exit. False

      hatch new

      Create or initialize a project.

      Usage:

      hatch new [OPTIONS] [NAME] [LOCATION]
       

      Options:

      Name Type Description Default
      --interactive, -i boolean Interactively choose details about the project False
      --cli boolean Give the project a command line interface False
      --init boolean Initialize an existing project False
      --help boolean Show this message and exit. False

      hatch project

      View project information

      Usage:

      hatch project [OPTIONS] COMMAND [ARGS]...
       

      Options:

      Name Type Description Default
      --help boolean Show this message and exit. False

      hatch project metadata

      Display project metadata.

      If you want to view the raw readme file without rendering, you can use a JSON parser like jq:

      hatch project metadata | jq -r .readme
       

      Usage:

      hatch project metadata [OPTIONS] [FIELD]
      @@ -59,6 +59,10 @@
       version = ["42", "3.14", "9000"]
       

      then running:

      hatch run +py=3.10 -version=9000 test:pytest
       

      would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

      Usage:

      hatch run [OPTIONS] [ENV:]ARGS...
      +

      Options:

      Name Type Description Default
      --help boolean Show this message and exit. False

      hatch self

      Manage Hatch

      Usage:

      hatch self [OPTIONS] COMMAND [ARGS]...
      +

      Options:

      Name Type Description Default
      --help boolean Show this message and exit. False

      hatch self report

      Generate a pre-populated GitHub issue.

      Usage:

      hatch self report [OPTIONS]
      +

      Options:

      Name Type Description Default
      --no-open, -n boolean Show the URL instead of opening it False
      --help boolean Show this message and exit. False

      hatch self restore

      Restore the installation

      Usage:

      hatch self restore [OPTIONS] [ARGS]...
      +

      Options:

      Name Type Description Default
      --help boolean Show this message and exit. False

      hatch self update

      Install the latest version

      Usage:

      hatch self update [OPTIONS] [ARGS]...
       

      Options:

      Name Type Description Default
      --help boolean Show this message and exit. False

      hatch shell

      Enter a shell within a project's environment.

      Usage:

      hatch shell [OPTIONS] [SHELL_NAME] [SHELL_PATH] [SHELL_ARGS]...
       

      Options:

      Name Type Description Default
      --help boolean Show this message and exit. False

      hatch status

      Show information about the current environment.

      Usage:

      hatch status [OPTIONS]
       

      Options:

      Name Type Description Default
      --help boolean Show this message and exit. False

      hatch version

      View or set a project's version.

      Usage:

      hatch version [OPTIONS] [DESIRED_VERSION]
      diff --git a/latest/community/contributing/index.html b/latest/community/contributing/index.html
      index 996fc9b23..fb7ff676c 100644
      --- a/latest/community/contributing/index.html
      +++ b/latest/community/contributing/index.html
      @@ -7,7 +7,7 @@
           .gdesc-inner { font-size: 0.75rem; }
           body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
           body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
      -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Contributing

      The usual process to make a contribution is to:

      1. Check for existing related issues
      2. Fork the repository and create a new branch
      3. Make your changes
      4. Make sure formatting, linting and tests passes.
      5. Add tests if possible to cover the lines you added.
      6. Commit, and send a Pull Request.

      Clone the repository

      Clone the hatch repository, cd into it, and create a new branch for your contribution:

      cd hatch
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Contributing

      The usual process to make a contribution is to:

      1. Check for existing related issues
      2. Fork the repository and create a new branch
      3. Make your changes
      4. Make sure formatting, linting and tests passes.
      5. Add tests if possible to cover the lines you added.
      6. Commit, and send a Pull Request.

      Clone the repository

      Clone the hatch repository, cd into it, and create a new branch for your contribution:

      cd hatch
       git checkout -b add-my-contribution
       

      Run the tests

      Run the test suite while developing:

      hatch run dev
       

      Run the test suite with coverage report:

      hatch run cov
      @@ -15,5 +15,5 @@
       

      Lint

      Run automated formatting:

      hatch run lint:fmt
       

      Run full linting and type checking:

      hatch run lint:all
       

      Docs

      Start the documentation in development:

      hatch run docs:serve
      -

      Build and validate the documentation website:

      hatch run build-check
      -
      \ No newline at end of file +

      Build and validate the documentation website:

      hatch run docs:build-check
      +
      \ No newline at end of file diff --git a/latest/community/highlights/index.html b/latest/community/highlights/index.html index a9119eaa2..8fa49d757 100644 --- a/latest/community/highlights/index.html +++ b/latest/community/highlights/index.html @@ -1,4 +1,4 @@ - Highlights - Hatch
      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}
      \ No newline at end of file diff --git a/latest/community/users/index.html b/latest/community/users/index.html index 5b5c43d5e..c92898610 100644 --- a/latest/community/users/index.html +++ b/latest/community/users/index.html @@ -7,4 +7,4 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Users


      The following is not intended to be a complete enumeration. Be sure to view the development version of this page for an up-to-date listing.

      Projects

      aiogram | argon2-cffi | attrs | Black | coffea | Colorama | Django Anymail | Django Debug Toolbar | Django Wiki | FastAPI | filelock | github3.py | Gradio | HTTPX | iCalendar for Humans | LinkChecker | Material for MkDocs | MkDocs | openSUSE | Nox | Packit | pipx | platformdirs | Pydantic | Pygments | PyHamcrest | PyMdown Extensions | Python JSON Schema | Rye | SALib | Spack | Starlette | structlog | tox | Twisted | urllib3 | Uvicorn | virtualenv | Voilà | XGBoost | Ypy

      Industry

      Organizations

      Government

      Academia

      Research

      Security

      Crypto

      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Users


      The following is not intended to be a complete enumeration. Be sure to view the development version of this page for an up-to-date listing.

      Projects

      aiogram | Apache Airflow | argon2-cffi | attrs | Black | coffea | Colorama | Django Anymail | Django Debug Toolbar | Django Wiki | FastAPI | filelock | github3.py | Gradio | HTTPX | iCalendar for Humans | LinkChecker | Material for MkDocs | MkDocs | openSUSE | Nox | Packit | pipx | platformdirs | Pydantic | Pygments | PyHamcrest | PyMdown Extensions | Python JSON Schema | Rye | SALib | Spack | Starlette | structlog | tox | Twisted | urllib3 | Uvicorn | virtualenv | Voilà | XGBoost | Ypy

      Industry

      Organizations

      Government

      Academia

      Research

      Security

      Crypto

      \ No newline at end of file diff --git a/latest/config/build/index.html b/latest/config/build/index.html index a2b3c05c5..f08716016 100644 --- a/latest/config/build/index.html +++ b/latest/config/build/index.html @@ -1,4 +1,4 @@ - Build - Hatch

      Build configuration


      Build targets are defined as sections within tool.hatch.build.targets:

      [tool.hatch.build.targets.<TARGET_NAME>]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Build configuration


      Build targets are defined as sections within tool.hatch.build.targets:

      [tool.hatch.build.targets.<TARGET_NAME>]
       
      [build.targets.<TARGET_NAME>]
       

      Tip

      Although not recommended, you may define global configuration in the tool.hatch.build table. Keys may then be overridden by target config.

      Build system

      To be compatible with the broader Python packaging ecosystem, you must define the build system as follows:

      [build-system]
       requires = ["hatchling"]
      diff --git a/latest/config/context/index.html b/latest/config/context/index.html
      index ca26ed0b5..84ebd7978 100644
      --- a/latest/config/context/index.html
      +++ b/latest/config/context/index.html
      @@ -7,7 +7,7 @@
           .gdesc-inner { font-size: 0.75rem; }
           body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
           body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
      -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Context formatting


      You can populate configuration with the values of certain supported fields using the syntax of Python's format strings. Each field interprets the modifier part after the colon differently, if at all.

      Global fields

      Any configuration that declares support for context formatting will always support these fields.

      Paths

      Field Description
      root The root project directory
      home The user's home directory

      All paths support the following modifiers:

      Modifier Description
      uri The normalized absolute URI path prefixed by file:
      real The path with all symbolic links resolved
      parent The parent of the preceding path

      Tip

      The parent modifier can be chained and may be combined with either the uri or real modifier, with the latter placed at the end. For example:

      [tool.hatch.envs.test]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Context formatting


      You can populate configuration with the values of certain supported fields using the syntax of Python's format strings. Each field interprets the modifier part after the colon differently, if at all.

      Global fields

      Any configuration that declares support for context formatting will always support these fields.

      Paths

      Field Description
      root The root project directory
      home The user's home directory

      All paths support the following modifiers:

      Modifier Description
      uri The normalized absolute URI path prefixed by file:
      real The path with all symbolic links resolved
      parent The parent of the preceding path

      Tip

      The parent modifier can be chained and may be combined with either the uri or real modifier, with the latter placed at the end. For example:

      [tool.hatch.envs.test]
       dependencies = [
           "example-project @ {root:parent:parent:uri}/example-project",
       ]
      diff --git a/latest/config/dependency/index.html b/latest/config/dependency/index.html
      index 2a32def8d..0cf9c6863 100644
      --- a/latest/config/dependency/index.html
      +++ b/latest/config/dependency/index.html
      @@ -1,4 +1,4 @@
      - Dependencies - Hatch      

      Dependency configuration


      Project dependencies are defined with PEP 508 strings using optional PEP 440 version specifiers.

      Version specifiers

      A version specifier consists of a series of version clauses, separated by commas. For example:

      [project]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Dependency configuration


      Project dependencies are defined with PEP 508 strings using optional PEP 440 version specifiers.

      Version specifiers

      A version specifier consists of a series of version clauses, separated by commas. For example:

      [project]
       ...
       dependencies = [
         "cryptography",
      diff --git a/latest/config/environment/advanced/index.html b/latest/config/environment/advanced/index.html
      index dfb6211fc..118c4aded 100644
      --- a/latest/config/environment/advanced/index.html
      +++ b/latest/config/environment/advanced/index.html
      @@ -1,4 +1,4 @@
      - Advanced - Hatch      

      Advanced environment configuration


      Context formatting

      All environments support the following extra context formatting fields:

      Field Description
      env_name The name of the environment
      env_type The type of environment
      matrix Its modifier selects the value of that matrix variable. If the environment is not part of a matrix or was not generated with the variable, you must specify a default value as an additional modifier e.g. {matrix:version:v1.0.0}.
      verbosity The integer verbosity value of Hatch. A flag modifier is supported that will render the value as a CLI flag e.g. -2 becomes -qq, 1 becomes -v, and 0 becomes an empty string. An additional flag integer modifier may be used to adjust the verbosity level. For example, if you wanted to make a command quiet by default, you could use {verbosity:flag:-1} within the command.
      args For executed commands only, any extra command line arguments with an optional default modifier if none were provided

      Matrix

      Environments can define a series of matrices with the matrix option:

      [tool.hatch.envs.test]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Advanced environment configuration


      Context formatting

      All environments support the following extra context formatting fields:

      Field Description
      env_name The name of the environment
      env_type The type of environment
      matrix Its modifier selects the value of that matrix variable. If the environment is not part of a matrix or was not generated with the variable, you must specify a default value as an additional modifier e.g. {matrix:version:v1.0.0}.
      verbosity The integer verbosity value of Hatch. A flag modifier is supported that will render the value as a CLI flag e.g. -2 becomes -qq, 1 becomes -v, and 0 becomes an empty string. An additional flag integer modifier may be used to adjust the verbosity level. For example, if you wanted to make a command quiet by default, you could use {verbosity:flag:-1} within the command.
      args For executed commands only, any extra command line arguments with an optional default modifier if none were provided

      Matrix

      Environments can define a series of matrices with the matrix option:

      [tool.hatch.envs.test]
       dependencies = [
         "pytest"
       ]
      diff --git a/latest/config/environment/overview/index.html b/latest/config/environment/overview/index.html
      index 04a12e5ef..8dfa032a3 100644
      --- a/latest/config/environment/overview/index.html
      +++ b/latest/config/environment/overview/index.html
      @@ -1,4 +1,4 @@
      - Overview - Hatch      

      Environment configuration


      All environments are defined as sections within the tool.hatch.envs table.

      [tool.hatch.envs.<ENV_NAME>]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Environment configuration


      All environments are defined as sections within the tool.hatch.envs table.

      [tool.hatch.envs.<ENV_NAME>]
       
      [envs.<ENV_NAME>]
       

      The storage location for environments is completely configurable.

      Unless an environment is explicitly selected on the command line, the default environment will be used. The type of this environment defaults to virtual.

      Info

      Environments prefixed by hatch- are used for special purposes e.g. static analysis.

      Inheritance

      All environments inherit from the environment defined by its template option, which defaults to default.

      So for the following configuration:

      [tool.hatch.envs.foo]
       type = "baz"
      diff --git a/latest/config/hatch/index.html b/latest/config/hatch/index.html
      index d6bfabed8..75fdc5547 100644
      --- a/latest/config/hatch/index.html
      +++ b/latest/config/hatch/index.html
      @@ -1,4 +1,4 @@
      - Hatch - Hatch      

      Hatch configuration


      Configuration for Hatch itself is stored in a config.toml file located by default in one of the following platform-specific directories.

      Platform Path
      macOS ~/Library/Application Support/hatch
      Windows %USERPROFILE%\AppData\Local\hatch
      Unix $XDG_CONFIG_HOME/hatch (the XDG_CONFIG_HOME environment variable default is ~/.config)

      You can select a custom path to the file using the --config root option or by setting the HATCH_CONFIG environment variable.

      The file can be managed by the config command group.

      Mode

      The mode key controls how Hatch selects the project to work on.

      Local

      mode = "local"
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Hatch configuration


      Configuration for Hatch itself is stored in a config.toml file located by default in one of the following platform-specific directories.

      Platform Path
      macOS ~/Library/Application Support/hatch
      Windows %USERPROFILE%\AppData\Local\hatch
      Unix $XDG_CONFIG_HOME/hatch (the XDG_CONFIG_HOME environment variable default is ~/.config)

      You can select a custom path to the file using the --config root option or by setting the HATCH_CONFIG environment variable.

      The file can be managed by the config command group.

      Mode

      The mode key controls how Hatch selects the project to work on.

      Local

      mode = "local"
       

      By default, Hatch will look for a pyproject.toml file in the current working directory and any parent directories. The directory storing the first found file will be considered the project root.

      Project

      mode = "project"
       project = "proj1"
       
      diff --git a/latest/config/metadata/index.html b/latest/config/metadata/index.html
      index 57c841e89..78506e1f0 100644
      --- a/latest/config/metadata/index.html
      +++ b/latest/config/metadata/index.html
      @@ -1,4 +1,4 @@
      - Metadata - Hatch      

      Project metadata


      Project metadata is stored in a pyproject.toml file located at the root of a project's tree and is based entirely on the standard.

      Name (required)

      The name of the project.

      [project]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Configuring project metadata


      Project metadata is stored in a pyproject.toml file located at the root of a project's tree and is based entirely on the standard.

      Name (required)

      The name of the project.

      [project]
       name = "your-app"
       

      Version (required)

      See the dedicated versioning section.

      [project]
       ...
      @@ -100,4 +100,4 @@
       allow-ambiguous-features = true
       
      [metadata]
       allow-ambiguous-features = true
      -

      Deprecated

      This option temporarily exists to provide better interoperability with tools that do not yet support PEP 685 and will be removed in the first minor release after Jan 1, 2024.

      \ No newline at end of file +

      Deprecated

      This option temporarily exists to provide better interoperability with tools that do not yet support PEP 685 and will be removed in the first minor release after Jan 1, 2024.

      \ No newline at end of file diff --git a/latest/config/project-templates/index.html b/latest/config/project-templates/index.html index cc3d6efe4..b5eea3c47 100644 --- a/latest/config/project-templates/index.html +++ b/latest/config/project-templates/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Project templates


      You can control how new projects are created by the new command using Hatch's config file.

      Author

      [template]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Project templates


      You can control how new projects are created by the new command using Hatch's config file.

      Author

      [template]
       name = "..."
       email = "..."
       

      Licenses

      [template.licenses]
      diff --git a/latest/config/static-analysis/index.html b/latest/config/static-analysis/index.html
      index b2745b0f9..1c77a605e 100644
      --- a/latest/config/static-analysis/index.html
      +++ b/latest/config/static-analysis/index.html
      @@ -1,4 +1,4 @@
      - Static analysis - Hatch      

      Static analysis configuration


      Static analysis performed by the fmt command is backed entirely by Ruff.

      Hatch provides default settings that user configuration can extend.

      Extending config

      When defining your configuration, be sure to use options that are prefixed by extend- such as extend-select, for example:

      [tool.ruff.format]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Static analysis configuration


      Static analysis performed by the fmt command is (by default) backed entirely by Ruff.

      Hatch provides default settings that user configuration can extend.

      Extending config

      When defining your configuration, be sure to use options that are prefixed by extend- such as extend-select, for example:

      [tool.ruff.format]
       preview = true
       quote-style = "single"
       
      @@ -41,8 +41,22 @@
       extend = "ruff_defaults.toml"
       
      extend = "ruff_defaults.toml"
       

      Anytime you wish to update the defaults (such as when upgrading Hatch), you must run the fmt command once with the --sync flag e.g.:

      hatch fmt --check --sync
      -

      Tip

      This is the recommended approach since it allows other tools like IDEs to use the default configuration.

      Versioning

      You can pin the particular version of Ruff by explicitly defining the environment dependencies:

      [tool.hatch.envs.hatch-static-analysis]
      +

      Tip

      This is the recommended approach since it allows other tools like IDEs to use the default configuration.

      No config

      If you don't want Hatch to use any of its default configuration and rely entirely on yours, set the path to anything and then simply don't extend in your Ruff config:

      [tool.hatch.envs.hatch-static-analysis]
      +config-path = "none"
      +
      [envs.hatch-static-analysis]
      +config-path = "none"
      +

      Customize behavior

      You can fully alter the behavior of the environment used by the fmt command. See the how-to for a detailed example.

      Dependencies

      Pin the particular version of Ruff by explicitly defining the environment dependencies:

      [tool.hatch.envs.hatch-static-analysis]
       dependencies = ["ruff==X.Y.Z"]
       
      [envs.hatch-static-analysis]
       dependencies = ["ruff==X.Y.Z"]
      -

      Default settings

      Non-rule settings

      Per-file ignored rules

      Selected rules

      The following rules are based on version 0.1.8 of Ruff. Rules with a P are only selected when preview mode is enabled.

      \ No newline at end of file +

      Scripts

      If you want to change the default commands that are executed, you can override the scripts. The following four scripts must be defined:

      [tool.hatch.envs.hatch-static-analysis.scripts]
      +format-check = "..."
      +format-fix = "..."
      +lint-check = "..."
      +lint-fix = "..."
      +
      [envs.hatch-static-analysis.scripts]
      +format-check = "..."
      +format-fix = "..."
      +lint-check = "..."
      +lint-fix = "..."
      +

      The format-* scripts correspond to the --formatter/-f flag while the lint-* scripts correspond to the --linter/-l flag. The *-fix scripts run by default while the *-check scripts correspond to the --check flag.

      Reminder

      If you choose to use different tools for static analysis, be sure to update the required dependencies.

      Default settings

      Non-rule settings

      Per-file ignored rules

      Selected rules

      The following rules are based on version 0.3.1 of Ruff. Rules with a P are only selected when preview mode is enabled.

      \ No newline at end of file diff --git a/latest/environment/index.html b/latest/environment/index.html index 440ad6ed7..23448cacc 100644 --- a/latest/environment/index.html +++ b/latest/environment/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Environments


      Environments are designed to allow for isolated workspaces for testing, building documentation, or anything else projects need.

      Unless an environment is chosen explicitly, Hatch will use the default environment.

      Creation

      You can create environments by using the env create command. Let's enter the directory of the project we created in the setup phase:

      $ hatch env create
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Environments


      Environments are designed to allow for isolated workspaces for testing, building documentation, or anything else projects need.

      Unless an environment is chosen explicitly, Hatch will use the default environment.

      Tip

      For a more comprehensive walk-through, see the Basic usage tutorial.

      Creation

      You can create environments by using the env create command. Let's enter the directory of the project we created in the setup phase:

      $ hatch env create
       Creating environment: default
       Installing project in development mode
       Syncing dependencies
      @@ -100,4 +100,4 @@
       |      |         | test.py3.9-9000-foo |              |
       |      |         | test.py3.9-9000-bar |              |
       +------+---------+---------------------+--------------+
      -

      Removal

      You can remove a single environment or environment matrix by using the env remove command or all of a project's environments by using the env prune command.

      \ No newline at end of file +

      Removal

      You can remove a single environment or environment matrix by using the env remove command or all of a project's environments by using the env prune command.

      \ No newline at end of file diff --git a/latest/history/hatch/index.html b/latest/history/hatch/index.html index db4c72f24..6d3b09796 100644 --- a/latest/history/hatch/index.html +++ b/latest/history/hatch/index.html @@ -1,4 +1,4 @@ - Hatch - Hatch

      Hatch history


      All notable changes to Hatch will be documented in this file.

      The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

      Unreleased

      1.9.4 - 2024-03-12

      Fixed:

      • Limit the maximum version of Hatchling in anticipation of backward incompatible changes

      1.9.3 - 2024-01-25

      Fixed:

      • Fix loading of local plugins to account for newly released versions of a dependency

      1.9.2 - 2024-01-21

      Fixed:

      • Fix the default token variable name for publishing to PyPI

      1.9.1 - 2023-12-25

      Fixed:

      • Ensure that the dependency_hash method of the environment interface is called after sync_dependencies for cases where the hash is only known at that point, such as for dependency lockers
      • Only acknowledge the HATCH_PYTHON_VARIANT_* environment variables for Python resolution for supported platforms and architectures
      • Fix Python resolution when there are metadata hooks with unsatisfied dependencies

      1.9.0 - 2023-12-19

      Changed:

      • Environments prefixed by hatch- are now considered internal and used for special purposes such as configuration for static analysis

      Added:

      • Enable docstring formatting by default for static analysis
      • Allow for overriding config of internal environments
      • Concretely state the expected API contract for the environment interface methods find and check_compatibility
      • Upgrade Ruff to 0.1.8
      • Bump the minimum supported version of Hatchling to 1.21.0

      Fixed:

      • Ignore a project's Python requirement for environments where the project is not installed
      • When not persisting config for static analysis, properly manage internal settings when Ruff's top level table already exists
      • Ignore compatibility checks when environments have already been created, significantly improving performance of environment usage
      • Properly allow overriding of the path option for the virtual environment type
      • Fix nushell activation on non-Windows systems

      1.8.1 - 2023-12-14

      Fixed:

      • Fix regression in calling subprocesses with updated PATH
      • Fix automatic installation of environment plugins when running as a standalone binary
      • Change default location of Python installations

      1.8.0 - 2023-12-11

      Changed:

      • Drop support for Python 3.7
      • The get_build_process method of the environment interface has been removed; plugins should use the new run_builder method instead
      • Remove pyperclip dependency and the --copy flag of the config find command
      • When running the build command all output from builders is now displayed as-is in real time without the stripping of ANSI codes
      • Version information (for Hatch itself) is now derived from Git

      Added:

      • Support Python 3.12
      • Add installers and standalone binaries
      • Add the ability to manage Python installations
      • Add fmt command
      • The virtual environment type can now automatically download requested versions of Python that are not installed
      • Add dependency_hash method to the environment interface
      • The state of installed dependencies for environments is saved as metadata so if dependency definitions have not changed then no checking is performed, which can be computationally expensive
      • The build command now supports backends other than Hatchling
      • Allow the use of features for environments when skip-install is enabled
      • The default is now __token__ when prompting for a username for the publish command
      • Add a new run_builder method to the environment interface
      • Bump the minimum supported version of Hatchling to 1.19.0
      • Bump the minimum supported version of click to 8.0.6

      Fixed:

      • Fix nushell activation
      • Better handling of flat storage directory hierarchies for the virtual environment type
      • Display useful information when running the version command outside of a project rather than erroring
      • Fix the project metadata command by only capturing stdout from the backend
      • Properly support Google Artifact Registry
      • Fix parsing dependencies for environments when warnings are emitted

      1.7.0 - 2023-04-03

      Changed:

      • The src-layout project template option is now enabled by default
      • Non-critical output now goes to stderr

      Added:

      • Add tool.hatch.env.requires configuration to automatically install dependencies for environment and environment collector plugins
      • Add custom environment collector
      • Improve syncing of dependencies provided through Git direct references
      • Add isolated_data_directory attribute to the environment interface
      • Increase the timeout for and add retries to the index publisher
      • Expand home and environment variables in configured cache and data directories
      • Improve readability of exceptions
      • Update project templates
      • Bump the minimum supported version of Hatchling to 1.14.0

      Fixed:

      • Fix displaying the version with the version command when the version is static and build dependencies are unmet
      • Fix build environments for the virtual environment type when storing within a relative path
      • Work around System Integrity Protection on macOS when running commands
      • Allow setuptools metadata migration for projects without setup.py if setup.cfg is present
      • Handle additional edge cases for setuptools metadata migration
      • Support boolean values for the config set command

      1.6.3 - 2022-10-24

      Fixed:

      • Fix version command when the version is dynamic and build dependencies are unmet

      1.6.2 - 2022-10-20

      Fixed:

      • Fix getting dynamic metadata from hooks for environments when dependencies are not dynamic

      1.6.1 - 2022-10-16

      Fixed:

      • Computing the path to the user's home directory now gracefully falls back to ~ when it cannot be determined

      1.6.0 - 2022-10-08

      Changed:

      • The run_shell_command environment interface method now accepts arbitrary subprocess.Popen keyword arguments. This is not strictly breaking, but will be utilized in upcoming features.
      • The internal directory structure for storing virtual environments is now more nested. This is not breaking, but any local environments will be created anew.

      Added:

      • Add project command group to view details about the project like PEP 621 metadata
      • Better support for auto-detection of environments by tools like Visual Studio Code now that the storage directory of virtual environments will be flat if Hatch's configured virtual environment directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
      • Build environments for the virtual environment type are now cached for improved performance
      • Add build_environment_exists method to the environment interface for implementations that cache the build environment
      • Add path option to the virtual environment type
      • Add --initialize-auth flag to the index publisher to allow for the saving of authentication information before publishing
      • Support Bash on Windows for the shell command
      • The setuptools migration script no longer modifies the formatting of existing pyproject.toml configuration
      • Bump the minimum supported version of Hatchling to 1.11.0

      Fixed:

      • Environments now respect dynamically defined project dependencies
      • The dep hash and all dep show commands now respect dynamically defined project dependencies
      • The env show, dep hash, and all dep show commands now honor context formatting
      • Fix matrix variable inclusion filtering of the run and env run commands when there are multiple possible variables
      • Build environment compatibility is now checked before use
      • Decreasing verbosity now has no affect on output that should always be displayed
      • Handle more edge cases in the setuptools migration script
      • Environments now respect user defined environment variables for context formatting
      • Update the scripts in the generated test environment template for new projects to reflect the documentation
      • Allow extra-dependencies in environment overrides
      • Depend on packaging explicitly rather than relying on it being a transitive dependency of Hatchling

      1.5.0 - 2022-08-28

      Added:

      • The index publisher now recognizes repository-specific options
      • Add the --ignore-compat flag to the env run command
      • Setting the HATCH_PYTHON environment variable to self will now force the use of the Python executable Hatch is running on for virtual environment creation

      Fixed:

      • Fix the --force-continue flag of the env run command
      • Handle more edge cases in the setuptools migration script

      1.4.2 - 2022-08-16

      Fixed:

      • Fix check for updating static versions with the version command when metadata hooks are in use

      1.4.1 - 2022-08-13

      Fixed:

      • Fix non-detached inheritance disabling for environments

      1.4.0 - 2022-08-06

      Added:

      • The default Python for virtual environments now checks PATH before using the one Hatch is running on
      • Values for environment env-vars now support context formatting
      • Add name override for environments to allow for regular expression matching
      • The index publisher now better supports non-PyPI indices
      • Add certificate options to the index publisher
      • Display waiting text when checking dependencies and removing environments
      • Display help text the first time the shell command is executed
      • Update project templates with Python 3.11 and the latest versions of various GitHub Actions
      • Add support for Almquist (ash) shells
      • Add hyperlink as a dependency for better handling of package index URLs
      • Bump the minimum supported version of virtualenv to 20.16.2
      • Bump the minimum supported version of tomlkit to 0.11.1

      Fixed:

      • Acknowledge extra-dependencies for the env show command
      • Fix locating executables within virtual environments on Debian
      • Fix managing the terminal size inside the shell command
      • Fix default code coverage file omission for the src-layout project template option

      1.3.1 - 2022-07-11

      Fixed:

      • Support -h/--help flag for the run command

      1.3.0 - 2022-07-10

      Changed:

      • Rename the default publishing plugin from pypi to the more generic index

      Added:

      • Support the absence of pyproject.toml files, as is the case for apps and non-Python projects
      • Hide scripts that start with an underscore for the env show command by default
      • Ignoring the exit codes of commands by prefixing with hyphens now works with entire named scripts
      • Add a way to require confirmation for publishing
      • Add --force-continue flag to the env run command
      • Make tracebacks colorful and less verbose
      • When shell configuration has not been defined, attempt to use the current shell based on parent processes before resorting to the defaults
      • The shell name pwsh is now an alias for powershell
      • Remove atomicwrites dependency
      • Relax constraint on userpath dependency
      • Bump the minimum supported version of Hatchling to 1.4.1

      Fixed:

      • Keep environments in sync with the dependencies of the selected features
      • Use utf-8 for all files generated for new projects
      • Escape special characters Git may return in the user name when writing generated files for new projects
      • Normalize the package name to lowercase in setuptools migration script
      • Fix parsing of source distributions during publishing

      1.2.1 - 2022-05-30

      Fixed:

      • Fix handling of top level data_files in setuptools migration script

      1.2.0 - 2022-05-22

      Changed:

      • The enter_shell environment plugin method now accepts an additional args parameter

      Added:

      • Allow context string formatting for environment dependencies
      • Add environment context string formatting fields env_name, env_type, matrix, verbosity, and args
      • Support overriding the default arguments used to spawn shells on non-Windows systems
      • Bump the minimum supported version of Hatchling to 1.3.0

      Fixed:

      • Improve setuptools migration script

      1.1.2 - 2022-05-20

      Fixed:

      • Bump the minimum supported version of Hatchling to 1.2.0
      • Update project metadata to reflect support for Python 3.11

      1.1.1 - 2022-05-12

      Fixed:

      • Fix setuptools migration script for non-Windows systems

      1.1.0 - 2022-05-12

      Changed:

      • In order to simplify the implementation of command execution for environment plugins, the run_shell_commands method has been replaced by the singular run_shell_command. A new command_context method has been added to more easily satisfy complex use cases.
      • The finalize_command environment plugin method has been removed in favor of the newly introduced context formatting functionality.

      Added:

      • Add context formatting functionality i.e. the ability to insert values into configuration like environment variables and command line arguments
      • Any verbosity for command execution will now always display headers, even for single environments
      • Every executed command is now displayed when running multiple commands or when verbosity is enabled
      • Similar to make, ignore the exit code of executed commands that start with - (a hyphen)
      • Add ability for the --init flag of the new command to automatically migrate setuptools configuration
      • Update project metadata to reflect the adoption by PyPA and production stability

      1.0.0 - 2022-04-28

      This is the first stable release of Hatch v1, a complete rewrite. Enjoy!

      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Hatch history


      All notable changes to Hatch will be documented in this file.

      The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

      Unreleased

      Added:

      • Add self report command for submitting pre-populated bug reports to GitHub
      • The reserved environment used for static analysis is now completely configurable
      • Add the following methods to the environment interface for complete control over output during life cycle management: app_status_creation, app_status_pre_installation, app_status_post_installation, app_status_project_installation, app_status_dependency_state_check, app_status_dependency_installation_check, app_status_dependency_synchronization
      • Add binaries for 32-bit versions of Windows
      • Read configuration from any ~/.pypirc file for the index publisher
      • Use the Git user as the default username for new project URL metadata
      • Add HATCH_DEBUG environment variable that when enabled will show local variables in the case of unhandled tracebacks
      • Upgrade default CPython distributions to 20240224
      • Upgrade Ruff to 0.3.1
      • Upgrade PyApp to 0.15.1 for binary builds
      • Bump the minimum supported version of Hatchling to 1.22.2

      Fixed:

      • When projects derive dependencies from metadata hooks, there is now by default a status indicator for when the hooks are executed for better responsiveness
      • Fix dependency inheritance for the template of the types environment for new projects

      1.9.4 - 2024-03-12

      Fixed:

      • Limit the maximum version of Hatchling in anticipation of backward incompatible changes

      1.9.3 - 2024-01-25

      Fixed:

      • Fix loading of local plugins to account for newly released versions of a dependency

      1.9.2 - 2024-01-21

      Fixed:

      • Fix the default token variable name for publishing to PyPI

      1.9.1 - 2023-12-25

      Fixed:

      • Ensure that the dependency_hash method of the environment interface is called after sync_dependencies for cases where the hash is only known at that point, such as for dependency lockers
      • Only acknowledge the HATCH_PYTHON_VARIANT_* environment variables for Python resolution for supported platforms and architectures
      • Fix Python resolution when there are metadata hooks with unsatisfied dependencies

      1.9.0 - 2023-12-19

      Changed:

      • Environments prefixed by hatch- are now considered internal and used for special purposes such as configuration for static analysis

      Added:

      • Enable docstring formatting by default for static analysis
      • Allow for overriding config of internal environments
      • Concretely state the expected API contract for the environment interface methods find and check_compatibility
      • Upgrade Ruff to 0.1.8
      • Bump the minimum supported version of Hatchling to 1.21.0

      Fixed:

      • Ignore a project's Python requirement for environments where the project is not installed
      • When not persisting config for static analysis, properly manage internal settings when Ruff's top level table already exists
      • Ignore compatibility checks when environments have already been created, significantly improving performance of environment usage
      • Properly allow overriding of the path option for the virtual environment type
      • Fix nushell activation on non-Windows systems

      1.8.1 - 2023-12-14

      Fixed:

      • Fix regression in calling subprocesses with updated PATH
      • Fix automatic installation of environment plugins when running as a standalone binary
      • Change default location of Python installations

      1.8.0 - 2023-12-11

      Changed:

      • Drop support for Python 3.7
      • The get_build_process method of the environment interface has been removed; plugins should use the new run_builder method instead
      • Remove pyperclip dependency and the --copy flag of the config find command
      • When running the build command all output from builders is now displayed as-is in real time without the stripping of ANSI codes
      • Version information (for Hatch itself) is now derived from Git

      Added:

      • Support Python 3.12
      • Add installers and standalone binaries
      • Add the ability to manage Python installations
      • Add fmt command
      • The virtual environment type can now automatically download requested versions of Python that are not installed
      • Add dependency_hash method to the environment interface
      • The state of installed dependencies for environments is saved as metadata so if dependency definitions have not changed then no checking is performed, which can be computationally expensive
      • The build command now supports backends other than Hatchling
      • Allow the use of features for environments when skip-install is enabled
      • The default is now __token__ when prompting for a username for the publish command
      • Add a new run_builder method to the environment interface
      • Bump the minimum supported version of Hatchling to 1.19.0
      • Bump the minimum supported version of click to 8.0.6

      Fixed:

      • Fix nushell activation
      • Better handling of flat storage directory hierarchies for the virtual environment type
      • Display useful information when running the version command outside of a project rather than erroring
      • Fix the project metadata command by only capturing stdout from the backend
      • Properly support Google Artifact Registry
      • Fix parsing dependencies for environments when warnings are emitted

      1.7.0 - 2023-04-03

      Changed:

      • The src-layout project template option is now enabled by default
      • Non-critical output now goes to stderr

      Added:

      • Add tool.hatch.env.requires configuration to automatically install dependencies for environment and environment collector plugins
      • Add custom environment collector
      • Improve syncing of dependencies provided through Git direct references
      • Add isolated_data_directory attribute to the environment interface
      • Increase the timeout for and add retries to the index publisher
      • Expand home and environment variables in configured cache and data directories
      • Improve readability of exceptions
      • Update project templates
      • Bump the minimum supported version of Hatchling to 1.14.0

      Fixed:

      • Fix displaying the version with the version command when the version is static and build dependencies are unmet
      • Fix build environments for the virtual environment type when storing within a relative path
      • Work around System Integrity Protection on macOS when running commands
      • Allow setuptools metadata migration for projects without setup.py if setup.cfg is present
      • Handle additional edge cases for setuptools metadata migration
      • Support boolean values for the config set command

      1.6.3 - 2022-10-24

      Fixed:

      • Fix version command when the version is dynamic and build dependencies are unmet

      1.6.2 - 2022-10-20

      Fixed:

      • Fix getting dynamic metadata from hooks for environments when dependencies are not dynamic

      1.6.1 - 2022-10-16

      Fixed:

      • Computing the path to the user's home directory now gracefully falls back to ~ when it cannot be determined

      1.6.0 - 2022-10-08

      Changed:

      • The run_shell_command environment interface method now accepts arbitrary subprocess.Popen keyword arguments. This is not strictly breaking, but will be utilized in upcoming features.
      • The internal directory structure for storing virtual environments is now more nested. This is not breaking, but any local environments will be created anew.

      Added:

      • Add project command group to view details about the project like PEP 621 metadata
      • Better support for auto-detection of environments by tools like Visual Studio Code now that the storage directory of virtual environments will be flat if Hatch's configured virtual environment directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
      • Build environments for the virtual environment type are now cached for improved performance
      • Add build_environment_exists method to the environment interface for implementations that cache the build environment
      • Add path option to the virtual environment type
      • Add --initialize-auth flag to the index publisher to allow for the saving of authentication information before publishing
      • Support Bash on Windows for the shell command
      • The setuptools migration script no longer modifies the formatting of existing pyproject.toml configuration
      • Bump the minimum supported version of Hatchling to 1.11.0

      Fixed:

      • Environments now respect dynamically defined project dependencies
      • The dep hash and all dep show commands now respect dynamically defined project dependencies
      • The env show, dep hash, and all dep show commands now honor context formatting
      • Fix matrix variable inclusion filtering of the run and env run commands when there are multiple possible variables
      • Build environment compatibility is now checked before use
      • Decreasing verbosity now has no affect on output that should always be displayed
      • Handle more edge cases in the setuptools migration script
      • Environments now respect user defined environment variables for context formatting
      • Update the scripts in the generated test environment template for new projects to reflect the documentation
      • Allow extra-dependencies in environment overrides
      • Depend on packaging explicitly rather than relying on it being a transitive dependency of Hatchling

      1.5.0 - 2022-08-28

      Added:

      • The index publisher now recognizes repository-specific options
      • Add the --ignore-compat flag to the env run command
      • Setting the HATCH_PYTHON environment variable to self will now force the use of the Python executable Hatch is running on for virtual environment creation

      Fixed:

      • Fix the --force-continue flag of the env run command
      • Handle more edge cases in the setuptools migration script

      1.4.2 - 2022-08-16

      Fixed:

      • Fix check for updating static versions with the version command when metadata hooks are in use

      1.4.1 - 2022-08-13

      Fixed:

      • Fix non-detached inheritance disabling for environments

      1.4.0 - 2022-08-06

      Added:

      • The default Python for virtual environments now checks PATH before using the one Hatch is running on
      • Values for environment env-vars now support context formatting
      • Add name override for environments to allow for regular expression matching
      • The index publisher now better supports non-PyPI indices
      • Add certificate options to the index publisher
      • Display waiting text when checking dependencies and removing environments
      • Display help text the first time the shell command is executed
      • Update project templates with Python 3.11 and the latest versions of various GitHub Actions
      • Add support for Almquist (ash) shells
      • Add hyperlink as a dependency for better handling of package index URLs
      • Bump the minimum supported version of virtualenv to 20.16.2
      • Bump the minimum supported version of tomlkit to 0.11.1

      Fixed:

      • Acknowledge extra-dependencies for the env show command
      • Fix locating executables within virtual environments on Debian
      • Fix managing the terminal size inside the shell command
      • Fix default code coverage file omission for the src-layout project template option

      1.3.1 - 2022-07-11

      Fixed:

      • Support -h/--help flag for the run command

      1.3.0 - 2022-07-10

      Changed:

      • Rename the default publishing plugin from pypi to the more generic index

      Added:

      • Support the absence of pyproject.toml files, as is the case for apps and non-Python projects
      • Hide scripts that start with an underscore for the env show command by default
      • Ignoring the exit codes of commands by prefixing with hyphens now works with entire named scripts
      • Add a way to require confirmation for publishing
      • Add --force-continue flag to the env run command
      • Make tracebacks colorful and less verbose
      • When shell configuration has not been defined, attempt to use the current shell based on parent processes before resorting to the defaults
      • The shell name pwsh is now an alias for powershell
      • Remove atomicwrites dependency
      • Relax constraint on userpath dependency
      • Bump the minimum supported version of Hatchling to 1.4.1

      Fixed:

      • Keep environments in sync with the dependencies of the selected features
      • Use utf-8 for all files generated for new projects
      • Escape special characters Git may return in the user name when writing generated files for new projects
      • Normalize the package name to lowercase in setuptools migration script
      • Fix parsing of source distributions during publishing

      1.2.1 - 2022-05-30

      Fixed:

      • Fix handling of top level data_files in setuptools migration script

      1.2.0 - 2022-05-22

      Changed:

      • The enter_shell environment plugin method now accepts an additional args parameter

      Added:

      • Allow context string formatting for environment dependencies
      • Add environment context string formatting fields env_name, env_type, matrix, verbosity, and args
      • Support overriding the default arguments used to spawn shells on non-Windows systems
      • Bump the minimum supported version of Hatchling to 1.3.0

      Fixed:

      • Improve setuptools migration script

      1.1.2 - 2022-05-20

      Fixed:

      • Bump the minimum supported version of Hatchling to 1.2.0
      • Update project metadata to reflect support for Python 3.11

      1.1.1 - 2022-05-12

      Fixed:

      • Fix setuptools migration script for non-Windows systems

      1.1.0 - 2022-05-12

      Changed:

      • In order to simplify the implementation of command execution for environment plugins, the run_shell_commands method has been replaced by the singular run_shell_command. A new command_context method has been added to more easily satisfy complex use cases.
      • The finalize_command environment plugin method has been removed in favor of the newly introduced context formatting functionality.

      Added:

      • Add context formatting functionality i.e. the ability to insert values into configuration like environment variables and command line arguments
      • Any verbosity for command execution will now always display headers, even for single environments
      • Every executed command is now displayed when running multiple commands or when verbosity is enabled
      • Similar to make, ignore the exit code of executed commands that start with - (a hyphen)
      • Add ability for the --init flag of the new command to automatically migrate setuptools configuration
      • Update project metadata to reflect the adoption by PyPA and production stability

      1.0.0 - 2022-04-28

      This is the first stable release of Hatch v1, a complete rewrite. Enjoy!

      \ No newline at end of file diff --git a/latest/history/hatchling/index.html b/latest/history/hatchling/index.html index 0d59e601a..a05b118c7 100644 --- a/latest/history/hatchling/index.html +++ b/latest/history/hatchling/index.html @@ -1,4 +1,4 @@ - Hatchling - Hatch

      Hatchling history


      All notable changes to Hatchling will be documented in this file.

      The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

      Unreleased

      1.21.0 - 2023-12-18

      Added:

      • Add parent context modifier for path fields

      1.20.0 - 2023-12-13

      Added:

      • Add bypass-selection option to the wheel build target to allow for empty (metadata-only) wheels

      Fixed:

      • Fix regression in 1.19.1 that allowed exclude to count toward inclusion selection, thus bypassing the default inclusion selection heuristics
      • Fix writing optional dependency core metadata in situations where there are multiple environment markers

      1.19.1 - 2023-12-12

      Fixed:

      • Add better error message when the wheel build target cannot determine what to ship
      • Consider forced inclusion patterns and build-time artifacts as file selection since some build hooks generate the entire wheel contents without user configuration

      1.19.0 - 2023-12-11

      Changed:

      • An error will now be raised if a force-included path does not exist
      • An error will now be raised for the wheel build target if no file selection options are defined

      Added:

      • Officially support Python 3.12
      • Allow using an empty string for the sources option to add a prefix to distribution paths

      Fixed:

      • Properly handle non-zero version epoch for the standard version scheme
      • Fix the wheel build target for case insensitive file systems when the project metadata name does not match the directory name on disk
      • The app build target no longer has suppressed output
      • Prevent duplicate paths when projects require the sources option while build hooks overwrite included paths
      • Properly escape spaces for URI context formatting

      1.18.0 - 2023-06-12

      Changed:

      • Drop support for Python 3.7

      Added:

      • Update the list of directories that are always excluded for builds

      1.17.1 - 2023-06-03

      Fixed:

      • Fix dev mode when the project has symlinks and file inclusion is defined with the packages or only-include options
      • Change the name of generated PTH files for dev mode so they come first lexicographically and therefore load first

      1.17.0 - 2023-05-12

      Added:

      • The app build target now embeds the project version in the name of binaries

      1.16.1 - 2023-05-11

      Fixed:

      • Fix determining the built executable path for the app build target option when using a local copy of PyApp when there is an explicit target triple set

      1.16.0 - 2023-05-11

      Added:

      • Add app build target option to build using a local copy of the PyApp repository

      1.15.0 - 2023-05-09

      Added:

      • Add app build target

      1.14.1 - 2023-04-23

      Fixed:

      • Fix internal archive root naming for the sdist target when strict-naming is disabled to match the file name in order to support the expectation of some frontends

      1.14.0 - 2023-04-02

      Added:

      • Add trove-classifiers as a dependency

      Fixed:

      • Properly normalize metadata descriptions that contain line breaks

      1.13.0 - 2023-02-09

      Added:

      • Update the set of known trove classifiers to version 2023.2.8

      1.12.2 - 2023-01-05

      Fixed:

      • Add macos-max-compat option to the wheel target that is enabled by default to support the latest version 22.0 of the packaging library

      1.12.1 - 2022-12-31

      Fixed:

      • Fix minor regression in the PEP 517/660 function signatures that was discovered by Fedora

      1.12.0 - 2022-12-30

      Added:

      • Improve readability of exceptions
      • Add extra_metadata build data to the wheel target
      • Retroactively support License-Expression core metadata starting at version 2.1
      • Add more type hints
      • Update the set of known trove classifiers to version 2022.12.22
      • Update SPDX license information to version 3.19
      • Store Hatchling's metadata in pyproject.toml

      Fixed:

      • Acknowledge the ARCHFLAGS environment variable on macOS for the wheel target when build hooks set the infer_tag build data to true
      • Fix dependency checking when encountering broken distributions
      • Fix the support-legacy option for the sdist target when using a src-layout project structure
      • Remove unnecessary encoding declaration in the default template for the version build hook

      1.11.1 - 2022-10-19

      Fixed:

      • Fix default file selection behavior of the wheel target when there is a single top-level module

      1.11.0 - 2022-10-08

      Added:

      • Add env version source to retrieve the version from an environment variable
      • Add validate-bump option to the standard version scheme

      Fixed:

      • Use proper CSV formatting for the RECORD metadata file of the wheel target to avoid warnings during installation by pip if, for example, file names contain commas
      • Fix installations with pip for build hooks that modify runtime dependencies
      • Decreasing verbosity now has no affect on output that should always be displayed

      1.10.0 - 2022-09-18

      Added:

      • Add the following to the list of directories that cannot be traversed: __pypackages__, .hg, .hatch, .tox, .nox
      • Add deprecated option to allow ambiguous features

      Fixed:

      • Improve tracking of dynamic metadata
      • Fix core metadata for entries in project.optional-dependencies that use direct references

      1.9.0 - 2022-09-09

      Changed:

      • File pattern matching now more closely resembles Git's behavior

      Added:

      • Implement a minimal version of prepare_metadata_for_build_wheel and prepare_metadata_for_build_editable for non-frontend tools that only need to inspect a project's metadata
      • Add metadata command to view PEP 621 project metadata
      • Improve error messages for SPDX license errors
      • Retroactively support License-File for core metadata starting at version 2.1
      • Bump the minimum supported version of pathspec to 0.10.1

      Fixed:

      • Allow the valid non-SPDX license values LicenseRef-Public-Domain and LicenseRef-Proprietary
      • Show the help text of the CLI when no subcommand is selected

      1.8.1 - 2022-08-25

      Fixed:

      • Fix default file inclusion for wheel build targets when both the project name and package directory name are not normalized

      1.8.0 - 2022-08-16

      Added:

      • Add get_known_classifiers method to metadata hooks

      Fixed:

      • Fix check for updating static versions with the version command when metadata hooks are in use

      1.7.1 - 2022-08-13

      Fixed:

      • Fix the value of the relative_path attribute of included files, that some build plugins may use, when selecting explicit paths

      1.7.0 - 2022-08-12

      Added:

      • Add require-runtime-features option for builders and build hooks
      • Check for unknown trove classifiers
      • Update SPDX license information to version 3.18

      Fixed:

      • Add better error message for wheel target dev mode installations that define path rewrites with the sources option
      • Note the allow-direct-references option in the relevant error messages

      1.6.0 - 2022-07-23

      Changed:

      • When no build targets are specified on the command line, now default to sdist and wheel targets rather than what happens to be defined in config
      • The code version source now only supports files with known extensions
      • Global build hooks now run before target-specific build hooks to better match expected behavior

      Added:

      • The code version source now supports loading extension modules
      • Add search-paths option for the code version source

      Fixed:

      • Fix removing sources using an empty string value in the mapping
      • The strict-naming option now also applies to the metadata directory of wheel targets

      1.5.0 - 2022-07-11

      Added:

      • Support the final draft of PEP 639
      • Add strict-naming option for sdist and wheel targets

      Fixed:

      • Project names are now stored in sdist and wheel target core metadata exactly as defined in pyproject.toml without normalization to allow control of how PyPI displays them

      1.4.1 - 2022-07-04

      Fixed:

      • Fix forced inclusion of important files like licenses for sdist targets when using the explicit selection options
      • Don't sort project URL metadata so that the rendered order on PyPI can be controlled

      1.4.0 - 2022-07-03

      Changed:

      • The packages option uses the new only-include option to provide targeted inclusion, since that is desired most of the time. You can retain the old behavior by using the include and sources options together.

      Added:

      • Support PEP 561 type hinting
      • Add version build hook
      • Add only-include option
      • The editable version of wheel targets now respects the force-include option by default
      • The force-include option now supports path rewriting with the sources option
      • The wheel target shared-data and extra-metadata options now respect file selection options
      • The wheel target now auto-detects single module layouts
      • Improve performance by never entering directories that are guaranteed to be undesirable like __pycache__ rather than excluding individual files within
      • Update SPDX license information to version 3.17

      Fixed:

      • Don't write empty entry points file for wheel targets if there are no entry points defined
      • Allow metadata hooks to set the version in all cases
      • Prevent duplicate file entries from inclusion when using the force-include option

      1.3.1 - 2022-05-30

      Fixed:

      • Better populate global variables for the code version source

      1.3.0 - 2022-05-22

      Removed:

      • Remove unused global args context string formatting field

      Added:

      • Improve error messages for the env context string formatting field

      Fixed:

      • Fix uri context string formatting modifier on Windows

      1.2.0 - 2022-05-20

      Added:

      • Allow context formatting for project.dependencies and project.optional-dependencies

      1.1.0 - 2022-05-19

      Added:

      • Add uri and real context string formatting modifiers for file system paths

      1.0.0 - 2022-05-17

      Changed:

      • Drop support for Python 2

      Added:

      • Improve error messaging for invalid versions
      • Update project metadata to reflect support for Python 3.11

      0.25.1 - 2022-06-14

      Fixed:

      • Fix support for Windows on Python 2 by removing its support for symlinks

      0.25.0 - 2022-05-15

      Added:

      • Add skip-excluded-dirs build option
      • Allow build data to add additional project dependencies for wheel and sdist build targets
      • Add force_include_editable build data for the wheel build target
      • Add build_hooks build data
      • Add support for Mercurial's .hgignore files when using glob syntax
      • Update project metadata to reflect the adoption by PyPA

      Fixed:

      • Properly use underscores for the name of force_include build data
      • No longer greedily skip excluded directories by default

      0.24.0 - 2022-04-28

      This is the initial public release of the Hatchling build system. Support for Python 2 will be dropped in version 1.

      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Hatchling history


      All notable changes to Hatchling will be documented in this file.

      The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

      Unreleased

      1.22.4 - 2024-03-23

      Fixed:

      • Only read source distribution metadata for fields that are explicitly defined as dynamic

      1.22.3 - 2024-03-19

      Fixed:

      • Fix the custom build hook when using dynamic dependencies

      1.22.2 - 2024-03-16

      Fixed:

      • Fix regression when loading metadata from source distributions
      • Fix metadata hooks when building wheels from source distributions

      1.22.1 - 2024-03-16

      Fixed:

      • Update the default version of core metadata to 2.3

      1.22.0 - 2024-03-16

      Deprecated:

      • The app build target has been renamed to binary to reduce ambiguity with the name of an upcoming feature. The former name will still be usable for several minor releases.

      Added:

      • Metadata for the wheel target now defaults to the PKG-INFO metadata within source distributions
      • Add dependencies method to the build hook interface so that hooks can themselves dynamically define dependencies
      • Update the default version of core metadata to 2.2
      • Update SPDX license information to version 3.23
      • Improve error message for when the default heuristics for wheel file inclusion fail

      Fixed:

      • Properly support core metadata version 2.2
      • Remove editables as a direct dependency
      • Fix default wheel tag when the supported Python version declaration is strict
      • Load VCS ignore patterns first so that whitelisted patterns can be excluded by project configuration
      • Don't consider VCS ignore files that are outside of the VCS boundary
      • The sdist build target now gracefully ignores UNIX socket files
      • Begin ignoring certain files ubiquitously, like .DS_Store on macOS

      1.21.1 - 2024-01-25

      Fixed:

      • Fix loading of local plugins to account for newly released versions of a dependency

      1.21.0 - 2023-12-18

      Added:

      • Add parent context modifier for path fields

      1.20.0 - 2023-12-13

      Added:

      • Add bypass-selection option to the wheel build target to allow for empty (metadata-only) wheels

      Fixed:

      • Fix regression in 1.19.1 that allowed exclude to count toward inclusion selection, thus bypassing the default inclusion selection heuristics
      • Fix writing optional dependency core metadata in situations where there are multiple environment markers

      1.19.1 - 2023-12-12

      Fixed:

      • Add better error message when the wheel build target cannot determine what to ship
      • Consider forced inclusion patterns and build-time artifacts as file selection since some build hooks generate the entire wheel contents without user configuration

      1.19.0 - 2023-12-11

      Changed:

      • An error will now be raised if a force-included path does not exist
      • An error will now be raised for the wheel build target if no file selection options are defined

      Added:

      • Officially support Python 3.12
      • Allow using an empty string for the sources option to add a prefix to distribution paths

      Fixed:

      • Properly handle non-zero version epoch for the standard version scheme
      • Fix the wheel build target for case insensitive file systems when the project metadata name does not match the directory name on disk
      • The app build target no longer has suppressed output
      • Prevent duplicate paths when projects require the sources option while build hooks overwrite included paths
      • Properly escape spaces for URI context formatting

      1.18.0 - 2023-06-12

      Changed:

      • Drop support for Python 3.7

      Added:

      • Update the list of directories that are always excluded for builds

      1.17.1 - 2023-06-03

      Fixed:

      • Fix dev mode when the project has symlinks and file inclusion is defined with the packages or only-include options
      • Change the name of generated PTH files for dev mode so they come first lexicographically and therefore load first

      1.17.0 - 2023-05-12

      Added:

      • The app build target now embeds the project version in the name of binaries

      1.16.1 - 2023-05-11

      Fixed:

      • Fix determining the built executable path for the app build target option when using a local copy of PyApp when there is an explicit target triple set

      1.16.0 - 2023-05-11

      Added:

      • Add app build target option to build using a local copy of the PyApp repository

      1.15.0 - 2023-05-09

      Added:

      • Add app build target

      1.14.1 - 2023-04-23

      Fixed:

      • Fix internal archive root naming for the sdist target when strict-naming is disabled to match the file name in order to support the expectation of some frontends

      1.14.0 - 2023-04-02

      Added:

      • Add trove-classifiers as a dependency

      Fixed:

      • Properly normalize metadata descriptions that contain line breaks

      1.13.0 - 2023-02-09

      Added:

      • Update the set of known trove classifiers to version 2023.2.8

      1.12.2 - 2023-01-05

      Fixed:

      • Add macos-max-compat option to the wheel target that is enabled by default to support the latest version 22.0 of the packaging library

      1.12.1 - 2022-12-31

      Fixed:

      • Fix minor regression in the PEP 517/660 function signatures that was discovered by Fedora

      1.12.0 - 2022-12-30

      Added:

      • Improve readability of exceptions
      • Add extra_metadata build data to the wheel target
      • Retroactively support License-Expression core metadata starting at version 2.1
      • Add more type hints
      • Update the set of known trove classifiers to version 2022.12.22
      • Update SPDX license information to version 3.19
      • Store Hatchling's metadata in pyproject.toml

      Fixed:

      • Acknowledge the ARCHFLAGS environment variable on macOS for the wheel target when build hooks set the infer_tag build data to true
      • Fix dependency checking when encountering broken distributions
      • Fix the support-legacy option for the sdist target when using a src-layout project structure
      • Remove unnecessary encoding declaration in the default template for the version build hook

      1.11.1 - 2022-10-19

      Fixed:

      • Fix default file selection behavior of the wheel target when there is a single top-level module

      1.11.0 - 2022-10-08

      Added:

      • Add env version source to retrieve the version from an environment variable
      • Add validate-bump option to the standard version scheme

      Fixed:

      • Use proper CSV formatting for the RECORD metadata file of the wheel target to avoid warnings during installation by pip if, for example, file names contain commas
      • Fix installations with pip for build hooks that modify runtime dependencies
      • Decreasing verbosity now has no affect on output that should always be displayed

      1.10.0 - 2022-09-18

      Added:

      • Add the following to the list of directories that cannot be traversed: __pypackages__, .hg, .hatch, .tox, .nox
      • Add deprecated option to allow ambiguous features

      Fixed:

      • Improve tracking of dynamic metadata
      • Fix core metadata for entries in project.optional-dependencies that use direct references

      1.9.0 - 2022-09-09

      Changed:

      • File pattern matching now more closely resembles Git's behavior

      Added:

      • Implement a minimal version of prepare_metadata_for_build_wheel and prepare_metadata_for_build_editable for non-frontend tools that only need to inspect a project's metadata
      • Add metadata command to view PEP 621 project metadata
      • Improve error messages for SPDX license errors
      • Retroactively support License-File for core metadata starting at version 2.1
      • Bump the minimum supported version of pathspec to 0.10.1

      Fixed:

      • Allow the valid non-SPDX license values LicenseRef-Public-Domain and LicenseRef-Proprietary
      • Show the help text of the CLI when no subcommand is selected

      1.8.1 - 2022-08-25

      Fixed:

      • Fix default file inclusion for wheel build targets when both the project name and package directory name are not normalized

      1.8.0 - 2022-08-16

      Added:

      • Add get_known_classifiers method to metadata hooks

      Fixed:

      • Fix check for updating static versions with the version command when metadata hooks are in use

      1.7.1 - 2022-08-13

      Fixed:

      • Fix the value of the relative_path attribute of included files, that some build plugins may use, when selecting explicit paths

      1.7.0 - 2022-08-12

      Added:

      • Add require-runtime-features option for builders and build hooks
      • Check for unknown trove classifiers
      • Update SPDX license information to version 3.18

      Fixed:

      • Add better error message for wheel target dev mode installations that define path rewrites with the sources option
      • Note the allow-direct-references option in the relevant error messages

      1.6.0 - 2022-07-23

      Changed:

      • When no build targets are specified on the command line, now default to sdist and wheel targets rather than what happens to be defined in config
      • The code version source now only supports files with known extensions
      • Global build hooks now run before target-specific build hooks to better match expected behavior

      Added:

      • The code version source now supports loading extension modules
      • Add search-paths option for the code version source

      Fixed:

      • Fix removing sources using an empty string value in the mapping
      • The strict-naming option now also applies to the metadata directory of wheel targets

      1.5.0 - 2022-07-11

      Added:

      • Support the final draft of PEP 639
      • Add strict-naming option for sdist and wheel targets

      Fixed:

      • Project names are now stored in sdist and wheel target core metadata exactly as defined in pyproject.toml without normalization to allow control of how PyPI displays them

      1.4.1 - 2022-07-04

      Fixed:

      • Fix forced inclusion of important files like licenses for sdist targets when using the explicit selection options
      • Don't sort project URL metadata so that the rendered order on PyPI can be controlled

      1.4.0 - 2022-07-03

      Changed:

      • The packages option uses the new only-include option to provide targeted inclusion, since that is desired most of the time. You can retain the old behavior by using the include and sources options together.

      Added:

      • Support PEP 561 type hinting
      • Add version build hook
      • Add only-include option
      • The editable version of wheel targets now respects the force-include option by default
      • The force-include option now supports path rewriting with the sources option
      • The wheel target shared-data and extra-metadata options now respect file selection options
      • The wheel target now auto-detects single module layouts
      • Improve performance by never entering directories that are guaranteed to be undesirable like __pycache__ rather than excluding individual files within
      • Update SPDX license information to version 3.17

      Fixed:

      • Don't write empty entry points file for wheel targets if there are no entry points defined
      • Allow metadata hooks to set the version in all cases
      • Prevent duplicate file entries from inclusion when using the force-include option

      1.3.1 - 2022-05-30

      Fixed:

      • Better populate global variables for the code version source

      1.3.0 - 2022-05-22

      Removed:

      • Remove unused global args context string formatting field

      Added:

      • Improve error messages for the env context string formatting field

      Fixed:

      • Fix uri context string formatting modifier on Windows

      1.2.0 - 2022-05-20

      Added:

      • Allow context formatting for project.dependencies and project.optional-dependencies

      1.1.0 - 2022-05-19

      Added:

      • Add uri and real context string formatting modifiers for file system paths

      1.0.0 - 2022-05-17

      Changed:

      • Drop support for Python 2

      Added:

      • Improve error messaging for invalid versions
      • Update project metadata to reflect support for Python 3.11

      0.25.1 - 2022-06-14

      Fixed:

      • Fix support for Windows on Python 2 by removing its support for symlinks

      0.25.0 - 2022-05-15

      Added:

      • Add skip-excluded-dirs build option
      • Allow build data to add additional project dependencies for wheel and sdist build targets
      • Add force_include_editable build data for the wheel build target
      • Add build_hooks build data
      • Add support for Mercurial's .hgignore files when using glob syntax
      • Update project metadata to reflect the adoption by PyPA

      Fixed:

      • Properly use underscores for the name of force_include build data
      • No longer greedily skip excluded directories by default

      0.24.0 - 2022-04-28

      This is the initial public release of the Hatchling build system. Support for Python 2 will be dropped in version 1.

      \ No newline at end of file diff --git a/latest/how-to/config/dynamic-metadata/index.html b/latest/how-to/config/dynamic-metadata/index.html new file mode 100644 index 000000000..77b890814 --- /dev/null +++ b/latest/how-to/config/dynamic-metadata/index.html @@ -0,0 +1,30 @@ + How to configure custom dynamic metadata - Hatch

      How to configure custom dynamic metadata


      If you have project metadata that is not appropriate for static entry into pyproject.toml you will need to provide a custom metadata hook to apply such data during builds.

      Alternatives

      Dynamic metadata is a way to have a single source of truth that will be available at build time and at run time. Another way to achieve that is to enter the build data statically and then look up the same information dynamically in the program or package, using importlib.metadata.

      If the version field is the only metadata of concern, Hatchling provides a few built-in ways such as the regex version source and also third-party plugins. The approach here will also work, but is more complex.

      Update project metadata

      Change the [project] section of pyproject.toml:

      1. Define the dynamic field as an array of all the fields you will set dynamically e.g. dynamic = ["version", "license", "authors", "maintainers"]
      2. If any of those fields have static definitions in pyproject.toml, delete those definitions. It is verboten to define a field statically and dynamically.

      Add a section to trigger loading of dynamic metadata plugins: [tool.hatch.metadata.hooks.custom]. Use exactly that name, regardless of the name of the class you will use or its PLUGIN_NAME. There doesn't need to be anything in the section.

      If your plugin requires additional third-party packages to do its work, add them to the requires array in the [build-system] section of pyproject.toml.

      Implement hook

      The dynamic lookup must happen in a custom plugin that you write. The default expectation is that it is in a hatch_build.py file at the root of the project. Subclass MetadataHookInterface and implement update(); for example, here's plugin that reads metadata from a JSON file:

      import json
      +import os
      +
      +from hatchling.metadata.plugin.interface import MetadataHookInterface
      +
      +
      +class JSONMetaDataHook(MetadataHookInterface):
      +    def update(self, metadata):
      +        src_file = os.path.join(self.root, "gnumeric", ".constants.json")
      +        with open(src_file) as src:
      +            constants = json.load(src)
      +            metadata["version"] = constants["__version__"]
      +            metadata["license"] = constants["__license__"]
      +            metadata["authors"] = [
      +                {"name": constants["__author__"], "email": constants["__author_email__"]},
      +            ]
      +
      1. You must import the MetadataHookInterface to subclass it.
      2. Do your operations inside the update method.
      3. metadata refers to project metadata.
      4. When writing to metadata, use list for TOML arrays. Note that if a list is expected, it is required even if there is a single element.
      5. Use dict for TOML tables e.g. authors.

      If you want to store the hook in a different location, set the path option:

      [tool.hatch.metadata.hooks.custom]
      +path = "some/where.py"
      +
      [metadata.hooks.custom]
      +path = "some/where.py"
      +
      \ No newline at end of file diff --git a/latest/how-to/environment/package-indices/index.html b/latest/how-to/environment/package-indices/index.html index c6987637e..491b9ccf4 100644 --- a/latest/how-to/environment/package-indices/index.html +++ b/latest/how-to/environment/package-indices/index.html @@ -1,4 +1,4 @@ - Package indices - Hatch

      Package indices


      Most Hatch environment types, like the default virtual, simply use pip to install dependencies. Therefore, you can use the standard environment variables that influence pip's behavior to choose where to search for packages.

      Here's an example of setting up the default environment to look at 2 private indices (using context formatting for authentication) before finally falling back to PyPI:

      [tool.hatch.envs.default.env-vars]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      How to configure package indices


      Most Hatch environment types, like the default virtual, simply use pip to install dependencies. Therefore, you can use the standard environment variables that influence pip's behavior to choose where to search for packages.

      Here's an example of setting up the default environment to look at 2 private indices (using context formatting for authentication) before finally falling back to PyPI:

      [tool.hatch.envs.default.env-vars]
       PIP_INDEX_URL = "https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/"
       PIP_EXTRA_INDEX_URL = "https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/"
       
      [envs.default.env-vars]
       PIP_INDEX_URL = "https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/"
       PIP_EXTRA_INDEX_URL = "https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/"
      -
      \ No newline at end of file +
      \ No newline at end of file diff --git a/latest/how-to/meta/report-issues/index.html b/latest/how-to/meta/report-issues/index.html new file mode 100644 index 000000000..c01f481aa --- /dev/null +++ b/latest/how-to/meta/report-issues/index.html @@ -0,0 +1,13 @@ + How to report issues - Hatch

      How to report issues


      All reports regarding unexpected behavior should be generated with the self report command:

      $ hatch self report
      +

      By default, this will open a new tab in your default browser with pre-populated information about your environment.

      If Hatch is not installed alongside a web browser, you may also pass the --no-open/-n command which will output the URL with correct parameters for copying elsewhere:

      $ hatch self report -n
      +https://github.com/pypa/hatch/issues/new?body=%23%23+Current+behavior%0A%3C%21--+A+clear+and+concise+description+of+the+behavior.+--%3E%0A%0A%23%23+Expected+behavior%0A%3C%21--+A+clear+and+concise+description+of+what+you+expected+to+happen.+--%3E%0A%0A%23%23+Additional+context%0A%3C%21--+Add+any+other+context+about+the+problem+here.+If+applicable%2C+add+screenshots+to+help+explain.+--%3E%0A%0A%23%23+Debug%0A%0A%23%23%23+Installation%0A%0A-+Source%3A+pip%0A-+Version%3A+1.9.2.dev5%0A-+Platform%3A+Windows%0A-+Python+version%3A%0A++++%60%60%60%0A++++3.11.1+%28tags%2Fv3.11.1%3Aa7a450f%2C+Dec++6+2022%2C+19%3A58%3A39%29+%5BMSC+v.1934+64+bit+%28AMD64%29%5D%0A++++%60%60%60%0A%0A%23%23%23+Configuration%0A%0A%60%60%60toml%0Amode+%3D+%22local%22%0Ashell+%3D+%22nu%22%0A%60%60%60%0A
      +
      \ No newline at end of file diff --git a/latest/how-to/plugins/testing-builds/index.html b/latest/how-to/plugins/testing-builds/index.html index 75bde32e8..9ac8ce8ff 100644 --- a/latest/how-to/plugins/testing-builds/index.html +++ b/latest/how-to/plugins/testing-builds/index.html @@ -1,4 +1,4 @@ - Testing builds - Hatch

      Testing builds


      For testing Hatchling plugins, you'll usually want to generate a project to execute builds as a real user would. For example, as a minimal pytest fixture:

      from pathlib import Path
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Testing build plugins


      For testing Hatchling plugins, you'll usually want to generate a project to execute builds as a real user would. For example, as a minimal pytest fixture:

      from pathlib import Path
       
       import pytest
       
      @@ -68,4 +68,4 @@
               encoding='utf-8',
           )
           ...
      -

      Note

      This example chooses to ignore copying .git for performance reasons. You may want to ignore more patterns, or copy only specific paths like this plugin does.

      \ No newline at end of file +

      Note

      This example chooses to ignore copying .git for performance reasons. You may want to ignore more patterns, or copy only specific paths like this plugin does.

      \ No newline at end of file diff --git a/latest/how-to/publish/auth/index.html b/latest/how-to/publish/auth/index.html new file mode 100644 index 000000000..13cbd710b --- /dev/null +++ b/latest/how-to/publish/auth/index.html @@ -0,0 +1,10 @@ + How to authenticate for index publishing - Hatch

      How to authenticate for index publishing


      The username is derived from the following sources, in order of precedence:

      1. The --user / -u cli option.
      2. The HATCH_INDEX_USER environment variable.
      3. The repos tables.
      4. The ~/.pypirc file.
      5. The input to an interactive prompt.

      As a fallback the value __token__ is applied.

      The password is looked up in these:

      1. The ~/.pypirc file if the username was provided by it.
      2. The --auth / -a cli option.
      3. The HATCH_INDEX_AUTH environment variable.
      4. The repos tables.
      5. A variety of OS-level credentials services backed by keyring.
      6. The input to an interactive prompt.

      If interactively provided credentials were used, the username will be stored in Hatch's cache and the password stored in the available keyring backed credentials stores.

      For automated releasing to PyPI, it is recommended to use "Trusted Publishing" with OIDC (e.g. PyPA's pypi-publish GitHub Action) or per-project API tokens.

      \ No newline at end of file diff --git a/latest/how-to/publish/repo/index.html b/latest/how-to/publish/repo/index.html new file mode 100644 index 000000000..db6f49e4e --- /dev/null +++ b/latest/how-to/publish/repo/index.html @@ -0,0 +1,13 @@ + How to configure repositories for index publishing - Hatch

      How to configure repositories for index publishing


      You can select the repository with which to upload using the -r/--repo option or by setting the HATCH_INDEX_REPO environment variable.

      Rather than specifying the full URL of a repository, you can use a named repository from a publish.index.repos table defined in Hatch's config file:

      [publish.index.repos.private]
      +url = "..."
      +...
      +

      The following repository names are reserved by Hatch and cannot be overridden:

      Name Repository
      main https://upload.pypi.org/legacy/
      test https://test.pypi.org/legacy/

      The main repository is used by default.

      \ No newline at end of file diff --git a/latest/how-to/static-analysis/behavior/index.html b/latest/how-to/static-analysis/behavior/index.html new file mode 100644 index 000000000..7f75584af --- /dev/null +++ b/latest/how-to/static-analysis/behavior/index.html @@ -0,0 +1,38 @@ + Customize static analysis behavior - Hatch

      Customize static analysis behavior


      You can fully alter the static analysis performed by the fmt command by modifing the reserved environment named hatch-static-analysis. For example, you could define the following if you wanted to replace the default behavior with a mix of Black, isort and basic flake8:

      [tool.hatch.envs.hatch-static-analysis]
      +dependencies = ["black", "flake8", "isort"]
      +
      +[tool.hatch.envs.hatch-static-analysis.scripts]
      +format-check = [
      +  "black --check --diff {args:.}",
      +  "isort --check-only --diff {args:.}",
      +]
      +format-fix = [
      +  "isort {args:.}",
      +  "black {args:.}",
      +]
      +lint-check = "flake8 {args:.}"
      +lint-fix = "lint-check"
      +
      [envs.hatch-static-analysis]
      +dependencies = ["black", "flake8", "isort"]
      +
      +[envs.hatch-static-analysis.scripts]
      +format-check = [
      +  "black --check --diff {args:.}",
      +  "isort --check-only --diff {args:.}",
      +]
      +format-fix = [
      +  "isort {args:.}",
      +  "black {args:.}",
      +]
      +lint-check = "flake8 {args:.}"
      +lint-fix = "lint-check"
      +

      The format-* scripts correspond to the --formatter/-f flag while the lint-* scripts correspond to the --linter/-l flag. The *-fix scripts run by default while the *-check scripts correspond to the --check flag. Based on this example, the following shows how the various scripts influence behavior:

      Command Expanded scripts
      hatch fmt
      • flake8 .
      • isort .
      • black .
      hatch fmt src tests
      • flake8 src tests
      • isort src tests
      • black src tests
      hatch fmt -f
      • isort .
      • black .
      hatch fmt -l
      • flake8 .
      hatch fmt --check
      • flake8 .
      • black --check --diff .
      • isort --check-only --diff .
      hatch fmt --check -f
      • black --check --diff .
      • isort --check-only --diff .
      hatch fmt --check -l
      • flake8 .
      \ No newline at end of file diff --git a/latest/index.html b/latest/index.html index b3835073c..6a322f66a 100644 --- a/latest/index.html +++ b/latest/index.html @@ -1,4 +1,4 @@ - About - Hatch

      Hatch

      Hatch logo

      CI/CD CI - Test CD - Build Hatch CD - Build Hatchling
      Docs Docs - Release Docs - Dev
      Package PyPI - Version PyPI - Downloads PyPI - Python Version
      Meta Hatch project linting - Ruff types - Mypy License - MIT GitHub Sponsors

      Hatch is a modern, extensible Python project manager. See the Why Hatch? page for more information.

      • Build system


        Reproducible builds by default with a rich ecosystem of plugins

        Configure builds

      • Environments


        Robust environment management with support for custom scripts

        Getting started

      • Python management


        Choose between easy manual installations or automatic as part of environments

        Try it

      • Static analysis


        Static analysis backed by Ruff with up-to-date, sane defaults

        Learn

      • Publishing


        Easily upload to PyPI or other indices

        See how

      • Versioning


        Streamlined workflow for bumping versions

        Managing versions

      • Project generation


        Create new projects from templates with known best practices

        Project setup

      • Responsive CLI


        Hatch is up to 3x faster than equivalent tools

        CLI reference

      License

      Hatch is distributed under the terms of the MIT license.

      Documentation for specific MAJOR.MINOR versions can be chosen by using the dropdown on the top of every page. The dev version reflects changes that have not yet been released.

      Also, desktop readers can use special keyboard shortcuts:

      Keys Action
      • , (comma)
      • p
      Navigate to the "previous" page
      • . (period)
      • n
      Navigate to the "next" page
      • /
      • s
      Display the search modal
      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Hatch

      Hatch logo

      CI/CD CI - Test CD - Build Hatch CD - Build Hatchling
      Docs Docs - Release Docs - Dev
      Package PyPI - Version PyPI - Downloads PyPI - Python Version
      Meta Hatch project linting - Ruff types - Mypy License - MIT GitHub Sponsors

      Hatch is a modern, extensible Python project manager. See the Why Hatch? page for more information.

      • Build system


        Reproducible builds by default with a rich ecosystem of plugins

        Configure builds

      • Environments


        Robust environment management with support for custom scripts

        Getting started

      • Python management


        Choose between easy manual installations or automatic as part of environments

        Try it

      • Static analysis


        Static analysis backed by Ruff with up-to-date, sane defaults

        Learn

      • Publishing


        Easily upload to PyPI or other indices

        See how

      • Versioning


        Streamlined workflow for bumping versions

        Managing versions

      • Project generation


        Create new projects from templates with known best practices

        Project setup

      • Responsive CLI


        Hatch is up to 3x faster than equivalent tools

        CLI reference

      License

      Hatch is distributed under the terms of the MIT license.

      Documentation for specific MAJOR.MINOR versions can be chosen by using the dropdown on the top of every page. The dev version reflects changes that have not yet been released.

      Also, desktop readers can use special keyboard shortcuts:

      Keys Action
      • , (comma)
      • p
      Navigate to the "previous" page
      • . (period)
      • n
      Navigate to the "next" page
      • /
      • s
      Display the search modal
      \ No newline at end of file diff --git a/latest/install/index.html b/latest/install/index.html index d738bfec7..d0a3c6fe5 100644 --- a/latest/install/index.html +++ b/latest/install/index.html @@ -7,18 +7,19 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Installation


      Installers

      1. In your browser, download the .pkg file: hatch-1.9.4.pkg
      2. Run your downloaded file and follow the on-screen instructions.
      3. Restart your terminal.
      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version
        -1.9.4
        -
      1. Download the file using the curl command. The -o option specifies the file name that the downloaded package is written to. In this example, the file is written to hatch-1.9.4.pkg in the current directory.

        curl -o hatch-1.9.4.pkg https://github.com/pypa/hatch/releases/download/hatch-v1.9.4/hatch-1.9.4.pkg
        -
      2. Run the standard macOS installer program, specifying the downloaded .pkg file as the source. Use the -pkg parameter to specify the name of the package to install, and the -target / parameter for the drive in which to install the package. The files are installed to /usr/local/hatch, and an entry is created at /etc/paths.d/hatch that instructs shells to add the /usr/local/hatch directory to. You must include sudo on the command to grant write permissions to those folders.

        sudo installer -pkg ./hatch-1.9.4.pkg -target /
        +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

        Installation


        Installers

        1. In your browser, download the .pkg file: hatch-1.9.1.pkg
        2. Run your downloaded file and follow the on-screen instructions.
        3. Restart your terminal.
        4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

          $ hatch --version
          +1.9.1
          +
        1. Download the file using the curl command. The -o option specifies the file name that the downloaded package is written to. In this example, the file is written to hatch-1.9.1.pkg in the current directory.

          curl -o hatch-1.9.1.pkg https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1.pkg
          +
        2. Run the standard macOS installer program, specifying the downloaded .pkg file as the source. Use the -pkg parameter to specify the name of the package to install, and the -target / parameter for the drive in which to install the package. The files are installed to /usr/local/hatch, and an entry is created at /etc/paths.d/hatch that instructs shells to add the /usr/local/hatch directory to. You must include sudo on the command to grant write permissions to those folders.

          sudo installer -pkg ./hatch-1.9.1.pkg -target /
           
        3. Restart your terminal.

        4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

          $ hatch --version
          -1.9.4
          -
        1. In your browser, download one the .msi files:
        2. Run your downloaded file and follow the on-screen instructions.
        3. Restart your terminal.
        4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

          $ hatch --version
          -1.9.4
          -
        1. Download and run the installer using the standard Windows msiexec program, specifying one of the .msi files as the source. Use the /passive and /i parameters to request an unattended, normal installation.

          msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.4/hatch-1.9.4-x64.msi
          +1.9.1
          +
        1. In your browser, download one the .msi files:
        2. Run your downloaded file and follow the on-screen instructions.
        3. Restart your terminal.
        4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

          $ hatch --version
          +1.9.1
          +
        1. Download and run the installer using the standard Windows msiexec program, specifying one of the .msi files as the source. Use the /passive and /i parameters to request an unattended, normal installation.

          msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1-x64.msi
          +
          msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1-x86.msi
           
        2. Restart your terminal.

        3. To verify that the shell can find and run the hatch command in your PATH, use the following command.

          $ hatch --version
          -1.9.4
          -

        Standalone binaries

        After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to hatch.

        pip

        Hatch is available on PyPI and can be installed with pip.

        pip install hatch
        +1.9.1
        +

      Standalone binaries

      After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to hatch.

      pip

      Hatch is available on PyPI and can be installed with pip.

      pip install hatch
       

      Warning

      This method modifies the Python environment in which you choose to install. Consider instead using pipx to avoid dependency conflicts.

      pipx

      pipx allows for the global installation of Python applications in isolated environments.

      pipx install hatch
       

      Homebrew

      See the formula for more details.

      brew install hatch
       

      Conda

      See the feedstock for more details.

      conda install -c conda-forge hatch
      @@ -26,4 +27,4 @@
       

      Warning

      This method modifies the Conda environment in which you choose to install. Consider instead using pipx or condax to avoid dependency conflicts.

      MacPorts

      See the port for more details.

      sudo port install hatch
       

      Fedora

      The minimum supported version is 37, currently in development as Rawhide.

      sudo dnf install hatch
       

      Void Linux

      xbps-install hatch
      -

      Build system availability

      Hatchling is Hatch's build backend which you will never need to install manually. See its changelog for version information.

      Packaging status

      \ No newline at end of file +

      Build system availability

      Hatchling is Hatch's build backend which you will never need to install manually. See its changelog for version information.

      Packaging status

      \ No newline at end of file diff --git a/latest/intro/index.html b/latest/intro/index.html index 8ad713a3e..5408c51fe 100644 --- a/latest/intro/index.html +++ b/latest/intro/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Introduction


      Setup

      Projects can be set up for use by Hatch using the new command.

      New project

      Let's say you want to create a project named Hatch Demo. You would run:

      hatch new "Hatch Demo"
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Introduction


      Setup

      Projects can be set up for use by Hatch using the new command.

      New project

      Let's say you want to create a project named Hatch Demo. You would run:

      hatch new "Hatch Demo"
       

      This would create the following structure in your current working directory:

      hatch-demo
       ├── src
       │   └── hatch_demo
      diff --git a/latest/meta/authors/index.html b/latest/meta/authors/index.html
      index 057a836bf..1d62e8f64 100644
      --- a/latest/meta/authors/index.html
      +++ b/latest/meta/authors/index.html
      @@ -7,4 +7,4 @@
           .gdesc-inner { font-size: 0.75rem; }
           body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
           body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
      -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Authors


      Maintainers

      • Ofek Lev

      Contributors

      • Amjith Ramanujam
      • Arnaud Crowther
      • Chaojie
      • Chris Warrick
      • Lumír 'Frenzy' Balhar
      • Ofek Lev
      • Olga Matoula
      • Philip Blair
      • Robert Rosca
      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Authors


      Maintainers

      • Ofek Lev

      Contributors

      • Amjith Ramanujam
      • Arnaud Crowther
      • Chaojie
      • Chris Warrick
      • Lumír 'Frenzy' Balhar
      • Ofek Lev
      • Olga Matoula
      • Philip Blair
      • Robert Rosca
      \ No newline at end of file diff --git a/latest/meta/faq/index.html b/latest/meta/faq/index.html index 04e117653..3fb876c9a 100644 --- a/latest/meta/faq/index.html +++ b/latest/meta/faq/index.html @@ -1,4 +1,4 @@ - FAQ - Hatch

      FAQ


      Interoperability

      Q: What is the risk of lock-in?

      A: Not much! Other than the plugin system, everything uses Python's established standards by default. Project metadata is based entirely on the standard, the build system is compatible with PEP 517/PEP 660, versioning uses the scheme specified by PEP 440, dependencies are defined with PEP 508 strings, and environments use virtualenv.

      Q: Must one use all features?

      A: No, all features are optional! You can use just the build system, publish wheels and source distributions that were built by other tools, only use the environment management, etc.

      Libraries vs applications

      Q: Are workflows for both libraries and applications supported?

      A: Yes, mostly! Applications can utilize environment management just like libraries, and plugins can be used to build projects in arbitrary formats or publish artifacts to arbitrary destinations.

      The only caveat is that currently there is no support for re-creating an environment given a set of dependencies in a reproducible manner. Although a standard lock file format may be far off since [PEP 665][] was rejected, resolving capabilities are coming to pip. When that is stabilized, Hatch will add locking functionality and dedicated documentation for managing applications.

      Tool migration

      Q: How to migrate to Hatch?

      Build system

      import os
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      FAQ


      Interoperability

      Q: What is the risk of lock-in?

      A: Not much! Other than the plugin system, everything uses Python's established standards by default. Project metadata is based entirely on the standard, the build system is compatible with PEP 517/PEP 660, versioning uses the scheme specified by PEP 440, dependencies are defined with PEP 508 strings, and environments use virtualenv.

      Q: Must one use all features?

      A: No, all features are optional! You can use just the build system, publish wheels and source distributions that were built by other tools, only use the environment management, etc.

      Libraries vs applications

      Q: Are workflows for both libraries and applications supported?

      A: Yes, mostly! Applications can utilize environment management just like libraries, and plugins can be used to build projects in arbitrary formats or publish artifacts to arbitrary destinations.

      The only caveat is that currently there is no support for re-creating an environment given a set of dependencies in a reproducible manner. Although a standard lock file format may be far off since PEP 665 was rejected, resolving capabilities are coming to pip. When that is stabilized, Hatch will add locking functionality and dedicated documentation for managing applications.

      Tool migration

      Q: How to migrate to Hatch?

      Build system

      import os
       from io import open
       
       from setuptools import find_packages, setup
      @@ -174,4 +174,4 @@
       python = ["3.8", "3.9"]
       version = ["9000"]
       features = ["foo", "bar"]
      -

      Fast CLI?

      The claim about being faster than other tools is based on timings that are always checked in CI.

      Hatch achieves this by using lazy imports, lazily performing computation manually and with functools.cached_property, using hacks like not not ... instead of bool(...), etc.

      \ No newline at end of file +

      Fast CLI?

      The claim about being faster than other tools is based on timings that are always checked in CI.

      Hatch achieves this by using lazy imports, lazily performing computation manually and with functools.cached_property, using hacks like not not ... instead of bool(...), etc.

      \ No newline at end of file diff --git a/latest/next-steps/index.html b/latest/next-steps/index.html index a0857c59a..1c0dc622b 100644 --- a/latest/next-steps/index.html +++ b/latest/next-steps/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Next steps


      Learn more

      At this point you should have a basic understanding of how to use Hatch.

      Now you may want to check out advanced configuration for environments or builds, set up your preferred shell, or read more about Hatch's CLI.

      After that, check out the Hatch Showcase project to see examples of what is possible.

      Finally, if you see a need, feel free to write a plugin for extended functionality.

      Community

      For any projects using Hatch, you may add its official badge somewhere prominent like the README.

      Hatch project

      [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Next steps


      Learn more

      At this point you should have a basic understanding of how to use Hatch.

      Now you may want to check out advanced configuration for environments or builds, set up your preferred shell, or read more about Hatch's CLI.

      After that, check out the Hatch Showcase project to see examples of what is possible.

      Finally, if you see a need, feel free to write a plugin for extended functionality.

      Community

      For any projects using Hatch, you may add its official badge somewhere prominent like the README.

      Hatch project

      [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
       
      .. image:: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg
          :alt: Hatch project
          :target: https://github.com/pypa/hatch
      diff --git a/latest/objects.inv b/latest/objects.inv
      index daedd3f68ad49b92da47455de40e53e5c73cc48b..11ee19d74ee607034e3bc4754493b6980812bf23 100644
      GIT binary patch
      delta 1311
      zcmV+)1>pL|3Wp1jd4HQrZ`?Kz$M5|V2AZp7^qN~5q-}sEFi^Btf=i7gW+{^3L$>ni
      zOX{(!)T`Gn$?eIu9{(SQ9L@|$xx$828So|}f-xXQD4j`WOUg6K4X6SW$UgCgD#2^u
      z=HvL-=ke}?Y~K@xwSM^Jp?_09!TE*9lkk&*0u*opPd~qVcz^tKgML4M{fzaJ^Oyz|clnH$D2%9Dj^VV%z|hRE~2qA>Jp(1j#{tzsEML-OinTTvq81UAua{{
      zZ%9|bSp2?oPrB4Yn2m2$<6JNisKH7{r<_uEx(S`CNGNEEMB=w9l2rsAHn;{7GEE^n
      zVd^xr-hVP=TA8A79!rm5nUEZarU5xJSqr!PfgGi*O1=q~w8z>Rt1`ima$HA_&(igy
      z-&jjSi5!p>)S^k?er_EsSOcRoByfcFUE7-pmiH^Ce&;r_IS$s9RO!}9`gmTQ#qCL7
      z*T1Pkt}#y91Eacni+%2I!19Th9G|*beP#1HAb;rcmU2J6
      zn%!Lqi5gOT5>|g{X4V7*%>>mIf+`B|1%`}#He-`TQpNV?b32fJcC}SsY3Q*e~^jX52WoO
      z;D2~m;&zJ}<@WVfks1@BZx#``WpJ}h2siNcNm
      zCFs!Vi~F%xtM+?MzLXCsyRemXr6eu6aAjRX0ya~Ds~U1k=;bxWm8xz6Yd7TAwX+i9
      zc;RETj_`-Ox42a8R35#=#hUv{(#oz-MaMWPZ0cy7Z!7BaDk8-Mn1
      zVv!d@P$cB|>1H{dSHQo7UgR(0>}V!L{7GZmPjx@5yhC_%hsCEu2S*l@zj*v=Zne
      zL1#xO63-9hk&74J2QpgF`F|~m)Px!Lk3_RFpZ}zCBXfvLnI;v~@Rs~ffB&!U_M+u!=0OyW86wt9vvwajRp+fv-DO92oAjBv~lF
      VBDZ4Az2i{z+4if<{udBwwGLk8jjI3v
      
      delta 1245
      zcmV<31S0!~3&skNd4HNqkK`s0$M5+RBPG}IDA(LJt4*>}b~RFzToH}SHrp5w5BGFF
      zeZbh=olN`H4RlWPu>Jp0P!v^VH`tJ-0NxcuFb2d3r3=YyO?g4N0aalF#V6iTC3p+m
      zd>n84JYId0$DatpT0i~x6rR*CaDL$VB>bYF0tKAF%lAJ#J%4}K+|MpvfB*B>&tK8k
      z4_`j{abRQABZff)uW0?q5mc08M*jwM9!h07F;wt}4(EcXA3dlV45FMGirN2Unv@VG
      zhSxa3H}h{+|F2(!YMnNyYn#*>%G_jtzCo|3#^0t^by9t9iq-~|>A6^?zCLW+3&L(%
      zI&5Is(e5TmnSa<6DcKQKfQ?n4(;Kw2l$Dq9;{iwnZ&aHM#*zle-UX#rVncU+=NvOY
      zMcZOtqG7-104^Vs5g6JiOAHFDIT)G6xB)DwbmxpVn6Zp_1zF-ui48_2RsETCOuLpP
      zEx8t(VcHY=SmV>QI+8!@l{f`jKISN*FfSFE3z?l9$K&r
      znWM~+IFG4^RN|XErLzOkWk60$)`Ge0phP*dl5fHt+GFmFRh?l;Ic^ijXX)nA*YtTP
      zi375NR)2IE+|Sj)f^{%DLk34!ZW!H7usl>wp=p%Z90%)Ds(f{l-k+5-Mz&IhWc0S&~g+t}HX?Kur_V^6=gRxgSW|UBoqN#MKmUlLn*QzTGR*
      zVj}e2BBHbm?v|OzdpBwL93!Fw99$7D4r?uQD^eFbMa#NB(~1vLGD`4R=&lJAGZF>f
      z34gU^7u+j))Z0lTMo9bHxNc&Z(!ozTNu
      zr`3KP$^<>U*C~Due}6pX2J78>PU&E;q6->dTyS*_rmwjgqwH!lhyzi8xFJE`Mt%Euq)zf*V!c2G(xLZyRSL#Qw^+D?Q;i
      zcWt)3>{Xt<#MM0cM$$s5nFxBl>`Vk3-%n3eQi-U90iJ5Ir$S~naV`)fLXO|N<(=5!
      zW47$viGn#1&0ytUqD<5Ro1oWm3;na<=@{~BqFN-DbSI8g8pb5QL=|O_!_>K090@T5;0T)|
      zG*!IVWfqJKZ9yB{%B|H)3kG{nes9E=;mTtAI!Y`YAsa~xfj$v*a)lD{{6g-zIPeh2
      zXho;L2TwGF3HMJ#v$CB27;zsV>v%Z` About - Hatch      

      Plugins


      Hatch utilizes pluggy for its plugin functionality.

      Overview

      All plugins provide registration hooks that return one or more classes that inherit from a particular type interface.

      Each registration hook must be decorated by Hatch's hook marker. For example, if you wanted to create a new kind of environment you could do:

      from hatchling.plugin import hookimpl
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Plugins


      Hatch utilizes pluggy for its plugin functionality.

      Overview

      All plugins provide registration hooks that return one or more classes that inherit from a particular type interface.

      Each registration hook must be decorated by Hatch's hook marker. For example, if you wanted to create a new kind of environment you could do:

      from hatchling.plugin import hookimpl
       
       from .plugin import SpecialEnvironment
       
      diff --git a/latest/plugins/build-hook/custom/index.html b/latest/plugins/build-hook/custom/index.html
      index c32ff44b4..1b15bb555 100644
      --- a/latest/plugins/build-hook/custom/index.html
      +++ b/latest/plugins/build-hook/custom/index.html
      @@ -1,4 +1,4 @@
      - Custom - Hatch      

      Custom build hook


      This is a custom class in a given Python file that inherits from the BuildHookInterface.

      Configuration

      The build hook plugin name is custom.

      [tool.hatch.build.hooks.custom]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Custom build hook


      This is a custom class in a given Python file that inherits from the BuildHookInterface.

      Configuration

      The build hook plugin name is custom.

      [tool.hatch.build.hooks.custom]
       [tool.hatch.build.targets.<TARGET_NAME>.hooks.custom]
       
      [build.hooks.custom]
       [build.targets.<TARGET_NAME>.hooks.custom]
      diff --git a/latest/plugins/build-hook/reference/index.html b/latest/plugins/build-hook/reference/index.html
      index fc2b976e1..254b1d284 100644
      --- a/latest/plugins/build-hook/reference/index.html
      +++ b/latest/plugins/build-hook/reference/index.html
      @@ -1,4 +1,4 @@
      - Reference - Hatch      

      Build hook plugins


      A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.

      Known third-party

      Overview

      Build hooks run for every selected version of build targets.

      The initialization stage occurs immediately before each build and the finalization stage occurs immediately after. Each stage has the opportunity to view or modify build data.

      Build data

      Build data is a simple mapping whose contents can influence the behavior of builds. Which fields exist and are recognized depends on each build target.

      The following fields are always present and recognized by the build system itself:

      Field Type Description
      artifacts list[str] This is a list of extra artifact patterns and should generally only be appended to
      force_include dict[str, str] This is a mapping of extra forced inclusion paths, with this mapping taking precedence in case of conflicts
      build_hooks tuple[str, ...] This is an immutable sequence of the names of the configured build hooks and matches the order in which they run

      Attention

      While user-facing TOML options are hyphenated, build data fields should be named with underscores to allow plugins to use them as valid Python identifiers.

      Notes

      In some cases it may be necessary to use force_include rather than artifacts. For example, say that you want to install a lib.so directly at the root of site-packages and a project defines a package src/foo. If you create src/lib.so, there will never be a match because the directory traversal starts at src/foo rather than src. In that case you must do either:

      build_data['force_include']['src/lib.so'] = 'src/lib.so'
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Build hook plugins


      A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.

      Known third-party

      Overview

      Build hooks run for every selected version of build targets.

      The initialization stage occurs immediately before each build and the finalization stage occurs immediately after. Each stage has the opportunity to view or modify build data.

      Build data

      Build data is a simple mapping whose contents can influence the behavior of builds. Which fields exist and are recognized depends on each build target.

      The following fields are always present and recognized by the build system itself:

      Field Type Description
      artifacts list[str] This is a list of extra artifact patterns and should generally only be appended to
      force_include dict[str, str] This is a mapping of extra forced inclusion paths, with this mapping taking precedence in case of conflicts
      build_hooks tuple[str, ...] This is an immutable sequence of the names of the configured build hooks and matches the order in which they run

      Attention

      While user-facing TOML options are hyphenated, build data fields should be named with underscores to allow plugins to use them as valid Python identifiers.

      Notes

      In some cases it may be necessary to use force_include rather than artifacts. For example, say that you want to install a lib.so directly at the root of site-packages and a project defines a package src/foo. If you create src/lib.so, there will never be a match because the directory traversal starts at src/foo rather than src. In that case you must do either:

      build_data['force_include']['src/lib.so'] = 'src/lib.so'
       

      or

      build_data['force_include']['/absolute/path/to/src/lib.so'] = 'src/lib.so'
       

      BuildHookInterface

      Example usage:

      from hatchling.builders.hooks.plugin.interface import BuildHookInterface
       
      @@ -126,48 +126,73 @@
               """
               return self.__target_name
       
      -    def clean(self, versions: list[str]) -> None:
      +    def dependencies(self) -> list[str]:  # noqa: PLR6301
               """
      -        This occurs before the build process if the `-c`/`--clean` flag was passed to
      -        the [`build`](../../cli/reference.md#hatch-build) command, or when invoking
      -        the [`clean`](../../cli/reference.md#hatch-clean) command.
      -        """
      -
      -    def initialize(self, version: str, build_data: dict[str, Any]) -> None:
      -        """
      -        This occurs immediately before each build.
      -
      -        Any modifications to the build data will be seen by the build target.
      -        """
      -
      -    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
      -        """
      -        This occurs immediately after each build and will not run if the `--hooks-only` flag
      -        was passed to the [`build`](../../cli/reference.md#hatch-build) command.
      -
      -        The build data will reflect any modifications done by the target during the build.
      -        """
      +        A list of extra [dependencies](../../config/dependency.md) that must be installed
      +        prior to builds.
      +
      +        !!! warning
      +            - For this to have any effect the hook dependency itself cannot be dynamic and
      +                must always be defined in `build-system.requires`.
      +            - As the hook must be imported to call this method, imports that require these
      +                dependencies must be evaluated lazily.
      +        """
      +        return []
      +
      +    def clean(self, versions: list[str]) -> None:
      +        """
      +        This occurs before the build process if the `-c`/`--clean` flag was passed to
      +        the [`build`](../../cli/reference.md#hatch-build) command, or when invoking
      +        the [`clean`](../../cli/reference.md#hatch-clean) command.
      +        """
      +
      +    def initialize(self, version: str, build_data: dict[str, Any]) -> None:
      +        """
      +        This occurs immediately before each build.
      +
      +        Any modifications to the build data will be seen by the build target.
      +        """
      +
      +    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
      +        """
      +        This occurs immediately after each build and will not run if the `--hooks-only` flag
      +        was passed to the [`build`](../../cli/reference.md#hatch-build) command.
      +
      +        The build data will reflect any modifications done by the target during the build.
      +        """
       

      PLUGIN_NAME = '' class-attribute instance-attribute

      The name used for selection.

      app: Application property

      An instance of Application.

      root: str property

      The root of the project tree.

      config: dict[str, Any] property

      The cumulative hook configuration.

      [tool.hatch.build.hooks.<PLUGIN_NAME>]
       [tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]
       
      [build.hooks.<PLUGIN_NAME>]
       [build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]
      -

      build_config: BuilderConfigBound property

      An instance of BuilderConfig.

      target_name: str property

      The plugin name of the build target.

      directory: str property

      The build directory.

      clean(versions: list[str]) -> None

      This occurs before the build process if the -c/--clean flag was passed to the build command, or when invoking the clean command.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def clean(self, versions: list[str]) -> None:
      +

      build_config: BuilderConfigBound property

      An instance of BuilderConfig.

      target_name: str property

      The plugin name of the build target.

      directory: str property

      The build directory.

      dependencies() -> list[str]

      A list of extra dependencies that must be installed prior to builds.

      Warning

      • For this to have any effect the hook dependency itself cannot be dynamic and must always be defined in build-system.requires.
      • As the hook must be imported to call this method, imports that require these dependencies must be evaluated lazily.
      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def dependencies(self) -> list[str]:  # noqa: PLR6301
           """
      -    This occurs before the build process if the `-c`/`--clean` flag was passed to
      -    the [`build`](../../cli/reference.md#hatch-build) command, or when invoking
      -    the [`clean`](../../cli/reference.md#hatch-clean) command.
      -    """
      -

      initialize(version: str, build_data: dict[str, Any]) -> None

      This occurs immediately before each build.

      Any modifications to the build data will be seen by the build target.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def initialize(self, version: str, build_data: dict[str, Any]) -> None:
      -    """
      -    This occurs immediately before each build.
      -
      -    Any modifications to the build data will be seen by the build target.
      -    """
      -

      finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None

      This occurs immediately after each build and will not run if the --hooks-only flag was passed to the build command.

      The build data will reflect any modifications done by the target during the build.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
      -    """
      -    This occurs immediately after each build and will not run if the `--hooks-only` flag
      -    was passed to the [`build`](../../cli/reference.md#hatch-build) command.
      -
      -    The build data will reflect any modifications done by the target during the build.
      -    """
      -
      \ No newline at end of file + A list of extra [dependencies](../../config/dependency.md) that must be installed + prior to builds. + + !!! warning + - For this to have any effect the hook dependency itself cannot be dynamic and + must always be defined in `build-system.requires`. + - As the hook must be imported to call this method, imports that require these + dependencies must be evaluated lazily. + """ + return [] +

      clean(versions: list[str]) -> None

      This occurs before the build process if the -c/--clean flag was passed to the build command, or when invoking the clean command.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def clean(self, versions: list[str]) -> None:
      +    """
      +    This occurs before the build process if the `-c`/`--clean` flag was passed to
      +    the [`build`](../../cli/reference.md#hatch-build) command, or when invoking
      +    the [`clean`](../../cli/reference.md#hatch-clean) command.
      +    """
      +

      initialize(version: str, build_data: dict[str, Any]) -> None

      This occurs immediately before each build.

      Any modifications to the build data will be seen by the build target.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def initialize(self, version: str, build_data: dict[str, Any]) -> None:
      +    """
      +    This occurs immediately before each build.
      +
      +    Any modifications to the build data will be seen by the build target.
      +    """
      +

      finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None

      This occurs immediately after each build and will not run if the --hooks-only flag was passed to the build command.

      The build data will reflect any modifications done by the target during the build.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
      +    """
      +    This occurs immediately after each build and will not run if the `--hooks-only` flag
      +    was passed to the [`build`](../../cli/reference.md#hatch-build) command.
      +
      +    The build data will reflect any modifications done by the target during the build.
      +    """
      +
      \ No newline at end of file diff --git a/latest/plugins/build-hook/version/index.html b/latest/plugins/build-hook/version/index.html index e0b8d175e..0f60fe576 100644 --- a/latest/plugins/build-hook/version/index.html +++ b/latest/plugins/build-hook/version/index.html @@ -1,4 +1,4 @@ - Version - Hatch

      Version build hook


      This writes the project's version to a file.

      Configuration

      The build hook plugin name is version.

      [tool.hatch.build.hooks.version]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Version build hook


      This writes the project's version to a file.

      Configuration

      The build hook plugin name is version.

      [tool.hatch.build.hooks.version]
       [tool.hatch.build.targets.<TARGET_NAME>.hooks.version]
       
      [build.hooks.version]
       [build.targets.<TARGET_NAME>.hooks.version]
      diff --git a/latest/plugins/builder/app/index.html b/latest/plugins/builder/app/index.html
      index 9b9423f3d..ddc5927bf 100644
      --- a/latest/plugins/builder/app/index.html
      +++ b/latest/plugins/builder/app/index.html
      @@ -1,12 +1,15 @@
      - Application - Hatch      

      Application builder


      This uses PyApp to build an application that is able to bootstrap itself at runtime.

      Note

      This requires an installation of Rust.

      Configuration

      The builder plugin name is app.

      [tool.hatch.build.targets.app]
      -
      [build.targets.app]
      -

      Options

      Option Default Description
      scripts all defined An array of defined script names to limit what gets built
      python-version latest compatible Python minor version The Python version ID to use
      pyapp-version The version of PyApp to use

      Build behavior

      If any scripts are defined then each one will be built (limited by the scripts option). Otherwise, a single executable will be built based on the project name assuming there is an equivalently named module with a __main__.py file.

      Every executable will be built inside an app directory in the output directory.

      If the CARGO environment variable is set then that path will be used as the executable for performing builds.

      If the CARGO_BUILD_TARGET environment variable is set then its value will be appended to the file name stems.

      If the PYAPP_REPO environment variable is set then a local build will be performed inside that directory rather than installing from crates.io. Note that this is required if the CARGO environment variable refers to cross.

      \ No newline at end of file + + + + + + Redirecting... + + + + + + +Redirecting... + + diff --git a/latest/plugins/builder/binary/index.html b/latest/plugins/builder/binary/index.html new file mode 100644 index 000000000..891741ecf --- /dev/null +++ b/latest/plugins/builder/binary/index.html @@ -0,0 +1,12 @@ + Binary builder - Hatch

      Binary builder


      This uses PyApp to build an application that is able to bootstrap itself at runtime.

      Note

      This requires an installation of Rust.

      Configuration

      The builder plugin name is binary.

      [tool.hatch.build.targets.binary]
      +
      [build.targets.binary]
      +

      Options

      Option Default Description
      scripts all defined An array of defined script names to limit what gets built
      python-version latest compatible Python minor version The Python version ID to use
      pyapp-version The version of PyApp to use

      Build behavior

      If any scripts are defined then each one will be built (limited by the scripts option). Otherwise, a single executable will be built based on the project name assuming there is an equivalently named module with a __main__.py file.

      Every executable will be built inside an app directory in the output directory.

      If the CARGO environment variable is set then that path will be used as the executable for performing builds.

      If the CARGO_BUILD_TARGET environment variable is set then its value will be appended to the file name stems.

      If the PYAPP_REPO environment variable is set then a local build will be performed inside that directory rather than installing from crates.io. Note that this is required if the CARGO environment variable refers to cross.

      \ No newline at end of file diff --git a/latest/plugins/builder/custom/index.html b/latest/plugins/builder/custom/index.html index 57506e279..df6732bd5 100644 --- a/latest/plugins/builder/custom/index.html +++ b/latest/plugins/builder/custom/index.html @@ -1,4 +1,4 @@ - Custom - Hatch

      Custom builder


      This is a custom class in a given Python file that inherits from the BuilderInterface.

      Configuration

      The builder plugin name is custom.

      [tool.hatch.build.targets.custom]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Custom builder


      This is a custom class in a given Python file that inherits from the BuilderInterface.

      Configuration

      The builder plugin name is custom.

      [tool.hatch.build.targets.custom]
       
      [build.targets.custom]
       

      Options

      Option Default Description
      path hatch_build.py The path of the Python file

      Example

      from hatchling.builders.plugin.interface import BuilderInterface
       
       
       class CustomBuilder(BuilderInterface):
           ...
      -

      If multiple subclasses are found, you must define a function named get_builder that returns the desired builder.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      \ No newline at end of file +

      If multiple subclasses are found, you must define a function named get_builder that returns the desired builder.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      \ No newline at end of file diff --git a/latest/plugins/builder/reference/index.html b/latest/plugins/builder/reference/index.html index 5e6d598ab..a244dbb46 100644 --- a/latest/plugins/builder/reference/index.html +++ b/latest/plugins/builder/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

      Builder plugins


      See the documentation for build configuration.

      Known third-party

      • hatch-aws - used for building AWS Lambda functions with SAM
      • hatch-zipped-directory - used for building ZIP archives for installation into various foreign package installation systems

      BuilderInterface

      Example usage:

      from hatchling.builders.plugin.interface import BuilderInterface
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Builder plugins


      See the documentation for build configuration.

      Known third-party

      • hatch-aws - used for building AWS Lambda functions with SAM
      • hatch-zipped-directory - used for building ZIP archives for installation into various foreign package installation systems

      BuilderInterface

      Example usage:

      from hatchling.builders.plugin.interface import BuilderInterface
       
       
       class SpecialBuilder(BuilderInterface):
      @@ -187,278 +187,287 @@
                   files.sort()
                   is_package = '__init__.py' in files
                   for f in files:
      -                relative_file_path = os.path.join(relative_path, f)
      -                distribution_path = self.config.get_distribution_path(relative_file_path)
      -                if self.config.path_is_reserved(distribution_path):
      -                    continue
      -
      -                if self.config.include_path(relative_file_path, is_package=is_package):
      -                    yield IncludedFile(
      -                        os.path.join(root, f), relative_file_path, self.config.get_distribution_path(relative_file_path)
      -                    )
      -
      -    def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:
      -        for source, target_path in inclusion_map.items():
      -            external = not source.startswith(self.root)
      -            if os.path.isfile(source):
      -                yield IncludedFile(
      -                    source,
      -                    '' if external else os.path.relpath(source, self.root),
      -                    self.config.get_distribution_path(target_path),
      -                )
      -            elif os.path.isdir(source):
      -                for root, dirs, files in safe_walk(source):
      -                    relative_directory = get_relative_path(root, source)
      -
      -                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)
      -
      -                    files.sort()
      -                    for f in files:
      -                        relative_file_path = os.path.join(target_path, relative_directory, f)
      -                        distribution_path = self.config.get_distribution_path(relative_file_path)
      -                        if not self.config.path_is_reserved(distribution_path):
      -                            yield IncludedFile(
      -                                os.path.join(root, f),
      -                                '' if external else relative_file_path,
      -                                distribution_path,
      -                            )
      -            else:
      -                msg = f'Forced include not found: {source}'
      -                raise FileNotFoundError(msg)
      -
      -    def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:
      -        for source, target_path in inclusion_map.items():
      -            external = not source.startswith(self.root)
      -            if os.path.isfile(source):
      -                distribution_path = self.config.get_distribution_path(target_path)
      -                if not self.config.path_is_reserved(distribution_path):
      -                    yield IncludedFile(
      -                        source,
      -                        '' if external else os.path.relpath(source, self.root),
      -                        self.config.get_distribution_path(target_path),
      -                    )
      -            elif os.path.isdir(source):
      -                for root, dirs, files in safe_walk(source):
      -                    relative_directory = get_relative_path(root, source)
      -
      -                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)
      -
      -                    files.sort()
      -                    is_package = '__init__.py' in files
      -                    for f in files:
      -                        relative_file_path = os.path.join(target_path, relative_directory, f)
      -                        distribution_path = self.config.get_distribution_path(relative_file_path)
      -                        if self.config.path_is_reserved(distribution_path):
      -                            continue
      -
      -                        if self.config.include_path(relative_file_path, explicit=True, is_package=is_package):
      -                            yield IncludedFile(
      -                                os.path.join(root, f), '' if external else relative_file_path, distribution_path
      -                            )
      -
      -    @property
      -    def root(self) -> str:
      -        """
      -        The root of the project tree.
      -        """
      -        return self.__root
      -
      -    @property
      -    def plugin_manager(self) -> PluginManagerBound:
      -        if self.__plugin_manager is None:
      -            from hatchling.plugin.manager import PluginManager
      -
      -            self.__plugin_manager = PluginManager()
      -
      -        return self.__plugin_manager
      +                if f in EXCLUDED_FILES:
      +                    continue
      +
      +                relative_file_path = os.path.join(relative_path, f)
      +                distribution_path = self.config.get_distribution_path(relative_file_path)
      +                if self.config.path_is_reserved(distribution_path):
      +                    continue
      +
      +                if self.config.include_path(relative_file_path, is_package=is_package):
      +                    yield IncludedFile(
      +                        os.path.join(root, f), relative_file_path, self.config.get_distribution_path(relative_file_path)
      +                    )
      +
      +    def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:
      +        for source, target_path in inclusion_map.items():
      +            external = not source.startswith(self.root)
      +            if os.path.isfile(source):
      +                yield IncludedFile(
      +                    source,
      +                    '' if external else os.path.relpath(source, self.root),
      +                    self.config.get_distribution_path(target_path),
      +                )
      +            elif os.path.isdir(source):
      +                for root, dirs, files in safe_walk(source):
      +                    relative_directory = get_relative_path(root, source)
      +
      +                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)
      +
      +                    files.sort()
      +                    for f in files:
      +                        if f in EXCLUDED_FILES:
      +                            continue
      +
      +                        relative_file_path = os.path.join(target_path, relative_directory, f)
      +                        distribution_path = self.config.get_distribution_path(relative_file_path)
      +                        if not self.config.path_is_reserved(distribution_path):
      +                            yield IncludedFile(
      +                                os.path.join(root, f),
      +                                '' if external else relative_file_path,
      +                                distribution_path,
      +                            )
      +            else:
      +                msg = f'Forced include not found: {source}'
      +                raise FileNotFoundError(msg)
      +
      +    def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:
      +        for source, target_path in inclusion_map.items():
      +            external = not source.startswith(self.root)
      +            if os.path.isfile(source):
      +                distribution_path = self.config.get_distribution_path(target_path)
      +                if not self.config.path_is_reserved(distribution_path):
      +                    yield IncludedFile(
      +                        source,
      +                        '' if external else os.path.relpath(source, self.root),
      +                        self.config.get_distribution_path(target_path),
      +                    )
      +            elif os.path.isdir(source):
      +                for root, dirs, files in safe_walk(source):
      +                    relative_directory = get_relative_path(root, source)
      +
      +                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)
      +
      +                    files.sort()
      +                    is_package = '__init__.py' in files
      +                    for f in files:
      +                        if f in EXCLUDED_FILES:
      +                            continue
      +
      +                        relative_file_path = os.path.join(target_path, relative_directory, f)
      +                        distribution_path = self.config.get_distribution_path(relative_file_path)
      +                        if self.config.path_is_reserved(distribution_path):
      +                            continue
      +
      +                        if self.config.include_path(relative_file_path, explicit=True, is_package=is_package):
      +                            yield IncludedFile(
      +                                os.path.join(root, f), '' if external else relative_file_path, distribution_path
      +                            )
      +
      +    @property
      +    def root(self) -> str:
      +        """
      +        The root of the project tree.
      +        """
      +        return self.__root
       
           @property
      -    def metadata(self) -> ProjectMetadata:
      -        if self.__metadata is None:
      -            from hatchling.metadata.core import ProjectMetadata
      +    def plugin_manager(self) -> PluginManagerBound:
      +        if self.__plugin_manager is None:
      +            from hatchling.plugin.manager import PluginManager
       
      -            self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)
      +            self.__plugin_manager = PluginManager()
       
      -        return self.__metadata
      +        return self.__plugin_manager
       
           @property
      -    def app(self) -> Application:
      -        """
      -        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).
      -        """
      -        if self.__app is None:
      -            from hatchling.bridge.app import Application
      -
      -            self.__app = cast(Application, Application().get_safe_application())
      -
      -        return self.__app
      -
      -    @property
      -    def raw_config(self) -> dict[str, Any]:
      -        if self.__raw_config is None:
      -            self.__raw_config = self.metadata.config
      +    def metadata(self) -> ProjectMetadata:
      +        if self.__metadata is None:
      +            from hatchling.metadata.core import ProjectMetadata
      +
      +            self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)
      +
      +        return self.__metadata
      +
      +    @property
      +    def app(self) -> Application:
      +        """
      +        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).
      +        """
      +        if self.__app is None:
      +            from hatchling.bridge.app import Application
       
      -        return self.__raw_config
      +            self.__app = cast(Application, Application().get_safe_application())
       
      -    @property
      -    def project_config(self) -> dict[str, Any]:
      -        if self.__project_config is None:
      -            self.__project_config = self.metadata.core.config
      -
      -        return self.__project_config
      +        return self.__app
      +
      +    @property
      +    def raw_config(self) -> dict[str, Any]:
      +        if self.__raw_config is None:
      +            self.__raw_config = self.metadata.config
       
      -    @property
      -    def hatch_config(self) -> dict[str, Any]:
      -        if self.__hatch_config is None:
      -            self.__hatch_config = self.metadata.hatch.config
      -
      -        return self.__hatch_config
      +        return self.__raw_config
      +
      +    @property
      +    def project_config(self) -> dict[str, Any]:
      +        if self.__project_config is None:
      +            self.__project_config = self.metadata.core.config
       
      -    @property
      -    def config(self) -> BuilderConfigBound:
      -        """
      -        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
      -        """
      -        if self.__config is None:
      -            self.__config = self.get_config_class()(
      -                self, self.root, self.PLUGIN_NAME, self.build_config, self.target_config
      -            )
      -
      -        return self.__config
      -
      -    @property
      -    def build_config(self) -> dict[str, Any]:
      -        """
      -        ```toml config-example
      -        [tool.hatch.build]
      -        ```
      -        """
      -        if self.__build_config is None:
      -            self.__build_config = self.metadata.hatch.build_config
      -
      -        return self.__build_config
      -
      -    @property
      -    def target_config(self) -> dict[str, Any]:
      -        """
      -        ```toml config-example
      -        [tool.hatch.build.targets.<PLUGIN_NAME>]
      -        ```
      -        """
      -        if self.__target_config is None:
      -            target_config: dict[str, Any] = self.metadata.hatch.build_targets.get(self.PLUGIN_NAME, {})
      -            if not isinstance(target_config, dict):
      -                message = f'Field `tool.hatch.build.targets.{self.PLUGIN_NAME}` must be a table'
      -                raise TypeError(message)
      -
      -            self.__target_config = target_config
      -
      -        return self.__target_config
      -
      -    @property
      -    def project_id(self) -> str:
      -        if self.__project_id is None:
      -            self.__project_id = f'{self.normalize_file_name_component(self.metadata.core.name)}-{self.metadata.version}'
      +        return self.__project_config
      +
      +    @property
      +    def hatch_config(self) -> dict[str, Any]:
      +        if self.__hatch_config is None:
      +            self.__hatch_config = self.metadata.hatch.config
      +
      +        return self.__hatch_config
      +
      +    @property
      +    def config(self) -> BuilderConfigBound:
      +        """
      +        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
      +        """
      +        if self.__config is None:
      +            self.__config = self.get_config_class()(
      +                self, self.root, self.PLUGIN_NAME, self.build_config, self.target_config
      +            )
      +
      +        return self.__config
      +
      +    @property
      +    def build_config(self) -> dict[str, Any]:
      +        """
      +        ```toml config-example
      +        [tool.hatch.build]
      +        ```
      +        """
      +        if self.__build_config is None:
      +            self.__build_config = self.metadata.hatch.build_config
      +
      +        return self.__build_config
      +
      +    @property
      +    def target_config(self) -> dict[str, Any]:
      +        """
      +        ```toml config-example
      +        [tool.hatch.build.targets.<PLUGIN_NAME>]
      +        ```
      +        """
      +        if self.__target_config is None:
      +            target_config: dict[str, Any] = self.metadata.hatch.build_targets.get(self.PLUGIN_NAME, {})
      +            if not isinstance(target_config, dict):
      +                message = f'Field `tool.hatch.build.targets.{self.PLUGIN_NAME}` must be a table'
      +                raise TypeError(message)
       
      -        return self.__project_id
      +            self.__target_config = target_config
       
      -    def get_build_hooks(self, directory: str) -> dict[str, BuildHookInterface]:
      -        configured_build_hooks = {}
      -        for hook_name, config in self.config.hook_config.items():
      -            build_hook = self.plugin_manager.build_hook.get(hook_name)
      -            if build_hook is None:
      -                from hatchling.plugin.exceptions import UnknownPluginError
      +        return self.__target_config
      +
      +    @property
      +    def project_id(self) -> str:
      +        if self.__project_id is None:
      +            self.__project_id = f'{self.normalize_file_name_component(self.metadata.core.name)}-{self.metadata.version}'
       
      -                message = f'Unknown build hook: {hook_name}'
      -                raise UnknownPluginError(message)
      -
      -            configured_build_hooks[hook_name] = build_hook(
      -                self.root, config, self.config, self.metadata, directory, self.PLUGIN_NAME, self.app
      -            )
      -
      -        return configured_build_hooks
      +        return self.__project_id
      +
      +    def get_build_hooks(self, directory: str) -> dict[str, BuildHookInterface]:
      +        configured_build_hooks = {}
      +        for hook_name, config in self.config.hook_config.items():
      +            build_hook = self.plugin_manager.build_hook.get(hook_name)
      +            if build_hook is None:
      +                from hatchling.plugin.exceptions import UnknownPluginError
       
      -    @abstractmethod
      -    def get_version_api(self) -> dict[str, Callable]:
      -        """
      -        A mapping of `str` versions to a callable that is used for building.
      -        Each callable must have the following signature:
      -
      -        ```python
      -        def ...(build_dir: str, build_data: dict) -> str:
      -        ```
      -
      -        The return value must be the absolute path to the built artifact.
      -        """
      -
      -    def get_default_versions(self) -> list[str]:
      -        """
      -        A list of versions to build when users do not specify any, defaulting to all versions.
      -        """
      -        return list(self.get_version_api())
      +                message = f'Unknown build hook: {hook_name}'
      +                raise UnknownPluginError(message)
      +
      +            configured_build_hooks[hook_name] = build_hook(
      +                self.root, config, self.config, self.metadata, directory, self.PLUGIN_NAME, self.app
      +            )
      +
      +        return configured_build_hooks
      +
      +    @abstractmethod
      +    def get_version_api(self) -> dict[str, Callable]:
      +        """
      +        A mapping of `str` versions to a callable that is used for building.
      +        Each callable must have the following signature:
      +
      +        ```python
      +        def ...(build_dir: str, build_data: dict) -> str:
      +        ```
       
      -    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301
      -        """
      -        A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.
      -        """
      -        return {}
      -
      -    def set_build_data_defaults(self, build_data: dict[str, Any]) -> None:  # noqa: PLR6301
      -        build_data.setdefault('artifacts', [])
      -        build_data.setdefault('force_include', {})
      -
      -    def clean(self, directory: str, versions: list[str]) -> None:
      -        """
      -        Called before builds if the `-c`/`--clean` flag was passed to the
      -        [`build`](../../cli/reference.md#hatch-build) command.
      -        """
      -
      -    @classmethod
      -    def get_config_class(cls) -> type[BuilderConfig]:
      -        """
      -        Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
      -        """
      -        return BuilderConfig
      -
      -    @staticmethod
      -    def normalize_file_name_component(file_name: str) -> str:
      -        """
      -        https://peps.python.org/pep-0427/#escaping-and-unicode
      -        """
      -        return re.sub(r'[^\w\d.]+', '_', file_name, flags=re.UNICODE)
      +        The return value must be the absolute path to the built artifact.
      +        """
      +
      +    def get_default_versions(self) -> list[str]:
      +        """
      +        A list of versions to build when users do not specify any, defaulting to all versions.
      +        """
      +        return list(self.get_version_api())
      +
      +    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301
      +        """
      +        A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.
      +        """
      +        return {}
      +
      +    def set_build_data_defaults(self, build_data: dict[str, Any]) -> None:  # noqa: PLR6301
      +        build_data.setdefault('artifacts', [])
      +        build_data.setdefault('force_include', {})
      +
      +    def clean(self, directory: str, versions: list[str]) -> None:
      +        """
      +        Called before builds if the `-c`/`--clean` flag was passed to the
      +        [`build`](../../cli/reference.md#hatch-build) command.
      +        """
      +
      +    @classmethod
      +    def get_config_class(cls) -> type[BuilderConfig]:
      +        """
      +        Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
      +        """
      +        return BuilderConfig
      +
      +    @staticmethod
      +    def normalize_file_name_component(file_name: str) -> str:
      +        """
      +        https://peps.python.org/pep-0427/#escaping-and-unicode
      +        """
      +        return re.sub(r'[^\w\d.]+', '_', file_name, flags=re.UNICODE)
       

      PLUGIN_NAME = '' class-attribute instance-attribute

      The name used for selection.

      app: Application property

      An instance of Application.

      root: str property

      The root of the project tree.

      build_config: dict[str, Any] property

      [tool.hatch.build]
       
      [build]
       

      target_config: dict[str, Any] property

      [tool.hatch.build.targets.<PLUGIN_NAME>]
       
      [build.targets.<PLUGIN_NAME>]
      -

      config: BuilderConfigBound property

      An instance of BuilderConfig.

      get_config_class() -> type[BuilderConfig] classmethod

      Must return a subclass of BuilderConfig.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      @classmethod
      -def get_config_class(cls) -> type[BuilderConfig]:
      -    """
      -    Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
      -    """
      -    return BuilderConfig
      +

      config: BuilderConfigBound property

      An instance of BuilderConfig.

      get_config_class() -> type[BuilderConfig] classmethod

      Must return a subclass of BuilderConfig.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      @classmethod
      +def get_config_class(cls) -> type[BuilderConfig]:
      +    """
      +    Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
      +    """
      +    return BuilderConfig
       

      get_version_api() -> dict[str, Callable] abstractmethod

      A mapping of str versions to a callable that is used for building. Each callable must have the following signature:

      def ...(build_dir: str, build_data: dict) -> str:
      -

      The return value must be the absolute path to the built artifact.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      @abstractmethod
      -def get_version_api(self) -> dict[str, Callable]:
      -    """
      -    A mapping of `str` versions to a callable that is used for building.
      -    Each callable must have the following signature:
      -
      -    ```python
      -    def ...(build_dir: str, build_data: dict) -> str:
      -    ```
      -
      -    The return value must be the absolute path to the built artifact.
      -    """
      -

      get_default_versions() -> list[str]

      A list of versions to build when users do not specify any, defaulting to all versions.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def get_default_versions(self) -> list[str]:
      -    """
      -    A list of versions to build when users do not specify any, defaulting to all versions.
      -    """
      -    return list(self.get_version_api())
      -

      clean(directory: str, versions: list[str]) -> None

      Called before builds if the -c/--clean flag was passed to the build command.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def clean(self, directory: str, versions: list[str]) -> None:
      -    """
      -    Called before builds if the `-c`/`--clean` flag was passed to the
      -    [`build`](../../cli/reference.md#hatch-build) command.
      -    """
      +

      The return value must be the absolute path to the built artifact.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      @abstractmethod
      +def get_version_api(self) -> dict[str, Callable]:
      +    """
      +    A mapping of `str` versions to a callable that is used for building.
      +    Each callable must have the following signature:
      +
      +    ```python
      +    def ...(build_dir: str, build_data: dict) -> str:
      +    ```
      +
      +    The return value must be the absolute path to the built artifact.
      +    """
      +

      get_default_versions() -> list[str]

      A list of versions to build when users do not specify any, defaulting to all versions.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def get_default_versions(self) -> list[str]:
      +    """
      +    A list of versions to build when users do not specify any, defaulting to all versions.
      +    """
      +    return list(self.get_version_api())
      +

      clean(directory: str, versions: list[str]) -> None

      Called before builds if the -c/--clean flag was passed to the build command.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def clean(self, directory: str, versions: list[str]) -> None:
      +    """
      +    Called before builds if the `-c`/`--clean` flag was passed to the
      +    [`build`](../../cli/reference.md#hatch-build) command.
      +    """
       

      recurse_included_files() -> Iterable[IncludedFile]

      Returns a consistently generated series of file objects for every file that should be distributed. Each file object has three str attributes:

      • path - the absolute path
      • relative_path - the path relative to the project root; will be an empty string for external files
      • distribution_path - the path to be distributed as
      Source code in backend/src/hatchling/builders/plugin/interface.py
      def recurse_included_files(self) -> Iterable[IncludedFile]:
           """
           Returns a consistently generated series of file objects for every file that should be distributed. Each file
      @@ -470,9 +479,9 @@
           """
           yield from self.recurse_selected_project_files()
           yield from self.recurse_forced_files(self.config.get_force_include())
      -

      get_default_build_data() -> dict[str, Any]

      A mapping that can be modified by build hooks to influence the behavior of builds.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301
      -    """
      -    A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.
      -    """
      -    return {}
      +

      get_default_build_data() -> dict[str, Any]

      A mapping that can be modified by build hooks to influence the behavior of builds.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301
      +    """
      +    A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.
      +    """
      +    return {}
       
      \ No newline at end of file diff --git a/latest/plugins/builder/sdist/index.html b/latest/plugins/builder/sdist/index.html index fd509346c..a790529c2 100644 --- a/latest/plugins/builder/sdist/index.html +++ b/latest/plugins/builder/sdist/index.html @@ -1,4 +1,4 @@ - Source distribution - Hatch

      Source distribution builder


      A source distribution, or sdist, is an archive of Python "source code". Although largely unspecified, by convention it should include everything that is required to build a wheel without making network requests.

      Configuration

      The builder plugin name is sdist.

      [tool.hatch.build.targets.sdist]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Source distribution builder


      A source distribution, or sdist, is an archive of Python "source code". Although largely unspecified, by convention it should include everything that is required to build a wheel without making network requests.

      Configuration

      The builder plugin name is sdist.

      [tool.hatch.build.targets.sdist]
       
      [build.targets.sdist]
      -

      Options

      Option Default Description
      core-metadata-version "2.1" The version of core metadata to use
      strict-naming true Whether or not file names should contain the normalized version of the project name
      support-legacy false Whether or not to include a setup.py file to support legacy installation mechanisms

      Versions

      Version Description
      standard (default) The latest conventional format

      Default file selection

      When the user has not set any file selection options, all files that are not ignored by your VCS will be included.

      Note

      The following files are always included and cannot be excluded:

      • /pyproject.toml
      • /hatch.toml
      • /hatch_build.py
      • /.gitignore or /.hgignore
      • Any defined readme file
      • All defined license-files

      Reproducibility

      Reproducible builds are supported.

      Build data

      This is data that can be modified by build hooks.

      Data Default Description
      dependencies Extra project dependencies
      \ No newline at end of file +

      Options

      Option Default Description
      core-metadata-version "2.3" The version of core metadata to use
      strict-naming true Whether or not file names should contain the normalized version of the project name
      support-legacy false Whether or not to include a setup.py file to support legacy installation mechanisms

      Versions

      Version Description
      standard (default) The latest conventional format

      Default file selection

      When the user has not set any file selection options, all files that are not ignored by your VCS will be included.

      Note

      The following files are always included and cannot be excluded:

      • /pyproject.toml
      • /hatch.toml
      • /hatch_build.py
      • /.gitignore or /.hgignore
      • Any defined readme file
      • All defined license-files

      Reproducibility

      Reproducible builds are supported.

      Build data

      This is data that can be modified by build hooks.

      Data Default Description
      dependencies Extra project dependencies
      \ No newline at end of file diff --git a/latest/plugins/builder/wheel/index.html b/latest/plugins/builder/wheel/index.html index 49451e528..d65381d07 100644 --- a/latest/plugins/builder/wheel/index.html +++ b/latest/plugins/builder/wheel/index.html @@ -1,4 +1,4 @@ - Wheel - Hatch

      Wheel builder


      A wheel is a binary distribution of a Python package that can be installed directly into an environment.

      Configuration

      The builder plugin name is wheel.

      [tool.hatch.build.targets.wheel]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Wheel builder


      A wheel is a binary distribution of a Python package that can be installed directly into an environment.

      Configuration

      The builder plugin name is wheel.

      [tool.hatch.build.targets.wheel]
       
      [build.targets.wheel]
      -

      Options

      Option Default Description
      core-metadata-version "2.1" The version of core metadata to use
      shared-data A mapping similar to the forced inclusion option corresponding to data that will be installed globally in a given Python environment, usually under sys.prefix
      extra-metadata A mapping similar to the forced inclusion option corresponding to extra metadata that will be shipped in a directory named extra_metadata
      strict-naming true Whether or not file names should contain the normalized version of the project name
      macos-max-compat true Whether or not on macOS, when build hooks have set the infer_tag build data, the wheel name should signal broad support rather than specific versions for newer SDK versions.

      Note: The default will become false, and this option eventually removed, sometime after consumers like pip start supporting these newer SDK versions.
      bypass-selection false Whether or not to suppress the error when one has not defined any file selection options and all heuristics have failed to determine what to ship

      Versions

      Version Description
      standard (default) The latest standardized format
      editable A wheel that only ships .pth files or import hooks for real-time development

      Default file selection

      When the user has not set any file selection options, the project name will be used to determine the package to ship in the following heuristic order:

      1. <NAME>/__init__.py
      2. src/<NAME>/__init__.py
      3. <NAME>.py
      4. <NAMESPACE>/<NAME>/__init__.py

      If none of these heuristics are satisfied, an error will be raised.

      Reproducibility

      Reproducible builds are supported.

      Build data

      This is data that can be modified by build hooks.

      Data Default Description
      tag The full tag part of the filename (e.g. py3-none-any), defaulting to a cross-platform wheel with the supported major versions of Python based on project metadata
      infer_tag False When tag is not set, this may be enabled to use the one most specific to the platform, Python interpreter, and ABI
      pure_python True Whether or not to write metadata indicating that the package does not contain any platform-specific files
      dependencies Extra project dependencies
      extra_metadata Additional extra-metadata entries, which take precedence in case of conflicts
      force_include_editable Similar to the force_include option but specifically for the editable version and takes precedence
      \ No newline at end of file +

      Options

      Option Default Description
      core-metadata-version "2.3" The version of core metadata to use
      shared-data A mapping similar to the forced inclusion option corresponding to data that will be installed globally in a given Python environment, usually under sys.prefix
      extra-metadata A mapping similar to the forced inclusion option corresponding to extra metadata that will be shipped in a directory named extra_metadata
      strict-naming true Whether or not file names should contain the normalized version of the project name
      macos-max-compat true Whether or not on macOS, when build hooks have set the infer_tag build data, the wheel name should signal broad support rather than specific versions for newer SDK versions.

      Note: The default will become false, and this option eventually removed, sometime after consumers like pip start supporting these newer SDK versions.
      bypass-selection false Whether or not to suppress the error when one has not defined any file selection options and all heuristics have failed to determine what to ship

      Versions

      Version Description
      standard (default) The latest standardized format
      editable A wheel that only ships .pth files or import hooks for real-time development

      Default file selection

      When the user has not set any file selection options, the project name will be used to determine the package to ship in the following heuristic order:

      1. <NAME>/__init__.py
      2. src/<NAME>/__init__.py
      3. <NAME>.py
      4. <NAMESPACE>/<NAME>/__init__.py

      If none of these heuristics are satisfied, an error will be raised.

      Reproducibility

      Reproducible builds are supported.

      Build data

      This is data that can be modified by build hooks.

      Data Default Description
      tag The full tag part of the filename (e.g. py3-none-any), defaulting to a cross-platform wheel with the supported major versions of Python based on project metadata
      infer_tag False When tag is not set, this may be enabled to use the one most specific to the platform, Python interpreter, and ABI
      pure_python True Whether or not to write metadata indicating that the package does not contain any platform-specific files
      dependencies Extra project dependencies
      extra_metadata Additional extra-metadata entries, which take precedence in case of conflicts
      force_include_editable Similar to the force_include option but specifically for the editable version and takes precedence
      \ No newline at end of file diff --git a/latest/plugins/environment-collector/custom/index.html b/latest/plugins/environment-collector/custom/index.html index fa339b66b..3b7213d06 100644 --- a/latest/plugins/environment-collector/custom/index.html +++ b/latest/plugins/environment-collector/custom/index.html @@ -1,4 +1,4 @@ - Custom - Hatch

      Custom environment collector


      This is a custom class in a given Python file that inherits from the EnvironmentCollectorInterface.

      Configuration

      The environment collector plugin name is custom.

      [tool.hatch.env.collectors.custom]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Custom environment collector


      This is a custom class in a given Python file that inherits from the EnvironmentCollectorInterface.

      Configuration

      The environment collector plugin name is custom.

      [tool.hatch.env.collectors.custom]
       
      [env.collectors.custom]
       

      Options

      Option Default Description
      path hatch_plugins.py The path of the Python file

      Example

          from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface
       
      diff --git a/latest/plugins/environment-collector/default/index.html b/latest/plugins/environment-collector/default/index.html
      index 4599dbb74..6f326b031 100644
      --- a/latest/plugins/environment-collector/default/index.html
      +++ b/latest/plugins/environment-collector/default/index.html
      @@ -1,4 +1,4 @@
      - Default - Hatch      

      Default environment collector


      This adds the default environment with type set to virtual and will always be applied.

      Configuration

      The environment collector plugin name is default.

      [tool.hatch.env.collectors.default]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Default environment collector


      This adds the default environment with type set to virtual and will always be applied.

      Configuration

      The environment collector plugin name is default.

      [tool.hatch.env.collectors.default]
       
      [env.collectors.default]
       

      Options

      There are no options available currently.

      \ No newline at end of file diff --git a/latest/plugins/environment-collector/reference/index.html b/latest/plugins/environment-collector/reference/index.html index 744a61467..12d490ccb 100644 --- a/latest/plugins/environment-collector/reference/index.html +++ b/latest/plugins/environment-collector/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

      Environment collector plugins


      Environment collectors allow for dynamically modifying environments or adding environments beyond those defined in config. Users can override default values provided by each environment.

      Known third-party

      Installation

      Any required environment collectors that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

      [tool.hatch.env]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Environment collector plugins


      Environment collectors allow for dynamically modifying environments or adding environments beyond those defined in config. Users can override default values provided by each environment.

      Known third-party

      Installation

      Any required environment collectors that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

      [tool.hatch.env]
       requires = [
         "...",
       ]
      diff --git a/latest/plugins/environment/reference/index.html b/latest/plugins/environment/reference/index.html
      index e04e66a46..a5648b4e5 100644
      --- a/latest/plugins/environment/reference/index.html
      +++ b/latest/plugins/environment/reference/index.html
      @@ -1,4 +1,4 @@
      - Reference - Hatch      

      Environment plugins


      See the documentation for environment configuration.

      Known third-party

      Installation

      Any required environment types that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

      [tool.hatch.env]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Environment plugins


      See the documentation for environment configuration.

      Known third-party

      Installation

      Any required environment types that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

      [tool.hatch.env]
       requires = [
         "...",
       ]
      @@ -19,37 +19,38 @@
           if not environment.exists():
               self.env_metadata.reset(environment)
       
      -        with self.status(f'Creating environment: {environment.name}'):
      +        with environment.app_status_creation():
                   environment.create()
       
               if not environment.skip_install:
                   if environment.pre_install_commands:
      -                with self.status('Running pre-installation commands'):
      +                with environment.app_status_pre_installation():
                           self.run_shell_commands(environment, environment.pre_install_commands, source='pre-install')
       
      -            if environment.dev_mode:
      -                with self.status('Installing project in development mode'):
      +            with environment.app_status_project_installation():
      +                if environment.dev_mode:
                           environment.install_project_dev_mode()
      -            else:
      -                with self.status('Installing project'):
      -                    environment.install_project()
      -
      -            if environment.post_install_commands:
      -                with self.status('Running post-installation commands'):
      -                    self.run_shell_commands(environment, environment.post_install_commands, source='post-install')
      -
      -    new_dep_hash = environment.dependency_hash()
      -    current_dep_hash = self.env_metadata.dependency_hash(environment)
      -    if new_dep_hash != current_dep_hash:
      -        with self.status('Checking dependencies'):
      -            dependencies_in_sync = environment.dependencies_in_sync()
      -
      -        if not dependencies_in_sync:
      -            with self.status('Syncing dependencies'):
      -                environment.sync_dependencies()
      -                new_dep_hash = environment.dependency_hash()
      -
      -        self.env_metadata.update_dependency_hash(environment, new_dep_hash)
      +                else:
      +                    environment.install_project()
      +
      +            if environment.post_install_commands:
      +                with environment.app_status_post_installation():
      +                    self.run_shell_commands(environment, environment.post_install_commands, source='post-install')
      +
      +    with environment.app_status_dependency_state_check():
      +        new_dep_hash = environment.dependency_hash()
      +
      +    current_dep_hash = self.env_metadata.dependency_hash(environment)
      +    if new_dep_hash != current_dep_hash:
      +        with environment.app_status_dependency_installation_check():
      +            dependencies_in_sync = environment.dependencies_in_sync()
      +
      +        if not dependencies_in_sync:
      +            with environment.app_status_dependency_synchronization():
      +                environment.sync_dependencies()
      +                new_dep_hash = environment.dependency_hash()
      +
      +        self.env_metadata.update_dependency_hash(environment, new_dep_hash)
       

      Build environments

      All environment types should offer support for a special sub-environment in which projects can be built. This environment is used in the following scenarios:

      EnvironmentInterface

      Example usage:

          from hatch.env.plugin.interface import EnvironmentInterface
       
       
      @@ -604,353 +605,421 @@
               A convenience method called when using the environment as a context manager:
       
               ```python
      -        with environment: ...
      -        ```
      -        """
      -
      -    def deactivate(self):
      -        """
      -        A convenience method called after using the environment as a context manager:
      -
      -        ```python
      -        with environment: ...
      -        ```
      -        """
      -
      -    @abstractmethod
      -    def find(self):
      -        """
      -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -        This should return information about how to locate the environment or represent its ID in
      -        some way. Additionally, this is expected to return something even if the environment is
      -        [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).
      -        """
      -
      -    @abstractmethod
      -    def create(self):
      -        """
      -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -        This should perform the necessary steps to set up the environment.
      -        """
      -
      -    @abstractmethod
      -    def remove(self):
      -        """
      -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -        This should perform the necessary steps to completely remove the environment from the system and will only
      -        be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or
      -        [`env prune`](../../cli/reference.md#hatch-env-prune) commands.
      -
      -        If the
      -        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      -        has a caching mechanism, this should remove that as well.
      -        """
      -
      -    @abstractmethod
      -    def exists(self) -> bool:
      -        """
      -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -        This should indicate whether or not the environment has already been created.
      -        """
      -
      -    @abstractmethod
      -    def install_project(self):
      -        """
      -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -        This should install the project in the environment.
      -        """
      -
      -    @abstractmethod
      -    def install_project_dev_mode(self):
      -        """
      -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -        This should install the project in the environment such that the environment
      -        always reflects the current state of the project.
      -        """
      -
      -    @abstractmethod
      -    def dependencies_in_sync(self) -> bool:
      -        """
      -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -        This should indicate whether or not the environment is compatible with the current
      -        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).
      -        """
      -
      -    @abstractmethod
      -    def sync_dependencies(self):
      -        """
      -        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -        This should install the
      -        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
      -        in the environment.
      -        """
      -
      -    def dependency_hash(self):
      -        """
      -        This should return a hash of the environment's
      -        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
      -        and any other data that is handled by the
      -        [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)
      -        and
      -        [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)
      -        methods.
      -        """
      -        from hatch.utils.dep import hash_dependencies
      -
      -        return hash_dependencies(self.dependencies_complex)
      +        with environment:
      +            ...
      +        ```
      +        """
      +
      +    def deactivate(self):
      +        """
      +        A convenience method called after using the environment as a context manager:
      +
      +        ```python
      +        with environment:
      +            ...
      +        ```
      +        """
      +
      +    @abstractmethod
      +    def find(self):
      +        """
      +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +        This should return information about how to locate the environment or represent its ID in
      +        some way. Additionally, this is expected to return something even if the environment is
      +        [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).
      +        """
      +
      +    @abstractmethod
      +    def create(self):
      +        """
      +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +        This should perform the necessary steps to set up the environment.
      +        """
      +
      +    @abstractmethod
      +    def remove(self):
      +        """
      +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +        This should perform the necessary steps to completely remove the environment from the system and will only
      +        be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or
      +        [`env prune`](../../cli/reference.md#hatch-env-prune) commands.
      +
      +        If the
      +        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      +        has a caching mechanism, this should remove that as well.
      +        """
      +
      +    @abstractmethod
      +    def exists(self) -> bool:
      +        """
      +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +        This should indicate whether or not the environment has already been created.
      +        """
      +
      +    @abstractmethod
      +    def install_project(self):
      +        """
      +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +        This should install the project in the environment.
      +        """
      +
      +    @abstractmethod
      +    def install_project_dev_mode(self):
      +        """
      +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +        This should install the project in the environment such that the environment
      +        always reflects the current state of the project.
      +        """
      +
      +    @abstractmethod
      +    def dependencies_in_sync(self) -> bool:
      +        """
      +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +        This should indicate whether or not the environment is compatible with the current
      +        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).
      +        """
      +
      +    @abstractmethod
      +    def sync_dependencies(self):
      +        """
      +        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +        This should install the
      +        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
      +        in the environment.
      +        """
      +
      +    def dependency_hash(self):
      +        """
      +        This should return a hash of the environment's
      +        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
      +        and any other data that is handled by the
      +        [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)
      +        and
      +        [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)
      +        methods.
      +        """
      +        from hatch.utils.dep import hash_dependencies
       
      -    @contextmanager
      -    def build_environment(
      -        self,
      -        dependencies: list[str],  # noqa: ARG002
      -    ):
      -        """
      -        This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project
      -        given a set of dependencies and must be a context manager:
      -
      -        ```python
      -        with environment.build_environment([...]): ...
      -        ```
      -
      -        The build environment should reflect any
      -        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
      -        the user defined either currently or at the time of
      -        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      -        """
      -        with self.get_env_vars():
      -            yield
      -
      -    def run_builder(
      -        self,
      -        build_environment,  # noqa: ARG002
      -        **kwargs,
      -    ):
      -        """
      -        This will be called when the
      -        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      -        is active:
      -
      -        ```python
      -        with environment.build_environment([...]) as build_env:
      -            process = environment.run_builder(build_env, ...)
      -        ```
      -
      -        This should return the standard library's
      -        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).
      -        The command is constructed by passing all keyword arguments to
      -        [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).
      -
      -        For an example, open the default implementation below:
      +        return hash_dependencies(self.dependencies_complex)
      +
      +    @contextmanager
      +    def app_status_creation(self):
      +        """
      +        See the [life cycle of environments](reference.md#life-cycle).
      +        """
      +        with self.app.status(f'Creating environment: {self.name}'):
      +            yield
      +
      +    @contextmanager
      +    def app_status_pre_installation(self):
      +        """
      +        See the [life cycle of environments](reference.md#life-cycle).
      +        """
      +        with self.app.status('Running pre-installation commands'):
      +            yield
      +
      +    @contextmanager
      +    def app_status_post_installation(self):
      +        """
      +        See the [life cycle of environments](reference.md#life-cycle).
      +        """
      +        with self.app.status('Running post-installation commands'):
      +            yield
      +
      +    @contextmanager
      +    def app_status_project_installation(self):
      +        """
      +        See the [life cycle of environments](reference.md#life-cycle).
      +        """
      +        if self.dev_mode:
      +            with self.app.status('Installing project in development mode'):
      +                yield
      +        else:
      +            with self.app.status('Installing project'):
      +                yield
      +
      +    @contextmanager
      +    def app_status_dependency_state_check(self):
      +        """
      +        See the [life cycle of environments](reference.md#life-cycle).
               """
      -        return self.platform.run_command(self.construct_build_command(**kwargs))
      -
      -    def build_environment_exists(self):  # noqa: PLR6301
      -        """
      -        If the
      -        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      -        has a caching mechanism, this should indicate whether or not it has already been created.
      -        """
      -        return False
      -
      -    def enter_shell(
      -        self,
      -        name: str,  # noqa: ARG002
      -        path: str,
      -        args: Iterable[str],
      -    ):
      -        """
      -        Spawn a [shell](../../config/hatch.md#shell) within the environment.
      -
      -        This should either use
      -        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
      -        directly or provide the same guarantee.
      -        """
      -        with self.command_context():
      -            self.platform.exit_with_command([path, *args])
      -
      -    def run_shell_command(self, command: str, **kwargs):
      -        """
      -        This should return the standard library's
      -        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)
      -        and will always be called when the
      -        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
      -        is active, with the expectation of providing the same guarantee.
      -        """
      -        kwargs.setdefault('shell', True)
      -        return self.platform.run_command(command, **kwargs)
      -
      -    @contextmanager
      -    def command_context(self):
      -        """
      -        A context manager that when active should make executed shell commands reflect any
      -        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
      -        the user defined either currently or at the time of
      -        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      -
      -        For an example, open the default implementation below:
      -        """
      -        with self.get_env_vars():
      -            yield
      -
      -    def resolve_commands(self, commands: list[str]):
      +        if not self.skip_install and (
      +            'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic
      +        ):
      +            with self.app.status('Polling dependency state'):
      +                yield
      +        else:
      +            yield
      +
      +    @contextmanager
      +    def app_status_dependency_installation_check(self):
      +        """
      +        See the [life cycle of environments](reference.md#life-cycle).
      +        """
      +        with self.app.status('Checking dependencies'):
      +            yield
      +
      +    @contextmanager
      +    def app_status_dependency_synchronization(self):
      +        """
      +        See the [life cycle of environments](reference.md#life-cycle).
      +        """
      +        with self.app.status('Syncing dependencies'):
      +            yield
      +
      +    @contextmanager
      +    def build_environment(
      +        self,
      +        dependencies: list[str],  # noqa: ARG002
      +    ):
      +        """
      +        This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project
      +        given a set of dependencies and must be a context manager:
      +
      +        ```python
      +        with environment.build_environment([...]):
      +            ...
      +        ```
      +
      +        The build environment should reflect any
      +        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
      +        the user defined either currently or at the time of
      +        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      +        """
      +        with self.get_env_vars():
      +            yield
      +
      +    def run_builder(
      +        self,
      +        build_environment,  # noqa: ARG002
      +        **kwargs,
      +    ):
               """
      -        This expands each command into one or more commands based on any
      -        [scripts](../../config/environment/overview.md#scripts) that the user defined.
      -        """
      -        for command in commands:
      -            yield from self.expand_command(command)
      -
      -    def expand_command(self, command):
      -        possible_script, args, _ignore_exit_code = parse_script_command(command)
      +        This will be called when the
      +        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      +        is active:
      +
      +        ```python
      +        with environment.build_environment([...]) as build_env:
      +            process = environment.run_builder(build_env, ...)
      +        ```
       
      -        # Indicate undefined
      -        if not args:
      -            args = None
      -
      -        with self.apply_context():
      -            if possible_script in self.scripts:
      -                for cmd in self.scripts[possible_script]:
      -                    yield self.metadata.context.format(cmd, args=args).strip()
      -            else:
      -                yield self.metadata.context.format(command, args=args).strip()
      -
      -    def construct_build_command(  # noqa: PLR6301
      -        self,
      -        *,
      -        directory=None,
      -        targets=(),
      -        hooks_only=False,
      -        no_hooks=False,
      -        clean=False,
      -        clean_hooks_after=False,
      -        clean_only=False,
      -    ):
      -        """
      -        This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to
      -        a subprocess command issued to [builders](../builder/reference.md).
      -        """
      -        command = ['python', '-u', '-m', 'hatchling', 'build']
      -
      -        if directory:
      -            command.extend(('--directory', directory))
      -
      -        if targets:
      -            for target in targets:
      -                command.extend(('--target', target))
      -
      -        if hooks_only:
      -            command.append('--hooks-only')
      -
      -        if no_hooks:
      -            command.append('--no-hooks')
      -
      -        if clean:
      -            command.append('--clean')
      +        This should return the standard library's
      +        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).
      +        The command is constructed by passing all keyword arguments to
      +        [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).
      +
      +        For an example, open the default implementation below:
      +        """
      +        return self.platform.run_command(self.construct_build_command(**kwargs))
      +
      +    def build_environment_exists(self):  # noqa: PLR6301
      +        """
      +        If the
      +        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      +        has a caching mechanism, this should indicate whether or not it has already been created.
      +        """
      +        return False
      +
      +    def enter_shell(
      +        self,
      +        name: str,  # noqa: ARG002
      +        path: str,
      +        args: Iterable[str],
      +    ):
      +        """
      +        Spawn a [shell](../../config/hatch.md#shell) within the environment.
      +
      +        This should either use
      +        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
      +        directly or provide the same guarantee.
      +        """
      +        with self.command_context():
      +            self.platform.exit_with_command([path, *args])
      +
      +    def run_shell_command(self, command: str, **kwargs):
      +        """
      +        This should return the standard library's
      +        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)
      +        and will always be called when the
      +        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
      +        is active, with the expectation of providing the same guarantee.
      +        """
      +        kwargs.setdefault('shell', True)
      +        return self.platform.run_command(command, **kwargs)
       
      -        if clean_hooks_after:
      -            command.append('--clean-hooks-after')
      -
      -        if clean_only:
      -            command.append('--clean-only')
      -
      -        return command
      +    @contextmanager
      +    def command_context(self):
      +        """
      +        A context manager that when active should make executed shell commands reflect any
      +        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
      +        the user defined either currently or at the time of
      +        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
       
      -    def construct_pip_install_command(self, args: list[str]):
      -        """
      -        A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)
      -        command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.
      -        """
      -        command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']
      -
      -        # Default to -1 verbosity
      -        add_verbosity_flag(command, self.verbosity, adjustment=-1)
      -
      -        command.extend(args)
      -        return command
      +        For an example, open the default implementation below:
      +        """
      +        with self.get_env_vars():
      +            yield
      +
      +    def resolve_commands(self, commands: list[str]):
      +        """
      +        This expands each command into one or more commands based on any
      +        [scripts](../../config/environment/overview.md#scripts) that the user defined.
      +        """
      +        for command in commands:
      +            yield from self.expand_command(command)
       
      -    def join_command_args(self, args: list[str]):
      -        """
      -        This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string
      -        from the received arguments.
      -        """
      -        return self.platform.join_command_args(args)
      +    def expand_command(self, command):
      +        possible_script, args, _ignore_exit_code = parse_script_command(command)
      +
      +        # Indicate undefined
      +        if not args:
      +            args = None
       
      -    def apply_features(self, requirement: str):
      -        """
      -        A convenience method that applies any user defined [features](../../config/environment/overview.md#features)
      -        to the given requirement.
      -        """
      -        if self.features:
      -            features = ','.join(self.features)
      -            return f'{requirement}[{features}]'
      -
      -        return requirement
      -
      -    def check_compatibility(self):
      -        """
      -        This raises an exception if the environment is not compatible with the user's setup. The default behavior
      -        checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)
      -        and any method override should keep this check.
      -
      -        This check is never performed if the environment has been
      -        [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      -        """
      -        if self.platforms and self.platform.name not in self.platforms:
      -            message = 'unsupported platform'
      -            raise OSError(message)
      +        with self.apply_context():
      +            if possible_script in self.scripts:
      +                for cmd in self.scripts[possible_script]:
      +                    yield self.metadata.context.format(cmd, args=args).strip()
      +            else:
      +                yield self.metadata.context.format(command, args=args).strip()
      +
      +    def construct_build_command(  # noqa: PLR6301
      +        self,
      +        *,
      +        directory=None,
      +        targets=(),
      +        hooks_only=False,
      +        no_hooks=False,
      +        clean=False,
      +        clean_hooks_after=False,
      +        clean_only=False,
      +    ):
      +        """
      +        This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to
      +        a subprocess command issued to [builders](../builder/reference.md).
      +        """
      +        command = ['python', '-u', '-m', 'hatchling', 'build']
       
      -    def get_env_vars(self) -> EnvVars:
      -        """
      -        Returns a mapping of environment variables that should be available to the environment. The object can
      -        be used as a context manager to temporarily apply the environment variables to the current process.
      -
      -        !!! note
      -            The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.
      -        """
      -        return EnvVars(self.env_vars, self.env_include, self.env_exclude)
      +        if directory:
      +            command.extend(('--directory', directory))
      +
      +        if targets:
      +            for target in targets:
      +                command.extend(('--target', target))
      +
      +        if hooks_only:
      +            command.append('--hooks-only')
       
      -    def get_env_var_option(self, option: str) -> str:
      -        """
      -        Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.
      -        """
      -        return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')
      +        if no_hooks:
      +            command.append('--no-hooks')
      +
      +        if clean:
      +            command.append('--clean')
       
      -    def get_context(self):
      -        """
      -        Returns a subclass of
      -        [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).
      -        """
      -        from hatch.env.context import EnvironmentContextFormatter
      -
      -        return EnvironmentContextFormatter(self)
      -
      -    @staticmethod
      -    def get_option_types() -> dict:
      -        """
      -        Returns a mapping of supported options to their respective types so that they can be used by
      -        [overrides](../../config/environment/advanced.md#option-overrides).
      -        """
      -        return {}
      -
      -    @contextmanager
      -    def apply_context(self):
      -        with self.get_env_vars(), self.metadata.context.apply_context(self.context):
      -            yield
      -
      -    def __enter__(self):
      -        self.activate()
      -        return self
      -
      -    def __exit__(self, exc_type, exc_value, traceback):
      -        self.deactivate()
      +        if clean_hooks_after:
      +            command.append('--clean-hooks-after')
      +
      +        if clean_only:
      +            command.append('--clean-only')
      +
      +        return command
      +
      +    def construct_pip_install_command(self, args: list[str]):
      +        """
      +        A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)
      +        command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.
      +        """
      +        command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']
      +
      +        # Default to -1 verbosity
      +        add_verbosity_flag(command, self.verbosity, adjustment=-1)
      +
      +        command.extend(args)
      +        return command
      +
      +    def join_command_args(self, args: list[str]):
      +        """
      +        This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string
      +        from the received arguments.
      +        """
      +        return self.platform.join_command_args(args)
      +
      +    def apply_features(self, requirement: str):
      +        """
      +        A convenience method that applies any user defined [features](../../config/environment/overview.md#features)
      +        to the given requirement.
      +        """
      +        if self.features:
      +            features = ','.join(self.features)
      +            return f'{requirement}[{features}]'
      +
      +        return requirement
      +
      +    def check_compatibility(self):
      +        """
      +        This raises an exception if the environment is not compatible with the user's setup. The default behavior
      +        checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)
      +        and any method override should keep this check.
      +
      +        This check is never performed if the environment has been
      +        [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      +        """
      +        if self.platforms and self.platform.name not in self.platforms:
      +            message = 'unsupported platform'
      +            raise OSError(message)
      +
      +    def get_env_vars(self) -> EnvVars:
      +        """
      +        Returns a mapping of environment variables that should be available to the environment. The object can
      +        be used as a context manager to temporarily apply the environment variables to the current process.
      +
      +        !!! note
      +            The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.
      +        """
      +        return EnvVars(self.env_vars, self.env_include, self.env_exclude)
      +
      +    def get_env_var_option(self, option: str) -> str:
      +        """
      +        Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.
      +        """
      +        return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')
      +
      +    def get_context(self):
      +        """
      +        Returns a subclass of
      +        [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).
      +        """
      +        from hatch.env.context import EnvironmentContextFormatter
      +
      +        return EnvironmentContextFormatter(self)
      +
      +    @staticmethod
      +    def get_option_types() -> dict:
      +        """
      +        Returns a mapping of supported options to their respective types so that they can be used by
      +        [overrides](../../config/environment/advanced.md#option-overrides).
      +        """
      +        return {}
      +
      +    @contextmanager
      +    def apply_context(self):
      +        with self.get_env_vars(), self.metadata.context.apply_context(self.context):
      +            yield
      +
      +    def __enter__(self):
      +        self.activate()
      +        return self
      +
      +    def __exit__(self, exc_type, exc_value, traceback):
      +        self.deactivate()
       

      PLUGIN_NAME = '' class-attribute instance-attribute

      The name used for selection.

      app property

      An instance of Application.

      root property

      The root of the project tree as a path-like object.

      name: str property

      The name of the environment.

      data_directory property

      The directory this plugin should use for storage as a path-like object. If the user has not configured one then this will be the same as the isolated data directory.

      isolated_data_directory property

      The default directory reserved exclusively for this plugin as a path-like object.

      config: dict property

      [tool.hatch.envs.<ENV_NAME>]
       
      [envs.<ENV_NAME>]
       

      platform property

      An instance of Platform.

      environment_dependencies: list[str] property

      The list of all environment dependencies.

      dependencies: list[str] property

      env_vars: dict property

      [tool.hatch.envs.<ENV_NAME>.env-vars]
      @@ -979,309 +1048,373 @@
       description = ...
       
      [envs.<ENV_NAME>]
       description = ...
      -

      activate()

      A convenience method called when using the environment as a context manager:

      with environment: ...
      +

      find() abstractmethod

      REQUIRED

      This should return information about how to locate the environment or represent its ID in some way. Additionally, this is expected to return something even if the environment is incompatible.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      +def find(self):
      +    """
      +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +    This should return information about how to locate the environment or represent its ID in
      +    some way. Additionally, this is expected to return something even if the environment is
      +    [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).
      +    """
      +

      create() abstractmethod

      REQUIRED

      This should perform the necessary steps to set up the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      +def create(self):
      +    """
      +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +    This should perform the necessary steps to set up the environment.
      +    """
      +

      remove() abstractmethod

      REQUIRED

      This should perform the necessary steps to completely remove the environment from the system and will only be triggered manually by users with the env remove or env prune commands.

      If the build environment has a caching mechanism, this should remove that as well.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      +def remove(self):
      +    """
      +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +    This should perform the necessary steps to completely remove the environment from the system and will only
      +    be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or
      +    [`env prune`](../../cli/reference.md#hatch-env-prune) commands.
      +
      +    If the
      +    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      +    has a caching mechanism, this should remove that as well.
      +    """
      +

      exists() -> bool abstractmethod

      REQUIRED

      This should indicate whether or not the environment has already been created.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      +def exists(self) -> bool:
      +    """
      +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +    This should indicate whether or not the environment has already been created.
      +    """
      +

      install_project() abstractmethod

      REQUIRED

      This should install the project in the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      +def install_project(self):
      +    """
      +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +    This should install the project in the environment.
      +    """
      +

      install_project_dev_mode() abstractmethod

      REQUIRED

      This should install the project in the environment such that the environment always reflects the current state of the project.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      +def install_project_dev_mode(self):
      +    """
      +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +    This should install the project in the environment such that the environment
      +    always reflects the current state of the project.
      +    """
      +

      dependencies_in_sync() -> bool abstractmethod

      REQUIRED

      This should indicate whether or not the environment is compatible with the current dependencies.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      +def dependencies_in_sync(self) -> bool:
      +    """
      +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +    This should indicate whether or not the environment is compatible with the current
      +    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).
      +    """
      +

      sync_dependencies() abstractmethod

      REQUIRED

      This should install the dependencies in the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      +def sync_dependencies(self):
      +    """
      +    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      +
      +    This should install the
      +    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
      +    in the environment.
      +    """
      +

      dependency_hash()

      This should return a hash of the environment's dependencies and any other data that is handled by the sync_dependencies and dependencies_in_sync methods.

      Source code in src/hatch/env/plugin/interface.py
      def dependency_hash(self):
      +    """
      +    This should return a hash of the environment's
      +    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
      +    and any other data that is handled by the
      +    [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)
      +    and
      +    [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)
      +    methods.
      +    """
      +    from hatch.utils.dep import hash_dependencies
      +
      +    return hash_dependencies(self.dependencies_complex)
      +

      build_environment(dependencies: list[str])

      This should set up an isolated environment in which to build the project given a set of dependencies and must be a context manager:

      with environment.build_environment([...]):
      +    ...
      +

      The build environment should reflect any environment variables the user defined either currently or at the time of creation.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      +def build_environment(
      +    self,
      +    dependencies: list[str],  # noqa: ARG002
      +):
      +    """
      +    This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project
      +    given a set of dependencies and must be a context manager:
      +
      +    ```python
      +    with environment.build_environment([...]):
      +        ...
      +    ```
      +
      +    The build environment should reflect any
      +    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
      +    the user defined either currently or at the time of
      +    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      +    """
      +    with self.get_env_vars():
      +        yield
      +

      build_environment_exists()

      If the build environment has a caching mechanism, this should indicate whether or not it has already been created.

      Source code in src/hatch/env/plugin/interface.py
      def build_environment_exists(self):  # noqa: PLR6301
      +    """
      +    If the
      +    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      +    has a caching mechanism, this should indicate whether or not it has already been created.
      +    """
      +    return False
      +

      activate()

      A convenience method called when using the environment as a context manager:

      with environment:
      +    ...
       
      Source code in src/hatch/env/plugin/interface.py
      def activate(self):
           """
           A convenience method called when using the environment as a context manager:
       
           ```python
      -    with environment: ...
      -    ```
      -    """
      -

      deactivate()

      A convenience method called after using the environment as a context manager:

      with environment: ...
      -
      Source code in src/hatch/env/plugin/interface.py
      def deactivate(self):
      -    """
      -    A convenience method called after using the environment as a context manager:
      -
      -    ```python
      -    with environment: ...
      -    ```
      -    """
      -

      find() abstractmethod

      REQUIRED

      This should return information about how to locate the environment or represent its ID in some way. Additionally, this is expected to return something even if the environment is incompatible.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      -def find(self):
      -    """
      -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -    This should return information about how to locate the environment or represent its ID in
      -    some way. Additionally, this is expected to return something even if the environment is
      -    [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).
      -    """
      -

      create() abstractmethod

      REQUIRED

      This should perform the necessary steps to set up the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      -def create(self):
      -    """
      -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -    This should perform the necessary steps to set up the environment.
      -    """
      -

      remove() abstractmethod

      REQUIRED

      This should perform the necessary steps to completely remove the environment from the system and will only be triggered manually by users with the env remove or env prune commands.

      If the build environment has a caching mechanism, this should remove that as well.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      -def remove(self):
      -    """
      -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -    This should perform the necessary steps to completely remove the environment from the system and will only
      -    be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or
      -    [`env prune`](../../cli/reference.md#hatch-env-prune) commands.
      -
      -    If the
      -    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      -    has a caching mechanism, this should remove that as well.
      -    """
      -

      exists() -> bool abstractmethod

      REQUIRED

      This should indicate whether or not the environment has already been created.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      -def exists(self) -> bool:
      -    """
      -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -    This should indicate whether or not the environment has already been created.
      -    """
      -

      install_project() abstractmethod

      REQUIRED

      This should install the project in the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      -def install_project(self):
      -    """
      -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -    This should install the project in the environment.
      -    """
      -

      install_project_dev_mode() abstractmethod

      REQUIRED

      This should install the project in the environment such that the environment always reflects the current state of the project.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      -def install_project_dev_mode(self):
      -    """
      -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -    This should install the project in the environment such that the environment
      -    always reflects the current state of the project.
      -    """
      -

      dependencies_in_sync() -> bool abstractmethod

      REQUIRED

      This should indicate whether or not the environment is compatible with the current dependencies.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      -def dependencies_in_sync(self) -> bool:
      -    """
      -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -    This should indicate whether or not the environment is compatible with the current
      -    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).
      -    """
      -

      sync_dependencies() abstractmethod

      REQUIRED

      This should install the dependencies in the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod
      -def sync_dependencies(self):
      -    """
      -    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:
      -
      -    This should install the
      -    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
      -    in the environment.
      -    """
      -

      dependency_hash()

      This should return a hash of the environment's dependencies and any other data that is handled by the sync_dependencies and dependencies_in_sync methods.

      Source code in src/hatch/env/plugin/interface.py
      def dependency_hash(self):
      -    """
      -    This should return a hash of the environment's
      -    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)
      -    and any other data that is handled by the
      -    [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)
      -    and
      -    [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)
      -    methods.
      -    """
      -    from hatch.utils.dep import hash_dependencies
      -
      -    return hash_dependencies(self.dependencies_complex)
      -

      build_environment(dependencies: list[str])

      This should set up an isolated environment in which to build the project given a set of dependencies and must be a context manager:

      with environment.build_environment([...]): ...
      -

      The build environment should reflect any environment variables the user defined either currently or at the time of creation.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      -def build_environment(
      -    self,
      -    dependencies: list[str],  # noqa: ARG002
      -):
      -    """
      -    This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project
      -    given a set of dependencies and must be a context manager:
      -
      -    ```python
      -    with environment.build_environment([...]): ...
      -    ```
      -
      -    The build environment should reflect any
      -    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
      -    the user defined either currently or at the time of
      -    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      -    """
      -    with self.get_env_vars():
      -        yield
      -

      build_environment_exists()

      If the build environment has a caching mechanism, this should indicate whether or not it has already been created.

      Source code in src/hatch/env/plugin/interface.py
      def build_environment_exists(self):  # noqa: PLR6301
      -    """
      -    If the
      -    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      -    has a caching mechanism, this should indicate whether or not it has already been created.
      -    """
      -    return False
      +    with environment:
      +        ...
      +    ```
      +    """
      +

      deactivate()

      A convenience method called after using the environment as a context manager:

      with environment:
      +    ...
      +
      Source code in src/hatch/env/plugin/interface.py
      def deactivate(self):
      +    """
      +    A convenience method called after using the environment as a context manager:
      +
      +    ```python
      +    with environment:
      +        ...
      +    ```
      +    """
      +

      app_status_creation()

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      +def app_status_creation(self):
      +    """
      +    See the [life cycle of environments](reference.md#life-cycle).
      +    """
      +    with self.app.status(f'Creating environment: {self.name}'):
      +        yield
      +

      app_status_pre_installation()

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      +def app_status_pre_installation(self):
      +    """
      +    See the [life cycle of environments](reference.md#life-cycle).
      +    """
      +    with self.app.status('Running pre-installation commands'):
      +        yield
      +

      app_status_post_installation()

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      +def app_status_post_installation(self):
      +    """
      +    See the [life cycle of environments](reference.md#life-cycle).
      +    """
      +    with self.app.status('Running post-installation commands'):
      +        yield
      +

      app_status_project_installation()

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      +def app_status_project_installation(self):
      +    """
      +    See the [life cycle of environments](reference.md#life-cycle).
      +    """
      +    if self.dev_mode:
      +        with self.app.status('Installing project in development mode'):
      +            yield
      +    else:
      +        with self.app.status('Installing project'):
      +            yield
      +

      app_status_dependency_state_check()

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      +def app_status_dependency_state_check(self):
      +    """
      +    See the [life cycle of environments](reference.md#life-cycle).
      +    """
      +    if not self.skip_install and (
      +        'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic
      +    ):
      +        with self.app.status('Polling dependency state'):
      +            yield
      +    else:
      +        yield
      +

      app_status_dependency_installation_check()

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      +def app_status_dependency_installation_check(self):
      +    """
      +    See the [life cycle of environments](reference.md#life-cycle).
      +    """
      +    with self.app.status('Checking dependencies'):
      +        yield
      +

      app_status_dependency_synchronization()

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      +def app_status_dependency_synchronization(self):
      +    """
      +    See the [life cycle of environments](reference.md#life-cycle).
      +    """
      +    with self.app.status('Syncing dependencies'):
      +        yield
       

      run_builder(build_environment, **kwargs)

      This will be called when the build environment is active:

      with environment.build_environment([...]) as build_env:
           process = environment.run_builder(build_env, ...)
      -

      This should return the standard library's subprocess.CompletedProcess. The command is constructed by passing all keyword arguments to construct_build_command.

      For an example, open the default implementation below:

      Source code in src/hatch/env/plugin/interface.py
      def run_builder(
      -    self,
      -    build_environment,  # noqa: ARG002
      -    **kwargs,
      -):
      -    """
      -    This will be called when the
      -    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)
      -    is active:
      -
      -    ```python
      -    with environment.build_environment([...]) as build_env:
      -        process = environment.run_builder(build_env, ...)
      -    ```
      -
      -    This should return the standard library's
      -    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).
      -    The command is constructed by passing all keyword arguments to
      -    [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).
      -
      -    For an example, open the default implementation below:
      -    """
      -    return self.platform.run_command(self.construct_build_command(**kwargs))
      -

      construct_build_command(*, directory=None, targets=(), hooks_only=False, no_hooks=False, clean=False, clean_hooks_after=False, clean_only=False)

      This is the canonical way build command options are translated to a subprocess command issued to builders.

      Source code in src/hatch/env/plugin/interface.py
      def construct_build_command(  # noqa: PLR6301
      -    self,
      -    *,
      -    directory=None,
      -    targets=(),
      -    hooks_only=False,
      -    no_hooks=False,
      -    clean=False,
      -    clean_hooks_after=False,
      -    clean_only=False,
      -):
      -    """
      -    This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to
      -    a subprocess command issued to [builders](../builder/reference.md).
      -    """
      -    command = ['python', '-u', '-m', 'hatchling', 'build']
      -
      -    if directory:
      -        command.extend(('--directory', directory))
      -
      -    if targets:
      -        for target in targets:
      -            command.extend(('--target', target))
      -
      -    if hooks_only:
      -        command.append('--hooks-only')
      -
      -    if no_hooks:
      -        command.append('--no-hooks')
      -
      -    if clean:
      -        command.append('--clean')
      -
      -    if clean_hooks_after:
      -        command.append('--clean-hooks-after')
      -
      -    if clean_only:
      -        command.append('--clean-only')
      -
      -    return command
      -

      command_context()

      A context manager that when active should make executed shell commands reflect any environment variables the user defined either currently or at the time of creation.

      For an example, open the default implementation below:

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      -def command_context(self):
      -    """
      -    A context manager that when active should make executed shell commands reflect any
      -    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
      -    the user defined either currently or at the time of
      -    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      -
      -    For an example, open the default implementation below:
      -    """
      -    with self.get_env_vars():
      -        yield
      -

      enter_shell(name: str, path: str, args: Iterable[str])

      Spawn a shell within the environment.

      This should either use command_context directly or provide the same guarantee.

      Source code in src/hatch/env/plugin/interface.py
      def enter_shell(
      -    self,
      -    name: str,  # noqa: ARG002
      -    path: str,
      -    args: Iterable[str],
      -):
      -    """
      -    Spawn a [shell](../../config/hatch.md#shell) within the environment.
      -
      -    This should either use
      -    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
      -    directly or provide the same guarantee.
      -    """
      -    with self.command_context():
      -        self.platform.exit_with_command([path, *args])
      -

      run_shell_command(command: str, **kwargs)

      This should return the standard library's subprocess.CompletedProcess and will always be called when the command_context is active, with the expectation of providing the same guarantee.

      Source code in src/hatch/env/plugin/interface.py
      def run_shell_command(self, command: str, **kwargs):
      -    """
      -    This should return the standard library's
      -    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)
      -    and will always be called when the
      -    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
      -    is active, with the expectation of providing the same guarantee.
      -    """
      -    kwargs.setdefault('shell', True)
      -    return self.platform.run_command(command, **kwargs)
      -

      resolve_commands(commands: list[str])

      This expands each command into one or more commands based on any scripts that the user defined.

      Source code in src/hatch/env/plugin/interface.py
      def resolve_commands(self, commands: list[str]):
      +

      This should return the standard library's subprocess.CompletedProcess. The command is constructed by passing all keyword arguments to construct_build_command.

      For an example, open the default implementation below:

      Source code in src/hatch/env/plugin/interface.py
      def run_builder(
      +    self,
      +    build_environment,  # noqa: ARG002
      +    **kwargs,
      +):
           """
      -    This expands each command into one or more commands based on any
      -    [scripts](../../config/environment/overview.md#scripts) that the user defined.
      -    """
      -    for command in commands:
      -        yield from self.expand_command(command)
      -

      get_env_vars() -> EnvVars

      Returns a mapping of environment variables that should be available to the environment. The object can be used as a context manager to temporarily apply the environment variables to the current process.

      Note

      The environment variable HATCH_ENV_ACTIVE will always be set to the name of the environment.

      Source code in src/hatch/env/plugin/interface.py
      def get_env_vars(self) -> EnvVars:
      -    """
      -    Returns a mapping of environment variables that should be available to the environment. The object can
      -    be used as a context manager to temporarily apply the environment variables to the current process.
      -
      -    !!! note
      -        The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.
      -    """
      -    return EnvVars(self.env_vars, self.env_include, self.env_exclude)
      -

      apply_features(requirement: str)

      A convenience method that applies any user defined features to the given requirement.

      Source code in src/hatch/env/plugin/interface.py
      def apply_features(self, requirement: str):
      -    """
      -    A convenience method that applies any user defined [features](../../config/environment/overview.md#features)
      -    to the given requirement.
      -    """
      -    if self.features:
      -        features = ','.join(self.features)
      -        return f'{requirement}[{features}]'
      -
      -    return requirement
      -

      construct_pip_install_command(args: list[str])

      A convenience method for constructing a pip install command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.

      Source code in src/hatch/env/plugin/interface.py
      def construct_pip_install_command(self, args: list[str]):
      -    """
      -    A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)
      -    command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.
      -    """
      -    command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']
      -
      -    # Default to -1 verbosity
      -    add_verbosity_flag(command, self.verbosity, adjustment=-1)
      -
      -    command.extend(args)
      -    return command
      -

      join_command_args(args: list[str])

      This is used by the run command to construct the root command string from the received arguments.

      Source code in src/hatch/env/plugin/interface.py
      def join_command_args(self, args: list[str]):
      -    """
      -    This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string
      -    from the received arguments.
      -    """
      -    return self.platform.join_command_args(args)
      -

      check_compatibility()

      This raises an exception if the environment is not compatible with the user's setup. The default behavior checks for platform compatibility and any method override should keep this check.

      This check is never performed if the environment has been created.

      Source code in src/hatch/env/plugin/interface.py
      def check_compatibility(self):
      -    """
      -    This raises an exception if the environment is not compatible with the user's setup. The default behavior
      -    checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)
      -    and any method override should keep this check.
      -
      -    This check is never performed if the environment has been
      -    [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      -    """
      -    if self.platforms and self.platform.name not in self.platforms:
      -        message = 'unsupported platform'
      -        raise OSError(message)
      -

      get_option_types() -> dict staticmethod

      Returns a mapping of supported options to their respective types so that they can be used by overrides.

      Source code in src/hatch/env/plugin/interface.py
      @staticmethod
      -def get_option_types() -> dict:
      -    """
      -    Returns a mapping of supported options to their respective types so that they can be used by
      -    [overrides](../../config/environment/advanced.md#option-overrides).
      -    """
      -    return {}
      -

      get_env_var_option(option: str) -> str

      Returns the value of the upper-cased environment variable HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>.

      Source code in src/hatch/env/plugin/interface.py
      def get_env_var_option(self, option: str) -> str:
      -    """
      -    Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.
      -    """
      -    return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')
      -

      get_context()

      Returns a subclass of EnvironmentContextFormatter.

      Source code in src/hatch/env/plugin/interface.py
      def get_context(self):
      -    """
      -    Returns a subclass of
      -    [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).
      -    """
      -    from hatch.env.context import EnvironmentContextFormatter
      -
      -    return EnvironmentContextFormatter(self)
      -
      \ No newline at end of file + This will be called when the + [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment) + is active: + + ```python + with environment.build_environment([...]) as build_env: + process = environment.run_builder(build_env, ...) + ``` + + This should return the standard library's + [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess). + The command is constructed by passing all keyword arguments to + [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command). + + For an example, open the default implementation below: + """ + return self.platform.run_command(self.construct_build_command(**kwargs)) +

      construct_build_command(*, directory=None, targets=(), hooks_only=False, no_hooks=False, clean=False, clean_hooks_after=False, clean_only=False)

      This is the canonical way build command options are translated to a subprocess command issued to builders.

      Source code in src/hatch/env/plugin/interface.py
      def construct_build_command(  # noqa: PLR6301
      +    self,
      +    *,
      +    directory=None,
      +    targets=(),
      +    hooks_only=False,
      +    no_hooks=False,
      +    clean=False,
      +    clean_hooks_after=False,
      +    clean_only=False,
      +):
      +    """
      +    This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to
      +    a subprocess command issued to [builders](../builder/reference.md).
      +    """
      +    command = ['python', '-u', '-m', 'hatchling', 'build']
      +
      +    if directory:
      +        command.extend(('--directory', directory))
      +
      +    if targets:
      +        for target in targets:
      +            command.extend(('--target', target))
      +
      +    if hooks_only:
      +        command.append('--hooks-only')
      +
      +    if no_hooks:
      +        command.append('--no-hooks')
      +
      +    if clean:
      +        command.append('--clean')
      +
      +    if clean_hooks_after:
      +        command.append('--clean-hooks-after')
      +
      +    if clean_only:
      +        command.append('--clean-only')
      +
      +    return command
      +

      command_context()

      A context manager that when active should make executed shell commands reflect any environment variables the user defined either currently or at the time of creation.

      For an example, open the default implementation below:

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager
      +def command_context(self):
      +    """
      +    A context manager that when active should make executed shell commands reflect any
      +    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)
      +    the user defined either currently or at the time of
      +    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      +
      +    For an example, open the default implementation below:
      +    """
      +    with self.get_env_vars():
      +        yield
      +

      enter_shell(name: str, path: str, args: Iterable[str])

      Spawn a shell within the environment.

      This should either use command_context directly or provide the same guarantee.

      Source code in src/hatch/env/plugin/interface.py
      def enter_shell(
      +    self,
      +    name: str,  # noqa: ARG002
      +    path: str,
      +    args: Iterable[str],
      +):
      +    """
      +    Spawn a [shell](../../config/hatch.md#shell) within the environment.
      +
      +    This should either use
      +    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
      +    directly or provide the same guarantee.
      +    """
      +    with self.command_context():
      +        self.platform.exit_with_command([path, *args])
      +

      run_shell_command(command: str, **kwargs)

      This should return the standard library's subprocess.CompletedProcess and will always be called when the command_context is active, with the expectation of providing the same guarantee.

      Source code in src/hatch/env/plugin/interface.py
      def run_shell_command(self, command: str, **kwargs):
      +    """
      +    This should return the standard library's
      +    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)
      +    and will always be called when the
      +    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)
      +    is active, with the expectation of providing the same guarantee.
      +    """
      +    kwargs.setdefault('shell', True)
      +    return self.platform.run_command(command, **kwargs)
      +

      resolve_commands(commands: list[str])

      This expands each command into one or more commands based on any scripts that the user defined.

      Source code in src/hatch/env/plugin/interface.py
      def resolve_commands(self, commands: list[str]):
      +    """
      +    This expands each command into one or more commands based on any
      +    [scripts](../../config/environment/overview.md#scripts) that the user defined.
      +    """
      +    for command in commands:
      +        yield from self.expand_command(command)
      +

      get_env_vars() -> EnvVars

      Returns a mapping of environment variables that should be available to the environment. The object can be used as a context manager to temporarily apply the environment variables to the current process.

      Note

      The environment variable HATCH_ENV_ACTIVE will always be set to the name of the environment.

      Source code in src/hatch/env/plugin/interface.py
      def get_env_vars(self) -> EnvVars:
      +    """
      +    Returns a mapping of environment variables that should be available to the environment. The object can
      +    be used as a context manager to temporarily apply the environment variables to the current process.
      +
      +    !!! note
      +        The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.
      +    """
      +    return EnvVars(self.env_vars, self.env_include, self.env_exclude)
      +

      apply_features(requirement: str)

      A convenience method that applies any user defined features to the given requirement.

      Source code in src/hatch/env/plugin/interface.py
      def apply_features(self, requirement: str):
      +    """
      +    A convenience method that applies any user defined [features](../../config/environment/overview.md#features)
      +    to the given requirement.
      +    """
      +    if self.features:
      +        features = ','.join(self.features)
      +        return f'{requirement}[{features}]'
      +
      +    return requirement
      +

      construct_pip_install_command(args: list[str])

      A convenience method for constructing a pip install command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.

      Source code in src/hatch/env/plugin/interface.py
      def construct_pip_install_command(self, args: list[str]):
      +    """
      +    A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)
      +    command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.
      +    """
      +    command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']
      +
      +    # Default to -1 verbosity
      +    add_verbosity_flag(command, self.verbosity, adjustment=-1)
      +
      +    command.extend(args)
      +    return command
      +

      join_command_args(args: list[str])

      This is used by the run command to construct the root command string from the received arguments.

      Source code in src/hatch/env/plugin/interface.py
      def join_command_args(self, args: list[str]):
      +    """
      +    This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string
      +    from the received arguments.
      +    """
      +    return self.platform.join_command_args(args)
      +

      check_compatibility()

      This raises an exception if the environment is not compatible with the user's setup. The default behavior checks for platform compatibility and any method override should keep this check.

      This check is never performed if the environment has been created.

      Source code in src/hatch/env/plugin/interface.py
      def check_compatibility(self):
      +    """
      +    This raises an exception if the environment is not compatible with the user's setup. The default behavior
      +    checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)
      +    and any method override should keep this check.
      +
      +    This check is never performed if the environment has been
      +    [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).
      +    """
      +    if self.platforms and self.platform.name not in self.platforms:
      +        message = 'unsupported platform'
      +        raise OSError(message)
      +

      get_option_types() -> dict staticmethod

      Returns a mapping of supported options to their respective types so that they can be used by overrides.

      Source code in src/hatch/env/plugin/interface.py
      @staticmethod
      +def get_option_types() -> dict:
      +    """
      +    Returns a mapping of supported options to their respective types so that they can be used by
      +    [overrides](../../config/environment/advanced.md#option-overrides).
      +    """
      +    return {}
      +

      get_env_var_option(option: str) -> str

      Returns the value of the upper-cased environment variable HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>.

      Source code in src/hatch/env/plugin/interface.py
      def get_env_var_option(self, option: str) -> str:
      +    """
      +    Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.
      +    """
      +    return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')
      +

      get_context()

      Returns a subclass of EnvironmentContextFormatter.

      Source code in src/hatch/env/plugin/interface.py
      def get_context(self):
      +    """
      +    Returns a subclass of
      +    [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).
      +    """
      +    from hatch.env.context import EnvironmentContextFormatter
      +
      +    return EnvironmentContextFormatter(self)
      +
      \ No newline at end of file diff --git a/latest/plugins/environment/virtual/index.html b/latest/plugins/environment/virtual/index.html index 002b4868b..a06148360 100644 --- a/latest/plugins/environment/virtual/index.html +++ b/latest/plugins/environment/virtual/index.html @@ -1,4 +1,4 @@ - Virtual - Hatch

      Virtual environment


      This uses virtual environments backed by the standard virtualenv tool.

      Configuration

      The environment plugin name is virtual.

      [tool.hatch.envs.<ENV_NAME>]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Virtual environment


      This uses virtual environments backed by the standard virtualenv tool.

      Configuration

      The environment plugin name is virtual.

      [tool.hatch.envs.<ENV_NAME>]
       type = "virtual"
       
      [envs.<ENV_NAME>]
       type = "virtual"
      diff --git a/latest/plugins/metadata-hook/custom/index.html b/latest/plugins/metadata-hook/custom/index.html
      index acd1efdbe..c3014bc25 100644
      --- a/latest/plugins/metadata-hook/custom/index.html
      +++ b/latest/plugins/metadata-hook/custom/index.html
      @@ -1,4 +1,4 @@
      - Custom - Hatch      

      Custom metadata hook


      This is a custom class in a given Python file that inherits from the MetadataHookInterface.

      Configuration

      The metadata hook plugin name is custom.

      [tool.hatch.metadata.hooks.custom]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Custom metadata hook


      This is a custom class in a given Python file that inherits from the MetadataHookInterface.

      Configuration

      The metadata hook plugin name is custom.

      [tool.hatch.metadata.hooks.custom]
       
      [metadata.hooks.custom]
      -

      Options

      Option Default Description
      path hatch_build.py The path of the Python file

      Example

          from hatchling.metadata.plugin.interface import MetadataHookInterface
      +

      Options

      Option Default Description
      path hatch_build.py The path of the Python file

      Example

      from hatchling.metadata.plugin.interface import MetadataHookInterface
       
       
      -    class CustomMetadataHook(MetadataHookInterface):
      -        ...
      -

      If multiple subclasses are found, you must define a function named get_metadata_hook that returns the desired build hook.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      \ No newline at end of file +class CustomMetadataHook(MetadataHookInterface): + ... +

      If multiple subclasses are found, you must define a function named get_metadata_hook that returns the desired build hook.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      \ No newline at end of file diff --git a/latest/plugins/metadata-hook/reference/index.html b/latest/plugins/metadata-hook/reference/index.html index 829ed1780..2e1f85bdf 100644 --- a/latest/plugins/metadata-hook/reference/index.html +++ b/latest/plugins/metadata-hook/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

      Metadata hook plugins


      Metadata hooks allow for the modification of project metadata after it has been loaded.

      Known third-party

      MetadataHookInterface

      Example usage:

      from hatchling.metadata.plugin.interface import MetadataHookInterface
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Metadata hook plugins


      Metadata hooks allow for the modification of project metadata after it has been loaded.

      Known third-party

      MetadataHookInterface

      Example usage:

      from hatchling.metadata.plugin.interface import MetadataHookInterface
       
       
       class SpecialMetadataHook(MetadataHookInterface):
      diff --git a/latest/plugins/publisher/package-index/index.html b/latest/plugins/publisher/package-index/index.html
      index 099f510b1..51d2084d4 100644
      --- a/latest/plugins/publisher/package-index/index.html
      +++ b/latest/plugins/publisher/package-index/index.html
      @@ -1,4 +1,4 @@
      - Index - Hatch      

      Index publisher


      See the documentation for publishing.

      Configuration

      The publisher plugin name is index.

      [publish.index]
      -

      Options

      Flag Config name Description
      -r/--repo repo The repository with which to publish artifacts
      -u/--user user The user with which to authenticate
      -a/--auth auth The credentials to use for authentication
      --ca-cert ca-cert The path to a CA bundle
      --client-cert client-cert The path to a client certificate, optionally containing the private key
      --client-key client-key The path to the client certificate's private key
      repos A table of named repositories to their respective options

      Repositories

      All top-level options can be overridden per repository using the repos table with a required url attribute for each repository. The following shows the default configuration:

      [publish.index.repos.main]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Index publisher


      See the documentation for publishing.

      Options

      Flag Config name Description
      -r/--repo repo The repository with which to publish artifacts
      -u/--user user The user with which to authenticate
      -a/--auth auth The credentials to use for authentication
      --ca-cert ca-cert The path to a CA bundle
      --client-cert client-cert The path to a client certificate, optionally containing the private key
      --client-key client-key The path to the client certificate's private key
      repos A table of named repositories to their respective options

      Configuration

      The publisher plugin name is index.

      [publish.index]
      +

      Repositories

      All top-level options can be overridden per repository using the repos table with a required url attribute for each repository. The following shows the default configuration:

      [publish.index.repos.main]
       url = "https://upload.pypi.org/legacy/"
       
       [publish.index.repos.test]
       url = "https://test.pypi.org/legacy/"
      -

      The repo and repos options have no effect.

      \ No newline at end of file +

      The repo and repos options have no effect.

      Confirmation prompt

      You can require a confirmation prompt or use of the -y/--yes flag by setting publishers' disable option to true in either Hatch's config file or project-specific configuration (which takes precedence):

      [publish.index]
      +disable = true
      +
      [tool.hatch.publish.index]
      +disable = true
      +
      [publish.index]
      +disable = true
      +
      \ No newline at end of file diff --git a/latest/plugins/publisher/reference/index.html b/latest/plugins/publisher/reference/index.html index fc0794bd3..b7e876f85 100644 --- a/latest/plugins/publisher/reference/index.html +++ b/latest/plugins/publisher/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

      Publisher plugins


      PublisherInterface

      Example usage:

          from hatch.publish.plugin.interface import PublisherInterface
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Publisher plugins


      PublisherInterface

      Example usage:

          from hatch.publish.plugin.interface import PublisherInterface
       
       
           class SpecialPublisher(PublisherInterface):
      diff --git a/latest/plugins/utilities/index.html b/latest/plugins/utilities/index.html
      index 1de1b0557..cb1c451fe 100644
      --- a/latest/plugins/utilities/index.html
      +++ b/latest/plugins/utilities/index.html
      @@ -1,4 +1,4 @@
      - Utilities - Hatch      

      Plugin utilities


      hatchling.builders.utils.get_reproducible_timestamp() -> int

      Returns an int derived from the SOURCE_DATE_EPOCH environment variable; see https://reproducible-builds.org/specs/source-date-epoch/.

      The default value will always be: 1580601600

      Source code in backend/src/hatchling/builders/utils.py
      def get_reproducible_timestamp() -> int:
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Plugin utilities


      hatchling.builders.utils.get_reproducible_timestamp() -> int

      Returns an int derived from the SOURCE_DATE_EPOCH environment variable; see https://reproducible-builds.org/specs/source-date-epoch/.

      The default value will always be: 1580601600

      Source code in backend/src/hatchling/builders/utils.py
      def get_reproducible_timestamp() -> int:
           """
           Returns an `int` derived from the `SOURCE_DATE_EPOCH` environment variable; see
           https://reproducible-builds.org/specs/source-date-epoch/.
      @@ -15,4 +15,4 @@
           The default value will always be: `1580601600`
           """
           return int(os.environ.get('SOURCE_DATE_EPOCH', '1580601600'))
      -

      BuilderConfig

      directory: str property

      ignore_vcs: bool property

      reproducible: bool property

      Whether or not the target should be built in a reproducible manner, defaulting to true.

      dev_mode_dirs: list[str] property

      Directories which must be added to Python's search path in dev mode.

      versions: list[str] property

      dependencies: list[str] property

      default_include() -> list

      default_exclude() -> list

      default_packages() -> list

      default_only_include() -> list

      Application

      The way output is displayed can be configured by users.

      Important

      Never import this directly; Hatch judiciously decides if a type of plugin requires the capabilities herein and will grant access via an attribute.

      verbosity: int property

      The verbosity level of the application, with 0 as the default.

      abort(message: str = '', code: int = 1, **kwargs: Any) -> None

      Terminate the program with the given return code.

      display_debug(message: str = '', level: int = 1, **kwargs: Any) -> None

      Meant to be used for messages that are not useful for most user experiences. The level option must be between 1 and 3 (inclusive).

      display_error(message: str = '', **kwargs: Any) -> None

      Meant to be used for messages indicating some unrecoverable error.

      display_info(message: str = '', **kwargs: Any) -> None

      Meant to be used for messages conveying basic information.

      display_success(message: str = '', **kwargs: Any) -> None

      Meant to be used for messages indicating some positive outcome.

      display_waiting(message: str = '', **kwargs: Any) -> None

      Meant to be used for messages shown before potentially time consuming operations.

      display_warning(message: str = '', **kwargs: Any) -> None

      Meant to be used for messages conveying important information.

      Platform

      default_shell: str property

      Returns the default shell of the system.

      On Windows systems first try the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

      modules: LazilyLoadedModules property

      Accessor for lazily loading modules that either take multiple milliseconds to import (like shutil and subprocess) or are not used on all platforms (like shlex).

      home: Path property

      The user's home directory as a path-like object.

      name: str property

      One of the following:

      • linux
      • windows
      • macos

      windows: bool property

      Indicates whether Hatch is running on Windows.

      macos: bool property

      Indicates whether Hatch is running on macOS.

      linux: bool property

      Indicates whether Hatch is running on neither Windows nor macOS.

      format_for_subprocess(command: str | list[str], *, shell: bool) -> str | list[str]

      Format the given command in a cross-platform manner for immediate consumption by subprocess utilities.

      run_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess

      Equivalent to the standard library's subprocess.run, with the command first being properly formatted.

      check_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess

      Equivalent to run_command, but non-zero exit codes will gracefully end program execution.

      check_command_output(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> str

      Equivalent to the output from the process returned by capture_process, but non-zero exit codes will gracefully end program execution.

      capture_process(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> Popen

      Equivalent to the standard library's subprocess.Popen, with all output captured by stdout and the command first being properly formatted.

      exit_with_command(command: list[str]) -> None

      Run the given command and exit with its exit code. On non-Windows systems, this uses the standard library's os.execvp.

      EnvironmentContextFormatter

      formatters()

      This returns a mapping of supported field names to their respective formatting functions. Each function accepts 2 arguments:

      • the value that was passed to the format call, defaulting to None
      • the modifier data, defaulting to an empty string
      \ No newline at end of file +

      BuilderConfig

      directory: str property

      ignore_vcs: bool property

      reproducible: bool property

      Whether or not the target should be built in a reproducible manner, defaulting to true.

      dev_mode_dirs: list[str] property

      Directories which must be added to Python's search path in dev mode.

      versions: list[str] property

      dependencies: list[str] property

      default_include() -> list

      default_exclude() -> list

      default_packages() -> list

      default_only_include() -> list

      Application

      The way output is displayed can be configured by users.

      Important

      Never import this directly; Hatch judiciously decides if a type of plugin requires the capabilities herein and will grant access via an attribute.

      verbosity: int property

      The verbosity level of the application, with 0 as the default.

      abort(message: str = '', code: int = 1, **kwargs: Any) -> None

      Terminate the program with the given return code.

      display_debug(message: str = '', level: int = 1, **kwargs: Any) -> None

      Meant to be used for messages that are not useful for most user experiences. The level option must be between 1 and 3 (inclusive).

      display_error(message: str = '', **kwargs: Any) -> None

      Meant to be used for messages indicating some unrecoverable error.

      display_info(message: str = '', **kwargs: Any) -> None

      Meant to be used for messages conveying basic information.

      display_success(message: str = '', **kwargs: Any) -> None

      Meant to be used for messages indicating some positive outcome.

      display_waiting(message: str = '', **kwargs: Any) -> None

      Meant to be used for messages shown before potentially time consuming operations.

      display_warning(message: str = '', **kwargs: Any) -> None

      Meant to be used for messages conveying important information.

      Platform

      default_shell: str property

      Returns the default shell of the system.

      On Windows systems first try the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

      modules: LazilyLoadedModules property

      Accessor for lazily loading modules that either take multiple milliseconds to import (like shutil and subprocess) or are not used on all platforms (like shlex).

      home: Path property

      The user's home directory as a path-like object.

      name: str property

      One of the following:

      • linux
      • windows
      • macos

      display_name: str property

      One of the following:

      • Linux
      • Windows
      • macOS

      windows: bool property

      Indicates whether Hatch is running on Windows.

      macos: bool property

      Indicates whether Hatch is running on macOS.

      linux: bool property

      Indicates whether Hatch is running on neither Windows nor macOS.

      format_for_subprocess(command: str | list[str], *, shell: bool) -> str | list[str]

      Format the given command in a cross-platform manner for immediate consumption by subprocess utilities.

      run_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess

      Equivalent to the standard library's subprocess.run, with the command first being properly formatted.

      check_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess

      Equivalent to run_command, but non-zero exit codes will gracefully end program execution.

      check_command_output(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> str

      Equivalent to the output from the process returned by capture_process, but non-zero exit codes will gracefully end program execution.

      capture_process(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> Popen

      Equivalent to the standard library's subprocess.Popen, with all output captured by stdout and the command first being properly formatted.

      exit_with_command(command: list[str]) -> None

      Run the given command and exit with its exit code. On non-Windows systems, this uses the standard library's os.execvp.

      EnvironmentContextFormatter

      formatters()

      This returns a mapping of supported field names to their respective formatting functions. Each function accepts 2 arguments:

      • the value that was passed to the format call, defaulting to None
      • the modifier data, defaulting to an empty string
      \ No newline at end of file diff --git a/latest/plugins/version-scheme/reference/index.html b/latest/plugins/version-scheme/reference/index.html index f242f940d..6bb20a782 100644 --- a/latest/plugins/version-scheme/reference/index.html +++ b/latest/plugins/version-scheme/reference/index.html @@ -1,4 +1,4 @@ - Reference - Hatch

      Version scheme plugins


      Known third-party

      VersionSchemeInterface

      Example usage:

      from hatchling.version.scheme.plugin.interface import VersionSchemeInterface
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Version scheme plugins


      Known third-party

      VersionSchemeInterface

      Example usage:

      from hatchling.version.scheme.plugin.interface import VersionSchemeInterface
       
       
       class SpecialVersionScheme(VersionSchemeInterface):
      diff --git a/latest/plugins/version-scheme/standard/index.html b/latest/plugins/version-scheme/standard/index.html
      index 838021bb6..26e698d9b 100644
      --- a/latest/plugins/version-scheme/standard/index.html
      +++ b/latest/plugins/version-scheme/standard/index.html
      @@ -1,4 +1,4 @@
      - Standard - Hatch      

      Standard version scheme


      See the documentation for versioning.

      Configuration

      The version scheme plugin name is standard.

      [tool.hatch.version]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Standard version scheme


      See the documentation for versioning.

      Configuration

      The version scheme plugin name is standard.

      [tool.hatch.version]
       scheme = "standard"
       
      [version]
       scheme = "standard"
      diff --git a/latest/plugins/version-source/code/index.html b/latest/plugins/version-source/code/index.html
      index 24b38400b..08bb7798d 100644
      --- a/latest/plugins/version-source/code/index.html
      +++ b/latest/plugins/version-source/code/index.html
      @@ -1,4 +1,4 @@
      - Code - Hatch      

      Code version source


      Updates

      Setting the version is not supported.

      Configuration

      The version source plugin name is code.

      [tool.hatch.version]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Code version source


      Updates

      Setting the version is not supported.

      Configuration

      The version source plugin name is code.

      [tool.hatch.version]
       source = "code"
       
      [version]
       source = "code"
      diff --git a/latest/plugins/version-source/env/index.html b/latest/plugins/version-source/env/index.html
      index b7910989e..f206e72a3 100644
      --- a/latest/plugins/version-source/env/index.html
      +++ b/latest/plugins/version-source/env/index.html
      @@ -1,4 +1,4 @@
      - Environment - Hatch      

      Environment version source


      Retrieves the version from an environment variable. This can be useful in build pipelines where the version is set by an external trigger.

      Updates

      Setting the version is not supported.

      Configuration

      The version source plugin name is env.

      [tool.hatch.version]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Environment version source


      Retrieves the version from an environment variable. This can be useful in build pipelines where the version is set by an external trigger.

      Updates

      Setting the version is not supported.

      Configuration

      The version source plugin name is env.

      [tool.hatch.version]
       source = "env"
       
      [version]
       source = "env"
      diff --git a/latest/plugins/version-source/reference/index.html b/latest/plugins/version-source/reference/index.html
      index c500b046f..14467916c 100644
      --- a/latest/plugins/version-source/reference/index.html
      +++ b/latest/plugins/version-source/reference/index.html
      @@ -1,4 +1,4 @@
      - Reference - Hatch      

      Version source plugins


      Known third-party

      • hatch-vcs - uses your preferred version control system (like Git)
      • hatch-nodejs-version - uses the version field of NodeJS package.json files
      • hatch-regex-commit - automatically creates a Git commit and tag after version bumping
      • versioningit - determines version from Git or Mercurial tags, with customizable version formatting

      VersionSourceInterface

      Example usage:

      from hatchling.version.source.plugin.interface import VersionSourceInterface
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Version source plugins


      Known third-party

      • hatch-vcs - uses your preferred version control system (like Git)
      • hatch-nodejs-version - uses the version field of NodeJS package.json files
      • hatch-regex-commit - automatically creates a Git commit and tag after version bumping
      • versioningit - determines version from Git or Mercurial tags, with customizable version formatting

      VersionSourceInterface

      Example usage:

      from hatchling.version.source.plugin.interface import VersionSourceInterface
       
       
       class SpecialVersionSource(VersionSourceInterface):
      diff --git a/latest/plugins/version-source/regex/index.html b/latest/plugins/version-source/regex/index.html
      index 3749d484a..40ca31822 100644
      --- a/latest/plugins/version-source/regex/index.html
      +++ b/latest/plugins/version-source/regex/index.html
      @@ -1,4 +1,4 @@
      - Regex - Hatch      

      Regex version source


      See the documentation for versioning.

      Updates

      Setting the version is supported.

      Configuration

      The version source plugin name is regex.

      [tool.hatch.version]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Regex version source


      See the documentation for versioning.

      Updates

      Setting the version is supported.

      Configuration

      The version source plugin name is regex.

      [tool.hatch.version]
       source = "regex"
       
      [version]
       source = "regex"
      diff --git a/latest/publish/index.html b/latest/publish/index.html
      index 4794b8365..0391468ae 100644
      --- a/latest/publish/index.html
      +++ b/latest/publish/index.html
      @@ -7,20 +7,11 @@
           .gdesc-inner { font-size: 0.75rem; }
           body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
           body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
      -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Publishing


      After your project is built, you can distribute it using the publish command.

      The -p/--publisher option controls which publisher to use, with the default being index.

      Artifact selection

      By default, the dist directory located at the root of your project will be used:

      $ hatch publish
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Publishing


      After your project is built, you can distribute it using the publish command.

      The -p/--publisher option controls which publisher to use, with the default being index.

      Artifact selection

      By default, the dist directory located at the root of your project will be used:

      $ hatch publish
       dist/hatch_demo-1rc0-py3-none-any.whl ... success
       dist/hatch_demo-1rc0.tar.gz ... success
       
       [hatch-demo]
       https://pypi.org/project/hatch-demo/1rc0/
       

      You can instead pass specific paths as arguments:

      hatch publish /path/to/artifacts foo-1.tar.gz
      -

      Only files ending with .whl or .tar.gz will be published.

      Repository

      You can select the repository with which to upload using the -r/--repo option or by setting the HATCH_INDEX_REPO environment variable.

      Rather than specifying the full URL of a repository, you can use a named repository from a publish.index.repos table defined in Hatch's config file:

      [publish.index.repos.private]
      -url = "..."
      -...
      -

      The following repository names are reserved by Hatch and cannot be overridden:

      Name Repository
      main https://upload.pypi.org/legacy/
      test https://test.pypi.org/legacy/

      The main repository is used by default.

      Authentication

      The first time you publish to a repository you need to authenticate using the -u/--user (environment variable HATCH_INDEX_USER) and -a/--auth (environment variable HATCH_INDEX_AUTH) options. You will be prompted if either option is not provided.

      The user that most recently published to the chosen repository is cached, with their credentials saved to the system keyring, so that they will no longer need to provide authentication information.

      For automated releasing to PyPI, it is recommended that you use per-project API tokens.

      Confirmation

      You can require a confirmation prompt or use of the -y/--yes flag by setting publishers' disable option to true in either Hatch's config file or project-specific configuration (which takes precedence):

      [publish.index]
      -disable = true
      -
      [tool.hatch.publish.index]
      -disable = true
      -
      [publish.index]
      -disable = true
      -
      \ No newline at end of file +

      Only files ending with .whl or .tar.gz will be published.

      Further resources

      Please refer to the publisher plugin reference for configuration options.

      There's a How-To on authentication and on options to select the target repository.

      The publish command is implemented as a built-in plugin, if you're planning your own plugin, read about the publisher plugin API.

      \ No newline at end of file diff --git a/latest/search/search_index.json b/latest/search/search_index.json index 26f267a67..a84569b41 100644 --- a/latest/search/search_index.json +++ b/latest/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Hatch","text":"CI/CD Docs Package Meta

      Hatch is a modern, extensible Python project manager. See the Why Hatch? page for more information.

      • Build system

        Reproducible builds by default with a rich ecosystem of plugins

        Configure builds

      • Environments

        Robust environment management with support for custom scripts

        Getting started

      • Python management

        Choose between easy manual installations or automatic as part of environments

        Try it

      • Static analysis

        Static analysis backed by Ruff with up-to-date, sane defaults

        Learn

      • Publishing

        Easily upload to PyPI or other indices

        See how

      • Versioning

        Streamlined workflow for bumping versions

        Managing versions

      • Project generation

        Create new projects from templates with known best practices

        Project setup

      • Responsive CLI

        Hatch is up to 3x faster than equivalent tools

        CLI reference

      "},{"location":"#license","title":"License","text":"

      Hatch is distributed under the terms of the MIT license.

      "},{"location":"#navigation","title":"Navigation","text":"

      Documentation for specific MAJOR.MINOR versions can be chosen by using the dropdown on the top of every page. The dev version reflects changes that have not yet been released.

      Also, desktop readers can use special keyboard shortcuts:

      Keys Action
      • , (comma)
      • p
      Navigate to the \"previous\" page
      • . (period)
      • n
      Navigate to the \"next\" page
      • /
      • s
      Display the search modal"},{"location":"build/","title":"Builds","text":""},{"location":"build/#configuration","title":"Configuration","text":"

      Builds are configured using the tool.hatch.build table. Every target is defined by a section within tool.hatch.build.targets, for example:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.sdist]\nexclude = [\n  \"/.github\",\n  \"/docs\",\n]\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
      [build.targets.sdist]\nexclude = [\n  \"/.github\",\n  \"/docs\",\n]\n\n[build.targets.wheel]\npackages = [\"src/foo\"]\n
      "},{"location":"build/#building","title":"Building","text":"

      Invoking the build command without any arguments will build the sdist and wheel targets:

      $ hatch build\n[sdist]\ndist/hatch_demo-1rc0.tar.gz\n\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n

      To only build specific targets, use the -t/--target option:

      $ hatch build -t wheel\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n

      If the target supports multiple versions, you can specify the exact versions to build by appending a colon followed by the desired versions separated by commas:

      $ hatch -v build -t wheel:standard\n[wheel]\nBuilding `wheel` version `standard`\ndist/hatch_demo-1rc0-py3-none-any.whl\n
      "},{"location":"build/#packaging-ecosystem","title":"Packaging ecosystem","text":"

      Hatch complies with modern Python packaging specs and therefore your projects can be used by other tools with Hatch serving as just the build backend.

      So you could use tox as an alternative to Hatch's environment management, or cibuildwheel to distribute packages for every platform, and they both will transparently use Hatch without any extra modification.

      "},{"location":"environment/","title":"Environments","text":"

      Environments are designed to allow for isolated workspaces for testing, building documentation, or anything else projects need.

      Unless an environment is chosen explicitly, Hatch will use the default environment.

      "},{"location":"environment/#creation","title":"Creation","text":"

      You can create environments by using the env create command. Let's enter the directory of the project we created in the setup phase:

      $ hatch env create\nCreating environment: default\nInstalling project in development mode\nSyncing dependencies\n

      Tip

      You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.

      "},{"location":"environment/#entering-environments","title":"Entering environments","text":"

      You can spawn a shell within an environment by using the shell command.

      $ hatch shell\n(hatch-demo) $\n

      Now confirm the project has been installed:

      (hatch-demo) $ pip show hatch-demo\nName: hatch-demo\nVersion: 0.0.1\n...\n

      Finally, see where your environment's Python is located:

      (hatch-demo) $ python -c \"import sys;print(sys.executable)\"\n...\n

      You can type exit to leave the environment.

      "},{"location":"environment/#command-execution","title":"Command execution","text":"

      The run command allows you to execute commands in an environment as if you had already entered it. For example, running the following command will output the same path as before:

      hatch run python -c \"import sys;print(sys.executable)\"\n
      "},{"location":"environment/#scripts","title":"Scripts","text":"

      You can also run any scripts that have been defined.

      You'll notice that in the pyproject.toml file there are already scripts defined in the default environment. Try running the test command, which invokes pytest with some default arguments:

      hatch run test\n

      All additional arguments are passed through to that script, so for example if you wanted to see the version of pytest and which plugins are installed you could do:

      hatch run test -VV\n
      "},{"location":"environment/#dependencies","title":"Dependencies","text":"

      Hatch ensures that environments are always compatible with the currently defined project dependencies (if installed and in dev mode) and environment dependencies.

      To add cowsay as a dependency, open pyproject.toml and add it to the dependencies array:

      pyproject.toml
      [project]\n...\ndependencies = [\n  \"cowsay\"\n]\n

      This dependency will be installed the next time you spawn a shell or run a command. For example:

      $ hatch run cowsay -t \"Hello, world!\"\nSyncing dependencies\n  _____________\n| Hello, world! |\n  =============\n             \\\n              \\\n                ^__^\n                (oo)\\_______\n                (__)\\       )\\/\\\n                    ||----w |\n                    ||     ||\n

      Note

      The Syncing dependencies status will display temporarily when Hatch updates environments in response to any dependency changes that you make.

      "},{"location":"environment/#selection","title":"Selection","text":"

      You can select which environment to enter or run commands in by using the -e/--env root option or by setting the HATCH_ENV environment variable.

      The run command allows for more explicit selection by prepending <ENV_NAME>: to commands. For example, if you had the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[tool.hatch.envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n
      [envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n

      you could then serve your documentation by running:

      hatch run docs:serve\n

      Tip

      If you've already entered an environment, commands will target it by default.

      "},{"location":"environment/#matrix","title":"Matrix","text":"

      Every environment can define its own set of matrices:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
      [envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n

      Using the env show command would then display:

      $ hatch env show --ascii\n     Standalone\n+---------+---------+\n| Name    | Type    |\n+=========+=========+\n| default | virtual |\n+---------+---------+\n                       Matrices\n+------+---------+---------------------+--------------+\n| Name | Type    | Envs                | Dependencies |\n+======+=========+=====================+==============+\n| test | virtual | test.py2.7-42       | pytest       |\n|      |         | test.py2.7-3.14     |              |\n|      |         | test.py3.8-42       |              |\n|      |         | test.py3.8-3.14     |              |\n|      |         | test.py3.8-9000-foo |              |\n|      |         | test.py3.8-9000-bar |              |\n|      |         | test.py3.9-9000-foo |              |\n|      |         | test.py3.9-9000-bar |              |\n+------+---------+---------------------+--------------+\n
      "},{"location":"environment/#removal","title":"Removal","text":"

      You can remove a single environment or environment matrix by using the env remove command or all of a project's environments by using the env prune command.

      "},{"location":"install/","title":"Installation","text":""},{"location":"install/#installers","title":"Installers","text":"macOSWindows GUI installerCommand line installer
      1. In your browser, download the .pkg file: hatch-1.9.4.pkg
      2. Run your downloaded file and follow the on-screen instructions.
      3. Restart your terminal.
      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version\n1.9.4\n
      1. Download the file using the curl command. The -o option specifies the file name that the downloaded package is written to. In this example, the file is written to hatch-1.9.4.pkg in the current directory.

        curl -o hatch-1.9.4.pkg https://github.com/pypa/hatch/releases/download/hatch-v1.9.4/hatch-1.9.4.pkg\n
      2. Run the standard macOS installer program, specifying the downloaded .pkg file as the source. Use the -pkg parameter to specify the name of the package to install, and the -target / parameter for the drive in which to install the package. The files are installed to /usr/local/hatch, and an entry is created at /etc/paths.d/hatch that instructs shells to add the /usr/local/hatch directory to. You must include sudo on the command to grant write permissions to those folders.

        sudo installer -pkg ./hatch-1.9.4.pkg -target /\n
      3. Restart your terminal.

      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version\n1.9.4\n
      GUI installerCommand line installer
      1. In your browser, download one the .msi files:
        • hatch-1.9.4-x64.msi
      2. Run your downloaded file and follow the on-screen instructions.
      3. Restart your terminal.
      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version\n1.9.4\n
      1. Download and run the installer using the standard Windows msiexec program, specifying one of the .msi files as the source. Use the /passive and /i parameters to request an unattended, normal installation.

        x64
        msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.4/hatch-1.9.4-x64.msi\n
      2. Restart your terminal.

      3. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version\n1.9.4\n
      "},{"location":"install/#standalone-binaries","title":"Standalone binaries","text":"

      After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to hatch.

      LinuxmacOSWindows
      • hatch-1.9.4-aarch64-unknown-linux-gnu.tar.gz
      • hatch-1.9.4-x86_64-unknown-linux-gnu.tar.gz
      • hatch-1.9.4-x86_64-unknown-linux-musl.tar.gz
      • hatch-1.9.4-i686-unknown-linux-gnu.tar.gz
      • hatch-1.9.4-powerpc64le-unknown-linux-gnu.tar.gz
      • hatch-1.9.4-aarch64-apple-darwin.tar.gz
      • hatch-1.9.4-x86_64-apple-darwin.tar.gz
      • hatch-1.9.4-x86_64-pc-windows-msvc.zip
      "},{"location":"install/#pip","title":"pip","text":"

      Hatch is available on PyPI and can be installed with pip.

      pip install hatch\n

      Warning

      This method modifies the Python environment in which you choose to install. Consider instead using pipx to avoid dependency conflicts.

      "},{"location":"install/#pipx","title":"pipx","text":"

      pipx allows for the global installation of Python applications in isolated environments.

      pipx install hatch\n
      "},{"location":"install/#homebrew","title":"Homebrew","text":"

      See the formula for more details.

      brew install hatch\n
      "},{"location":"install/#conda","title":"Conda","text":"

      See the feedstock for more details.

      conda install -c conda-forge hatch\n

      or with mamba:

      mamba install hatch\n

      Warning

      This method modifies the Conda environment in which you choose to install. Consider instead using pipx or condax to avoid dependency conflicts.

      "},{"location":"install/#macports","title":"MacPorts","text":"

      See the port for more details.

      sudo port install hatch\n
      "},{"location":"install/#fedora","title":"Fedora","text":"

      The minimum supported version is 37, currently in development as Rawhide.

      sudo dnf install hatch\n
      "},{"location":"install/#void-linux","title":"Void Linux","text":"
      xbps-install hatch\n
      "},{"location":"install/#build-system-availability","title":"Build system availability","text":"

      Hatchling is Hatch's build backend which you will never need to install manually. See its changelog for version information.

      "},{"location":"intro/","title":"Introduction","text":""},{"location":"intro/#setup","title":"Setup","text":"

      Projects can be set up for use by Hatch using the new command.

      "},{"location":"intro/#new-project","title":"New project","text":"

      Let's say you want to create a project named Hatch Demo. You would run:

      hatch new \"Hatch Demo\"\n

      This would create the following structure in your current working directory:

      hatch-demo\n\u251c\u2500\u2500 src\n\u2502   \u2514\u2500\u2500 hatch_demo\n\u2502       \u251c\u2500\u2500 __about__.py\n\u2502       \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 tests\n\u2502   \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 LICENSE.txt\n\u251c\u2500\u2500 README.md\n\u2514\u2500\u2500 pyproject.toml\n

      Tip

      There are many ways to customize project generation.

      "},{"location":"intro/#existing-project","title":"Existing project","text":"

      To initialize an existing project, enter the directory containing the project and run the following:

      hatch new --init\n

      If your project has a setup.py file the command will automatically migrate setuptools configuration for you. Otherwise, this will interactively guide you through the setup process.

      "},{"location":"intro/#project-metadata","title":"Project metadata","text":"

      Next you'll want to define more of your project's metadata located in the pyproject.toml file. You can specify things like its license, the supported versions of Python, and URLs referring to various parts of your project, like documentation.

      "},{"location":"intro/#dependencies","title":"Dependencies","text":"

      The last step of the setup process is to define any dependencies that you'd like your project to begin with.

      "},{"location":"intro/#configuration","title":"Configuration","text":"

      All project-specific configuration recognized by Hatch can be defined in either the pyproject.toml file, or a file named hatch.toml where options are not contained within the tool.hatch table:

      pyproject.toml hatch.toml
      [tool.hatch]\noption = \"...\"\n\n[tool.hatch.table1]\noption = \"...\"\n\n[tool.hatch.table2]\noption = \"...\"\n
      option = \"...\"\n\n[table1]\noption = \"...\"\n\n[table2]\noption = \"...\"\n

      Top level keys in the latter file take precedence when defined in both.

      Tip

      If you want to make your file more compact, you can use dotted keys, turning the above example into:

      pyproject.toml hatch.toml
      [tool.hatch]\noption = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
      option = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
      "},{"location":"next-steps/","title":"Next steps","text":""},{"location":"next-steps/#learn-more","title":"Learn more","text":"

      At this point you should have a basic understanding of how to use Hatch.

      Now you may want to check out advanced configuration for environments or builds, set up your preferred shell, or read more about Hatch's CLI.

      After that, check out the Hatch Showcase project to see examples of what is possible.

      Finally, if you see a need, feel free to write a plugin for extended functionality.

      "},{"location":"next-steps/#community","title":"Community","text":"

      For any projects using Hatch, you may add its official badge somewhere prominent like the README.

      MarkdownreStructuredText
      [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)\n
      .. image:: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg\n   :alt: Hatch project\n   :target: https://github.com/pypa/hatch\n
      "},{"location":"publish/","title":"Publishing","text":"

      After your project is built, you can distribute it using the publish command.

      The -p/--publisher option controls which publisher to use, with the default being index.

      "},{"location":"publish/#artifact-selection","title":"Artifact selection","text":"

      By default, the dist directory located at the root of your project will be used:

      $ hatch publish\ndist/hatch_demo-1rc0-py3-none-any.whl ... success\ndist/hatch_demo-1rc0.tar.gz ... success\n\n[hatch-demo]\nhttps://pypi.org/project/hatch-demo/1rc0/\n

      You can instead pass specific paths as arguments:

      hatch publish /path/to/artifacts foo-1.tar.gz\n

      Only files ending with .whl or .tar.gz will be published.

      "},{"location":"publish/#repository","title":"Repository","text":"

      You can select the repository with which to upload using the -r/--repo option or by setting the HATCH_INDEX_REPO environment variable.

      Rather than specifying the full URL of a repository, you can use a named repository from a publish.index.repos table defined in Hatch's config file:

      config.toml
      [publish.index.repos.private]\nurl = \"...\"\n...\n

      The following repository names are reserved by Hatch and cannot be overridden:

      Name Repository main https://upload.pypi.org/legacy/ test https://test.pypi.org/legacy/

      The main repository is used by default.

      "},{"location":"publish/#authentication","title":"Authentication","text":"

      The first time you publish to a repository you need to authenticate using the -u/--user (environment variable HATCH_INDEX_USER) and -a/--auth (environment variable HATCH_INDEX_AUTH) options. You will be prompted if either option is not provided.

      The user that most recently published to the chosen repository is cached, with their credentials saved to the system keyring, so that they will no longer need to provide authentication information.

      For automated releasing to PyPI, it is recommended that you use per-project API tokens.

      "},{"location":"publish/#confirmation","title":"Confirmation","text":"

      You can require a confirmation prompt or use of the -y/--yes flag by setting publishers' disable option to true in either Hatch's config file or project-specific configuration (which takes precedence):

      config.toml pyproject.toml hatch.toml
      [publish.index]\ndisable = true\n
      [tool.hatch.publish.index]\ndisable = true\n
      [publish.index]\ndisable = true\n
      "},{"location":"version/","title":"Versioning","text":""},{"location":"version/#configuration","title":"Configuration","text":"

      When the version is not statically set, configuration is defined in the tool.hatch.version table. The source option determines the source to use for retrieving and updating the version. The regex source is used by default.

      The regex source requires an option path that represents a relative path to a file containing the project's version:

      pyproject.toml hatch.toml
      [tool.hatch.version]\npath = \"src/hatch_demo/__about__.py\"\n
      [version]\npath = \"src/hatch_demo/__about__.py\"\n

      The default pattern looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v.

      If this doesn't reflect how you store the version, you can define a different regular expression using the pattern option:

      pyproject.toml hatch.toml
      [tool.hatch.version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n
      [version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n

      The pattern must have a named group called version that represents the version.

      "},{"location":"version/#display","title":"Display","text":"

      Invoking the version command without any arguments will display the current version of the project:

      $ hatch version\n0.0.1\n
      "},{"location":"version/#updating","title":"Updating","text":"

      You can update the version like so:

      $ hatch version \"0.1.0\"\nOld: 0.0.1\nNew: 0.1.0\n

      The scheme option determines the scheme to use for parsing both the existing and new versions. The standard scheme is used by default, which is based on PEP 440.

      Rather than setting the version explicitly, you can select the name of a segment used to increment the version:

      $ hatch version minor\nOld: 0.1.0\nNew: 0.2.0\n

      You can chain multiple segment updates with a comma. For example, if you wanted to release a preview of your project's first major version, you could do:

      $ hatch version major,rc\nOld: 0.2.0\nNew: 1.0.0rc0\n

      When you want to release the final version, you would do:

      $ hatch version release\nOld: 1.0.0rc0\nNew: 1.0.0\n
      "},{"location":"version/#supported-segments","title":"Supported segments","text":"

      Here are the supported segments and how they would influence an existing version of 1.0.0:

      Segments New version release 1.0.0 major 2.0.0 minor 1.1.0 micropatchfix 1.0.1 aalpha 1.0.0a0 bbeta 1.0.0b0 crcprepreview 1.0.0rc0 rrevpost 1.0.0.post0 dev 1.0.0.dev0"},{"location":"why/","title":"Why Hatch?","text":"

      The high level value proposition of Hatch is that if one adopts all functionality then many other tools become unnecessary since there is support for everything one might require. Further, if one chooses to use only specific features then there are still benefits compared to alternatives.

      "},{"location":"why/#build-backend","title":"Build backend","text":"

      Hatchling, the build backend sister project, has many benefits compared to setuptools. Here we only compare setuptools as that is the one most people are familiar with.

      • Better defaults: The default behavior for setuptools is often not desirable for the average user.
        • For source distributions, setuptools has a custom enumeration of files that get included and excluded by default. Hatchling takes the defaults from your version control system such as Git's .gitignore file.
        • For wheels, setuptools attempts to find every directory that looks like a Python package. This is often undesirable as you might ship files to the end-user unintentionally such as test or tooling directories. Hatchling defaults to very specific inclusion based on the project name and errors if no heuristic is satisfied.
      • Ease of configurability: Hatchling was designed based on a history of significant challenges when configuring setuptools.
        • Hatchling uses the same glob pattern syntax as Git itself for every option which is what most users are familiar with. On the other hand, setuptools uses shell-style glob patterns for source distributions while wheels use a mix of shell-style globs and Python package syntax.
        • Configuring what gets included in source distributions requires a separate MANIFEST.in file. The custom syntax and directives must be learned and it is difficult knowing which options in the main files like setup.py influence the behavior and under what conditions. For Hatchling, everything gets configured in a single file under dedicated sections for specific targets like [tool.hatch.build.targets.wheel].
        • By default, non-Python files are excluded from wheels. Including such files requires usually verbose rules for every nested package directory. Hatchling makes no such distinction between file types and acts more like a general build system one might already be familiar with.
      • Editable installations: The default behavior of Hatchling allows for proper static analysis by external tools such as IDEs. With setuptools, you must provide additional configuration which means that by default, for example, you would not get autocompletion in Visual Studio Code. This is marked as a legacy feature and may in fact be removed in future versions of setuptools.
      • Reproducibility: Hatchling builds reproducible wheels and source distributions by default. setuptools does not support this for source distributions and there is no guarantee that wheels are reproducible.
      • Extensibility: Although it is possible to extend setuptools, the API is quite low level. Hatchling has the concept of plugins that are separated into discrete types and only expose what is necessary, leading to an easier developer experience.

      Why not?:

      If building extension modules is required then it is recommended that you continue using setuptools, or even other backends that specialize in interfacing with compilers.

      "},{"location":"why/#environment-management","title":"Environment management","text":"

      Here we compare to both tox and nox. At a high level, there are a few common advantages:

      • Python management: Hatch is able to automatically download Python distributions on the fly when specific versions that environments request cannot be found. The alternatives will raise an error, with the option to ignore unknown distributions.
      • Philosophy: In the alternatives, environments are for the most part treated as executable units where a dependency set is associated with an action. If you are familiar with container ecosystems, this would be like defining a CMD at the end of a Dockerfile but without the ability to change the action at runtime. This involves significant wasted disk space usually because one often requires slight modifications to the actions and therefore will define entirely different environments inherited from a base config just to perform different logic. Additionally, this can be confusing to users not just configuration-wise but also for execution of the different environments.

        In Hatch, environments are treated as isolated areas where you can execute arbitrary commands at runtime. For example, you can define a single test environment with named scripts that runs unit vs non-unit tests, each command being potentially very long but named however you wish so you get to control the interface. Since environments are treated as places where work is performed, you can also spawn a shell into any which will execute a subprocess that automatically drops into your shell of choice. Your shell will be configured appropriately like python on PATH being updated and the prompt being changed to reflect the chosen environment.

      • Configuration:

        • tox only supports INI configuration and if one desires putting that in the standard pyproject.toml file then it must be a multi-line string containing the INI config which would preclude syntax highlighting. Hatch allows for TOML-based config just like most other tools in the Python ecosystem.
        • nox config is defined in Python which often leads to increased verbosity and makes it challenging to onboard folks compared to a standardized format with known behaviors.
      • Extensibility:
        • tox allows for extending most aspects of its functionality however the API is so low-level and attached to internals that creating plugins may be challenging. For example, here is a tox plugin that was migrated to an equivalent Hatch environment collector plugin.
        • nox is configured with Python so for the local project you can do whatever you want, however there is no concept of third-party plugins per se. To achieve that, you must usually use a package that wraps nox and use that package's imports instead (example).

      Why not?:

      If you are using nox and you wish to migrate, and for some reason you notify sessions, then migration wouldn't be a straight translation but rather you might have to redesign that conditional step.

      "},{"location":"why/#python-management","title":"Python management","text":"

      Here we compare Python management to that of pyenv.

      • Cross-platform: Hatch allows for the same experience no matter the system whereas pyenv does not support Windows so you must use an entirely different project that tries to emulate the functionality.
      • No build dependencies: Hatch guarantees that every available distribution is prebuilt whereas the alternative requires one to maintain a precise build environment which differs by platform and potentially Python version. Another benefit to this is extremely fast installations since the distributions are simply downloaded and unpacked.
      • Optimized by default: The CPython distributions are built with profile guided optimization and link-time optimization, resulting in a 10-30% performance improvement depending on the workload. These distributions have seen wide adoption throughout the industry and are even used by the build system Bazel.
      • Simplicity: Hatch treats Python installations as just another directory that one would add to PATH. It can do this for you or you can manage PATH yourself, even allowing for custom install locations. On the other hand, pyenv operates by adding shims which then act as wrappers around the actual underlying binaries. This has many unfortunate side effects:
        • It is incumbent upon the user to manage which specific Python comes first via the CLI, switch when necessary, and/or have a mental model of which versions are exposed globally and locally per-project. This can become confusing quite quickly. When working with Hatch, your global Python installations are only important insofar as they are on PATH somewhere since environments do not use them directly but rather create virtual environments from them, always using a version that is compatible with your project.
        • Configuration is required for each shell to properly set up pyenv on start, leading to inconsistencies when running processes that do not spawn a shell.
        • Debugging issues with Python search paths can be extremely difficult, especially for users of software. If you or users have ever ran into an issue where code was being executed that you did not anticipate, the issue is almost always pyenv influencing the python on PATH.

      Why not?:

      Currently, Hatch does not allow for the installation of specific patch release versions but rather only uses minor release granularity that tracks the latest patch release. If specific patch releases are important to you then it is best to use an alternative installation mechanism.

      "},{"location":"blog/","title":"Blog","text":""},{"location":"blog/2022/10/08/hatch-v160/","title":"Hatch v1.6.0","text":"

      Hatch v1.6.0 brings improvements to build environments, better handling of dynamic metadata, and support for tools like Visual Studio Code.

      "},{"location":"blog/2022/10/08/hatch-v160/#build-environments","title":"Build environments","text":"

      Originally, the environment interface method for providing builder sub-environments was intended to be used in conjunction with some cleanup logic in order to provide a fresh setup every time. However, this is unnecessary in practice because build dependencies rarely change.

      Without caching, repeat build environment use is slow which affects the following scenarios:

      • the build command
      • commands that read project metadata, like dep hash, if any fields are set dynamically

      Now a new environment interface method build_environment_exists is used by Hatch to determine whether or not it has already been created, for implementations that have a caching mechanism.

      The virtual environment type now uses this method to cache build environments.

      "},{"location":"blog/2022/10/08/hatch-v160/#project-metadata","title":"Project metadata","text":"

      Dynamically defined metadata is now supported everywhere, thanks to the new caching of virtual build environments.

      A project metadata command is introduced that displays the fully resolved metadata. The output format is JSON unless a field is specified as an argument.

      For example, if you checkout a project that is built by Hatch, like FastAPI, and run:

      hatch project metadata readme\n

      only the readme text will be displayed. If the content is in Markdown, then Rich will render it directly in your terminal:

      "},{"location":"blog/2022/10/08/hatch-v160/#virtual-environment-location","title":"Virtual environment location","text":"

      The virtual environment type now uses a flat layout for storage in the configured virtual environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory.

      For example, if you define the following Hatch configuration:

      config.toml
      [dirs.env]\nvirtual = \".hatch\"\n

      and the following matrix:

      pyproject.toml hatch.toml
      [[tool.hatch.envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n
      [[envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n

      then locating environments with the following command:

      hatch env find test\n

      will show that the general directory structure is:

      .hatch\n\u251c\u2500\u2500 test.py3.7\n\u251c\u2500\u2500 test.py3.8\n\u251c\u2500\u2500 test.py3.9\n\u251c\u2500\u2500 test.py3.10\n\u2514\u2500\u2500 test.py3.11\n

      This flat structure is required for detection of virtual environments by tools like Visual Studio Code and PyCharm.

      Additionally, the virtual environment type now supports a path option to specify an explicit path that all inherited environments will share, such as the common .venv.

      "},{"location":"blog/2022/10/08/hatch-v160/#migration-script-improvements","title":"Migration script improvements","text":"

      The script used to migrate existing projects from setuptools has been improved to handle more edge cases that were encountered in the wild and now no longer modifies the formatting of existing pyproject.toml configuration.

      "},{"location":"blog/2022/10/08/hatch-v160/#hatchling","title":"Hatchling","text":"

      Hatch now depends on Hatchling v1.11.0, which was also just released.

      "},{"location":"blog/2022/10/08/hatch-v160/#environment-version-source","title":"Environment version source","text":"

      A new env version source is available that allows for the project version to be defined by an environment variable.

      "},{"location":"blog/2022/10/08/hatch-v160/#relaxed-version-bumping","title":"Relaxed version bumping","text":"

      The standard version scheme now supports a validate-bump option that when set to false will forego the check when updating the version that the desired version is higher than the current version.

      This use case comes from Project Jupyter:

      A common pattern we use in Jupyter is to bump to a .dev0 minor version bump after making a release. If we have a bug fix that needs to go out in the interim, we'd rather not be forced to create a branch every time.

      "},{"location":"blog/2023/12/11/hatch-v180/","title":"Hatch v1.8.0","text":"

      Hatch v1.8.0 brings Python distribution management, static analysis and formatting backed by Ruff, and binaries for every platform.

      "},{"location":"blog/2023/12/11/hatch-v180/#installation-made-easy","title":"Installation made easy","text":"

      One thing that has been a perpetual problem for Hatch and other Python applications is that Python itself is a dependency. You, and more importantly your users, need to in some way get Python before your software can even be used. The recommended way to go about that is platform-dependent and even differs based on your target audience. I viewed this as a central UX problem for Hatch and so severe that I took a bit of a hiatus to solve it.

      Luckily, I have to my satisfaction solved this problem in the form of PyApp. It is a runtime installer for Python projects written in Rust. Apps are distributed as standalone executables as users have come to expect and bootstrapping occurs upon the first invocation. Here is an example of what you would see the first time you run a binary from this release:

      Now that we have binaries, creating installers for different platforms becomes trivial. Starting with this release not only are binaries available for every platform but also we have installers for Windows and macOS. The installer for macOS is signed using a certificate from the same account used to sign the official distributions from https://www.python.org, so users will not get any security pop-ups. Shout out to @ewdurbin for their extreme generosity in setting up multiple certificates in their free time!

      These installers and binaries are now the recommended way to install and update Hatch. These binaries have built-in management so you can update to the latest version by running hatch self update.

      Windows signing

      In future we will sign the installers for Windows but I did not have time to look into how that works. macOS signing took way longer than I anticipated

      "},{"location":"blog/2023/12/11/hatch-v180/#python-management","title":"Python management","text":"

      For a long time I and other users have desired that Hatch gain the ability to manage Python distributions. In my mind this was always blocked on a better installation experience because there was sort of a chicken-or-egg problem where you want a Python manager but you first need Python. No longer is that the case!

      The new python command group allows for easy installation of various distributions to arbitrary locations which are then added to your PATH by default. Hatch supports CPython and PyPy distributions:

      "},{"location":"blog/2023/12/11/hatch-v180/#virtual-environment-python-resolution","title":"Virtual environment Python resolution","text":"

      The virtual environment type is now far more intelligent when resolving the parent distribution to use and guarantees that, when no specific version is requested, the resolved distribution will always be compatible with the project.

      Additionally, when a requested version cannot be found on PATH it will automatically be downloaded and managed internally.

      "},{"location":"blog/2023/12/11/hatch-v180/#static-analysis","title":"Static analysis","text":"

      There is a new fmt command, backed entirely by Ruff, that checks and fixes your code for formatting and linting issues.

      Starting with this release, Hatch maintains default settings that are guaranteed to be up-to-date and represent best practices for programming in modern Python. The idea is to provide defaults that are so broadly applicable that the majority of users will maintain little if any of their own overrides.

      The default behavior is internal management of settings to provide an OOTB experience that works. It is recommended however that you persist the default config file in version control so that other tools like IDEs can utilize your full configuration.

      Since Ruff is now provided as a built-in feature, new project templates no longer have such configuration and are much less verbose.

      "},{"location":"blog/2023/12/11/hatch-v180/#build-improvements","title":"Build improvements","text":"

      Building projects that do not use Hatchling as a backend is now supported and such builds are managed with the standard build tool.

      The bridge between Hatch and the Hatchling CLI has been removed. Previously, the builder would send serialized messages to Hatch that would contain the desired content and style for each line of output. This was done in an effort to allow builder and build hook plugins to output pretty messages without actually requiring a dependency like Rich. A problem that arises with this is that builders that invoke subprocesses will not display ANSI codes as one might expect and will lose out on the interactive experience of such invocations, like the built-in app builder plugin calling cargo build. So now everything is simpler at the expense of no colored output without manual logic, or adding a dependency if you're a third-party plugin.

      "},{"location":"blog/2023/12/11/hatch-v180/#faster-environment-usage","title":"Faster environment usage","text":"

      Spawning a shell or running commands within environments always first checks that your project's dependencies are satisfied and if not synchronizes the environment with what is defined. Previously, this had the potential to be quite slow for projects that have many dependencies.

      Now the set of dependency definitions is hashed and no check is performed if the hash is the same as before, significantly speeding up environment usage in most cases.

      "},{"location":"blog/2023/12/11/hatch-v180/#hatchling","title":"Hatchling","text":"

      Hatch now depends on Hatchling v1.19.0, which was also just released.

      "},{"location":"blog/2023/12/11/hatch-v180/#better-defaults","title":"Better defaults","text":"

      Hatchling is all about providing the best possible defaults, even at the expense of backward compatibility. In this release, there are two breaking changes that provide a much better user experience and were in fact requested by users.

      • Both the force-include option and the force_include_editable wheel build data setting now raise errors if source paths do not exist.
      • The wheel build target now raises an error when no file inclusion options have been defined and none of its heuristics to determine what to ship are satisfied.
      "},{"location":"blog/2023/12/11/hatch-v180/#app-build-target","title":"App build target","text":"

      A new app build target is now stable that allows for the building of standalone binaries for projects. This is what Hatch itself uses for its binaries.

      "},{"location":"blog/2023/12/11/hatch-v180/#meta","title":"Meta","text":""},{"location":"blog/2023/12/11/hatch-v180/#why-hatch","title":"Why Hatch?","text":"

      A new page has been introduced that discusses the value proposition of Hatch and Hatchling in comparison to alternatives. Currently, it only addresses a few features but in future this page will become more comprehensive.

      "},{"location":"blog/2023/12/11/hatch-v180/#future","title":"Future","text":"

      Upcoming features include a test command, commands to manage dependencies, and workspaces functionality similar to Cargo that will make managing monorepos far easier.

      Next year there will be two large efforts that you should expect to see:

      1. A significant amount of my free time (and some at work) will be devoted to introducing lock file functionality in Hatch and trying to get whatever that happens to be standardized.

        I met with @brettcannon about his thoughts post-PEP 665 and about mousebender. I also met with the prefix.dev team about rip and was fortunate enough to be shown a demo before its official announcement.

        At the moment, the two options I see are to either go all in and contribute to mousebender or rely on the Prefix folks and use rip. The latter has the benefit of potentially supporting Conda as a side effect with the downside of being quite new with the spec firmly out of our control. The former has the benefit of being able to easily gain institutional support from the Python packaging team and each of our employers with the downside being a significant amount of work needing to be done.

      2. When @henryiii is able to get some free time away from teaching I plan to work with him once again and push very hard for the Python build ecosystem to adopt the extensionlib approach.

        I am of the opinion that the Python community has not fully completed the expressed outcome of PEP 517 in that build backends are still (for the most part) reliant on setuptools for building non-Python code bases.

        Basically, there are components that interact with compilers to produce extension modules and components that pack files into an archive which we call a build backend. These are two distinct pieces of functionality and my view is that there should be an API that allows backends to consume extension module builders to find out where things got created and where they should be shipped inside archives.

        In this hypothetical future any build backend would be able to trigger the building of extension modules based on user configuration.

      "},{"location":"blog/2023/12/11/hatch-v180/#support","title":"Support","text":"

      If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!

      "},{"location":"blog/2023/12/18/hatch-v190/","title":"Hatch v1.9.0","text":"

      Hatch v1.9.0 brings improvements to static analysis and important bug fixes.

      "},{"location":"blog/2023/12/18/hatch-v190/#static-analysis","title":"Static analysis","text":"

      The default version of Ruff has been increased to v0.1.8. This release brings formatting capabilities to docstrings and Hatch enables this by default with line length set to 80. This length was chosen as the default because it plays nicely with the rendering of the most popular themes for Python documentation, such as Material for MkDocs and Furo.

      Additionally, it is now possible for projects to pin to specific versions of Ruff for upgrading at a later time:

      pyproject.toml hatch.toml
      [tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
      [envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
      "},{"location":"blog/2023/12/18/hatch-v190/#notable-fixes","title":"Notable fixes","text":"
      • Python resolution for environments that do not install the project is no longer bound by the project's Python requirement.
      • Fixed an edge case for out-of-the-box static analysis when there was existing configuration.
      • Compatibility checks for environments no longer occur if the environment is already created. This significantly increases the responsiveness of environment usage.
      "},{"location":"cli/about/","title":"About","text":""},{"location":"cli/about/#verbosity","title":"Verbosity","text":"

      The amount of displayed output is controlled solely by the -v/--verbose (environment variable HATCH_VERBOSE) and -q/--quiet (environment variable HATCH_QUIET) root options.

      The levels are documented here.

      "},{"location":"cli/about/#project-awareness","title":"Project awareness","text":"

      No matter the mode, Hatch will always change to the project's root directory for entering or running commands in environments.

      "},{"location":"cli/about/#tab-completion","title":"Tab completion","text":"

      Completion is achieved by saving a script and then executing it as a part of your shell's startup sequence.

      Afterward, you'll need to start a new shell in order for the changes to take effect.

      BashZ shellfish

      Save the script somewhere:

      _HATCH_COMPLETE=bash_source hatch > ~/.hatch-complete.bash\n

      Source the file in ~/.bashrc (or ~/.bash_profile if on macOS):

      . ~/.hatch-complete.bash\n

      Save the script somewhere:

      _HATCH_COMPLETE=zsh_source hatch > ~/.hatch-complete.zsh\n

      Source the file in ~/.zshrc:

      . ~/.hatch-complete.zsh\n

      Save the script in ~/.config/fish/completions:

      _HATCH_COMPLETE=fish_source hatch > ~/.config/fish/completions/hatch.fish\n
      "},{"location":"cli/reference/","title":"hatch","text":"

      Usage:

      hatch [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --env, -e text The name of the environment to use [env var: HATCH_ENV] default --project, -p text The name of the project to work on [env var: HATCH_PROJECT] None --verbose, -v integer range (0 and above) Increase verbosity (can be used additively) [env var: HATCH_VERBOSE] 0 --quiet, -q integer range (0 and above) Decrease verbosity (can be used additively) [env var: HATCH_QUIET] 0 --color / --no-color boolean Whether or not to display colored output (default is auto-detection) [env vars: FORCE_COLOR/NO_COLOR] None --interactive / --no-interactive boolean Whether or not to allow features like prompts and progress bars (default is auto-detection) [env var: HATCH_INTERACTIVE] None --data-dir text The path to a custom directory used to persist data [env var: HATCH_DATA_DIR] None --cache-dir text The path to a custom directory used to cache data [env var: HATCH_CACHE_DIR] None --config text The path to a custom config file to use [env var: HATCH_CONFIG] None --version boolean Show the version and exit. False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-build","title":"hatch build","text":"

      Build a project.

      Usage:

      hatch build [OPTIONS] [LOCATION]\n

      Options:

      Name Type Description Default --target, -t text The target to build, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None --hooks-only boolean Whether or not to only execute build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False --no-hooks boolean Whether or not to disable build hooks [env var: HATCH_BUILD_NO_HOOKS] False --ext boolean Whether or not to only execute build hooks for distributing binary Python packages, such as compiling extensions. Equivalent to --hooks-only -t wheel False --clean, -c boolean Whether or not existing artifacts should first be removed [env var: HATCH_BUILD_CLEAN] False --clean-hooks-after boolean Whether or not build hook artifacts should be removed after each build [env var: HATCH_BUILD_CLEAN_HOOKS_AFTER] False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-clean","title":"hatch clean","text":"

      Remove build artifacts.

      Usage:

      hatch clean [OPTIONS] [LOCATION]\n

      Options:

      Name Type Description Default --target, -t text The target with which to remove artifacts, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None --hooks-only boolean Whether or not to only remove artifacts from build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False --no-hooks boolean Whether or not to ignore artifacts from build hooks [env var: HATCH_BUILD_NO_HOOKS] False --ext boolean Whether or not to only remove artifacts from build hooks for distributing binary Python packages, such as compiled extensions. Equivalent to --hooks-only -t wheel False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config","title":"hatch config","text":"

      Manage the config file

      Usage:

      hatch config [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-explore","title":"hatch config explore","text":"

      Open the config location in your file manager.

      Usage:

      hatch config explore [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-find","title":"hatch config find","text":"

      Show the location of the config file.

      Usage:

      hatch config find [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-restore","title":"hatch config restore","text":"

      Restore the config file to default settings.

      Usage:

      hatch config restore [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-set","title":"hatch config set","text":"

      Assign values to config file entries. If the value is omitted, you will be prompted, with the input hidden if it is sensitive.

      Usage:

      hatch config set [OPTIONS] KEY [VALUE]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-show","title":"hatch config show","text":"

      Show the contents of the config file.

      Usage:

      hatch config show [OPTIONS]\n

      Options:

      Name Type Description Default --all, -a boolean Do not scrub secret fields False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-update","title":"hatch config update","text":"

      Update the config file with any new fields.

      Usage:

      hatch config update [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep","title":"hatch dep","text":"

      Manage environment dependencies

      Usage:

      hatch dep [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-hash","title":"hatch dep hash","text":"

      Output a hash of the currently defined dependencies.

      Usage:

      hatch dep hash [OPTIONS]\n

      Options:

      Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show","title":"hatch dep show","text":"

      Display dependencies in various formats

      Usage:

      hatch dep show [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show-requirements","title":"hatch dep show requirements","text":"

      Enumerate dependencies as a list of requirements.

      Usage:

      hatch dep show requirements [OPTIONS]\n

      Options:

      Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --feature, -f text Whether or not to only show the dependencies of the specified features None --all boolean Whether or not to include the dependencies of all features False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show-table","title":"hatch dep show table","text":"

      Enumerate dependencies in a tabular format.

      Usage:

      hatch dep show table [OPTIONS]\n

      Options:

      Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --lines, -l boolean Whether or not to show lines between table rows False --ascii boolean Whether or not to only use ASCII characters False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env","title":"hatch env","text":"

      Manage project environments

      Usage:

      hatch env [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-create","title":"hatch env create","text":"

      Create environments.

      Usage:

      hatch env create [OPTIONS] [ENV_NAME]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-find","title":"hatch env find","text":"

      Locate environments.

      Usage:

      hatch env find [OPTIONS] [ENV_NAME]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-prune","title":"hatch env prune","text":"

      Remove all environments.

      Usage:

      hatch env prune [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-remove","title":"hatch env remove","text":"

      Remove environments.

      Usage:

      hatch env remove [OPTIONS] [ENV_NAME]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-run","title":"hatch env run","text":"

      Run commands within project environments.

      The -e/--env option overrides the equivalent root option and the HATCH_ENV environment variable.

      If environments provide matrices, then you may use the -i/--include and -x/--exclude options to select or exclude certain variables, optionally followed by specific comma-separated values. For example, if you have the following configuration:

      pyproject.toml hatch.toml
      [[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
      [[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n

      then running:

      hatch env run -i py=3.10 -x version=9000 test:pytest\n

      would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

      Usage:

      hatch env run [OPTIONS] ARGS...\n

      Options:

      Name Type Description Default --env, -e text The environments to target None --include, -i text The matrix variables to include None --exclude, -x text The matrix variables to exclude None --filter, -f text The JSON data used to select environments None --force-continue boolean Run every command and if there were any errors exit with the first code False --ignore-compat boolean Ignore incompatibility when selecting specific environments False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-show","title":"hatch env show","text":"

      Show the available environments.

      Usage:

      hatch env show [OPTIONS] [ENVS]...\n

      Options:

      Name Type Description Default --ascii boolean Whether or not to only use ASCII characters False --json boolean Whether or not to output in JSON format False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-fmt","title":"hatch fmt","text":"

      Format and lint source code.

      Usage:

      hatch fmt [OPTIONS] [ARGS]...\n

      Options:

      Name Type Description Default --check boolean Only check for errors rather than fixing them False --preview / --no-preview boolean Preview new rules and formatting None --linter, -l boolean Only run the linter False --formatter, -f boolean Only run the formatter False --sync boolean Sync the default config file with the current version of Hatch False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-new","title":"hatch new","text":"

      Create or initialize a project.

      Usage:

      hatch new [OPTIONS] [NAME] [LOCATION]\n

      Options:

      Name Type Description Default --interactive, -i boolean Interactively choose details about the project False --cli boolean Give the project a command line interface False --init boolean Initialize an existing project False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-project","title":"hatch project","text":"

      View project information

      Usage:

      hatch project [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-project-metadata","title":"hatch project metadata","text":"

      Display project metadata.

      If you want to view the raw readme file without rendering, you can use a JSON parser like jq:

      hatch project metadata | jq -r .readme\n

      Usage:

      hatch project metadata [OPTIONS] [FIELD]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-publish","title":"hatch publish","text":"

      Publish build artifacts.

      Usage:

      hatch publish [OPTIONS] [ARTIFACTS]...\n

      Options:

      Name Type Description Default --repo, -r text The repository with which to publish artifacts [env var: HATCH_INDEX_REPO] None --user, -u text The user with which to authenticate [env var: HATCH_INDEX_USER] None --auth, -a text The credentials to use for authentication [env var: HATCH_INDEX_AUTH] None --ca-cert text The path to a CA bundle [env var: HATCH_INDEX_CA_CERT] None --client-cert text The path to a client certificate, optionally containing the private key [env var: HATCH_INDEX_CLIENT_CERT] None --client-key text The path to the client certificate's private key [env var: HATCH_INDEX_CLIENT_KEY] None --no-prompt, -n boolean Disable prompts, such as for missing required fields False --initialize-auth boolean Save first-time authentication information even if nothing was published False --publisher, -p text The publisher plugin to use (default is index) [env var: HATCH_PUBLISHER] index --option, -o text Options to pass to the publisher plugin. This may be selected multiple times e.g. -o foo=bar -o baz=23 [env var: HATCH_PUBLISHER_OPTIONS] None --yes, -y boolean Confirm without prompting when the plugin is disabled False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python","title":"hatch python","text":"

      Manage Python installations

      Usage:

      hatch python [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-find","title":"hatch python find","text":"

      Locate Python binaries.

      Usage:

      hatch python find [OPTIONS] NAME\n

      Options:

      Name Type Description Default -p, --parent boolean Show the parent directory of the Python binary False --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-install","title":"hatch python install","text":"

      Install Python distributions.

      You may select all to install all compatible distributions:

      hatch python install all\n

      Usage:

      hatch python install [OPTIONS] NAMES...\n

      Options:

      Name Type Description Default --private boolean Do not add distributions to the user PATH False --update, -u boolean Update existing installations False --dir, -d text The directory in which to install distributions, overriding configuration None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-remove","title":"hatch python remove","text":"

      Remove Python distributions.

      You may select all to remove all installed distributions:

      hatch python remove all\n

      Usage:

      hatch python remove [OPTIONS] NAMES...\n

      Options:

      Name Type Description Default --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-show","title":"hatch python show","text":"

      Show the available Python distributions.

      Usage:

      hatch python show [OPTIONS]\n

      Options:

      Name Type Description Default --ascii boolean Whether or not to only use ASCII characters False --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-update","title":"hatch python update","text":"

      Update Python distributions.

      You may select all to update all installed distributions:

      hatch python update all\n

      Usage:

      hatch python update [OPTIONS] NAMES...\n

      Options:

      Name Type Description Default --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-run","title":"hatch run","text":"

      Run commands within project environments. This is a convenience wrapper around the env run command.

      If the first argument contains a colon, then the preceding component will be interpreted as the name of the environment to target, overriding the -e/--env root option and the HATCH_ENV environment variable.

      If the environment provides matrices, then you may also provide leading arguments starting with a + or - to select or exclude certain variables, optionally followed by specific comma-separated values. For example, if you have the following configuration:

      pyproject.toml hatch.toml
      [[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
      [[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n

      then running:

      hatch run +py=3.10 -version=9000 test:pytest\n

      would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

      Usage:

      hatch run [OPTIONS] [ENV:]ARGS...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-shell","title":"hatch shell","text":"

      Enter a shell within a project's environment.

      Usage:

      hatch shell [OPTIONS] [SHELL_NAME] [SHELL_PATH] [SHELL_ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-status","title":"hatch status","text":"

      Show information about the current environment.

      Usage:

      hatch status [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-version","title":"hatch version","text":"

      View or set a project's version.

      Usage:

      hatch version [OPTIONS] [DESIRED_VERSION]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"community/contributing/","title":"Contributing","text":"

      The usual process to make a contribution is to:

      1. Check for existing related issues
      2. Fork the repository and create a new branch
      3. Make your changes
      4. Make sure formatting, linting and tests passes.
      5. Add tests if possible to cover the lines you added.
      6. Commit, and send a Pull Request.
      "},{"location":"community/contributing/#clone-the-repository","title":"Clone the repository","text":"

      Clone the hatch repository, cd into it, and create a new branch for your contribution:

      cd hatch\ngit checkout -b add-my-contribution\n
      "},{"location":"community/contributing/#run-the-tests","title":"Run the tests","text":"

      Run the test suite while developing:

      hatch run dev\n

      Run the test suite with coverage report:

      hatch run cov\n

      Run the extended test suite with coverage:

      hatch run full\n
      "},{"location":"community/contributing/#lint","title":"Lint","text":"

      Run automated formatting:

      hatch run lint:fmt\n

      Run full linting and type checking:

      hatch run lint:all\n
      "},{"location":"community/contributing/#docs","title":"Docs","text":"

      Start the documentation in development:

      hatch run docs:serve\n

      Build and validate the documentation website:

      hatch run build-check\n
      "},{"location":"community/highlights/","title":"Highlights","text":""},{"location":"community/highlights/#integration","title":"Integration","text":"
      • Project Jupyter - https://blog.jupyter.org/packaging-for-jupyter-in-2022-c7be64c38926
      "},{"location":"community/highlights/#adoption","title":"Adoption","text":"
      • Black - https://ichard26.github.io/blog/2022/10/black-22.10.0/#goodbye-python-36-and-hello-hatchling
      • \"Switching to Hatch\" - https://andrich.me/2023/08/switching-to-hatch/
      "},{"location":"community/users/","title":"Users","text":"

      The following is not intended to be a complete enumeration. Be sure to view the development version of this page for an up-to-date listing.

      "},{"location":"community/users/#projects","title":"Projects","text":"

      aiogram | argon2-cffi | attrs | Black | coffea | Colorama | Django Anymail | Django Debug Toolbar | Django Wiki | FastAPI | filelock | github3.py | Gradio | HTTPX | iCalendar for Humans | LinkChecker | Material for MkDocs | MkDocs | openSUSE | Nox | Packit | pipx | platformdirs | Pydantic | Pygments | PyHamcrest | PyMdown Extensions | Python JSON Schema | Rye | SALib | Spack | Starlette | structlog | tox | Twisted | urllib3 | Uvicorn | virtualenv | Voil\u00e0 | XGBoost | Ypy

      "},{"location":"community/users/#industry","title":"Industry","text":"
      • Anaconda [1|2|3|4|5|6]
      • Astronomer [1]
      • Bloomberg [1|2]
      • Blue Robotics [1]
      • Cars.com [1]
      • Databricks [1|2]
      • Datadog [1|2|3|4]
      • deepset [1|2]
      • Elastic [1|2|3]
      • Google [1|2|3|4|5]
      • IBM [1]
      • JPMorgan Chase [1]
      • Intel Corporation [1|2|3]
      • Meta [1|2]
      • Microsoft [1|2|3|4|5]
      • OpenAI [1]
      • Oracle [1]
      • Palo Alto Networks [1]
      • Red Hat [1|2|3|4|5]
      • Snowflake [1]
      • Splunk [1]
      • Virtru [1|2]
      • VMware [1|2|3]
      • Volvo Group [1]
      "},{"location":"community/users/#organizations","title":"Organizations","text":"
      • Greater Paris University Hospitals (AP-HP) [1]
      • OpenTelemetry [1|2]
      • Smithsonian Institution [1]
      • The New York Public Library [1]
      "},{"location":"community/users/#government","title":"Government","text":"
      • European Molecular Biology Laboratory
        • European Bioinformatics Institute [1]
      • Germany
        • Berlin Institute of Health [1]
        • Helmholtz Munich [1|2]
      • Norway
        • Statistics Norway [1]
      • United Kingdom
        • The Alan Turing Institute [1]
        • Department for Business and Trade [1]
        • The National Archives [1]
      • United States
        • NASA [1]
        • National Security Agency [1|2]
        • National Telecommunications and Information Administration [1|2|3|4]
      "},{"location":"community/users/#academia","title":"Academia","text":"
      • Brown University
        • Carney Institute for Brain Science [1]
      • Chinese Academy of Sciences
        • Academy of Mathematics and Systems Science [1]
      • Georgia Institute of Technology
        • Georgia Tech Database Group [1]
      • Harvard University
        • Department of Molecular and Cellular Biology [1]
      • Heidelberg University
        • Center for Molecular Biology [1]
      • Leiden University
        • Leiden University Libraries [1|2]
      • Maastricht University
        • Institute of Data Science [1|2|3|4|5|6|7]
      • Massachusetts Institute of Technology
        • Computer Science and Artificial Intelligence Laboratory [1]
        • Digital Humanities [1]
      • Medical University of Innsbruck
        • Institute of Bioinformatics [1]
      • Polytechnique Montr\u00e9al
        • Department of Computer Engineering and Software Engineering [1]
      • Siberian Branch of the Russian Academy of Sciences
        • Institute of Cytology and Genetics [1|2|3|4]
      • Stanford University
        • Empirical Security Research Group [1]
      • University of British Columbia
        • Department of Earth, Ocean and Atmospheric Sciences [1|2|3]
      • University of California, Berkeley
        • Center for Computational Biology [1]
      • University of Freiburg
        • Freiburg Center for Data Analysis and Modeling [1]
      • University of Illinois Urbana-Champaign
        • Grainger College of Engineering [1]
      • University of Lausanne
        • Department of Computational Biology [1]
      • University of Ljubljana
        • Faculty of Mechanical Engineering [1]
      • University of Oxford
        • Oxford Research Software Engineering [1]
      • University of Pennsylvania
        • Lifespan Informatics and Neuroimaging Center [1]
      • University of Sussex
        • Predictive Analytics Lab [1]
      • University of Toronto Scarborough
        • utsc-networking [1|2|3|4]
      • University of Washington
        • Interactive Data Lab [1]
        • Virtual Brain Lab [1]
      • Waseda University
        • Tackeuchi Laboratory [1|2|3|4|5]
      • Wellcome Sanger Institute [1]
      "},{"location":"community/users/#research","title":"Research","text":"
      • Clariah [1]
      • CloudDrift [1]
      • GAMA [1]
      • IPython [1|2|3]
      • MNE [1|2|3]
      • NIPY [1|2]
      • Project Jupyter
        • Jupyter [1|2|3|4]
        • JupyterLab [1|2|3|4|5]
        • Jupyter Server [1|2|3|4]
      • Scikit-HEP [1|2|3|4|5|6|7|8|9|10]
      • scverse [1|2|3]
      • Spyder [1]
      "},{"location":"community/users/#security","title":"Security","text":"
      • Armory
      • in-toto
      • The Update Framework
      "},{"location":"community/users/#crypto","title":"Crypto","text":"
      • Ocean Protocol [1]
      "},{"location":"config/build/","title":"Build configuration","text":"

      Build targets are defined as sections within tool.hatch.build.targets:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.<TARGET_NAME>]\n
      [build.targets.<TARGET_NAME>]\n

      Tip

      Although not recommended, you may define global configuration in the tool.hatch.build table. Keys may then be overridden by target config.

      "},{"location":"config/build/#build-system","title":"Build system","text":"

      To be compatible with the broader Python packaging ecosystem, you must define the build system as follows:

      pyproject.toml
      [build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n

      The version of hatchling defined here will be used to build all targets.

      Hatchling is a standards-compliant1 build backend and is a dependency of Hatch itself.

      "},{"location":"config/build/#file-selection","title":"File selection","text":""},{"location":"config/build/#vcs","title":"VCS","text":"

      By default, Hatch will respect the first .gitignore or .hgignore file found in your project's root directory or parent directories. Set ignore-vcs to true to disable this behavior:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.sdist]\nignore-vcs = true\n
      [build.targets.sdist]\nignore-vcs = true\n

      Note

      For .hgignore files only glob syntax is supported.

      "},{"location":"config/build/#patterns","title":"Patterns","text":"

      You can set the include and exclude options to select exactly which files will be shipped in each build, with exclude taking precedence. Every entry represents a Git-style glob pattern.

      For example, the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.sdist]\ninclude = [\n  \"pkg/*.py\",\n  \"/tests\",\n]\nexclude = [\n  \"*.json\",\n  \"pkg/_compat.py\",\n]\n
      [build.targets.sdist]\ninclude = [\n  \"pkg/*.py\",\n  \"/tests\",\n]\nexclude = [\n  \"*.json\",\n  \"pkg/_compat.py\",\n]\n

      will exclude every file with a .json extension, and will include everything under a tests directory located at the root and every file with a .py extension that is directly under a pkg directory located at the root except for _compat.py.

      "},{"location":"config/build/#artifacts","title":"Artifacts","text":"

      If you want to include files that are ignored by your VCS, such as those that might be created by build hooks, you can use the artifacts option. This option is semantically equivalent to include.

      Note that artifacts are not affected by the exclude option. Artifacts can be excluded by using more explicit paths or by using the ! negation operator. When using the ! operator, the negated pattern(s) must come after the more generic ones.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\nartifacts = [\n  \"*.so\",\n  \"*.dll\",\n  \"!/foo/*.so\",\n]\n
      [build.targets.wheel]\nartifacts = [\n  \"*.so\",\n  \"*.dll\",\n  \"!/foo/*.so\",\n]\n
      "},{"location":"config/build/#explicit-selection","title":"Explicit selection","text":""},{"location":"config/build/#generic","title":"Generic","text":"

      You can use the only-include option to prevent directory traversal starting at the project root and only select specific relative paths to directories or files. Using this option ignores any defined include patterns.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
      [build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
      "},{"location":"config/build/#packages","title":"Packages","text":"

      The packages option is semantically equivalent to only-include (which takes precedence) except that the shipped path will be collapsed to only include the final component.

      So for example, if you want to ship a package foo that is stored in a directory src you would do:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
      [build.targets.wheel]\npackages = [\"src/foo\"]\n
      "},{"location":"config/build/#forced-inclusion","title":"Forced inclusion","text":"

      The force-include option allows you to select specific files or directories from anywhere on the file system that should be included and map them to the desired relative distribution path.

      For example, if there was a directory alongside the project root named artifacts containing a file named lib.so and a file named lib.h in your home directory, you could ship both files in a pkg directory with the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n
      [build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n

      Note

      • Files must be mapped exactly to their desired paths, not to directories.
      • The contents of directory sources are recursively included.
      • To map directory contents directly to the root use / (a forward slash).
      • Sources that do not exist will raise an error.

      Warning

      Files included using this option will overwrite any file path that was already included by other file selection options.

      "},{"location":"config/build/#default-file-selection","title":"Default file selection","text":"

      If no file selection options are provided, then what gets included is determined by each build target.

      "},{"location":"config/build/#excluding-files-outside-packages","title":"Excluding files outside packages","text":"

      If you want to exclude non-artifact files that do not reside within a Python package, set only-packages to true:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\nonly-packages = true\n
      [build.targets.wheel]\nonly-packages = true\n
      "},{"location":"config/build/#rewriting-paths","title":"Rewriting paths","text":"

      You can rewrite relative paths to directories with the sources option. For example, the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n
      [build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n

      would distribute the file src/foo/file.ext as bar/file.ext.

      If you want to remove path prefixes entirely, rather than setting each to an empty string, you can define sources as an array:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\nsources = [\"src\"]\n
      [build.targets.wheel]\nsources = [\"src\"]\n

      If you want to add a prefix to paths, you can use an empty string. For example, the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel.sources]\n\"\" = \"foo\"\n
      [build.targets.wheel.sources]\n\"\" = \"foo\"\n

      would distribute the file bar/file.ext as foo/bar/file.ext.

      The packages option itself relies on sources. Defining packages = [\"src/foo\"] for the wheel target is equivalent to the following:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
      [build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
      "},{"location":"config/build/#performance","title":"Performance","text":"

      All encountered directories are traversed by default. To skip non-artifact directories that are excluded, set skip-excluded-dirs to true:

      pyproject.toml hatch.toml
      [tool.hatch.build]\nskip-excluded-dirs = true\n
      [build]\nskip-excluded-dirs = true\n

      Warning

      This may result in not shipping desired files. For example, if you want to include the file a/b/c.txt but your VCS ignores a/b, the file c.txt will not be seen because its parent directory will not be entered. In such cases you can use the force-include option.

      "},{"location":"config/build/#reproducible-builds","title":"Reproducible builds","text":"

      By default, build targets will build in a reproducible manner provided that they support that behavior. To disable this, set reproducible to false:

      pyproject.toml hatch.toml
      [tool.hatch.build]\nreproducible = false\n
      [build]\nreproducible = false\n

      When enabled, the SOURCE_DATE_EPOCH environment variable will be used for all build timestamps. If not set, then Hatch will use an unchanging default value.

      "},{"location":"config/build/#output-directory","title":"Output directory","text":"

      When the output directory is not provided to the build command, the dist directory will be used by default. You can change the default to a different directory using a relative or absolute path like so:

      pyproject.toml hatch.toml
      [tool.hatch.build]\ndirectory = \"<PATH>\"\n
      [build]\ndirectory = \"<PATH>\"\n
      "},{"location":"config/build/#dev-mode","title":"Dev mode","text":"

      By default for dev mode environment installations or editable installs, the wheel target will determine which directories should be added to Python's search path based on the selected files.

      If you want to override this detection or perhaps instruct other build targets as well, you can use the dev-mode-dirs option:

      pyproject.toml hatch.toml
      [tool.hatch.build]\ndev-mode-dirs = [\".\"]\n
      [build]\ndev-mode-dirs = [\".\"]\n

      If you don't want to add entire directories to Python's search path, you can enable a more targeted mechanism with the mutually exclusive dev-mode-exact option:

      pyproject.toml hatch.toml
      [tool.hatch.build]\ndev-mode-exact = true\n
      [build]\ndev-mode-exact = true\n

      Warning

      The dev-mode-exact mechanism is not supported by static analysis tools & IDEs, therefore functionality such as autocompletion is unlikely to work.

      "},{"location":"config/build/#build-targets","title":"Build targets","text":"

      A build target can be provided by any builder plugin. There are three built-in build targets: wheel, sdist, and custom.

      "},{"location":"config/build/#dependencies","title":"Dependencies","text":"

      You can specify additional dependencies that will be installed in each build environment, such as for third party builders:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.your-target-name]\ndependencies = [\n  \"your-builder-plugin\"\n]\n
      [build.targets.your-target-name]\ndependencies = [\n  \"your-builder-plugin\"\n]\n

      You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies option:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.your-target-name]\nrequire-runtime-dependencies = true\n
      [build.targets.your-target-name]\nrequire-runtime-dependencies = true\n

      Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features option:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.your-target-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
      [build.targets.your-target-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
      "},{"location":"config/build/#versions","title":"Versions","text":"

      If a build target supports multiple build strategies or if there are major changes over time, you can specify exactly which versions you want to build using the versions option:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.<TARGET_NAME>]\nversions = [\n  \"v1\",\n  \"beta-feature\",\n]\n
      [build.targets.<TARGET_NAME>]\nversions = [\n  \"v1\",\n  \"beta-feature\",\n]\n

      See the wheel target for a real world example.

      "},{"location":"config/build/#build-hooks","title":"Build hooks","text":"

      A build hook defines code that will be executed at various stages of the build process and can be provided by any build hook plugin. There is one built-in build hook: custom.

      Build hooks can be applied either globally:

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.<HOOK_NAME>]\n
      [build.hooks.<HOOK_NAME>]\n

      or to specific build targets:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
      [build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
      "},{"location":"config/build/#dependencies_1","title":"Dependencies","text":"

      You can specify additional dependencies that will be installed in each build environment, such as for third party build hooks:

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.your-hook-name]\ndependencies = [\n  \"your-build-hook-plugin\"\n]\n
      [build.hooks.your-hook-name]\ndependencies = [\n  \"your-build-hook-plugin\"\n]\n

      You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies option:

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n
      [build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n

      Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features option:

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
      [build.hooks.your-hook-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
      "},{"location":"config/build/#order-of-execution","title":"Order of execution","text":"

      For each build target, build hooks execute in the order in which they are defined, starting with global hooks.

      As an example, for the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.foo.hooks.hook2]\n\n[tool.hatch.build.hooks.hook3]\n[tool.hatch.build.hooks.hook1]\n
      [build.targets.foo.hooks.hook2]\n\n[build.hooks.hook3]\n[build.hooks.hook1]\n

      When target foo is built, build hook hook3 will be executed first, followed by hook1, and then finally hook2.

      "},{"location":"config/build/#conditional-execution","title":"Conditional execution","text":"

      If you want to disable a build hook by default and control its use by environment variables, you can do so by setting the enable-by-default option to false:

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
      [build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
      "},{"location":"config/build/#environment-variables","title":"Environment variables","text":"Variable Default Description HATCH_BUILD_CLEAN false Whether or not existing artifacts should first be removed HATCH_BUILD_CLEAN_HOOKS_AFTER false Whether or not build hook artifacts should be removed after each build HATCH_BUILD_HOOKS_ONLY false Whether or not to only execute build hooks HATCH_BUILD_NO_HOOKS false Whether or not to disable all build hooks; this takes precedence over other options HATCH_BUILD_HOOKS_ENABLE false Whether or not to enable all build hooks HATCH_BUILD_HOOK_ENABLE_<HOOK_NAME> false Whether or not to enable the build hook named <HOOK_NAME> HATCH_BUILD_LOCATION dist The location with which to build the targets; only used by the build command
      1. Support for PEP 517 and PEP 660 guarantees interoperability with other build tools.\u00a0\u21a9

      "},{"location":"config/context/","title":"Context formatting","text":"

      You can populate configuration with the values of certain supported fields using the syntax of Python's format strings. Each field interprets the modifier part after the colon differently, if at all.

      "},{"location":"config/context/#global-fields","title":"Global fields","text":"

      Any configuration that declares support for context formatting will always support these fields.

      "},{"location":"config/context/#paths","title":"Paths","text":"Field Description root The root project directory home The user's home directory

      All paths support the following modifiers:

      Modifier Description uri The normalized absolute URI path prefixed by file: real The path with all symbolic links resolved parent The parent of the preceding path

      Tip

      The parent modifier can be chained and may be combined with either the uri or real modifier, with the latter placed at the end. For example:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n    \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
      [envs.test]\ndependencies = [\n    \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
      "},{"location":"config/context/#system-separators","title":"System separators","text":"Field Description / \\ on Windows, / otherwise ; ; on Windows, : otherwise"},{"location":"config/context/#environment-variables","title":"Environment variables","text":"

      The env field and its modifier allow you to select the value of an environment variable. If the environment variable is not set, you must specify a default value as an additional modifier e.g. {env:PATH:DEFAULT}.

      "},{"location":"config/context/#field-nesting","title":"Field nesting","text":"

      You can insert fields within others. For example, if you wanted a script that displays the value of the environment variable FOO, with a fallback to the environment variable BAR, with its own fallback to the user's home directory, you could do the following:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
      [envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
      "},{"location":"config/dependency/","title":"Dependency configuration","text":"

      Project dependencies are defined with PEP 508 strings using optional PEP 440 version specifiers.

      "},{"location":"config/dependency/#version-specifiers","title":"Version specifiers","text":"

      A version specifier consists of a series of version clauses, separated by commas. For example:

      pyproject.toml
      [project]\n...\ndependencies = [\n  \"cryptography\",\n  \"click>=7, <9, != 8.0.0\",\n  \"python-dateutil==2.8.*\",\n  \"numpy~=1.21.4\",\n]\n

      The comma is equivalent to a logical AND operator: a candidate version must match all given version clauses in order to match the specifier as a whole.

      "},{"location":"config/dependency/#operators","title":"Operators","text":"Operators Function ~= Compatible release == Version matching != Version exclusion <=, >= Inclusive ordered comparison <, > Exclusive ordered comparison === Arbitrary equality"},{"location":"config/dependency/#version-matching","title":"Version matching","text":"

      A version matching clause includes the version matching operator == and a version identifier.

      By default, the version matching operator is based on a strict equality comparison: the specified version must be exactly the same as the requested version.

      Clause Allowed versions ==1 1.0.0 ==1.2 1.2.0

      Prefix matching may be requested instead of strict comparison, by appending a trailing .* to the version identifier in the version matching clause. This means that additional trailing segments will be ignored when determining whether or not a version identifier matches the clause.

      Clause Allowed versions ==1.* >=1.0.0, <2.0.0 ==1.2.* >=1.2.0, <1.3.0"},{"location":"config/dependency/#compatible-release","title":"Compatible release","text":"

      A compatible release clause consists of the compatible release operator ~= and a version identifier. It matches any candidate version that is expected to be compatible with the specified version.

      For a given release identifier V.N, the compatible release clause is approximately equivalent to the following pair of comparison clauses:

      >= V.N, == V.*\n

      This operator cannot be used with a single segment version number such as ~=1.

      Clause Allowed versions ~=1.2 >=1.2.0, <2.0.0 ~=1.2.3 >=1.2.3, <1.3.0"},{"location":"config/dependency/#version-exclusion","title":"Version exclusion","text":"

      A version exclusion clause includes the version exclusion operator != and a version identifier.

      The allowed version identifiers and comparison semantics are the same as those of the Version matching operator, except that the sense of any match is inverted.

      "},{"location":"config/dependency/#ordered-comparison","title":"Ordered comparison","text":"

      Inclusive comparisons allow for the version identifier part of clauses whereas exclusive comparisons do not. For example, >=1.2 allows for version 1.2.0 while >1.2 does not.

      Unlike the inclusive ordered comparisons <= and >=, the exclusive ordered comparisons < and > specifically exclude pre-releases, post-releases, and local versions of the specified version.

      "},{"location":"config/dependency/#arbitrary-equality","title":"Arbitrary equality","text":"

      Though heavily discouraged, arbitrary equality comparisons allow for simple string matching without any version semantics, for example ===foobar.

      "},{"location":"config/dependency/#environment-markers","title":"Environment markers","text":"

      Environment markers allow for dependencies to only be installed when certain conditions are met.

      For example, if you need to install the latest version of cryptography that is available for a given Python major version you could define the following:

      cryptography==3.3.2; python_version < \"3\"\ncryptography>=35.0; python_version > \"3\"\n

      Alternatively, if you only need it on Python 3 when running on Windows you could do:

      cryptography; python_version ~= \"3.0\" and platform_system == \"Windows\"\n

      The available environment markers are as follows.

      Marker Python equivalent Examples os_name import osos.name
      • posix
      • java
      sys_platform import syssys.platform
      • linux
      • win32
      • darwin
      platform_machine import platformplatform.machine()
      • x86_64
      platform_python_implementation import platformplatform.python_implementation()
      • CPython
      • Jython
      platform_release import platformplatform.release()
      • 1.8.0_51
      • 3.14.1-x86_64-linode39
      platform_system import platformplatform.system()
      • Linux
      • Windows
      • Darwin
      platform_version import platformplatform.version()
      • 10.0.19041
      • #1 SMP Fri Apr 2 22:23:49 UTC 2021
      python_version import platform'.'.join(platform.python_version_tuple()[:2])
      • 2.7
      • 3.10
      python_full_version import platformplatform.python_version()
      • 2.7.18
      • 3.11.0b1
      implementation_name import syssys.implementation.name
      • cpython
      implementation_version See here
      • 2.7.18
      • 3.11.0b1
      "},{"location":"config/dependency/#features","title":"Features","text":"

      You can select groups of optional dependencies to install using the extras syntax. For example, if a dependency named foo defined the following:

      pyproject.toml
      [project.optional-dependencies]\ncrypto = [\n  \"PyJWT\",\n  \"cryptography\",\n]\nfastjson = [\n  \"orjson\",\n]\ncli = [\n  \"prompt-toolkit\",\n  \"colorama; platform_system == 'Windows'\",\n]\n

      You can select the cli and crypto features like so:

      foo[cli,crypto]==1.*\n

      Note that the features come immediately after the package name, before any version specifiers.

      "},{"location":"config/dependency/#self-referential","title":"Self-referential","text":"

      Feature groups can self-referentially extend others. For example, for a project called awesome-project, the dev feature group in the following pyproject.toml file would select everything in the crypto feature group, plus black:

      pyproject.toml
      [project]\nname = \"awesome-project\"\n\n[project.optional-dependencies]\ncrypto = [\n  \"PyJWT\",\n  \"cryptography\",\n]\ndev = [\n  \"awesome-project[crypto]\",\n  \"black\",\n]\n
      "},{"location":"config/dependency/#direct-references","title":"Direct references","text":"

      Instead of using normal version specifiers and fetching packages from an index like PyPI, you can define exact sources using direct references with an explicit URI.

      Direct references are usually not meant to be used for dependencies of a published project but rather are used for defining dependencies for an environment.

      All direct reference types are prefixed by the package name like:

      <NAME> @ <REFERENCE>\n
      "},{"location":"config/dependency/#version-control-systems","title":"Version control systems","text":"

      Various version control systems (VCS) are supported as long as the associated executable is available along your PATH.

      VCS direct references are defined using one of the following formats:

      <NAME> @ <SCHEME>://<PATH>\n<NAME> @ <SCHEME>://<PATH>@<REVISION>\n

      You may also append a #subdirectory=<PATH> component for specifying the relative path to the Python package when it is not located at the root e.g. #subdirectory=lib/foo.

      For more information, refer to this.

      "},{"location":"config/dependency/#supported-vcs","title":"Supported VCS","text":"GitMercurialSubversionBazaar Executable Schemes Revisions Example git
      • git+file
      • git+https
      • git+ssh
      • git+http
      • git+git
      • git
      • Commit hash
      • Tag name
      • Branch name
      proj @ git+https://github.com/org/proj.git@v1 Executable Schemes Revisions Example hg
      • hg+file
      • hg+https
      • hg+ssh
      • hg+http
      • hg+static-http
      • Revision hash
      • Revision number
      • Tag name
      • Branch name
      proj @ hg+file:///path/to/proj@v1 Executable Schemes Revisions Example svn
      • svn+https
      • svn+ssh
      • svn+http
      • svn+svn
      • svn
      • Revision number
      proj @ svn+file:///path/to/proj Executable Schemes Revisions Example bzr
      • bzr+https
      • bzr+ssh
      • bzr+sftp
      • bzr+lp
      • bzr+http
      • bzr+ftp
      • Revision number
      • Tag name
      proj @ bzr+lp:proj@v1"},{"location":"config/dependency/#local","title":"Local","text":"

      You can install local packages with the file scheme in the following format:

      <NAME> @ file://<HOST>/<PATH>\n

      The <HOST> is only used on Windows systems, where it can refer to a network share. If omitted it is assumed to be localhost and the third slash must still be present.

      The <PATH> can refer to a source archive, a wheel, or a directory containing a Python package.

      Type Unix Windows Source archive proj @ file:///path/to/pkg.tar.gz proj @ file:///c:/path/to/pkg.tar.gz Wheel proj @ file:///path/to/pkg.whl proj @ file:///c:/path/to/pkg.whl Directory proj @ file:///path/to/pkg proj @ file:///c:/path/to/pkg

      Tip

      You may also specify paths relative to your project's root directory on all platforms by using context formatting:

      <NAME> @ {root:uri}/pkg_inside_project\n<NAME> @ {root:uri}/../pkg_alongside_project\n
      "},{"location":"config/dependency/#remote","title":"Remote","text":"

      You can install source archives and wheels by simply referring to a URL:

      black @ https://github.com/psf/black/archive/refs/tags/21.10b0.zip\npytorch @ https://download.pytorch.org/whl/cu102/torch-1.10.0%2Bcu102-cp39-cp39-linux_x86_64.whl\n

      An expected hash value may be specified by appending a #<HASH_ALGORITHM>=<EXPECTED_HASH> component:

      requests @ https://github.com/psf/requests/archive/refs/tags/v2.26.0.zip#sha256=eb729a757f01c10546ebd179ae2aec852dd0d7f8ada2328ccf4558909d859985\n

      If the hash differs from the expected hash, the installation will fail.

      It is recommended that only hashes which are unconditionally provided by the latest version of the standard library's hashlib module be used for hashes. As of Python 3.10, that list consists of:

      • md5
      • sha1
      • sha224
      • sha256
      • sha384
      • sha512
      • blake2b
      • blake2s
      "},{"location":"config/dependency/#complex-syntax","title":"Complex syntax","text":"

      The following is an example that uses features and environment markers:

      pkg[feature1,feature2] @ <REFERENCE> ; python_version < \"3.7\"\n

      Note that the space before the semicolon is required.

      "},{"location":"config/hatch/","title":"Hatch configuration","text":"

      Configuration for Hatch itself is stored in a config.toml file located by default in one of the following platform-specific directories.

      Platform Path macOS ~/Library/Application Support/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch Unix $XDG_CONFIG_HOME/hatch (the XDG_CONFIG_HOME environment variable default is ~/.config)

      You can select a custom path to the file using the --config root option or by setting the HATCH_CONFIG environment variable.

      The file can be managed by the config command group.

      "},{"location":"config/hatch/#mode","title":"Mode","text":"

      The mode key controls how Hatch selects the project to work on.

      "},{"location":"config/hatch/#local","title":"Local","text":"config.toml
      mode = \"local\"\n

      By default, Hatch will look for a pyproject.toml file in the current working directory and any parent directories. The directory storing the first found file will be considered the project root.

      "},{"location":"config/hatch/#project","title":"Project","text":"config.toml
      mode = \"project\"\nproject = \"proj1\"\n\n[projects]\nproj1 = \"/path/to/project1\"\nproj2 = {\"location\": \"/path/to/project2\"}\n\n[dirs]\nproject = [\"/path/to/monorepo1\", \"/path/to/monorepo2\"]\n

      In this mode, Hatch will only work on the selected project. The project is located using multiple heuristics:

      1. If the project is defined in the projects table then it must be a string, or an inline table with a location key, that is the full path to the project.
      2. If the project matches a subdirectory in any of the directories listed in dirs.project, then that will be used as the project root.

      An error will occur if the project cannot be found.

      You can use the config set command to change the project you are working on:

      $ hatch config set project proj2\nNew setting:\nproject = \"proj2\"\n

      The project can be selected on a per-command basis with the -p/--project (environment variable HATCH_PROJECT) root option.

      "},{"location":"config/hatch/#aware","title":"Aware","text":"config.toml
      mode = \"aware\"\n

      This is essentially the local mode with a fallback to the project mode.

      "},{"location":"config/hatch/#shell","title":"Shell","text":"

      You can control the shell used to enter environments with the shell key.

      If defined as a string, it must be the name of one of the supported shells and be available along your PATH.

      config.toml
      shell = \"fish\"\n

      If the executable name of your shell differs from the supported name, you can define the shell as a table with name and path keys.

      config.toml
      [shell]\nname = \"bash\"\npath = \"/bin/ash\"\n

      You can change the default arguments used to spawn most shells with the args key. The default for such supported shells is usually [\"-i\"].

      config.toml
      [shell]\nname = \"bash\"\nargs = [\"--login\"]\n
      "},{"location":"config/hatch/#supported","title":"Supported","text":"Shell Name Arguments macOS Windows Unix Almquist shell ash [\"-i\"] Bash bash [\"-i\"] Command Prompt cmd C shell csh [\"-i\"] fish fish [\"-i\"] Nushell nu [] PowerShell pwsh, powershell tcsh tcsh [\"-i\"] xonsh xonsh [\"-i\"] Z shell zsh [\"-i\"]"},{"location":"config/hatch/#default","title":"Default","text":"

      Hatch will attempt to use the current shell based on parent processes. If the shell cannot be determined, then on Windows systems Hatch will use the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

      "},{"location":"config/hatch/#directories","title":"Directories","text":""},{"location":"config/hatch/#data","title":"Data","text":"config.toml
      [dirs]\ndata = \"...\"\n

      This is the directory that is used to persist data. By default it is set to one of the following platform-specific directories.

      Platform Path macOS ~/Library/Application Support/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch Unix $XDG_DATA_HOME/hatch (the XDG_DATA_HOME environment variable default is ~/.local/share)

      You can select a custom path to the directory using the --data-dir root option or by setting the HATCH_DATA_DIR environment variable.

      "},{"location":"config/hatch/#cache","title":"Cache","text":"config.toml
      [dirs]\ncache = \"...\"\n

      This is the directory that is used to cache data. By default it is set to one of the following platform-specific directories.

      Platform Path macOS ~/Library/Caches/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch\\Cache Unix $XDG_CACHE_HOME/hatch (the XDG_CACHE_HOME environment variable default is ~/.cache)

      You can select a custom path to the directory using the --cache-dir root option or by setting the HATCH_CACHE_DIR environment variable.

      "},{"location":"config/hatch/#environments","title":"Environments","text":"config.toml
      [dirs.env]\n<ENV_TYPE> = \"...\"\n

      This determines where to store environments, with every key being the type of environment and the value being the desired storage location.

      For example, if you wanted to store virtual environments in a .virtualenvs directory within your home directory, you could specify the following:

      config.toml
      [dirs.env]\nvirtual = \"~/.virtualenvs\"\n

      Any environment variables are also expanded.

      If the path is not absolute, then it will be relative to the project root. So if you wanted to use a directory named .hatch in each project directory, you could do:

      config.toml
      [dirs.env]\nvirtual = \".hatch\"\n

      Any type of environment that is not explicitly defined will default to <DATA_DIR>/env/<ENV_TYPE>.

      "},{"location":"config/hatch/#python-installations","title":"Python installations","text":"config.toml
      [dirs]\npython = \"...\"\n

      This determines where to install specific versions of Python.

      The following values have special meanings:

      Value Path isolated (default) <DATA_DIR>/pythons"},{"location":"config/hatch/#terminal","title":"Terminal","text":"

      You can configure how all output is displayed using the terminal.styles table. These settings are also applied to all plugins.

      config.toml
      [terminal.styles]\nerror = \"...\"\n...\n

      Cross-platform terminal capabilities are provided by Rich.

      "},{"location":"config/hatch/#output-levels","title":"Output levels","text":"

      The levels of output are as follows. Note that the verbosity indicates the minimum level at which the output is displayed.

      Level Default Verbosity Description debug bold 1 - 3 Messages that are not useful for most user experiences error bold red -2 Messages indicating some unrecoverable error info bold 0 Messages conveying basic information success bold cyan 0 Messages indicating some positive outcome waiting bold magenta 0 Messages shown before potentially time consuming operations warning bold yellow -1 Messages conveying important information

      See the documentation and color reference for guidance on valid values.

      "},{"location":"config/hatch/#spinner","title":"Spinner","text":"

      You can select the sequence used for waiting animations with the spinner option.

      config.toml
      [terminal.styles]\nspinner = \"...\"\n
      "},{"location":"config/metadata/","title":"Project metadata","text":"

      Project metadata is stored in a pyproject.toml file located at the root of a project's tree and is based entirely on the standard.

      "},{"location":"config/metadata/#name","title":"Name (required)","text":"

      The name of the project.

      pyproject.toml
      [project]\nname = \"your-app\"\n
      "},{"location":"config/metadata/#version","title":"Version (required)","text":"pyproject.toml DynamicStatic

      See the dedicated versioning section.

      [project]\n...\ndynamic = [\"version\"]\n\n[tool.hatch.version]\npath = \"...\"\n
      [project]\n...\nversion = \"0.0.1\"\n
      "},{"location":"config/metadata/#description","title":"Description","text":"

      A brief summary of the project.

      pyproject.toml
      [project]\n...\ndescription = '...'\n
      "},{"location":"config/metadata/#readme","title":"Readme","text":"

      The full description of the project.

      pyproject.toml SimpleComplex

      The file extension must be .md, .rst, or .txt.

      [project]\n...\nreadme = \"README.md\"\n

      The content-type field must be set to text/markdown, text/x-rst, or text/plain.

      FileText

      A charset field may also be set to instruct which encoding to use for reading the file, defaulting to utf-8.

      [project]\n...\nreadme = {\"file\" = \"README.md\", \"content-type\" = \"text/markdown\"}\n

      The content-type field must be set to text/markdown or text/x-rst.

      [project]\n...\nreadme = {\"text\" = \"...\", \"content-type\" = \"text/markdown\"}\n

      Note

      If this is defined as a file, then it will always be included in source distributions for consistent builds.

      "},{"location":"config/metadata/#python-support","title":"Python support","text":"

      The Python version requirements of the project.

      pyproject.toml
      [project]\n...\nrequires-python = \">=3.8\"\n
      "},{"location":"config/metadata/#license","title":"License","text":"

      For more information, see PEP 639.

      pyproject.toml SPDX expressionFiles
      [project]\n...\nlicense = \"Apache-2.0 OR MIT\"\n
      PathsGlobs
      [project]\n...\nlicense-files = { paths = [\"LICENSE.txt\"] }\n
      [project]\n...\nlicense-files = { globs = [\"LICENSES/*\"] }\n
      "},{"location":"config/metadata/#ownership","title":"Ownership","text":"

      The people or organizations considered to be the authors or maintainers of the project. The exact meaning is open to interpretation; it may list the original or primary authors, current maintainers, or owners of the package. If the values are the same, prefer only the use of the authors field.

      pyproject.toml
      [project]\n...\nauthors = [\n  { name = \"...\", email = \"...\" },\n]\nmaintainers = [\n  { name = \"...\", email = \"...\" },\n]\n
      "},{"location":"config/metadata/#keywords","title":"Keywords","text":"

      The keywords used to assist in the discovery of the project.

      pyproject.toml
      [project]\n...\nkeywords = [\n  \"...\",\n]\n
      "},{"location":"config/metadata/#classifiers","title":"Classifiers","text":"

      The trove classifiers that apply to the project.

      pyproject.toml
      [project]\n...\nclassifiers = [\n  \"...\",\n]\n
      "},{"location":"config/metadata/#urls","title":"URLs","text":"

      A table of URLs where the key is the URL label and the value is the URL itself.

      pyproject.toml
      [project.urls]\nDocumentation = \"...\"\n\"Source code\" = \"...\"\n
      "},{"location":"config/metadata/#dependencies","title":"Dependencies","text":"

      See the dependency specification page for more information.

      Entries support context formatting and disallow direct references by default.

      "},{"location":"config/metadata/#required","title":"Required","text":"pyproject.toml
      [project]\n...\ndependencies = [\n  \"...\",\n]\n
      "},{"location":"config/metadata/#optional","title":"Optional","text":"pyproject.toml
      [project.optional-dependencies]\noption1 = [\n  \"...\",\n]\noption2 = [\n  \"...\",\n]\n
      "},{"location":"config/metadata/#entry-points","title":"Entry points","text":"

      Entry points are a mechanism for the project to advertise components it provides to be discovered and used by other code.

      "},{"location":"config/metadata/#cli","title":"CLI","text":"

      After installing projects that define CLI scripts, each key will be available along your PATH as a command that will call its associated object.

      pyproject.toml
      [project.scripts]\ncli-name = \"pkg.subpkg:func\"\n

      Using the above example, running cli-name would essentially execute the following Python script:

      import sys\n\nfrom pkg.subpkg import func\n\nsys.exit(func())\n
      "},{"location":"config/metadata/#gui","title":"GUI","text":"

      GUI scripts are exactly the same as CLI scripts except on Windows, where they are handled specially so that they can be started without a console.

      pyproject.toml
      [project.gui-scripts]\ngui-name = \"pkg.subpkg:func\"\n
      "},{"location":"config/metadata/#plugins","title":"Plugins","text":"pyproject.toml
      [project.entry-points.plugin-namespace]\nplugin-name1 = \"pkg.subpkg1\"\nplugin-name2 = \"pkg.subpkg2:func\"\n
      "},{"location":"config/metadata/#dynamic","title":"Dynamic","text":"

      If any metadata fields are set dynamically, like the version may be, then they must be listed here.

      pyproject.toml
      [project]\n...\ndynamic = [\n  \"...\",\n]\n
      "},{"location":"config/metadata/#metadata-options","title":"Metadata options","text":""},{"location":"config/metadata/#allowing-direct-references","title":"Allowing direct references","text":"

      By default, dependencies are not allowed to define direct references. To disable this check, set allow-direct-references to true:

      pyproject.toml hatch.toml
      [tool.hatch.metadata]\nallow-direct-references = true\n
      [metadata]\nallow-direct-references = true\n
      "},{"location":"config/metadata/#allowing-ambiguous-features","title":"Allowing ambiguous features","text":"

      By default, names of optional dependencies are normalized to prevent ambiguity. To disable this normalization, set allow-ambiguous-features to true:

      pyproject.toml hatch.toml
      [tool.hatch.metadata]\nallow-ambiguous-features = true\n
      [metadata]\nallow-ambiguous-features = true\n

      Deprecated

      This option temporarily exists to provide better interoperability with tools that do not yet support PEP 685 and will be removed in the first minor release after Jan 1, 2024.

      "},{"location":"config/project-templates/","title":"Project templates","text":"

      You can control how new projects are created by the new command using Hatch's config file.

      "},{"location":"config/project-templates/#author","title":"Author","text":"config.toml
      [template]\nname = \"...\"\nemail = \"...\"\n
      "},{"location":"config/project-templates/#licenses","title":"Licenses","text":"config.toml
      [template.licenses]\nheaders = true\ndefault = [\n  \"MIT\",\n]\n

      The list of licenses should be composed of SPDX identifiers. If multiple licenses are specified, then they will be placed in a LICENSES directory.

      "},{"location":"config/project-templates/#options","title":"Options","text":""},{"location":"config/project-templates/#tests","title":"Tests","text":"

      This adds a tests directory with environments for testing and linting.

      config.toml
      [template.plugins.default]\ntests = true\n
      "},{"location":"config/project-templates/#ci","title":"CI","text":"

      This adds a GitHub Actions workflow that runs tests on all platforms using modern versions of Python.

      config.toml
      [template.plugins.default]\nci = false\n
      "},{"location":"config/project-templates/#src-layout","title":"src layout","text":"

      See this blog post.

      config.toml
      [template.plugins.default]\nsrc-layout = true\n
      "},{"location":"config/project-templates/#feature-flags","title":"Feature flags","text":""},{"location":"config/project-templates/#command-line-interface","title":"Command line interface","text":"

      The --cli flag adds a CLI backed by Click that can also be invoked with python -m <PKG_NAME>.

      "},{"location":"config/static-analysis/","title":"Static analysis configuration","text":"

      Static analysis performed by the fmt command is backed entirely by Ruff.

      Hatch provides default settings that user configuration can extend.

      "},{"location":"config/static-analysis/#extending-config","title":"Extending config","text":"

      When defining your configuration, be sure to use options that are prefixed by extend- such as extend-select, for example:

      pyproject.toml ruff.toml
      [tool.ruff.format]\npreview = true\nquote-style = \"single\"\n\n[tool.ruff.lint]\npreview = true\nextend-select = [\"C901\"]\n\n[tool.ruff.lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[tool.ruff.lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n
      [format]\npreview = true\nquote-style = \"single\"\n\n[lint]\npreview = true\nextend-select = [\"C901\"]\n\n[lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n

      Note

      When not persisting config, there is no need to explicitly extend the defaults as Hatch automatically handles that.

      "},{"location":"config/static-analysis/#persistent-config","title":"Persistent config","text":"

      If you want to store the default configuration in the project, set an explicit path like so:

      pyproject.toml hatch.toml
      [tool.hatch.envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n
      [envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n

      Then instruct Ruff to consider your configuration as an extension of the default file:

      pyproject.toml ruff.toml
      [tool.ruff]\nextend = \"ruff_defaults.toml\"\n
      extend = \"ruff_defaults.toml\"\n

      Anytime you wish to update the defaults (such as when upgrading Hatch), you must run the fmt command once with the --sync flag e.g.:

      hatch fmt --check --sync\n

      Tip

      This is the recommended approach since it allows other tools like IDEs to use the default configuration.

      "},{"location":"config/static-analysis/#versioning","title":"Versioning","text":"

      You can pin the particular version of Ruff by explicitly defining the environment dependencies:

      pyproject.toml hatch.toml
      [tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
      [envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
      "},{"location":"config/static-analysis/#default-settings","title":"Default settings","text":""},{"location":"config/static-analysis/#non-rule-settings","title":"Non-rule settings","text":"
      • Line length set to 120
      • Docstring formatting enabled with line length set to 80
      • Only absolute imports are allowed, except for tests
      • The normalized project name is a known first party import
      "},{"location":"config/static-analysis/#per-file-ignored-rules","title":"Per-file ignored rules","text":"
      • **/scripts/*: INP001, T201
      • **/tests/**/*: PLC1901, PLR2004, PLR6301, S, TID252
      "},{"location":"config/static-analysis/#selected-rules","title":"Selected rules","text":"

      The following rules are based on version 0.1.8 of Ruff. Rules with a P are only selected when preview mode is enabled.

      • A001, A002, A003
      • ARG001, ARG002, ARG003, ARG004, ARG005
      • ASYNC100, ASYNC101, ASYNC102
      • B002, B003, B004, B005, B006, B007, B008, B009, B010, B011, B012, B013, B014, B015, B016, B017, B018, B019, B020, B021, B022, B023, B024, B025, B026, B028, B029, B030, B031, B032, B033, B034, B904, B905
      • BLE001
      • C400, C401, C402, C403, C404, C405, C406, C408, C409, C410, C411, C413, C414, C415, C416, C417, C418, C419
      • COM818
      • DTZ001, DTZ002, DTZ003, DTZ004, DTZ005, DTZ006, DTZ007, DTZ011, DTZ012
      • E101, E112P, E113P, E115P, E116P, E201P, E202P, E203P, E211P, E221P, E222P, E223P, E224P, E225P, E226P, E227P, E228P, E231P, E241P, E242P, E251P, E252P, E261P, E262P, E265P, E266P, E271P, E272P, E273P, E274P, E275P, E401, E402, E501, E701, E702, E703, E711, E712, E713, E714, E721, E722, E731, E741, E742, E743, E902, E999
      • EM101, EM102, EM103
      • EXE001, EXE002, EXE003, EXE004, EXE005
      • F401, F402, F403, F404, F405, F406, F407, F501, F502, F503, F504, F505, F506, F507, F508, F509, F521, F522, F523, F524, F525, F541, F601, F602, F621, F622, F631, F632, F633, F634, F701, F702, F704, F706, F707, F722, F811, F821, F822, F823, F841, F842, F901
      • FA100, FA102
      • FBT001, FBT002
      • FLY002
      • FURB105P, FURB113P, FURB131P, FURB132P, FURB136P, FURB145P, FURB148P, FURB152P, FURB163P, FURB168P, FURB169P, FURB171P, FURB177P, FURB181P
      • G001, G002, G003, G004, G010, G101, G201, G202
      • I001, I002
      • ICN001, ICN002, ICN003
      • INP001
      • INT001, INT002, INT003
      • ISC003
      • LOG001P, LOG002P, LOG007P, LOG009P
      • N801, N802, N803, N804, N805, N806, N807, N811, N812, N813, N814, N815, N816, N817, N818, N999
      • PERF101, PERF102, PERF401, PERF402, PERF403P
      • PGH001, PGH002, PGH005
      • PIE790, PIE794, PIE796, PIE800, PIE804, PIE807, PIE808, PIE810
      • PLC0105, PLC0131, PLC0132, PLC0205, PLC0208, PLC0414, PLC0415P, PLC1901P, PLC2401P, PLC2403P, PLC3002
      • PLE0100, PLE0101, PLE0116, PLE0117, PLE0118, PLE0241, PLE0302, PLE0307, PLE0604, PLE0605, PLE0704P, PLE1132P, PLE1142, PLE1205, PLE1206, PLE1300, PLE1307, PLE1310, PLE1507, PLE1700, PLE2502, PLE2510, PLE2512, PLE2513, PLE2514, PLE2515
      • PLR0124, PLR0133, PLR0202P, PLR0203P, PLR0206, PLR0402, PLR1701, PLR1704P, PLR1706P, PLR1711, PLR1714, PLR1722, PLR1733P, PLR1736P, PLR2004, PLR5501, PLR6201P, PLR6301P
      • PLW0108P, PLW0120, PLW0127, PLW0129, PLW0131, PLW0406, PLW0602, PLW0603, PLW0604P, PLW0711, PLW1501P, PLW1508, PLW1509, PLW1510, PLW1514P, PLW1641P, PLW2101P, PLW2901, PLW3201P, PLW3301
      • PT001, PT002, PT003, PT006, PT007, PT008, PT009, PT010, PT011, PT012, PT013, PT014, PT015, PT016, PT017, PT018, PT019, PT020, PT021, PT022, PT023, PT024, PT025, PT026, PT027
      • PYI001, PYI002, PYI003, PYI004, PYI005, PYI006, PYI007, PYI008, PYI009, PYI010, PYI011, PYI012, PYI013, PYI014, PYI015, PYI016, PYI017, PYI018, PYI019, PYI020, PYI021, PYI024, PYI025, PYI026, PYI029, PYI030, PYI032, PYI033, PYI034, PYI035, PYI036, PYI041, PYI042, PYI043, PYI044, PYI045, PYI046, PYI047, PYI048, PYI049, PYI050, PYI051, PYI052, PYI053, PYI054, PYI055, PYI056
      • RET503, RET504, RET505, RET506, RET507, RET508
      • RSE102
      • RUF001, RUF002, RUF003, RUF005, RUF006, RUF007, RUF008, RUF009, RUF010, RUF011, RUF012, RUF013, RUF015, RUF016, RUF017P, RUF018P, RUF019P, RUF100, RUF200
      • S101, S102, S103, S104, S105, S106, S107, S108, S110, S112, S113, S201P, S202P, S301, S302, S303, S304, S305, S306, S307, S308, S310, S311, S312, S313, S314, S315, S316, S317, S318, S319, S320, S321, S323, S324, S501, S505P, S506, S507P, S508, S509, S601, S602, S604, S605, S606, S607, S608, S609, S611P, S612, S701, S702P
      • SIM101, SIM102, SIM103, SIM105, SIM107, SIM108, SIM109, SIM110, SIM112, SIM114, SIM115, SIM116, SIM117, SIM118, SIM201, SIM202, SIM208, SIM210, SIM211, SIM212, SIM220, SIM221, SIM222, SIM223, SIM300, SIM910
      • SLF001
      • SLOT000, SLOT001, SLOT002
      • T100, T201, T203
      • TCH001, TCH002, TCH003, TCH004, TCH005
      • TD004, TD005, TD006, TD007
      • TID251, TID252, TID253
      • TRIO100P, TRIO105P, TRIO109P, TRIO110P, TRIO115P
      • TRY002, TRY003, TRY004, TRY200, TRY201, TRY300, TRY301, TRY302, TRY400, TRY401
      • UP001, UP003, UP004, UP005, UP006, UP007, UP008, UP009, UP010, UP011, UP012, UP013, UP014, UP015, UP017, UP018, UP019, UP020, UP021, UP022, UP023, UP024, UP025, UP026, UP027, UP028, UP029, UP030, UP031, UP032, UP033, UP034, UP035, UP036, UP037, UP038, UP039, UP040, UP041P
      • W291, W292, W293, W505, W605
      • YTT101, YTT102, YTT103, YTT201, YTT202, YTT203, YTT204, YTT301, YTT302, YTT303
      "},{"location":"config/environment/advanced/","title":"Advanced environment configuration","text":""},{"location":"config/environment/advanced/#context-formatting","title":"Context formatting","text":"

      All environments support the following extra context formatting fields:

      Field Description env_name The name of the environment env_type The type of environment matrix Its modifier selects the value of that matrix variable. If the environment is not part of a matrix or was not generated with the variable, you must specify a default value as an additional modifier e.g. {matrix:version:v1.0.0}. verbosity The integer verbosity value of Hatch. A flag modifier is supported that will render the value as a CLI flag e.g. -2 becomes -qq, 1 becomes -v, and 0 becomes an empty string. An additional flag integer modifier may be used to adjust the verbosity level. For example, if you wanted to make a command quiet by default, you could use {verbosity:flag:-1} within the command. args For executed commands only, any extra command line arguments with an optional default modifier if none were provided"},{"location":"config/environment/advanced/#matrix","title":"Matrix","text":"

      Environments can define a series of matrices with the matrix option:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
      [envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n

      Doing so will result in the product of each variable combination being its own environment.

      "},{"location":"config/environment/advanced/#naming","title":"Naming","text":"

      The name of the generated environments will be the variable values of each combination separated by hyphens, altogether prefixed by <ENV_NAME>.. For example, the following configuration:

      pyproject.toml hatch.toml
      [[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
      [[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n

      would indicate the following unique environments:

      test.42-foo\ntest.42-bar\n

      The exceptions to this format are described below.

      "},{"location":"config/environment/advanced/#python-variables","title":"Python variables","text":"

      If the variables py or python are specified, then they will rank first in the product result and will be prefixed by py if the value is not. For example, the following configuration:

      pyproject.toml hatch.toml
      [[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n
      [[envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n

      would generate the following environments:

      test.py3.9-42\ntest.pypy3-42\n

      Note

      The value of this variable sets the Python version.

      "},{"location":"config/environment/advanced/#name-formatting","title":"Name formatting","text":"

      You can set the matrix-name-format option to modify how each variable part is formatted which recognizes the placeholders {variable} and {value}. For example, the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
      [envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n

      would produce the following environments:

      test.version_42-feature_foo\ntest.version_42-feature_bar\n

      By default this option is set to {value}.

      "},{"location":"config/environment/advanced/#default-environment","title":"Default environment","text":"

      If the default environment defines matrices, then the generated names will not be prefixed by the environment name. This can be useful for projects that only need a single series of matrices without any standalone environments.

      "},{"location":"config/environment/advanced/#selection","title":"Selection","text":"

      Rather than selecting a single generated environment, you can select the root environment to target all of them. For example, if you have the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[tool.hatch.envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n
      [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n

      you could then run your tests consecutively in all 4 environments with:

      hatch run test:cov\n
      "},{"location":"config/environment/advanced/#option-overrides","title":"Option overrides","text":"

      You can modify options based on the conditions of different sources like matrix variables with the overrides table, using dotted key syntax for each declaration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n
      [envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n

      The type of the selected option determines the types of values.

      "},{"location":"config/environment/advanced/#platform-overrides","title":"Platform overrides","text":"

      Options can be modified based on the current platform using the platform source.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nplatform.windows.scripts = [\n  'run=pytest -m \"not io_uring\"',\n]\n
      [envs.test.overrides]\nplatform.windows.scripts = [\n  'run=pytest -m \"not io_uring\"',\n]\n

      The following platforms are supported:

      • linux
      • windows
      • macos
      "},{"location":"config/environment/advanced/#environment-variable-overrides","title":"Environment variable overrides","text":"

      Environment variables can modify options using the env source.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
      [envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
      "},{"location":"config/environment/advanced/#matrix-variable-overrides","title":"Matrix variable overrides","text":"

      The matrix variables used to generate each environment can be used to modify options within using the matrix source.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n  { value = \"oauth\", if = [\"oauth2\"] },\n  { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
      [envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n  { value = \"oauth\", if = [\"oauth2\"] },\n  { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
      "},{"location":"config/environment/advanced/#name-overrides","title":"Name overrides","text":"

      When a matrix is defined, the name source can be used for regular expression matching on the generated name, minus the prefix for non-default environments.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
      [envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
      "},{"location":"config/environment/advanced/#types","title":"Types","text":"
      • Literal types like strings for the Python version or booleans for skipping installation can be set using the value itself, an inline table, or an array. For example:

        pyproject.toml hatch.toml
        [tool.hatch.envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n  { value = false, if = [\"...\"] },\n  true,\n]\n
        [envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n  { value = false, if = [\"...\"] },\n  true,\n]\n

        For arrays, the first allowed value will be used.

      • Array types like dependencies or commands can be appended to using an array of strings or inline tables. For example:

        pyproject.toml hatch.toml
        [tool.hatch.envs.test.overrides]\nmatrix.foo.dependencies = [\n  \"httpx\",\n  { value = \"cryptography\" },\n]\n
        [envs.test.overrides]\nmatrix.foo.dependencies = [\n  \"httpx\",\n  { value = \"cryptography\" },\n]\n
      • Mapping types like environment variables or scripts can have keys set using a string, or an array of strings or inline tables. For example:

        pyproject.toml hatch.toml
        [tool.hatch.envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n  \"KEY1=VALUE1\",\n  { key = \"KEY2\", value = \"VALUE2\" },\n]\n
        [envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n  \"KEY1=VALUE1\",\n  { key = \"KEY2\", value = \"VALUE2\" },\n]\n

        If the value is missing (no = for strings, no value key for inline tables), then the value will be set to the value of the source condition.

      "},{"location":"config/environment/advanced/#overwriting","title":"Overwriting","text":"

      Rather than supplementing the values within mapping types or array types, you can overwrite the option as a whole by prefixing the name with set-:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n
      [envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n

      When overwriting entire options or keys within mappings, override sources are applied in the following order:

      1. platform
      2. environment variables
      3. matrix variables
      4. names
      "},{"location":"config/environment/advanced/#conditions","title":"Conditions","text":"

      You may specify certain extra keys for any inline table that will determine whether or not to apply that entry. These modifiers may be combined with others and any negative evaluation will immediately cause the entry to be skipped.

      "},{"location":"config/environment/advanced/#allowed-values","title":"Allowed values","text":"

      The if key represents the allowed values for that condition. If the value of the condition is not listed, then that entry will not be applied:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      [envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      "},{"location":"config/environment/advanced/#specific-platforms","title":"Specific platforms","text":"

      The platform key represents the desired platforms. If the current platform is not listed, then that entry will not be applied:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      [envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      "},{"location":"config/environment/advanced/#required-environment-variables","title":"Required environment variables","text":"

      The env key represents the required environment variables. If any of the listed environment variables are not set or the defined value does not match, then that entry will not be applied:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      [envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      "},{"location":"config/environment/overview/","title":"Environment configuration","text":"

      All environments are defined as sections within the tool.hatch.envs table.

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\n
      [envs.<ENV_NAME>]\n

      The storage location for environments is completely configurable.

      Unless an environment is explicitly selected on the command line, the default environment will be used. The type of this environment defaults to virtual.

      Info

      Environments prefixed by hatch- are used for special purposes e.g. static analysis.

      "},{"location":"config/environment/overview/#inheritance","title":"Inheritance","text":"

      All environments inherit from the environment defined by its template option, which defaults to default.

      So for the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[tool.hatch.envs.bar]\ntemplate = \"foo\"\nskip-install = false\n
      [envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[envs.bar]\ntemplate = \"foo\"\nskip-install = false\n

      the environment bar will be of type baz with skip-install set to false.

      Note

      Environments do not inherit matrices.

      "},{"location":"config/environment/overview/#self-referential-environments","title":"Self-referential environments","text":"

      You can disable inheritance by setting template to the environment's own name:

      pyproject.toml hatch.toml
      [tool.hatch.envs.foo]\ntemplate = \"foo\"\n
      [envs.foo]\ntemplate = \"foo\"\n
      "},{"location":"config/environment/overview/#detached-environments","title":"Detached environments","text":"

      A common use case is standalone environments that do not require inheritance nor the installation of the project, such as for linting or sometimes building documentation. Enabling the detached option will make the environment self-referential and will skip project installation:

      pyproject.toml hatch.toml
      [tool.hatch.envs.lint]\ndetached = true\n
      [envs.lint]\ndetached = true\n
      "},{"location":"config/environment/overview/#dependencies","title":"Dependencies","text":"

      You can install dependencies in addition to the ones defined by your project's metadata. Entries support context formatting.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n
      [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n

      If you define environments with dependencies that only slightly differ from their inherited environments, you can use the extra-dependencies option to avoid redeclaring the dependencies option:

      pyproject.toml hatch.toml
      [tool.hatch.envs.default]\ndependencies = [\n  \"foo\",\n  \"bar\",\n]\n\n[tool.hatch.envs.experimental]\nextra-dependencies = [\n  \"baz\",\n]\n
      [envs.default]\ndependencies = [\n  \"foo\",\n  \"bar\",\n]\n\n[envs.experimental]\nextra-dependencies = [\n  \"baz\",\n]\n

      Tip

      Hatch uses pip to install dependencies so any configuration it supports Hatch does as well. For example, if you wanted to only use a private repository you could set the PIP_INDEX_URL environment variable.

      "},{"location":"config/environment/overview/#installation","title":"Installation","text":""},{"location":"config/environment/overview/#features","title":"Features (extras)","text":"

      If your project defines optional dependencies, you can select which groups to install using the features option:

      pyproject.toml hatch.toml
      [tool.hatch.envs.nightly]\nfeatures = [\n  \"server\",\n  \"grpc\",\n]\n
      [envs.nightly]\nfeatures = [\n  \"server\",\n  \"grpc\",\n]\n

      Note

      Features/optional dependencies are also known as extras in other tools.

      "},{"location":"config/environment/overview/#dev-mode","title":"Dev mode","text":"

      By default, environments will always reflect the current state of your project on disk. Set dev-mode to false to disable this behavior:

      pyproject.toml hatch.toml
      [tool.hatch.envs.static]\ndev-mode = false\n
      [envs.static]\ndev-mode = false\n
      "},{"location":"config/environment/overview/#skip-install","title":"Skip install","text":"

      By default, environments will install your project during creation. To ignore this step, set skip-install to true:

      pyproject.toml hatch.toml
      [tool.hatch.envs.lint]\nskip-install = true\n
      [envs.lint]\nskip-install = true\n
      "},{"location":"config/environment/overview/#environment-variables","title":"Environment variables","text":""},{"location":"config/environment/overview/#defined","title":"Defined","text":"

      You can define environment variables with the env-vars option:

      pyproject.toml hatch.toml
      [tool.hatch.envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[tool.hatch.envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
      [envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n

      Values support context formatting.

      "},{"location":"config/environment/overview/#filters","title":"Filters","text":"

      By default, environments will have access to all environment variables. You can filter with wildcard patterns using the env-include/env-exclude options:

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nenv-include = [\n  \"FOO*\",\n]\nenv-exclude = [\n  \"BAR\",\n]\n
      [envs.<ENV_NAME>]\nenv-include = [\n  \"FOO*\",\n]\nenv-exclude = [\n  \"BAR\",\n]\n

      Exclusion patterns take precedence but will never affect defined environment variables.

      "},{"location":"config/environment/overview/#scripts","title":"Scripts","text":"

      You can define named scripts that may be executed or referenced at the beginning of other scripts. Context formatting is supported.

      For example, in the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n[tool.hatch.envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n
      [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n[envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n

      the run script would be expanded to:

      pytest --cov-config=pyproject.toml --cov=pkg --cov=tests --no-cov\n

      Scripts can also be defined as an array of strings.

      pyproject.toml hatch.toml
      [tool.hatch.envs.style]\ndetached = true\ndependencies = [\n  \"flake8\",\n  \"black\",\n  \"isort\",\n]\n[tool.hatch.envs.style.scripts]\ncheck = [\n  \"flake8 .\",\n  \"black --check --diff .\",\n  \"isort --check-only --diff .\",\n]\nfmt = [\n  \"isort .\",\n  \"black .\",\n  \"check\",\n]\n
      [envs.style]\ndetached = true\ndependencies = [\n  \"flake8\",\n  \"black\",\n  \"isort\",\n]\n[envs.style.scripts]\ncheck = [\n  \"flake8 .\",\n  \"black --check --diff .\",\n  \"isort --check-only --diff .\",\n]\nfmt = [\n  \"isort .\",\n  \"black .\",\n  \"check\",\n]\n

      Similar to make, you can ignore the exit code of commands that start with - (a hyphen). For example, the script error defined by the following configuration would halt after the second command with 3 as the exit code:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.scripts]\nerror = [\n  \"- exit 1\",\n  \"exit 3\",\n  \"exit 0\",\n]\n
      [envs.test.scripts]\nerror = [\n  \"- exit 1\",\n  \"exit 3\",\n  \"exit 0\",\n]\n

      Tip

      Individual scripts inherit from parent environments just like options.

      "},{"location":"config/environment/overview/#commands","title":"Commands","text":"

      All commands are able to use any defined scripts. Also like scripts, context formatting is supported and the exit code of commands that start with a hyphen will be ignored.

      "},{"location":"config/environment/overview/#pre-install","title":"Pre-install","text":"

      You can run commands immediately before environments install your project.

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\npre-install-commands = [\n  \"...\",\n]\n
      [envs.<ENV_NAME>]\npre-install-commands = [\n  \"...\",\n]\n
      "},{"location":"config/environment/overview/#post-install","title":"Post-install","text":"

      You can run commands immediately after environments install your project.

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\npost-install-commands = [\n  \"...\",\n]\n
      [envs.<ENV_NAME>]\npost-install-commands = [\n  \"...\",\n]\n
      "},{"location":"config/environment/overview/#python-version","title":"Python version","text":"

      The python option specifies which version of Python to use, or an absolute path to a Python interpreter:

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\npython = \"3.10\"\n
      [envs.<ENV_NAME>]\npython = \"3.10\"\n

      All environment types should respect this option.

      "},{"location":"config/environment/overview/#supported-platforms","title":"Supported platforms","text":"

      The platforms option indicates the operating systems with which the environment is compatible:

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n
      [envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n

      The following platforms are supported:

      • linux
      • windows
      • macos

      If unspecified, the environment is assumed to be compatible with all platforms.

      "},{"location":"config/environment/overview/#description","title":"Description","text":"

      The description option is purely informational and is displayed in the output of the env show command:

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
      [envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
      "},{"location":"config/environment/overview/#type","title":"Type","text":"

      An environment's type determines which environment plugin will be used for management. The only built-in environment type is virtual, which uses virtual Python environments.

      "},{"location":"history/hatch/","title":"Hatch history","text":"

      All notable changes to Hatch will be documented in this file.

      The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

      "},{"location":"history/hatch/#unreleased","title":"Unreleased","text":""},{"location":"history/hatch/#hatch-v1.9.4","title":"1.9.4 - 2024-03-12","text":"

      Fixed:

      • Limit the maximum version of Hatchling in anticipation of backward incompatible changes
      "},{"location":"history/hatch/#hatch-v1.9.3","title":"1.9.3 - 2024-01-25","text":"

      Fixed:

      • Fix loading of local plugins to account for newly released versions of a dependency
      "},{"location":"history/hatch/#hatch-v1.9.2","title":"1.9.2 - 2024-01-21","text":"

      Fixed:

      • Fix the default token variable name for publishing to PyPI
      "},{"location":"history/hatch/#hatch-v1.9.1","title":"1.9.1 - 2023-12-25","text":"

      Fixed:

      • Ensure that the dependency_hash method of the environment interface is called after sync_dependencies for cases where the hash is only known at that point, such as for dependency lockers
      • Only acknowledge the HATCH_PYTHON_VARIANT_* environment variables for Python resolution for supported platforms and architectures
      • Fix Python resolution when there are metadata hooks with unsatisfied dependencies
      "},{"location":"history/hatch/#hatch-v1.9.0","title":"1.9.0 - 2023-12-19","text":"

      Changed:

      • Environments prefixed by hatch- are now considered internal and used for special purposes such as configuration for static analysis

      Added:

      • Enable docstring formatting by default for static analysis
      • Allow for overriding config of internal environments
      • Concretely state the expected API contract for the environment interface methods find and check_compatibility
      • Upgrade Ruff to 0.1.8
      • Bump the minimum supported version of Hatchling to 1.21.0

      Fixed:

      • Ignore a project's Python requirement for environments where the project is not installed
      • When not persisting config for static analysis, properly manage internal settings when Ruff's top level table already exists
      • Ignore compatibility checks when environments have already been created, significantly improving performance of environment usage
      • Properly allow overriding of the path option for the virtual environment type
      • Fix nushell activation on non-Windows systems
      "},{"location":"history/hatch/#hatch-v1.8.1","title":"1.8.1 - 2023-12-14","text":"

      Fixed:

      • Fix regression in calling subprocesses with updated PATH
      • Fix automatic installation of environment plugins when running as a standalone binary
      • Change default location of Python installations
      "},{"location":"history/hatch/#hatch-v1.8.0","title":"1.8.0 - 2023-12-11","text":"

      Changed:

      • Drop support for Python 3.7
      • The get_build_process method of the environment interface has been removed; plugins should use the new run_builder method instead
      • Remove pyperclip dependency and the --copy flag of the config find command
      • When running the build command all output from builders is now displayed as-is in real time without the stripping of ANSI codes
      • Version information (for Hatch itself) is now derived from Git

      Added:

      • Support Python 3.12
      • Add installers and standalone binaries
      • Add the ability to manage Python installations
      • Add fmt command
      • The virtual environment type can now automatically download requested versions of Python that are not installed
      • Add dependency_hash method to the environment interface
      • The state of installed dependencies for environments is saved as metadata so if dependency definitions have not changed then no checking is performed, which can be computationally expensive
      • The build command now supports backends other than Hatchling
      • Allow the use of features for environments when skip-install is enabled
      • The default is now __token__ when prompting for a username for the publish command
      • Add a new run_builder method to the environment interface
      • Bump the minimum supported version of Hatchling to 1.19.0
      • Bump the minimum supported version of click to 8.0.6

      Fixed:

      • Fix nushell activation
      • Better handling of flat storage directory hierarchies for the virtual environment type
      • Display useful information when running the version command outside of a project rather than erroring
      • Fix the project metadata command by only capturing stdout from the backend
      • Properly support Google Artifact Registry
      • Fix parsing dependencies for environments when warnings are emitted
      "},{"location":"history/hatch/#hatch-v1.7.0","title":"1.7.0 - 2023-04-03","text":"

      Changed:

      • The src-layout project template option is now enabled by default
      • Non-critical output now goes to stderr

      Added:

      • Add tool.hatch.env.requires configuration to automatically install dependencies for environment and environment collector plugins
      • Add custom environment collector
      • Improve syncing of dependencies provided through Git direct references
      • Add isolated_data_directory attribute to the environment interface
      • Increase the timeout for and add retries to the index publisher
      • Expand home and environment variables in configured cache and data directories
      • Improve readability of exceptions
      • Update project templates
      • Bump the minimum supported version of Hatchling to 1.14.0

      Fixed:

      • Fix displaying the version with the version command when the version is static and build dependencies are unmet
      • Fix build environments for the virtual environment type when storing within a relative path
      • Work around System Integrity Protection on macOS when running commands
      • Allow setuptools metadata migration for projects without setup.py if setup.cfg is present
      • Handle additional edge cases for setuptools metadata migration
      • Support boolean values for the config set command
      "},{"location":"history/hatch/#hatch-v1.6.3","title":"1.6.3 - 2022-10-24","text":"

      Fixed:

      • Fix version command when the version is dynamic and build dependencies are unmet
      "},{"location":"history/hatch/#hatch-v1.6.2","title":"1.6.2 - 2022-10-20","text":"

      Fixed:

      • Fix getting dynamic metadata from hooks for environments when dependencies are not dynamic
      "},{"location":"history/hatch/#hatch-v1.6.1","title":"1.6.1 - 2022-10-16","text":"

      Fixed:

      • Computing the path to the user's home directory now gracefully falls back to ~ when it cannot be determined
      "},{"location":"history/hatch/#hatch-v1.6.0","title":"1.6.0 - 2022-10-08","text":"

      Changed:

      • The run_shell_command environment interface method now accepts arbitrary subprocess.Popen keyword arguments. This is not strictly breaking, but will be utilized in upcoming features.
      • The internal directory structure for storing virtual environments is now more nested. This is not breaking, but any local environments will be created anew.

      Added:

      • Add project command group to view details about the project like PEP 621 metadata
      • Better support for auto-detection of environments by tools like Visual Studio Code now that the storage directory of virtual environments will be flat if Hatch's configured virtual environment directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
      • Build environments for the virtual environment type are now cached for improved performance
      • Add build_environment_exists method to the environment interface for implementations that cache the build environment
      • Add path option to the virtual environment type
      • Add --initialize-auth flag to the index publisher to allow for the saving of authentication information before publishing
      • Support Bash on Windows for the shell command
      • The setuptools migration script no longer modifies the formatting of existing pyproject.toml configuration
      • Bump the minimum supported version of Hatchling to 1.11.0

      Fixed:

      • Environments now respect dynamically defined project dependencies
      • The dep hash and all dep show commands now respect dynamically defined project dependencies
      • The env show, dep hash, and all dep show commands now honor context formatting
      • Fix matrix variable inclusion filtering of the run and env run commands when there are multiple possible variables
      • Build environment compatibility is now checked before use
      • Decreasing verbosity now has no affect on output that should always be displayed
      • Handle more edge cases in the setuptools migration script
      • Environments now respect user defined environment variables for context formatting
      • Update the scripts in the generated test environment template for new projects to reflect the documentation
      • Allow extra-dependencies in environment overrides
      • Depend on packaging explicitly rather than relying on it being a transitive dependency of Hatchling
      "},{"location":"history/hatch/#hatch-v1.5.0","title":"1.5.0 - 2022-08-28","text":"

      Added:

      • The index publisher now recognizes repository-specific options
      • Add the --ignore-compat flag to the env run command
      • Setting the HATCH_PYTHON environment variable to self will now force the use of the Python executable Hatch is running on for virtual environment creation

      Fixed:

      • Fix the --force-continue flag of the env run command
      • Handle more edge cases in the setuptools migration script
      "},{"location":"history/hatch/#hatch-v1.4.2","title":"1.4.2 - 2022-08-16","text":"

      Fixed:

      • Fix check for updating static versions with the version command when metadata hooks are in use
      "},{"location":"history/hatch/#hatch-v1.4.1","title":"1.4.1 - 2022-08-13","text":"

      Fixed:

      • Fix non-detached inheritance disabling for environments
      "},{"location":"history/hatch/#hatch-v1.4.0","title":"1.4.0 - 2022-08-06","text":"

      Added:

      • The default Python for virtual environments now checks PATH before using the one Hatch is running on
      • Values for environment env-vars now support context formatting
      • Add name override for environments to allow for regular expression matching
      • The index publisher now better supports non-PyPI indices
      • Add certificate options to the index publisher
      • Display waiting text when checking dependencies and removing environments
      • Display help text the first time the shell command is executed
      • Update project templates with Python 3.11 and the latest versions of various GitHub Actions
      • Add support for Almquist (ash) shells
      • Add hyperlink as a dependency for better handling of package index URLs
      • Bump the minimum supported version of virtualenv to 20.16.2
      • Bump the minimum supported version of tomlkit to 0.11.1

      Fixed:

      • Acknowledge extra-dependencies for the env show command
      • Fix locating executables within virtual environments on Debian
      • Fix managing the terminal size inside the shell command
      • Fix default code coverage file omission for the src-layout project template option
      "},{"location":"history/hatch/#hatch-v1.3.1","title":"1.3.1 - 2022-07-11","text":"

      Fixed:

      • Support -h/--help flag for the run command
      "},{"location":"history/hatch/#hatch-v1.3.0","title":"1.3.0 - 2022-07-10","text":"

      Changed:

      • Rename the default publishing plugin from pypi to the more generic index

      Added:

      • Support the absence of pyproject.toml files, as is the case for apps and non-Python projects
      • Hide scripts that start with an underscore for the env show command by default
      • Ignoring the exit codes of commands by prefixing with hyphens now works with entire named scripts
      • Add a way to require confirmation for publishing
      • Add --force-continue flag to the env run command
      • Make tracebacks colorful and less verbose
      • When shell configuration has not been defined, attempt to use the current shell based on parent processes before resorting to the defaults
      • The shell name pwsh is now an alias for powershell
      • Remove atomicwrites dependency
      • Relax constraint on userpath dependency
      • Bump the minimum supported version of Hatchling to 1.4.1

      Fixed:

      • Keep environments in sync with the dependencies of the selected features
      • Use utf-8 for all files generated for new projects
      • Escape special characters Git may return in the user name when writing generated files for new projects
      • Normalize the package name to lowercase in setuptools migration script
      • Fix parsing of source distributions during publishing
      "},{"location":"history/hatch/#hatch-v1.2.1","title":"1.2.1 - 2022-05-30","text":"

      Fixed:

      • Fix handling of top level data_files in setuptools migration script
      "},{"location":"history/hatch/#hatch-v1.2.0","title":"1.2.0 - 2022-05-22","text":"

      Changed:

      • The enter_shell environment plugin method now accepts an additional args parameter

      Added:

      • Allow context string formatting for environment dependencies
      • Add environment context string formatting fields env_name, env_type, matrix, verbosity, and args
      • Support overriding the default arguments used to spawn shells on non-Windows systems
      • Bump the minimum supported version of Hatchling to 1.3.0

      Fixed:

      • Improve setuptools migration script
      "},{"location":"history/hatch/#hatch-v1.1.2","title":"1.1.2 - 2022-05-20","text":"

      Fixed:

      • Bump the minimum supported version of Hatchling to 1.2.0
      • Update project metadata to reflect support for Python 3.11
      "},{"location":"history/hatch/#hatch-v1.1.1","title":"1.1.1 - 2022-05-12","text":"

      Fixed:

      • Fix setuptools migration script for non-Windows systems
      "},{"location":"history/hatch/#hatch-v1.1.0","title":"1.1.0 - 2022-05-12","text":"

      Changed:

      • In order to simplify the implementation of command execution for environment plugins, the run_shell_commands method has been replaced by the singular run_shell_command. A new command_context method has been added to more easily satisfy complex use cases.
      • The finalize_command environment plugin method has been removed in favor of the newly introduced context formatting functionality.

      Added:

      • Add context formatting functionality i.e. the ability to insert values into configuration like environment variables and command line arguments
      • Any verbosity for command execution will now always display headers, even for single environments
      • Every executed command is now displayed when running multiple commands or when verbosity is enabled
      • Similar to make, ignore the exit code of executed commands that start with - (a hyphen)
      • Add ability for the --init flag of the new command to automatically migrate setuptools configuration
      • Update project metadata to reflect the adoption by PyPA and production stability
      "},{"location":"history/hatch/#hatch-v1.0.0","title":"1.0.0 - 2022-04-28","text":"

      This is the first stable release of Hatch v1, a complete rewrite. Enjoy!

      "},{"location":"history/hatchling/","title":"Hatchling history","text":"

      All notable changes to Hatchling will be documented in this file.

      The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

      "},{"location":"history/hatchling/#unreleased","title":"Unreleased","text":""},{"location":"history/hatchling/#hatchling-v1.21.0","title":"1.21.0 - 2023-12-18","text":"

      Added:

      • Add parent context modifier for path fields
      "},{"location":"history/hatchling/#hatchling-v1.20.0","title":"1.20.0 - 2023-12-13","text":"

      Added:

      • Add bypass-selection option to the wheel build target to allow for empty (metadata-only) wheels

      Fixed:

      • Fix regression in 1.19.1 that allowed exclude to count toward inclusion selection, thus bypassing the default inclusion selection heuristics
      • Fix writing optional dependency core metadata in situations where there are multiple environment markers
      "},{"location":"history/hatchling/#hatchling-v1.19.1","title":"1.19.1 - 2023-12-12","text":"

      Fixed:

      • Add better error message when the wheel build target cannot determine what to ship
      • Consider forced inclusion patterns and build-time artifacts as file selection since some build hooks generate the entire wheel contents without user configuration
      "},{"location":"history/hatchling/#hatchling-v1.19.0","title":"1.19.0 - 2023-12-11","text":"

      Changed:

      • An error will now be raised if a force-included path does not exist
      • An error will now be raised for the wheel build target if no file selection options are defined

      Added:

      • Officially support Python 3.12
      • Allow using an empty string for the sources option to add a prefix to distribution paths

      Fixed:

      • Properly handle non-zero version epoch for the standard version scheme
      • Fix the wheel build target for case insensitive file systems when the project metadata name does not match the directory name on disk
      • The app build target no longer has suppressed output
      • Prevent duplicate paths when projects require the sources option while build hooks overwrite included paths
      • Properly escape spaces for URI context formatting
      "},{"location":"history/hatchling/#hatchling-v1.18.0","title":"1.18.0 - 2023-06-12","text":"

      Changed:

      • Drop support for Python 3.7

      Added:

      • Update the list of directories that are always excluded for builds
      "},{"location":"history/hatchling/#hatchling-v1.17.1","title":"1.17.1 - 2023-06-03","text":"

      Fixed:

      • Fix dev mode when the project has symlinks and file inclusion is defined with the packages or only-include options
      • Change the name of generated PTH files for dev mode so they come first lexicographically and therefore load first
      "},{"location":"history/hatchling/#hatchling-v1.17.0","title":"1.17.0 - 2023-05-12","text":"

      Added:

      • The app build target now embeds the project version in the name of binaries
      "},{"location":"history/hatchling/#hatchling-v1.16.1","title":"1.16.1 - 2023-05-11","text":"

      Fixed:

      • Fix determining the built executable path for the app build target option when using a local copy of PyApp when there is an explicit target triple set
      "},{"location":"history/hatchling/#hatchling-v1.16.0","title":"1.16.0 - 2023-05-11","text":"

      Added:

      • Add app build target option to build using a local copy of the PyApp repository
      "},{"location":"history/hatchling/#hatchling-v1.15.0","title":"1.15.0 - 2023-05-09","text":"

      Added:

      • Add app build target
      "},{"location":"history/hatchling/#hatchling-v1.14.1","title":"1.14.1 - 2023-04-23","text":"

      Fixed:

      • Fix internal archive root naming for the sdist target when strict-naming is disabled to match the file name in order to support the expectation of some frontends
      "},{"location":"history/hatchling/#hatchling-v1.14.0","title":"1.14.0 - 2023-04-02","text":"

      Added:

      • Add trove-classifiers as a dependency

      Fixed:

      • Properly normalize metadata descriptions that contain line breaks
      "},{"location":"history/hatchling/#hatchling-v1.13.0","title":"1.13.0 - 2023-02-09","text":"

      Added:

      • Update the set of known trove classifiers to version 2023.2.8
      "},{"location":"history/hatchling/#hatchling-v1.12.2","title":"1.12.2 - 2023-01-05","text":"

      Fixed:

      • Add macos-max-compat option to the wheel target that is enabled by default to support the latest version 22.0 of the packaging library
      "},{"location":"history/hatchling/#hatchling-v1.12.1","title":"1.12.1 - 2022-12-31","text":"

      Fixed:

      • Fix minor regression in the PEP 517/660 function signatures that was discovered by Fedora
      "},{"location":"history/hatchling/#hatchling-v1.12.0","title":"1.12.0 - 2022-12-30","text":"

      Added:

      • Improve readability of exceptions
      • Add extra_metadata build data to the wheel target
      • Retroactively support License-Expression core metadata starting at version 2.1
      • Add more type hints
      • Update the set of known trove classifiers to version 2022.12.22
      • Update SPDX license information to version 3.19
      • Store Hatchling's metadata in pyproject.toml

      Fixed:

      • Acknowledge the ARCHFLAGS environment variable on macOS for the wheel target when build hooks set the infer_tag build data to true
      • Fix dependency checking when encountering broken distributions
      • Fix the support-legacy option for the sdist target when using a src-layout project structure
      • Remove unnecessary encoding declaration in the default template for the version build hook
      "},{"location":"history/hatchling/#hatchling-v1.11.1","title":"1.11.1 - 2022-10-19","text":"

      Fixed:

      • Fix default file selection behavior of the wheel target when there is a single top-level module
      "},{"location":"history/hatchling/#hatchling-v1.11.0","title":"1.11.0 - 2022-10-08","text":"

      Added:

      • Add env version source to retrieve the version from an environment variable
      • Add validate-bump option to the standard version scheme

      Fixed:

      • Use proper CSV formatting for the RECORD metadata file of the wheel target to avoid warnings during installation by pip if, for example, file names contain commas
      • Fix installations with pip for build hooks that modify runtime dependencies
      • Decreasing verbosity now has no affect on output that should always be displayed
      "},{"location":"history/hatchling/#hatchling-v1.10.0","title":"1.10.0 - 2022-09-18","text":"

      Added:

      • Add the following to the list of directories that cannot be traversed: __pypackages__, .hg, .hatch, .tox, .nox
      • Add deprecated option to allow ambiguous features

      Fixed:

      • Improve tracking of dynamic metadata
      • Fix core metadata for entries in project.optional-dependencies that use direct references
      "},{"location":"history/hatchling/#hatchling-v1.9.0","title":"1.9.0 - 2022-09-09","text":"

      Changed:

      • File pattern matching now more closely resembles Git's behavior

      Added:

      • Implement a minimal version of prepare_metadata_for_build_wheel and prepare_metadata_for_build_editable for non-frontend tools that only need to inspect a project's metadata
      • Add metadata command to view PEP 621 project metadata
      • Improve error messages for SPDX license errors
      • Retroactively support License-File for core metadata starting at version 2.1
      • Bump the minimum supported version of pathspec to 0.10.1

      Fixed:

      • Allow the valid non-SPDX license values LicenseRef-Public-Domain and LicenseRef-Proprietary
      • Show the help text of the CLI when no subcommand is selected
      "},{"location":"history/hatchling/#hatchling-v1.8.1","title":"1.8.1 - 2022-08-25","text":"

      Fixed:

      • Fix default file inclusion for wheel build targets when both the project name and package directory name are not normalized
      "},{"location":"history/hatchling/#hatchling-v1.8.0","title":"1.8.0 - 2022-08-16","text":"

      Added:

      • Add get_known_classifiers method to metadata hooks

      Fixed:

      • Fix check for updating static versions with the version command when metadata hooks are in use
      "},{"location":"history/hatchling/#hatchling-v1.7.1","title":"1.7.1 - 2022-08-13","text":"

      Fixed:

      • Fix the value of the relative_path attribute of included files, that some build plugins may use, when selecting explicit paths
      "},{"location":"history/hatchling/#hatchling-v1.7.0","title":"1.7.0 - 2022-08-12","text":"

      Added:

      • Add require-runtime-features option for builders and build hooks
      • Check for unknown trove classifiers
      • Update SPDX license information to version 3.18

      Fixed:

      • Add better error message for wheel target dev mode installations that define path rewrites with the sources option
      • Note the allow-direct-references option in the relevant error messages
      "},{"location":"history/hatchling/#hatchling-v1.6.0","title":"1.6.0 - 2022-07-23","text":"

      Changed:

      • When no build targets are specified on the command line, now default to sdist and wheel targets rather than what happens to be defined in config
      • The code version source now only supports files with known extensions
      • Global build hooks now run before target-specific build hooks to better match expected behavior

      Added:

      • The code version source now supports loading extension modules
      • Add search-paths option for the code version source

      Fixed:

      • Fix removing sources using an empty string value in the mapping
      • The strict-naming option now also applies to the metadata directory of wheel targets
      "},{"location":"history/hatchling/#hatchling-v1.5.0","title":"1.5.0 - 2022-07-11","text":"

      Added:

      • Support the final draft of PEP 639
      • Add strict-naming option for sdist and wheel targets

      Fixed:

      • Project names are now stored in sdist and wheel target core metadata exactly as defined in pyproject.toml without normalization to allow control of how PyPI displays them
      "},{"location":"history/hatchling/#hatchling-v1.4.1","title":"1.4.1 - 2022-07-04","text":"

      Fixed:

      • Fix forced inclusion of important files like licenses for sdist targets when using the explicit selection options
      • Don't sort project URL metadata so that the rendered order on PyPI can be controlled
      "},{"location":"history/hatchling/#hatchling-v1.4.0","title":"1.4.0 - 2022-07-03","text":"

      Changed:

      • The packages option uses the new only-include option to provide targeted inclusion, since that is desired most of the time. You can retain the old behavior by using the include and sources options together.

      Added:

      • Support PEP 561 type hinting
      • Add version build hook
      • Add only-include option
      • The editable version of wheel targets now respects the force-include option by default
      • The force-include option now supports path rewriting with the sources option
      • The wheel target shared-data and extra-metadata options now respect file selection options
      • The wheel target now auto-detects single module layouts
      • Improve performance by never entering directories that are guaranteed to be undesirable like __pycache__ rather than excluding individual files within
      • Update SPDX license information to version 3.17

      Fixed:

      • Don't write empty entry points file for wheel targets if there are no entry points defined
      • Allow metadata hooks to set the version in all cases
      • Prevent duplicate file entries from inclusion when using the force-include option
      "},{"location":"history/hatchling/#hatchling-v1.3.1","title":"1.3.1 - 2022-05-30","text":"

      Fixed:

      • Better populate global variables for the code version source
      "},{"location":"history/hatchling/#hatchling-v1.3.0","title":"1.3.0 - 2022-05-22","text":"

      Removed:

      • Remove unused global args context string formatting field

      Added:

      • Improve error messages for the env context string formatting field

      Fixed:

      • Fix uri context string formatting modifier on Windows
      "},{"location":"history/hatchling/#hatchling-v1.2.0","title":"1.2.0 - 2022-05-20","text":"

      Added:

      • Allow context formatting for project.dependencies and project.optional-dependencies
      "},{"location":"history/hatchling/#hatchling-v1.1.0","title":"1.1.0 - 2022-05-19","text":"

      Added:

      • Add uri and real context string formatting modifiers for file system paths
      "},{"location":"history/hatchling/#hatchling-v1.0.0","title":"1.0.0 - 2022-05-17","text":"

      Changed:

      • Drop support for Python 2

      Added:

      • Improve error messaging for invalid versions
      • Update project metadata to reflect support for Python 3.11
      "},{"location":"history/hatchling/#hatchling-v0.25.1","title":"0.25.1 - 2022-06-14","text":"

      Fixed:

      • Fix support for Windows on Python 2 by removing its support for symlinks
      "},{"location":"history/hatchling/#hatchling-v0.25.0","title":"0.25.0 - 2022-05-15","text":"

      Added:

      • Add skip-excluded-dirs build option
      • Allow build data to add additional project dependencies for wheel and sdist build targets
      • Add force_include_editable build data for the wheel build target
      • Add build_hooks build data
      • Add support for Mercurial's .hgignore files when using glob syntax
      • Update project metadata to reflect the adoption by PyPA

      Fixed:

      • Properly use underscores for the name of force_include build data
      • No longer greedily skip excluded directories by default
      "},{"location":"history/hatchling/#hatchling-v0.24.0","title":"0.24.0 - 2022-04-28","text":"

      This is the initial public release of the Hatchling build system. Support for Python 2 will be dropped in version 1.

      "},{"location":"how-to/environment/package-indices/","title":"Package indices","text":"

      Most Hatch environment types, like the default virtual, simply use pip to install dependencies. Therefore, you can use the standard environment variables that influence pip's behavior to choose where to search for packages.

      Here's an example of setting up the default environment to look at 2 private indices (using context formatting for authentication) before finally falling back to PyPI:

      pyproject.toml hatch.toml
      [tool.hatch.envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
      [envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
      "},{"location":"how-to/plugins/testing-builds/","title":"Testing builds","text":"

      For testing Hatchling plugins, you'll usually want to generate a project to execute builds as a real user would. For example, as a minimal pytest fixture:

      from pathlib import Path\n\nimport pytest\n\n\n@pytest.fixture\ndef new_project(tmp_path):\n    project_dir = tmp_path / 'my-app'\n    project_dir.mkdir()\n\n    project_file = project_dir / 'pyproject.toml'\n    project_file.write_text(\n        f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {Path.cwd().as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n        encoding='utf-8',\n    )\n    ...\n

      The issue with this is that after the first test session, the project will be forever cached by pip based on the file path. Therefore, subsequent tests runs will never use updated code.

      To invalidate the cache, copy your code to a new path for every test session:

      import shutil\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\n\nimport pytest\n\n\n@pytest.fixture(scope='session')\ndef plugin_dir():\n    with TemporaryDirectory() as d:\n        directory = Path(d, 'plugin')\n        shutil.copytree(\n            Path.cwd(), directory, ignore=shutil.ignore_patterns('.git')\n        )\n\n        yield directory.resolve()\n\n\n@pytest.fixture\ndef new_project(tmp_path, plugin_dir):\n    project_dir = tmp_path / 'my-app'\n    project_dir.mkdir()\n\n    project_file = project_dir / 'pyproject.toml'\n    project_file.write_text(\n        f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {plugin_dir.as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n        encoding='utf-8',\n    )\n    ...\n

      Note

      This example chooses to ignore copying .git for performance reasons. You may want to ignore more patterns, or copy only specific paths like this plugin does.

      "},{"location":"meta/authors/","title":"Authors","text":""},{"location":"meta/authors/#maintainers","title":"Maintainers","text":"
      • Ofek Lev
      "},{"location":"meta/authors/#contributors","title":"Contributors","text":"
      • Amjith Ramanujam
      • Arnaud Crowther
      • Chaojie
      • Chris Warrick
      • Lum\u00edr 'Frenzy' Balhar
      • Ofek Lev
      • Olga Matoula
      • Philip Blair
      • Robert Rosca
      "},{"location":"meta/faq/","title":"FAQ","text":""},{"location":"meta/faq/#interoperability","title":"Interoperability","text":"

      Q: What is the risk of lock-in?

      A: Not much! Other than the plugin system, everything uses Python's established standards by default. Project metadata is based entirely on the standard, the build system is compatible with PEP 517/PEP 660, versioning uses the scheme specified by PEP 440, dependencies are defined with PEP 508 strings, and environments use virtualenv.

      Q: Must one use all features?

      A: No, all features are optional! You can use just the build system, publish wheels and source distributions that were built by other tools, only use the environment management, etc.

      "},{"location":"meta/faq/#libraries-vs-applications","title":"Libraries vs applications","text":"

      Q: Are workflows for both libraries and applications supported?

      A: Yes, mostly! Applications can utilize environment management just like libraries, and plugins can be used to build projects in arbitrary formats or publish artifacts to arbitrary destinations.

      The only caveat is that currently there is no support for re-creating an environment given a set of dependencies in a reproducible manner. Although a standard lock file format may be far off since [PEP 665][] was rejected, resolving capabilities are coming to pip. When that is stabilized, Hatch will add locking functionality and dedicated documentation for managing applications.

      "},{"location":"meta/faq/#tool-migration","title":"Tool migration","text":"

      Q: How to migrate to Hatch?

      "},{"location":"meta/faq/#build-system","title":"Build system","text":"SetuptoolsHatch setup.py MANIFEST.in
      import os\nfrom io import open\n\nfrom setuptools import find_packages, setup\n\nabout = {}\nwith open(os.path.join('src', 'foo', '__about__.py'), 'r', 'utf-8') as f:\n    exec(f.read(), about)\n\nwith open('README.md', 'r', 'utf-8') as f:\n    readme = f.read()\n\nsetup(\n    # Metadata\n    name='foo',\n    version=about['__version__'],\n    description='...',\n    long_description=readme,\n    long_description_content_type='text/markdown',\n    author='...',\n    author_email='...',\n    project_urls={\n        'Documentation': '...',\n        'Source': '...',\n    },\n    classifiers=[\n        '...',\n    ],\n    keywords=[\n        '...',\n    ],\n    python_requires='>=3.8',\n    install_requires=[\n        '...',\n    ],\n    extras_require={\n        'feature': ['...'],\n    },\n\n    # Packaging\n    packages=find_packages(where='src'),\n    package_dir={'': 'src'},\n    package_data={\n        'foo': ['py.typed'],\n    },\n    zip_safe=False,\n    entry_points={\n        'console_scripts': [\n            'foo = foo.cli:main',\n        ],\n    },\n)\n
      graft tests\n\nglobal-exclude *.py[cod] __pycache__\n
      pyproject.toml
      [build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"foo\"\ndescription = \"...\"\nreadme = \"README.md\"\nauthors = [\n  { name = \"...\", email = \"...\" },\n]\nclassifiers = [\n  \"...\",\n]\nkeywords = [\n  \"...\",\n]\nrequires-python = \">=3.8\"\ndependencies = [\n  \"...\",\n]\ndynamic = [\"version\"]\n\n[project.urls]\nDocumentation = \"...\"\nSource = \"...\"\n\n[project.optional-dependencies]\nfeature = [\"...\"]\n\n[project.scripts]\nfoo = \"foo.cli:main\"\n\n[tool.hatch.version]\npath = \"src/foo/__about__.py\"\n\n[tool.hatch.build.targets.sdist]\ninclude = [\n  \"/src\",\n  \"/tests\",\n]\n
      "},{"location":"meta/faq/#environments","title":"Environments","text":"ToxHatch

      Invocation:

      tox\n
      tox.ini
      [tox]\nenvlist =\n    py{27,38}-{42,3.14}\n    py{38,39}-{9000}-{foo,bar}\n\n[testenv]\nusedevelop = true\ndeps =\n    coverage[toml]\n    pytest\n    pytest-cov\n    foo: cryptography\ncommands =\n    pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests {posargs}\nsetenv =\n    3.14: PRODUCT_VERSION=3.14\n    42: PRODUCT_VERSION=42\n    9000: PRODUCT_VERSION=9000\n    {foo,bar}: EXPERIMENTAL=true\n

      Invocation:

      hatch run test\n
      pyproject.toml hatch.toml
      [tool.hatch.envs.default]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[tool.hatch.envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[tool.hatch.envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.features.env-vars = \"EXPERIMENTAL=true\"\nmatrix.features.dependencies = [\n  { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
      [envs.default]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.features.env-vars = \"EXPERIMENTAL=true\"\nmatrix.features.dependencies = [\n  { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[envs.default.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
      "},{"location":"meta/faq/#fast-cli","title":"Fast CLI?","text":"

      The claim about being faster than other tools is based on timings that are always checked in CI.

      Hatch achieves this by using lazy imports, lazily performing computation manually and with functools.cached_property, using hacks like not not ... instead of bool(...), etc.

      "},{"location":"plugins/about/","title":"Plugins","text":"

      Hatch utilizes pluggy for its plugin functionality.

      "},{"location":"plugins/about/#overview","title":"Overview","text":"

      All plugins provide registration hooks that return one or more classes that inherit from a particular type interface.

      Each registration hook must be decorated by Hatch's hook marker. For example, if you wanted to create a new kind of environment you could do:

      hooks.py
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialEnvironment\n\n\n@hookimpl\ndef hatch_register_environment():\n    return SpecialEnvironment\n

      The hooks can return a single class or a list of classes.

      Every class must define an attribute called PLUGIN_NAME that users will select when they wish to use the plugin. So in the example above, the class might be defined like:

      plugin.py
      ...\nclass SpecialEnvironment(...):\n    PLUGIN_NAME = 'special'\n    ...\n
      "},{"location":"plugins/about/#project-configuration","title":"Project configuration","text":""},{"location":"plugins/about/#naming","title":"Naming","text":"

      It is recommended that plugin project names are prefixed with hatch-. For example, if you wanted to make a plugin that provides some functionality for a product named foo you might do:

      pyproject.toml
      [project]\nname = \"hatch-foo\"\n
      "},{"location":"plugins/about/#discovery","title":"Discovery","text":"

      You'll need to define your project as a Python plugin for Hatch:

      pyproject.toml
      [project.entry-points.hatch]\nfoo = \"pkg.hooks\"\n

      The name of the plugin should be the project name (excluding any hatch- prefix) and the path should represent the module that contains the registration hooks.

      "},{"location":"plugins/about/#classifier","title":"Classifier","text":"

      Add Framework :: Hatch to your project's classifiers to make it easy to search for Hatch plugins:

      pyproject.toml
      [project]\nclassifiers = [\n  ...\n  \"Framework :: Hatch\",\n  ...\n]\n
      "},{"location":"plugins/about/#types","title":"Types","text":""},{"location":"plugins/about/#hatchling","title":"Hatchling","text":"

      These are all involved in building projects and therefore any defined dependencies are automatically installed in each build environment.

      • Builder
      • Build hook
      • Metadata hook
      • Version source
      • Version scheme
      "},{"location":"plugins/about/#hatch","title":"Hatch","text":"

      These must be installed in the same environment as Hatch itself.

      • Environment
      • Environment collector
      • Publisher
      "},{"location":"plugins/utilities/","title":"Plugin utilities","text":""},{"location":"plugins/utilities/#hatchling.builders.utils.get_reproducible_timestamp","title":"hatchling.builders.utils.get_reproducible_timestamp() -> int","text":"

      Returns an int derived from the SOURCE_DATE_EPOCH environment variable; see https://reproducible-builds.org/specs/source-date-epoch/.

      The default value will always be: 1580601600

      Source code in backend/src/hatchling/builders/utils.py
      def get_reproducible_timestamp() -> int:\n    \"\"\"\n    Returns an `int` derived from the `SOURCE_DATE_EPOCH` environment variable; see\n    https://reproducible-builds.org/specs/source-date-epoch/.\n\n    The default value will always be: `1580601600`\n    \"\"\"\n    return int(os.environ.get('SOURCE_DATE_EPOCH', '1580601600'))\n
      "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig","title":"BuilderConfig","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.directory","title":"directory: str property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.ignore_vcs","title":"ignore_vcs: bool property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.reproducible","title":"reproducible: bool property","text":"

      Whether or not the target should be built in a reproducible manner, defaulting to true.

      "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dev_mode_dirs","title":"dev_mode_dirs: list[str] property","text":"

      Directories which must be added to Python's search path in dev mode.

      "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.versions","title":"versions: list[str] property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dependencies","title":"dependencies: list[str] property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_include","title":"default_include() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_exclude","title":"default_exclude() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_packages","title":"default_packages() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_only_include","title":"default_only_include() -> list","text":""},{"location":"plugins/utilities/#hatchling.bridge.app.Application","title":"Application","text":"

      The way output is displayed can be configured by users.

      Important

      Never import this directly; Hatch judiciously decides if a type of plugin requires the capabilities herein and will grant access via an attribute.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.verbosity","title":"verbosity: int property","text":"

      The verbosity level of the application, with 0 as the default.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.abort","title":"abort(message: str = '', code: int = 1, **kwargs: Any) -> None","text":"

      Terminate the program with the given return code.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_debug","title":"display_debug(message: str = '', level: int = 1, **kwargs: Any) -> None","text":"

      Meant to be used for messages that are not useful for most user experiences. The level option must be between 1 and 3 (inclusive).

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_error","title":"display_error(message: str = '', **kwargs: Any) -> None","text":"

      Meant to be used for messages indicating some unrecoverable error.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_info","title":"display_info(message: str = '', **kwargs: Any) -> None","text":"

      Meant to be used for messages conveying basic information.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_success","title":"display_success(message: str = '', **kwargs: Any) -> None","text":"

      Meant to be used for messages indicating some positive outcome.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_waiting","title":"display_waiting(message: str = '', **kwargs: Any) -> None","text":"

      Meant to be used for messages shown before potentially time consuming operations.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_warning","title":"display_warning(message: str = '', **kwargs: Any) -> None","text":"

      Meant to be used for messages conveying important information.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform","title":"Platform","text":""},{"location":"plugins/utilities/#hatch.utils.platform.Platform.default_shell","title":"default_shell: str property","text":"

      Returns the default shell of the system.

      On Windows systems first try the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.modules","title":"modules: LazilyLoadedModules property","text":"

      Accessor for lazily loading modules that either take multiple milliseconds to import (like shutil and subprocess) or are not used on all platforms (like shlex).

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.home","title":"home: Path property","text":"

      The user's home directory as a path-like object.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.name","title":"name: str property","text":"

      One of the following:

      • linux
      • windows
      • macos
      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.windows","title":"windows: bool property","text":"

      Indicates whether Hatch is running on Windows.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.macos","title":"macos: bool property","text":"

      Indicates whether Hatch is running on macOS.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.linux","title":"linux: bool property","text":"

      Indicates whether Hatch is running on neither Windows nor macOS.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.format_for_subprocess","title":"format_for_subprocess(command: str | list[str], *, shell: bool) -> str | list[str]","text":"

      Format the given command in a cross-platform manner for immediate consumption by subprocess utilities.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.run_command","title":"run_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess","text":"

      Equivalent to the standard library's subprocess.run, with the command first being properly formatted.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command","title":"check_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess","text":"

      Equivalent to run_command, but non-zero exit codes will gracefully end program execution.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command_output","title":"check_command_output(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> str","text":"

      Equivalent to the output from the process returned by capture_process, but non-zero exit codes will gracefully end program execution.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.capture_process","title":"capture_process(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> Popen","text":"

      Equivalent to the standard library's subprocess.Popen, with all output captured by stdout and the command first being properly formatted.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.exit_with_command","title":"exit_with_command(command: list[str]) -> None","text":"

      Run the given command and exit with its exit code. On non-Windows systems, this uses the standard library's os.execvp.

      "},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter","title":"EnvironmentContextFormatter","text":""},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter.formatters","title":"formatters()","text":"

      This returns a mapping of supported field names to their respective formatting functions. Each function accepts 2 arguments:

      • the value that was passed to the format call, defaulting to None
      • the modifier data, defaulting to an empty string
      "},{"location":"plugins/build-hook/custom/","title":"Custom build hook","text":"

      This is a custom class in a given Python file that inherits from the BuildHookInterface.

      "},{"location":"plugins/build-hook/custom/#configuration","title":"Configuration","text":"

      The build hook plugin name is custom.

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.custom]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.custom]\n
      [build.hooks.custom]\n[build.targets.<TARGET_NAME>.hooks.custom]\n
      "},{"location":"plugins/build-hook/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/build-hook/custom/#example","title":"Example","text":"hatch_build.py
      from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass CustomBuildHook(BuildHookInterface):\n    ...\n

      If multiple subclasses are found, you must define a function named get_build_hook that returns the desired build hook.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      "},{"location":"plugins/build-hook/reference/","title":"Build hook plugins","text":"

      A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.

      "},{"location":"plugins/build-hook/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-autorun - used to inject code into an installation that will automatically run before the first import
      • hatch-build-scripts - run arbitrary shell commands that create artifacts
      • hatch-jupyter-builder - used for packages in the Project Jupyter ecosystem
      • hatch-mypyc - compiles code with Mypyc
      • hatch-odoo - package Odoo add-ons into the appropriate namespace
      "},{"location":"plugins/build-hook/reference/#overview","title":"Overview","text":"

      Build hooks run for every selected version of build targets.

      The initialization stage occurs immediately before each build and the finalization stage occurs immediately after. Each stage has the opportunity to view or modify build data.

      "},{"location":"plugins/build-hook/reference/#build-data","title":"Build data","text":"

      Build data is a simple mapping whose contents can influence the behavior of builds. Which fields exist and are recognized depends on each build target.

      The following fields are always present and recognized by the build system itself:

      Field Type Description artifacts list[str] This is a list of extra artifact patterns and should generally only be appended to force_include dict[str, str] This is a mapping of extra forced inclusion paths, with this mapping taking precedence in case of conflicts build_hooks tuple[str, ...] This is an immutable sequence of the names of the configured build hooks and matches the order in which they run

      Attention

      While user-facing TOML options are hyphenated, build data fields should be named with underscores to allow plugins to use them as valid Python identifiers.

      "},{"location":"plugins/build-hook/reference/#notes","title":"Notes","text":"

      In some cases it may be necessary to use force_include rather than artifacts. For example, say that you want to install a lib.so directly at the root of site-packages and a project defines a package src/foo. If you create src/lib.so, there will never be a match because the directory traversal starts at src/foo rather than src. In that case you must do either:

      build_data['force_include']['src/lib.so'] = 'src/lib.so'\n

      or

      build_data['force_include']['/absolute/path/to/src/lib.so'] = 'src/lib.so'\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface","title":"BuildHookInterface","text":"

      Example usage:

      plugin.py hooks.py
      from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass SpecialBuildHook(BuildHookInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuildHook\n\n\n@hookimpl\ndef hatch_register_build_hook():\n    return SpecialBuildHook\n
      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      class BuildHookInterface(Generic[BuilderConfigBound]):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\n    class SpecialBuildHook(BuildHookInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialBuildHook\n\n\n    @hookimpl\n    def hatch_register_build_hook():\n        return SpecialBuildHook\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root: str,\n        config: dict[str, Any],\n        build_config: BuilderConfigBound,\n        metadata: ProjectMetadata,\n        directory: str,\n        target_name: str,\n        app: Application | None = None,\n    ) -> None:\n        self.__root = root\n        self.__config = config\n        self.__build_config = build_config\n        self.__metadata = metadata\n        self.__directory = directory\n        self.__target_name = target_name\n        self.__app = app\n\n    @property\n    def app(self) -> Application:\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = cast(Application, Application().get_safe_application())\n\n        return self.__app\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict[str, Any]:\n        \"\"\"\n        The cumulative hook configuration.\n\n        ```toml config-example\n        [tool.hatch.build.hooks.<PLUGIN_NAME>]\n        [tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @property\n    def metadata(self) -> ProjectMetadata:\n        # Undocumented for now\n        return self.__metadata\n\n    @property\n    def build_config(self) -> BuilderConfigBound:\n        \"\"\"\n        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        return self.__build_config\n\n    @property\n    def directory(self) -> str:\n        \"\"\"\n        The build directory.\n        \"\"\"\n        return self.__directory\n\n    @property\n    def target_name(self) -> str:\n        \"\"\"\n        The plugin name of the build target.\n        \"\"\"\n        return self.__target_name\n\n    def clean(self, versions: list[str]) -> None:\n        \"\"\"\n        This occurs before the build process if the `-c`/`--clean` flag was passed to\n        the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n        the [`clean`](../../cli/reference.md#hatch-clean) command.\n        \"\"\"\n\n    def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n        \"\"\"\n        This occurs immediately before each build.\n\n        Any modifications to the build data will be seen by the build target.\n        \"\"\"\n\n    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n        \"\"\"\n        This occurs immediately after each build and will not run if the `--hooks-only` flag\n        was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n        The build data will reflect any modifications done by the target during the build.\n        \"\"\"\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.app","title":"app: Application property","text":"

      An instance of Application.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.root","title":"root: str property","text":"

      The root of the project tree.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.config","title":"config: dict[str, Any] property","text":"

      The cumulative hook configuration.

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.<PLUGIN_NAME>]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
      [build.hooks.<PLUGIN_NAME>]\n[build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.build_config","title":"build_config: BuilderConfigBound property","text":"

      An instance of BuilderConfig.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.target_name","title":"target_name: str property","text":"

      The plugin name of the build target.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.directory","title":"directory: str property","text":"

      The build directory.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.clean","title":"clean(versions: list[str]) -> None","text":"

      This occurs before the build process if the -c/--clean flag was passed to the build command, or when invoking the clean command.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def clean(self, versions: list[str]) -> None:\n    \"\"\"\n    This occurs before the build process if the `-c`/`--clean` flag was passed to\n    the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n    the [`clean`](../../cli/reference.md#hatch-clean) command.\n    \"\"\"\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.initialize","title":"initialize(version: str, build_data: dict[str, Any]) -> None","text":"

      This occurs immediately before each build.

      Any modifications to the build data will be seen by the build target.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n    \"\"\"\n    This occurs immediately before each build.\n\n    Any modifications to the build data will be seen by the build target.\n    \"\"\"\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.finalize","title":"finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None","text":"

      This occurs immediately after each build and will not run if the --hooks-only flag was passed to the build command.

      The build data will reflect any modifications done by the target during the build.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n    \"\"\"\n    This occurs immediately after each build and will not run if the `--hooks-only` flag\n    was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n    The build data will reflect any modifications done by the target during the build.\n    \"\"\"\n
      "},{"location":"plugins/build-hook/version/","title":"Version build hook","text":"

      This writes the project's version to a file.

      "},{"location":"plugins/build-hook/version/#configuration","title":"Configuration","text":"

      The build hook plugin name is version.

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.version]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.version]\n
      [build.hooks.version]\n[build.targets.<TARGET_NAME>.hooks.version]\n
      "},{"location":"plugins/build-hook/version/#options","title":"Options","text":"Option Description path (required) A relative path to the desired file template A string representing the entire contents of path that will be formatted with a version variable pattern Rather than updating the entire file, a regular expression may be used that has a named group called version that represents the version. If set to true, a pattern will be used that looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v."},{"location":"plugins/builder/app/","title":"Application builder","text":"

      This uses PyApp to build an application that is able to bootstrap itself at runtime.

      Note

      This requires an installation of Rust.

      "},{"location":"plugins/builder/app/#configuration","title":"Configuration","text":"

      The builder plugin name is app.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.app]\n
      [build.targets.app]\n
      "},{"location":"plugins/builder/app/#options","title":"Options","text":"Option Default Description scripts all defined An array of defined script names to limit what gets built python-version latest compatible Python minor version The Python version ID to use pyapp-version The version of PyApp to use"},{"location":"plugins/builder/app/#build-behavior","title":"Build behavior","text":"

      If any scripts are defined then each one will be built (limited by the scripts option). Otherwise, a single executable will be built based on the project name assuming there is an equivalently named module with a __main__.py file.

      Every executable will be built inside an app directory in the output directory.

      If the CARGO environment variable is set then that path will be used as the executable for performing builds.

      If the CARGO_BUILD_TARGET environment variable is set then its value will be appended to the file name stems.

      If the PYAPP_REPO environment variable is set then a local build will be performed inside that directory rather than installing from crates.io. Note that this is required if the CARGO environment variable refers to cross.

      "},{"location":"plugins/builder/custom/","title":"Custom builder","text":"

      This is a custom class in a given Python file that inherits from the BuilderInterface.

      "},{"location":"plugins/builder/custom/#configuration","title":"Configuration","text":"

      The builder plugin name is custom.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.custom]\n
      [build.targets.custom]\n
      "},{"location":"plugins/builder/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/builder/custom/#example","title":"Example","text":"hatch_build.py
      from hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass CustomBuilder(BuilderInterface):\n    ...\n

      If multiple subclasses are found, you must define a function named get_builder that returns the desired builder.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      "},{"location":"plugins/builder/reference/","title":"Builder plugins","text":"

      See the documentation for build configuration.

      "},{"location":"plugins/builder/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-aws - used for building AWS Lambda functions with SAM
      • hatch-zipped-directory - used for building ZIP archives for installation into various foreign package installation systems
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface","title":"BuilderInterface","text":"

      Example usage:

      plugin.py hooks.py
      from hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass SpecialBuilder(BuilderInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuilder\n\n\n@hookimpl\ndef hatch_register_builder():\n    return SpecialBuilder\n
      Source code in backend/src/hatchling/builders/plugin/interface.py
      class BuilderInterface(ABC, Generic[BuilderConfigBound, PluginManagerBound]):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.builders.plugin.interface import BuilderInterface\n\n\n    class SpecialBuilder(BuilderInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialBuilder\n\n\n    @hookimpl\n    def hatch_register_builder():\n        return SpecialBuilder\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root: str,\n        plugin_manager: PluginManagerBound | None = None,\n        config: dict[str, Any] | None = None,\n        metadata: ProjectMetadata | None = None,\n        app: Application | None = None,\n    ) -> None:\n        self.__root = root\n        self.__plugin_manager = cast(PluginManagerBound, plugin_manager)\n        self.__raw_config = config\n        self.__metadata = metadata\n        self.__app = app\n        self.__config = cast(BuilderConfigBound, None)\n        self.__project_config: dict[str, Any] | None = None\n        self.__hatch_config: dict[str, Any] | None = None\n        self.__build_config: dict[str, Any] | None = None\n        self.__build_targets: list[str] | None = None\n        self.__target_config: dict[str, Any] | None = None\n\n        # Metadata\n        self.__project_id: str | None = None\n\n    def build(\n        self,\n        *,\n        directory: str | None = None,\n        versions: list[str] | None = None,\n        hooks_only: bool | None = None,\n        clean: bool | None = None,\n        clean_hooks_after: bool | None = None,\n        clean_only: bool | None = False,\n    ) -> Generator[str, None, None]:\n        # Fail early for invalid project metadata\n        self.metadata.validate_fields()\n\n        if directory is None:\n            directory = (\n                self.config.normalize_build_directory(os.environ[BuildEnvVars.LOCATION])\n                if BuildEnvVars.LOCATION in os.environ\n                else self.config.directory\n            )\n\n        if not os.path.isdir(directory):\n            os.makedirs(directory)\n\n        version_api = self.get_version_api()\n\n        versions = versions or self.config.versions\n        if versions:\n            unknown_versions = set(versions) - set(version_api)\n            if unknown_versions:\n                message = (\n                    f'Unknown versions for target `{self.PLUGIN_NAME}`: {\", \".join(map(str, sorted(unknown_versions)))}'\n                )\n                raise ValueError(message)\n\n        if hooks_only is None:\n            hooks_only = env_var_enabled(BuildEnvVars.HOOKS_ONLY)\n\n        configured_build_hooks = self.get_build_hooks(directory)\n        build_hooks = list(configured_build_hooks.values())\n\n        if clean_only:\n            clean = True\n        elif clean is None:\n            clean = env_var_enabled(BuildEnvVars.CLEAN)\n        if clean:\n            if not hooks_only:\n                self.clean(directory, versions)\n\n            for build_hook in build_hooks:\n                build_hook.clean(versions)\n\n            if clean_only:\n                return\n\n        if clean_hooks_after is None:\n            clean_hooks_after = env_var_enabled(BuildEnvVars.CLEAN_HOOKS_AFTER)\n\n        for version in versions:\n            self.app.display_debug(f'Building `{self.PLUGIN_NAME}` version `{version}`')\n\n            build_data = self.get_default_build_data()\n            self.set_build_data_defaults(build_data)\n\n            # Allow inspection of configured build hooks and the order in which they run\n            build_data['build_hooks'] = tuple(configured_build_hooks)\n\n            # Execute all `initialize` build hooks\n            for build_hook in build_hooks:\n                build_hook.initialize(version, build_data)\n\n            if hooks_only:\n                self.app.display_debug(f'Only ran build hooks for `{self.PLUGIN_NAME}` version `{version}`')\n                continue\n\n            # Build the artifact\n            with self.config.set_build_data(build_data):\n                artifact = version_api[version](directory, **build_data)\n\n            # Execute all `finalize` build hooks\n            for build_hook in build_hooks:\n                build_hook.finalize(version, build_data, artifact)\n\n            if clean_hooks_after:\n                for build_hook in build_hooks:\n                    build_hook.clean([version])\n\n            yield artifact\n\n    def recurse_included_files(self) -> Iterable[IncludedFile]:\n        \"\"\"\n        Returns a consistently generated series of file objects for every file that should be distributed. Each file\n        object has three `str` attributes:\n\n        - `path` - the absolute path\n        - `relative_path` - the path relative to the project root; will be an empty string for external files\n        - `distribution_path` - the path to be distributed as\n        \"\"\"\n        yield from self.recurse_selected_project_files()\n        yield from self.recurse_forced_files(self.config.get_force_include())\n\n    def recurse_selected_project_files(self) -> Iterable[IncludedFile]:\n        if self.config.only_include:\n            yield from self.recurse_explicit_files(self.config.only_include)\n        else:\n            yield from self.recurse_project_files()\n\n    def recurse_project_files(self) -> Iterable[IncludedFile]:\n        for root, dirs, files in safe_walk(self.root):\n            relative_path = get_relative_path(root, self.root)\n\n            dirs[:] = sorted(d for d in dirs if not self.config.directory_is_excluded(d, relative_path))\n\n            files.sort()\n            is_package = '__init__.py' in files\n            for f in files:\n                relative_file_path = os.path.join(relative_path, f)\n                distribution_path = self.config.get_distribution_path(relative_file_path)\n                if self.config.path_is_reserved(distribution_path):\n                    continue\n\n                if self.config.include_path(relative_file_path, is_package=is_package):\n                    yield IncludedFile(\n                        os.path.join(root, f), relative_file_path, self.config.get_distribution_path(relative_file_path)\n                    )\n\n    def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n        for source, target_path in inclusion_map.items():\n            external = not source.startswith(self.root)\n            if os.path.isfile(source):\n                yield IncludedFile(\n                    source,\n                    '' if external else os.path.relpath(source, self.root),\n                    self.config.get_distribution_path(target_path),\n                )\n            elif os.path.isdir(source):\n                for root, dirs, files in safe_walk(source):\n                    relative_directory = get_relative_path(root, source)\n\n                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n                    files.sort()\n                    for f in files:\n                        relative_file_path = os.path.join(target_path, relative_directory, f)\n                        distribution_path = self.config.get_distribution_path(relative_file_path)\n                        if not self.config.path_is_reserved(distribution_path):\n                            yield IncludedFile(\n                                os.path.join(root, f),\n                                '' if external else relative_file_path,\n                                distribution_path,\n                            )\n            else:\n                msg = f'Forced include not found: {source}'\n                raise FileNotFoundError(msg)\n\n    def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n        for source, target_path in inclusion_map.items():\n            external = not source.startswith(self.root)\n            if os.path.isfile(source):\n                distribution_path = self.config.get_distribution_path(target_path)\n                if not self.config.path_is_reserved(distribution_path):\n                    yield IncludedFile(\n                        source,\n                        '' if external else os.path.relpath(source, self.root),\n                        self.config.get_distribution_path(target_path),\n                    )\n            elif os.path.isdir(source):\n                for root, dirs, files in safe_walk(source):\n                    relative_directory = get_relative_path(root, source)\n\n                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n                    files.sort()\n                    is_package = '__init__.py' in files\n                    for f in files:\n                        relative_file_path = os.path.join(target_path, relative_directory, f)\n                        distribution_path = self.config.get_distribution_path(relative_file_path)\n                        if self.config.path_is_reserved(distribution_path):\n                            continue\n\n                        if self.config.include_path(relative_file_path, explicit=True, is_package=is_package):\n                            yield IncludedFile(\n                                os.path.join(root, f), '' if external else relative_file_path, distribution_path\n                            )\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def plugin_manager(self) -> PluginManagerBound:\n        if self.__plugin_manager is None:\n            from hatchling.plugin.manager import PluginManager\n\n            self.__plugin_manager = PluginManager()\n\n        return self.__plugin_manager\n\n    @property\n    def metadata(self) -> ProjectMetadata:\n        if self.__metadata is None:\n            from hatchling.metadata.core import ProjectMetadata\n\n            self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)\n\n        return self.__metadata\n\n    @property\n    def app(self) -> Application:\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = cast(Application, Application().get_safe_application())\n\n        return self.__app\n\n    @property\n    def raw_config(self) -> dict[str, Any]:\n        if self.__raw_config is None:\n            self.__raw_config = self.metadata.config\n\n        return self.__raw_config\n\n    @property\n    def project_config(self) -> dict[str, Any]:\n        if self.__project_config is None:\n            self.__project_config = self.metadata.core.config\n\n        return self.__project_config\n\n    @property\n    def hatch_config(self) -> dict[str, Any]:\n        if self.__hatch_config is None:\n            self.__hatch_config = self.metadata.hatch.config\n\n        return self.__hatch_config\n\n    @property\n    def config(self) -> BuilderConfigBound:\n        \"\"\"\n        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        if self.__config is None:\n            self.__config = self.get_config_class()(\n                self, self.root, self.PLUGIN_NAME, self.build_config, self.target_config\n            )\n\n        return self.__config\n\n    @property\n    def build_config(self) -> dict[str, Any]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.build]\n        ```\n        \"\"\"\n        if self.__build_config is None:\n            self.__build_config = self.metadata.hatch.build_config\n\n        return self.__build_config\n\n    @property\n    def target_config(self) -> dict[str, Any]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.build.targets.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        if self.__target_config is None:\n            target_config: dict[str, Any] = self.metadata.hatch.build_targets.get(self.PLUGIN_NAME, {})\n            if not isinstance(target_config, dict):\n                message = f'Field `tool.hatch.build.targets.{self.PLUGIN_NAME}` must be a table'\n                raise TypeError(message)\n\n            self.__target_config = target_config\n\n        return self.__target_config\n\n    @property\n    def project_id(self) -> str:\n        if self.__project_id is None:\n            self.__project_id = f'{self.normalize_file_name_component(self.metadata.core.name)}-{self.metadata.version}'\n\n        return self.__project_id\n\n    def get_build_hooks(self, directory: str) -> dict[str, BuildHookInterface]:\n        configured_build_hooks = {}\n        for hook_name, config in self.config.hook_config.items():\n            build_hook = self.plugin_manager.build_hook.get(hook_name)\n            if build_hook is None:\n                from hatchling.plugin.exceptions import UnknownPluginError\n\n                message = f'Unknown build hook: {hook_name}'\n                raise UnknownPluginError(message)\n\n            configured_build_hooks[hook_name] = build_hook(\n                self.root, config, self.config, self.metadata, directory, self.PLUGIN_NAME, self.app\n            )\n\n        return configured_build_hooks\n\n    @abstractmethod\n    def get_version_api(self) -> dict[str, Callable]:\n        \"\"\"\n        A mapping of `str` versions to a callable that is used for building.\n        Each callable must have the following signature:\n\n        ```python\n        def ...(build_dir: str, build_data: dict) -> str:\n        ```\n\n        The return value must be the absolute path to the built artifact.\n        \"\"\"\n\n    def get_default_versions(self) -> list[str]:\n        \"\"\"\n        A list of versions to build when users do not specify any, defaulting to all versions.\n        \"\"\"\n        return list(self.get_version_api())\n\n    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301\n        \"\"\"\n        A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n        \"\"\"\n        return {}\n\n    def set_build_data_defaults(self, build_data: dict[str, Any]) -> None:  # noqa: PLR6301\n        build_data.setdefault('artifacts', [])\n        build_data.setdefault('force_include', {})\n\n    def clean(self, directory: str, versions: list[str]) -> None:\n        \"\"\"\n        Called before builds if the `-c`/`--clean` flag was passed to the\n        [`build`](../../cli/reference.md#hatch-build) command.\n        \"\"\"\n\n    @classmethod\n    def get_config_class(cls) -> type[BuilderConfig]:\n        \"\"\"\n        Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        return BuilderConfig\n\n    @staticmethod\n    def normalize_file_name_component(file_name: str) -> str:\n        \"\"\"\n        https://peps.python.org/pep-0427/#escaping-and-unicode\n        \"\"\"\n        return re.sub(r'[^\\w\\d.]+', '_', file_name, flags=re.UNICODE)\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.app","title":"app: Application property","text":"

      An instance of Application.

      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.root","title":"root: str property","text":"

      The root of the project tree.

      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.build_config","title":"build_config: dict[str, Any] property","text":"pyproject.toml hatch.toml
      [tool.hatch.build]\n
      [build]\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.target_config","title":"target_config: dict[str, Any] property","text":"pyproject.toml hatch.toml
      [tool.hatch.build.targets.<PLUGIN_NAME>]\n
      [build.targets.<PLUGIN_NAME>]\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.config","title":"config: BuilderConfigBound property","text":"

      An instance of BuilderConfig.

      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_config_class","title":"get_config_class() -> type[BuilderConfig] classmethod","text":"

      Must return a subclass of BuilderConfig.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      @classmethod\ndef get_config_class(cls) -> type[BuilderConfig]:\n    \"\"\"\n    Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n    \"\"\"\n    return BuilderConfig\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_version_api","title":"get_version_api() -> dict[str, Callable] abstractmethod","text":"

      A mapping of str versions to a callable that is used for building. Each callable must have the following signature:

      def ...(build_dir: str, build_data: dict) -> str:\n

      The return value must be the absolute path to the built artifact.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      @abstractmethod\ndef get_version_api(self) -> dict[str, Callable]:\n    \"\"\"\n    A mapping of `str` versions to a callable that is used for building.\n    Each callable must have the following signature:\n\n    ```python\n    def ...(build_dir: str, build_data: dict) -> str:\n    ```\n\n    The return value must be the absolute path to the built artifact.\n    \"\"\"\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_versions","title":"get_default_versions() -> list[str]","text":"

      A list of versions to build when users do not specify any, defaulting to all versions.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def get_default_versions(self) -> list[str]:\n    \"\"\"\n    A list of versions to build when users do not specify any, defaulting to all versions.\n    \"\"\"\n    return list(self.get_version_api())\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.clean","title":"clean(directory: str, versions: list[str]) -> None","text":"

      Called before builds if the -c/--clean flag was passed to the build command.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def clean(self, directory: str, versions: list[str]) -> None:\n    \"\"\"\n    Called before builds if the `-c`/`--clean` flag was passed to the\n    [`build`](../../cli/reference.md#hatch-build) command.\n    \"\"\"\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.recurse_included_files","title":"recurse_included_files() -> Iterable[IncludedFile]","text":"

      Returns a consistently generated series of file objects for every file that should be distributed. Each file object has three str attributes:

      • path - the absolute path
      • relative_path - the path relative to the project root; will be an empty string for external files
      • distribution_path - the path to be distributed as
      Source code in backend/src/hatchling/builders/plugin/interface.py
      def recurse_included_files(self) -> Iterable[IncludedFile]:\n    \"\"\"\n    Returns a consistently generated series of file objects for every file that should be distributed. Each file\n    object has three `str` attributes:\n\n    - `path` - the absolute path\n    - `relative_path` - the path relative to the project root; will be an empty string for external files\n    - `distribution_path` - the path to be distributed as\n    \"\"\"\n    yield from self.recurse_selected_project_files()\n    yield from self.recurse_forced_files(self.config.get_force_include())\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_build_data","title":"get_default_build_data() -> dict[str, Any]","text":"

      A mapping that can be modified by build hooks to influence the behavior of builds.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301\n    \"\"\"\n    A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n    \"\"\"\n    return {}\n
      "},{"location":"plugins/builder/sdist/","title":"Source distribution builder","text":"

      A source distribution, or sdist, is an archive of Python \"source code\". Although largely unspecified, by convention it should include everything that is required to build a wheel without making network requests.

      "},{"location":"plugins/builder/sdist/#configuration","title":"Configuration","text":"

      The builder plugin name is sdist.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.sdist]\n
      [build.targets.sdist]\n
      "},{"location":"plugins/builder/sdist/#options","title":"Options","text":"Option Default Description core-metadata-version \"2.1\" The version of core metadata to use strict-naming true Whether or not file names should contain the normalized version of the project name support-legacy false Whether or not to include a setup.py file to support legacy installation mechanisms"},{"location":"plugins/builder/sdist/#versions","title":"Versions","text":"Version Description standard (default) The latest conventional format"},{"location":"plugins/builder/sdist/#default-file-selection","title":"Default file selection","text":"

      When the user has not set any file selection options, all files that are not ignored by your VCS will be included.

      Note

      The following files are always included and cannot be excluded:

      • /pyproject.toml
      • /hatch.toml
      • /hatch_build.py
      • /.gitignore or /.hgignore
      • Any defined readme file
      • All defined license-files
      "},{"location":"plugins/builder/sdist/#reproducibility","title":"Reproducibility","text":"

      Reproducible builds are supported.

      "},{"location":"plugins/builder/sdist/#build-data","title":"Build data","text":"

      This is data that can be modified by build hooks.

      Data Default Description dependencies Extra project dependencies"},{"location":"plugins/builder/wheel/","title":"Wheel builder","text":"

      A wheel is a binary distribution of a Python package that can be installed directly into an environment.

      "},{"location":"plugins/builder/wheel/#configuration","title":"Configuration","text":"

      The builder plugin name is wheel.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\n
      [build.targets.wheel]\n
      "},{"location":"plugins/builder/wheel/#options","title":"Options","text":"Option Default Description core-metadata-version \"2.1\" The version of core metadata to use shared-data A mapping similar to the forced inclusion option corresponding to data that will be installed globally in a given Python environment, usually under sys.prefix extra-metadata A mapping similar to the forced inclusion option corresponding to extra metadata that will be shipped in a directory named extra_metadata strict-naming true Whether or not file names should contain the normalized version of the project name macos-max-compat true Whether or not on macOS, when build hooks have set the infer_tag build data, the wheel name should signal broad support rather than specific versions for newer SDK versions.Note: The default will become false, and this option eventually removed, sometime after consumers like pip start supporting these newer SDK versions. bypass-selection false Whether or not to suppress the error when one has not defined any file selection options and all heuristics have failed to determine what to ship"},{"location":"plugins/builder/wheel/#versions","title":"Versions","text":"Version Description standard (default) The latest standardized format editable A wheel that only ships .pth files or import hooks for real-time development"},{"location":"plugins/builder/wheel/#default-file-selection","title":"Default file selection","text":"

      When the user has not set any file selection options, the project name will be used to determine the package to ship in the following heuristic order:

      1. <NAME>/__init__.py
      2. src/<NAME>/__init__.py
      3. <NAME>.py
      4. <NAMESPACE>/<NAME>/__init__.py

      If none of these heuristics are satisfied, an error will be raised.

      "},{"location":"plugins/builder/wheel/#reproducibility","title":"Reproducibility","text":"

      Reproducible builds are supported.

      "},{"location":"plugins/builder/wheel/#build-data","title":"Build data","text":"

      This is data that can be modified by build hooks.

      Data Default Description tag The full tag part of the filename (e.g. py3-none-any), defaulting to a cross-platform wheel with the supported major versions of Python based on project metadata infer_tag False When tag is not set, this may be enabled to use the one most specific to the platform, Python interpreter, and ABI pure_python True Whether or not to write metadata indicating that the package does not contain any platform-specific files dependencies Extra project dependencies extra_metadata Additional extra-metadata entries, which take precedence in case of conflicts force_include_editable Similar to the force_include option but specifically for the editable version and takes precedence"},{"location":"plugins/environment/reference/","title":"Environment plugins","text":"

      See the documentation for environment configuration.

      "},{"location":"plugins/environment/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-conda - environments backed by Conda/Mamba
      • hatch-containers - environments run inside containers
      • hatch-pip-compile - use pip-compile to manage project dependencies and lockfiles
      • hatch-pip-deepfreeze - virtual environments with dependency locking by pip-deepfreeze
      "},{"location":"plugins/environment/reference/#installation","title":"Installation","text":"

      Any required environment types that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

      pyproject.toml hatch.toml
      [tool.hatch.env]\nrequires = [\n  \"...\",\n]\n
      [env]\nrequires = [\n  \"...\",\n]\n
      "},{"location":"plugins/environment/reference/#life-cycle","title":"Life cycle","text":"

      Whenever an environment is used, the following logic is performed:

      Source code in src/hatch/cli/application.py
      def prepare_environment(self, environment: EnvironmentInterface):\n    if not environment.exists():\n        self.env_metadata.reset(environment)\n\n        with self.status(f'Creating environment: {environment.name}'):\n            environment.create()\n\n        if not environment.skip_install:\n            if environment.pre_install_commands:\n                with self.status('Running pre-installation commands'):\n                    self.run_shell_commands(environment, environment.pre_install_commands, source='pre-install')\n\n            if environment.dev_mode:\n                with self.status('Installing project in development mode'):\n                    environment.install_project_dev_mode()\n            else:\n                with self.status('Installing project'):\n                    environment.install_project()\n\n            if environment.post_install_commands:\n                with self.status('Running post-installation commands'):\n                    self.run_shell_commands(environment, environment.post_install_commands, source='post-install')\n\n    new_dep_hash = environment.dependency_hash()\n    current_dep_hash = self.env_metadata.dependency_hash(environment)\n    if new_dep_hash != current_dep_hash:\n        with self.status('Checking dependencies'):\n            dependencies_in_sync = environment.dependencies_in_sync()\n\n        if not dependencies_in_sync:\n            with self.status('Syncing dependencies'):\n                environment.sync_dependencies()\n                new_dep_hash = environment.dependency_hash()\n\n        self.env_metadata.update_dependency_hash(environment, new_dep_hash)\n
      "},{"location":"plugins/environment/reference/#build-environments","title":"Build environments","text":"

      All environment types should offer support for a special sub-environment in which projects can be built. This environment is used in the following scenarios:

      • the build command
      • commands that read dependencies, like dep hash, if any project dependencies are set dynamically
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface","title":"EnvironmentInterface","text":"

      Example usage:

      plugin.py hooks.py
          from hatch.env.plugin.interface import EnvironmentInterface\n\n\n    class SpecialEnvironment(EnvironmentInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
          from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialEnvironment\n\n\n    @hookimpl\n    def hatch_register_environment():\n        return SpecialEnvironment\n
      Source code in src/hatch/env/plugin/interface.py
      class EnvironmentInterface(ABC):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.env.plugin.interface import EnvironmentInterface\n\n\n        class SpecialEnvironment(EnvironmentInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialEnvironment\n\n\n        @hookimpl\n        def hatch_register_environment():\n            return SpecialEnvironment\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root,\n        metadata,\n        name,\n        config,\n        matrix_variables,\n        data_directory,\n        isolated_data_directory,\n        platform,\n        verbosity,\n        app=None,\n    ):\n        self.__root = root\n        self.__metadata = metadata\n        self.__name = name\n        self.__config = config\n        self.__matrix_variables = matrix_variables\n        self.__data_directory = data_directory\n        self.__isolated_data_directory = isolated_data_directory\n        self.__platform = platform\n        self.__verbosity = verbosity\n        self.__app = app\n        self.__context = None\n\n        self._system_python = None\n        self._env_vars = None\n        self._env_include = None\n        self._env_exclude = None\n        self._environment_dependencies_complex = None\n        self._environment_dependencies = None\n        self._dependencies_complex = None\n        self._dependencies = None\n        self._platforms = None\n        self._skip_install = None\n        self._dev_mode = None\n        self._features = None\n        self._description = None\n        self._scripts = None\n        self._pre_install_commands = None\n        self._post_install_commands = None\n\n    @property\n    def matrix_variables(self):\n        return self.__matrix_variables\n\n    @property\n    def app(self):\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = Application().get_safe_application()\n\n        return self.__app\n\n    @property\n    def context(self):\n        if self.__context is None:\n            self.__context = self.get_context()\n\n        return self.__context\n\n    @property\n    def verbosity(self):\n        return self.__verbosity\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def metadata(self):\n        return self.__metadata\n\n    @property\n    def name(self) -> str:\n        \"\"\"\n        The name of the environment.\n        \"\"\"\n        return self.__name\n\n    @property\n    def platform(self):\n        \"\"\"\n        An instance of [Platform](../utilities.md#hatch.utils.platform.Platform).\n        \"\"\"\n        return self.__platform\n\n    @property\n    def data_directory(self):\n        \"\"\"\n        The [directory](../../config/hatch.md#environments) this plugin should use for storage as a path-like object.\n        If the user has not configured one then this will be the same as the\n        [isolated data directory](reference.md#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory).\n        \"\"\"\n        return self.__data_directory\n\n    @property\n    def isolated_data_directory(self):\n        \"\"\"\n        The default [directory](../../config/hatch.md#environments) reserved exclusively for this plugin as a path-like\n        object.\n        \"\"\"\n        return self.__isolated_data_directory\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @property\n    def system_python(self):\n        if self._system_python is None:\n            system_python = os.environ.get(AppEnvVars.PYTHON)\n            if system_python == 'self':\n                system_python = sys.executable\n\n            system_python = (\n                system_python\n                or self.platform.modules.shutil.which('python')\n                or self.platform.modules.shutil.which('python3')\n                or sys.executable\n            )\n            if not isabs(system_python):\n                system_python = self.platform.modules.shutil.which(system_python)\n\n            self._system_python = system_python\n\n        return self._system_python\n\n    @property\n    def env_vars(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>.env-vars]\n        ```\n        \"\"\"\n        if self._env_vars is None:\n            env_vars = self.config.get('env-vars', {})\n            if not isinstance(env_vars, dict):\n                message = f'Field `tool.hatch.envs.{self.name}.env-vars` must be a mapping'\n                raise TypeError(message)\n\n            for key, value in env_vars.items():\n                if not isinstance(value, str):\n                    message = (\n                        f'Environment variable `{key}` of field `tool.hatch.envs.{self.name}.env-vars` must be a string'\n                    )\n                    raise TypeError(message)\n\n            new_env_vars = {}\n            with self.metadata.context.apply_context(self.context):\n                for key, value in env_vars.items():\n                    new_env_vars[key] = self.metadata.context.format(value)\n\n            new_env_vars[AppEnvVars.ENV_ACTIVE] = self.name\n            self._env_vars = new_env_vars\n\n        return self._env_vars\n\n    @property\n    def env_include(self) -> list[str]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        env-include = [...]\n        ```\n        \"\"\"\n        if self._env_include is None:\n            env_include = self.config.get('env-include', [])\n            if not isinstance(env_include, list):\n                message = f'Field `tool.hatch.envs.{self.name}.env-include` must be an array'\n                raise TypeError(message)\n\n            for i, pattern in enumerate(env_include, 1):\n                if not isinstance(pattern, str):\n                    message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-include` must be a string'\n                    raise TypeError(message)\n\n            if env_include:\n                self._env_include = ['HATCH_BUILD_*', *env_include]\n            else:\n                self._env_include = env_include\n\n        return self._env_include\n\n    @property\n    def env_exclude(self) -> list[str]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        env-exclude = [...]\n        ```\n        \"\"\"\n        if self._env_exclude is None:\n            env_exclude = self.config.get('env-exclude', [])\n            if not isinstance(env_exclude, list):\n                message = f'Field `tool.hatch.envs.{self.name}.env-exclude` must be an array'\n                raise TypeError(message)\n\n            for i, pattern in enumerate(env_exclude, 1):\n                if not isinstance(pattern, str):\n                    message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-exclude` must be a string'\n                    raise TypeError(message)\n\n            self._env_exclude = env_exclude\n\n        return self._env_exclude\n\n    @property\n    def environment_dependencies_complex(self):\n        if self._environment_dependencies_complex is None:\n            from packaging.requirements import InvalidRequirement, Requirement\n\n            dependencies_complex = []\n            with self.apply_context():\n                for option in ('dependencies', 'extra-dependencies'):\n                    dependencies = self.config.get(option, [])\n                    if not isinstance(dependencies, list):\n                        message = f'Field `tool.hatch.envs.{self.name}.{option}` must be an array'\n                        raise TypeError(message)\n\n                    for i, entry in enumerate(dependencies, 1):\n                        if not isinstance(entry, str):\n                            message = (\n                                f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` must be a string'\n                            )\n                            raise TypeError(message)\n\n                        try:\n                            dependencies_complex.append(Requirement(self.metadata.context.format(entry)))\n                        except InvalidRequirement as e:\n                            message = f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` is invalid: {e}'\n                            raise ValueError(message) from None\n\n            self._environment_dependencies_complex = dependencies_complex\n\n        return self._environment_dependencies_complex\n\n    @property\n    def environment_dependencies(self) -> list[str]:\n        \"\"\"\n        The list of all [environment dependencies](../../config/environment/overview.md#dependencies).\n        \"\"\"\n        if self._environment_dependencies is None:\n            self._environment_dependencies = [str(dependency) for dependency in self.environment_dependencies_complex]\n\n        return self._environment_dependencies\n\n    @property\n    def dependencies_complex(self):\n        if self._dependencies_complex is None:\n            all_dependencies_complex = list(self.environment_dependencies_complex)\n\n            # Ensure these are checked last to speed up initial environment creation since\n            # they will already be installed along with the project\n            if (not self.skip_install and self.dev_mode) or self.features:\n                from hatch.utils.dep import get_project_dependencies_complex\n\n                dependencies_complex, optional_dependencies_complex = get_project_dependencies_complex(self)\n\n                if not self.skip_install and self.dev_mode:\n                    all_dependencies_complex.extend(dependencies_complex.values())\n\n                for feature in self.features:\n                    if feature not in optional_dependencies_complex:\n                        message = (\n                            f'Feature `{feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n                            f'defined in the dynamic field `project.optional-dependencies`'\n                        )\n                        raise ValueError(message)\n\n                    all_dependencies_complex.extend(optional_dependencies_complex[feature].values())\n\n            self._dependencies_complex = all_dependencies_complex\n\n        return self._dependencies_complex\n\n    @property\n    def dependencies(self) -> list[str]:\n        \"\"\"\n        The list of all [project dependencies](../../config/metadata.md#dependencies) (if\n        [installed](../../config/environment/overview.md#skip-install) and in\n        [dev mode](../../config/environment/overview.md#dev-mode)), selected\n        [optional dependencies](../../config/environment/overview.md#features), and\n        [environment dependencies](../../config/environment/overview.md#dependencies).\n        \"\"\"\n        if self._dependencies is None:\n            self._dependencies = [str(dependency) for dependency in self.dependencies_complex]\n\n        return self._dependencies\n\n    @property\n    def platforms(self) -> list[str]:\n        \"\"\"\n        All names are stored as their lower-cased version.\n\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        platforms = [...]\n        ```\n        \"\"\"\n        if self._platforms is None:\n            platforms = self.config.get('platforms', [])\n            if not isinstance(platforms, list):\n                message = f'Field `tool.hatch.envs.{self.name}.platforms` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(platforms, 1):\n                if not isinstance(command, str):\n                    message = f'Platform #{i} of field `tool.hatch.envs.{self.name}.platforms` must be a string'\n                    raise TypeError(message)\n\n            self._platforms = [platform.lower() for platform in platforms]\n\n        return self._platforms\n\n    @property\n    def skip_install(self) -> bool:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        skip-install = ...\n        ```\n        \"\"\"\n        if self._skip_install is None:\n            skip_install = self.config.get('skip-install', not self.metadata.has_project_file())\n            if not isinstance(skip_install, bool):\n                message = f'Field `tool.hatch.envs.{self.name}.skip-install` must be a boolean'\n                raise TypeError(message)\n\n            self._skip_install = skip_install\n\n        return self._skip_install\n\n    @property\n    def dev_mode(self) -> bool:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        dev-mode = ...\n        ```\n        \"\"\"\n        if self._dev_mode is None:\n            dev_mode = self.config.get('dev-mode', True)\n            if not isinstance(dev_mode, bool):\n                message = f'Field `tool.hatch.envs.{self.name}.dev-mode` must be a boolean'\n                raise TypeError(message)\n\n            self._dev_mode = dev_mode\n\n        return self._dev_mode\n\n    @property\n    def features(self):\n        if self._features is None:\n            from hatchling.metadata.utils import normalize_project_name\n\n            features = self.config.get('features', [])\n            if not isinstance(features, list):\n                message = f'Field `tool.hatch.envs.{self.name}.features` must be an array of strings'\n                raise TypeError(message)\n\n            all_features = set()\n            for i, feature in enumerate(features, 1):\n                if not isinstance(feature, str):\n                    message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` must be a string'\n                    raise TypeError(message)\n\n                if not feature:\n                    message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` cannot be an empty string'\n                    raise ValueError(message)\n\n                normalized_feature = (\n                    feature\n                    if self.metadata.hatch.metadata.allow_ambiguous_features\n                    else normalize_project_name(feature)\n                )\n                if (\n                    not self.metadata.hatch.metadata.hook_config\n                    and normalized_feature not in self.metadata.core.optional_dependencies\n                ):\n                    message = (\n                        f'Feature `{normalized_feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n                        f'defined in field `project.optional-dependencies`'\n                    )\n                    raise ValueError(message)\n\n                all_features.add(normalized_feature)\n\n            self._features = sorted(all_features)\n\n        return self._features\n\n    @property\n    def description(self) -> str:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        description = ...\n        ```\n        \"\"\"\n        if self._description is None:\n            description = self.config.get('description', '')\n            if not isinstance(description, str):\n                message = f'Field `tool.hatch.envs.{self.name}.description` must be a string'\n                raise TypeError(message)\n\n            self._description = description\n\n        return self._description\n\n    @property\n    def scripts(self):\n        if self._scripts is None:\n            script_config = self.config.get('scripts', {})\n            if not isinstance(script_config, dict):\n                message = f'Field `tool.hatch.envs.{self.name}.scripts` must be a table'\n                raise TypeError(message)\n\n            config = {}\n\n            for name, data in script_config.items():\n                if ' ' in name:\n                    message = (\n                        f'Script name `{name}` in field `tool.hatch.envs.{self.name}.scripts` must not contain spaces'\n                    )\n                    raise ValueError(message)\n\n                commands = []\n\n                if isinstance(data, str):\n                    commands.append(data)\n                elif isinstance(data, list):\n                    for i, command in enumerate(data, 1):\n                        if not isinstance(command, str):\n                            message = (\n                                f'Command #{i} in field `tool.hatch.envs.{self.name}.scripts.{name}` must be a string'\n                            )\n                            raise TypeError(message)\n\n                        commands.append(command)\n                else:\n                    message = (\n                        f'Field `tool.hatch.envs.{self.name}.scripts.{name}` must be a string or an array of strings'\n                    )\n                    raise TypeError(message)\n\n                config[name] = commands\n\n            seen = {}\n            active = []\n            for script_name, commands in config.items():\n                commands[:] = expand_script_commands(self.name, script_name, commands, config, seen, active)\n\n            self._scripts = config\n\n        return self._scripts\n\n    @property\n    def pre_install_commands(self):\n        if self._pre_install_commands is None:\n            pre_install_commands = self.config.get('pre-install-commands', [])\n            if not isinstance(pre_install_commands, list):\n                message = f'Field `tool.hatch.envs.{self.name}.pre-install-commands` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(pre_install_commands, 1):\n                if not isinstance(command, str):\n                    message = (\n                        f'Command #{i} of field `tool.hatch.envs.{self.name}.pre-install-commands` must be a string'\n                    )\n                    raise TypeError(message)\n\n            self._pre_install_commands = list(pre_install_commands)\n\n        return self._pre_install_commands\n\n    @property\n    def post_install_commands(self):\n        if self._post_install_commands is None:\n            post_install_commands = self.config.get('post-install-commands', [])\n            if not isinstance(post_install_commands, list):\n                message = f'Field `tool.hatch.envs.{self.name}.post-install-commands` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(post_install_commands, 1):\n                if not isinstance(command, str):\n                    message = (\n                        f'Command #{i} of field `tool.hatch.envs.{self.name}.post-install-commands` must be a string'\n                    )\n                    raise TypeError(message)\n\n            self._post_install_commands = list(post_install_commands)\n\n        return self._post_install_commands\n\n    def activate(self):\n        \"\"\"\n        A convenience method called when using the environment as a context manager:\n\n        ```python\n        with environment: ...\n        ```\n        \"\"\"\n\n    def deactivate(self):\n        \"\"\"\n        A convenience method called after using the environment as a context manager:\n\n        ```python\n        with environment: ...\n        ```\n        \"\"\"\n\n    @abstractmethod\n    def find(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should return information about how to locate the environment or represent its ID in\n        some way. Additionally, this is expected to return something even if the environment is\n        [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n        \"\"\"\n\n    @abstractmethod\n    def create(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should perform the necessary steps to set up the environment.\n        \"\"\"\n\n    @abstractmethod\n    def remove(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should perform the necessary steps to completely remove the environment from the system and will only\n        be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n        [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n\n        If the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        has a caching mechanism, this should remove that as well.\n        \"\"\"\n\n    @abstractmethod\n    def exists(self) -> bool:\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should indicate whether or not the environment has already been created.\n        \"\"\"\n\n    @abstractmethod\n    def install_project(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the project in the environment.\n        \"\"\"\n\n    @abstractmethod\n    def install_project_dev_mode(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the project in the environment such that the environment\n        always reflects the current state of the project.\n        \"\"\"\n\n    @abstractmethod\n    def dependencies_in_sync(self) -> bool:\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should indicate whether or not the environment is compatible with the current\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n        \"\"\"\n\n    @abstractmethod\n    def sync_dependencies(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n        in the environment.\n        \"\"\"\n\n    def dependency_hash(self):\n        \"\"\"\n        This should return a hash of the environment's\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n        and any other data that is handled by the\n        [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n        and\n        [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n        methods.\n        \"\"\"\n        from hatch.utils.dep import hash_dependencies\n\n        return hash_dependencies(self.dependencies_complex)\n\n    @contextmanager\n    def build_environment(\n        self,\n        dependencies: list[str],  # noqa: ARG002\n    ):\n        \"\"\"\n        This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project\n        given a set of dependencies and must be a context manager:\n\n        ```python\n        with environment.build_environment([...]): ...\n        ```\n\n        The build environment should reflect any\n        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n        the user defined either currently or at the time of\n        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n        \"\"\"\n        with self.get_env_vars():\n            yield\n\n    def run_builder(\n        self,\n        build_environment,  # noqa: ARG002\n        **kwargs,\n    ):\n        \"\"\"\n        This will be called when the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        is active:\n\n        ```python\n        with environment.build_environment([...]) as build_env:\n            process = environment.run_builder(build_env, ...)\n        ```\n\n        This should return the standard library's\n        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).\n        The command is constructed by passing all keyword arguments to\n        [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).\n\n        For an example, open the default implementation below:\n        \"\"\"\n        return self.platform.run_command(self.construct_build_command(**kwargs))\n\n    def build_environment_exists(self):  # noqa: PLR6301\n        \"\"\"\n        If the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        has a caching mechanism, this should indicate whether or not it has already been created.\n        \"\"\"\n        return False\n\n    def enter_shell(\n        self,\n        name: str,  # noqa: ARG002\n        path: str,\n        args: Iterable[str],\n    ):\n        \"\"\"\n        Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n        This should either use\n        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n        directly or provide the same guarantee.\n        \"\"\"\n        with self.command_context():\n            self.platform.exit_with_command([path, *args])\n\n    def run_shell_command(self, command: str, **kwargs):\n        \"\"\"\n        This should return the standard library's\n        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n        and will always be called when the\n        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n        is active, with the expectation of providing the same guarantee.\n        \"\"\"\n        kwargs.setdefault('shell', True)\n        return self.platform.run_command(command, **kwargs)\n\n    @contextmanager\n    def command_context(self):\n        \"\"\"\n        A context manager that when active should make executed shell commands reflect any\n        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n        the user defined either currently or at the time of\n        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n        For an example, open the default implementation below:\n        \"\"\"\n        with self.get_env_vars():\n            yield\n\n    def resolve_commands(self, commands: list[str]):\n        \"\"\"\n        This expands each command into one or more commands based on any\n        [scripts](../../config/environment/overview.md#scripts) that the user defined.\n        \"\"\"\n        for command in commands:\n            yield from self.expand_command(command)\n\n    def expand_command(self, command):\n        possible_script, args, _ignore_exit_code = parse_script_command(command)\n\n        # Indicate undefined\n        if not args:\n            args = None\n\n        with self.apply_context():\n            if possible_script in self.scripts:\n                for cmd in self.scripts[possible_script]:\n                    yield self.metadata.context.format(cmd, args=args).strip()\n            else:\n                yield self.metadata.context.format(command, args=args).strip()\n\n    def construct_build_command(  # noqa: PLR6301\n        self,\n        *,\n        directory=None,\n        targets=(),\n        hooks_only=False,\n        no_hooks=False,\n        clean=False,\n        clean_hooks_after=False,\n        clean_only=False,\n    ):\n        \"\"\"\n        This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to\n        a subprocess command issued to [builders](../builder/reference.md).\n        \"\"\"\n        command = ['python', '-u', '-m', 'hatchling', 'build']\n\n        if directory:\n            command.extend(('--directory', directory))\n\n        if targets:\n            for target in targets:\n                command.extend(('--target', target))\n\n        if hooks_only:\n            command.append('--hooks-only')\n\n        if no_hooks:\n            command.append('--no-hooks')\n\n        if clean:\n            command.append('--clean')\n\n        if clean_hooks_after:\n            command.append('--clean-hooks-after')\n\n        if clean_only:\n            command.append('--clean-only')\n\n        return command\n\n    def construct_pip_install_command(self, args: list[str]):\n        \"\"\"\n        A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n        command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n        \"\"\"\n        command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n        # Default to -1 verbosity\n        add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n        command.extend(args)\n        return command\n\n    def join_command_args(self, args: list[str]):\n        \"\"\"\n        This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n        from the received arguments.\n        \"\"\"\n        return self.platform.join_command_args(args)\n\n    def apply_features(self, requirement: str):\n        \"\"\"\n        A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n        to the given requirement.\n        \"\"\"\n        if self.features:\n            features = ','.join(self.features)\n            return f'{requirement}[{features}]'\n\n        return requirement\n\n    def check_compatibility(self):\n        \"\"\"\n        This raises an exception if the environment is not compatible with the user's setup. The default behavior\n        checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n        and any method override should keep this check.\n\n        This check is never performed if the environment has been\n        [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n        \"\"\"\n        if self.platforms and self.platform.name not in self.platforms:\n            message = 'unsupported platform'\n            raise OSError(message)\n\n    def get_env_vars(self) -> EnvVars:\n        \"\"\"\n        Returns a mapping of environment variables that should be available to the environment. The object can\n        be used as a context manager to temporarily apply the environment variables to the current process.\n\n        !!! note\n            The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n        \"\"\"\n        return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n\n    def get_env_var_option(self, option: str) -> str:\n        \"\"\"\n        Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n        \"\"\"\n        return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')\n\n    def get_context(self):\n        \"\"\"\n        Returns a subclass of\n        [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n        \"\"\"\n        from hatch.env.context import EnvironmentContextFormatter\n\n        return EnvironmentContextFormatter(self)\n\n    @staticmethod\n    def get_option_types() -> dict:\n        \"\"\"\n        Returns a mapping of supported options to their respective types so that they can be used by\n        [overrides](../../config/environment/advanced.md#option-overrides).\n        \"\"\"\n        return {}\n\n    @contextmanager\n    def apply_context(self):\n        with self.get_env_vars(), self.metadata.context.apply_context(self.context):\n            yield\n\n    def __enter__(self):\n        self.activate()\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        self.deactivate()\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app","title":"app property","text":"

      An instance of Application.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.root","title":"root property","text":"

      The root of the project tree as a path-like object.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.name","title":"name: str property","text":"

      The name of the environment.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.data_directory","title":"data_directory property","text":"

      The directory this plugin should use for storage as a path-like object. If the user has not configured one then this will be the same as the isolated data directory.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory","title":"isolated_data_directory property","text":"

      The default directory reserved exclusively for this plugin as a path-like object.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\n
      [envs.<ENV_NAME>]\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platform","title":"platform property","text":"

      An instance of Platform.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.environment_dependencies","title":"environment_dependencies: list[str] property","text":"

      The list of all environment dependencies.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies","title":"dependencies: list[str] property","text":"

      The list of all project dependencies (if installed and in dev mode), selected optional dependencies, and environment dependencies.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_vars","title":"env_vars: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>.env-vars]\n
      [envs.<ENV_NAME>.env-vars]\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_include","title":"env_include: list[str] property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nenv-include = [...]\n
      [envs.<ENV_NAME>]\nenv-include = [...]\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_exclude","title":"env_exclude: list[str] property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nenv-exclude = [...]\n
      [envs.<ENV_NAME>]\nenv-exclude = [...]\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platforms","title":"platforms: list[str] property","text":"

      All names are stored as their lower-cased version.

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nplatforms = [...]\n
      [envs.<ENV_NAME>]\nplatforms = [...]\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.skip_install","title":"skip_install: bool property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nskip-install = ...\n
      [envs.<ENV_NAME>]\nskip-install = ...\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dev_mode","title":"dev_mode: bool property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\ndev-mode = ...\n
      [envs.<ENV_NAME>]\ndev-mode = ...\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.description","title":"description: str property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\ndescription = ...\n
      [envs.<ENV_NAME>]\ndescription = ...\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.activate","title":"activate()","text":"

      A convenience method called when using the environment as a context manager:

      with environment: ...\n
      Source code in src/hatch/env/plugin/interface.py
      def activate(self):\n    \"\"\"\n    A convenience method called when using the environment as a context manager:\n\n    ```python\n    with environment: ...\n    ```\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.deactivate","title":"deactivate()","text":"

      A convenience method called after using the environment as a context manager:

      with environment: ...\n
      Source code in src/hatch/env/plugin/interface.py
      def deactivate(self):\n    \"\"\"\n    A convenience method called after using the environment as a context manager:\n\n    ```python\n    with environment: ...\n    ```\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.find","title":"find() abstractmethod","text":"

      REQUIRED

      This should return information about how to locate the environment or represent its ID in some way. Additionally, this is expected to return something even if the environment is incompatible.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef find(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should return information about how to locate the environment or represent its ID in\n    some way. Additionally, this is expected to return something even if the environment is\n    [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.create","title":"create() abstractmethod","text":"

      REQUIRED

      This should perform the necessary steps to set up the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef create(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should perform the necessary steps to set up the environment.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.remove","title":"remove() abstractmethod","text":"

      REQUIRED

      This should perform the necessary steps to completely remove the environment from the system and will only be triggered manually by users with the env remove or env prune commands.

      If the build environment has a caching mechanism, this should remove that as well.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef remove(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should perform the necessary steps to completely remove the environment from the system and will only\n    be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n    [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n\n    If the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    has a caching mechanism, this should remove that as well.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.exists","title":"exists() -> bool abstractmethod","text":"

      REQUIRED

      This should indicate whether or not the environment has already been created.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef exists(self) -> bool:\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should indicate whether or not the environment has already been created.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project","title":"install_project() abstractmethod","text":"

      REQUIRED

      This should install the project in the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef install_project(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the project in the environment.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project_dev_mode","title":"install_project_dev_mode() abstractmethod","text":"

      REQUIRED

      This should install the project in the environment such that the environment always reflects the current state of the project.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef install_project_dev_mode(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the project in the environment such that the environment\n    always reflects the current state of the project.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync","title":"dependencies_in_sync() -> bool abstractmethod","text":"

      REQUIRED

      This should indicate whether or not the environment is compatible with the current dependencies.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef dependencies_in_sync(self) -> bool:\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should indicate whether or not the environment is compatible with the current\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies","title":"sync_dependencies() abstractmethod","text":"

      REQUIRED

      This should install the dependencies in the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef sync_dependencies(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n    in the environment.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependency_hash","title":"dependency_hash()","text":"

      This should return a hash of the environment's dependencies and any other data that is handled by the sync_dependencies and dependencies_in_sync methods.

      Source code in src/hatch/env/plugin/interface.py
      def dependency_hash(self):\n    \"\"\"\n    This should return a hash of the environment's\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n    and any other data that is handled by the\n    [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n    and\n    [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n    methods.\n    \"\"\"\n    from hatch.utils.dep import hash_dependencies\n\n    return hash_dependencies(self.dependencies_complex)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.build_environment","title":"build_environment(dependencies: list[str])","text":"

      This should set up an isolated environment in which to build the project given a set of dependencies and must be a context manager:

      with environment.build_environment([...]): ...\n

      The build environment should reflect any environment variables the user defined either currently or at the time of creation.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef build_environment(\n    self,\n    dependencies: list[str],  # noqa: ARG002\n):\n    \"\"\"\n    This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project\n    given a set of dependencies and must be a context manager:\n\n    ```python\n    with environment.build_environment([...]): ...\n    ```\n\n    The build environment should reflect any\n    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n    the user defined either currently or at the time of\n    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n    \"\"\"\n    with self.get_env_vars():\n        yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.build_environment_exists","title":"build_environment_exists()","text":"

      If the build environment has a caching mechanism, this should indicate whether or not it has already been created.

      Source code in src/hatch/env/plugin/interface.py
      def build_environment_exists(self):  # noqa: PLR6301\n    \"\"\"\n    If the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    has a caching mechanism, this should indicate whether or not it has already been created.\n    \"\"\"\n    return False\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.run_builder","title":"run_builder(build_environment, **kwargs)","text":"

      This will be called when the build environment is active:

      with environment.build_environment([...]) as build_env:\n    process = environment.run_builder(build_env, ...)\n

      This should return the standard library's subprocess.CompletedProcess. The command is constructed by passing all keyword arguments to construct_build_command.

      For an example, open the default implementation below:

      Source code in src/hatch/env/plugin/interface.py
      def run_builder(\n    self,\n    build_environment,  # noqa: ARG002\n    **kwargs,\n):\n    \"\"\"\n    This will be called when the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    is active:\n\n    ```python\n    with environment.build_environment([...]) as build_env:\n        process = environment.run_builder(build_env, ...)\n    ```\n\n    This should return the standard library's\n    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).\n    The command is constructed by passing all keyword arguments to\n    [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).\n\n    For an example, open the default implementation below:\n    \"\"\"\n    return self.platform.run_command(self.construct_build_command(**kwargs))\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command","title":"construct_build_command(*, directory=None, targets=(), hooks_only=False, no_hooks=False, clean=False, clean_hooks_after=False, clean_only=False)","text":"

      This is the canonical way build command options are translated to a subprocess command issued to builders.

      Source code in src/hatch/env/plugin/interface.py
      def construct_build_command(  # noqa: PLR6301\n    self,\n    *,\n    directory=None,\n    targets=(),\n    hooks_only=False,\n    no_hooks=False,\n    clean=False,\n    clean_hooks_after=False,\n    clean_only=False,\n):\n    \"\"\"\n    This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to\n    a subprocess command issued to [builders](../builder/reference.md).\n    \"\"\"\n    command = ['python', '-u', '-m', 'hatchling', 'build']\n\n    if directory:\n        command.extend(('--directory', directory))\n\n    if targets:\n        for target in targets:\n            command.extend(('--target', target))\n\n    if hooks_only:\n        command.append('--hooks-only')\n\n    if no_hooks:\n        command.append('--no-hooks')\n\n    if clean:\n        command.append('--clean')\n\n    if clean_hooks_after:\n        command.append('--clean-hooks-after')\n\n    if clean_only:\n        command.append('--clean-only')\n\n    return command\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.command_context","title":"command_context()","text":"

      A context manager that when active should make executed shell commands reflect any environment variables the user defined either currently or at the time of creation.

      For an example, open the default implementation below:

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef command_context(self):\n    \"\"\"\n    A context manager that when active should make executed shell commands reflect any\n    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n    the user defined either currently or at the time of\n    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n    For an example, open the default implementation below:\n    \"\"\"\n    with self.get_env_vars():\n        yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.enter_shell","title":"enter_shell(name: str, path: str, args: Iterable[str])","text":"

      Spawn a shell within the environment.

      This should either use command_context directly or provide the same guarantee.

      Source code in src/hatch/env/plugin/interface.py
      def enter_shell(\n    self,\n    name: str,  # noqa: ARG002\n    path: str,\n    args: Iterable[str],\n):\n    \"\"\"\n    Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n    This should either use\n    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n    directly or provide the same guarantee.\n    \"\"\"\n    with self.command_context():\n        self.platform.exit_with_command([path, *args])\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.run_shell_command","title":"run_shell_command(command: str, **kwargs)","text":"

      This should return the standard library's subprocess.CompletedProcess and will always be called when the command_context is active, with the expectation of providing the same guarantee.

      Source code in src/hatch/env/plugin/interface.py
      def run_shell_command(self, command: str, **kwargs):\n    \"\"\"\n    This should return the standard library's\n    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n    and will always be called when the\n    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n    is active, with the expectation of providing the same guarantee.\n    \"\"\"\n    kwargs.setdefault('shell', True)\n    return self.platform.run_command(command, **kwargs)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.resolve_commands","title":"resolve_commands(commands: list[str])","text":"

      This expands each command into one or more commands based on any scripts that the user defined.

      Source code in src/hatch/env/plugin/interface.py
      def resolve_commands(self, commands: list[str]):\n    \"\"\"\n    This expands each command into one or more commands based on any\n    [scripts](../../config/environment/overview.md#scripts) that the user defined.\n    \"\"\"\n    for command in commands:\n        yield from self.expand_command(command)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars","title":"get_env_vars() -> EnvVars","text":"

      Returns a mapping of environment variables that should be available to the environment. The object can be used as a context manager to temporarily apply the environment variables to the current process.

      Note

      The environment variable HATCH_ENV_ACTIVE will always be set to the name of the environment.

      Source code in src/hatch/env/plugin/interface.py
      def get_env_vars(self) -> EnvVars:\n    \"\"\"\n    Returns a mapping of environment variables that should be available to the environment. The object can\n    be used as a context manager to temporarily apply the environment variables to the current process.\n\n    !!! note\n        The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n    \"\"\"\n    return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.apply_features","title":"apply_features(requirement: str)","text":"

      A convenience method that applies any user defined features to the given requirement.

      Source code in src/hatch/env/plugin/interface.py
      def apply_features(self, requirement: str):\n    \"\"\"\n    A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n    to the given requirement.\n    \"\"\"\n    if self.features:\n        features = ','.join(self.features)\n        return f'{requirement}[{features}]'\n\n    return requirement\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.construct_pip_install_command","title":"construct_pip_install_command(args: list[str])","text":"

      A convenience method for constructing a pip install command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.

      Source code in src/hatch/env/plugin/interface.py
      def construct_pip_install_command(self, args: list[str]):\n    \"\"\"\n    A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n    command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n    \"\"\"\n    command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n    # Default to -1 verbosity\n    add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n    command.extend(args)\n    return command\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.join_command_args","title":"join_command_args(args: list[str])","text":"

      This is used by the run command to construct the root command string from the received arguments.

      Source code in src/hatch/env/plugin/interface.py
      def join_command_args(self, args: list[str]):\n    \"\"\"\n    This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n    from the received arguments.\n    \"\"\"\n    return self.platform.join_command_args(args)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility","title":"check_compatibility()","text":"

      This raises an exception if the environment is not compatible with the user's setup. The default behavior checks for platform compatibility and any method override should keep this check.

      This check is never performed if the environment has been created.

      Source code in src/hatch/env/plugin/interface.py
      def check_compatibility(self):\n    \"\"\"\n    This raises an exception if the environment is not compatible with the user's setup. The default behavior\n    checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n    and any method override should keep this check.\n\n    This check is never performed if the environment has been\n    [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n    \"\"\"\n    if self.platforms and self.platform.name not in self.platforms:\n        message = 'unsupported platform'\n        raise OSError(message)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_option_types","title":"get_option_types() -> dict staticmethod","text":"

      Returns a mapping of supported options to their respective types so that they can be used by overrides.

      Source code in src/hatch/env/plugin/interface.py
      @staticmethod\ndef get_option_types() -> dict:\n    \"\"\"\n    Returns a mapping of supported options to their respective types so that they can be used by\n    [overrides](../../config/environment/advanced.md#option-overrides).\n    \"\"\"\n    return {}\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_var_option","title":"get_env_var_option(option: str) -> str","text":"

      Returns the value of the upper-cased environment variable HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>.

      Source code in src/hatch/env/plugin/interface.py
      def get_env_var_option(self, option: str) -> str:\n    \"\"\"\n    Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n    \"\"\"\n    return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_context","title":"get_context()","text":"

      Returns a subclass of EnvironmentContextFormatter.

      Source code in src/hatch/env/plugin/interface.py
      def get_context(self):\n    \"\"\"\n    Returns a subclass of\n    [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n    \"\"\"\n    from hatch.env.context import EnvironmentContextFormatter\n\n    return EnvironmentContextFormatter(self)\n
      "},{"location":"plugins/environment/virtual/","title":"Virtual environment","text":"

      This uses virtual environments backed by the standard virtualenv tool.

      "},{"location":"plugins/environment/virtual/#configuration","title":"Configuration","text":"

      The environment plugin name is virtual.

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\ntype = \"virtual\"\n
      [envs.<ENV_NAME>]\ntype = \"virtual\"\n
      "},{"location":"plugins/environment/virtual/#options","title":"Options","text":"Option Default Description python The version of Python to find on your system and subsequently use to create the environment, defaulting to the HATCH_PYTHON environment variable, followed by the normal resolution logic. Setting the HATCH_PYTHON environment variable to self will force the use of the Python executable Hatch is running on. For more information, see the documentation. python-sources ['external', 'internal'] This may be set to an array of strings that are either the literal internal or external. External considers only Python executables that are already on PATH. Internal considers only internally managed Python distributions. path An explicit path to the virtual environment. The path may be absolute or relative to the project root. Any environments that inherit this option will also use this path. The environment variable HATCH_ENV_TYPE_VIRTUAL_PATH may be used, which will take precedence. system-packages false Whether or not to give the virtual environment access to the system site-packages directory"},{"location":"plugins/environment/virtual/#location","title":"Location","text":"

      The location of environments is determined in the following heuristic order:

      1. The path option
      2. A directory named after the environment within the configured virtual environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
      3. Otherwise, environments are stored within the configured virtual environment directory in a deeply nested structure in order to support multiple projects

      Additionally, when the path option is not used, the name of the directory for the default environment will be the normalized project name to provide a more meaningful default shell prompt.

      "},{"location":"plugins/environment/virtual/#python-resolution","title":"Python resolution","text":"

      Virtual environments necessarily require a parent installation of Python. The following rules determine how the parent is resolved.

      The Python choice is determined by the python option followed by the HATCH_PYTHON environment variable. If the choice is via the environment variable, then resolution stops and that path is used unconditionally.

      The resolvers will be based on the python-sources option and all resolved interpreters will ensure compatibility with the project's defined Python support.

      If a Python version has been chosen then each resolver will try to find an interpreter that satisfies that version.

      If no version has been chosen, then each resolver will try to find a version that matches the version of Python that Hatch is currently running on. If not found then each resolver will try to find the highest compatible version.

      Note

      Some external Python paths are considered unstable and are ignored during resolution. For example, if Hatch is installed via Homebrew then sys.executable will be ignored because the interpreter could change or be removed at any time.

      Note

      When resolution finds a match using an internally managed distribution and an update is available, the latest distribution will automatically be downloaded before environment creation.

      "},{"location":"plugins/environment/virtual/#internal-distributions","title":"Internal distributions","text":"

      The following options are recognized for internal Python resolution.

      "},{"location":"plugins/environment/virtual/#cpython","title":"CPython","text":"ID 3.7 3.8 3.9 3.10 3.11 3.12

      The source of distributions is the python-build-standalone project.

      Some distributions have variants that may be configured with the HATCH_PYTHON_VARIANT_<PLATFORM> environment variable where <PLATFORM> is the uppercase version of one of the following:

      Platform Options Linux
      • v1
      • v2
      • v3 (default)
      • v4
      Windows
      • shared (default)
      • static
      "},{"location":"plugins/environment/virtual/#pypy","title":"PyPy","text":"ID pypy2.7 pypy3.9 pypy3.10

      The source of distributions is the PyPy project.

      "},{"location":"plugins/environment/virtual/#troubleshooting","title":"Troubleshooting","text":""},{"location":"plugins/environment/virtual/#macos-sip","title":"macOS SIP","text":"

      If you need to set linker environment variables like those starting with DYLD_ or LD_, any executable secured by System Integrity Protection that is invoked when running commands will not see those environment variable modifications as macOS strips those.

      Hatch interprets such commands as shell commands but deliberately ignores such paths to protected shells. This workaround suffices for the majority of use cases but there are 2 situations in which it may not:

      1. There are no unprotected sh, bash, zsh, nor fish executables found along PATH.
      2. The desired executable is a project's script, and the location of environments contains spaces or is longer than 1241 characters. In this case pip and other installers will create such an entry point with a shebang pointing to /bin/sh (which is protected) to avoid shebang limitations. Rather than changing the location, you could invoke the script as e.g. python -m pytest (if the project supports that method of invocation by shipping a __main__.py).
      1. The shebang length limit is usually 127 but 3 characters surround the executable path: #!<EXE_PATH>\\n \u21a9

      "},{"location":"plugins/environment-collector/custom/","title":"Custom environment collector","text":"

      This is a custom class in a given Python file that inherits from the EnvironmentCollectorInterface.

      "},{"location":"plugins/environment-collector/custom/#configuration","title":"Configuration","text":"

      The environment collector plugin name is custom.

      pyproject.toml hatch.toml
      [tool.hatch.env.collectors.custom]\n
      [env.collectors.custom]\n
      "},{"location":"plugins/environment-collector/custom/#options","title":"Options","text":"Option Default Description path hatch_plugins.py The path of the Python file"},{"location":"plugins/environment-collector/custom/#example","title":"Example","text":"hatch_plugins.py
          from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n    class CustomEnvironmentCollector(EnvironmentCollectorInterface):\n        ...\n

      If multiple subclasses are found, you must define a function named get_environment_collector that returns the desired environment collector.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      "},{"location":"plugins/environment-collector/default/","title":"Default environment collector","text":"

      This adds the default environment with type set to virtual and will always be applied.

      "},{"location":"plugins/environment-collector/default/#configuration","title":"Configuration","text":"

      The environment collector plugin name is default.

      pyproject.toml hatch.toml
      [tool.hatch.env.collectors.default]\n
      [env.collectors.default]\n
      "},{"location":"plugins/environment-collector/default/#options","title":"Options","text":"

      There are no options available currently.

      "},{"location":"plugins/environment-collector/reference/","title":"Environment collector plugins","text":"

      Environment collectors allow for dynamically modifying environments or adding environments beyond those defined in config. Users can override default values provided by each environment.

      "},{"location":"plugins/environment-collector/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-mkdocs - integrate MkDocs and infer dependencies into an env
      "},{"location":"plugins/environment-collector/reference/#installation","title":"Installation","text":"

      Any required environment collectors that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

      pyproject.toml hatch.toml
      [tool.hatch.env]\nrequires = [\n  \"...\",\n]\n
      [env]\nrequires = [\n  \"...\",\n]\n
      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface","title":"EnvironmentCollectorInterface","text":"

      Example usage:

      plugin.py hooks.py
          from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n    class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
          from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialEnvironmentCollector\n\n\n    @hookimpl\n    def hatch_register_environment_collector():\n        return SpecialEnvironmentCollector\n
      Source code in src/hatch/env/collectors/plugin/interface.py
      class EnvironmentCollectorInterface:\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n        class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialEnvironmentCollector\n\n\n        @hookimpl\n        def hatch_register_environment_collector():\n            return SpecialEnvironmentCollector\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root, config):\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.env.collectors.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    def get_initial_config(self) -> dict[str, dict]:  # noqa: PLR6301\n        \"\"\"\n        Returns configuration for environments keyed by the environment or matrix name.\n        \"\"\"\n        return {}\n\n    def finalize_config(self, config: dict[str, dict]):\n        \"\"\"\n        Finalizes configuration for environments keyed by the environment or matrix name. This will override\n        any user-defined settings and any collectors that ran before this call.\n\n        This is called before matrices are turned into concrete environments.\n        \"\"\"\n\n    def finalize_environments(self, config: dict[str, dict]):\n        \"\"\"\n        Finalizes configuration for environments keyed by the environment name. This will override\n        any user-defined settings and any collectors that ran before this call.\n\n        This is called after matrices are turned into concrete environments.\n        \"\"\"\n
      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.root","title":"root property","text":"

      The root of the project tree as a path-like object.

      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.env.collectors.<PLUGIN_NAME>]\n
      [env.collectors.<PLUGIN_NAME>]\n
      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.get_initial_config","title":"get_initial_config() -> dict[str, dict]","text":"

      Returns configuration for environments keyed by the environment or matrix name.

      Source code in src/hatch/env/collectors/plugin/interface.py
      def get_initial_config(self) -> dict[str, dict]:  # noqa: PLR6301\n    \"\"\"\n    Returns configuration for environments keyed by the environment or matrix name.\n    \"\"\"\n    return {}\n
      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_config","title":"finalize_config(config: dict[str, dict])","text":"

      Finalizes configuration for environments keyed by the environment or matrix name. This will override any user-defined settings and any collectors that ran before this call.

      This is called before matrices are turned into concrete environments.

      Source code in src/hatch/env/collectors/plugin/interface.py
      def finalize_config(self, config: dict[str, dict]):\n    \"\"\"\n    Finalizes configuration for environments keyed by the environment or matrix name. This will override\n    any user-defined settings and any collectors that ran before this call.\n\n    This is called before matrices are turned into concrete environments.\n    \"\"\"\n
      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_environments","title":"finalize_environments(config: dict[str, dict])","text":"

      Finalizes configuration for environments keyed by the environment name. This will override any user-defined settings and any collectors that ran before this call.

      This is called after matrices are turned into concrete environments.

      Source code in src/hatch/env/collectors/plugin/interface.py
      def finalize_environments(self, config: dict[str, dict]):\n    \"\"\"\n    Finalizes configuration for environments keyed by the environment name. This will override\n    any user-defined settings and any collectors that ran before this call.\n\n    This is called after matrices are turned into concrete environments.\n    \"\"\"\n
      "},{"location":"plugins/metadata-hook/custom/","title":"Custom metadata hook","text":"

      This is a custom class in a given Python file that inherits from the MetadataHookInterface.

      "},{"location":"plugins/metadata-hook/custom/#configuration","title":"Configuration","text":"

      The metadata hook plugin name is custom.

      pyproject.toml hatch.toml
      [tool.hatch.metadata.hooks.custom]\n
      [metadata.hooks.custom]\n
      "},{"location":"plugins/metadata-hook/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/metadata-hook/custom/#example","title":"Example","text":"hatch_build.py
          from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\n    class CustomMetadataHook(MetadataHookInterface):\n        ...\n

      If multiple subclasses are found, you must define a function named get_metadata_hook that returns the desired build hook.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      "},{"location":"plugins/metadata-hook/reference/","title":"Metadata hook plugins","text":"

      Metadata hooks allow for the modification of project metadata after it has been loaded.

      "},{"location":"plugins/metadata-hook/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-docstring-description - set the project description using docstrings
      • hatch-fancy-pypi-readme - dynamically construct the README
      • hatch-nodejs-version - uses fields from NodeJS package.json files
      • hatch-odoo - determine dependencies based on manifests of Odoo add-ons
      • hatch-requirements-txt - read project dependencies from requirements.txt files
      • UniDep - for unified pip and conda dependency management using a single requirements.yaml file for both
      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface","title":"MetadataHookInterface","text":"

      Example usage:

      plugin.py hooks.py
      from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass SpecialMetadataHook(MetadataHookInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialMetadataHook\n\n\n@hookimpl\ndef hatch_register_metadata_hook():\n    return SpecialMetadataHook\n
      Source code in backend/src/hatchling/metadata/plugin/interface.py
      class MetadataHookInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\n    class SpecialMetadataHook(MetadataHookInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialMetadataHook\n\n\n    @hookimpl\n    def hatch_register_metadata_hook():\n        return SpecialMetadataHook\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        The hook configuration.\n\n        ```toml config-example\n        [tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def update(self, metadata: dict) -> None:\n        \"\"\"\n        This updates the metadata mapping of the `project` table in-place.\n        \"\"\"\n\n    def get_known_classifiers(self) -> list[str]:  # noqa: PLR6301\n        \"\"\"\n        This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n        \"\"\"\n        return []\n
      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.root","title":"root: str property","text":"

      The root of the project tree.

      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.config","title":"config: dict property","text":"

      The hook configuration.

      pyproject.toml hatch.toml
      [tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n
      [metadata.hooks.<PLUGIN_NAME>]\n
      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.update","title":"update(metadata: dict) -> None abstractmethod","text":"

      This updates the metadata mapping of the project table in-place.

      Source code in backend/src/hatchling/metadata/plugin/interface.py
      @abstractmethod\ndef update(self, metadata: dict) -> None:\n    \"\"\"\n    This updates the metadata mapping of the `project` table in-place.\n    \"\"\"\n
      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.get_known_classifiers","title":"get_known_classifiers() -> list[str]","text":"

      This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.

      Source code in backend/src/hatchling/metadata/plugin/interface.py
      def get_known_classifiers(self) -> list[str]:  # noqa: PLR6301\n    \"\"\"\n    This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n    \"\"\"\n    return []\n
      "},{"location":"plugins/publisher/package-index/","title":"Index publisher","text":"

      See the documentation for publishing.

      "},{"location":"plugins/publisher/package-index/#configuration","title":"Configuration","text":"

      The publisher plugin name is index.

      config.toml
      [publish.index]\n
      "},{"location":"plugins/publisher/package-index/#options","title":"Options","text":"Flag Config name Description -r/--repo repo The repository with which to publish artifacts -u/--user user The user with which to authenticate -a/--auth auth The credentials to use for authentication --ca-cert ca-cert The path to a CA bundle --client-cert client-cert The path to a client certificate, optionally containing the private key --client-key client-key The path to the client certificate's private key repos A table of named repositories to their respective options"},{"location":"plugins/publisher/package-index/#repositories","title":"Repositories","text":"

      All top-level options can be overridden per repository using the repos table with a required url attribute for each repository. The following shows the default configuration:

      config.toml
      [publish.index.repos.main]\nurl = \"https://upload.pypi.org/legacy/\"\n\n[publish.index.repos.test]\nurl = \"https://test.pypi.org/legacy/\"\n

      The repo and repos options have no effect.

      "},{"location":"plugins/publisher/reference/","title":"Publisher plugins","text":""},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface","title":"PublisherInterface","text":"

      Example usage:

      plugin.py hooks.py
          from hatch.publish.plugin.interface import PublisherInterface\n\n\n    class SpecialPublisher(PublisherInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
          from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialPublisher\n\n\n    @hookimpl\n    def hatch_register_publisher():\n        return SpecialPublisher\n
      Source code in src/hatch/publish/plugin/interface.py
      class PublisherInterface(ABC):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.publish.plugin.interface import PublisherInterface\n\n\n        class SpecialPublisher(PublisherInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialPublisher\n\n\n        @hookimpl\n        def hatch_register_publisher():\n            return SpecialPublisher\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, app, root, cache_dir, project_config, plugin_config):\n        self.__app = app\n        self.__root = root\n        self.__cache_dir = cache_dir\n        self.__project_config = project_config\n        self.__plugin_config = plugin_config\n\n        self.__disable = None\n\n    @property\n    def app(self):\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        return self.__app\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def cache_dir(self):\n        \"\"\"\n        The directory reserved exclusively for this plugin as a path-like object.\n        \"\"\"\n        return self.__cache_dir\n\n    @property\n    def project_config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.publish.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__project_config\n\n    @property\n    def plugin_config(self) -> dict:\n        \"\"\"\n        This is defined in Hatch's [config file](../../config/hatch.md).\n\n        ```toml tab=\"config.toml\"\n        [publish.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__plugin_config\n\n    @property\n    def disable(self):\n        \"\"\"\n        Whether this plugin is disabled, thus requiring confirmation when publishing. Local\n        [project configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.project_config)\n        takes precedence over global\n        [plugin configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.plugin_config).\n        \"\"\"\n        if self.__disable is None:\n            if 'disable' in self.project_config:\n                disable = self.project_config['disable']\n                if not isinstance(disable, bool):\n                    message = f'Field `tool.hatch.publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n                    raise TypeError(message)\n            else:\n                disable = self.plugin_config.get('disable', False)\n                if not isinstance(disable, bool):\n                    message = f'Global plugin configuration `publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n                    raise TypeError(message)\n\n            self.__disable = disable\n\n        return self.__disable\n\n    @abstractmethod\n    def publish(self, artifacts: list[str], options: dict):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n        with the arguments and options it receives.\n        \"\"\"\n
      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.app","title":"app property","text":"

      An instance of Application.

      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.root","title":"root property","text":"

      The root of the project tree as a path-like object.

      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.cache_dir","title":"cache_dir property","text":"

      The directory reserved exclusively for this plugin as a path-like object.

      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.project_config","title":"project_config: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.publish.<PLUGIN_NAME>]\n
      [publish.<PLUGIN_NAME>]\n
      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.plugin_config","title":"plugin_config: dict property","text":"

      This is defined in Hatch's config file.

      config.toml
      [publish.<PLUGIN_NAME>]\n
      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.disable","title":"disable property","text":"

      Whether this plugin is disabled, thus requiring confirmation when publishing. Local project configuration takes precedence over global plugin configuration.

      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.publish","title":"publish(artifacts: list[str], options: dict) abstractmethod","text":"

      REQUIRED

      This is called directly by the publish command with the arguments and options it receives.

      Source code in src/hatch/publish/plugin/interface.py
      @abstractmethod\ndef publish(self, artifacts: list[str], options: dict):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n    with the arguments and options it receives.\n    \"\"\"\n
      "},{"location":"plugins/version-scheme/reference/","title":"Version scheme plugins","text":""},{"location":"plugins/version-scheme/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-semver - uses semantic versioning
      "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface","title":"VersionSchemeInterface","text":"

      Example usage:

      plugin.py hooks.py
      from hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\nclass SpecialVersionScheme(VersionSchemeInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionScheme\n\n\n@hookimpl\ndef hatch_register_version_scheme():\n    return SpecialVersionScheme\n
      Source code in backend/src/hatchling/version/scheme/plugin/interface.py
      class VersionSchemeInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\n    class SpecialVersionScheme(VersionSchemeInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialVersionScheme\n\n\n    @hookimpl\n    def hatch_register_version_scheme():\n        return SpecialVersionScheme\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree as a string.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.version]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n        \"\"\"\n        This should return a normalized form of the desired version and verify that it\n        is higher than the original version.\n        \"\"\"\n
      "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.root","title":"root: str property","text":"

      The root of the project tree as a string.

      "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.version]\n
      [version]\n
      "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.update","title":"update(desired_version: str, original_version: str, version_data: dict) -> str abstractmethod","text":"

      This should return a normalized form of the desired version and verify that it is higher than the original version.

      Source code in backend/src/hatchling/version/scheme/plugin/interface.py
      @abstractmethod\ndef update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n    \"\"\"\n    This should return a normalized form of the desired version and verify that it\n    is higher than the original version.\n    \"\"\"\n
      "},{"location":"plugins/version-scheme/standard/","title":"Standard version scheme","text":"

      See the documentation for versioning.

      "},{"location":"plugins/version-scheme/standard/#configuration","title":"Configuration","text":"

      The version scheme plugin name is standard.

      pyproject.toml hatch.toml
      [tool.hatch.version]\nscheme = \"standard\"\n
      [version]\nscheme = \"standard\"\n
      "},{"location":"plugins/version-scheme/standard/#options","title":"Options","text":"Option Description validate-bump When setting a specific version, this determines whether to check that the new version is higher than the original. The default is true."},{"location":"plugins/version-source/code/","title":"Code version source","text":""},{"location":"plugins/version-source/code/#updates","title":"Updates","text":"

      Setting the version is not supported.

      "},{"location":"plugins/version-source/code/#configuration","title":"Configuration","text":"

      The version source plugin name is code.

      pyproject.toml hatch.toml
      [tool.hatch.version]\nsource = \"code\"\n
      [version]\nsource = \"code\"\n
      "},{"location":"plugins/version-source/code/#options","title":"Options","text":"Option Description path (required) A relative path to a Python file or extension module that will be loaded expression A Python expression that when evaluated in the context of the loaded file returns the version. The default expression is simply __version__. search-paths A list of relative paths to directories that will be prepended to Python's search path"},{"location":"plugins/version-source/code/#missing-imports","title":"Missing imports","text":"

      If the chosen path imports another module in your project, then you'll need to use absolute imports coupled with the search-paths option. For example, say you need to load the following file:

      src/pkg/__init__.py
          from ._version import get_version\n\n    __version__ = get_version()\n

      You should change it to:

      src/pkg/__init__.py
          from pkg._version import get_version\n\n    __version__ = get_version()\n

      and the configuration would become:

      pyproject.toml hatch.toml
      [tool.hatch.version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
      [version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
      "},{"location":"plugins/version-source/env/","title":"Environment version source","text":"

      Retrieves the version from an environment variable. This can be useful in build pipelines where the version is set by an external trigger.

      "},{"location":"plugins/version-source/env/#updates","title":"Updates","text":"

      Setting the version is not supported.

      "},{"location":"plugins/version-source/env/#configuration","title":"Configuration","text":"

      The version source plugin name is env.

      pyproject.toml hatch.toml
      [tool.hatch.version]\nsource = \"env\"\n
      [version]\nsource = \"env\"\n
      "},{"location":"plugins/version-source/env/#options","title":"Options","text":"Option Description variable (required) The name of the environment variable"},{"location":"plugins/version-source/reference/","title":"Version source plugins","text":""},{"location":"plugins/version-source/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-vcs - uses your preferred version control system (like Git)
      • hatch-nodejs-version - uses the version field of NodeJS package.json files
      • hatch-regex-commit - automatically creates a Git commit and tag after version bumping
      • versioningit - determines version from Git or Mercurial tags, with customizable version formatting
      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface","title":"VersionSourceInterface","text":"

      Example usage:

      plugin.py hooks.py
      from hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\nclass SpecialVersionSource(VersionSourceInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionSource\n\n\n@hookimpl\ndef hatch_register_version_source():\n    return SpecialVersionSource\n
      Source code in backend/src/hatchling/version/source/plugin/interface.py
      class VersionSourceInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\n    class SpecialVersionSource(VersionSourceInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialVersionSource\n\n\n    @hookimpl\n    def hatch_register_version_source():\n        return SpecialVersionSource\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree as a string.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.version]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def get_version_data(self) -> dict:\n        \"\"\"\n        This should return a mapping with a `version` key representing the current version of the project and will be\n        displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n        The mapping can contain anything else and will be passed to\n        [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n        when updating the version.\n        \"\"\"\n\n    def set_version(self, version: str, version_data: dict) -> None:\n        \"\"\"\n        This should update the version to the first argument with the data provided during retrieval.\n        \"\"\"\n        raise NotImplementedError\n
      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.root","title":"root: str property","text":"

      The root of the project tree as a string.

      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.version]\n
      [version]\n
      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.get_version_data","title":"get_version_data() -> dict abstractmethod","text":"

      This should return a mapping with a version key representing the current version of the project and will be displayed when invoking the version command without any arguments.

      The mapping can contain anything else and will be passed to set_version when updating the version.

      Source code in backend/src/hatchling/version/source/plugin/interface.py
      @abstractmethod\ndef get_version_data(self) -> dict:\n    \"\"\"\n    This should return a mapping with a `version` key representing the current version of the project and will be\n    displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n    The mapping can contain anything else and will be passed to\n    [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n    when updating the version.\n    \"\"\"\n
      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version","title":"set_version(version: str, version_data: dict) -> None","text":"

      This should update the version to the first argument with the data provided during retrieval.

      Source code in backend/src/hatchling/version/source/plugin/interface.py
      def set_version(self, version: str, version_data: dict) -> None:\n    \"\"\"\n    This should update the version to the first argument with the data provided during retrieval.\n    \"\"\"\n    raise NotImplementedError\n
      "},{"location":"plugins/version-source/regex/","title":"Regex version source","text":"

      See the documentation for versioning.

      "},{"location":"plugins/version-source/regex/#updates","title":"Updates","text":"

      Setting the version is supported.

      "},{"location":"plugins/version-source/regex/#configuration","title":"Configuration","text":"

      The version source plugin name is regex.

      pyproject.toml hatch.toml
      [tool.hatch.version]\nsource = \"regex\"\n
      [version]\nsource = \"regex\"\n
      "},{"location":"plugins/version-source/regex/#options","title":"Options","text":"Option Description path (required) A relative path to a file containing the project's version pattern A regular expression that has a named group called version that represents the version. The default pattern looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v."},{"location":"blog/archive/2023/","title":"2023","text":""},{"location":"blog/archive/2022/","title":"2022","text":""},{"location":"blog/category/release/","title":"Release","text":""}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Hatch","text":"CI/CD Docs Package Meta

      Hatch is a modern, extensible Python project manager. See the Why Hatch? page for more information.

      • Build system

        Reproducible builds by default with a rich ecosystem of plugins

        Configure builds

      • Environments

        Robust environment management with support for custom scripts

        Getting started

      • Python management

        Choose between easy manual installations or automatic as part of environments

        Try it

      • Static analysis

        Static analysis backed by Ruff with up-to-date, sane defaults

        Learn

      • Publishing

        Easily upload to PyPI or other indices

        See how

      • Versioning

        Streamlined workflow for bumping versions

        Managing versions

      • Project generation

        Create new projects from templates with known best practices

        Project setup

      • Responsive CLI

        Hatch is up to 3x faster than equivalent tools

        CLI reference

      "},{"location":"#license","title":"License","text":"

      Hatch is distributed under the terms of the MIT license.

      "},{"location":"#navigation","title":"Navigation","text":"

      Documentation for specific MAJOR.MINOR versions can be chosen by using the dropdown on the top of every page. The dev version reflects changes that have not yet been released.

      Also, desktop readers can use special keyboard shortcuts:

      Keys Action
      • , (comma)
      • p
      Navigate to the \"previous\" page
      • . (period)
      • n
      Navigate to the \"next\" page
      • /
      • s
      Display the search modal"},{"location":"build/","title":"Builds","text":""},{"location":"build/#configuration","title":"Configuration","text":"

      Builds are configured using the tool.hatch.build table. Every target is defined by a section within tool.hatch.build.targets, for example:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.sdist]\nexclude = [\n  \"/.github\",\n  \"/docs\",\n]\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
      [build.targets.sdist]\nexclude = [\n  \"/.github\",\n  \"/docs\",\n]\n\n[build.targets.wheel]\npackages = [\"src/foo\"]\n
      "},{"location":"build/#building","title":"Building","text":"

      Invoking the build command without any arguments will build the sdist and wheel targets:

      $ hatch build\n[sdist]\ndist/hatch_demo-1rc0.tar.gz\n\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n

      To only build specific targets, use the -t/--target option:

      $ hatch build -t wheel\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n

      If the target supports multiple versions, you can specify the exact versions to build by appending a colon followed by the desired versions separated by commas:

      $ hatch -v build -t wheel:standard\n[wheel]\nBuilding `wheel` version `standard`\ndist/hatch_demo-1rc0-py3-none-any.whl\n
      "},{"location":"build/#packaging-ecosystem","title":"Packaging ecosystem","text":"

      Hatch complies with modern Python packaging specs and therefore your projects can be used by other tools with Hatch serving as just the build backend.

      So you could use tox as an alternative to Hatch's environment management, or cibuildwheel to distribute packages for every platform, and they both will transparently use Hatch without any extra modification.

      "},{"location":"environment/","title":"Environments","text":"

      Environments are designed to allow for isolated workspaces for testing, building documentation, or anything else projects need.

      Unless an environment is chosen explicitly, Hatch will use the default environment.

      Tip

      For a more comprehensive walk-through, see the Basic usage tutorial.

      "},{"location":"environment/#creation","title":"Creation","text":"

      You can create environments by using the env create command. Let's enter the directory of the project we created in the setup phase:

      $ hatch env create\nCreating environment: default\nInstalling project in development mode\nSyncing dependencies\n

      Tip

      You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.

      "},{"location":"environment/#entering-environments","title":"Entering environments","text":"

      You can spawn a shell within an environment by using the shell command.

      $ hatch shell\n(hatch-demo) $\n

      Now confirm the project has been installed:

      (hatch-demo) $ pip show hatch-demo\nName: hatch-demo\nVersion: 0.0.1\n...\n

      Finally, see where your environment's Python is located:

      (hatch-demo) $ python -c \"import sys;print(sys.executable)\"\n...\n

      You can type exit to leave the environment.

      "},{"location":"environment/#command-execution","title":"Command execution","text":"

      The run command allows you to execute commands in an environment as if you had already entered it. For example, running the following command will output the same path as before:

      hatch run python -c \"import sys;print(sys.executable)\"\n
      "},{"location":"environment/#scripts","title":"Scripts","text":"

      You can also run any scripts that have been defined.

      You'll notice that in the pyproject.toml file there are already scripts defined in the default environment. Try running the test command, which invokes pytest with some default arguments:

      hatch run test\n

      All additional arguments are passed through to that script, so for example if you wanted to see the version of pytest and which plugins are installed you could do:

      hatch run test -VV\n
      "},{"location":"environment/#dependencies","title":"Dependencies","text":"

      Hatch ensures that environments are always compatible with the currently defined project dependencies (if installed and in dev mode) and environment dependencies.

      To add cowsay as a dependency, open pyproject.toml and add it to the dependencies array:

      pyproject.toml
      [project]\n...\ndependencies = [\n  \"cowsay\"\n]\n

      This dependency will be installed the next time you spawn a shell or run a command. For example:

      $ hatch run cowsay -t \"Hello, world!\"\nSyncing dependencies\n  _____________\n| Hello, world! |\n  =============\n             \\\n              \\\n                ^__^\n                (oo)\\_______\n                (__)\\       )\\/\\\n                    ||----w |\n                    ||     ||\n

      Note

      The Syncing dependencies status will display temporarily when Hatch updates environments in response to any dependency changes that you make.

      "},{"location":"environment/#selection","title":"Selection","text":"

      You can select which environment to enter or run commands in by using the -e/--env root option or by setting the HATCH_ENV environment variable.

      The run command allows for more explicit selection by prepending <ENV_NAME>: to commands. For example, if you had the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[tool.hatch.envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n
      [envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n

      you could then serve your documentation by running:

      hatch run docs:serve\n

      Tip

      If you've already entered an environment, commands will target it by default.

      "},{"location":"environment/#matrix","title":"Matrix","text":"

      Every environment can define its own set of matrices:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
      [envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n

      Using the env show command would then display:

      $ hatch env show --ascii\n     Standalone\n+---------+---------+\n| Name    | Type    |\n+=========+=========+\n| default | virtual |\n+---------+---------+\n                       Matrices\n+------+---------+---------------------+--------------+\n| Name | Type    | Envs                | Dependencies |\n+======+=========+=====================+==============+\n| test | virtual | test.py2.7-42       | pytest       |\n|      |         | test.py2.7-3.14     |              |\n|      |         | test.py3.8-42       |              |\n|      |         | test.py3.8-3.14     |              |\n|      |         | test.py3.8-9000-foo |              |\n|      |         | test.py3.8-9000-bar |              |\n|      |         | test.py3.9-9000-foo |              |\n|      |         | test.py3.9-9000-bar |              |\n+------+---------+---------------------+--------------+\n
      "},{"location":"environment/#removal","title":"Removal","text":"

      You can remove a single environment or environment matrix by using the env remove command or all of a project's environments by using the env prune command.

      "},{"location":"install/","title":"Installation","text":""},{"location":"install/#installers","title":"Installers","text":"macOSWindows GUI installerCommand line installer
      1. In your browser, download the .pkg file: hatch-1.9.1.pkg
      2. Run your downloaded file and follow the on-screen instructions.
      3. Restart your terminal.
      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version\n1.9.1\n
      1. Download the file using the curl command. The -o option specifies the file name that the downloaded package is written to. In this example, the file is written to hatch-1.9.1.pkg in the current directory.

        curl -o hatch-1.9.1.pkg https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1.pkg\n
      2. Run the standard macOS installer program, specifying the downloaded .pkg file as the source. Use the -pkg parameter to specify the name of the package to install, and the -target / parameter for the drive in which to install the package. The files are installed to /usr/local/hatch, and an entry is created at /etc/paths.d/hatch that instructs shells to add the /usr/local/hatch directory to. You must include sudo on the command to grant write permissions to those folders.

        sudo installer -pkg ./hatch-1.9.1.pkg -target /\n
      3. Restart your terminal.

      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version\n1.9.1\n
      GUI installerCommand line installer
      1. In your browser, download one the .msi files:
        • hatch-1.9.1-x64.msi
      2. Run your downloaded file and follow the on-screen instructions.
      3. Restart your terminal.
      4. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version\n1.9.1\n
      1. Download and run the installer using the standard Windows msiexec program, specifying one of the .msi files as the source. Use the /passive and /i parameters to request an unattended, normal installation.

        x64x86
        msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1-x64.msi\n
        msiexec /passive /i https://github.com/pypa/hatch/releases/download/hatch-v1.9.1/hatch-1.9.1-x86.msi\n
      2. Restart your terminal.

      3. To verify that the shell can find and run the hatch command in your PATH, use the following command.

        $ hatch --version\n1.9.1\n
      "},{"location":"install/#standalone-binaries","title":"Standalone binaries","text":"

      After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to hatch.

      LinuxmacOSWindows
      • hatch-1.9.1-aarch64-unknown-linux-gnu.tar.gz
      • hatch-1.9.1-x86_64-unknown-linux-gnu.tar.gz
      • hatch-1.9.1-x86_64-unknown-linux-musl.tar.gz
      • hatch-1.9.1-i686-unknown-linux-gnu.tar.gz
      • hatch-1.9.1-powerpc64le-unknown-linux-gnu.tar.gz
      • hatch-1.9.1-aarch64-apple-darwin.tar.gz
      • hatch-1.9.1-x86_64-apple-darwin.tar.gz
      • hatch-1.9.1-x86_64-pc-windows-msvc.zip
      • hatch-1.9.1-i686-pc-windows-msvc.zip
      "},{"location":"install/#pip","title":"pip","text":"

      Hatch is available on PyPI and can be installed with pip.

      pip install hatch\n

      Warning

      This method modifies the Python environment in which you choose to install. Consider instead using pipx to avoid dependency conflicts.

      "},{"location":"install/#pipx","title":"pipx","text":"

      pipx allows for the global installation of Python applications in isolated environments.

      pipx install hatch\n
      "},{"location":"install/#homebrew","title":"Homebrew","text":"

      See the formula for more details.

      brew install hatch\n
      "},{"location":"install/#conda","title":"Conda","text":"

      See the feedstock for more details.

      conda install -c conda-forge hatch\n

      or with mamba:

      mamba install hatch\n

      Warning

      This method modifies the Conda environment in which you choose to install. Consider instead using pipx or condax to avoid dependency conflicts.

      "},{"location":"install/#macports","title":"MacPorts","text":"

      See the port for more details.

      sudo port install hatch\n
      "},{"location":"install/#fedora","title":"Fedora","text":"

      The minimum supported version is 37, currently in development as Rawhide.

      sudo dnf install hatch\n
      "},{"location":"install/#void-linux","title":"Void Linux","text":"
      xbps-install hatch\n
      "},{"location":"install/#build-system-availability","title":"Build system availability","text":"

      Hatchling is Hatch's build backend which you will never need to install manually. See its changelog for version information.

      "},{"location":"intro/","title":"Introduction","text":""},{"location":"intro/#setup","title":"Setup","text":"

      Projects can be set up for use by Hatch using the new command.

      "},{"location":"intro/#new-project","title":"New project","text":"

      Let's say you want to create a project named Hatch Demo. You would run:

      hatch new \"Hatch Demo\"\n

      This would create the following structure in your current working directory:

      hatch-demo\n\u251c\u2500\u2500 src\n\u2502   \u2514\u2500\u2500 hatch_demo\n\u2502       \u251c\u2500\u2500 __about__.py\n\u2502       \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 tests\n\u2502   \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 LICENSE.txt\n\u251c\u2500\u2500 README.md\n\u2514\u2500\u2500 pyproject.toml\n

      Tip

      There are many ways to customize project generation.

      "},{"location":"intro/#existing-project","title":"Existing project","text":"

      To initialize an existing project, enter the directory containing the project and run the following:

      hatch new --init\n

      If your project has a setup.py file the command will automatically migrate setuptools configuration for you. Otherwise, this will interactively guide you through the setup process.

      "},{"location":"intro/#project-metadata","title":"Project metadata","text":"

      Next you'll want to define more of your project's metadata located in the pyproject.toml file. You can specify things like its license, the supported versions of Python, and URLs referring to various parts of your project, like documentation.

      "},{"location":"intro/#dependencies","title":"Dependencies","text":"

      The last step of the setup process is to define any dependencies that you'd like your project to begin with.

      "},{"location":"intro/#configuration","title":"Configuration","text":"

      All project-specific configuration recognized by Hatch can be defined in either the pyproject.toml file, or a file named hatch.toml where options are not contained within the tool.hatch table:

      pyproject.toml hatch.toml
      [tool.hatch]\noption = \"...\"\n\n[tool.hatch.table1]\noption = \"...\"\n\n[tool.hatch.table2]\noption = \"...\"\n
      option = \"...\"\n\n[table1]\noption = \"...\"\n\n[table2]\noption = \"...\"\n

      Top level keys in the latter file take precedence when defined in both.

      Tip

      If you want to make your file more compact, you can use dotted keys, turning the above example into:

      pyproject.toml hatch.toml
      [tool.hatch]\noption = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
      option = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
      "},{"location":"next-steps/","title":"Next steps","text":""},{"location":"next-steps/#learn-more","title":"Learn more","text":"

      At this point you should have a basic understanding of how to use Hatch.

      Now you may want to check out advanced configuration for environments or builds, set up your preferred shell, or read more about Hatch's CLI.

      After that, check out the Hatch Showcase project to see examples of what is possible.

      Finally, if you see a need, feel free to write a plugin for extended functionality.

      "},{"location":"next-steps/#community","title":"Community","text":"

      For any projects using Hatch, you may add its official badge somewhere prominent like the README.

      MarkdownreStructuredText
      [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)\n
      .. image:: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg\n   :alt: Hatch project\n   :target: https://github.com/pypa/hatch\n
      "},{"location":"publish/","title":"Publishing","text":"

      After your project is built, you can distribute it using the publish command.

      The -p/--publisher option controls which publisher to use, with the default being index.

      "},{"location":"publish/#artifact-selection","title":"Artifact selection","text":"

      By default, the dist directory located at the root of your project will be used:

      $ hatch publish\ndist/hatch_demo-1rc0-py3-none-any.whl ... success\ndist/hatch_demo-1rc0.tar.gz ... success\n\n[hatch-demo]\nhttps://pypi.org/project/hatch-demo/1rc0/\n

      You can instead pass specific paths as arguments:

      hatch publish /path/to/artifacts foo-1.tar.gz\n

      Only files ending with .whl or .tar.gz will be published.

      "},{"location":"publish/#further-resources","title":"Further resources","text":"

      Please refer to the publisher plugin reference for configuration options.

      There's a How-To on authentication and on options to select the target repository.

      The publish command is implemented as a built-in plugin, if you're planning your own plugin, read about the publisher plugin API.

      "},{"location":"version/","title":"Versioning","text":""},{"location":"version/#configuration","title":"Configuration","text":"

      When the version is not statically set, configuration is defined in the tool.hatch.version table. The source option determines the source to use for retrieving and updating the version. The regex source is used by default.

      The regex source requires an option path that represents a relative path to a file containing the project's version:

      pyproject.toml hatch.toml
      [tool.hatch.version]\npath = \"src/hatch_demo/__about__.py\"\n
      [version]\npath = \"src/hatch_demo/__about__.py\"\n

      The default pattern looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v.

      If this doesn't reflect how you store the version, you can define a different regular expression using the pattern option:

      pyproject.toml hatch.toml
      [tool.hatch.version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n
      [version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n

      The pattern must have a named group called version that represents the version.

      "},{"location":"version/#display","title":"Display","text":"

      Invoking the version command without any arguments will display the current version of the project:

      $ hatch version\n0.0.1\n
      "},{"location":"version/#updating","title":"Updating","text":"

      You can update the version like so:

      $ hatch version \"0.1.0\"\nOld: 0.0.1\nNew: 0.1.0\n

      The scheme option determines the scheme to use for parsing both the existing and new versions. The standard scheme is used by default, which is based on PEP 440.

      Rather than setting the version explicitly, you can select the name of a segment used to increment the version:

      $ hatch version minor\nOld: 0.1.0\nNew: 0.2.0\n

      You can chain multiple segment updates with a comma. For example, if you wanted to release a preview of your project's first major version, you could do:

      $ hatch version major,rc\nOld: 0.2.0\nNew: 1.0.0rc0\n

      When you want to release the final version, you would do:

      $ hatch version release\nOld: 1.0.0rc0\nNew: 1.0.0\n
      "},{"location":"version/#supported-segments","title":"Supported segments","text":"

      Here are the supported segments and how they would influence an existing version of 1.0.0:

      Segments New version release 1.0.0 major 2.0.0 minor 1.1.0 micropatchfix 1.0.1 aalpha 1.0.0a0 bbeta 1.0.0b0 crcprepreview 1.0.0rc0 rrevpost 1.0.0.post0 dev 1.0.0.dev0"},{"location":"why/","title":"Why Hatch?","text":"

      The high level value proposition of Hatch is that if one adopts all functionality then many other tools become unnecessary since there is support for everything one might require. Further, if one chooses to use only specific features then there are still benefits compared to alternatives.

      "},{"location":"why/#build-backend","title":"Build backend","text":"

      Hatchling, the build backend sister project, has many benefits compared to setuptools. Here we only compare setuptools as that is the one most people are familiar with.

      • Better defaults: The default behavior for setuptools is often not desirable for the average user.
        • For source distributions, setuptools has a custom enumeration of files that get included and excluded by default. Hatchling takes the defaults from your version control system such as Git's .gitignore file.
        • For wheels, setuptools attempts to find every directory that looks like a Python package. This is often undesirable as you might ship files to the end-user unintentionally such as test or tooling directories. Hatchling defaults to very specific inclusion based on the project name and errors if no heuristic is satisfied.
      • Ease of configurability: Hatchling was designed based on a history of significant challenges when configuring setuptools.
        • Hatchling uses the same glob pattern syntax as Git itself for every option which is what most users are familiar with. On the other hand, setuptools uses shell-style glob patterns for source distributions while wheels use a mix of shell-style globs and Python package syntax.
        • Configuring what gets included in source distributions requires a separate MANIFEST.in file. The custom syntax and directives must be learned and it is difficult knowing which options in the main files like setup.py influence the behavior and under what conditions. For Hatchling, everything gets configured in a single file under dedicated sections for specific targets like [tool.hatch.build.targets.wheel].
        • By default, non-Python files are excluded from wheels. Including such files requires usually verbose rules for every nested package directory. Hatchling makes no such distinction between file types and acts more like a general build system one might already be familiar with.
      • Editable installations: The default behavior of Hatchling allows for proper static analysis by external tools such as IDEs. With setuptools, you must provide additional configuration which means that by default, for example, you would not get autocompletion in Visual Studio Code. This is marked as a legacy feature and may in fact be removed in future versions of setuptools.
      • Reproducibility: Hatchling builds reproducible wheels and source distributions by default. setuptools does not support this for source distributions and there is no guarantee that wheels are reproducible.
      • Extensibility: Although it is possible to extend setuptools, the API is quite low level. Hatchling has the concept of plugins that are separated into discrete types and only expose what is necessary, leading to an easier developer experience.

      Why not?:

      If building extension modules is required then it is recommended that you continue using setuptools, or even other backends that specialize in interfacing with compilers.

      "},{"location":"why/#environment-management","title":"Environment management","text":"

      Here we compare to both tox and nox. At a high level, there are a few common advantages:

      • Python management: Hatch is able to automatically download Python distributions on the fly when specific versions that environments request cannot be found. The alternatives will raise an error, with the option to ignore unknown distributions.
      • Philosophy: In the alternatives, environments are for the most part treated as executable units where a dependency set is associated with an action. If you are familiar with container ecosystems, this would be like defining a CMD at the end of a Dockerfile but without the ability to change the action at runtime. This involves significant wasted disk space usually because one often requires slight modifications to the actions and therefore will define entirely different environments inherited from a base config just to perform different logic. Additionally, this can be confusing to users not just configuration-wise but also for execution of the different environments.

        In Hatch, environments are treated as isolated areas where you can execute arbitrary commands at runtime. For example, you can define a single test environment with named scripts that runs unit vs non-unit tests, each command being potentially very long but named however you wish so you get to control the interface. Since environments are treated as places where work is performed, you can also spawn a shell into any which will execute a subprocess that automatically drops into your shell of choice. Your shell will be configured appropriately like python on PATH being updated and the prompt being changed to reflect the chosen environment.

      • Configuration:

        • tox only supports INI configuration and if one desires putting that in the standard pyproject.toml file then it must be a multi-line string containing the INI config which would preclude syntax highlighting. Hatch allows for TOML-based config just like most other tools in the Python ecosystem.
        • nox config is defined in Python which often leads to increased verbosity and makes it challenging to onboard folks compared to a standardized format with known behaviors.
      • Extensibility:
        • tox allows for extending most aspects of its functionality however the API is so low-level and attached to internals that creating plugins may be challenging. For example, here is a tox plugin that was migrated to an equivalent Hatch environment collector plugin.
        • nox is configured with Python so for the local project you can do whatever you want, however there is no concept of third-party plugins per se. To achieve that, you must usually use a package that wraps nox and use that package's imports instead (example).

      Why not?:

      If you are using nox and you wish to migrate, and for some reason you notify sessions, then migration wouldn't be a straight translation but rather you might have to redesign that conditional step.

      "},{"location":"why/#python-management","title":"Python management","text":"

      Here we compare Python management to that of pyenv.

      • Cross-platform: Hatch allows for the same experience no matter the system whereas pyenv does not support Windows so you must use an entirely different project that tries to emulate the functionality.
      • No build dependencies: Hatch guarantees that every available distribution is prebuilt whereas the alternative requires one to maintain a precise build environment which differs by platform and potentially Python version. Another benefit to this is extremely fast installations since the distributions are simply downloaded and unpacked.
      • Optimized by default: The CPython distributions are built with profile guided optimization and link-time optimization, resulting in a 10-30% performance improvement depending on the workload. These distributions have seen wide adoption throughout the industry and are even used by the build system Bazel.
      • Simplicity: Hatch treats Python installations as just another directory that one would add to PATH. It can do this for you or you can manage PATH yourself, even allowing for custom install locations. On the other hand, pyenv operates by adding shims which then act as wrappers around the actual underlying binaries. This has many unfortunate side effects:
        • It is incumbent upon the user to manage which specific Python comes first via the CLI, switch when necessary, and/or have a mental model of which versions are exposed globally and locally per-project. This can become confusing quite quickly. When working with Hatch, your global Python installations are only important insofar as they are on PATH somewhere since environments do not use them directly but rather create virtual environments from them, always using a version that is compatible with your project.
        • Configuration is required for each shell to properly set up pyenv on start, leading to inconsistencies when running processes that do not spawn a shell.
        • Debugging issues with Python search paths can be extremely difficult, especially for users of software. If you or users have ever ran into an issue where code was being executed that you did not anticipate, the issue is almost always pyenv influencing the python on PATH.

      Why not?:

      Currently, Hatch does not allow for the installation of specific patch release versions but rather only uses minor release granularity that tracks the latest patch release. If specific patch releases are important to you then it is best to use an alternative installation mechanism.

      "},{"location":"blog/","title":"Blog","text":""},{"location":"blog/2022/10/08/hatch-v160/","title":"Hatch v1.6.0","text":"

      Hatch v1.6.0 brings improvements to build environments, better handling of dynamic metadata, and support for tools like Visual Studio Code.

      "},{"location":"blog/2022/10/08/hatch-v160/#build-environments","title":"Build environments","text":"

      Originally, the environment interface method for providing builder sub-environments was intended to be used in conjunction with some cleanup logic in order to provide a fresh setup every time. However, this is unnecessary in practice because build dependencies rarely change.

      Without caching, repeat build environment use is slow which affects the following scenarios:

      • the build command
      • commands that read project metadata, like dep hash, if any fields are set dynamically

      Now a new environment interface method build_environment_exists is used by Hatch to determine whether or not it has already been created, for implementations that have a caching mechanism.

      The virtual environment type now uses this method to cache build environments.

      "},{"location":"blog/2022/10/08/hatch-v160/#project-metadata","title":"Project metadata","text":"

      Dynamically defined metadata is now supported everywhere, thanks to the new caching of virtual build environments.

      A project metadata command is introduced that displays the fully resolved metadata. The output format is JSON unless a field is specified as an argument.

      For example, if you checkout a project that is built by Hatch, like FastAPI, and run:

      hatch project metadata readme\n

      only the readme text will be displayed. If the content is in Markdown, then Rich will render it directly in your terminal:

      "},{"location":"blog/2022/10/08/hatch-v160/#virtual-environment-location","title":"Virtual environment location","text":"

      The virtual environment type now uses a flat layout for storage in the configured virtual environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory.

      For example, if you define the following Hatch configuration:

      config.toml
      [dirs.env]\nvirtual = \".hatch\"\n

      and the following matrix:

      pyproject.toml hatch.toml
      [[tool.hatch.envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n
      [[envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n

      then locating environments with the following command:

      hatch env find test\n

      will show that the general directory structure is:

      .hatch\n\u251c\u2500\u2500 test.py3.7\n\u251c\u2500\u2500 test.py3.8\n\u251c\u2500\u2500 test.py3.9\n\u251c\u2500\u2500 test.py3.10\n\u2514\u2500\u2500 test.py3.11\n

      This flat structure is required for detection of virtual environments by tools like Visual Studio Code and PyCharm.

      Additionally, the virtual environment type now supports a path option to specify an explicit path that all inherited environments will share, such as the common .venv.

      "},{"location":"blog/2022/10/08/hatch-v160/#migration-script-improvements","title":"Migration script improvements","text":"

      The script used to migrate existing projects from setuptools has been improved to handle more edge cases that were encountered in the wild and now no longer modifies the formatting of existing pyproject.toml configuration.

      "},{"location":"blog/2022/10/08/hatch-v160/#hatchling","title":"Hatchling","text":"

      Hatch now depends on Hatchling v1.11.0, which was also just released.

      "},{"location":"blog/2022/10/08/hatch-v160/#environment-version-source","title":"Environment version source","text":"

      A new env version source is available that allows for the project version to be defined by an environment variable.

      "},{"location":"blog/2022/10/08/hatch-v160/#relaxed-version-bumping","title":"Relaxed version bumping","text":"

      The standard version scheme now supports a validate-bump option that when set to false will forego the check when updating the version that the desired version is higher than the current version.

      This use case comes from Project Jupyter:

      A common pattern we use in Jupyter is to bump to a .dev0 minor version bump after making a release. If we have a bug fix that needs to go out in the interim, we'd rather not be forced to create a branch every time.

      "},{"location":"blog/2023/12/11/hatch-v180/","title":"Hatch v1.8.0","text":"

      Hatch v1.8.0 brings Python distribution management, static analysis and formatting backed by Ruff, and binaries for every platform.

      "},{"location":"blog/2023/12/11/hatch-v180/#installation-made-easy","title":"Installation made easy","text":"

      One thing that has been a perpetual problem for Hatch and other Python applications is that Python itself is a dependency. You, and more importantly your users, need to in some way get Python before your software can even be used. The recommended way to go about that is platform-dependent and even differs based on your target audience. I viewed this as a central UX problem for Hatch and so severe that I took a bit of a hiatus to solve it.

      Luckily, I have to my satisfaction solved this problem in the form of PyApp. It is a runtime installer for Python projects written in Rust. Apps are distributed as standalone executables as users have come to expect and bootstrapping occurs upon the first invocation. Here is an example of what you would see the first time you run a binary from this release:

      Now that we have binaries, creating installers for different platforms becomes trivial. Starting with this release not only are binaries available for every platform but also we have installers for Windows and macOS. The installer for macOS is signed using a certificate from the same account used to sign the official distributions from https://www.python.org, so users will not get any security pop-ups. Shout out to @ewdurbin for their extreme generosity in setting up multiple certificates in their free time!

      These installers and binaries are now the recommended way to install and update Hatch. These binaries have built-in management so you can update to the latest version by running hatch self update.

      Windows signing

      In future we will sign the installers for Windows but I did not have time to look into how that works. macOS signing took way longer than I anticipated

      "},{"location":"blog/2023/12/11/hatch-v180/#python-management","title":"Python management","text":"

      For a long time I and other users have desired that Hatch gain the ability to manage Python distributions. In my mind this was always blocked on a better installation experience because there was sort of a chicken-or-egg problem where you want a Python manager but you first need Python. No longer is that the case!

      The new python command group allows for easy installation of various distributions to arbitrary locations which are then added to your PATH by default. Hatch supports CPython and PyPy distributions:

      "},{"location":"blog/2023/12/11/hatch-v180/#virtual-environment-python-resolution","title":"Virtual environment Python resolution","text":"

      The virtual environment type is now far more intelligent when resolving the parent distribution to use and guarantees that, when no specific version is requested, the resolved distribution will always be compatible with the project.

      Additionally, when a requested version cannot be found on PATH it will automatically be downloaded and managed internally.

      "},{"location":"blog/2023/12/11/hatch-v180/#static-analysis","title":"Static analysis","text":"

      There is a new fmt command, backed entirely by Ruff, that checks and fixes your code for formatting and linting issues.

      Starting with this release, Hatch maintains default settings that are guaranteed to be up-to-date and represent best practices for programming in modern Python. The idea is to provide defaults that are so broadly applicable that the majority of users will maintain little if any of their own overrides.

      The default behavior is internal management of settings to provide an OOTB experience that works. It is recommended however that you persist the default config file in version control so that other tools like IDEs can utilize your full configuration.

      Since Ruff is now provided as a built-in feature, new project templates no longer have such configuration and are much less verbose.

      "},{"location":"blog/2023/12/11/hatch-v180/#build-improvements","title":"Build improvements","text":"

      Building projects that do not use Hatchling as a backend is now supported and such builds are managed with the standard build tool.

      The bridge between Hatch and the Hatchling CLI has been removed. Previously, the builder would send serialized messages to Hatch that would contain the desired content and style for each line of output. This was done in an effort to allow builder and build hook plugins to output pretty messages without actually requiring a dependency like Rich. A problem that arises with this is that builders that invoke subprocesses will not display ANSI codes as one might expect and will lose out on the interactive experience of such invocations, like the built-in binary builder plugin calling cargo build. So now everything is simpler at the expense of no colored output without manual logic, or adding a dependency if you're a third-party plugin.

      "},{"location":"blog/2023/12/11/hatch-v180/#faster-environment-usage","title":"Faster environment usage","text":"

      Spawning a shell or running commands within environments always first checks that your project's dependencies are satisfied and if not synchronizes the environment with what is defined. Previously, this had the potential to be quite slow for projects that have many dependencies.

      Now the set of dependency definitions is hashed and no check is performed if the hash is the same as before, significantly speeding up environment usage in most cases.

      "},{"location":"blog/2023/12/11/hatch-v180/#hatchling","title":"Hatchling","text":"

      Hatch now depends on Hatchling v1.19.0, which was also just released.

      "},{"location":"blog/2023/12/11/hatch-v180/#better-defaults","title":"Better defaults","text":"

      Hatchling is all about providing the best possible defaults, even at the expense of backward compatibility. In this release, there are two breaking changes that provide a much better user experience and were in fact requested by users.

      • Both the force-include option and the force_include_editable wheel build data setting now raise errors if source paths do not exist.
      • The wheel build target now raises an error when no file inclusion options have been defined and none of its heuristics to determine what to ship are satisfied.
      "},{"location":"blog/2023/12/11/hatch-v180/#binary-build-target","title":"Binary build target","text":"

      A new binary build target is now stable that allows for the building of standalone binaries for projects. This is what Hatch itself uses for its binaries.

      "},{"location":"blog/2023/12/11/hatch-v180/#meta","title":"Meta","text":""},{"location":"blog/2023/12/11/hatch-v180/#why-hatch","title":"Why Hatch?","text":"

      A new page has been introduced that discusses the value proposition of Hatch and Hatchling in comparison to alternatives. Currently, it only addresses a few features but in future this page will become more comprehensive.

      "},{"location":"blog/2023/12/11/hatch-v180/#future","title":"Future","text":"

      Upcoming features include a test command, commands to manage dependencies, and workspaces functionality similar to Cargo that will make managing monorepos far easier.

      Next year there will be two large efforts that you should expect to see:

      1. A significant amount of my free time (and some at work) will be devoted to introducing lock file functionality in Hatch and trying to get whatever that happens to be standardized.

        I met with @brettcannon about his thoughts post-PEP 665 and about mousebender. I also met with the prefix.dev team about rip and was fortunate enough to be shown a demo before its official announcement.

        At the moment, the two options I see are to either go all in and contribute to mousebender or rely on the Prefix folks and use rip. The latter has the benefit of potentially supporting Conda as a side effect with the downside of being quite new with the spec firmly out of our control. The former has the benefit of being able to easily gain institutional support from the Python packaging team and each of our employers with the downside being a significant amount of work needing to be done.

      2. When @henryiii is able to get some free time away from teaching I plan to work with him once again and push very hard for the Python build ecosystem to adopt the extensionlib approach.

        I am of the opinion that the Python community has not fully completed the expressed outcome of PEP 517 in that build backends are still (for the most part) reliant on setuptools for building non-Python code bases.

        Basically, there are components that interact with compilers to produce extension modules and components that pack files into an archive which we call a build backend. These are two distinct pieces of functionality and my view is that there should be an API that allows backends to consume extension module builders to find out where things got created and where they should be shipped inside archives.

        In this hypothetical future any build backend would be able to trigger the building of extension modules based on user configuration.

      "},{"location":"blog/2023/12/11/hatch-v180/#support","title":"Support","text":"

      If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!

      "},{"location":"blog/2023/12/18/hatch-v190/","title":"Hatch v1.9.0","text":"

      Hatch v1.9.0 brings improvements to static analysis and important bug fixes.

      "},{"location":"blog/2023/12/18/hatch-v190/#static-analysis","title":"Static analysis","text":"

      The default version of Ruff has been increased to v0.1.8. This release brings formatting capabilities to docstrings and Hatch enables this by default with line length set to 80. This length was chosen as the default because it plays nicely with the rendering of the most popular themes for Python documentation, such as Material for MkDocs and Furo.

      Additionally, it is now possible for projects to pin to specific versions of Ruff for upgrading at a later time:

      pyproject.toml hatch.toml
      [tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
      [envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
      "},{"location":"blog/2023/12/18/hatch-v190/#notable-fixes","title":"Notable fixes","text":"
      • Python resolution for environments that do not install the project is no longer bound by the project's Python requirement.
      • Fixed an edge case for out-of-the-box static analysis when there was existing configuration.
      • Compatibility checks for environments no longer occur if the environment is already created. This significantly increases the responsiveness of environment usage.
      "},{"location":"cli/about/","title":"CLI usage","text":""},{"location":"cli/about/#verbosity","title":"Verbosity","text":"

      The amount of displayed output is controlled solely by the -v/--verbose (environment variable HATCH_VERBOSE) and -q/--quiet (environment variable HATCH_QUIET) root options.

      The levels are documented here.

      "},{"location":"cli/about/#project-awareness","title":"Project awareness","text":"

      No matter the mode, Hatch will always change to the project's root directory for entering or running commands in environments.

      "},{"location":"cli/about/#tab-completion","title":"Tab completion","text":"

      Completion is achieved by saving a script and then executing it as a part of your shell's startup sequence.

      Afterward, you'll need to start a new shell in order for the changes to take effect.

      BashZ shellfish

      Save the script somewhere:

      _HATCH_COMPLETE=bash_source hatch > ~/.hatch-complete.bash\n

      Source the file in ~/.bashrc (or ~/.bash_profile if on macOS):

      . ~/.hatch-complete.bash\n

      Save the script somewhere:

      _HATCH_COMPLETE=zsh_source hatch > ~/.hatch-complete.zsh\n

      Source the file in ~/.zshrc:

      . ~/.hatch-complete.zsh\n

      Save the script in ~/.config/fish/completions:

      _HATCH_COMPLETE=fish_source hatch > ~/.config/fish/completions/hatch.fish\n
      "},{"location":"cli/reference/","title":"hatch","text":"

      Usage:

      hatch [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --env, -e text The name of the environment to use [env var: HATCH_ENV] default --project, -p text The name of the project to work on [env var: HATCH_PROJECT] None --verbose, -v integer range (0 and above) Increase verbosity (can be used additively) [env var: HATCH_VERBOSE] 0 --quiet, -q integer range (0 and above) Decrease verbosity (can be used additively) [env var: HATCH_QUIET] 0 --color / --no-color boolean Whether or not to display colored output (default is auto-detection) [env vars: FORCE_COLOR/NO_COLOR] None --interactive / --no-interactive boolean Whether or not to allow features like prompts and progress bars (default is auto-detection) [env var: HATCH_INTERACTIVE] None --data-dir text The path to a custom directory used to persist data [env var: HATCH_DATA_DIR] None --cache-dir text The path to a custom directory used to cache data [env var: HATCH_CACHE_DIR] None --config text The path to a custom config file to use [env var: HATCH_CONFIG] None --version boolean Show the version and exit. False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-build","title":"hatch build","text":"

      Build a project.

      Usage:

      hatch build [OPTIONS] [LOCATION]\n

      Options:

      Name Type Description Default --target, -t text The target to build, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None --hooks-only boolean Whether or not to only execute build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False --no-hooks boolean Whether or not to disable build hooks [env var: HATCH_BUILD_NO_HOOKS] False --ext boolean Whether or not to only execute build hooks for distributing binary Python packages, such as compiling extensions. Equivalent to --hooks-only -t wheel False --clean, -c boolean Whether or not existing artifacts should first be removed [env var: HATCH_BUILD_CLEAN] False --clean-hooks-after boolean Whether or not build hook artifacts should be removed after each build [env var: HATCH_BUILD_CLEAN_HOOKS_AFTER] False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-clean","title":"hatch clean","text":"

      Remove build artifacts.

      Usage:

      hatch clean [OPTIONS] [LOCATION]\n

      Options:

      Name Type Description Default --target, -t text The target with which to remove artifacts, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel None --hooks-only boolean Whether or not to only remove artifacts from build hooks [env var: HATCH_BUILD_HOOKS_ONLY] False --no-hooks boolean Whether or not to ignore artifacts from build hooks [env var: HATCH_BUILD_NO_HOOKS] False --ext boolean Whether or not to only remove artifacts from build hooks for distributing binary Python packages, such as compiled extensions. Equivalent to --hooks-only -t wheel False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config","title":"hatch config","text":"

      Manage the config file

      Usage:

      hatch config [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-explore","title":"hatch config explore","text":"

      Open the config location in your file manager.

      Usage:

      hatch config explore [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-find","title":"hatch config find","text":"

      Show the location of the config file.

      Usage:

      hatch config find [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-restore","title":"hatch config restore","text":"

      Restore the config file to default settings.

      Usage:

      hatch config restore [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-set","title":"hatch config set","text":"

      Assign values to config file entries. If the value is omitted, you will be prompted, with the input hidden if it is sensitive.

      Usage:

      hatch config set [OPTIONS] KEY [VALUE]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-show","title":"hatch config show","text":"

      Show the contents of the config file.

      Usage:

      hatch config show [OPTIONS]\n

      Options:

      Name Type Description Default --all, -a boolean Do not scrub secret fields False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-config-update","title":"hatch config update","text":"

      Update the config file with any new fields.

      Usage:

      hatch config update [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep","title":"hatch dep","text":"

      Manage environment dependencies

      Usage:

      hatch dep [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-hash","title":"hatch dep hash","text":"

      Output a hash of the currently defined dependencies.

      Usage:

      hatch dep hash [OPTIONS]\n

      Options:

      Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show","title":"hatch dep show","text":"

      Display dependencies in various formats

      Usage:

      hatch dep show [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show-requirements","title":"hatch dep show requirements","text":"

      Enumerate dependencies as a list of requirements.

      Usage:

      hatch dep show requirements [OPTIONS]\n

      Options:

      Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --feature, -f text Whether or not to only show the dependencies of the specified features None --all boolean Whether or not to include the dependencies of all features False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-dep-show-table","title":"hatch dep show table","text":"

      Enumerate dependencies in a tabular format.

      Usage:

      hatch dep show table [OPTIONS]\n

      Options:

      Name Type Description Default --project-only, -p boolean Whether or not to exclude environment dependencies False --env-only, -e boolean Whether or not to exclude project dependencies False --lines, -l boolean Whether or not to show lines between table rows False --ascii boolean Whether or not to only use ASCII characters False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env","title":"hatch env","text":"

      Manage project environments

      Usage:

      hatch env [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-create","title":"hatch env create","text":"

      Create environments.

      Usage:

      hatch env create [OPTIONS] [ENV_NAME]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-find","title":"hatch env find","text":"

      Locate environments.

      Usage:

      hatch env find [OPTIONS] [ENV_NAME]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-prune","title":"hatch env prune","text":"

      Remove all environments.

      Usage:

      hatch env prune [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-remove","title":"hatch env remove","text":"

      Remove environments.

      Usage:

      hatch env remove [OPTIONS] [ENV_NAME]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-run","title":"hatch env run","text":"

      Run commands within project environments.

      The -e/--env option overrides the equivalent root option and the HATCH_ENV environment variable.

      If environments provide matrices, then you may use the -i/--include and -x/--exclude options to select or exclude certain variables, optionally followed by specific comma-separated values. For example, if you have the following configuration:

      pyproject.toml hatch.toml
      [[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
      [[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n

      then running:

      hatch env run -i py=3.10 -x version=9000 test:pytest\n

      would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

      Usage:

      hatch env run [OPTIONS] ARGS...\n

      Options:

      Name Type Description Default --env, -e text The environments to target None --include, -i text The matrix variables to include None --exclude, -x text The matrix variables to exclude None --filter, -f text The JSON data used to select environments None --force-continue boolean Run every command and if there were any errors exit with the first code False --ignore-compat boolean Ignore incompatibility when selecting specific environments False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-env-show","title":"hatch env show","text":"

      Show the available environments.

      Usage:

      hatch env show [OPTIONS] [ENVS]...\n

      Options:

      Name Type Description Default --ascii boolean Whether or not to only use ASCII characters False --json boolean Whether or not to output in JSON format False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-fmt","title":"hatch fmt","text":"

      Format and lint source code.

      Usage:

      hatch fmt [OPTIONS] [ARGS]...\n

      Options:

      Name Type Description Default --check boolean Only check for errors rather than fixing them False --linter, -l boolean Only run the linter False --formatter, -f boolean Only run the formatter False --sync boolean Sync the default config file with the current version of Hatch False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-new","title":"hatch new","text":"

      Create or initialize a project.

      Usage:

      hatch new [OPTIONS] [NAME] [LOCATION]\n

      Options:

      Name Type Description Default --interactive, -i boolean Interactively choose details about the project False --cli boolean Give the project a command line interface False --init boolean Initialize an existing project False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-project","title":"hatch project","text":"

      View project information

      Usage:

      hatch project [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-project-metadata","title":"hatch project metadata","text":"

      Display project metadata.

      If you want to view the raw readme file without rendering, you can use a JSON parser like jq:

      hatch project metadata | jq -r .readme\n

      Usage:

      hatch project metadata [OPTIONS] [FIELD]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-publish","title":"hatch publish","text":"

      Publish build artifacts.

      Usage:

      hatch publish [OPTIONS] [ARTIFACTS]...\n

      Options:

      Name Type Description Default --repo, -r text The repository with which to publish artifacts [env var: HATCH_INDEX_REPO] None --user, -u text The user with which to authenticate [env var: HATCH_INDEX_USER] None --auth, -a text The credentials to use for authentication [env var: HATCH_INDEX_AUTH] None --ca-cert text The path to a CA bundle [env var: HATCH_INDEX_CA_CERT] None --client-cert text The path to a client certificate, optionally containing the private key [env var: HATCH_INDEX_CLIENT_CERT] None --client-key text The path to the client certificate's private key [env var: HATCH_INDEX_CLIENT_KEY] None --no-prompt, -n boolean Disable prompts, such as for missing required fields False --initialize-auth boolean Save first-time authentication information even if nothing was published False --publisher, -p text The publisher plugin to use (default is index) [env var: HATCH_PUBLISHER] index --option, -o text Options to pass to the publisher plugin. This may be selected multiple times e.g. -o foo=bar -o baz=23 [env var: HATCH_PUBLISHER_OPTIONS] None --yes, -y boolean Confirm without prompting when the plugin is disabled False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python","title":"hatch python","text":"

      Manage Python installations

      Usage:

      hatch python [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-find","title":"hatch python find","text":"

      Locate Python binaries.

      Usage:

      hatch python find [OPTIONS] NAME\n

      Options:

      Name Type Description Default -p, --parent boolean Show the parent directory of the Python binary False --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-install","title":"hatch python install","text":"

      Install Python distributions.

      You may select all to install all compatible distributions:

      hatch python install all\n

      Usage:

      hatch python install [OPTIONS] NAMES...\n

      Options:

      Name Type Description Default --private boolean Do not add distributions to the user PATH False --update, -u boolean Update existing installations False --dir, -d text The directory in which to install distributions, overriding configuration None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-remove","title":"hatch python remove","text":"

      Remove Python distributions.

      You may select all to remove all installed distributions:

      hatch python remove all\n

      Usage:

      hatch python remove [OPTIONS] NAMES...\n

      Options:

      Name Type Description Default --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-show","title":"hatch python show","text":"

      Show the available Python distributions.

      Usage:

      hatch python show [OPTIONS]\n

      Options:

      Name Type Description Default --ascii boolean Whether or not to only use ASCII characters False --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-python-update","title":"hatch python update","text":"

      Update Python distributions.

      You may select all to update all installed distributions:

      hatch python update all\n

      Usage:

      hatch python update [OPTIONS] NAMES...\n

      Options:

      Name Type Description Default --dir, -d text The directory in which distributions reside None --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-run","title":"hatch run","text":"

      Run commands within project environments. This is a convenience wrapper around the env run command.

      If the first argument contains a colon, then the preceding component will be interpreted as the name of the environment to target, overriding the -e/--env root option and the HATCH_ENV environment variable.

      If the environment provides matrices, then you may also provide leading arguments starting with a + or - to select or exclude certain variables, optionally followed by specific comma-separated values. For example, if you have the following configuration:

      pyproject.toml hatch.toml
      [[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
      [[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n

      then running:

      hatch run +py=3.10 -version=9000 test:pytest\n

      would execute pytest in the environments test.py3.10-42 and test.py3.10-3.14. Note that py may be used as an alias for python.

      Usage:

      hatch run [OPTIONS] [ENV:]ARGS...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-self","title":"hatch self","text":"

      Manage Hatch

      Usage:

      hatch self [OPTIONS] COMMAND [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-self-report","title":"hatch self report","text":"

      Generate a pre-populated GitHub issue.

      Usage:

      hatch self report [OPTIONS]\n

      Options:

      Name Type Description Default --no-open, -n boolean Show the URL instead of opening it False --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-self-restore","title":"hatch self restore","text":"

      Restore the installation

      Usage:

      hatch self restore [OPTIONS] [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-self-update","title":"hatch self update","text":"

      Install the latest version

      Usage:

      hatch self update [OPTIONS] [ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-shell","title":"hatch shell","text":"

      Enter a shell within a project's environment.

      Usage:

      hatch shell [OPTIONS] [SHELL_NAME] [SHELL_PATH] [SHELL_ARGS]...\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-status","title":"hatch status","text":"

      Show information about the current environment.

      Usage:

      hatch status [OPTIONS]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"cli/reference/#hatch-version","title":"hatch version","text":"

      View or set a project's version.

      Usage:

      hatch version [OPTIONS] [DESIRED_VERSION]\n

      Options:

      Name Type Description Default --help boolean Show this message and exit. False"},{"location":"community/contributing/","title":"Contributing","text":"

      The usual process to make a contribution is to:

      1. Check for existing related issues
      2. Fork the repository and create a new branch
      3. Make your changes
      4. Make sure formatting, linting and tests passes.
      5. Add tests if possible to cover the lines you added.
      6. Commit, and send a Pull Request.
      "},{"location":"community/contributing/#clone-the-repository","title":"Clone the repository","text":"

      Clone the hatch repository, cd into it, and create a new branch for your contribution:

      cd hatch\ngit checkout -b add-my-contribution\n
      "},{"location":"community/contributing/#run-the-tests","title":"Run the tests","text":"

      Run the test suite while developing:

      hatch run dev\n

      Run the test suite with coverage report:

      hatch run cov\n

      Run the extended test suite with coverage:

      hatch run full\n
      "},{"location":"community/contributing/#lint","title":"Lint","text":"

      Run automated formatting:

      hatch run lint:fmt\n

      Run full linting and type checking:

      hatch run lint:all\n
      "},{"location":"community/contributing/#docs","title":"Docs","text":"

      Start the documentation in development:

      hatch run docs:serve\n

      Build and validate the documentation website:

      hatch run docs:build-check\n
      "},{"location":"community/highlights/","title":"Community highlights","text":""},{"location":"community/highlights/#integration","title":"Integration","text":"
      • Project Jupyter - https://blog.jupyter.org/packaging-for-jupyter-in-2022-c7be64c38926
      "},{"location":"community/highlights/#adoption","title":"Adoption","text":"
      • Black - https://ichard26.github.io/blog/2022/10/black-22.10.0/#goodbye-python-36-and-hello-hatchling
      • \"Switching to Hatch\" - https://andrich.me/2023/08/switching-to-hatch/
      "},{"location":"community/users/","title":"Users","text":"

      The following is not intended to be a complete enumeration. Be sure to view the development version of this page for an up-to-date listing.

      "},{"location":"community/users/#projects","title":"Projects","text":"

      aiogram | Apache Airflow | argon2-cffi | attrs | Black | coffea | Colorama | Django Anymail | Django Debug Toolbar | Django Wiki | FastAPI | filelock | github3.py | Gradio | HTTPX | iCalendar for Humans | LinkChecker | Material for MkDocs | MkDocs | openSUSE | Nox | Packit | pipx | platformdirs | Pydantic | Pygments | PyHamcrest | PyMdown Extensions | Python JSON Schema | Rye | SALib | Spack | Starlette | structlog | tox | Twisted | urllib3 | Uvicorn | virtualenv | Voil\u00e0 | XGBoost | Ypy

      "},{"location":"community/users/#industry","title":"Industry","text":"
      • Anaconda [1|2|3|4|5|6]
      • Astronomer [1]
      • Bloomberg [1|2]
      • Blue Robotics [1]
      • Cars.com [1]
      • Databricks [1|2]
      • Datadog [1|2|3|4]
      • deepset [1|2]
      • Elastic [1|2|3]
      • Google [1|2|3|4|5]
      • IBM [1]
      • JPMorgan Chase [1]
      • Intel Corporation [1|2|3]
      • Meta [1|2]
      • Microsoft [1|2|3|4|5]
      • OpenAI [1]
      • Oracle [1]
      • Palo Alto Networks [1]
      • Red Hat [1|2|3|4|5]
      • Snowflake [1]
      • Splunk [1]
      • Virtru [1|2]
      • VMware [1|2|3]
      • Volvo Group [1]
      "},{"location":"community/users/#organizations","title":"Organizations","text":"
      • Greater Paris University Hospitals (AP-HP) [1]
      • OpenTelemetry [1|2]
      • Smithsonian Institution [1]
      • The New York Public Library [1]
      "},{"location":"community/users/#government","title":"Government","text":"
      • European Molecular Biology Laboratory
        • European Bioinformatics Institute [1]
      • Germany
        • Berlin Institute of Health [1]
        • Helmholtz Munich [1|2]
      • Norway
        • Statistics Norway [1]
      • United Kingdom
        • The Alan Turing Institute [1]
        • Department for Business and Trade [1]
        • The National Archives [1]
      • United States
        • NASA [1]
        • National Security Agency [1|2]
        • National Telecommunications and Information Administration [1|2|3|4]
      "},{"location":"community/users/#academia","title":"Academia","text":"
      • Brown University
        • Carney Institute for Brain Science [1]
      • Chinese Academy of Sciences
        • Academy of Mathematics and Systems Science [1]
      • Georgia Institute of Technology
        • Georgia Tech Database Group [1]
      • Harvard University
        • Department of Molecular and Cellular Biology [1]
      • Heidelberg University
        • Center for Molecular Biology [1]
      • Leiden University
        • Leiden University Libraries [1|2]
      • Maastricht University
        • Institute of Data Science [1|2|3|4|5|6|7]
      • Massachusetts Institute of Technology
        • Computer Science and Artificial Intelligence Laboratory [1]
        • Digital Humanities [1]
      • Medical University of Innsbruck
        • Institute of Bioinformatics [1]
      • Polytechnique Montr\u00e9al
        • Department of Computer Engineering and Software Engineering [1]
      • Siberian Branch of the Russian Academy of Sciences
        • Institute of Cytology and Genetics [1|2|3|4]
      • Stanford University
        • Empirical Security Research Group [1]
      • University of British Columbia
        • Department of Earth, Ocean and Atmospheric Sciences [1|2|3]
      • University of California, Berkeley
        • Center for Computational Biology [1]
      • University of Freiburg
        • Freiburg Center for Data Analysis and Modeling [1]
      • University of Illinois Urbana-Champaign
        • Grainger College of Engineering [1]
      • University of Lausanne
        • Department of Computational Biology [1]
      • University of Ljubljana
        • Faculty of Mechanical Engineering [1]
      • University of Oxford
        • Oxford Research Software Engineering [1]
      • University of Pennsylvania
        • Lifespan Informatics and Neuroimaging Center [1]
      • University of Sussex
        • Predictive Analytics Lab [1]
      • University of Toronto Scarborough
        • utsc-networking [1|2|3|4]
      • University of Washington
        • Interactive Data Lab [1]
        • Virtual Brain Lab [1]
      • Waseda University
        • Tackeuchi Laboratory [1|2|3|4|5]
      • Wellcome Sanger Institute [1]
      "},{"location":"community/users/#research","title":"Research","text":"
      • Clariah [1]
      • CloudDrift [1]
      • GAMA [1]
      • IPython [1|2|3]
      • MNE [1|2|3]
      • NIPY [1|2]
      • Project Jupyter
        • Jupyter [1|2|3|4]
        • JupyterLab [1|2|3|4|5]
        • Jupyter Server [1|2|3|4]
      • Scikit-HEP [1|2|3|4|5|6|7|8|9|10]
      • scverse [1|2|3]
      • Spyder [1]
      "},{"location":"community/users/#security","title":"Security","text":"
      • Armory
      • in-toto
      • The Update Framework
      "},{"location":"community/users/#crypto","title":"Crypto","text":"
      • Ocean Protocol [1]
      "},{"location":"config/build/","title":"Build configuration","text":"

      Build targets are defined as sections within tool.hatch.build.targets:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.<TARGET_NAME>]\n
      [build.targets.<TARGET_NAME>]\n

      Tip

      Although not recommended, you may define global configuration in the tool.hatch.build table. Keys may then be overridden by target config.

      "},{"location":"config/build/#build-system","title":"Build system","text":"

      To be compatible with the broader Python packaging ecosystem, you must define the build system as follows:

      pyproject.toml
      [build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n

      The version of hatchling defined here will be used to build all targets.

      Hatchling is a standards-compliant1 build backend and is a dependency of Hatch itself.

      "},{"location":"config/build/#file-selection","title":"File selection","text":""},{"location":"config/build/#vcs","title":"VCS","text":"

      By default, Hatch will respect the first .gitignore or .hgignore file found in your project's root directory or parent directories. Set ignore-vcs to true to disable this behavior:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.sdist]\nignore-vcs = true\n
      [build.targets.sdist]\nignore-vcs = true\n

      Note

      For .hgignore files only glob syntax is supported.

      "},{"location":"config/build/#patterns","title":"Patterns","text":"

      You can set the include and exclude options to select exactly which files will be shipped in each build, with exclude taking precedence. Every entry represents a Git-style glob pattern.

      For example, the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.sdist]\ninclude = [\n  \"pkg/*.py\",\n  \"/tests\",\n]\nexclude = [\n  \"*.json\",\n  \"pkg/_compat.py\",\n]\n
      [build.targets.sdist]\ninclude = [\n  \"pkg/*.py\",\n  \"/tests\",\n]\nexclude = [\n  \"*.json\",\n  \"pkg/_compat.py\",\n]\n

      will exclude every file with a .json extension, and will include everything under a tests directory located at the root and every file with a .py extension that is directly under a pkg directory located at the root except for _compat.py.

      "},{"location":"config/build/#artifacts","title":"Artifacts","text":"

      If you want to include files that are ignored by your VCS, such as those that might be created by build hooks, you can use the artifacts option. This option is semantically equivalent to include.

      Note that artifacts are not affected by the exclude option. Artifacts can be excluded by using more explicit paths or by using the ! negation operator. When using the ! operator, the negated pattern(s) must come after the more generic ones.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\nartifacts = [\n  \"*.so\",\n  \"*.dll\",\n  \"!/foo/*.so\",\n]\n
      [build.targets.wheel]\nartifacts = [\n  \"*.so\",\n  \"*.dll\",\n  \"!/foo/*.so\",\n]\n
      "},{"location":"config/build/#explicit-selection","title":"Explicit selection","text":""},{"location":"config/build/#generic","title":"Generic","text":"

      You can use the only-include option to prevent directory traversal starting at the project root and only select specific relative paths to directories or files. Using this option ignores any defined include patterns.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
      [build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
      "},{"location":"config/build/#packages","title":"Packages","text":"

      The packages option is semantically equivalent to only-include (which takes precedence) except that the shipped path will be collapsed to only include the final component.

      So for example, if you want to ship a package foo that is stored in a directory src you would do:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
      [build.targets.wheel]\npackages = [\"src/foo\"]\n
      "},{"location":"config/build/#forced-inclusion","title":"Forced inclusion","text":"

      The force-include option allows you to select specific files or directories from anywhere on the file system that should be included and map them to the desired relative distribution path.

      For example, if there was a directory alongside the project root named artifacts containing a file named lib.so and a file named lib.h in your home directory, you could ship both files in a pkg directory with the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n
      [build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n

      Note

      • Files must be mapped exactly to their desired paths, not to directories.
      • The contents of directory sources are recursively included.
      • To map directory contents directly to the root use / (a forward slash).
      • Sources that do not exist will raise an error.

      Warning

      Files included using this option will overwrite any file path that was already included by other file selection options.

      "},{"location":"config/build/#default-file-selection","title":"Default file selection","text":"

      If no file selection options are provided, then what gets included is determined by each build target.

      "},{"location":"config/build/#excluding-files-outside-packages","title":"Excluding files outside packages","text":"

      If you want to exclude non-artifact files that do not reside within a Python package, set only-packages to true:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\nonly-packages = true\n
      [build.targets.wheel]\nonly-packages = true\n
      "},{"location":"config/build/#rewriting-paths","title":"Rewriting paths","text":"

      You can rewrite relative paths to directories with the sources option. For example, the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n
      [build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n

      would distribute the file src/foo/file.ext as bar/file.ext.

      If you want to remove path prefixes entirely, rather than setting each to an empty string, you can define sources as an array:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\nsources = [\"src\"]\n
      [build.targets.wheel]\nsources = [\"src\"]\n

      If you want to add a prefix to paths, you can use an empty string. For example, the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel.sources]\n\"\" = \"foo\"\n
      [build.targets.wheel.sources]\n\"\" = \"foo\"\n

      would distribute the file bar/file.ext as foo/bar/file.ext.

      The packages option itself relies on sources. Defining packages = [\"src/foo\"] for the wheel target is equivalent to the following:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
      [build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
      "},{"location":"config/build/#performance","title":"Performance","text":"

      All encountered directories are traversed by default. To skip non-artifact directories that are excluded, set skip-excluded-dirs to true:

      pyproject.toml hatch.toml
      [tool.hatch.build]\nskip-excluded-dirs = true\n
      [build]\nskip-excluded-dirs = true\n

      Warning

      This may result in not shipping desired files. For example, if you want to include the file a/b/c.txt but your VCS ignores a/b, the file c.txt will not be seen because its parent directory will not be entered. In such cases you can use the force-include option.

      "},{"location":"config/build/#reproducible-builds","title":"Reproducible builds","text":"

      By default, build targets will build in a reproducible manner provided that they support that behavior. To disable this, set reproducible to false:

      pyproject.toml hatch.toml
      [tool.hatch.build]\nreproducible = false\n
      [build]\nreproducible = false\n

      When enabled, the SOURCE_DATE_EPOCH environment variable will be used for all build timestamps. If not set, then Hatch will use an unchanging default value.

      "},{"location":"config/build/#output-directory","title":"Output directory","text":"

      When the output directory is not provided to the build command, the dist directory will be used by default. You can change the default to a different directory using a relative or absolute path like so:

      pyproject.toml hatch.toml
      [tool.hatch.build]\ndirectory = \"<PATH>\"\n
      [build]\ndirectory = \"<PATH>\"\n
      "},{"location":"config/build/#dev-mode","title":"Dev mode","text":"

      By default for dev mode environment installations or editable installs, the wheel target will determine which directories should be added to Python's search path based on the selected files.

      If you want to override this detection or perhaps instruct other build targets as well, you can use the dev-mode-dirs option:

      pyproject.toml hatch.toml
      [tool.hatch.build]\ndev-mode-dirs = [\".\"]\n
      [build]\ndev-mode-dirs = [\".\"]\n

      If you don't want to add entire directories to Python's search path, you can enable a more targeted mechanism with the mutually exclusive dev-mode-exact option:

      pyproject.toml hatch.toml
      [tool.hatch.build]\ndev-mode-exact = true\n
      [build]\ndev-mode-exact = true\n

      Warning

      The dev-mode-exact mechanism is not supported by static analysis tools & IDEs, therefore functionality such as autocompletion is unlikely to work.

      "},{"location":"config/build/#build-targets","title":"Build targets","text":"

      A build target can be provided by any builder plugin. There are three built-in build targets: wheel, sdist, and custom.

      "},{"location":"config/build/#dependencies","title":"Dependencies","text":"

      You can specify additional dependencies that will be installed in each build environment, such as for third party builders:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.your-target-name]\ndependencies = [\n  \"your-builder-plugin\"\n]\n
      [build.targets.your-target-name]\ndependencies = [\n  \"your-builder-plugin\"\n]\n

      You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies option:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.your-target-name]\nrequire-runtime-dependencies = true\n
      [build.targets.your-target-name]\nrequire-runtime-dependencies = true\n

      Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features option:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.your-target-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
      [build.targets.your-target-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
      "},{"location":"config/build/#versions","title":"Versions","text":"

      If a build target supports multiple build strategies or if there are major changes over time, you can specify exactly which versions you want to build using the versions option:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.<TARGET_NAME>]\nversions = [\n  \"v1\",\n  \"beta-feature\",\n]\n
      [build.targets.<TARGET_NAME>]\nversions = [\n  \"v1\",\n  \"beta-feature\",\n]\n

      See the wheel target for a real world example.

      "},{"location":"config/build/#build-hooks","title":"Build hooks","text":"

      A build hook defines code that will be executed at various stages of the build process and can be provided by any build hook plugin. There is one built-in build hook: custom.

      Build hooks can be applied either globally:

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.<HOOK_NAME>]\n
      [build.hooks.<HOOK_NAME>]\n

      or to specific build targets:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
      [build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
      "},{"location":"config/build/#dependencies_1","title":"Dependencies","text":"

      You can specify additional dependencies that will be installed in each build environment, such as for third party build hooks:

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.your-hook-name]\ndependencies = [\n  \"your-build-hook-plugin\"\n]\n
      [build.hooks.your-hook-name]\ndependencies = [\n  \"your-build-hook-plugin\"\n]\n

      You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies option:

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n
      [build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n

      Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features option:

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
      [build.hooks.your-hook-name]\nrequire-runtime-features = [\n  \"feature1\",\n  \"feature2\",\n]\n
      "},{"location":"config/build/#order-of-execution","title":"Order of execution","text":"

      For each build target, build hooks execute in the order in which they are defined, starting with global hooks.

      As an example, for the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.foo.hooks.hook2]\n\n[tool.hatch.build.hooks.hook3]\n[tool.hatch.build.hooks.hook1]\n
      [build.targets.foo.hooks.hook2]\n\n[build.hooks.hook3]\n[build.hooks.hook1]\n

      When target foo is built, build hook hook3 will be executed first, followed by hook1, and then finally hook2.

      "},{"location":"config/build/#conditional-execution","title":"Conditional execution","text":"

      If you want to disable a build hook by default and control its use by environment variables, you can do so by setting the enable-by-default option to false:

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
      [build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
      "},{"location":"config/build/#environment-variables","title":"Environment variables","text":"Variable Default Description HATCH_BUILD_CLEAN false Whether or not existing artifacts should first be removed HATCH_BUILD_CLEAN_HOOKS_AFTER false Whether or not build hook artifacts should be removed after each build HATCH_BUILD_HOOKS_ONLY false Whether or not to only execute build hooks HATCH_BUILD_NO_HOOKS false Whether or not to disable all build hooks; this takes precedence over other options HATCH_BUILD_HOOKS_ENABLE false Whether or not to enable all build hooks HATCH_BUILD_HOOK_ENABLE_<HOOK_NAME> false Whether or not to enable the build hook named <HOOK_NAME> HATCH_BUILD_LOCATION dist The location with which to build the targets; only used by the build command
      1. Support for PEP 517 and PEP 660 guarantees interoperability with other build tools.\u00a0\u21a9

      "},{"location":"config/context/","title":"Context formatting","text":"

      You can populate configuration with the values of certain supported fields using the syntax of Python's format strings. Each field interprets the modifier part after the colon differently, if at all.

      "},{"location":"config/context/#global-fields","title":"Global fields","text":"

      Any configuration that declares support for context formatting will always support these fields.

      "},{"location":"config/context/#paths","title":"Paths","text":"Field Description root The root project directory home The user's home directory

      All paths support the following modifiers:

      Modifier Description uri The normalized absolute URI path prefixed by file: real The path with all symbolic links resolved parent The parent of the preceding path

      Tip

      The parent modifier can be chained and may be combined with either the uri or real modifier, with the latter placed at the end. For example:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n    \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
      [envs.test]\ndependencies = [\n    \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
      "},{"location":"config/context/#system-separators","title":"System separators","text":"Field Description / \\ on Windows, / otherwise ; ; on Windows, : otherwise"},{"location":"config/context/#environment-variables","title":"Environment variables","text":"

      The env field and its modifier allow you to select the value of an environment variable. If the environment variable is not set, you must specify a default value as an additional modifier e.g. {env:PATH:DEFAULT}.

      "},{"location":"config/context/#field-nesting","title":"Field nesting","text":"

      You can insert fields within others. For example, if you wanted a script that displays the value of the environment variable FOO, with a fallback to the environment variable BAR, with its own fallback to the user's home directory, you could do the following:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
      [envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
      "},{"location":"config/dependency/","title":"Dependency configuration","text":"

      Project dependencies are defined with PEP 508 strings using optional PEP 440 version specifiers.

      "},{"location":"config/dependency/#version-specifiers","title":"Version specifiers","text":"

      A version specifier consists of a series of version clauses, separated by commas. For example:

      pyproject.toml
      [project]\n...\ndependencies = [\n  \"cryptography\",\n  \"click>=7, <9, != 8.0.0\",\n  \"python-dateutil==2.8.*\",\n  \"numpy~=1.21.4\",\n]\n

      The comma is equivalent to a logical AND operator: a candidate version must match all given version clauses in order to match the specifier as a whole.

      "},{"location":"config/dependency/#operators","title":"Operators","text":"Operators Function ~= Compatible release == Version matching != Version exclusion <=, >= Inclusive ordered comparison <, > Exclusive ordered comparison === Arbitrary equality"},{"location":"config/dependency/#version-matching","title":"Version matching","text":"

      A version matching clause includes the version matching operator == and a version identifier.

      By default, the version matching operator is based on a strict equality comparison: the specified version must be exactly the same as the requested version.

      Clause Allowed versions ==1 1.0.0 ==1.2 1.2.0

      Prefix matching may be requested instead of strict comparison, by appending a trailing .* to the version identifier in the version matching clause. This means that additional trailing segments will be ignored when determining whether or not a version identifier matches the clause.

      Clause Allowed versions ==1.* >=1.0.0, <2.0.0 ==1.2.* >=1.2.0, <1.3.0"},{"location":"config/dependency/#compatible-release","title":"Compatible release","text":"

      A compatible release clause consists of the compatible release operator ~= and a version identifier. It matches any candidate version that is expected to be compatible with the specified version.

      For a given release identifier V.N, the compatible release clause is approximately equivalent to the following pair of comparison clauses:

      >= V.N, == V.*\n

      This operator cannot be used with a single segment version number such as ~=1.

      Clause Allowed versions ~=1.2 >=1.2.0, <2.0.0 ~=1.2.3 >=1.2.3, <1.3.0"},{"location":"config/dependency/#version-exclusion","title":"Version exclusion","text":"

      A version exclusion clause includes the version exclusion operator != and a version identifier.

      The allowed version identifiers and comparison semantics are the same as those of the Version matching operator, except that the sense of any match is inverted.

      "},{"location":"config/dependency/#ordered-comparison","title":"Ordered comparison","text":"

      Inclusive comparisons allow for the version identifier part of clauses whereas exclusive comparisons do not. For example, >=1.2 allows for version 1.2.0 while >1.2 does not.

      Unlike the inclusive ordered comparisons <= and >=, the exclusive ordered comparisons < and > specifically exclude pre-releases, post-releases, and local versions of the specified version.

      "},{"location":"config/dependency/#arbitrary-equality","title":"Arbitrary equality","text":"

      Though heavily discouraged, arbitrary equality comparisons allow for simple string matching without any version semantics, for example ===foobar.

      "},{"location":"config/dependency/#environment-markers","title":"Environment markers","text":"

      Environment markers allow for dependencies to only be installed when certain conditions are met.

      For example, if you need to install the latest version of cryptography that is available for a given Python major version you could define the following:

      cryptography==3.3.2; python_version < \"3\"\ncryptography>=35.0; python_version > \"3\"\n

      Alternatively, if you only need it on Python 3 when running on Windows you could do:

      cryptography; python_version ~= \"3.0\" and platform_system == \"Windows\"\n

      The available environment markers are as follows.

      Marker Python equivalent Examples os_name import osos.name
      • posix
      • java
      sys_platform import syssys.platform
      • linux
      • win32
      • darwin
      platform_machine import platformplatform.machine()
      • x86_64
      platform_python_implementation import platformplatform.python_implementation()
      • CPython
      • Jython
      platform_release import platformplatform.release()
      • 1.8.0_51
      • 3.14.1-x86_64-linode39
      platform_system import platformplatform.system()
      • Linux
      • Windows
      • Darwin
      platform_version import platformplatform.version()
      • 10.0.19041
      • #1 SMP Fri Apr 2 22:23:49 UTC 2021
      python_version import platform'.'.join(platform.python_version_tuple()[:2])
      • 2.7
      • 3.10
      python_full_version import platformplatform.python_version()
      • 2.7.18
      • 3.11.0b1
      implementation_name import syssys.implementation.name
      • cpython
      implementation_version See here
      • 2.7.18
      • 3.11.0b1
      "},{"location":"config/dependency/#features","title":"Features","text":"

      You can select groups of optional dependencies to install using the extras syntax. For example, if a dependency named foo defined the following:

      pyproject.toml
      [project.optional-dependencies]\ncrypto = [\n  \"PyJWT\",\n  \"cryptography\",\n]\nfastjson = [\n  \"orjson\",\n]\ncli = [\n  \"prompt-toolkit\",\n  \"colorama; platform_system == 'Windows'\",\n]\n

      You can select the cli and crypto features like so:

      foo[cli,crypto]==1.*\n

      Note that the features come immediately after the package name, before any version specifiers.

      "},{"location":"config/dependency/#self-referential","title":"Self-referential","text":"

      Feature groups can self-referentially extend others. For example, for a project called awesome-project, the dev feature group in the following pyproject.toml file would select everything in the crypto feature group, plus black:

      pyproject.toml
      [project]\nname = \"awesome-project\"\n\n[project.optional-dependencies]\ncrypto = [\n  \"PyJWT\",\n  \"cryptography\",\n]\ndev = [\n  \"awesome-project[crypto]\",\n  \"black\",\n]\n
      "},{"location":"config/dependency/#direct-references","title":"Direct references","text":"

      Instead of using normal version specifiers and fetching packages from an index like PyPI, you can define exact sources using direct references with an explicit URI.

      Direct references are usually not meant to be used for dependencies of a published project but rather are used for defining dependencies for an environment.

      All direct reference types are prefixed by the package name like:

      <NAME> @ <REFERENCE>\n
      "},{"location":"config/dependency/#version-control-systems","title":"Version control systems","text":"

      Various version control systems (VCS) are supported as long as the associated executable is available along your PATH.

      VCS direct references are defined using one of the following formats:

      <NAME> @ <SCHEME>://<PATH>\n<NAME> @ <SCHEME>://<PATH>@<REVISION>\n

      You may also append a #subdirectory=<PATH> component for specifying the relative path to the Python package when it is not located at the root e.g. #subdirectory=lib/foo.

      For more information, refer to this.

      "},{"location":"config/dependency/#supported-vcs","title":"Supported VCS","text":"GitMercurialSubversionBazaar Executable Schemes Revisions Example git
      • git+file
      • git+https
      • git+ssh
      • git+http
      • git+git
      • git
      • Commit hash
      • Tag name
      • Branch name
      proj @ git+https://github.com/org/proj.git@v1 Executable Schemes Revisions Example hg
      • hg+file
      • hg+https
      • hg+ssh
      • hg+http
      • hg+static-http
      • Revision hash
      • Revision number
      • Tag name
      • Branch name
      proj @ hg+file:///path/to/proj@v1 Executable Schemes Revisions Example svn
      • svn+https
      • svn+ssh
      • svn+http
      • svn+svn
      • svn
      • Revision number
      proj @ svn+file:///path/to/proj Executable Schemes Revisions Example bzr
      • bzr+https
      • bzr+ssh
      • bzr+sftp
      • bzr+lp
      • bzr+http
      • bzr+ftp
      • Revision number
      • Tag name
      proj @ bzr+lp:proj@v1"},{"location":"config/dependency/#local","title":"Local","text":"

      You can install local packages with the file scheme in the following format:

      <NAME> @ file://<HOST>/<PATH>\n

      The <HOST> is only used on Windows systems, where it can refer to a network share. If omitted it is assumed to be localhost and the third slash must still be present.

      The <PATH> can refer to a source archive, a wheel, or a directory containing a Python package.

      Type Unix Windows Source archive proj @ file:///path/to/pkg.tar.gz proj @ file:///c:/path/to/pkg.tar.gz Wheel proj @ file:///path/to/pkg.whl proj @ file:///c:/path/to/pkg.whl Directory proj @ file:///path/to/pkg proj @ file:///c:/path/to/pkg

      Tip

      You may also specify paths relative to your project's root directory on all platforms by using context formatting:

      <NAME> @ {root:uri}/pkg_inside_project\n<NAME> @ {root:uri}/../pkg_alongside_project\n
      "},{"location":"config/dependency/#remote","title":"Remote","text":"

      You can install source archives and wheels by simply referring to a URL:

      black @ https://github.com/psf/black/archive/refs/tags/21.10b0.zip\npytorch @ https://download.pytorch.org/whl/cu102/torch-1.10.0%2Bcu102-cp39-cp39-linux_x86_64.whl\n

      An expected hash value may be specified by appending a #<HASH_ALGORITHM>=<EXPECTED_HASH> component:

      requests @ https://github.com/psf/requests/archive/refs/tags/v2.26.0.zip#sha256=eb729a757f01c10546ebd179ae2aec852dd0d7f8ada2328ccf4558909d859985\n

      If the hash differs from the expected hash, the installation will fail.

      It is recommended that only hashes which are unconditionally provided by the latest version of the standard library's hashlib module be used for hashes. As of Python 3.10, that list consists of:

      • md5
      • sha1
      • sha224
      • sha256
      • sha384
      • sha512
      • blake2b
      • blake2s
      "},{"location":"config/dependency/#complex-syntax","title":"Complex syntax","text":"

      The following is an example that uses features and environment markers:

      pkg[feature1,feature2] @ <REFERENCE> ; python_version < \"3.7\"\n

      Note that the space before the semicolon is required.

      "},{"location":"config/hatch/","title":"Hatch configuration","text":"

      Configuration for Hatch itself is stored in a config.toml file located by default in one of the following platform-specific directories.

      Platform Path macOS ~/Library/Application Support/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch Unix $XDG_CONFIG_HOME/hatch (the XDG_CONFIG_HOME environment variable default is ~/.config)

      You can select a custom path to the file using the --config root option or by setting the HATCH_CONFIG environment variable.

      The file can be managed by the config command group.

      "},{"location":"config/hatch/#mode","title":"Mode","text":"

      The mode key controls how Hatch selects the project to work on.

      "},{"location":"config/hatch/#local","title":"Local","text":"config.toml
      mode = \"local\"\n

      By default, Hatch will look for a pyproject.toml file in the current working directory and any parent directories. The directory storing the first found file will be considered the project root.

      "},{"location":"config/hatch/#project","title":"Project","text":"config.toml
      mode = \"project\"\nproject = \"proj1\"\n\n[projects]\nproj1 = \"/path/to/project1\"\nproj2 = {\"location\": \"/path/to/project2\"}\n\n[dirs]\nproject = [\"/path/to/monorepo1\", \"/path/to/monorepo2\"]\n

      In this mode, Hatch will only work on the selected project. The project is located using multiple heuristics:

      1. If the project is defined in the projects table then it must be a string, or an inline table with a location key, that is the full path to the project.
      2. If the project matches a subdirectory in any of the directories listed in dirs.project, then that will be used as the project root.

      An error will occur if the project cannot be found.

      You can use the config set command to change the project you are working on:

      $ hatch config set project proj2\nNew setting:\nproject = \"proj2\"\n

      The project can be selected on a per-command basis with the -p/--project (environment variable HATCH_PROJECT) root option.

      "},{"location":"config/hatch/#aware","title":"Aware","text":"config.toml
      mode = \"aware\"\n

      This is essentially the local mode with a fallback to the project mode.

      "},{"location":"config/hatch/#shell","title":"Shell","text":"

      You can control the shell used to enter environments with the shell key.

      If defined as a string, it must be the name of one of the supported shells and be available along your PATH.

      config.toml
      shell = \"fish\"\n

      If the executable name of your shell differs from the supported name, you can define the shell as a table with name and path keys.

      config.toml
      [shell]\nname = \"bash\"\npath = \"/bin/ash\"\n

      You can change the default arguments used to spawn most shells with the args key. The default for such supported shells is usually [\"-i\"].

      config.toml
      [shell]\nname = \"bash\"\nargs = [\"--login\"]\n
      "},{"location":"config/hatch/#supported","title":"Supported","text":"Shell Name Arguments macOS Windows Unix Almquist shell ash [\"-i\"] Bash bash [\"-i\"] Command Prompt cmd C shell csh [\"-i\"] fish fish [\"-i\"] Nushell nu [] PowerShell pwsh, powershell tcsh tcsh [\"-i\"] xonsh xonsh [\"-i\"] Z shell zsh [\"-i\"]"},{"location":"config/hatch/#default","title":"Default","text":"

      Hatch will attempt to use the current shell based on parent processes. If the shell cannot be determined, then on Windows systems Hatch will use the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

      "},{"location":"config/hatch/#directories","title":"Directories","text":""},{"location":"config/hatch/#data","title":"Data","text":"config.toml
      [dirs]\ndata = \"...\"\n

      This is the directory that is used to persist data. By default it is set to one of the following platform-specific directories.

      Platform Path macOS ~/Library/Application Support/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch Unix $XDG_DATA_HOME/hatch (the XDG_DATA_HOME environment variable default is ~/.local/share)

      You can select a custom path to the directory using the --data-dir root option or by setting the HATCH_DATA_DIR environment variable.

      "},{"location":"config/hatch/#cache","title":"Cache","text":"config.toml
      [dirs]\ncache = \"...\"\n

      This is the directory that is used to cache data. By default it is set to one of the following platform-specific directories.

      Platform Path macOS ~/Library/Caches/hatch Windows %USERPROFILE%\\AppData\\Local\\hatch\\Cache Unix $XDG_CACHE_HOME/hatch (the XDG_CACHE_HOME environment variable default is ~/.cache)

      You can select a custom path to the directory using the --cache-dir root option or by setting the HATCH_CACHE_DIR environment variable.

      "},{"location":"config/hatch/#environments","title":"Environments","text":"config.toml
      [dirs.env]\n<ENV_TYPE> = \"...\"\n

      This determines where to store environments, with every key being the type of environment and the value being the desired storage location.

      For example, if you wanted to store virtual environments in a .virtualenvs directory within your home directory, you could specify the following:

      config.toml
      [dirs.env]\nvirtual = \"~/.virtualenvs\"\n

      Any environment variables are also expanded.

      If the path is not absolute, then it will be relative to the project root. So if you wanted to use a directory named .hatch in each project directory, you could do:

      config.toml
      [dirs.env]\nvirtual = \".hatch\"\n

      Any type of environment that is not explicitly defined will default to <DATA_DIR>/env/<ENV_TYPE>.

      "},{"location":"config/hatch/#python-installations","title":"Python installations","text":"config.toml
      [dirs]\npython = \"...\"\n

      This determines where to install specific versions of Python.

      The following values have special meanings:

      Value Path isolated (default) <DATA_DIR>/pythons"},{"location":"config/hatch/#terminal","title":"Terminal","text":"

      You can configure how all output is displayed using the terminal.styles table. These settings are also applied to all plugins.

      config.toml
      [terminal.styles]\nerror = \"...\"\n...\n

      Cross-platform terminal capabilities are provided by Rich.

      "},{"location":"config/hatch/#output-levels","title":"Output levels","text":"

      The levels of output are as follows. Note that the verbosity indicates the minimum level at which the output is displayed.

      Level Default Verbosity Description debug bold 1 - 3 Messages that are not useful for most user experiences error bold red -2 Messages indicating some unrecoverable error info bold 0 Messages conveying basic information success bold cyan 0 Messages indicating some positive outcome waiting bold magenta 0 Messages shown before potentially time consuming operations warning bold yellow -1 Messages conveying important information

      See the documentation and color reference for guidance on valid values.

      "},{"location":"config/hatch/#spinner","title":"Spinner","text":"

      You can select the sequence used for waiting animations with the spinner option.

      config.toml
      [terminal.styles]\nspinner = \"...\"\n
      "},{"location":"config/metadata/","title":"Configuring project metadata","text":"

      Project metadata is stored in a pyproject.toml file located at the root of a project's tree and is based entirely on the standard.

      "},{"location":"config/metadata/#name","title":"Name (required)","text":"

      The name of the project.

      pyproject.toml
      [project]\nname = \"your-app\"\n
      "},{"location":"config/metadata/#version","title":"Version (required)","text":"pyproject.toml DynamicStatic

      See the dedicated versioning section.

      [project]\n...\ndynamic = [\"version\"]\n\n[tool.hatch.version]\npath = \"...\"\n
      [project]\n...\nversion = \"0.0.1\"\n
      "},{"location":"config/metadata/#description","title":"Description","text":"

      A brief summary of the project.

      pyproject.toml
      [project]\n...\ndescription = '...'\n
      "},{"location":"config/metadata/#readme","title":"Readme","text":"

      The full description of the project.

      pyproject.toml SimpleComplex

      The file extension must be .md, .rst, or .txt.

      [project]\n...\nreadme = \"README.md\"\n

      The content-type field must be set to text/markdown, text/x-rst, or text/plain.

      FileText

      A charset field may also be set to instruct which encoding to use for reading the file, defaulting to utf-8.

      [project]\n...\nreadme = {\"file\" = \"README.md\", \"content-type\" = \"text/markdown\"}\n

      The content-type field must be set to text/markdown or text/x-rst.

      [project]\n...\nreadme = {\"text\" = \"...\", \"content-type\" = \"text/markdown\"}\n

      Note

      If this is defined as a file, then it will always be included in source distributions for consistent builds.

      "},{"location":"config/metadata/#python-support","title":"Python support","text":"

      The Python version requirements of the project.

      pyproject.toml
      [project]\n...\nrequires-python = \">=3.8\"\n
      "},{"location":"config/metadata/#license","title":"License","text":"

      For more information, see PEP 639.

      pyproject.toml SPDX expressionFiles
      [project]\n...\nlicense = \"Apache-2.0 OR MIT\"\n
      PathsGlobs
      [project]\n...\nlicense-files = { paths = [\"LICENSE.txt\"] }\n
      [project]\n...\nlicense-files = { globs = [\"LICENSES/*\"] }\n
      "},{"location":"config/metadata/#ownership","title":"Ownership","text":"

      The people or organizations considered to be the authors or maintainers of the project. The exact meaning is open to interpretation; it may list the original or primary authors, current maintainers, or owners of the package. If the values are the same, prefer only the use of the authors field.

      pyproject.toml
      [project]\n...\nauthors = [\n  { name = \"...\", email = \"...\" },\n]\nmaintainers = [\n  { name = \"...\", email = \"...\" },\n]\n
      "},{"location":"config/metadata/#keywords","title":"Keywords","text":"

      The keywords used to assist in the discovery of the project.

      pyproject.toml
      [project]\n...\nkeywords = [\n  \"...\",\n]\n
      "},{"location":"config/metadata/#classifiers","title":"Classifiers","text":"

      The trove classifiers that apply to the project.

      pyproject.toml
      [project]\n...\nclassifiers = [\n  \"...\",\n]\n
      "},{"location":"config/metadata/#urls","title":"URLs","text":"

      A table of URLs where the key is the URL label and the value is the URL itself.

      pyproject.toml
      [project.urls]\nDocumentation = \"...\"\n\"Source code\" = \"...\"\n
      "},{"location":"config/metadata/#dependencies","title":"Dependencies","text":"

      See the dependency specification page for more information.

      Entries support context formatting and disallow direct references by default.

      "},{"location":"config/metadata/#required","title":"Required","text":"pyproject.toml
      [project]\n...\ndependencies = [\n  \"...\",\n]\n
      "},{"location":"config/metadata/#optional","title":"Optional","text":"pyproject.toml
      [project.optional-dependencies]\noption1 = [\n  \"...\",\n]\noption2 = [\n  \"...\",\n]\n
      "},{"location":"config/metadata/#entry-points","title":"Entry points","text":"

      Entry points are a mechanism for the project to advertise components it provides to be discovered and used by other code.

      "},{"location":"config/metadata/#cli","title":"CLI","text":"

      After installing projects that define CLI scripts, each key will be available along your PATH as a command that will call its associated object.

      pyproject.toml
      [project.scripts]\ncli-name = \"pkg.subpkg:func\"\n

      Using the above example, running cli-name would essentially execute the following Python script:

      import sys\n\nfrom pkg.subpkg import func\n\nsys.exit(func())\n
      "},{"location":"config/metadata/#gui","title":"GUI","text":"

      GUI scripts are exactly the same as CLI scripts except on Windows, where they are handled specially so that they can be started without a console.

      pyproject.toml
      [project.gui-scripts]\ngui-name = \"pkg.subpkg:func\"\n
      "},{"location":"config/metadata/#plugins","title":"Plugins","text":"pyproject.toml
      [project.entry-points.plugin-namespace]\nplugin-name1 = \"pkg.subpkg1\"\nplugin-name2 = \"pkg.subpkg2:func\"\n
      "},{"location":"config/metadata/#dynamic","title":"Dynamic","text":"

      If any metadata fields are set dynamically, like the version may be, then they must be listed here.

      pyproject.toml
      [project]\n...\ndynamic = [\n  \"...\",\n]\n
      "},{"location":"config/metadata/#metadata-options","title":"Metadata options","text":""},{"location":"config/metadata/#allowing-direct-references","title":"Allowing direct references","text":"

      By default, dependencies are not allowed to define direct references. To disable this check, set allow-direct-references to true:

      pyproject.toml hatch.toml
      [tool.hatch.metadata]\nallow-direct-references = true\n
      [metadata]\nallow-direct-references = true\n
      "},{"location":"config/metadata/#allowing-ambiguous-features","title":"Allowing ambiguous features","text":"

      By default, names of optional dependencies are normalized to prevent ambiguity. To disable this normalization, set allow-ambiguous-features to true:

      pyproject.toml hatch.toml
      [tool.hatch.metadata]\nallow-ambiguous-features = true\n
      [metadata]\nallow-ambiguous-features = true\n

      Deprecated

      This option temporarily exists to provide better interoperability with tools that do not yet support PEP 685 and will be removed in the first minor release after Jan 1, 2024.

      "},{"location":"config/project-templates/","title":"Project templates","text":"

      You can control how new projects are created by the new command using Hatch's config file.

      "},{"location":"config/project-templates/#author","title":"Author","text":"config.toml
      [template]\nname = \"...\"\nemail = \"...\"\n
      "},{"location":"config/project-templates/#licenses","title":"Licenses","text":"config.toml
      [template.licenses]\nheaders = true\ndefault = [\n  \"MIT\",\n]\n

      The list of licenses should be composed of SPDX identifiers. If multiple licenses are specified, then they will be placed in a LICENSES directory.

      "},{"location":"config/project-templates/#options","title":"Options","text":""},{"location":"config/project-templates/#tests","title":"Tests","text":"

      This adds a tests directory with environments for testing and linting.

      config.toml
      [template.plugins.default]\ntests = true\n
      "},{"location":"config/project-templates/#ci","title":"CI","text":"

      This adds a GitHub Actions workflow that runs tests on all platforms using modern versions of Python.

      config.toml
      [template.plugins.default]\nci = false\n
      "},{"location":"config/project-templates/#src-layout","title":"src layout","text":"

      See this blog post.

      config.toml
      [template.plugins.default]\nsrc-layout = true\n
      "},{"location":"config/project-templates/#feature-flags","title":"Feature flags","text":""},{"location":"config/project-templates/#command-line-interface","title":"Command line interface","text":"

      The --cli flag adds a CLI backed by Click that can also be invoked with python -m <PKG_NAME>.

      "},{"location":"config/static-analysis/","title":"Static analysis configuration","text":"

      Static analysis performed by the fmt command is (by default) backed entirely by Ruff.

      Hatch provides default settings that user configuration can extend.

      "},{"location":"config/static-analysis/#extending-config","title":"Extending config","text":"

      When defining your configuration, be sure to use options that are prefixed by extend- such as extend-select, for example:

      pyproject.toml ruff.toml
      [tool.ruff.format]\npreview = true\nquote-style = \"single\"\n\n[tool.ruff.lint]\npreview = true\nextend-select = [\"C901\"]\n\n[tool.ruff.lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[tool.ruff.lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n
      [format]\npreview = true\nquote-style = \"single\"\n\n[lint]\npreview = true\nextend-select = [\"C901\"]\n\n[lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n

      Note

      When not persisting config, there is no need to explicitly extend the defaults as Hatch automatically handles that.

      "},{"location":"config/static-analysis/#persistent-config","title":"Persistent config","text":"

      If you want to store the default configuration in the project, set an explicit path like so:

      pyproject.toml hatch.toml
      [tool.hatch.envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n
      [envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n

      Then instruct Ruff to consider your configuration as an extension of the default file:

      pyproject.toml ruff.toml
      [tool.ruff]\nextend = \"ruff_defaults.toml\"\n
      extend = \"ruff_defaults.toml\"\n

      Anytime you wish to update the defaults (such as when upgrading Hatch), you must run the fmt command once with the --sync flag e.g.:

      hatch fmt --check --sync\n

      Tip

      This is the recommended approach since it allows other tools like IDEs to use the default configuration.

      "},{"location":"config/static-analysis/#no-config","title":"No config","text":"

      If you don't want Hatch to use any of its default configuration and rely entirely on yours, set the path to anything and then simply don't extend in your Ruff config:

      pyproject.toml hatch.toml
      [tool.hatch.envs.hatch-static-analysis]\nconfig-path = \"none\"\n
      [envs.hatch-static-analysis]\nconfig-path = \"none\"\n
      "},{"location":"config/static-analysis/#customize-behavior","title":"Customize behavior","text":"

      You can fully alter the behavior of the environment used by the fmt command. See the how-to for a detailed example.

      "},{"location":"config/static-analysis/#dependencies","title":"Dependencies","text":"

      Pin the particular version of Ruff by explicitly defining the environment dependencies:

      pyproject.toml hatch.toml
      [tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
      [envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
      "},{"location":"config/static-analysis/#scripts","title":"Scripts","text":"

      If you want to change the default commands that are executed, you can override the scripts. The following four scripts must be defined:

      pyproject.toml hatch.toml
      [tool.hatch.envs.hatch-static-analysis.scripts]\nformat-check = \"...\"\nformat-fix = \"...\"\nlint-check = \"...\"\nlint-fix = \"...\"\n
      [envs.hatch-static-analysis.scripts]\nformat-check = \"...\"\nformat-fix = \"...\"\nlint-check = \"...\"\nlint-fix = \"...\"\n

      The format-* scripts correspond to the --formatter/-f flag while the lint-* scripts correspond to the --linter/-l flag. The *-fix scripts run by default while the *-check scripts correspond to the --check flag.

      Reminder

      If you choose to use different tools for static analysis, be sure to update the required dependencies.

      "},{"location":"config/static-analysis/#default-settings","title":"Default settings","text":""},{"location":"config/static-analysis/#non-rule-settings","title":"Non-rule settings","text":"
      • Line length set to 120
      • Docstring formatting enabled with line length set to 80
      • Only absolute imports are allowed, except for tests
      • The normalized project name is a known first party import
      "},{"location":"config/static-analysis/#per-file-ignored-rules","title":"Per-file ignored rules","text":"
      • **/scripts/*: INP001, T201
      • **/tests/**/*: PLC1901, PLR2004, PLR6301, S, TID252
      "},{"location":"config/static-analysis/#selected-rules","title":"Selected rules","text":"

      The following rules are based on version 0.3.1 of Ruff. Rules with a P are only selected when preview mode is enabled.

      • A001, A002, A003
      • ARG001, ARG002, ARG003, ARG004, ARG005
      • ASYNC100, ASYNC101, ASYNC102
      • B002, B003, B004, B005, B006, B007, B008, B009, B010, B011, B012, B013, B014, B015, B016, B017, B018, B019, B020, B021, B022, B023, B024, B025, B026, B028, B029, B030, B031, B032, B033, B034, B035, B904, B905
      • BLE001
      • C400, C401, C402, C403, C404, C405, C406, C408, C409, C410, C411, C413, C414, C415, C416, C417, C418, C419
      • COM818
      • DTZ001, DTZ002, DTZ003, DTZ004, DTZ005, DTZ006, DTZ007, DTZ011, DTZ012
      • E101, E112P, E113P, E115P, E116P, E201P, E202P, E203P, E211P, E221P, E222P, E223P, E224P, E225P, E226P, E227P, E228P, E231P, E241P, E242P, E251P, E252P, E261P, E262P, E265P, E266P, E271P, E272P, E273P, E274P, E275P, E401, E402, E501, E701, E702, E703, E711, E712, E713, E714, E721, E722, E731, E741, E742, E743, E902, E999
      • EM101, EM102, EM103
      • EXE001, EXE002, EXE003, EXE004, EXE005
      • F401, F402, F403, F404, F405, F406, F407, F501, F502, F503, F504, F505, F506, F507, F508, F509, F521, F522, F523, F524, F525, F541, F601, F602, F621, F622, F631, F632, F633, F634, F701, F702, F704, F706, F707, F722, F811, F821, F822, F823, F841, F842, F901
      • FA100, FA102
      • FBT001, FBT002
      • FLY002
      • FURB105P, FURB113P, FURB118P, FURB129P, FURB131P, FURB132P, FURB136P, FURB145P, FURB148P, FURB152P, FURB161P, FURB163P, FURB167P, FURB168P, FURB169P, FURB171P, FURB177P, FURB180P, FURB181P
      • G001, G002, G003, G004, G010, G101, G201, G202
      • I001, I002
      • ICN001, ICN002, ICN003
      • INP001
      • INT001, INT002, INT003
      • ISC003
      • LOG001, LOG002, LOG007, LOG009
      • N801, N802, N803, N804, N805, N806, N807, N811, N812, N813, N814, N815, N816, N817, N818, N999
      • PERF101, PERF102, PERF401, PERF402, PERF403P
      • PGH005
      • PIE790, PIE794, PIE796, PIE800, PIE804, PIE807, PIE808, PIE810
      • PLC0105, PLC0131, PLC0132, PLC0205, PLC0208, PLC0414, PLC0415P, PLC1901P, PLC2401P, PLC2403P, PLC2701P, PLC2801P, PLC3002
      • PLE0100, PLE0101, PLE0116, PLE0117, PLE0118, PLE0237, PLE0241, PLE0302, PLE0307, PLE0604, PLE0605, PLE0643P, PLE0704P, PLE1132P, PLE1141P, PLE1142, PLE1205, PLE1206, PLE1300, PLE1307, PLE1310, PLE1507, PLE1519P, PLE1700, PLE2502, PLE2510, PLE2512, PLE2513, PLE2514, PLE2515
      • PLR0124, PLR0133, PLR0202P, PLR0203P, PLR0206, PLR0402, PLR1701, PLR1704P, PLR1711, PLR1714, PLR1722, PLR1733P, PLR1736P, PLR2004, PLR2044P, PLR5501, PLR6201P, PLR6301P
      • PLW0108P, PLW0120, PLW0127, PLW0129, PLW0131, PLW0133P, PLW0245P, PLW0406, PLW0602, PLW0603, PLW0604P, PLW0711, PLW1501P, PLW1508, PLW1509, PLW1510, PLW1514P, PLW1641P, PLW2101P, PLW2901, PLW3201P, PLW3301
      • PT001, PT002, PT003, PT006, PT007, PT008, PT009, PT010, PT011, PT012, PT013, PT014, PT015, PT016, PT017, PT018, PT019, PT020, PT021, PT022, PT023, PT024, PT025, PT026, PT027
      • PYI001, PYI002, PYI003, PYI004, PYI005, PYI006, PYI007, PYI008, PYI009, PYI010, PYI011, PYI012, PYI013, PYI014, PYI015, PYI016, PYI017, PYI018, PYI019, PYI020, PYI021, PYI024, PYI025, PYI026, PYI029, PYI030, PYI032, PYI033, PYI034, PYI035, PYI036, PYI041, PYI042, PYI043, PYI044, PYI045, PYI046, PYI047, PYI048, PYI049, PYI050, PYI051, PYI052, PYI053, PYI054, PYI055, PYI056, PYI058
      • RET503, RET504, RET505, RET506, RET507, RET508
      • RSE102
      • RUF001, RUF002, RUF003, RUF005, RUF006, RUF007, RUF008, RUF009, RUF010, RUF012, RUF013, RUF015, RUF016, RUF017, RUF018, RUF019, RUF020, RUF021P, RUF022P, RUF023P, RUF024P, RUF025P, RUF026P, RUF027P, RUF028P, RUF100, RUF200
      • S101, S102, S103, S104, S105, S106, S107, S108, S110, S112, S113, S201, S202, S301, S302, S303, S304, S305, S306, S307, S308, S310, S311, S312, S313, S314, S315, S316, S317, S318, S319, S320, S321, S323, S324, S401P, S402P, S403P, S405P, S406P, S407P, S408P, S409P, S411P, S412P, S413P, S415P, S501, S502, S503, S504, S505, S506, S507, S508, S509, S601, S602, S604, S605, S606, S607, S608, S609, S611, S612, S701, S702
      • SIM101, SIM102, SIM103, SIM105, SIM107, SIM108, SIM109, SIM110, SIM112, SIM113, SIM114, SIM115, SIM116, SIM117, SIM118, SIM201, SIM202, SIM208, SIM210, SIM211, SIM212, SIM220, SIM221, SIM222, SIM223, SIM300, SIM910, SIM911
      • SLF001
      • SLOT000, SLOT001, SLOT002
      • T100, T201, T203
      • TCH001, TCH002, TCH003, TCH004, TCH005, TCH010
      • TD004, TD005, TD006, TD007
      • TID251, TID252, TID253
      • TRIO100, TRIO105, TRIO109, TRIO110, TRIO115
      • TRY002, TRY003, TRY004, TRY201, TRY300, TRY301, TRY302, TRY400, TRY401
      • UP001, UP003, UP004, UP005, UP006, UP007, UP008, UP009, UP010, UP011, UP012, UP013, UP014, UP015, UP017, UP018, UP019, UP020, UP021, UP022, UP023, UP024, UP025, UP026, UP027, UP028, UP029, UP030, UP031, UP032, UP033, UP034, UP035, UP036, UP037, UP038, UP039, UP040, UP041
      • W291, W292, W293, W505, W605
      • YTT101, YTT102, YTT103, YTT201, YTT202, YTT203, YTT204, YTT301, YTT302, YTT303
      "},{"location":"config/environment/advanced/","title":"Advanced environment configuration","text":""},{"location":"config/environment/advanced/#context-formatting","title":"Context formatting","text":"

      All environments support the following extra context formatting fields:

      Field Description env_name The name of the environment env_type The type of environment matrix Its modifier selects the value of that matrix variable. If the environment is not part of a matrix or was not generated with the variable, you must specify a default value as an additional modifier e.g. {matrix:version:v1.0.0}. verbosity The integer verbosity value of Hatch. A flag modifier is supported that will render the value as a CLI flag e.g. -2 becomes -qq, 1 becomes -v, and 0 becomes an empty string. An additional flag integer modifier may be used to adjust the verbosity level. For example, if you wanted to make a command quiet by default, you could use {verbosity:flag:-1} within the command. args For executed commands only, any extra command line arguments with an optional default modifier if none were provided"},{"location":"config/environment/advanced/#matrix","title":"Matrix","text":"

      Environments can define a series of matrices with the matrix option:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
      [envs.test]\ndependencies = [\n  \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n

      Doing so will result in the product of each variable combination being its own environment.

      "},{"location":"config/environment/advanced/#naming","title":"Naming","text":"

      The name of the generated environments will be the variable values of each combination separated by hyphens, altogether prefixed by <ENV_NAME>.. For example, the following configuration:

      pyproject.toml hatch.toml
      [[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
      [[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n

      would indicate the following unique environments:

      test.42-foo\ntest.42-bar\n

      The exceptions to this format are described below.

      "},{"location":"config/environment/advanced/#python-variables","title":"Python variables","text":"

      If the variables py or python are specified, then they will rank first in the product result and will be prefixed by py if the value is not. For example, the following configuration:

      pyproject.toml hatch.toml
      [[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n
      [[envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n

      would generate the following environments:

      test.py3.9-42\ntest.pypy3-42\n

      Note

      The value of this variable sets the Python version.

      "},{"location":"config/environment/advanced/#name-formatting","title":"Name formatting","text":"

      You can set the matrix-name-format option to modify how each variable part is formatted which recognizes the placeholders {variable} and {value}. For example, the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
      [envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n

      would produce the following environments:

      test.version_42-feature_foo\ntest.version_42-feature_bar\n

      By default this option is set to {value}.

      "},{"location":"config/environment/advanced/#default-environment","title":"Default environment","text":"

      If the default environment defines matrices, then the generated names will not be prefixed by the environment name. This can be useful for projects that only need a single series of matrices without any standalone environments.

      "},{"location":"config/environment/advanced/#selection","title":"Selection","text":"

      Rather than selecting a single generated environment, you can select the root environment to target all of them. For example, if you have the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[tool.hatch.envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n
      [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n

      you could then run your tests consecutively in all 4 environments with:

      hatch run test:cov\n
      "},{"location":"config/environment/advanced/#option-overrides","title":"Option overrides","text":"

      You can modify options based on the conditions of different sources like matrix variables with the overrides table, using dotted key syntax for each declaration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n
      [envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n

      The type of the selected option determines the types of values.

      "},{"location":"config/environment/advanced/#platform-overrides","title":"Platform overrides","text":"

      Options can be modified based on the current platform using the platform source.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nplatform.windows.scripts = [\n  'run=pytest -m \"not io_uring\"',\n]\n
      [envs.test.overrides]\nplatform.windows.scripts = [\n  'run=pytest -m \"not io_uring\"',\n]\n

      The following platforms are supported:

      • linux
      • windows
      • macos
      "},{"location":"config/environment/advanced/#environment-variable-overrides","title":"Environment variable overrides","text":"

      Environment variables can modify options using the env source.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
      [envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
      "},{"location":"config/environment/advanced/#matrix-variable-overrides","title":"Matrix variable overrides","text":"

      The matrix variables used to generate each environment can be used to modify options within using the matrix source.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n  { value = \"oauth\", if = [\"oauth2\"] },\n  { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
      [envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n  { value = \"oauth\", if = [\"oauth2\"] },\n  { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[envs.test.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
      "},{"location":"config/environment/advanced/#name-overrides","title":"Name overrides","text":"

      When a matrix is defined, the name source can be used for regular expression matching on the generated name, minus the prefix for non-default environments.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
      [envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
      "},{"location":"config/environment/advanced/#types","title":"Types","text":"
      • Literal types like strings for the Python version or booleans for skipping installation can be set using the value itself, an inline table, or an array. For example:

        pyproject.toml hatch.toml
        [tool.hatch.envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n  { value = false, if = [\"...\"] },\n  true,\n]\n
        [envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n  { value = false, if = [\"...\"] },\n  true,\n]\n

        For arrays, the first allowed value will be used.

      • Array types like dependencies or commands can be appended to using an array of strings or inline tables. For example:

        pyproject.toml hatch.toml
        [tool.hatch.envs.test.overrides]\nmatrix.foo.dependencies = [\n  \"httpx\",\n  { value = \"cryptography\" },\n]\n
        [envs.test.overrides]\nmatrix.foo.dependencies = [\n  \"httpx\",\n  { value = \"cryptography\" },\n]\n
      • Mapping types like environment variables or scripts can have keys set using a string, or an array of strings or inline tables. For example:

        pyproject.toml hatch.toml
        [tool.hatch.envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n  \"KEY1=VALUE1\",\n  { key = \"KEY2\", value = \"VALUE2\" },\n]\n
        [envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n  \"KEY1=VALUE1\",\n  { key = \"KEY2\", value = \"VALUE2\" },\n]\n

        If the value is missing (no = for strings, no value key for inline tables), then the value will be set to the value of the source condition.

      "},{"location":"config/environment/advanced/#overwriting","title":"Overwriting","text":"

      Rather than supplementing the values within mapping types or array types, you can overwrite the option as a whole by prefixing the name with set-:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n
      [envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n

      When overwriting entire options or keys within mappings, override sources are applied in the following order:

      1. platform
      2. environment variables
      3. matrix variables
      4. names
      "},{"location":"config/environment/advanced/#conditions","title":"Conditions","text":"

      You may specify certain extra keys for any inline table that will determine whether or not to apply that entry. These modifiers may be combined with others and any negative evaluation will immediately cause the entry to be skipped.

      "},{"location":"config/environment/advanced/#allowed-values","title":"Allowed values","text":"

      The if key represents the allowed values for that condition. If the value of the condition is not listed, then that entry will not be applied:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      [envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      "},{"location":"config/environment/advanced/#specific-platforms","title":"Specific platforms","text":"

      The platform key represents the desired platforms. If the current platform is not listed, then that entry will not be applied:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      [envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      "},{"location":"config/environment/advanced/#required-environment-variables","title":"Required environment variables","text":"

      The env key represents the required environment variables. If any of the listed environment variables are not set or the defined value does not match, then that entry will not be applied:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      [envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n  { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n  { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
      "},{"location":"config/environment/overview/","title":"Environment configuration","text":"

      All environments are defined as sections within the tool.hatch.envs table.

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\n
      [envs.<ENV_NAME>]\n

      The storage location for environments is completely configurable.

      Unless an environment is explicitly selected on the command line, the default environment will be used. The type of this environment defaults to virtual.

      Info

      Environments prefixed by hatch- are used for special purposes e.g. static analysis.

      "},{"location":"config/environment/overview/#inheritance","title":"Inheritance","text":"

      All environments inherit from the environment defined by its template option, which defaults to default.

      So for the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[tool.hatch.envs.bar]\ntemplate = \"foo\"\nskip-install = false\n
      [envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[envs.bar]\ntemplate = \"foo\"\nskip-install = false\n

      the environment bar will be of type baz with skip-install set to false.

      Note

      Environments do not inherit matrices.

      "},{"location":"config/environment/overview/#self-referential-environments","title":"Self-referential environments","text":"

      You can disable inheritance by setting template to the environment's own name:

      pyproject.toml hatch.toml
      [tool.hatch.envs.foo]\ntemplate = \"foo\"\n
      [envs.foo]\ntemplate = \"foo\"\n
      "},{"location":"config/environment/overview/#detached-environments","title":"Detached environments","text":"

      A common use case is standalone environments that do not require inheritance nor the installation of the project, such as for linting or sometimes building documentation. Enabling the detached option will make the environment self-referential and will skip project installation:

      pyproject.toml hatch.toml
      [tool.hatch.envs.lint]\ndetached = true\n
      [envs.lint]\ndetached = true\n
      "},{"location":"config/environment/overview/#dependencies","title":"Dependencies","text":"

      You can install dependencies in addition to the ones defined by your project's metadata. Entries support context formatting.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n
      [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n

      If you define environments with dependencies that only slightly differ from their inherited environments, you can use the extra-dependencies option to avoid redeclaring the dependencies option:

      pyproject.toml hatch.toml
      [tool.hatch.envs.default]\ndependencies = [\n  \"foo\",\n  \"bar\",\n]\n\n[tool.hatch.envs.experimental]\nextra-dependencies = [\n  \"baz\",\n]\n
      [envs.default]\ndependencies = [\n  \"foo\",\n  \"bar\",\n]\n\n[envs.experimental]\nextra-dependencies = [\n  \"baz\",\n]\n

      Tip

      Hatch uses pip to install dependencies so any configuration it supports Hatch does as well. For example, if you wanted to only use a private repository you could set the PIP_INDEX_URL environment variable.

      "},{"location":"config/environment/overview/#installation","title":"Installation","text":""},{"location":"config/environment/overview/#features","title":"Features (extras)","text":"

      If your project defines optional dependencies, you can select which groups to install using the features option:

      pyproject.toml hatch.toml
      [tool.hatch.envs.nightly]\nfeatures = [\n  \"server\",\n  \"grpc\",\n]\n
      [envs.nightly]\nfeatures = [\n  \"server\",\n  \"grpc\",\n]\n

      Note

      Features/optional dependencies are also known as extras in other tools.

      "},{"location":"config/environment/overview/#dev-mode","title":"Dev mode","text":"

      By default, environments will always reflect the current state of your project on disk. Set dev-mode to false to disable this behavior:

      pyproject.toml hatch.toml
      [tool.hatch.envs.static]\ndev-mode = false\n
      [envs.static]\ndev-mode = false\n
      "},{"location":"config/environment/overview/#skip-install","title":"Skip install","text":"

      By default, environments will install your project during creation. To ignore this step, set skip-install to true:

      pyproject.toml hatch.toml
      [tool.hatch.envs.lint]\nskip-install = true\n
      [envs.lint]\nskip-install = true\n
      "},{"location":"config/environment/overview/#environment-variables","title":"Environment variables","text":""},{"location":"config/environment/overview/#defined","title":"Defined","text":"

      You can define environment variables with the env-vars option:

      pyproject.toml hatch.toml
      [tool.hatch.envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[tool.hatch.envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
      [envs.docs]\ndependencies = [\n  \"mkdocs\"\n]\n[envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n

      Values support context formatting.

      "},{"location":"config/environment/overview/#filters","title":"Filters","text":"

      By default, environments will have access to all environment variables. You can filter with wildcard patterns using the env-include/env-exclude options:

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nenv-include = [\n  \"FOO*\",\n]\nenv-exclude = [\n  \"BAR\",\n]\n
      [envs.<ENV_NAME>]\nenv-include = [\n  \"FOO*\",\n]\nenv-exclude = [\n  \"BAR\",\n]\n

      Exclusion patterns take precedence but will never affect defined environment variables.

      "},{"location":"config/environment/overview/#scripts","title":"Scripts","text":"

      You can define named scripts that may be executed or referenced at the beginning of other scripts. Context formatting is supported.

      For example, in the following configuration:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n[tool.hatch.envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n
      [envs.test]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n  \"pytest-mock\",\n]\n[envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n

      the run script would be expanded to:

      pytest --cov-config=pyproject.toml --cov=pkg --cov=tests --no-cov\n

      Scripts can also be defined as an array of strings.

      pyproject.toml hatch.toml
      [tool.hatch.envs.style]\ndetached = true\ndependencies = [\n  \"flake8\",\n  \"black\",\n  \"isort\",\n]\n[tool.hatch.envs.style.scripts]\ncheck = [\n  \"flake8 .\",\n  \"black --check --diff .\",\n  \"isort --check-only --diff .\",\n]\nfmt = [\n  \"isort .\",\n  \"black .\",\n  \"check\",\n]\n
      [envs.style]\ndetached = true\ndependencies = [\n  \"flake8\",\n  \"black\",\n  \"isort\",\n]\n[envs.style.scripts]\ncheck = [\n  \"flake8 .\",\n  \"black --check --diff .\",\n  \"isort --check-only --diff .\",\n]\nfmt = [\n  \"isort .\",\n  \"black .\",\n  \"check\",\n]\n

      Similar to make, you can ignore the exit code of commands that start with - (a hyphen). For example, the script error defined by the following configuration would halt after the second command with 3 as the exit code:

      pyproject.toml hatch.toml
      [tool.hatch.envs.test.scripts]\nerror = [\n  \"- exit 1\",\n  \"exit 3\",\n  \"exit 0\",\n]\n
      [envs.test.scripts]\nerror = [\n  \"- exit 1\",\n  \"exit 3\",\n  \"exit 0\",\n]\n

      Tip

      Individual scripts inherit from parent environments just like options.

      "},{"location":"config/environment/overview/#commands","title":"Commands","text":"

      All commands are able to use any defined scripts. Also like scripts, context formatting is supported and the exit code of commands that start with a hyphen will be ignored.

      "},{"location":"config/environment/overview/#pre-install","title":"Pre-install","text":"

      You can run commands immediately before environments install your project.

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\npre-install-commands = [\n  \"...\",\n]\n
      [envs.<ENV_NAME>]\npre-install-commands = [\n  \"...\",\n]\n
      "},{"location":"config/environment/overview/#post-install","title":"Post-install","text":"

      You can run commands immediately after environments install your project.

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\npost-install-commands = [\n  \"...\",\n]\n
      [envs.<ENV_NAME>]\npost-install-commands = [\n  \"...\",\n]\n
      "},{"location":"config/environment/overview/#python-version","title":"Python version","text":"

      The python option specifies which version of Python to use, or an absolute path to a Python interpreter:

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\npython = \"3.10\"\n
      [envs.<ENV_NAME>]\npython = \"3.10\"\n

      All environment types should respect this option.

      "},{"location":"config/environment/overview/#supported-platforms","title":"Supported platforms","text":"

      The platforms option indicates the operating systems with which the environment is compatible:

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n
      [envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n

      The following platforms are supported:

      • linux
      • windows
      • macos

      If unspecified, the environment is assumed to be compatible with all platforms.

      "},{"location":"config/environment/overview/#description","title":"Description","text":"

      The description option is purely informational and is displayed in the output of the env show command:

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
      [envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
      "},{"location":"config/environment/overview/#type","title":"Type","text":"

      An environment's type determines which environment plugin will be used for management. The only built-in environment type is virtual, which uses virtual Python environments.

      "},{"location":"history/hatch/","title":"Hatch history","text":"

      All notable changes to Hatch will be documented in this file.

      The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

      "},{"location":"history/hatch/#unreleased","title":"Unreleased","text":"

      Added:

      • Add self report command for submitting pre-populated bug reports to GitHub
      • The reserved environment used for static analysis is now completely configurable
      • Add the following methods to the environment interface for complete control over output during life cycle management: app_status_creation, app_status_pre_installation, app_status_post_installation, app_status_project_installation, app_status_dependency_state_check, app_status_dependency_installation_check, app_status_dependency_synchronization
      • Add binaries for 32-bit versions of Windows
      • Read configuration from any ~/.pypirc file for the index publisher
      • Use the Git user as the default username for new project URL metadata
      • Add HATCH_DEBUG environment variable that when enabled will show local variables in the case of unhandled tracebacks
      • Upgrade default CPython distributions to 20240224
      • Upgrade Ruff to 0.3.1
      • Upgrade PyApp to 0.15.1 for binary builds
      • Bump the minimum supported version of Hatchling to 1.22.2

      Fixed:

      • When projects derive dependencies from metadata hooks, there is now by default a status indicator for when the hooks are executed for better responsiveness
      • Fix dependency inheritance for the template of the types environment for new projects
      "},{"location":"history/hatch/#hatch-v1.9.4","title":"1.9.4 - 2024-03-12","text":"

      Fixed:

      • Limit the maximum version of Hatchling in anticipation of backward incompatible changes
      "},{"location":"history/hatch/#hatch-v1.9.3","title":"1.9.3 - 2024-01-25","text":"

      Fixed:

      • Fix loading of local plugins to account for newly released versions of a dependency
      "},{"location":"history/hatch/#hatch-v1.9.2","title":"1.9.2 - 2024-01-21","text":"

      Fixed:

      • Fix the default token variable name for publishing to PyPI
      "},{"location":"history/hatch/#hatch-v1.9.1","title":"1.9.1 - 2023-12-25","text":"

      Fixed:

      • Ensure that the dependency_hash method of the environment interface is called after sync_dependencies for cases where the hash is only known at that point, such as for dependency lockers
      • Only acknowledge the HATCH_PYTHON_VARIANT_* environment variables for Python resolution for supported platforms and architectures
      • Fix Python resolution when there are metadata hooks with unsatisfied dependencies
      "},{"location":"history/hatch/#hatch-v1.9.0","title":"1.9.0 - 2023-12-19","text":"

      Changed:

      • Environments prefixed by hatch- are now considered internal and used for special purposes such as configuration for static analysis

      Added:

      • Enable docstring formatting by default for static analysis
      • Allow for overriding config of internal environments
      • Concretely state the expected API contract for the environment interface methods find and check_compatibility
      • Upgrade Ruff to 0.1.8
      • Bump the minimum supported version of Hatchling to 1.21.0

      Fixed:

      • Ignore a project's Python requirement for environments where the project is not installed
      • When not persisting config for static analysis, properly manage internal settings when Ruff's top level table already exists
      • Ignore compatibility checks when environments have already been created, significantly improving performance of environment usage
      • Properly allow overriding of the path option for the virtual environment type
      • Fix nushell activation on non-Windows systems
      "},{"location":"history/hatch/#hatch-v1.8.1","title":"1.8.1 - 2023-12-14","text":"

      Fixed:

      • Fix regression in calling subprocesses with updated PATH
      • Fix automatic installation of environment plugins when running as a standalone binary
      • Change default location of Python installations
      "},{"location":"history/hatch/#hatch-v1.8.0","title":"1.8.0 - 2023-12-11","text":"

      Changed:

      • Drop support for Python 3.7
      • The get_build_process method of the environment interface has been removed; plugins should use the new run_builder method instead
      • Remove pyperclip dependency and the --copy flag of the config find command
      • When running the build command all output from builders is now displayed as-is in real time without the stripping of ANSI codes
      • Version information (for Hatch itself) is now derived from Git

      Added:

      • Support Python 3.12
      • Add installers and standalone binaries
      • Add the ability to manage Python installations
      • Add fmt command
      • The virtual environment type can now automatically download requested versions of Python that are not installed
      • Add dependency_hash method to the environment interface
      • The state of installed dependencies for environments is saved as metadata so if dependency definitions have not changed then no checking is performed, which can be computationally expensive
      • The build command now supports backends other than Hatchling
      • Allow the use of features for environments when skip-install is enabled
      • The default is now __token__ when prompting for a username for the publish command
      • Add a new run_builder method to the environment interface
      • Bump the minimum supported version of Hatchling to 1.19.0
      • Bump the minimum supported version of click to 8.0.6

      Fixed:

      • Fix nushell activation
      • Better handling of flat storage directory hierarchies for the virtual environment type
      • Display useful information when running the version command outside of a project rather than erroring
      • Fix the project metadata command by only capturing stdout from the backend
      • Properly support Google Artifact Registry
      • Fix parsing dependencies for environments when warnings are emitted
      "},{"location":"history/hatch/#hatch-v1.7.0","title":"1.7.0 - 2023-04-03","text":"

      Changed:

      • The src-layout project template option is now enabled by default
      • Non-critical output now goes to stderr

      Added:

      • Add tool.hatch.env.requires configuration to automatically install dependencies for environment and environment collector plugins
      • Add custom environment collector
      • Improve syncing of dependencies provided through Git direct references
      • Add isolated_data_directory attribute to the environment interface
      • Increase the timeout for and add retries to the index publisher
      • Expand home and environment variables in configured cache and data directories
      • Improve readability of exceptions
      • Update project templates
      • Bump the minimum supported version of Hatchling to 1.14.0

      Fixed:

      • Fix displaying the version with the version command when the version is static and build dependencies are unmet
      • Fix build environments for the virtual environment type when storing within a relative path
      • Work around System Integrity Protection on macOS when running commands
      • Allow setuptools metadata migration for projects without setup.py if setup.cfg is present
      • Handle additional edge cases for setuptools metadata migration
      • Support boolean values for the config set command
      "},{"location":"history/hatch/#hatch-v1.6.3","title":"1.6.3 - 2022-10-24","text":"

      Fixed:

      • Fix version command when the version is dynamic and build dependencies are unmet
      "},{"location":"history/hatch/#hatch-v1.6.2","title":"1.6.2 - 2022-10-20","text":"

      Fixed:

      • Fix getting dynamic metadata from hooks for environments when dependencies are not dynamic
      "},{"location":"history/hatch/#hatch-v1.6.1","title":"1.6.1 - 2022-10-16","text":"

      Fixed:

      • Computing the path to the user's home directory now gracefully falls back to ~ when it cannot be determined
      "},{"location":"history/hatch/#hatch-v1.6.0","title":"1.6.0 - 2022-10-08","text":"

      Changed:

      • The run_shell_command environment interface method now accepts arbitrary subprocess.Popen keyword arguments. This is not strictly breaking, but will be utilized in upcoming features.
      • The internal directory structure for storing virtual environments is now more nested. This is not breaking, but any local environments will be created anew.

      Added:

      • Add project command group to view details about the project like PEP 621 metadata
      • Better support for auto-detection of environments by tools like Visual Studio Code now that the storage directory of virtual environments will be flat if Hatch's configured virtual environment directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
      • Build environments for the virtual environment type are now cached for improved performance
      • Add build_environment_exists method to the environment interface for implementations that cache the build environment
      • Add path option to the virtual environment type
      • Add --initialize-auth flag to the index publisher to allow for the saving of authentication information before publishing
      • Support Bash on Windows for the shell command
      • The setuptools migration script no longer modifies the formatting of existing pyproject.toml configuration
      • Bump the minimum supported version of Hatchling to 1.11.0

      Fixed:

      • Environments now respect dynamically defined project dependencies
      • The dep hash and all dep show commands now respect dynamically defined project dependencies
      • The env show, dep hash, and all dep show commands now honor context formatting
      • Fix matrix variable inclusion filtering of the run and env run commands when there are multiple possible variables
      • Build environment compatibility is now checked before use
      • Decreasing verbosity now has no affect on output that should always be displayed
      • Handle more edge cases in the setuptools migration script
      • Environments now respect user defined environment variables for context formatting
      • Update the scripts in the generated test environment template for new projects to reflect the documentation
      • Allow extra-dependencies in environment overrides
      • Depend on packaging explicitly rather than relying on it being a transitive dependency of Hatchling
      "},{"location":"history/hatch/#hatch-v1.5.0","title":"1.5.0 - 2022-08-28","text":"

      Added:

      • The index publisher now recognizes repository-specific options
      • Add the --ignore-compat flag to the env run command
      • Setting the HATCH_PYTHON environment variable to self will now force the use of the Python executable Hatch is running on for virtual environment creation

      Fixed:

      • Fix the --force-continue flag of the env run command
      • Handle more edge cases in the setuptools migration script
      "},{"location":"history/hatch/#hatch-v1.4.2","title":"1.4.2 - 2022-08-16","text":"

      Fixed:

      • Fix check for updating static versions with the version command when metadata hooks are in use
      "},{"location":"history/hatch/#hatch-v1.4.1","title":"1.4.1 - 2022-08-13","text":"

      Fixed:

      • Fix non-detached inheritance disabling for environments
      "},{"location":"history/hatch/#hatch-v1.4.0","title":"1.4.0 - 2022-08-06","text":"

      Added:

      • The default Python for virtual environments now checks PATH before using the one Hatch is running on
      • Values for environment env-vars now support context formatting
      • Add name override for environments to allow for regular expression matching
      • The index publisher now better supports non-PyPI indices
      • Add certificate options to the index publisher
      • Display waiting text when checking dependencies and removing environments
      • Display help text the first time the shell command is executed
      • Update project templates with Python 3.11 and the latest versions of various GitHub Actions
      • Add support for Almquist (ash) shells
      • Add hyperlink as a dependency for better handling of package index URLs
      • Bump the minimum supported version of virtualenv to 20.16.2
      • Bump the minimum supported version of tomlkit to 0.11.1

      Fixed:

      • Acknowledge extra-dependencies for the env show command
      • Fix locating executables within virtual environments on Debian
      • Fix managing the terminal size inside the shell command
      • Fix default code coverage file omission for the src-layout project template option
      "},{"location":"history/hatch/#hatch-v1.3.1","title":"1.3.1 - 2022-07-11","text":"

      Fixed:

      • Support -h/--help flag for the run command
      "},{"location":"history/hatch/#hatch-v1.3.0","title":"1.3.0 - 2022-07-10","text":"

      Changed:

      • Rename the default publishing plugin from pypi to the more generic index

      Added:

      • Support the absence of pyproject.toml files, as is the case for apps and non-Python projects
      • Hide scripts that start with an underscore for the env show command by default
      • Ignoring the exit codes of commands by prefixing with hyphens now works with entire named scripts
      • Add a way to require confirmation for publishing
      • Add --force-continue flag to the env run command
      • Make tracebacks colorful and less verbose
      • When shell configuration has not been defined, attempt to use the current shell based on parent processes before resorting to the defaults
      • The shell name pwsh is now an alias for powershell
      • Remove atomicwrites dependency
      • Relax constraint on userpath dependency
      • Bump the minimum supported version of Hatchling to 1.4.1

      Fixed:

      • Keep environments in sync with the dependencies of the selected features
      • Use utf-8 for all files generated for new projects
      • Escape special characters Git may return in the user name when writing generated files for new projects
      • Normalize the package name to lowercase in setuptools migration script
      • Fix parsing of source distributions during publishing
      "},{"location":"history/hatch/#hatch-v1.2.1","title":"1.2.1 - 2022-05-30","text":"

      Fixed:

      • Fix handling of top level data_files in setuptools migration script
      "},{"location":"history/hatch/#hatch-v1.2.0","title":"1.2.0 - 2022-05-22","text":"

      Changed:

      • The enter_shell environment plugin method now accepts an additional args parameter

      Added:

      • Allow context string formatting for environment dependencies
      • Add environment context string formatting fields env_name, env_type, matrix, verbosity, and args
      • Support overriding the default arguments used to spawn shells on non-Windows systems
      • Bump the minimum supported version of Hatchling to 1.3.0

      Fixed:

      • Improve setuptools migration script
      "},{"location":"history/hatch/#hatch-v1.1.2","title":"1.1.2 - 2022-05-20","text":"

      Fixed:

      • Bump the minimum supported version of Hatchling to 1.2.0
      • Update project metadata to reflect support for Python 3.11
      "},{"location":"history/hatch/#hatch-v1.1.1","title":"1.1.1 - 2022-05-12","text":"

      Fixed:

      • Fix setuptools migration script for non-Windows systems
      "},{"location":"history/hatch/#hatch-v1.1.0","title":"1.1.0 - 2022-05-12","text":"

      Changed:

      • In order to simplify the implementation of command execution for environment plugins, the run_shell_commands method has been replaced by the singular run_shell_command. A new command_context method has been added to more easily satisfy complex use cases.
      • The finalize_command environment plugin method has been removed in favor of the newly introduced context formatting functionality.

      Added:

      • Add context formatting functionality i.e. the ability to insert values into configuration like environment variables and command line arguments
      • Any verbosity for command execution will now always display headers, even for single environments
      • Every executed command is now displayed when running multiple commands or when verbosity is enabled
      • Similar to make, ignore the exit code of executed commands that start with - (a hyphen)
      • Add ability for the --init flag of the new command to automatically migrate setuptools configuration
      • Update project metadata to reflect the adoption by PyPA and production stability
      "},{"location":"history/hatch/#hatch-v1.0.0","title":"1.0.0 - 2022-04-28","text":"

      This is the first stable release of Hatch v1, a complete rewrite. Enjoy!

      "},{"location":"history/hatchling/","title":"Hatchling history","text":"

      All notable changes to Hatchling will be documented in this file.

      The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

      "},{"location":"history/hatchling/#unreleased","title":"Unreleased","text":""},{"location":"history/hatchling/#hatchling-v1.22.4","title":"1.22.4 - 2024-03-23","text":"

      Fixed:

      • Only read source distribution metadata for fields that are explicitly defined as dynamic
      "},{"location":"history/hatchling/#hatchling-v1.22.3","title":"1.22.3 - 2024-03-19","text":"

      Fixed:

      • Fix the custom build hook when using dynamic dependencies
      "},{"location":"history/hatchling/#hatchling-v1.22.2","title":"1.22.2 - 2024-03-16","text":"

      Fixed:

      • Fix regression when loading metadata from source distributions
      • Fix metadata hooks when building wheels from source distributions
      "},{"location":"history/hatchling/#hatchling-v1.22.1","title":"1.22.1 - 2024-03-16","text":"

      Fixed:

      • Update the default version of core metadata to 2.3
      "},{"location":"history/hatchling/#hatchling-v1.22.0","title":"1.22.0 - 2024-03-16","text":"

      Deprecated:

      • The app build target has been renamed to binary to reduce ambiguity with the name of an upcoming feature. The former name will still be usable for several minor releases.

      Added:

      • Metadata for the wheel target now defaults to the PKG-INFO metadata within source distributions
      • Add dependencies method to the build hook interface so that hooks can themselves dynamically define dependencies
      • Update the default version of core metadata to 2.2
      • Update SPDX license information to version 3.23
      • Improve error message for when the default heuristics for wheel file inclusion fail

      Fixed:

      • Properly support core metadata version 2.2
      • Remove editables as a direct dependency
      • Fix default wheel tag when the supported Python version declaration is strict
      • Load VCS ignore patterns first so that whitelisted patterns can be excluded by project configuration
      • Don't consider VCS ignore files that are outside of the VCS boundary
      • The sdist build target now gracefully ignores UNIX socket files
      • Begin ignoring certain files ubiquitously, like .DS_Store on macOS
      "},{"location":"history/hatchling/#hatchling-v1.21.1","title":"1.21.1 - 2024-01-25","text":"

      Fixed:

      • Fix loading of local plugins to account for newly released versions of a dependency
      "},{"location":"history/hatchling/#hatchling-v1.21.0","title":"1.21.0 - 2023-12-18","text":"

      Added:

      • Add parent context modifier for path fields
      "},{"location":"history/hatchling/#hatchling-v1.20.0","title":"1.20.0 - 2023-12-13","text":"

      Added:

      • Add bypass-selection option to the wheel build target to allow for empty (metadata-only) wheels

      Fixed:

      • Fix regression in 1.19.1 that allowed exclude to count toward inclusion selection, thus bypassing the default inclusion selection heuristics
      • Fix writing optional dependency core metadata in situations where there are multiple environment markers
      "},{"location":"history/hatchling/#hatchling-v1.19.1","title":"1.19.1 - 2023-12-12","text":"

      Fixed:

      • Add better error message when the wheel build target cannot determine what to ship
      • Consider forced inclusion patterns and build-time artifacts as file selection since some build hooks generate the entire wheel contents without user configuration
      "},{"location":"history/hatchling/#hatchling-v1.19.0","title":"1.19.0 - 2023-12-11","text":"

      Changed:

      • An error will now be raised if a force-included path does not exist
      • An error will now be raised for the wheel build target if no file selection options are defined

      Added:

      • Officially support Python 3.12
      • Allow using an empty string for the sources option to add a prefix to distribution paths

      Fixed:

      • Properly handle non-zero version epoch for the standard version scheme
      • Fix the wheel build target for case insensitive file systems when the project metadata name does not match the directory name on disk
      • The app build target no longer has suppressed output
      • Prevent duplicate paths when projects require the sources option while build hooks overwrite included paths
      • Properly escape spaces for URI context formatting
      "},{"location":"history/hatchling/#hatchling-v1.18.0","title":"1.18.0 - 2023-06-12","text":"

      Changed:

      • Drop support for Python 3.7

      Added:

      • Update the list of directories that are always excluded for builds
      "},{"location":"history/hatchling/#hatchling-v1.17.1","title":"1.17.1 - 2023-06-03","text":"

      Fixed:

      • Fix dev mode when the project has symlinks and file inclusion is defined with the packages or only-include options
      • Change the name of generated PTH files for dev mode so they come first lexicographically and therefore load first
      "},{"location":"history/hatchling/#hatchling-v1.17.0","title":"1.17.0 - 2023-05-12","text":"

      Added:

      • The app build target now embeds the project version in the name of binaries
      "},{"location":"history/hatchling/#hatchling-v1.16.1","title":"1.16.1 - 2023-05-11","text":"

      Fixed:

      • Fix determining the built executable path for the app build target option when using a local copy of PyApp when there is an explicit target triple set
      "},{"location":"history/hatchling/#hatchling-v1.16.0","title":"1.16.0 - 2023-05-11","text":"

      Added:

      • Add app build target option to build using a local copy of the PyApp repository
      "},{"location":"history/hatchling/#hatchling-v1.15.0","title":"1.15.0 - 2023-05-09","text":"

      Added:

      • Add app build target
      "},{"location":"history/hatchling/#hatchling-v1.14.1","title":"1.14.1 - 2023-04-23","text":"

      Fixed:

      • Fix internal archive root naming for the sdist target when strict-naming is disabled to match the file name in order to support the expectation of some frontends
      "},{"location":"history/hatchling/#hatchling-v1.14.0","title":"1.14.0 - 2023-04-02","text":"

      Added:

      • Add trove-classifiers as a dependency

      Fixed:

      • Properly normalize metadata descriptions that contain line breaks
      "},{"location":"history/hatchling/#hatchling-v1.13.0","title":"1.13.0 - 2023-02-09","text":"

      Added:

      • Update the set of known trove classifiers to version 2023.2.8
      "},{"location":"history/hatchling/#hatchling-v1.12.2","title":"1.12.2 - 2023-01-05","text":"

      Fixed:

      • Add macos-max-compat option to the wheel target that is enabled by default to support the latest version 22.0 of the packaging library
      "},{"location":"history/hatchling/#hatchling-v1.12.1","title":"1.12.1 - 2022-12-31","text":"

      Fixed:

      • Fix minor regression in the PEP 517/660 function signatures that was discovered by Fedora
      "},{"location":"history/hatchling/#hatchling-v1.12.0","title":"1.12.0 - 2022-12-30","text":"

      Added:

      • Improve readability of exceptions
      • Add extra_metadata build data to the wheel target
      • Retroactively support License-Expression core metadata starting at version 2.1
      • Add more type hints
      • Update the set of known trove classifiers to version 2022.12.22
      • Update SPDX license information to version 3.19
      • Store Hatchling's metadata in pyproject.toml

      Fixed:

      • Acknowledge the ARCHFLAGS environment variable on macOS for the wheel target when build hooks set the infer_tag build data to true
      • Fix dependency checking when encountering broken distributions
      • Fix the support-legacy option for the sdist target when using a src-layout project structure
      • Remove unnecessary encoding declaration in the default template for the version build hook
      "},{"location":"history/hatchling/#hatchling-v1.11.1","title":"1.11.1 - 2022-10-19","text":"

      Fixed:

      • Fix default file selection behavior of the wheel target when there is a single top-level module
      "},{"location":"history/hatchling/#hatchling-v1.11.0","title":"1.11.0 - 2022-10-08","text":"

      Added:

      • Add env version source to retrieve the version from an environment variable
      • Add validate-bump option to the standard version scheme

      Fixed:

      • Use proper CSV formatting for the RECORD metadata file of the wheel target to avoid warnings during installation by pip if, for example, file names contain commas
      • Fix installations with pip for build hooks that modify runtime dependencies
      • Decreasing verbosity now has no affect on output that should always be displayed
      "},{"location":"history/hatchling/#hatchling-v1.10.0","title":"1.10.0 - 2022-09-18","text":"

      Added:

      • Add the following to the list of directories that cannot be traversed: __pypackages__, .hg, .hatch, .tox, .nox
      • Add deprecated option to allow ambiguous features

      Fixed:

      • Improve tracking of dynamic metadata
      • Fix core metadata for entries in project.optional-dependencies that use direct references
      "},{"location":"history/hatchling/#hatchling-v1.9.0","title":"1.9.0 - 2022-09-09","text":"

      Changed:

      • File pattern matching now more closely resembles Git's behavior

      Added:

      • Implement a minimal version of prepare_metadata_for_build_wheel and prepare_metadata_for_build_editable for non-frontend tools that only need to inspect a project's metadata
      • Add metadata command to view PEP 621 project metadata
      • Improve error messages for SPDX license errors
      • Retroactively support License-File for core metadata starting at version 2.1
      • Bump the minimum supported version of pathspec to 0.10.1

      Fixed:

      • Allow the valid non-SPDX license values LicenseRef-Public-Domain and LicenseRef-Proprietary
      • Show the help text of the CLI when no subcommand is selected
      "},{"location":"history/hatchling/#hatchling-v1.8.1","title":"1.8.1 - 2022-08-25","text":"

      Fixed:

      • Fix default file inclusion for wheel build targets when both the project name and package directory name are not normalized
      "},{"location":"history/hatchling/#hatchling-v1.8.0","title":"1.8.0 - 2022-08-16","text":"

      Added:

      • Add get_known_classifiers method to metadata hooks

      Fixed:

      • Fix check for updating static versions with the version command when metadata hooks are in use
      "},{"location":"history/hatchling/#hatchling-v1.7.1","title":"1.7.1 - 2022-08-13","text":"

      Fixed:

      • Fix the value of the relative_path attribute of included files, that some build plugins may use, when selecting explicit paths
      "},{"location":"history/hatchling/#hatchling-v1.7.0","title":"1.7.0 - 2022-08-12","text":"

      Added:

      • Add require-runtime-features option for builders and build hooks
      • Check for unknown trove classifiers
      • Update SPDX license information to version 3.18

      Fixed:

      • Add better error message for wheel target dev mode installations that define path rewrites with the sources option
      • Note the allow-direct-references option in the relevant error messages
      "},{"location":"history/hatchling/#hatchling-v1.6.0","title":"1.6.0 - 2022-07-23","text":"

      Changed:

      • When no build targets are specified on the command line, now default to sdist and wheel targets rather than what happens to be defined in config
      • The code version source now only supports files with known extensions
      • Global build hooks now run before target-specific build hooks to better match expected behavior

      Added:

      • The code version source now supports loading extension modules
      • Add search-paths option for the code version source

      Fixed:

      • Fix removing sources using an empty string value in the mapping
      • The strict-naming option now also applies to the metadata directory of wheel targets
      "},{"location":"history/hatchling/#hatchling-v1.5.0","title":"1.5.0 - 2022-07-11","text":"

      Added:

      • Support the final draft of PEP 639
      • Add strict-naming option for sdist and wheel targets

      Fixed:

      • Project names are now stored in sdist and wheel target core metadata exactly as defined in pyproject.toml without normalization to allow control of how PyPI displays them
      "},{"location":"history/hatchling/#hatchling-v1.4.1","title":"1.4.1 - 2022-07-04","text":"

      Fixed:

      • Fix forced inclusion of important files like licenses for sdist targets when using the explicit selection options
      • Don't sort project URL metadata so that the rendered order on PyPI can be controlled
      "},{"location":"history/hatchling/#hatchling-v1.4.0","title":"1.4.0 - 2022-07-03","text":"

      Changed:

      • The packages option uses the new only-include option to provide targeted inclusion, since that is desired most of the time. You can retain the old behavior by using the include and sources options together.

      Added:

      • Support PEP 561 type hinting
      • Add version build hook
      • Add only-include option
      • The editable version of wheel targets now respects the force-include option by default
      • The force-include option now supports path rewriting with the sources option
      • The wheel target shared-data and extra-metadata options now respect file selection options
      • The wheel target now auto-detects single module layouts
      • Improve performance by never entering directories that are guaranteed to be undesirable like __pycache__ rather than excluding individual files within
      • Update SPDX license information to version 3.17

      Fixed:

      • Don't write empty entry points file for wheel targets if there are no entry points defined
      • Allow metadata hooks to set the version in all cases
      • Prevent duplicate file entries from inclusion when using the force-include option
      "},{"location":"history/hatchling/#hatchling-v1.3.1","title":"1.3.1 - 2022-05-30","text":"

      Fixed:

      • Better populate global variables for the code version source
      "},{"location":"history/hatchling/#hatchling-v1.3.0","title":"1.3.0 - 2022-05-22","text":"

      Removed:

      • Remove unused global args context string formatting field

      Added:

      • Improve error messages for the env context string formatting field

      Fixed:

      • Fix uri context string formatting modifier on Windows
      "},{"location":"history/hatchling/#hatchling-v1.2.0","title":"1.2.0 - 2022-05-20","text":"

      Added:

      • Allow context formatting for project.dependencies and project.optional-dependencies
      "},{"location":"history/hatchling/#hatchling-v1.1.0","title":"1.1.0 - 2022-05-19","text":"

      Added:

      • Add uri and real context string formatting modifiers for file system paths
      "},{"location":"history/hatchling/#hatchling-v1.0.0","title":"1.0.0 - 2022-05-17","text":"

      Changed:

      • Drop support for Python 2

      Added:

      • Improve error messaging for invalid versions
      • Update project metadata to reflect support for Python 3.11
      "},{"location":"history/hatchling/#hatchling-v0.25.1","title":"0.25.1 - 2022-06-14","text":"

      Fixed:

      • Fix support for Windows on Python 2 by removing its support for symlinks
      "},{"location":"history/hatchling/#hatchling-v0.25.0","title":"0.25.0 - 2022-05-15","text":"

      Added:

      • Add skip-excluded-dirs build option
      • Allow build data to add additional project dependencies for wheel and sdist build targets
      • Add force_include_editable build data for the wheel build target
      • Add build_hooks build data
      • Add support for Mercurial's .hgignore files when using glob syntax
      • Update project metadata to reflect the adoption by PyPA

      Fixed:

      • Properly use underscores for the name of force_include build data
      • No longer greedily skip excluded directories by default
      "},{"location":"history/hatchling/#hatchling-v0.24.0","title":"0.24.0 - 2022-04-28","text":"

      This is the initial public release of the Hatchling build system. Support for Python 2 will be dropped in version 1.

      "},{"location":"how-to/config/dynamic-metadata/","title":"How to configure custom dynamic metadata","text":"

      If you have project metadata that is not appropriate for static entry into pyproject.toml you will need to provide a custom metadata hook to apply such data during builds.

      Alternatives

      Dynamic metadata is a way to have a single source of truth that will be available at build time and at run time. Another way to achieve that is to enter the build data statically and then look up the same information dynamically in the program or package, using importlib.metadata.

      If the version field is the only metadata of concern, Hatchling provides a few built-in ways such as the regex version source and also third-party plugins. The approach here will also work, but is more complex.

      "},{"location":"how-to/config/dynamic-metadata/#update-project-metadata","title":"Update project metadata","text":"

      Change the [project] section of pyproject.toml:

      1. Define the dynamic field as an array of all the fields you will set dynamically e.g. dynamic = [\"version\", \"license\", \"authors\", \"maintainers\"]
      2. If any of those fields have static definitions in pyproject.toml, delete those definitions. It is verboten to define a field statically and dynamically.

      Add a section to trigger loading of dynamic metadata plugins: [tool.hatch.metadata.hooks.custom]. Use exactly that name, regardless of the name of the class you will use or its PLUGIN_NAME. There doesn't need to be anything in the section.

      If your plugin requires additional third-party packages to do its work, add them to the requires array in the [build-system] section of pyproject.toml.

      "},{"location":"how-to/config/dynamic-metadata/#implement-hook","title":"Implement hook","text":"

      The dynamic lookup must happen in a custom plugin that you write. The default expectation is that it is in a hatch_build.py file at the root of the project. Subclass MetadataHookInterface and implement update(); for example, here's plugin that reads metadata from a JSON file:

      hatch_build.py
      import json\nimport os\n\nfrom hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass JSONMetaDataHook(MetadataHookInterface):\n    def update(self, metadata):\n        src_file = os.path.join(self.root, \"gnumeric\", \".constants.json\")\n        with open(src_file) as src:\n            constants = json.load(src)\n            metadata[\"version\"] = constants[\"__version__\"]\n            metadata[\"license\"] = constants[\"__license__\"]\n            metadata[\"authors\"] = [\n                {\"name\": constants[\"__author__\"], \"email\": constants[\"__author_email__\"]},\n            ]\n
      1. You must import the MetadataHookInterface to subclass it.
      2. Do your operations inside the update method.
      3. metadata refers to project metadata.
      4. When writing to metadata, use list for TOML arrays. Note that if a list is expected, it is required even if there is a single element.
      5. Use dict for TOML tables e.g. authors.

      If you want to store the hook in a different location, set the path option:

      pyproject.toml hatch.toml
      [tool.hatch.metadata.hooks.custom]\npath = \"some/where.py\"\n
      [metadata.hooks.custom]\npath = \"some/where.py\"\n
      "},{"location":"how-to/environment/package-indices/","title":"How to configure package indices","text":"

      Most Hatch environment types, like the default virtual, simply use pip to install dependencies. Therefore, you can use the standard environment variables that influence pip's behavior to choose where to search for packages.

      Here's an example of setting up the default environment to look at 2 private indices (using context formatting for authentication) before finally falling back to PyPI:

      pyproject.toml hatch.toml
      [tool.hatch.envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
      [envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
      "},{"location":"how-to/meta/report-issues/","title":"How to report issues","text":"

      All reports regarding unexpected behavior should be generated with the self report command:

      $ hatch self report\n

      By default, this will open a new tab in your default browser with pre-populated information about your environment.

      If Hatch is not installed alongside a web browser, you may also pass the --no-open/-n command which will output the URL with correct parameters for copying elsewhere:

      $ hatch self report -n\nhttps://github.com/pypa/hatch/issues/new?body=%23%23+Current+behavior%0A%3C%21--+A+clear+and+concise+description+of+the+behavior.+--%3E%0A%0A%23%23+Expected+behavior%0A%3C%21--+A+clear+and+concise+description+of+what+you+expected+to+happen.+--%3E%0A%0A%23%23+Additional+context%0A%3C%21--+Add+any+other+context+about+the+problem+here.+If+applicable%2C+add+screenshots+to+help+explain.+--%3E%0A%0A%23%23+Debug%0A%0A%23%23%23+Installation%0A%0A-+Source%3A+pip%0A-+Version%3A+1.9.2.dev5%0A-+Platform%3A+Windows%0A-+Python+version%3A%0A++++%60%60%60%0A++++3.11.1+%28tags%2Fv3.11.1%3Aa7a450f%2C+Dec++6+2022%2C+19%3A58%3A39%29+%5BMSC+v.1934+64+bit+%28AMD64%29%5D%0A++++%60%60%60%0A%0A%23%23%23+Configuration%0A%0A%60%60%60toml%0Amode+%3D+%22local%22%0Ashell+%3D+%22nu%22%0A%60%60%60%0A\n
      "},{"location":"how-to/plugins/testing-builds/","title":"Testing build plugins","text":"

      For testing Hatchling plugins, you'll usually want to generate a project to execute builds as a real user would. For example, as a minimal pytest fixture:

      from pathlib import Path\n\nimport pytest\n\n\n@pytest.fixture\ndef new_project(tmp_path):\n    project_dir = tmp_path / 'my-app'\n    project_dir.mkdir()\n\n    project_file = project_dir / 'pyproject.toml'\n    project_file.write_text(\n        f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {Path.cwd().as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n        encoding='utf-8',\n    )\n    ...\n

      The issue with this is that after the first test session, the project will be forever cached by pip based on the file path. Therefore, subsequent tests runs will never use updated code.

      To invalidate the cache, copy your code to a new path for every test session:

      import shutil\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\n\nimport pytest\n\n\n@pytest.fixture(scope='session')\ndef plugin_dir():\n    with TemporaryDirectory() as d:\n        directory = Path(d, 'plugin')\n        shutil.copytree(\n            Path.cwd(), directory, ignore=shutil.ignore_patterns('.git')\n        )\n\n        yield directory.resolve()\n\n\n@pytest.fixture\ndef new_project(tmp_path, plugin_dir):\n    project_dir = tmp_path / 'my-app'\n    project_dir.mkdir()\n\n    project_file = project_dir / 'pyproject.toml'\n    project_file.write_text(\n        f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {plugin_dir.as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n        encoding='utf-8',\n    )\n    ...\n

      Note

      This example chooses to ignore copying .git for performance reasons. You may want to ignore more patterns, or copy only specific paths like this plugin does.

      "},{"location":"how-to/publish/auth/","title":"How to authenticate for index publishing","text":"

      The username is derived from the following sources, in order of precedence:

      1. The --user / -u cli option.
      2. The HATCH_INDEX_USER environment variable.
      3. The repos tables.
      4. The ~/.pypirc file.
      5. The input to an interactive prompt.

      As a fallback the value __token__ is applied.

      The password is looked up in these:

      1. The ~/.pypirc file if the username was provided by it.
      2. The --auth / -a cli option.
      3. The HATCH_INDEX_AUTH environment variable.
      4. The repos tables.
      5. A variety of OS-level credentials services backed by keyring.
      6. The input to an interactive prompt.

      If interactively provided credentials were used, the username will be stored in Hatch's cache and the password stored in the available keyring backed credentials stores.

      For automated releasing to PyPI, it is recommended to use \"Trusted Publishing\" with OIDC (e.g. PyPA's pypi-publish GitHub Action) or per-project API tokens.

      "},{"location":"how-to/publish/repo/","title":"How to configure repositories for index publishing","text":"

      You can select the repository with which to upload using the -r/--repo option or by setting the HATCH_INDEX_REPO environment variable.

      Rather than specifying the full URL of a repository, you can use a named repository from a publish.index.repos table defined in Hatch's config file:

      config.toml
      [publish.index.repos.private]\nurl = \"...\"\n...\n

      The following repository names are reserved by Hatch and cannot be overridden:

      Name Repository main https://upload.pypi.org/legacy/ test https://test.pypi.org/legacy/

      The main repository is used by default.

      "},{"location":"how-to/static-analysis/behavior/","title":"Customize static analysis behavior","text":"

      You can fully alter the static analysis performed by the fmt command by modifing the reserved environment named hatch-static-analysis. For example, you could define the following if you wanted to replace the default behavior with a mix of Black, isort and basic flake8:

      pyproject.toml hatch.toml
      [tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"black\", \"flake8\", \"isort\"]\n\n[tool.hatch.envs.hatch-static-analysis.scripts]\nformat-check = [\n  \"black --check --diff {args:.}\",\n  \"isort --check-only --diff {args:.}\",\n]\nformat-fix = [\n  \"isort {args:.}\",\n  \"black {args:.}\",\n]\nlint-check = \"flake8 {args:.}\"\nlint-fix = \"lint-check\"\n
      [envs.hatch-static-analysis]\ndependencies = [\"black\", \"flake8\", \"isort\"]\n\n[envs.hatch-static-analysis.scripts]\nformat-check = [\n  \"black --check --diff {args:.}\",\n  \"isort --check-only --diff {args:.}\",\n]\nformat-fix = [\n  \"isort {args:.}\",\n  \"black {args:.}\",\n]\nlint-check = \"flake8 {args:.}\"\nlint-fix = \"lint-check\"\n

      The format-* scripts correspond to the --formatter/-f flag while the lint-* scripts correspond to the --linter/-l flag. The *-fix scripts run by default while the *-check scripts correspond to the --check flag. Based on this example, the following shows how the various scripts influence behavior:

      Command Expanded scripts hatch fmt
      • flake8 .
      • isort .
      • black .
      hatch fmt src tests
      • flake8 src tests
      • isort src tests
      • black src tests
      hatch fmt -f
      • isort .
      • black .
      hatch fmt -l
      • flake8 .
      hatch fmt --check
      • flake8 .
      • black --check --diff .
      • isort --check-only --diff .
      hatch fmt --check -f
      • black --check --diff .
      • isort --check-only --diff .
      hatch fmt --check -l
      • flake8 .
      "},{"location":"meta/authors/","title":"Authors","text":""},{"location":"meta/authors/#maintainers","title":"Maintainers","text":"
      • Ofek Lev
      "},{"location":"meta/authors/#contributors","title":"Contributors","text":"
      • Amjith Ramanujam
      • Arnaud Crowther
      • Chaojie
      • Chris Warrick
      • Lum\u00edr 'Frenzy' Balhar
      • Ofek Lev
      • Olga Matoula
      • Philip Blair
      • Robert Rosca
      "},{"location":"meta/faq/","title":"FAQ","text":""},{"location":"meta/faq/#interoperability","title":"Interoperability","text":"

      Q: What is the risk of lock-in?

      A: Not much! Other than the plugin system, everything uses Python's established standards by default. Project metadata is based entirely on the standard, the build system is compatible with PEP 517/PEP 660, versioning uses the scheme specified by PEP 440, dependencies are defined with PEP 508 strings, and environments use virtualenv.

      Q: Must one use all features?

      A: No, all features are optional! You can use just the build system, publish wheels and source distributions that were built by other tools, only use the environment management, etc.

      "},{"location":"meta/faq/#libraries-vs-applications","title":"Libraries vs applications","text":"

      Q: Are workflows for both libraries and applications supported?

      A: Yes, mostly! Applications can utilize environment management just like libraries, and plugins can be used to build projects in arbitrary formats or publish artifacts to arbitrary destinations.

      The only caveat is that currently there is no support for re-creating an environment given a set of dependencies in a reproducible manner. Although a standard lock file format may be far off since PEP 665 was rejected, resolving capabilities are coming to pip. When that is stabilized, Hatch will add locking functionality and dedicated documentation for managing applications.

      "},{"location":"meta/faq/#tool-migration","title":"Tool migration","text":"

      Q: How to migrate to Hatch?

      "},{"location":"meta/faq/#build-system","title":"Build system","text":"SetuptoolsHatch setup.py MANIFEST.in
      import os\nfrom io import open\n\nfrom setuptools import find_packages, setup\n\nabout = {}\nwith open(os.path.join('src', 'foo', '__about__.py'), 'r', 'utf-8') as f:\n    exec(f.read(), about)\n\nwith open('README.md', 'r', 'utf-8') as f:\n    readme = f.read()\n\nsetup(\n    # Metadata\n    name='foo',\n    version=about['__version__'],\n    description='...',\n    long_description=readme,\n    long_description_content_type='text/markdown',\n    author='...',\n    author_email='...',\n    project_urls={\n        'Documentation': '...',\n        'Source': '...',\n    },\n    classifiers=[\n        '...',\n    ],\n    keywords=[\n        '...',\n    ],\n    python_requires='>=3.8',\n    install_requires=[\n        '...',\n    ],\n    extras_require={\n        'feature': ['...'],\n    },\n\n    # Packaging\n    packages=find_packages(where='src'),\n    package_dir={'': 'src'},\n    package_data={\n        'foo': ['py.typed'],\n    },\n    zip_safe=False,\n    entry_points={\n        'console_scripts': [\n            'foo = foo.cli:main',\n        ],\n    },\n)\n
      graft tests\n\nglobal-exclude *.py[cod] __pycache__\n
      pyproject.toml
      [build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"foo\"\ndescription = \"...\"\nreadme = \"README.md\"\nauthors = [\n  { name = \"...\", email = \"...\" },\n]\nclassifiers = [\n  \"...\",\n]\nkeywords = [\n  \"...\",\n]\nrequires-python = \">=3.8\"\ndependencies = [\n  \"...\",\n]\ndynamic = [\"version\"]\n\n[project.urls]\nDocumentation = \"...\"\nSource = \"...\"\n\n[project.optional-dependencies]\nfeature = [\"...\"]\n\n[project.scripts]\nfoo = \"foo.cli:main\"\n\n[tool.hatch.version]\npath = \"src/foo/__about__.py\"\n\n[tool.hatch.build.targets.sdist]\ninclude = [\n  \"/src\",\n  \"/tests\",\n]\n
      "},{"location":"meta/faq/#environments","title":"Environments","text":"ToxHatch

      Invocation:

      tox\n
      tox.ini
      [tox]\nenvlist =\n    py{27,38}-{42,3.14}\n    py{38,39}-{9000}-{foo,bar}\n\n[testenv]\nusedevelop = true\ndeps =\n    coverage[toml]\n    pytest\n    pytest-cov\n    foo: cryptography\ncommands =\n    pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests {posargs}\nsetenv =\n    3.14: PRODUCT_VERSION=3.14\n    42: PRODUCT_VERSION=42\n    9000: PRODUCT_VERSION=9000\n    {foo,bar}: EXPERIMENTAL=true\n

      Invocation:

      hatch run test\n
      pyproject.toml hatch.toml
      [tool.hatch.envs.default]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[tool.hatch.envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[tool.hatch.envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.features.env-vars = \"EXPERIMENTAL=true\"\nmatrix.features.dependencies = [\n  { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
      [envs.default]\ndependencies = [\n  \"coverage[toml]\",\n  \"pytest\",\n  \"pytest-cov\",\n]\n\n[envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.features.env-vars = \"EXPERIMENTAL=true\"\nmatrix.features.dependencies = [\n  { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[envs.default.matrix]]\npython = [\"2.7\", \"3.8\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"9000\"]\nfeatures = [\"foo\", \"bar\"]\n
      "},{"location":"meta/faq/#fast-cli","title":"Fast CLI?","text":"

      The claim about being faster than other tools is based on timings that are always checked in CI.

      Hatch achieves this by using lazy imports, lazily performing computation manually and with functools.cached_property, using hacks like not not ... instead of bool(...), etc.

      "},{"location":"plugins/about/","title":"Plugins","text":"

      Hatch utilizes pluggy for its plugin functionality.

      "},{"location":"plugins/about/#overview","title":"Overview","text":"

      All plugins provide registration hooks that return one or more classes that inherit from a particular type interface.

      Each registration hook must be decorated by Hatch's hook marker. For example, if you wanted to create a new kind of environment you could do:

      hooks.py
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialEnvironment\n\n\n@hookimpl\ndef hatch_register_environment():\n    return SpecialEnvironment\n

      The hooks can return a single class or a list of classes.

      Every class must define an attribute called PLUGIN_NAME that users will select when they wish to use the plugin. So in the example above, the class might be defined like:

      plugin.py
      ...\nclass SpecialEnvironment(...):\n    PLUGIN_NAME = 'special'\n    ...\n
      "},{"location":"plugins/about/#project-configuration","title":"Project configuration","text":""},{"location":"plugins/about/#naming","title":"Naming","text":"

      It is recommended that plugin project names are prefixed with hatch-. For example, if you wanted to make a plugin that provides some functionality for a product named foo you might do:

      pyproject.toml
      [project]\nname = \"hatch-foo\"\n
      "},{"location":"plugins/about/#discovery","title":"Discovery","text":"

      You'll need to define your project as a Python plugin for Hatch:

      pyproject.toml
      [project.entry-points.hatch]\nfoo = \"pkg.hooks\"\n

      The name of the plugin should be the project name (excluding any hatch- prefix) and the path should represent the module that contains the registration hooks.

      "},{"location":"plugins/about/#classifier","title":"Classifier","text":"

      Add Framework :: Hatch to your project's classifiers to make it easy to search for Hatch plugins:

      pyproject.toml
      [project]\nclassifiers = [\n  ...\n  \"Framework :: Hatch\",\n  ...\n]\n
      "},{"location":"plugins/about/#types","title":"Types","text":""},{"location":"plugins/about/#hatchling","title":"Hatchling","text":"

      These are all involved in building projects and therefore any defined dependencies are automatically installed in each build environment.

      • Builder
      • Build hook
      • Metadata hook
      • Version source
      • Version scheme
      "},{"location":"plugins/about/#hatch","title":"Hatch","text":"

      These must be installed in the same environment as Hatch itself.

      • Environment
      • Environment collector
      • Publisher
      "},{"location":"plugins/utilities/","title":"Plugin utilities","text":""},{"location":"plugins/utilities/#hatchling.builders.utils.get_reproducible_timestamp","title":"hatchling.builders.utils.get_reproducible_timestamp() -> int","text":"

      Returns an int derived from the SOURCE_DATE_EPOCH environment variable; see https://reproducible-builds.org/specs/source-date-epoch/.

      The default value will always be: 1580601600

      Source code in backend/src/hatchling/builders/utils.py
      def get_reproducible_timestamp() -> int:\n    \"\"\"\n    Returns an `int` derived from the `SOURCE_DATE_EPOCH` environment variable; see\n    https://reproducible-builds.org/specs/source-date-epoch/.\n\n    The default value will always be: `1580601600`\n    \"\"\"\n    return int(os.environ.get('SOURCE_DATE_EPOCH', '1580601600'))\n
      "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig","title":"BuilderConfig","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.directory","title":"directory: str property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.ignore_vcs","title":"ignore_vcs: bool property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.reproducible","title":"reproducible: bool property","text":"

      Whether or not the target should be built in a reproducible manner, defaulting to true.

      "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dev_mode_dirs","title":"dev_mode_dirs: list[str] property","text":"

      Directories which must be added to Python's search path in dev mode.

      "},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.versions","title":"versions: list[str] property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dependencies","title":"dependencies: list[str] property","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_include","title":"default_include() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_exclude","title":"default_exclude() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_packages","title":"default_packages() -> list","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_only_include","title":"default_only_include() -> list","text":""},{"location":"plugins/utilities/#hatchling.bridge.app.Application","title":"Application","text":"

      The way output is displayed can be configured by users.

      Important

      Never import this directly; Hatch judiciously decides if a type of plugin requires the capabilities herein and will grant access via an attribute.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.verbosity","title":"verbosity: int property","text":"

      The verbosity level of the application, with 0 as the default.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.abort","title":"abort(message: str = '', code: int = 1, **kwargs: Any) -> None","text":"

      Terminate the program with the given return code.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_debug","title":"display_debug(message: str = '', level: int = 1, **kwargs: Any) -> None","text":"

      Meant to be used for messages that are not useful for most user experiences. The level option must be between 1 and 3 (inclusive).

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_error","title":"display_error(message: str = '', **kwargs: Any) -> None","text":"

      Meant to be used for messages indicating some unrecoverable error.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_info","title":"display_info(message: str = '', **kwargs: Any) -> None","text":"

      Meant to be used for messages conveying basic information.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_success","title":"display_success(message: str = '', **kwargs: Any) -> None","text":"

      Meant to be used for messages indicating some positive outcome.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_waiting","title":"display_waiting(message: str = '', **kwargs: Any) -> None","text":"

      Meant to be used for messages shown before potentially time consuming operations.

      "},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_warning","title":"display_warning(message: str = '', **kwargs: Any) -> None","text":"

      Meant to be used for messages conveying important information.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform","title":"Platform","text":""},{"location":"plugins/utilities/#hatch.utils.platform.Platform.default_shell","title":"default_shell: str property","text":"

      Returns the default shell of the system.

      On Windows systems first try the SHELL environment variable, if present, followed by the COMSPEC environment variable, defaulting to cmd. On all other platforms only the SHELL environment variable will be used, defaulting to bash.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.modules","title":"modules: LazilyLoadedModules property","text":"

      Accessor for lazily loading modules that either take multiple milliseconds to import (like shutil and subprocess) or are not used on all platforms (like shlex).

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.home","title":"home: Path property","text":"

      The user's home directory as a path-like object.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.name","title":"name: str property","text":"

      One of the following:

      • linux
      • windows
      • macos
      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.display_name","title":"display_name: str property","text":"

      One of the following:

      • Linux
      • Windows
      • macOS
      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.windows","title":"windows: bool property","text":"

      Indicates whether Hatch is running on Windows.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.macos","title":"macos: bool property","text":"

      Indicates whether Hatch is running on macOS.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.linux","title":"linux: bool property","text":"

      Indicates whether Hatch is running on neither Windows nor macOS.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.format_for_subprocess","title":"format_for_subprocess(command: str | list[str], *, shell: bool) -> str | list[str]","text":"

      Format the given command in a cross-platform manner for immediate consumption by subprocess utilities.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.run_command","title":"run_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess","text":"

      Equivalent to the standard library's subprocess.run, with the command first being properly formatted.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command","title":"check_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess","text":"

      Equivalent to run_command, but non-zero exit codes will gracefully end program execution.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command_output","title":"check_command_output(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> str","text":"

      Equivalent to the output from the process returned by capture_process, but non-zero exit codes will gracefully end program execution.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.capture_process","title":"capture_process(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> Popen","text":"

      Equivalent to the standard library's subprocess.Popen, with all output captured by stdout and the command first being properly formatted.

      "},{"location":"plugins/utilities/#hatch.utils.platform.Platform.exit_with_command","title":"exit_with_command(command: list[str]) -> None","text":"

      Run the given command and exit with its exit code. On non-Windows systems, this uses the standard library's os.execvp.

      "},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter","title":"EnvironmentContextFormatter","text":""},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter.formatters","title":"formatters()","text":"

      This returns a mapping of supported field names to their respective formatting functions. Each function accepts 2 arguments:

      • the value that was passed to the format call, defaulting to None
      • the modifier data, defaulting to an empty string
      "},{"location":"plugins/build-hook/custom/","title":"Custom build hook","text":"

      This is a custom class in a given Python file that inherits from the BuildHookInterface.

      "},{"location":"plugins/build-hook/custom/#configuration","title":"Configuration","text":"

      The build hook plugin name is custom.

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.custom]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.custom]\n
      [build.hooks.custom]\n[build.targets.<TARGET_NAME>.hooks.custom]\n
      "},{"location":"plugins/build-hook/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/build-hook/custom/#example","title":"Example","text":"hatch_build.py
      from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass CustomBuildHook(BuildHookInterface):\n    ...\n

      If multiple subclasses are found, you must define a function named get_build_hook that returns the desired build hook.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      "},{"location":"plugins/build-hook/reference/","title":"Build hook plugins","text":"

      A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.

      "},{"location":"plugins/build-hook/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-autorun - used to inject code into an installation that will automatically run before the first import
      • hatch-build-scripts - run arbitrary shell commands that create artifacts
      • hatch-jupyter-builder - used for packages in the Project Jupyter ecosystem
      • hatch-mypyc - compiles code with Mypyc
      • hatch-odoo - package Odoo add-ons into the appropriate namespace
      "},{"location":"plugins/build-hook/reference/#overview","title":"Overview","text":"

      Build hooks run for every selected version of build targets.

      The initialization stage occurs immediately before each build and the finalization stage occurs immediately after. Each stage has the opportunity to view or modify build data.

      "},{"location":"plugins/build-hook/reference/#build-data","title":"Build data","text":"

      Build data is a simple mapping whose contents can influence the behavior of builds. Which fields exist and are recognized depends on each build target.

      The following fields are always present and recognized by the build system itself:

      Field Type Description artifacts list[str] This is a list of extra artifact patterns and should generally only be appended to force_include dict[str, str] This is a mapping of extra forced inclusion paths, with this mapping taking precedence in case of conflicts build_hooks tuple[str, ...] This is an immutable sequence of the names of the configured build hooks and matches the order in which they run

      Attention

      While user-facing TOML options are hyphenated, build data fields should be named with underscores to allow plugins to use them as valid Python identifiers.

      "},{"location":"plugins/build-hook/reference/#notes","title":"Notes","text":"

      In some cases it may be necessary to use force_include rather than artifacts. For example, say that you want to install a lib.so directly at the root of site-packages and a project defines a package src/foo. If you create src/lib.so, there will never be a match because the directory traversal starts at src/foo rather than src. In that case you must do either:

      build_data['force_include']['src/lib.so'] = 'src/lib.so'\n

      or

      build_data['force_include']['/absolute/path/to/src/lib.so'] = 'src/lib.so'\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface","title":"BuildHookInterface","text":"

      Example usage:

      plugin.py hooks.py
      from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass SpecialBuildHook(BuildHookInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuildHook\n\n\n@hookimpl\ndef hatch_register_build_hook():\n    return SpecialBuildHook\n
      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      class BuildHookInterface(Generic[BuilderConfigBound]):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\n    class SpecialBuildHook(BuildHookInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialBuildHook\n\n\n    @hookimpl\n    def hatch_register_build_hook():\n        return SpecialBuildHook\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root: str,\n        config: dict[str, Any],\n        build_config: BuilderConfigBound,\n        metadata: ProjectMetadata,\n        directory: str,\n        target_name: str,\n        app: Application | None = None,\n    ) -> None:\n        self.__root = root\n        self.__config = config\n        self.__build_config = build_config\n        self.__metadata = metadata\n        self.__directory = directory\n        self.__target_name = target_name\n        self.__app = app\n\n    @property\n    def app(self) -> Application:\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = cast(Application, Application().get_safe_application())\n\n        return self.__app\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict[str, Any]:\n        \"\"\"\n        The cumulative hook configuration.\n\n        ```toml config-example\n        [tool.hatch.build.hooks.<PLUGIN_NAME>]\n        [tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @property\n    def metadata(self) -> ProjectMetadata:\n        # Undocumented for now\n        return self.__metadata\n\n    @property\n    def build_config(self) -> BuilderConfigBound:\n        \"\"\"\n        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        return self.__build_config\n\n    @property\n    def directory(self) -> str:\n        \"\"\"\n        The build directory.\n        \"\"\"\n        return self.__directory\n\n    @property\n    def target_name(self) -> str:\n        \"\"\"\n        The plugin name of the build target.\n        \"\"\"\n        return self.__target_name\n\n    def dependencies(self) -> list[str]:  # noqa: PLR6301\n        \"\"\"\n        A list of extra [dependencies](../../config/dependency.md) that must be installed\n        prior to builds.\n\n        !!! warning\n            - For this to have any effect the hook dependency itself cannot be dynamic and\n                must always be defined in `build-system.requires`.\n            - As the hook must be imported to call this method, imports that require these\n                dependencies must be evaluated lazily.\n        \"\"\"\n        return []\n\n    def clean(self, versions: list[str]) -> None:\n        \"\"\"\n        This occurs before the build process if the `-c`/`--clean` flag was passed to\n        the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n        the [`clean`](../../cli/reference.md#hatch-clean) command.\n        \"\"\"\n\n    def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n        \"\"\"\n        This occurs immediately before each build.\n\n        Any modifications to the build data will be seen by the build target.\n        \"\"\"\n\n    def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n        \"\"\"\n        This occurs immediately after each build and will not run if the `--hooks-only` flag\n        was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n        The build data will reflect any modifications done by the target during the build.\n        \"\"\"\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.app","title":"app: Application property","text":"

      An instance of Application.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.root","title":"root: str property","text":"

      The root of the project tree.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.config","title":"config: dict[str, Any] property","text":"

      The cumulative hook configuration.

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.<PLUGIN_NAME>]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
      [build.hooks.<PLUGIN_NAME>]\n[build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.build_config","title":"build_config: BuilderConfigBound property","text":"

      An instance of BuilderConfig.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.target_name","title":"target_name: str property","text":"

      The plugin name of the build target.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.directory","title":"directory: str property","text":"

      The build directory.

      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.dependencies","title":"dependencies() -> list[str]","text":"

      A list of extra dependencies that must be installed prior to builds.

      Warning

      • For this to have any effect the hook dependency itself cannot be dynamic and must always be defined in build-system.requires.
      • As the hook must be imported to call this method, imports that require these dependencies must be evaluated lazily.
      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def dependencies(self) -> list[str]:  # noqa: PLR6301\n    \"\"\"\n    A list of extra [dependencies](../../config/dependency.md) that must be installed\n    prior to builds.\n\n    !!! warning\n        - For this to have any effect the hook dependency itself cannot be dynamic and\n            must always be defined in `build-system.requires`.\n        - As the hook must be imported to call this method, imports that require these\n            dependencies must be evaluated lazily.\n    \"\"\"\n    return []\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.clean","title":"clean(versions: list[str]) -> None","text":"

      This occurs before the build process if the -c/--clean flag was passed to the build command, or when invoking the clean command.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def clean(self, versions: list[str]) -> None:\n    \"\"\"\n    This occurs before the build process if the `-c`/`--clean` flag was passed to\n    the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n    the [`clean`](../../cli/reference.md#hatch-clean) command.\n    \"\"\"\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.initialize","title":"initialize(version: str, build_data: dict[str, Any]) -> None","text":"

      This occurs immediately before each build.

      Any modifications to the build data will be seen by the build target.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n    \"\"\"\n    This occurs immediately before each build.\n\n    Any modifications to the build data will be seen by the build target.\n    \"\"\"\n
      "},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.finalize","title":"finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None","text":"

      This occurs immediately after each build and will not run if the --hooks-only flag was passed to the build command.

      The build data will reflect any modifications done by the target during the build.

      Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
      def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n    \"\"\"\n    This occurs immediately after each build and will not run if the `--hooks-only` flag\n    was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n    The build data will reflect any modifications done by the target during the build.\n    \"\"\"\n
      "},{"location":"plugins/build-hook/version/","title":"Version build hook","text":"

      This writes the project's version to a file.

      "},{"location":"plugins/build-hook/version/#configuration","title":"Configuration","text":"

      The build hook plugin name is version.

      pyproject.toml hatch.toml
      [tool.hatch.build.hooks.version]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.version]\n
      [build.hooks.version]\n[build.targets.<TARGET_NAME>.hooks.version]\n
      "},{"location":"plugins/build-hook/version/#options","title":"Options","text":"Option Description path (required) A relative path to the desired file template A string representing the entire contents of path that will be formatted with a version variable pattern Rather than updating the entire file, a regular expression may be used that has a named group called version that represents the version. If set to true, a pattern will be used that looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v."},{"location":"plugins/builder/binary/","title":"Binary builder","text":"

      This uses PyApp to build an application that is able to bootstrap itself at runtime.

      Note

      This requires an installation of Rust.

      "},{"location":"plugins/builder/binary/#configuration","title":"Configuration","text":"

      The builder plugin name is binary.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.binary]\n
      [build.targets.binary]\n
      "},{"location":"plugins/builder/binary/#options","title":"Options","text":"Option Default Description scripts all defined An array of defined script names to limit what gets built python-version latest compatible Python minor version The Python version ID to use pyapp-version The version of PyApp to use"},{"location":"plugins/builder/binary/#build-behavior","title":"Build behavior","text":"

      If any scripts are defined then each one will be built (limited by the scripts option). Otherwise, a single executable will be built based on the project name assuming there is an equivalently named module with a __main__.py file.

      Every executable will be built inside an app directory in the output directory.

      If the CARGO environment variable is set then that path will be used as the executable for performing builds.

      If the CARGO_BUILD_TARGET environment variable is set then its value will be appended to the file name stems.

      If the PYAPP_REPO environment variable is set then a local build will be performed inside that directory rather than installing from crates.io. Note that this is required if the CARGO environment variable refers to cross.

      "},{"location":"plugins/builder/custom/","title":"Custom builder","text":"

      This is a custom class in a given Python file that inherits from the BuilderInterface.

      "},{"location":"plugins/builder/custom/#configuration","title":"Configuration","text":"

      The builder plugin name is custom.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.custom]\n
      [build.targets.custom]\n
      "},{"location":"plugins/builder/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/builder/custom/#example","title":"Example","text":"hatch_build.py
      from hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass CustomBuilder(BuilderInterface):\n    ...\n

      If multiple subclasses are found, you must define a function named get_builder that returns the desired builder.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      "},{"location":"plugins/builder/reference/","title":"Builder plugins","text":"

      See the documentation for build configuration.

      "},{"location":"plugins/builder/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-aws - used for building AWS Lambda functions with SAM
      • hatch-zipped-directory - used for building ZIP archives for installation into various foreign package installation systems
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface","title":"BuilderInterface","text":"

      Example usage:

      plugin.py hooks.py
      from hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass SpecialBuilder(BuilderInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuilder\n\n\n@hookimpl\ndef hatch_register_builder():\n    return SpecialBuilder\n
      Source code in backend/src/hatchling/builders/plugin/interface.py
      class BuilderInterface(ABC, Generic[BuilderConfigBound, PluginManagerBound]):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.builders.plugin.interface import BuilderInterface\n\n\n    class SpecialBuilder(BuilderInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialBuilder\n\n\n    @hookimpl\n    def hatch_register_builder():\n        return SpecialBuilder\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root: str,\n        plugin_manager: PluginManagerBound | None = None,\n        config: dict[str, Any] | None = None,\n        metadata: ProjectMetadata | None = None,\n        app: Application | None = None,\n    ) -> None:\n        self.__root = root\n        self.__plugin_manager = cast(PluginManagerBound, plugin_manager)\n        self.__raw_config = config\n        self.__metadata = metadata\n        self.__app = app\n        self.__config = cast(BuilderConfigBound, None)\n        self.__project_config: dict[str, Any] | None = None\n        self.__hatch_config: dict[str, Any] | None = None\n        self.__build_config: dict[str, Any] | None = None\n        self.__build_targets: list[str] | None = None\n        self.__target_config: dict[str, Any] | None = None\n\n        # Metadata\n        self.__project_id: str | None = None\n\n    def build(\n        self,\n        *,\n        directory: str | None = None,\n        versions: list[str] | None = None,\n        hooks_only: bool | None = None,\n        clean: bool | None = None,\n        clean_hooks_after: bool | None = None,\n        clean_only: bool | None = False,\n    ) -> Generator[str, None, None]:\n        # Fail early for invalid project metadata\n        self.metadata.validate_fields()\n\n        if directory is None:\n            directory = (\n                self.config.normalize_build_directory(os.environ[BuildEnvVars.LOCATION])\n                if BuildEnvVars.LOCATION in os.environ\n                else self.config.directory\n            )\n\n        if not os.path.isdir(directory):\n            os.makedirs(directory)\n\n        version_api = self.get_version_api()\n\n        versions = versions or self.config.versions\n        if versions:\n            unknown_versions = set(versions) - set(version_api)\n            if unknown_versions:\n                message = (\n                    f'Unknown versions for target `{self.PLUGIN_NAME}`: {\", \".join(map(str, sorted(unknown_versions)))}'\n                )\n                raise ValueError(message)\n\n        if hooks_only is None:\n            hooks_only = env_var_enabled(BuildEnvVars.HOOKS_ONLY)\n\n        configured_build_hooks = self.get_build_hooks(directory)\n        build_hooks = list(configured_build_hooks.values())\n\n        if clean_only:\n            clean = True\n        elif clean is None:\n            clean = env_var_enabled(BuildEnvVars.CLEAN)\n        if clean:\n            if not hooks_only:\n                self.clean(directory, versions)\n\n            for build_hook in build_hooks:\n                build_hook.clean(versions)\n\n            if clean_only:\n                return\n\n        if clean_hooks_after is None:\n            clean_hooks_after = env_var_enabled(BuildEnvVars.CLEAN_HOOKS_AFTER)\n\n        for version in versions:\n            self.app.display_debug(f'Building `{self.PLUGIN_NAME}` version `{version}`')\n\n            build_data = self.get_default_build_data()\n            self.set_build_data_defaults(build_data)\n\n            # Allow inspection of configured build hooks and the order in which they run\n            build_data['build_hooks'] = tuple(configured_build_hooks)\n\n            # Execute all `initialize` build hooks\n            for build_hook in build_hooks:\n                build_hook.initialize(version, build_data)\n\n            if hooks_only:\n                self.app.display_debug(f'Only ran build hooks for `{self.PLUGIN_NAME}` version `{version}`')\n                continue\n\n            # Build the artifact\n            with self.config.set_build_data(build_data):\n                artifact = version_api[version](directory, **build_data)\n\n            # Execute all `finalize` build hooks\n            for build_hook in build_hooks:\n                build_hook.finalize(version, build_data, artifact)\n\n            if clean_hooks_after:\n                for build_hook in build_hooks:\n                    build_hook.clean([version])\n\n            yield artifact\n\n    def recurse_included_files(self) -> Iterable[IncludedFile]:\n        \"\"\"\n        Returns a consistently generated series of file objects for every file that should be distributed. Each file\n        object has three `str` attributes:\n\n        - `path` - the absolute path\n        - `relative_path` - the path relative to the project root; will be an empty string for external files\n        - `distribution_path` - the path to be distributed as\n        \"\"\"\n        yield from self.recurse_selected_project_files()\n        yield from self.recurse_forced_files(self.config.get_force_include())\n\n    def recurse_selected_project_files(self) -> Iterable[IncludedFile]:\n        if self.config.only_include:\n            yield from self.recurse_explicit_files(self.config.only_include)\n        else:\n            yield from self.recurse_project_files()\n\n    def recurse_project_files(self) -> Iterable[IncludedFile]:\n        for root, dirs, files in safe_walk(self.root):\n            relative_path = get_relative_path(root, self.root)\n\n            dirs[:] = sorted(d for d in dirs if not self.config.directory_is_excluded(d, relative_path))\n\n            files.sort()\n            is_package = '__init__.py' in files\n            for f in files:\n                if f in EXCLUDED_FILES:\n                    continue\n\n                relative_file_path = os.path.join(relative_path, f)\n                distribution_path = self.config.get_distribution_path(relative_file_path)\n                if self.config.path_is_reserved(distribution_path):\n                    continue\n\n                if self.config.include_path(relative_file_path, is_package=is_package):\n                    yield IncludedFile(\n                        os.path.join(root, f), relative_file_path, self.config.get_distribution_path(relative_file_path)\n                    )\n\n    def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n        for source, target_path in inclusion_map.items():\n            external = not source.startswith(self.root)\n            if os.path.isfile(source):\n                yield IncludedFile(\n                    source,\n                    '' if external else os.path.relpath(source, self.root),\n                    self.config.get_distribution_path(target_path),\n                )\n            elif os.path.isdir(source):\n                for root, dirs, files in safe_walk(source):\n                    relative_directory = get_relative_path(root, source)\n\n                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n                    files.sort()\n                    for f in files:\n                        if f in EXCLUDED_FILES:\n                            continue\n\n                        relative_file_path = os.path.join(target_path, relative_directory, f)\n                        distribution_path = self.config.get_distribution_path(relative_file_path)\n                        if not self.config.path_is_reserved(distribution_path):\n                            yield IncludedFile(\n                                os.path.join(root, f),\n                                '' if external else relative_file_path,\n                                distribution_path,\n                            )\n            else:\n                msg = f'Forced include not found: {source}'\n                raise FileNotFoundError(msg)\n\n    def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n        for source, target_path in inclusion_map.items():\n            external = not source.startswith(self.root)\n            if os.path.isfile(source):\n                distribution_path = self.config.get_distribution_path(target_path)\n                if not self.config.path_is_reserved(distribution_path):\n                    yield IncludedFile(\n                        source,\n                        '' if external else os.path.relpath(source, self.root),\n                        self.config.get_distribution_path(target_path),\n                    )\n            elif os.path.isdir(source):\n                for root, dirs, files in safe_walk(source):\n                    relative_directory = get_relative_path(root, source)\n\n                    dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n                    files.sort()\n                    is_package = '__init__.py' in files\n                    for f in files:\n                        if f in EXCLUDED_FILES:\n                            continue\n\n                        relative_file_path = os.path.join(target_path, relative_directory, f)\n                        distribution_path = self.config.get_distribution_path(relative_file_path)\n                        if self.config.path_is_reserved(distribution_path):\n                            continue\n\n                        if self.config.include_path(relative_file_path, explicit=True, is_package=is_package):\n                            yield IncludedFile(\n                                os.path.join(root, f), '' if external else relative_file_path, distribution_path\n                            )\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def plugin_manager(self) -> PluginManagerBound:\n        if self.__plugin_manager is None:\n            from hatchling.plugin.manager import PluginManager\n\n            self.__plugin_manager = PluginManager()\n\n        return self.__plugin_manager\n\n    @property\n    def metadata(self) -> ProjectMetadata:\n        if self.__metadata is None:\n            from hatchling.metadata.core import ProjectMetadata\n\n            self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)\n\n        return self.__metadata\n\n    @property\n    def app(self) -> Application:\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = cast(Application, Application().get_safe_application())\n\n        return self.__app\n\n    @property\n    def raw_config(self) -> dict[str, Any]:\n        if self.__raw_config is None:\n            self.__raw_config = self.metadata.config\n\n        return self.__raw_config\n\n    @property\n    def project_config(self) -> dict[str, Any]:\n        if self.__project_config is None:\n            self.__project_config = self.metadata.core.config\n\n        return self.__project_config\n\n    @property\n    def hatch_config(self) -> dict[str, Any]:\n        if self.__hatch_config is None:\n            self.__hatch_config = self.metadata.hatch.config\n\n        return self.__hatch_config\n\n    @property\n    def config(self) -> BuilderConfigBound:\n        \"\"\"\n        An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        if self.__config is None:\n            self.__config = self.get_config_class()(\n                self, self.root, self.PLUGIN_NAME, self.build_config, self.target_config\n            )\n\n        return self.__config\n\n    @property\n    def build_config(self) -> dict[str, Any]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.build]\n        ```\n        \"\"\"\n        if self.__build_config is None:\n            self.__build_config = self.metadata.hatch.build_config\n\n        return self.__build_config\n\n    @property\n    def target_config(self) -> dict[str, Any]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.build.targets.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        if self.__target_config is None:\n            target_config: dict[str, Any] = self.metadata.hatch.build_targets.get(self.PLUGIN_NAME, {})\n            if not isinstance(target_config, dict):\n                message = f'Field `tool.hatch.build.targets.{self.PLUGIN_NAME}` must be a table'\n                raise TypeError(message)\n\n            self.__target_config = target_config\n\n        return self.__target_config\n\n    @property\n    def project_id(self) -> str:\n        if self.__project_id is None:\n            self.__project_id = f'{self.normalize_file_name_component(self.metadata.core.name)}-{self.metadata.version}'\n\n        return self.__project_id\n\n    def get_build_hooks(self, directory: str) -> dict[str, BuildHookInterface]:\n        configured_build_hooks = {}\n        for hook_name, config in self.config.hook_config.items():\n            build_hook = self.plugin_manager.build_hook.get(hook_name)\n            if build_hook is None:\n                from hatchling.plugin.exceptions import UnknownPluginError\n\n                message = f'Unknown build hook: {hook_name}'\n                raise UnknownPluginError(message)\n\n            configured_build_hooks[hook_name] = build_hook(\n                self.root, config, self.config, self.metadata, directory, self.PLUGIN_NAME, self.app\n            )\n\n        return configured_build_hooks\n\n    @abstractmethod\n    def get_version_api(self) -> dict[str, Callable]:\n        \"\"\"\n        A mapping of `str` versions to a callable that is used for building.\n        Each callable must have the following signature:\n\n        ```python\n        def ...(build_dir: str, build_data: dict) -> str:\n        ```\n\n        The return value must be the absolute path to the built artifact.\n        \"\"\"\n\n    def get_default_versions(self) -> list[str]:\n        \"\"\"\n        A list of versions to build when users do not specify any, defaulting to all versions.\n        \"\"\"\n        return list(self.get_version_api())\n\n    def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301\n        \"\"\"\n        A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n        \"\"\"\n        return {}\n\n    def set_build_data_defaults(self, build_data: dict[str, Any]) -> None:  # noqa: PLR6301\n        build_data.setdefault('artifacts', [])\n        build_data.setdefault('force_include', {})\n\n    def clean(self, directory: str, versions: list[str]) -> None:\n        \"\"\"\n        Called before builds if the `-c`/`--clean` flag was passed to the\n        [`build`](../../cli/reference.md#hatch-build) command.\n        \"\"\"\n\n    @classmethod\n    def get_config_class(cls) -> type[BuilderConfig]:\n        \"\"\"\n        Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n        \"\"\"\n        return BuilderConfig\n\n    @staticmethod\n    def normalize_file_name_component(file_name: str) -> str:\n        \"\"\"\n        https://peps.python.org/pep-0427/#escaping-and-unicode\n        \"\"\"\n        return re.sub(r'[^\\w\\d.]+', '_', file_name, flags=re.UNICODE)\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.app","title":"app: Application property","text":"

      An instance of Application.

      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.root","title":"root: str property","text":"

      The root of the project tree.

      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.build_config","title":"build_config: dict[str, Any] property","text":"pyproject.toml hatch.toml
      [tool.hatch.build]\n
      [build]\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.target_config","title":"target_config: dict[str, Any] property","text":"pyproject.toml hatch.toml
      [tool.hatch.build.targets.<PLUGIN_NAME>]\n
      [build.targets.<PLUGIN_NAME>]\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.config","title":"config: BuilderConfigBound property","text":"

      An instance of BuilderConfig.

      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_config_class","title":"get_config_class() -> type[BuilderConfig] classmethod","text":"

      Must return a subclass of BuilderConfig.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      @classmethod\ndef get_config_class(cls) -> type[BuilderConfig]:\n    \"\"\"\n    Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n    \"\"\"\n    return BuilderConfig\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_version_api","title":"get_version_api() -> dict[str, Callable] abstractmethod","text":"

      A mapping of str versions to a callable that is used for building. Each callable must have the following signature:

      def ...(build_dir: str, build_data: dict) -> str:\n

      The return value must be the absolute path to the built artifact.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      @abstractmethod\ndef get_version_api(self) -> dict[str, Callable]:\n    \"\"\"\n    A mapping of `str` versions to a callable that is used for building.\n    Each callable must have the following signature:\n\n    ```python\n    def ...(build_dir: str, build_data: dict) -> str:\n    ```\n\n    The return value must be the absolute path to the built artifact.\n    \"\"\"\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_versions","title":"get_default_versions() -> list[str]","text":"

      A list of versions to build when users do not specify any, defaulting to all versions.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def get_default_versions(self) -> list[str]:\n    \"\"\"\n    A list of versions to build when users do not specify any, defaulting to all versions.\n    \"\"\"\n    return list(self.get_version_api())\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.clean","title":"clean(directory: str, versions: list[str]) -> None","text":"

      Called before builds if the -c/--clean flag was passed to the build command.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def clean(self, directory: str, versions: list[str]) -> None:\n    \"\"\"\n    Called before builds if the `-c`/`--clean` flag was passed to the\n    [`build`](../../cli/reference.md#hatch-build) command.\n    \"\"\"\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.recurse_included_files","title":"recurse_included_files() -> Iterable[IncludedFile]","text":"

      Returns a consistently generated series of file objects for every file that should be distributed. Each file object has three str attributes:

      • path - the absolute path
      • relative_path - the path relative to the project root; will be an empty string for external files
      • distribution_path - the path to be distributed as
      Source code in backend/src/hatchling/builders/plugin/interface.py
      def recurse_included_files(self) -> Iterable[IncludedFile]:\n    \"\"\"\n    Returns a consistently generated series of file objects for every file that should be distributed. Each file\n    object has three `str` attributes:\n\n    - `path` - the absolute path\n    - `relative_path` - the path relative to the project root; will be an empty string for external files\n    - `distribution_path` - the path to be distributed as\n    \"\"\"\n    yield from self.recurse_selected_project_files()\n    yield from self.recurse_forced_files(self.config.get_force_include())\n
      "},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_build_data","title":"get_default_build_data() -> dict[str, Any]","text":"

      A mapping that can be modified by build hooks to influence the behavior of builds.

      Source code in backend/src/hatchling/builders/plugin/interface.py
      def get_default_build_data(self) -> dict[str, Any]:  # noqa: PLR6301\n    \"\"\"\n    A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n    \"\"\"\n    return {}\n
      "},{"location":"plugins/builder/sdist/","title":"Source distribution builder","text":"

      A source distribution, or sdist, is an archive of Python \"source code\". Although largely unspecified, by convention it should include everything that is required to build a wheel without making network requests.

      "},{"location":"plugins/builder/sdist/#configuration","title":"Configuration","text":"

      The builder plugin name is sdist.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.sdist]\n
      [build.targets.sdist]\n
      "},{"location":"plugins/builder/sdist/#options","title":"Options","text":"Option Default Description core-metadata-version \"2.3\" The version of core metadata to use strict-naming true Whether or not file names should contain the normalized version of the project name support-legacy false Whether or not to include a setup.py file to support legacy installation mechanisms"},{"location":"plugins/builder/sdist/#versions","title":"Versions","text":"Version Description standard (default) The latest conventional format"},{"location":"plugins/builder/sdist/#default-file-selection","title":"Default file selection","text":"

      When the user has not set any file selection options, all files that are not ignored by your VCS will be included.

      Note

      The following files are always included and cannot be excluded:

      • /pyproject.toml
      • /hatch.toml
      • /hatch_build.py
      • /.gitignore or /.hgignore
      • Any defined readme file
      • All defined license-files
      "},{"location":"plugins/builder/sdist/#reproducibility","title":"Reproducibility","text":"

      Reproducible builds are supported.

      "},{"location":"plugins/builder/sdist/#build-data","title":"Build data","text":"

      This is data that can be modified by build hooks.

      Data Default Description dependencies Extra project dependencies"},{"location":"plugins/builder/wheel/","title":"Wheel builder","text":"

      A wheel is a binary distribution of a Python package that can be installed directly into an environment.

      "},{"location":"plugins/builder/wheel/#configuration","title":"Configuration","text":"

      The builder plugin name is wheel.

      pyproject.toml hatch.toml
      [tool.hatch.build.targets.wheel]\n
      [build.targets.wheel]\n
      "},{"location":"plugins/builder/wheel/#options","title":"Options","text":"Option Default Description core-metadata-version \"2.3\" The version of core metadata to use shared-data A mapping similar to the forced inclusion option corresponding to data that will be installed globally in a given Python environment, usually under sys.prefix extra-metadata A mapping similar to the forced inclusion option corresponding to extra metadata that will be shipped in a directory named extra_metadata strict-naming true Whether or not file names should contain the normalized version of the project name macos-max-compat true Whether or not on macOS, when build hooks have set the infer_tag build data, the wheel name should signal broad support rather than specific versions for newer SDK versions.Note: The default will become false, and this option eventually removed, sometime after consumers like pip start supporting these newer SDK versions. bypass-selection false Whether or not to suppress the error when one has not defined any file selection options and all heuristics have failed to determine what to ship"},{"location":"plugins/builder/wheel/#versions","title":"Versions","text":"Version Description standard (default) The latest standardized format editable A wheel that only ships .pth files or import hooks for real-time development"},{"location":"plugins/builder/wheel/#default-file-selection","title":"Default file selection","text":"

      When the user has not set any file selection options, the project name will be used to determine the package to ship in the following heuristic order:

      1. <NAME>/__init__.py
      2. src/<NAME>/__init__.py
      3. <NAME>.py
      4. <NAMESPACE>/<NAME>/__init__.py

      If none of these heuristics are satisfied, an error will be raised.

      "},{"location":"plugins/builder/wheel/#reproducibility","title":"Reproducibility","text":"

      Reproducible builds are supported.

      "},{"location":"plugins/builder/wheel/#build-data","title":"Build data","text":"

      This is data that can be modified by build hooks.

      Data Default Description tag The full tag part of the filename (e.g. py3-none-any), defaulting to a cross-platform wheel with the supported major versions of Python based on project metadata infer_tag False When tag is not set, this may be enabled to use the one most specific to the platform, Python interpreter, and ABI pure_python True Whether or not to write metadata indicating that the package does not contain any platform-specific files dependencies Extra project dependencies extra_metadata Additional extra-metadata entries, which take precedence in case of conflicts force_include_editable Similar to the force_include option but specifically for the editable version and takes precedence"},{"location":"plugins/environment/reference/","title":"Environment plugins","text":"

      See the documentation for environment configuration.

      "},{"location":"plugins/environment/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-conda - environments backed by Conda/Mamba
      • hatch-containers - environments run inside containers
      • hatch-pip-compile - use pip-compile to manage project dependencies and lockfiles
      • hatch-pip-deepfreeze - virtual environments with dependency locking by pip-deepfreeze
      "},{"location":"plugins/environment/reference/#installation","title":"Installation","text":"

      Any required environment types that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

      pyproject.toml hatch.toml
      [tool.hatch.env]\nrequires = [\n  \"...\",\n]\n
      [env]\nrequires = [\n  \"...\",\n]\n
      "},{"location":"plugins/environment/reference/#life-cycle","title":"Life cycle","text":"

      Whenever an environment is used, the following logic is performed:

      Source code in src/hatch/cli/application.py
      def prepare_environment(self, environment: EnvironmentInterface):\n    if not environment.exists():\n        self.env_metadata.reset(environment)\n\n        with environment.app_status_creation():\n            environment.create()\n\n        if not environment.skip_install:\n            if environment.pre_install_commands:\n                with environment.app_status_pre_installation():\n                    self.run_shell_commands(environment, environment.pre_install_commands, source='pre-install')\n\n            with environment.app_status_project_installation():\n                if environment.dev_mode:\n                    environment.install_project_dev_mode()\n                else:\n                    environment.install_project()\n\n            if environment.post_install_commands:\n                with environment.app_status_post_installation():\n                    self.run_shell_commands(environment, environment.post_install_commands, source='post-install')\n\n    with environment.app_status_dependency_state_check():\n        new_dep_hash = environment.dependency_hash()\n\n    current_dep_hash = self.env_metadata.dependency_hash(environment)\n    if new_dep_hash != current_dep_hash:\n        with environment.app_status_dependency_installation_check():\n            dependencies_in_sync = environment.dependencies_in_sync()\n\n        if not dependencies_in_sync:\n            with environment.app_status_dependency_synchronization():\n                environment.sync_dependencies()\n                new_dep_hash = environment.dependency_hash()\n\n        self.env_metadata.update_dependency_hash(environment, new_dep_hash)\n
      "},{"location":"plugins/environment/reference/#build-environments","title":"Build environments","text":"

      All environment types should offer support for a special sub-environment in which projects can be built. This environment is used in the following scenarios:

      • the build command
      • commands that read dependencies, like dep hash, if any project dependencies are set dynamically
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface","title":"EnvironmentInterface","text":"

      Example usage:

      plugin.py hooks.py
          from hatch.env.plugin.interface import EnvironmentInterface\n\n\n    class SpecialEnvironment(EnvironmentInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
          from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialEnvironment\n\n\n    @hookimpl\n    def hatch_register_environment():\n        return SpecialEnvironment\n
      Source code in src/hatch/env/plugin/interface.py
      class EnvironmentInterface(ABC):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.env.plugin.interface import EnvironmentInterface\n\n\n        class SpecialEnvironment(EnvironmentInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialEnvironment\n\n\n        @hookimpl\n        def hatch_register_environment():\n            return SpecialEnvironment\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(\n        self,\n        root,\n        metadata,\n        name,\n        config,\n        matrix_variables,\n        data_directory,\n        isolated_data_directory,\n        platform,\n        verbosity,\n        app=None,\n    ):\n        self.__root = root\n        self.__metadata = metadata\n        self.__name = name\n        self.__config = config\n        self.__matrix_variables = matrix_variables\n        self.__data_directory = data_directory\n        self.__isolated_data_directory = isolated_data_directory\n        self.__platform = platform\n        self.__verbosity = verbosity\n        self.__app = app\n        self.__context = None\n\n        self._system_python = None\n        self._env_vars = None\n        self._env_include = None\n        self._env_exclude = None\n        self._environment_dependencies_complex = None\n        self._environment_dependencies = None\n        self._dependencies_complex = None\n        self._dependencies = None\n        self._platforms = None\n        self._skip_install = None\n        self._dev_mode = None\n        self._features = None\n        self._description = None\n        self._scripts = None\n        self._pre_install_commands = None\n        self._post_install_commands = None\n\n    @property\n    def matrix_variables(self):\n        return self.__matrix_variables\n\n    @property\n    def app(self):\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        if self.__app is None:\n            from hatchling.bridge.app import Application\n\n            self.__app = Application().get_safe_application()\n\n        return self.__app\n\n    @property\n    def context(self):\n        if self.__context is None:\n            self.__context = self.get_context()\n\n        return self.__context\n\n    @property\n    def verbosity(self):\n        return self.__verbosity\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def metadata(self):\n        return self.__metadata\n\n    @property\n    def name(self) -> str:\n        \"\"\"\n        The name of the environment.\n        \"\"\"\n        return self.__name\n\n    @property\n    def platform(self):\n        \"\"\"\n        An instance of [Platform](../utilities.md#hatch.utils.platform.Platform).\n        \"\"\"\n        return self.__platform\n\n    @property\n    def data_directory(self):\n        \"\"\"\n        The [directory](../../config/hatch.md#environments) this plugin should use for storage as a path-like object.\n        If the user has not configured one then this will be the same as the\n        [isolated data directory](reference.md#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory).\n        \"\"\"\n        return self.__data_directory\n\n    @property\n    def isolated_data_directory(self):\n        \"\"\"\n        The default [directory](../../config/hatch.md#environments) reserved exclusively for this plugin as a path-like\n        object.\n        \"\"\"\n        return self.__isolated_data_directory\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @property\n    def system_python(self):\n        if self._system_python is None:\n            system_python = os.environ.get(AppEnvVars.PYTHON)\n            if system_python == 'self':\n                system_python = sys.executable\n\n            system_python = (\n                system_python\n                or self.platform.modules.shutil.which('python')\n                or self.platform.modules.shutil.which('python3')\n                or sys.executable\n            )\n            if not isabs(system_python):\n                system_python = self.platform.modules.shutil.which(system_python)\n\n            self._system_python = system_python\n\n        return self._system_python\n\n    @property\n    def env_vars(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>.env-vars]\n        ```\n        \"\"\"\n        if self._env_vars is None:\n            env_vars = self.config.get('env-vars', {})\n            if not isinstance(env_vars, dict):\n                message = f'Field `tool.hatch.envs.{self.name}.env-vars` must be a mapping'\n                raise TypeError(message)\n\n            for key, value in env_vars.items():\n                if not isinstance(value, str):\n                    message = (\n                        f'Environment variable `{key}` of field `tool.hatch.envs.{self.name}.env-vars` must be a string'\n                    )\n                    raise TypeError(message)\n\n            new_env_vars = {}\n            with self.metadata.context.apply_context(self.context):\n                for key, value in env_vars.items():\n                    new_env_vars[key] = self.metadata.context.format(value)\n\n            new_env_vars[AppEnvVars.ENV_ACTIVE] = self.name\n            self._env_vars = new_env_vars\n\n        return self._env_vars\n\n    @property\n    def env_include(self) -> list[str]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        env-include = [...]\n        ```\n        \"\"\"\n        if self._env_include is None:\n            env_include = self.config.get('env-include', [])\n            if not isinstance(env_include, list):\n                message = f'Field `tool.hatch.envs.{self.name}.env-include` must be an array'\n                raise TypeError(message)\n\n            for i, pattern in enumerate(env_include, 1):\n                if not isinstance(pattern, str):\n                    message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-include` must be a string'\n                    raise TypeError(message)\n\n            if env_include:\n                self._env_include = ['HATCH_BUILD_*', *env_include]\n            else:\n                self._env_include = env_include\n\n        return self._env_include\n\n    @property\n    def env_exclude(self) -> list[str]:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        env-exclude = [...]\n        ```\n        \"\"\"\n        if self._env_exclude is None:\n            env_exclude = self.config.get('env-exclude', [])\n            if not isinstance(env_exclude, list):\n                message = f'Field `tool.hatch.envs.{self.name}.env-exclude` must be an array'\n                raise TypeError(message)\n\n            for i, pattern in enumerate(env_exclude, 1):\n                if not isinstance(pattern, str):\n                    message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-exclude` must be a string'\n                    raise TypeError(message)\n\n            self._env_exclude = env_exclude\n\n        return self._env_exclude\n\n    @property\n    def environment_dependencies_complex(self):\n        if self._environment_dependencies_complex is None:\n            from packaging.requirements import InvalidRequirement, Requirement\n\n            dependencies_complex = []\n            with self.apply_context():\n                for option in ('dependencies', 'extra-dependencies'):\n                    dependencies = self.config.get(option, [])\n                    if not isinstance(dependencies, list):\n                        message = f'Field `tool.hatch.envs.{self.name}.{option}` must be an array'\n                        raise TypeError(message)\n\n                    for i, entry in enumerate(dependencies, 1):\n                        if not isinstance(entry, str):\n                            message = (\n                                f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` must be a string'\n                            )\n                            raise TypeError(message)\n\n                        try:\n                            dependencies_complex.append(Requirement(self.metadata.context.format(entry)))\n                        except InvalidRequirement as e:\n                            message = f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` is invalid: {e}'\n                            raise ValueError(message) from None\n\n            self._environment_dependencies_complex = dependencies_complex\n\n        return self._environment_dependencies_complex\n\n    @property\n    def environment_dependencies(self) -> list[str]:\n        \"\"\"\n        The list of all [environment dependencies](../../config/environment/overview.md#dependencies).\n        \"\"\"\n        if self._environment_dependencies is None:\n            self._environment_dependencies = [str(dependency) for dependency in self.environment_dependencies_complex]\n\n        return self._environment_dependencies\n\n    @property\n    def dependencies_complex(self):\n        if self._dependencies_complex is None:\n            all_dependencies_complex = list(self.environment_dependencies_complex)\n\n            # Ensure these are checked last to speed up initial environment creation since\n            # they will already be installed along with the project\n            if (not self.skip_install and self.dev_mode) or self.features:\n                from hatch.utils.dep import get_project_dependencies_complex\n\n                dependencies_complex, optional_dependencies_complex = get_project_dependencies_complex(self)\n\n                if not self.skip_install and self.dev_mode:\n                    all_dependencies_complex.extend(dependencies_complex.values())\n\n                for feature in self.features:\n                    if feature not in optional_dependencies_complex:\n                        message = (\n                            f'Feature `{feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n                            f'defined in the dynamic field `project.optional-dependencies`'\n                        )\n                        raise ValueError(message)\n\n                    all_dependencies_complex.extend(optional_dependencies_complex[feature].values())\n\n            self._dependencies_complex = all_dependencies_complex\n\n        return self._dependencies_complex\n\n    @property\n    def dependencies(self) -> list[str]:\n        \"\"\"\n        The list of all [project dependencies](../../config/metadata.md#dependencies) (if\n        [installed](../../config/environment/overview.md#skip-install) and in\n        [dev mode](../../config/environment/overview.md#dev-mode)), selected\n        [optional dependencies](../../config/environment/overview.md#features), and\n        [environment dependencies](../../config/environment/overview.md#dependencies).\n        \"\"\"\n        if self._dependencies is None:\n            self._dependencies = [str(dependency) for dependency in self.dependencies_complex]\n\n        return self._dependencies\n\n    @property\n    def platforms(self) -> list[str]:\n        \"\"\"\n        All names are stored as their lower-cased version.\n\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        platforms = [...]\n        ```\n        \"\"\"\n        if self._platforms is None:\n            platforms = self.config.get('platforms', [])\n            if not isinstance(platforms, list):\n                message = f'Field `tool.hatch.envs.{self.name}.platforms` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(platforms, 1):\n                if not isinstance(command, str):\n                    message = f'Platform #{i} of field `tool.hatch.envs.{self.name}.platforms` must be a string'\n                    raise TypeError(message)\n\n            self._platforms = [platform.lower() for platform in platforms]\n\n        return self._platforms\n\n    @property\n    def skip_install(self) -> bool:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        skip-install = ...\n        ```\n        \"\"\"\n        if self._skip_install is None:\n            skip_install = self.config.get('skip-install', not self.metadata.has_project_file())\n            if not isinstance(skip_install, bool):\n                message = f'Field `tool.hatch.envs.{self.name}.skip-install` must be a boolean'\n                raise TypeError(message)\n\n            self._skip_install = skip_install\n\n        return self._skip_install\n\n    @property\n    def dev_mode(self) -> bool:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        dev-mode = ...\n        ```\n        \"\"\"\n        if self._dev_mode is None:\n            dev_mode = self.config.get('dev-mode', True)\n            if not isinstance(dev_mode, bool):\n                message = f'Field `tool.hatch.envs.{self.name}.dev-mode` must be a boolean'\n                raise TypeError(message)\n\n            self._dev_mode = dev_mode\n\n        return self._dev_mode\n\n    @property\n    def features(self):\n        if self._features is None:\n            from hatchling.metadata.utils import normalize_project_name\n\n            features = self.config.get('features', [])\n            if not isinstance(features, list):\n                message = f'Field `tool.hatch.envs.{self.name}.features` must be an array of strings'\n                raise TypeError(message)\n\n            all_features = set()\n            for i, feature in enumerate(features, 1):\n                if not isinstance(feature, str):\n                    message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` must be a string'\n                    raise TypeError(message)\n\n                if not feature:\n                    message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` cannot be an empty string'\n                    raise ValueError(message)\n\n                normalized_feature = (\n                    feature\n                    if self.metadata.hatch.metadata.allow_ambiguous_features\n                    else normalize_project_name(feature)\n                )\n                if (\n                    not self.metadata.hatch.metadata.hook_config\n                    and normalized_feature not in self.metadata.core.optional_dependencies\n                ):\n                    message = (\n                        f'Feature `{normalized_feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n                        f'defined in field `project.optional-dependencies`'\n                    )\n                    raise ValueError(message)\n\n                all_features.add(normalized_feature)\n\n            self._features = sorted(all_features)\n\n        return self._features\n\n    @property\n    def description(self) -> str:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.envs.<ENV_NAME>]\n        description = ...\n        ```\n        \"\"\"\n        if self._description is None:\n            description = self.config.get('description', '')\n            if not isinstance(description, str):\n                message = f'Field `tool.hatch.envs.{self.name}.description` must be a string'\n                raise TypeError(message)\n\n            self._description = description\n\n        return self._description\n\n    @property\n    def scripts(self):\n        if self._scripts is None:\n            script_config = self.config.get('scripts', {})\n            if not isinstance(script_config, dict):\n                message = f'Field `tool.hatch.envs.{self.name}.scripts` must be a table'\n                raise TypeError(message)\n\n            config = {}\n\n            for name, data in script_config.items():\n                if ' ' in name:\n                    message = (\n                        f'Script name `{name}` in field `tool.hatch.envs.{self.name}.scripts` must not contain spaces'\n                    )\n                    raise ValueError(message)\n\n                commands = []\n\n                if isinstance(data, str):\n                    commands.append(data)\n                elif isinstance(data, list):\n                    for i, command in enumerate(data, 1):\n                        if not isinstance(command, str):\n                            message = (\n                                f'Command #{i} in field `tool.hatch.envs.{self.name}.scripts.{name}` must be a string'\n                            )\n                            raise TypeError(message)\n\n                        commands.append(command)\n                else:\n                    message = (\n                        f'Field `tool.hatch.envs.{self.name}.scripts.{name}` must be a string or an array of strings'\n                    )\n                    raise TypeError(message)\n\n                config[name] = commands\n\n            seen = {}\n            active = []\n            for script_name, commands in config.items():\n                commands[:] = expand_script_commands(self.name, script_name, commands, config, seen, active)\n\n            self._scripts = config\n\n        return self._scripts\n\n    @property\n    def pre_install_commands(self):\n        if self._pre_install_commands is None:\n            pre_install_commands = self.config.get('pre-install-commands', [])\n            if not isinstance(pre_install_commands, list):\n                message = f'Field `tool.hatch.envs.{self.name}.pre-install-commands` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(pre_install_commands, 1):\n                if not isinstance(command, str):\n                    message = (\n                        f'Command #{i} of field `tool.hatch.envs.{self.name}.pre-install-commands` must be a string'\n                    )\n                    raise TypeError(message)\n\n            self._pre_install_commands = list(pre_install_commands)\n\n        return self._pre_install_commands\n\n    @property\n    def post_install_commands(self):\n        if self._post_install_commands is None:\n            post_install_commands = self.config.get('post-install-commands', [])\n            if not isinstance(post_install_commands, list):\n                message = f'Field `tool.hatch.envs.{self.name}.post-install-commands` must be an array'\n                raise TypeError(message)\n\n            for i, command in enumerate(post_install_commands, 1):\n                if not isinstance(command, str):\n                    message = (\n                        f'Command #{i} of field `tool.hatch.envs.{self.name}.post-install-commands` must be a string'\n                    )\n                    raise TypeError(message)\n\n            self._post_install_commands = list(post_install_commands)\n\n        return self._post_install_commands\n\n    def activate(self):\n        \"\"\"\n        A convenience method called when using the environment as a context manager:\n\n        ```python\n        with environment:\n            ...\n        ```\n        \"\"\"\n\n    def deactivate(self):\n        \"\"\"\n        A convenience method called after using the environment as a context manager:\n\n        ```python\n        with environment:\n            ...\n        ```\n        \"\"\"\n\n    @abstractmethod\n    def find(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should return information about how to locate the environment or represent its ID in\n        some way. Additionally, this is expected to return something even if the environment is\n        [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n        \"\"\"\n\n    @abstractmethod\n    def create(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should perform the necessary steps to set up the environment.\n        \"\"\"\n\n    @abstractmethod\n    def remove(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should perform the necessary steps to completely remove the environment from the system and will only\n        be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n        [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n\n        If the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        has a caching mechanism, this should remove that as well.\n        \"\"\"\n\n    @abstractmethod\n    def exists(self) -> bool:\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should indicate whether or not the environment has already been created.\n        \"\"\"\n\n    @abstractmethod\n    def install_project(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the project in the environment.\n        \"\"\"\n\n    @abstractmethod\n    def install_project_dev_mode(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the project in the environment such that the environment\n        always reflects the current state of the project.\n        \"\"\"\n\n    @abstractmethod\n    def dependencies_in_sync(self) -> bool:\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should indicate whether or not the environment is compatible with the current\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n        \"\"\"\n\n    @abstractmethod\n    def sync_dependencies(self):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This should install the\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n        in the environment.\n        \"\"\"\n\n    def dependency_hash(self):\n        \"\"\"\n        This should return a hash of the environment's\n        [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n        and any other data that is handled by the\n        [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n        and\n        [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n        methods.\n        \"\"\"\n        from hatch.utils.dep import hash_dependencies\n\n        return hash_dependencies(self.dependencies_complex)\n\n    @contextmanager\n    def app_status_creation(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        with self.app.status(f'Creating environment: {self.name}'):\n            yield\n\n    @contextmanager\n    def app_status_pre_installation(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        with self.app.status('Running pre-installation commands'):\n            yield\n\n    @contextmanager\n    def app_status_post_installation(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        with self.app.status('Running post-installation commands'):\n            yield\n\n    @contextmanager\n    def app_status_project_installation(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        if self.dev_mode:\n            with self.app.status('Installing project in development mode'):\n                yield\n        else:\n            with self.app.status('Installing project'):\n                yield\n\n    @contextmanager\n    def app_status_dependency_state_check(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        if not self.skip_install and (\n            'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic\n        ):\n            with self.app.status('Polling dependency state'):\n                yield\n        else:\n            yield\n\n    @contextmanager\n    def app_status_dependency_installation_check(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        with self.app.status('Checking dependencies'):\n            yield\n\n    @contextmanager\n    def app_status_dependency_synchronization(self):\n        \"\"\"\n        See the [life cycle of environments](reference.md#life-cycle).\n        \"\"\"\n        with self.app.status('Syncing dependencies'):\n            yield\n\n    @contextmanager\n    def build_environment(\n        self,\n        dependencies: list[str],  # noqa: ARG002\n    ):\n        \"\"\"\n        This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project\n        given a set of dependencies and must be a context manager:\n\n        ```python\n        with environment.build_environment([...]):\n            ...\n        ```\n\n        The build environment should reflect any\n        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n        the user defined either currently or at the time of\n        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n        \"\"\"\n        with self.get_env_vars():\n            yield\n\n    def run_builder(\n        self,\n        build_environment,  # noqa: ARG002\n        **kwargs,\n    ):\n        \"\"\"\n        This will be called when the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        is active:\n\n        ```python\n        with environment.build_environment([...]) as build_env:\n            process = environment.run_builder(build_env, ...)\n        ```\n\n        This should return the standard library's\n        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).\n        The command is constructed by passing all keyword arguments to\n        [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).\n\n        For an example, open the default implementation below:\n        \"\"\"\n        return self.platform.run_command(self.construct_build_command(**kwargs))\n\n    def build_environment_exists(self):  # noqa: PLR6301\n        \"\"\"\n        If the\n        [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n        has a caching mechanism, this should indicate whether or not it has already been created.\n        \"\"\"\n        return False\n\n    def enter_shell(\n        self,\n        name: str,  # noqa: ARG002\n        path: str,\n        args: Iterable[str],\n    ):\n        \"\"\"\n        Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n        This should either use\n        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n        directly or provide the same guarantee.\n        \"\"\"\n        with self.command_context():\n            self.platform.exit_with_command([path, *args])\n\n    def run_shell_command(self, command: str, **kwargs):\n        \"\"\"\n        This should return the standard library's\n        [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n        and will always be called when the\n        [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n        is active, with the expectation of providing the same guarantee.\n        \"\"\"\n        kwargs.setdefault('shell', True)\n        return self.platform.run_command(command, **kwargs)\n\n    @contextmanager\n    def command_context(self):\n        \"\"\"\n        A context manager that when active should make executed shell commands reflect any\n        [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n        the user defined either currently or at the time of\n        [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n        For an example, open the default implementation below:\n        \"\"\"\n        with self.get_env_vars():\n            yield\n\n    def resolve_commands(self, commands: list[str]):\n        \"\"\"\n        This expands each command into one or more commands based on any\n        [scripts](../../config/environment/overview.md#scripts) that the user defined.\n        \"\"\"\n        for command in commands:\n            yield from self.expand_command(command)\n\n    def expand_command(self, command):\n        possible_script, args, _ignore_exit_code = parse_script_command(command)\n\n        # Indicate undefined\n        if not args:\n            args = None\n\n        with self.apply_context():\n            if possible_script in self.scripts:\n                for cmd in self.scripts[possible_script]:\n                    yield self.metadata.context.format(cmd, args=args).strip()\n            else:\n                yield self.metadata.context.format(command, args=args).strip()\n\n    def construct_build_command(  # noqa: PLR6301\n        self,\n        *,\n        directory=None,\n        targets=(),\n        hooks_only=False,\n        no_hooks=False,\n        clean=False,\n        clean_hooks_after=False,\n        clean_only=False,\n    ):\n        \"\"\"\n        This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to\n        a subprocess command issued to [builders](../builder/reference.md).\n        \"\"\"\n        command = ['python', '-u', '-m', 'hatchling', 'build']\n\n        if directory:\n            command.extend(('--directory', directory))\n\n        if targets:\n            for target in targets:\n                command.extend(('--target', target))\n\n        if hooks_only:\n            command.append('--hooks-only')\n\n        if no_hooks:\n            command.append('--no-hooks')\n\n        if clean:\n            command.append('--clean')\n\n        if clean_hooks_after:\n            command.append('--clean-hooks-after')\n\n        if clean_only:\n            command.append('--clean-only')\n\n        return command\n\n    def construct_pip_install_command(self, args: list[str]):\n        \"\"\"\n        A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n        command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n        \"\"\"\n        command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n        # Default to -1 verbosity\n        add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n        command.extend(args)\n        return command\n\n    def join_command_args(self, args: list[str]):\n        \"\"\"\n        This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n        from the received arguments.\n        \"\"\"\n        return self.platform.join_command_args(args)\n\n    def apply_features(self, requirement: str):\n        \"\"\"\n        A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n        to the given requirement.\n        \"\"\"\n        if self.features:\n            features = ','.join(self.features)\n            return f'{requirement}[{features}]'\n\n        return requirement\n\n    def check_compatibility(self):\n        \"\"\"\n        This raises an exception if the environment is not compatible with the user's setup. The default behavior\n        checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n        and any method override should keep this check.\n\n        This check is never performed if the environment has been\n        [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n        \"\"\"\n        if self.platforms and self.platform.name not in self.platforms:\n            message = 'unsupported platform'\n            raise OSError(message)\n\n    def get_env_vars(self) -> EnvVars:\n        \"\"\"\n        Returns a mapping of environment variables that should be available to the environment. The object can\n        be used as a context manager to temporarily apply the environment variables to the current process.\n\n        !!! note\n            The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n        \"\"\"\n        return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n\n    def get_env_var_option(self, option: str) -> str:\n        \"\"\"\n        Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n        \"\"\"\n        return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')\n\n    def get_context(self):\n        \"\"\"\n        Returns a subclass of\n        [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n        \"\"\"\n        from hatch.env.context import EnvironmentContextFormatter\n\n        return EnvironmentContextFormatter(self)\n\n    @staticmethod\n    def get_option_types() -> dict:\n        \"\"\"\n        Returns a mapping of supported options to their respective types so that they can be used by\n        [overrides](../../config/environment/advanced.md#option-overrides).\n        \"\"\"\n        return {}\n\n    @contextmanager\n    def apply_context(self):\n        with self.get_env_vars(), self.metadata.context.apply_context(self.context):\n            yield\n\n    def __enter__(self):\n        self.activate()\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        self.deactivate()\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app","title":"app property","text":"

      An instance of Application.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.root","title":"root property","text":"

      The root of the project tree as a path-like object.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.name","title":"name: str property","text":"

      The name of the environment.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.data_directory","title":"data_directory property","text":"

      The directory this plugin should use for storage as a path-like object. If the user has not configured one then this will be the same as the isolated data directory.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory","title":"isolated_data_directory property","text":"

      The default directory reserved exclusively for this plugin as a path-like object.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\n
      [envs.<ENV_NAME>]\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platform","title":"platform property","text":"

      An instance of Platform.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.environment_dependencies","title":"environment_dependencies: list[str] property","text":"

      The list of all environment dependencies.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies","title":"dependencies: list[str] property","text":"

      The list of all project dependencies (if installed and in dev mode), selected optional dependencies, and environment dependencies.

      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_vars","title":"env_vars: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>.env-vars]\n
      [envs.<ENV_NAME>.env-vars]\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_include","title":"env_include: list[str] property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nenv-include = [...]\n
      [envs.<ENV_NAME>]\nenv-include = [...]\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_exclude","title":"env_exclude: list[str] property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nenv-exclude = [...]\n
      [envs.<ENV_NAME>]\nenv-exclude = [...]\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platforms","title":"platforms: list[str] property","text":"

      All names are stored as their lower-cased version.

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nplatforms = [...]\n
      [envs.<ENV_NAME>]\nplatforms = [...]\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.skip_install","title":"skip_install: bool property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\nskip-install = ...\n
      [envs.<ENV_NAME>]\nskip-install = ...\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dev_mode","title":"dev_mode: bool property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\ndev-mode = ...\n
      [envs.<ENV_NAME>]\ndev-mode = ...\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.description","title":"description: str property","text":"pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\ndescription = ...\n
      [envs.<ENV_NAME>]\ndescription = ...\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.find","title":"find() abstractmethod","text":"

      REQUIRED

      This should return information about how to locate the environment or represent its ID in some way. Additionally, this is expected to return something even if the environment is incompatible.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef find(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should return information about how to locate the environment or represent its ID in\n    some way. Additionally, this is expected to return something even if the environment is\n    [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.create","title":"create() abstractmethod","text":"

      REQUIRED

      This should perform the necessary steps to set up the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef create(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should perform the necessary steps to set up the environment.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.remove","title":"remove() abstractmethod","text":"

      REQUIRED

      This should perform the necessary steps to completely remove the environment from the system and will only be triggered manually by users with the env remove or env prune commands.

      If the build environment has a caching mechanism, this should remove that as well.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef remove(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should perform the necessary steps to completely remove the environment from the system and will only\n    be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n    [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n\n    If the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    has a caching mechanism, this should remove that as well.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.exists","title":"exists() -> bool abstractmethod","text":"

      REQUIRED

      This should indicate whether or not the environment has already been created.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef exists(self) -> bool:\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should indicate whether or not the environment has already been created.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project","title":"install_project() abstractmethod","text":"

      REQUIRED

      This should install the project in the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef install_project(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the project in the environment.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project_dev_mode","title":"install_project_dev_mode() abstractmethod","text":"

      REQUIRED

      This should install the project in the environment such that the environment always reflects the current state of the project.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef install_project_dev_mode(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the project in the environment such that the environment\n    always reflects the current state of the project.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync","title":"dependencies_in_sync() -> bool abstractmethod","text":"

      REQUIRED

      This should indicate whether or not the environment is compatible with the current dependencies.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef dependencies_in_sync(self) -> bool:\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should indicate whether or not the environment is compatible with the current\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies","title":"sync_dependencies() abstractmethod","text":"

      REQUIRED

      This should install the dependencies in the environment.

      Source code in src/hatch/env/plugin/interface.py
      @abstractmethod\ndef sync_dependencies(self):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This should install the\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n    in the environment.\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependency_hash","title":"dependency_hash()","text":"

      This should return a hash of the environment's dependencies and any other data that is handled by the sync_dependencies and dependencies_in_sync methods.

      Source code in src/hatch/env/plugin/interface.py
      def dependency_hash(self):\n    \"\"\"\n    This should return a hash of the environment's\n    [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n    and any other data that is handled by the\n    [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n    and\n    [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n    methods.\n    \"\"\"\n    from hatch.utils.dep import hash_dependencies\n\n    return hash_dependencies(self.dependencies_complex)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.build_environment","title":"build_environment(dependencies: list[str])","text":"

      This should set up an isolated environment in which to build the project given a set of dependencies and must be a context manager:

      with environment.build_environment([...]):\n    ...\n

      The build environment should reflect any environment variables the user defined either currently or at the time of creation.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef build_environment(\n    self,\n    dependencies: list[str],  # noqa: ARG002\n):\n    \"\"\"\n    This should set up an isolated environment in which to [`build`](../../cli/reference.md#hatch-build) the project\n    given a set of dependencies and must be a context manager:\n\n    ```python\n    with environment.build_environment([...]):\n        ...\n    ```\n\n    The build environment should reflect any\n    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n    the user defined either currently or at the time of\n    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n    \"\"\"\n    with self.get_env_vars():\n        yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.build_environment_exists","title":"build_environment_exists()","text":"

      If the build environment has a caching mechanism, this should indicate whether or not it has already been created.

      Source code in src/hatch/env/plugin/interface.py
      def build_environment_exists(self):  # noqa: PLR6301\n    \"\"\"\n    If the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    has a caching mechanism, this should indicate whether or not it has already been created.\n    \"\"\"\n    return False\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.activate","title":"activate()","text":"

      A convenience method called when using the environment as a context manager:

      with environment:\n    ...\n
      Source code in src/hatch/env/plugin/interface.py
      def activate(self):\n    \"\"\"\n    A convenience method called when using the environment as a context manager:\n\n    ```python\n    with environment:\n        ...\n    ```\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.deactivate","title":"deactivate()","text":"

      A convenience method called after using the environment as a context manager:

      with environment:\n    ...\n
      Source code in src/hatch/env/plugin/interface.py
      def deactivate(self):\n    \"\"\"\n    A convenience method called after using the environment as a context manager:\n\n    ```python\n    with environment:\n        ...\n    ```\n    \"\"\"\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_creation","title":"app_status_creation()","text":"

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef app_status_creation(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    with self.app.status(f'Creating environment: {self.name}'):\n        yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_pre_installation","title":"app_status_pre_installation()","text":"

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef app_status_pre_installation(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    with self.app.status('Running pre-installation commands'):\n        yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_post_installation","title":"app_status_post_installation()","text":"

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef app_status_post_installation(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    with self.app.status('Running post-installation commands'):\n        yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_project_installation","title":"app_status_project_installation()","text":"

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef app_status_project_installation(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    if self.dev_mode:\n        with self.app.status('Installing project in development mode'):\n            yield\n    else:\n        with self.app.status('Installing project'):\n            yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_state_check","title":"app_status_dependency_state_check()","text":"

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef app_status_dependency_state_check(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    if not self.skip_install and (\n        'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic\n    ):\n        with self.app.status('Polling dependency state'):\n            yield\n    else:\n        yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_installation_check","title":"app_status_dependency_installation_check()","text":"

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef app_status_dependency_installation_check(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    with self.app.status('Checking dependencies'):\n        yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_synchronization","title":"app_status_dependency_synchronization()","text":"

      See the life cycle of environments.

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef app_status_dependency_synchronization(self):\n    \"\"\"\n    See the [life cycle of environments](reference.md#life-cycle).\n    \"\"\"\n    with self.app.status('Syncing dependencies'):\n        yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.run_builder","title":"run_builder(build_environment, **kwargs)","text":"

      This will be called when the build environment is active:

      with environment.build_environment([...]) as build_env:\n    process = environment.run_builder(build_env, ...)\n

      This should return the standard library's subprocess.CompletedProcess. The command is constructed by passing all keyword arguments to construct_build_command.

      For an example, open the default implementation below:

      Source code in src/hatch/env/plugin/interface.py
      def run_builder(\n    self,\n    build_environment,  # noqa: ARG002\n    **kwargs,\n):\n    \"\"\"\n    This will be called when the\n    [build environment](reference.md#hatch.env.plugin.interface.EnvironmentInterface.build_environment)\n    is active:\n\n    ```python\n    with environment.build_environment([...]) as build_env:\n        process = environment.run_builder(build_env, ...)\n    ```\n\n    This should return the standard library's\n    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess).\n    The command is constructed by passing all keyword arguments to\n    [construct_build_command](reference.md#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command).\n\n    For an example, open the default implementation below:\n    \"\"\"\n    return self.platform.run_command(self.construct_build_command(**kwargs))\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.construct_build_command","title":"construct_build_command(*, directory=None, targets=(), hooks_only=False, no_hooks=False, clean=False, clean_hooks_after=False, clean_only=False)","text":"

      This is the canonical way build command options are translated to a subprocess command issued to builders.

      Source code in src/hatch/env/plugin/interface.py
      def construct_build_command(  # noqa: PLR6301\n    self,\n    *,\n    directory=None,\n    targets=(),\n    hooks_only=False,\n    no_hooks=False,\n    clean=False,\n    clean_hooks_after=False,\n    clean_only=False,\n):\n    \"\"\"\n    This is the canonical way [`build`](../../cli/reference.md#hatch-build) command options are translated to\n    a subprocess command issued to [builders](../builder/reference.md).\n    \"\"\"\n    command = ['python', '-u', '-m', 'hatchling', 'build']\n\n    if directory:\n        command.extend(('--directory', directory))\n\n    if targets:\n        for target in targets:\n            command.extend(('--target', target))\n\n    if hooks_only:\n        command.append('--hooks-only')\n\n    if no_hooks:\n        command.append('--no-hooks')\n\n    if clean:\n        command.append('--clean')\n\n    if clean_hooks_after:\n        command.append('--clean-hooks-after')\n\n    if clean_only:\n        command.append('--clean-only')\n\n    return command\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.command_context","title":"command_context()","text":"

      A context manager that when active should make executed shell commands reflect any environment variables the user defined either currently or at the time of creation.

      For an example, open the default implementation below:

      Source code in src/hatch/env/plugin/interface.py
      @contextmanager\ndef command_context(self):\n    \"\"\"\n    A context manager that when active should make executed shell commands reflect any\n    [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n    the user defined either currently or at the time of\n    [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n    For an example, open the default implementation below:\n    \"\"\"\n    with self.get_env_vars():\n        yield\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.enter_shell","title":"enter_shell(name: str, path: str, args: Iterable[str])","text":"

      Spawn a shell within the environment.

      This should either use command_context directly or provide the same guarantee.

      Source code in src/hatch/env/plugin/interface.py
      def enter_shell(\n    self,\n    name: str,  # noqa: ARG002\n    path: str,\n    args: Iterable[str],\n):\n    \"\"\"\n    Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n    This should either use\n    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n    directly or provide the same guarantee.\n    \"\"\"\n    with self.command_context():\n        self.platform.exit_with_command([path, *args])\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.run_shell_command","title":"run_shell_command(command: str, **kwargs)","text":"

      This should return the standard library's subprocess.CompletedProcess and will always be called when the command_context is active, with the expectation of providing the same guarantee.

      Source code in src/hatch/env/plugin/interface.py
      def run_shell_command(self, command: str, **kwargs):\n    \"\"\"\n    This should return the standard library's\n    [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n    and will always be called when the\n    [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n    is active, with the expectation of providing the same guarantee.\n    \"\"\"\n    kwargs.setdefault('shell', True)\n    return self.platform.run_command(command, **kwargs)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.resolve_commands","title":"resolve_commands(commands: list[str])","text":"

      This expands each command into one or more commands based on any scripts that the user defined.

      Source code in src/hatch/env/plugin/interface.py
      def resolve_commands(self, commands: list[str]):\n    \"\"\"\n    This expands each command into one or more commands based on any\n    [scripts](../../config/environment/overview.md#scripts) that the user defined.\n    \"\"\"\n    for command in commands:\n        yield from self.expand_command(command)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars","title":"get_env_vars() -> EnvVars","text":"

      Returns a mapping of environment variables that should be available to the environment. The object can be used as a context manager to temporarily apply the environment variables to the current process.

      Note

      The environment variable HATCH_ENV_ACTIVE will always be set to the name of the environment.

      Source code in src/hatch/env/plugin/interface.py
      def get_env_vars(self) -> EnvVars:\n    \"\"\"\n    Returns a mapping of environment variables that should be available to the environment. The object can\n    be used as a context manager to temporarily apply the environment variables to the current process.\n\n    !!! note\n        The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n    \"\"\"\n    return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.apply_features","title":"apply_features(requirement: str)","text":"

      A convenience method that applies any user defined features to the given requirement.

      Source code in src/hatch/env/plugin/interface.py
      def apply_features(self, requirement: str):\n    \"\"\"\n    A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n    to the given requirement.\n    \"\"\"\n    if self.features:\n        features = ','.join(self.features)\n        return f'{requirement}[{features}]'\n\n    return requirement\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.construct_pip_install_command","title":"construct_pip_install_command(args: list[str])","text":"

      A convenience method for constructing a pip install command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.

      Source code in src/hatch/env/plugin/interface.py
      def construct_pip_install_command(self, args: list[str]):\n    \"\"\"\n    A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n    command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n    \"\"\"\n    command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n    # Default to -1 verbosity\n    add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n    command.extend(args)\n    return command\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.join_command_args","title":"join_command_args(args: list[str])","text":"

      This is used by the run command to construct the root command string from the received arguments.

      Source code in src/hatch/env/plugin/interface.py
      def join_command_args(self, args: list[str]):\n    \"\"\"\n    This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n    from the received arguments.\n    \"\"\"\n    return self.platform.join_command_args(args)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility","title":"check_compatibility()","text":"

      This raises an exception if the environment is not compatible with the user's setup. The default behavior checks for platform compatibility and any method override should keep this check.

      This check is never performed if the environment has been created.

      Source code in src/hatch/env/plugin/interface.py
      def check_compatibility(self):\n    \"\"\"\n    This raises an exception if the environment is not compatible with the user's setup. The default behavior\n    checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n    and any method override should keep this check.\n\n    This check is never performed if the environment has been\n    [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n    \"\"\"\n    if self.platforms and self.platform.name not in self.platforms:\n        message = 'unsupported platform'\n        raise OSError(message)\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_option_types","title":"get_option_types() -> dict staticmethod","text":"

      Returns a mapping of supported options to their respective types so that they can be used by overrides.

      Source code in src/hatch/env/plugin/interface.py
      @staticmethod\ndef get_option_types() -> dict:\n    \"\"\"\n    Returns a mapping of supported options to their respective types so that they can be used by\n    [overrides](../../config/environment/advanced.md#option-overrides).\n    \"\"\"\n    return {}\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_var_option","title":"get_env_var_option(option: str) -> str","text":"

      Returns the value of the upper-cased environment variable HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>.

      Source code in src/hatch/env/plugin/interface.py
      def get_env_var_option(self, option: str) -> str:\n    \"\"\"\n    Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n    \"\"\"\n    return os.environ.get(f'{AppEnvVars.ENV_OPTION_PREFIX}{self.PLUGIN_NAME}_{option}'.upper(), '')\n
      "},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_context","title":"get_context()","text":"

      Returns a subclass of EnvironmentContextFormatter.

      Source code in src/hatch/env/plugin/interface.py
      def get_context(self):\n    \"\"\"\n    Returns a subclass of\n    [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n    \"\"\"\n    from hatch.env.context import EnvironmentContextFormatter\n\n    return EnvironmentContextFormatter(self)\n
      "},{"location":"plugins/environment/virtual/","title":"Virtual environment","text":"

      This uses virtual environments backed by the standard virtualenv tool.

      "},{"location":"plugins/environment/virtual/#configuration","title":"Configuration","text":"

      The environment plugin name is virtual.

      pyproject.toml hatch.toml
      [tool.hatch.envs.<ENV_NAME>]\ntype = \"virtual\"\n
      [envs.<ENV_NAME>]\ntype = \"virtual\"\n
      "},{"location":"plugins/environment/virtual/#options","title":"Options","text":"Option Default Description python The version of Python to find on your system and subsequently use to create the environment, defaulting to the HATCH_PYTHON environment variable, followed by the normal resolution logic. Setting the HATCH_PYTHON environment variable to self will force the use of the Python executable Hatch is running on. For more information, see the documentation. python-sources ['external', 'internal'] This may be set to an array of strings that are either the literal internal or external. External considers only Python executables that are already on PATH. Internal considers only internally managed Python distributions. path An explicit path to the virtual environment. The path may be absolute or relative to the project root. Any environments that inherit this option will also use this path. The environment variable HATCH_ENV_TYPE_VIRTUAL_PATH may be used, which will take precedence. system-packages false Whether or not to give the virtual environment access to the system site-packages directory"},{"location":"plugins/environment/virtual/#location","title":"Location","text":"

      The location of environments is determined in the following heuristic order:

      1. The path option
      2. A directory named after the environment within the configured virtual environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs directory within the user's home directory
      3. Otherwise, environments are stored within the configured virtual environment directory in a deeply nested structure in order to support multiple projects

      Additionally, when the path option is not used, the name of the directory for the default environment will be the normalized project name to provide a more meaningful default shell prompt.

      "},{"location":"plugins/environment/virtual/#python-resolution","title":"Python resolution","text":"

      Virtual environments necessarily require a parent installation of Python. The following rules determine how the parent is resolved.

      The Python choice is determined by the python option followed by the HATCH_PYTHON environment variable. If the choice is via the environment variable, then resolution stops and that path is used unconditionally.

      The resolvers will be based on the python-sources option and all resolved interpreters will ensure compatibility with the project's defined Python support.

      If a Python version has been chosen then each resolver will try to find an interpreter that satisfies that version.

      If no version has been chosen, then each resolver will try to find a version that matches the version of Python that Hatch is currently running on. If not found then each resolver will try to find the highest compatible version.

      Note

      Some external Python paths are considered unstable and are ignored during resolution. For example, if Hatch is installed via Homebrew then sys.executable will be ignored because the interpreter could change or be removed at any time.

      Note

      When resolution finds a match using an internally managed distribution and an update is available, the latest distribution will automatically be downloaded before environment creation.

      "},{"location":"plugins/environment/virtual/#internal-distributions","title":"Internal distributions","text":"

      The following options are recognized for internal Python resolution.

      "},{"location":"plugins/environment/virtual/#cpython","title":"CPython","text":"ID 3.7 3.8 3.9 3.10 3.11 3.12

      The source of distributions is the python-build-standalone project.

      Some distributions have variants that may be configured with the HATCH_PYTHON_VARIANT_<PLATFORM> environment variable where <PLATFORM> is the uppercase version of one of the following:

      Platform Options Linux
      • v1
      • v2
      • v3 (default)
      • v4
      Windows
      • shared (default)
      • static
      "},{"location":"plugins/environment/virtual/#pypy","title":"PyPy","text":"ID pypy2.7 pypy3.9 pypy3.10

      The source of distributions is the PyPy project.

      "},{"location":"plugins/environment/virtual/#troubleshooting","title":"Troubleshooting","text":""},{"location":"plugins/environment/virtual/#macos-sip","title":"macOS SIP","text":"

      If you need to set linker environment variables like those starting with DYLD_ or LD_, any executable secured by System Integrity Protection that is invoked when running commands will not see those environment variable modifications as macOS strips those.

      Hatch interprets such commands as shell commands but deliberately ignores such paths to protected shells. This workaround suffices for the majority of use cases but there are 2 situations in which it may not:

      1. There are no unprotected sh, bash, zsh, nor fish executables found along PATH.
      2. The desired executable is a project's script, and the location of environments contains spaces or is longer than 1241 characters. In this case pip and other installers will create such an entry point with a shebang pointing to /bin/sh (which is protected) to avoid shebang limitations. Rather than changing the location, you could invoke the script as e.g. python -m pytest (if the project supports that method of invocation by shipping a __main__.py).
      1. The shebang length limit is usually 127 but 3 characters surround the executable path: #!<EXE_PATH>\\n \u21a9

      "},{"location":"plugins/environment-collector/custom/","title":"Custom environment collector","text":"

      This is a custom class in a given Python file that inherits from the EnvironmentCollectorInterface.

      "},{"location":"plugins/environment-collector/custom/#configuration","title":"Configuration","text":"

      The environment collector plugin name is custom.

      pyproject.toml hatch.toml
      [tool.hatch.env.collectors.custom]\n
      [env.collectors.custom]\n
      "},{"location":"plugins/environment-collector/custom/#options","title":"Options","text":"Option Default Description path hatch_plugins.py The path of the Python file"},{"location":"plugins/environment-collector/custom/#example","title":"Example","text":"hatch_plugins.py
          from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n    class CustomEnvironmentCollector(EnvironmentCollectorInterface):\n        ...\n

      If multiple subclasses are found, you must define a function named get_environment_collector that returns the desired environment collector.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      "},{"location":"plugins/environment-collector/default/","title":"Default environment collector","text":"

      This adds the default environment with type set to virtual and will always be applied.

      "},{"location":"plugins/environment-collector/default/#configuration","title":"Configuration","text":"

      The environment collector plugin name is default.

      pyproject.toml hatch.toml
      [tool.hatch.env.collectors.default]\n
      [env.collectors.default]\n
      "},{"location":"plugins/environment-collector/default/#options","title":"Options","text":"

      There are no options available currently.

      "},{"location":"plugins/environment-collector/reference/","title":"Environment collector plugins","text":"

      Environment collectors allow for dynamically modifying environments or adding environments beyond those defined in config. Users can override default values provided by each environment.

      "},{"location":"plugins/environment-collector/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-mkdocs - integrate MkDocs and infer dependencies into an env
      "},{"location":"plugins/environment-collector/reference/#installation","title":"Installation","text":"

      Any required environment collectors that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires array for automatic management:

      pyproject.toml hatch.toml
      [tool.hatch.env]\nrequires = [\n  \"...\",\n]\n
      [env]\nrequires = [\n  \"...\",\n]\n
      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface","title":"EnvironmentCollectorInterface","text":"

      Example usage:

      plugin.py hooks.py
          from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n    class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
          from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialEnvironmentCollector\n\n\n    @hookimpl\n    def hatch_register_environment_collector():\n        return SpecialEnvironmentCollector\n
      Source code in src/hatch/env/collectors/plugin/interface.py
      class EnvironmentCollectorInterface:\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n        class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialEnvironmentCollector\n\n\n        @hookimpl\n        def hatch_register_environment_collector():\n            return SpecialEnvironmentCollector\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root, config):\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.env.collectors.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    def get_initial_config(self) -> dict[str, dict]:  # noqa: PLR6301\n        \"\"\"\n        Returns configuration for environments keyed by the environment or matrix name.\n        \"\"\"\n        return {}\n\n    def finalize_config(self, config: dict[str, dict]):\n        \"\"\"\n        Finalizes configuration for environments keyed by the environment or matrix name. This will override\n        any user-defined settings and any collectors that ran before this call.\n\n        This is called before matrices are turned into concrete environments.\n        \"\"\"\n\n    def finalize_environments(self, config: dict[str, dict]):\n        \"\"\"\n        Finalizes configuration for environments keyed by the environment name. This will override\n        any user-defined settings and any collectors that ran before this call.\n\n        This is called after matrices are turned into concrete environments.\n        \"\"\"\n
      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.root","title":"root property","text":"

      The root of the project tree as a path-like object.

      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.env.collectors.<PLUGIN_NAME>]\n
      [env.collectors.<PLUGIN_NAME>]\n
      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.get_initial_config","title":"get_initial_config() -> dict[str, dict]","text":"

      Returns configuration for environments keyed by the environment or matrix name.

      Source code in src/hatch/env/collectors/plugin/interface.py
      def get_initial_config(self) -> dict[str, dict]:  # noqa: PLR6301\n    \"\"\"\n    Returns configuration for environments keyed by the environment or matrix name.\n    \"\"\"\n    return {}\n
      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_config","title":"finalize_config(config: dict[str, dict])","text":"

      Finalizes configuration for environments keyed by the environment or matrix name. This will override any user-defined settings and any collectors that ran before this call.

      This is called before matrices are turned into concrete environments.

      Source code in src/hatch/env/collectors/plugin/interface.py
      def finalize_config(self, config: dict[str, dict]):\n    \"\"\"\n    Finalizes configuration for environments keyed by the environment or matrix name. This will override\n    any user-defined settings and any collectors that ran before this call.\n\n    This is called before matrices are turned into concrete environments.\n    \"\"\"\n
      "},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_environments","title":"finalize_environments(config: dict[str, dict])","text":"

      Finalizes configuration for environments keyed by the environment name. This will override any user-defined settings and any collectors that ran before this call.

      This is called after matrices are turned into concrete environments.

      Source code in src/hatch/env/collectors/plugin/interface.py
      def finalize_environments(self, config: dict[str, dict]):\n    \"\"\"\n    Finalizes configuration for environments keyed by the environment name. This will override\n    any user-defined settings and any collectors that ran before this call.\n\n    This is called after matrices are turned into concrete environments.\n    \"\"\"\n
      "},{"location":"plugins/metadata-hook/custom/","title":"Custom metadata hook","text":"

      This is a custom class in a given Python file that inherits from the MetadataHookInterface.

      "},{"location":"plugins/metadata-hook/custom/#configuration","title":"Configuration","text":"

      The metadata hook plugin name is custom.

      pyproject.toml hatch.toml
      [tool.hatch.metadata.hooks.custom]\n
      [metadata.hooks.custom]\n
      "},{"location":"plugins/metadata-hook/custom/#options","title":"Options","text":"Option Default Description path hatch_build.py The path of the Python file"},{"location":"plugins/metadata-hook/custom/#example","title":"Example","text":"hatch_build.py
      from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass CustomMetadataHook(MetadataHookInterface):\n    ...\n

      If multiple subclasses are found, you must define a function named get_metadata_hook that returns the desired build hook.

      Note

      Any defined PLUGIN_NAME is ignored and will always be custom.

      "},{"location":"plugins/metadata-hook/reference/","title":"Metadata hook plugins","text":"

      Metadata hooks allow for the modification of project metadata after it has been loaded.

      "},{"location":"plugins/metadata-hook/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-docstring-description - set the project description using docstrings
      • hatch-fancy-pypi-readme - dynamically construct the README
      • hatch-nodejs-version - uses fields from NodeJS package.json files
      • hatch-odoo - determine dependencies based on manifests of Odoo add-ons
      • hatch-requirements-txt - read project dependencies from requirements.txt files
      • UniDep - for unified pip and conda dependency management using a single requirements.yaml file for both
      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface","title":"MetadataHookInterface","text":"

      Example usage:

      plugin.py hooks.py
      from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass SpecialMetadataHook(MetadataHookInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialMetadataHook\n\n\n@hookimpl\ndef hatch_register_metadata_hook():\n    return SpecialMetadataHook\n
      Source code in backend/src/hatchling/metadata/plugin/interface.py
      class MetadataHookInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\n    class SpecialMetadataHook(MetadataHookInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialMetadataHook\n\n\n    @hookimpl\n    def hatch_register_metadata_hook():\n        return SpecialMetadataHook\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        The hook configuration.\n\n        ```toml config-example\n        [tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def update(self, metadata: dict) -> None:\n        \"\"\"\n        This updates the metadata mapping of the `project` table in-place.\n        \"\"\"\n\n    def get_known_classifiers(self) -> list[str]:  # noqa: PLR6301\n        \"\"\"\n        This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n        \"\"\"\n        return []\n
      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.root","title":"root: str property","text":"

      The root of the project tree.

      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.config","title":"config: dict property","text":"

      The hook configuration.

      pyproject.toml hatch.toml
      [tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n
      [metadata.hooks.<PLUGIN_NAME>]\n
      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.update","title":"update(metadata: dict) -> None abstractmethod","text":"

      This updates the metadata mapping of the project table in-place.

      Source code in backend/src/hatchling/metadata/plugin/interface.py
      @abstractmethod\ndef update(self, metadata: dict) -> None:\n    \"\"\"\n    This updates the metadata mapping of the `project` table in-place.\n    \"\"\"\n
      "},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.get_known_classifiers","title":"get_known_classifiers() -> list[str]","text":"

      This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.

      Source code in backend/src/hatchling/metadata/plugin/interface.py
      def get_known_classifiers(self) -> list[str]:  # noqa: PLR6301\n    \"\"\"\n    This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n    \"\"\"\n    return []\n
      "},{"location":"plugins/publisher/package-index/","title":"Index publisher","text":"

      See the documentation for publishing.

      "},{"location":"plugins/publisher/package-index/#options","title":"Options","text":"Flag Config name Description -r/--repo repo The repository with which to publish artifacts -u/--user user The user with which to authenticate -a/--auth auth The credentials to use for authentication --ca-cert ca-cert The path to a CA bundle --client-cert client-cert The path to a client certificate, optionally containing the private key --client-key client-key The path to the client certificate's private key repos A table of named repositories to their respective options"},{"location":"plugins/publisher/package-index/#configuration","title":"Configuration","text":"

      The publisher plugin name is index.

      config.toml
      [publish.index]\n
      "},{"location":"plugins/publisher/package-index/#repositories","title":"Repositories","text":"

      All top-level options can be overridden per repository using the repos table with a required url attribute for each repository. The following shows the default configuration:

      config.toml
      [publish.index.repos.main]\nurl = \"https://upload.pypi.org/legacy/\"\n\n[publish.index.repos.test]\nurl = \"https://test.pypi.org/legacy/\"\n

      The repo and repos options have no effect.

      "},{"location":"plugins/publisher/package-index/#confirmation-prompt","title":"Confirmation prompt","text":"

      You can require a confirmation prompt or use of the -y/--yes flag by setting publishers' disable option to true in either Hatch's config file or project-specific configuration (which takes precedence):

      config.toml pyproject.toml hatch.toml
      [publish.index]\ndisable = true\n
      [tool.hatch.publish.index]\ndisable = true\n
      [publish.index]\ndisable = true\n
      "},{"location":"plugins/publisher/reference/","title":"Publisher plugins","text":""},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface","title":"PublisherInterface","text":"

      Example usage:

      plugin.py hooks.py
          from hatch.publish.plugin.interface import PublisherInterface\n\n\n    class SpecialPublisher(PublisherInterface):\n        PLUGIN_NAME = 'special'\n        ...\n
          from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialPublisher\n\n\n    @hookimpl\n    def hatch_register_publisher():\n        return SpecialPublisher\n
      Source code in src/hatch/publish/plugin/interface.py
      class PublisherInterface(ABC):\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n        from hatch.publish.plugin.interface import PublisherInterface\n\n\n        class SpecialPublisher(PublisherInterface):\n            PLUGIN_NAME = 'special'\n            ...\n    ```\n\n    ```python tab=\"hooks.py\"\n        from hatchling.plugin import hookimpl\n\n        from .plugin import SpecialPublisher\n\n\n        @hookimpl\n        def hatch_register_publisher():\n            return SpecialPublisher\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, app, root, cache_dir, project_config, plugin_config):\n        self.__app = app\n        self.__root = root\n        self.__cache_dir = cache_dir\n        self.__project_config = project_config\n        self.__plugin_config = plugin_config\n\n        self.__disable = None\n\n    @property\n    def app(self):\n        \"\"\"\n        An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n        \"\"\"\n        return self.__app\n\n    @property\n    def root(self):\n        \"\"\"\n        The root of the project tree as a path-like object.\n        \"\"\"\n        return self.__root\n\n    @property\n    def cache_dir(self):\n        \"\"\"\n        The directory reserved exclusively for this plugin as a path-like object.\n        \"\"\"\n        return self.__cache_dir\n\n    @property\n    def project_config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.publish.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__project_config\n\n    @property\n    def plugin_config(self) -> dict:\n        \"\"\"\n        This is defined in Hatch's [config file](../../config/hatch.md).\n\n        ```toml tab=\"config.toml\"\n        [publish.<PLUGIN_NAME>]\n        ```\n        \"\"\"\n        return self.__plugin_config\n\n    @property\n    def disable(self):\n        \"\"\"\n        Whether this plugin is disabled, thus requiring confirmation when publishing. Local\n        [project configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.project_config)\n        takes precedence over global\n        [plugin configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.plugin_config).\n        \"\"\"\n        if self.__disable is None:\n            if 'disable' in self.project_config:\n                disable = self.project_config['disable']\n                if not isinstance(disable, bool):\n                    message = f'Field `tool.hatch.publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n                    raise TypeError(message)\n            else:\n                disable = self.plugin_config.get('disable', False)\n                if not isinstance(disable, bool):\n                    message = f'Global plugin configuration `publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n                    raise TypeError(message)\n\n            self.__disable = disable\n\n        return self.__disable\n\n    @abstractmethod\n    def publish(self, artifacts: list[str], options: dict):\n        \"\"\"\n        :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n        This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n        with the arguments and options it receives.\n        \"\"\"\n
      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.app","title":"app property","text":"

      An instance of Application.

      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.root","title":"root property","text":"

      The root of the project tree as a path-like object.

      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.cache_dir","title":"cache_dir property","text":"

      The directory reserved exclusively for this plugin as a path-like object.

      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.project_config","title":"project_config: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.publish.<PLUGIN_NAME>]\n
      [publish.<PLUGIN_NAME>]\n
      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.plugin_config","title":"plugin_config: dict property","text":"

      This is defined in Hatch's config file.

      config.toml
      [publish.<PLUGIN_NAME>]\n
      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.disable","title":"disable property","text":"

      Whether this plugin is disabled, thus requiring confirmation when publishing. Local project configuration takes precedence over global plugin configuration.

      "},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.publish","title":"publish(artifacts: list[str], options: dict) abstractmethod","text":"

      REQUIRED

      This is called directly by the publish command with the arguments and options it receives.

      Source code in src/hatch/publish/plugin/interface.py
      @abstractmethod\ndef publish(self, artifacts: list[str], options: dict):\n    \"\"\"\n    :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n    This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n    with the arguments and options it receives.\n    \"\"\"\n
      "},{"location":"plugins/version-scheme/reference/","title":"Version scheme plugins","text":""},{"location":"plugins/version-scheme/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-semver - uses semantic versioning
      "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface","title":"VersionSchemeInterface","text":"

      Example usage:

      plugin.py hooks.py
      from hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\nclass SpecialVersionScheme(VersionSchemeInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionScheme\n\n\n@hookimpl\ndef hatch_register_version_scheme():\n    return SpecialVersionScheme\n
      Source code in backend/src/hatchling/version/scheme/plugin/interface.py
      class VersionSchemeInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\n    class SpecialVersionScheme(VersionSchemeInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialVersionScheme\n\n\n    @hookimpl\n    def hatch_register_version_scheme():\n        return SpecialVersionScheme\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree as a string.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.version]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n        \"\"\"\n        This should return a normalized form of the desired version and verify that it\n        is higher than the original version.\n        \"\"\"\n
      "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.root","title":"root: str property","text":"

      The root of the project tree as a string.

      "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.version]\n
      [version]\n
      "},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.update","title":"update(desired_version: str, original_version: str, version_data: dict) -> str abstractmethod","text":"

      This should return a normalized form of the desired version and verify that it is higher than the original version.

      Source code in backend/src/hatchling/version/scheme/plugin/interface.py
      @abstractmethod\ndef update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n    \"\"\"\n    This should return a normalized form of the desired version and verify that it\n    is higher than the original version.\n    \"\"\"\n
      "},{"location":"plugins/version-scheme/standard/","title":"Standard version scheme","text":"

      See the documentation for versioning.

      "},{"location":"plugins/version-scheme/standard/#configuration","title":"Configuration","text":"

      The version scheme plugin name is standard.

      pyproject.toml hatch.toml
      [tool.hatch.version]\nscheme = \"standard\"\n
      [version]\nscheme = \"standard\"\n
      "},{"location":"plugins/version-scheme/standard/#options","title":"Options","text":"Option Description validate-bump When setting a specific version, this determines whether to check that the new version is higher than the original. The default is true."},{"location":"plugins/version-source/code/","title":"Code version source","text":""},{"location":"plugins/version-source/code/#updates","title":"Updates","text":"

      Setting the version is not supported.

      "},{"location":"plugins/version-source/code/#configuration","title":"Configuration","text":"

      The version source plugin name is code.

      pyproject.toml hatch.toml
      [tool.hatch.version]\nsource = \"code\"\n
      [version]\nsource = \"code\"\n
      "},{"location":"plugins/version-source/code/#options","title":"Options","text":"Option Description path (required) A relative path to a Python file or extension module that will be loaded expression A Python expression that when evaluated in the context of the loaded file returns the version. The default expression is simply __version__. search-paths A list of relative paths to directories that will be prepended to Python's search path"},{"location":"plugins/version-source/code/#missing-imports","title":"Missing imports","text":"

      If the chosen path imports another module in your project, then you'll need to use absolute imports coupled with the search-paths option. For example, say you need to load the following file:

      src/pkg/__init__.py
          from ._version import get_version\n\n    __version__ = get_version()\n

      You should change it to:

      src/pkg/__init__.py
          from pkg._version import get_version\n\n    __version__ = get_version()\n

      and the configuration would become:

      pyproject.toml hatch.toml
      [tool.hatch.version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
      [version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
      "},{"location":"plugins/version-source/env/","title":"Environment version source","text":"

      Retrieves the version from an environment variable. This can be useful in build pipelines where the version is set by an external trigger.

      "},{"location":"plugins/version-source/env/#updates","title":"Updates","text":"

      Setting the version is not supported.

      "},{"location":"plugins/version-source/env/#configuration","title":"Configuration","text":"

      The version source plugin name is env.

      pyproject.toml hatch.toml
      [tool.hatch.version]\nsource = \"env\"\n
      [version]\nsource = \"env\"\n
      "},{"location":"plugins/version-source/env/#options","title":"Options","text":"Option Description variable (required) The name of the environment variable"},{"location":"plugins/version-source/reference/","title":"Version source plugins","text":""},{"location":"plugins/version-source/reference/#known-third-party","title":"Known third-party","text":"
      • hatch-vcs - uses your preferred version control system (like Git)
      • hatch-nodejs-version - uses the version field of NodeJS package.json files
      • hatch-regex-commit - automatically creates a Git commit and tag after version bumping
      • versioningit - determines version from Git or Mercurial tags, with customizable version formatting
      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface","title":"VersionSourceInterface","text":"

      Example usage:

      plugin.py hooks.py
      from hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\nclass SpecialVersionSource(VersionSourceInterface):\n    PLUGIN_NAME = 'special'\n    ...\n
      from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionSource\n\n\n@hookimpl\ndef hatch_register_version_source():\n    return SpecialVersionSource\n
      Source code in backend/src/hatchling/version/source/plugin/interface.py
      class VersionSourceInterface(ABC):  # no cov\n    \"\"\"\n    Example usage:\n\n    ```python tab=\"plugin.py\"\n    from hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\n    class SpecialVersionSource(VersionSourceInterface):\n        PLUGIN_NAME = 'special'\n        ...\n    ```\n\n    ```python tab=\"hooks.py\"\n    from hatchling.plugin import hookimpl\n\n    from .plugin import SpecialVersionSource\n\n\n    @hookimpl\n    def hatch_register_version_source():\n        return SpecialVersionSource\n    ```\n    \"\"\"\n\n    PLUGIN_NAME = ''\n    \"\"\"The name used for selection.\"\"\"\n\n    def __init__(self, root: str, config: dict) -> None:\n        self.__root = root\n        self.__config = config\n\n    @property\n    def root(self) -> str:\n        \"\"\"\n        The root of the project tree as a string.\n        \"\"\"\n        return self.__root\n\n    @property\n    def config(self) -> dict:\n        \"\"\"\n        ```toml config-example\n        [tool.hatch.version]\n        ```\n        \"\"\"\n        return self.__config\n\n    @abstractmethod\n    def get_version_data(self) -> dict:\n        \"\"\"\n        This should return a mapping with a `version` key representing the current version of the project and will be\n        displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n        The mapping can contain anything else and will be passed to\n        [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n        when updating the version.\n        \"\"\"\n\n    def set_version(self, version: str, version_data: dict) -> None:\n        \"\"\"\n        This should update the version to the first argument with the data provided during retrieval.\n        \"\"\"\n        raise NotImplementedError\n
      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.PLUGIN_NAME","title":"PLUGIN_NAME = '' class-attribute instance-attribute","text":"

      The name used for selection.

      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.root","title":"root: str property","text":"

      The root of the project tree as a string.

      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.config","title":"config: dict property","text":"pyproject.toml hatch.toml
      [tool.hatch.version]\n
      [version]\n
      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.get_version_data","title":"get_version_data() -> dict abstractmethod","text":"

      This should return a mapping with a version key representing the current version of the project and will be displayed when invoking the version command without any arguments.

      The mapping can contain anything else and will be passed to set_version when updating the version.

      Source code in backend/src/hatchling/version/source/plugin/interface.py
      @abstractmethod\ndef get_version_data(self) -> dict:\n    \"\"\"\n    This should return a mapping with a `version` key representing the current version of the project and will be\n    displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n    The mapping can contain anything else and will be passed to\n    [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n    when updating the version.\n    \"\"\"\n
      "},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version","title":"set_version(version: str, version_data: dict) -> None","text":"

      This should update the version to the first argument with the data provided during retrieval.

      Source code in backend/src/hatchling/version/source/plugin/interface.py
      def set_version(self, version: str, version_data: dict) -> None:\n    \"\"\"\n    This should update the version to the first argument with the data provided during retrieval.\n    \"\"\"\n    raise NotImplementedError\n
      "},{"location":"plugins/version-source/regex/","title":"Regex version source","text":"

      See the documentation for versioning.

      "},{"location":"plugins/version-source/regex/#updates","title":"Updates","text":"

      Setting the version is supported.

      "},{"location":"plugins/version-source/regex/#configuration","title":"Configuration","text":"

      The version source plugin name is regex.

      pyproject.toml hatch.toml
      [tool.hatch.version]\nsource = \"regex\"\n
      [version]\nsource = \"regex\"\n
      "},{"location":"plugins/version-source/regex/#options","title":"Options","text":"Option Description path (required) A relative path to a file containing the project's version pattern A regular expression that has a named group called version that represents the version. The default pattern looks for a variable named __version__ or VERSION that is set to a string containing the version, optionally prefixed with the lowercase letter v."},{"location":"tutorials/environment/basic-usage/","title":"Managing environments","text":"

      Hatch environments are isolated workspaces that can be used for project tasks including running tests, building documentation and running code formatters and linters.

      "},{"location":"tutorials/environment/basic-usage/#the-default-environment","title":"The default environment","text":"

      When you start using Hatch, you can create the default environment. To do this use the env create command:

      hatch env create\n

      This will not only create will the default environment for you to work in but will also install your project in dev mode in this default environment.

      Tip

      You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.

      "},{"location":"tutorials/environment/basic-usage/#using-the-default-environment","title":"Using the default environment","text":"

      Hatch will always use the default environment if an environment is not chosen explicitly when running a command.

      For instance, the following shows how to get version information for the Python in use.

      $ hatch run python -V\nPython 3.12.1\n
      "},{"location":"tutorials/environment/basic-usage/#configure-the-default-environment","title":"Configure the default environment","text":"

      You can customize the tools that are installed into the default environment by adding a table called tool.hatch.envs.default to your pyproject.toml file. Below is an example of adding the dependencies pydantic and numpy to the default environment.

      pyproject.toml hatch.toml
      [tool.hatch.envs.default]\ndependencies = [\n  \"pydantic\",\n  \"numpy\",\n]\n
      [envs.default]\ndependencies = [\n  \"pydantic\",\n  \"numpy\",\n]\n

      You can declare versions for your dependencies as well within this configuration.

      pyproject.toml hatch.toml
      [tool.hatch.envs.default]\ndependencies = [\n  \"pydantic>=2.0\",\n  \"numpy\",\n]\n
      [envs.default]\ndependencies = [\n  \"pydantic>=2.0\",\n  \"numpy\",\n]\n
      "},{"location":"tutorials/environment/basic-usage/#create-custom-environment","title":"Create custom environment","text":"

      You can create custom environments in Hatch by adding a section to your pyproject.toml file [tool.hatch.envs.<ENV_NAME>]. Below you define an environment called test and you add the pytest and pytest-cov dependencies to that environment's configuration.

      pyproject.toml hatch.toml
      [tool.hatch.envs.test]\ndependencies = [\n  \"pytest\",\n  \"pytest-cov\"\n]\n
      [envs.test]\ndependencies = [\n  \"pytest\",\n  \"pytest-cov\"\n]\n

      The first time that you call the test environment, Hatch will:

      1. Create the environment
      2. Install your project into that environment in dev mode (by default) along with its dependencies.
      3. Install the environment's dependencies
      "},{"location":"tutorials/environment/basic-usage/#run-commands-within-a-specific-environment","title":"Run commands within a specific environment","text":"

      Hatch offers a unique environment feature that allows you run a specific command within a specific environment rather than needing to activate the environment as you would using a tool such as Conda or venv.

      For instance, if you define an environment called test that contains the dependencies from the previous section, you can run the pytest command from the test environment using the syntax:

      hatch run <ENV_NAME>:command\n

      To access the test environment and run pytest, you can run:

      $ hatch run test:pytest\n============================== test session starts ===============================\nplatform darwin -- Python 3.12.1, pytest-7.4.4, pluggy-1.3.0\nrootdir: /your/path/to/yourproject\ncollected 0 items\n

      Note

      test:pytest represents the name of the environment to call (test) and the command to run (pytest).

      "},{"location":"tutorials/environment/basic-usage/#view-current-environments","title":"View current environments","text":"

      Above you defined and created a new test environment in your pyproject.toml file. You can now use the env show command to see both the currently created environments and the dependencies in each environment.

      $ hatch env show\n             Standalone\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Name    \u2503 Type    \u2503 Dependencies \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 default \u2502 virtual \u2502              \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 test    \u2502 virtual \u2502 pytest       \u2502\n\u2502         \u2502         \u2502 pytest-cov   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n

      Note

      The output may have more columns depending on your environment configuration.

      "},{"location":"tutorials/environment/basic-usage/#locating-environments","title":"Locating environments","text":"

      To see where your current environment is located you can use the env find command.

      $ hatch env find test\n/your/path/Application Support/hatch/env/virtual/yourproject/twO2iQR3/test\n

      Note

      That path is what you would see on macOS but differs for each platform, and is configurable.

      "},{"location":"tutorials/environment/basic-usage/#launching-a-shell-within-a-specific-environment","title":"Launching a shell within a specific environment","text":"

      If you wish to launch a shell for a specific environment that you have created, like the previous test environment, you can use:

      hatch -e test shell\n

      Once the environment is active, you can run commands like you would in any Python environment.

      Notice below that when running pip list in the test environment, you can see:

      1. That you package is installed in editable mode.
      2. That the environment contains both pytest and pytest-cov as specified above in the pyproject.toml file.
      $ pip list\nPackage     Version Editable project location\n----------- ------- ----------------------------------------------------\ncoverage    7.4.1\niniconfig   2.0.0\npackaging   23.2\npip         23.3.1\npluggy      1.4.0\npytest      8.0.0\npytest-cov  4.1.0\nyourproject 0.1.0  /your/path/to/yourproject\n
      "},{"location":"tutorials/environment/basic-usage/#conda-environments","title":"Conda environments","text":"

      If you prefer to use Conda environments with Hatch, you can check out the hatch-conda plugin.

      "},{"location":"blog/archive/2023/","title":"2023","text":""},{"location":"blog/archive/2022/","title":"2022","text":""},{"location":"blog/category/release/","title":"Release","text":""}]} \ No newline at end of file diff --git a/latest/sitemap.xml b/latest/sitemap.xml index ccc97a147..8b4ea4bf2 100644 --- a/latest/sitemap.xml +++ b/latest/sitemap.xml @@ -145,16 +145,41 @@ 2020-02-02 daily + + https://hatch.pypa.io/1.9/how-to/config/dynamic-metadata/ + 2020-02-02 + daily + https://hatch.pypa.io/1.9/how-to/environment/package-indices/ 2020-02-02 daily + + https://hatch.pypa.io/1.9/how-to/meta/report-issues/ + 2020-02-02 + daily + https://hatch.pypa.io/1.9/how-to/plugins/testing-builds/ 2020-02-02 daily + + https://hatch.pypa.io/1.9/how-to/publish/auth/ + 2020-02-02 + daily + + + https://hatch.pypa.io/1.9/how-to/publish/repo/ + 2020-02-02 + daily + + + https://hatch.pypa.io/1.9/how-to/static-analysis/behavior/ + 2020-02-02 + daily + https://hatch.pypa.io/1.9/meta/authors/ 2020-02-02 @@ -191,7 +216,7 @@ daily - https://hatch.pypa.io/1.9/plugins/builder/app/ + https://hatch.pypa.io/1.9/plugins/builder/binary/ 2020-02-02 daily @@ -290,6 +315,11 @@ 2020-02-02 daily + + https://hatch.pypa.io/1.9/tutorials/environment/basic-usage/ + 2020-02-02 + daily + https://hatch.pypa.io/1.9/blog/archive/2023/ 2020-02-02 diff --git a/latest/sitemap.xml.gz b/latest/sitemap.xml.gz index b6f8e3c049fa5f3443ddd9654e7c4ccfe57e5d38..4abbd34024141182b14b56f1e853dc48f9025167 100644 GIT binary patch delta 741 zcmVIw1{g9?t>yxq~iU{d*@bXjL8Q7yxwl=^$NWXjrHyG`sa`D)#Li*@UYL(C8QNM z_UU#_P-Gkf;mIVOQ_!s^0MrH<`~ZnrQ>R#Z$z$Lj%?gd$l-ob*K-> zzmbmFx<(=l{n^IgJM<)xXMG}YP9}|FkO=emPE{i8lSEygkIp6|kv7LMiL{FuM20mN zTCpzv_dB(%Re$|>ZBd=KUu((QFKWx+?T7ZU0PUZ?eG;kF&MG*DOj2LQNG{t-S+6$+McvDYCi(4{k_SvVU}0nL=|0ULu=9xPdE)v&D-< zuCa+i9OTaXJD?MqZkTYXD0~F^!9&NhN^-24#miyZgMNh;E9)DpWk#)8J$5W-%6*7b z*_5(qZ0~YweNwy-jM;KEB~qfn^Og)`G6gWlaUhua_X>MN17{neMDjGR#*aP7EJY^Y z3Eo6*WPi@nT^!CjsUcr0ZcUp|OMw!g7lY^|Lzh{95kp`J<|E2bO8-_mIER``*aE`B=k5kikR6o= zFJfrlHVH~ecJ94Jbn#p%a%5g?ao~Fy5(lg(#&p1)?_gjMpbz3PA3}A~g`U<2N}G X9YXpKANll_kPg2AnLcQym@EJQ8xm`1 delta 673 zcmV;S0$%;|1+N8=8h_$25CG77zXEYj99U`9t|-0r3wA$Xu!q=N$4>1Dl)v9e2;Cs{ zvX|930ud4`JURAcCSmvT(fQR0Q+6>tuQzqGUSZJDxX?bYfBk%|9@j7Xhux5TMp|*> zke}CX4_QFmS5at-nM9_Erb@23E%eyoWJbUV$0Q`J|X`` zIt*Al^s!gMs$A4>!>a_XZNY;K+8wPJawT}g8|Mu;ZNUiox!66PL6_@aciE}0t35;Dg z1Vj^7@pe~!N_Tc zU|)v>1_%Tb`xJkpri!c9-UFfJS0C8k=|zIa;ICjH z8Ijx0`zPVy=3Szi7H|UEWx}+1C-Lgm5$zXsTxZN3tzhp9%1lQ z9=wR5eY@LIN~Uw~EuxF(2cR687ZoFZltC_{hvyu!n*L9MMVd1~Fpx|Uq@ HfG7X}tb9`c diff --git a/latest/tutorials/environment/basic-usage/index.html b/latest/tutorials/environment/basic-usage/index.html new file mode 100644 index 000000000..29707a5e5 --- /dev/null +++ b/latest/tutorials/environment/basic-usage/index.html @@ -0,0 +1,73 @@ + Managing environments - Hatch

      Managing environments


      Hatch environments are isolated workspaces that can be used for project tasks including running tests, building documentation and running code formatters and linters.

      The default environment

      When you start using Hatch, you can create the default environment. To do this use the env create command:

      hatch env create
      +

      This will not only create will the default environment for you to work in but will also install your project in dev mode in this default environment.

      Tip

      You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.

      Using the default environment

      Hatch will always use the default environment if an environment is not chosen explicitly when running a command.

      For instance, the following shows how to get version information for the Python in use.

      $ hatch run python -V
      +Python 3.12.1
      +

      Configure the default environment

      You can customize the tools that are installed into the default environment by adding a table called tool.hatch.envs.default to your pyproject.toml file. Below is an example of adding the dependencies pydantic and numpy to the default environment.

      [tool.hatch.envs.default]
      +dependencies = [
      +  "pydantic",
      +  "numpy",
      +]
      +
      [envs.default]
      +dependencies = [
      +  "pydantic",
      +  "numpy",
      +]
      +

      You can declare versions for your dependencies as well within this configuration.

      [tool.hatch.envs.default]
      +dependencies = [
      +  "pydantic>=2.0",
      +  "numpy",
      +]
      +
      [envs.default]
      +dependencies = [
      +  "pydantic>=2.0",
      +  "numpy",
      +]
      +

      Create custom environment

      You can create custom environments in Hatch by adding a section to your pyproject.toml file [tool.hatch.envs.<ENV_NAME>]. Below you define an environment called test and you add the pytest and pytest-cov dependencies to that environment's configuration.

      [tool.hatch.envs.test]
      +dependencies = [
      +  "pytest",
      +  "pytest-cov"
      +]
      +
      [envs.test]
      +dependencies = [
      +  "pytest",
      +  "pytest-cov"
      +]
      +

      The first time that you call the test environment, Hatch will:

      1. Create the environment
      2. Install your project into that environment in dev mode (by default) along with its dependencies.
      3. Install the environment's dependencies

      Run commands within a specific environment

      Hatch offers a unique environment feature that allows you run a specific command within a specific environment rather than needing to activate the environment as you would using a tool such as Conda or venv.

      For instance, if you define an environment called test that contains the dependencies from the previous section, you can run the pytest command from the test environment using the syntax:

      hatch run <ENV_NAME>:command
      +

      To access the test environment and run pytest, you can run:

      $ hatch run test:pytest
      +============================== test session starts ===============================
      +platform darwin -- Python 3.12.1, pytest-7.4.4, pluggy-1.3.0
      +rootdir: /your/path/to/yourproject
      +collected 0 items
      +

      Note

      test:pytest represents the name of the environment to call (test) and the command to run (pytest).

      View current environments

      Above you defined and created a new test environment in your pyproject.toml file. You can now use the env show command to see both the currently created environments and the dependencies in each environment.

      $ hatch env show
      +             Standalone
      +┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┓
      +┃ Name    ┃ Type    ┃ Dependencies ┃
      +┡━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━┩
      +│ default │ virtual │              │
      +├─────────┼─────────┼──────────────┤
      +│ test    │ virtual │ pytest       │
      +│         │         │ pytest-cov   │
      +└─────────┴─────────┴──────────────┘
      +

      Note

      The output may have more columns depending on your environment configuration.

      Locating environments

      To see where your current environment is located you can use the env find command.

      $ hatch env find test
      +/your/path/Application Support/hatch/env/virtual/yourproject/twO2iQR3/test
      +

      Note

      That path is what you would see on macOS but differs for each platform, and is configurable.

      Launching a shell within a specific environment

      If you wish to launch a shell for a specific environment that you have created, like the previous test environment, you can use:

      hatch -e test shell
      +

      Once the environment is active, you can run commands like you would in any Python environment.

      Notice below that when running pip list in the test environment, you can see:

      1. That you package is installed in editable mode.
      2. That the environment contains both pytest and pytest-cov as specified above in the pyproject.toml file.
      $ pip list
      +Package     Version Editable project location
      +----------- ------- ----------------------------------------------------
      +coverage    7.4.1
      +iniconfig   2.0.0
      +packaging   23.2
      +pip         23.3.1
      +pluggy      1.4.0
      +pytest      8.0.0
      +pytest-cov  4.1.0
      +yourproject 0.1.0  /your/path/to/yourproject
      +

      Conda environments

      If you prefer to use Conda environments with Hatch, you can check out the hatch-conda plugin.

      \ No newline at end of file diff --git a/latest/version/index.html b/latest/version/index.html index 77554020b..e53d28844 100644 --- a/latest/version/index.html +++ b/latest/version/index.html @@ -7,7 +7,7 @@ .gdesc-inner { font-size: 0.75rem; } body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);} body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);} - body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Versioning


      Configuration

      When the version is not statically set, configuration is defined in the tool.hatch.version table. The source option determines the source to use for retrieving and updating the version. The regex source is used by default.

      The regex source requires an option path that represents a relative path to a file containing the project's version:

      [tool.hatch.version]
      +    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Versioning


      Configuration

      When the version is not statically set, configuration is defined in the tool.hatch.version table. The source option determines the source to use for retrieving and updating the version. The regex source is used by default.

      The regex source requires an option path that represents a relative path to a file containing the project's version:

      [tool.hatch.version]
       path = "src/hatch_demo/__about__.py"
       
      [version]
       path = "src/hatch_demo/__about__.py"
      diff --git a/latest/why/index.html b/latest/why/index.html
      index d819a4425..c405e8232 100644
      --- a/latest/why/index.html
      +++ b/latest/why/index.html
      @@ -7,4 +7,4 @@
           .gdesc-inner { font-size: 0.75rem; }
           body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color);}
           body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color);}
      -    body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}      

      Why Hatch?


      The high level value proposition of Hatch is that if one adopts all functionality then many other tools become unnecessary since there is support for everything one might require. Further, if one chooses to use only specific features then there are still benefits compared to alternatives.

      Build backend

      Hatchling, the build backend sister project, has many benefits compared to setuptools. Here we only compare setuptools as that is the one most people are familiar with.

      • Better defaults: The default behavior for setuptools is often not desirable for the average user.
        • For source distributions, setuptools has a custom enumeration of files that get included and excluded by default. Hatchling takes the defaults from your version control system such as Git's .gitignore file.
        • For wheels, setuptools attempts to find every directory that looks like a Python package. This is often undesirable as you might ship files to the end-user unintentionally such as test or tooling directories. Hatchling defaults to very specific inclusion based on the project name and errors if no heuristic is satisfied.
      • Ease of configurability: Hatchling was designed based on a history of significant challenges when configuring setuptools.
        • Hatchling uses the same glob pattern syntax as Git itself for every option which is what most users are familiar with. On the other hand, setuptools uses shell-style glob patterns for source distributions while wheels use a mix of shell-style globs and Python package syntax.
        • Configuring what gets included in source distributions requires a separate MANIFEST.in file. The custom syntax and directives must be learned and it is difficult knowing which options in the main files like setup.py influence the behavior and under what conditions. For Hatchling, everything gets configured in a single file under dedicated sections for specific targets like [tool.hatch.build.targets.wheel].
        • By default, non-Python files are excluded from wheels. Including such files requires usually verbose rules for every nested package directory. Hatchling makes no such distinction between file types and acts more like a general build system one might already be familiar with.
      • Editable installations: The default behavior of Hatchling allows for proper static analysis by external tools such as IDEs. With setuptools, you must provide additional configuration which means that by default, for example, you would not get autocompletion in Visual Studio Code. This is marked as a legacy feature and may in fact be removed in future versions of setuptools.
      • Reproducibility: Hatchling builds reproducible wheels and source distributions by default. setuptools does not support this for source distributions and there is no guarantee that wheels are reproducible.
      • Extensibility: Although it is possible to extend setuptools, the API is quite low level. Hatchling has the concept of plugins that are separated into discrete types and only expose what is necessary, leading to an easier developer experience.

      Why not?:

      If building extension modules is required then it is recommended that you continue using setuptools, or even other backends that specialize in interfacing with compilers.

      Environment management

      Here we compare to both tox and nox. At a high level, there are a few common advantages:

      • Python management: Hatch is able to automatically download Python distributions on the fly when specific versions that environments request cannot be found. The alternatives will raise an error, with the option to ignore unknown distributions.
      • Philosophy: In the alternatives, environments are for the most part treated as executable units where a dependency set is associated with an action. If you are familiar with container ecosystems, this would be like defining a CMD at the end of a Dockerfile but without the ability to change the action at runtime. This involves significant wasted disk space usually because one often requires slight modifications to the actions and therefore will define entirely different environments inherited from a base config just to perform different logic. Additionally, this can be confusing to users not just configuration-wise but also for execution of the different environments.

        In Hatch, environments are treated as isolated areas where you can execute arbitrary commands at runtime. For example, you can define a single test environment with named scripts that runs unit vs non-unit tests, each command being potentially very long but named however you wish so you get to control the interface. Since environments are treated as places where work is performed, you can also spawn a shell into any which will execute a subprocess that automatically drops into your shell of choice. Your shell will be configured appropriately like python on PATH being updated and the prompt being changed to reflect the chosen environment.

      • Configuration:

        • tox only supports INI configuration and if one desires putting that in the standard pyproject.toml file then it must be a multi-line string containing the INI config which would preclude syntax highlighting. Hatch allows for TOML-based config just like most other tools in the Python ecosystem.
        • nox config is defined in Python which often leads to increased verbosity and makes it challenging to onboard folks compared to a standardized format with known behaviors.
      • Extensibility:
        • tox allows for extending most aspects of its functionality however the API is so low-level and attached to internals that creating plugins may be challenging. For example, here is a tox plugin that was migrated to an equivalent Hatch environment collector plugin.
        • nox is configured with Python so for the local project you can do whatever you want, however there is no concept of third-party plugins per se. To achieve that, you must usually use a package that wraps nox and use that package's imports instead (example).

      Why not?:

      If you are using nox and you wish to migrate, and for some reason you notify sessions, then migration wouldn't be a straight translation but rather you might have to redesign that conditional step.

      Python management

      Here we compare Python management to that of pyenv.

      • Cross-platform: Hatch allows for the same experience no matter the system whereas pyenv does not support Windows so you must use an entirely different project that tries to emulate the functionality.
      • No build dependencies: Hatch guarantees that every available distribution is prebuilt whereas the alternative requires one to maintain a precise build environment which differs by platform and potentially Python version. Another benefit to this is extremely fast installations since the distributions are simply downloaded and unpacked.
      • Optimized by default: The CPython distributions are built with profile guided optimization and link-time optimization, resulting in a 10-30% performance improvement depending on the workload. These distributions have seen wide adoption throughout the industry and are even used by the build system Bazel.
      • Simplicity: Hatch treats Python installations as just another directory that one would add to PATH. It can do this for you or you can manage PATH yourself, even allowing for custom install locations. On the other hand, pyenv operates by adding shims which then act as wrappers around the actual underlying binaries. This has many unfortunate side effects:
        • It is incumbent upon the user to manage which specific Python comes first via the CLI, switch when necessary, and/or have a mental model of which versions are exposed globally and locally per-project. This can become confusing quite quickly. When working with Hatch, your global Python installations are only important insofar as they are on PATH somewhere since environments do not use them directly but rather create virtual environments from them, always using a version that is compatible with your project.
        • Configuration is required for each shell to properly set up pyenv on start, leading to inconsistencies when running processes that do not spawn a shell.
        • Debugging issues with Python search paths can be extremely difficult, especially for users of software. If you or users have ever ran into an issue where code was being executed that you did not anticipate, the issue is almost always pyenv influencing the python on PATH.

      Why not?:

      Currently, Hatch does not allow for the installation of specific patch release versions but rather only uses minor release granularity that tracks the latest patch release. If specific patch releases are important to you then it is best to use an alternative installation mechanism.

      \ No newline at end of file + body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color);}

      Why Hatch?


      The high level value proposition of Hatch is that if one adopts all functionality then many other tools become unnecessary since there is support for everything one might require. Further, if one chooses to use only specific features then there are still benefits compared to alternatives.

      Build backend

      Hatchling, the build backend sister project, has many benefits compared to setuptools. Here we only compare setuptools as that is the one most people are familiar with.

      • Better defaults: The default behavior for setuptools is often not desirable for the average user.
        • For source distributions, setuptools has a custom enumeration of files that get included and excluded by default. Hatchling takes the defaults from your version control system such as Git's .gitignore file.
        • For wheels, setuptools attempts to find every directory that looks like a Python package. This is often undesirable as you might ship files to the end-user unintentionally such as test or tooling directories. Hatchling defaults to very specific inclusion based on the project name and errors if no heuristic is satisfied.
      • Ease of configurability: Hatchling was designed based on a history of significant challenges when configuring setuptools.
        • Hatchling uses the same glob pattern syntax as Git itself for every option which is what most users are familiar with. On the other hand, setuptools uses shell-style glob patterns for source distributions while wheels use a mix of shell-style globs and Python package syntax.
        • Configuring what gets included in source distributions requires a separate MANIFEST.in file. The custom syntax and directives must be learned and it is difficult knowing which options in the main files like setup.py influence the behavior and under what conditions. For Hatchling, everything gets configured in a single file under dedicated sections for specific targets like [tool.hatch.build.targets.wheel].
        • By default, non-Python files are excluded from wheels. Including such files requires usually verbose rules for every nested package directory. Hatchling makes no such distinction between file types and acts more like a general build system one might already be familiar with.
      • Editable installations: The default behavior of Hatchling allows for proper static analysis by external tools such as IDEs. With setuptools, you must provide additional configuration which means that by default, for example, you would not get autocompletion in Visual Studio Code. This is marked as a legacy feature and may in fact be removed in future versions of setuptools.
      • Reproducibility: Hatchling builds reproducible wheels and source distributions by default. setuptools does not support this for source distributions and there is no guarantee that wheels are reproducible.
      • Extensibility: Although it is possible to extend setuptools, the API is quite low level. Hatchling has the concept of plugins that are separated into discrete types and only expose what is necessary, leading to an easier developer experience.

      Why not?:

      If building extension modules is required then it is recommended that you continue using setuptools, or even other backends that specialize in interfacing with compilers.

      Environment management

      Here we compare to both tox and nox. At a high level, there are a few common advantages:

      • Python management: Hatch is able to automatically download Python distributions on the fly when specific versions that environments request cannot be found. The alternatives will raise an error, with the option to ignore unknown distributions.
      • Philosophy: In the alternatives, environments are for the most part treated as executable units where a dependency set is associated with an action. If you are familiar with container ecosystems, this would be like defining a CMD at the end of a Dockerfile but without the ability to change the action at runtime. This involves significant wasted disk space usually because one often requires slight modifications to the actions and therefore will define entirely different environments inherited from a base config just to perform different logic. Additionally, this can be confusing to users not just configuration-wise but also for execution of the different environments.

        In Hatch, environments are treated as isolated areas where you can execute arbitrary commands at runtime. For example, you can define a single test environment with named scripts that runs unit vs non-unit tests, each command being potentially very long but named however you wish so you get to control the interface. Since environments are treated as places where work is performed, you can also spawn a shell into any which will execute a subprocess that automatically drops into your shell of choice. Your shell will be configured appropriately like python on PATH being updated and the prompt being changed to reflect the chosen environment.

      • Configuration:

        • tox only supports INI configuration and if one desires putting that in the standard pyproject.toml file then it must be a multi-line string containing the INI config which would preclude syntax highlighting. Hatch allows for TOML-based config just like most other tools in the Python ecosystem.
        • nox config is defined in Python which often leads to increased verbosity and makes it challenging to onboard folks compared to a standardized format with known behaviors.
      • Extensibility:
        • tox allows for extending most aspects of its functionality however the API is so low-level and attached to internals that creating plugins may be challenging. For example, here is a tox plugin that was migrated to an equivalent Hatch environment collector plugin.
        • nox is configured with Python so for the local project you can do whatever you want, however there is no concept of third-party plugins per se. To achieve that, you must usually use a package that wraps nox and use that package's imports instead (example).

      Why not?:

      If you are using nox and you wish to migrate, and for some reason you notify sessions, then migration wouldn't be a straight translation but rather you might have to redesign that conditional step.

      Python management

      Here we compare Python management to that of pyenv.

      • Cross-platform: Hatch allows for the same experience no matter the system whereas pyenv does not support Windows so you must use an entirely different project that tries to emulate the functionality.
      • No build dependencies: Hatch guarantees that every available distribution is prebuilt whereas the alternative requires one to maintain a precise build environment which differs by platform and potentially Python version. Another benefit to this is extremely fast installations since the distributions are simply downloaded and unpacked.
      • Optimized by default: The CPython distributions are built with profile guided optimization and link-time optimization, resulting in a 10-30% performance improvement depending on the workload. These distributions have seen wide adoption throughout the industry and are even used by the build system Bazel.
      • Simplicity: Hatch treats Python installations as just another directory that one would add to PATH. It can do this for you or you can manage PATH yourself, even allowing for custom install locations. On the other hand, pyenv operates by adding shims which then act as wrappers around the actual underlying binaries. This has many unfortunate side effects:
        • It is incumbent upon the user to manage which specific Python comes first via the CLI, switch when necessary, and/or have a mental model of which versions are exposed globally and locally per-project. This can become confusing quite quickly. When working with Hatch, your global Python installations are only important insofar as they are on PATH somewhere since environments do not use them directly but rather create virtual environments from them, always using a version that is compatible with your project.
        • Configuration is required for each shell to properly set up pyenv on start, leading to inconsistencies when running processes that do not spawn a shell.
        • Debugging issues with Python search paths can be extremely difficult, especially for users of software. If you or users have ever ran into an issue where code was being executed that you did not anticipate, the issue is almost always pyenv influencing the python on PATH.

      Why not?:

      Currently, Hatch does not allow for the installation of specific patch release versions but rather only uses minor release granularity that tracks the latest patch release. If specific patch releases are important to you then it is best to use an alternative installation mechanism.

      \ No newline at end of file