diff --git a/.gitattributes b/.gitattributes
index f3bffe3c0..6107f6104 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -3,3 +3,7 @@
*.png binary
*.pptx binary
*.odp binary
+
+# Instruct linguist not to ignore the PEPs
+# https://github.com/github-linguist/linguist/blob/master/docs/overrides.md
+peps/*.rst text linguist-detectable
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index b0f34bb0a..dbc89d23b 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -12,681 +12,689 @@ requirements.txt @AA-Turner
infra/ @ewdurbin
pep_sphinx_extensions/ @AA-Turner
-AUTHOR_OVERRIDES.csv @AA-Turner
build.py @AA-Turner
-conf.py @AA-Turner
-contents.rst @AA-Turner
+peps/conf.py @AA-Turner
+peps/contents.rst @AA-Turner
# Linting infrastructure
.codespell/ @CAM-Gerlach @hugovk
.codespellrc @CAM-Gerlach @hugovk
.pre-commit-config.yaml @CAM-Gerlach @hugovk
+.ruff.toml @AA-Turner @CAM-Gerlach @hugovk
+check-peps.py @AA-Turner @CAM-Gerlach @hugovk
# Git infrastructure
.gitattributes @CAM-Gerlach
.gitignore @CAM-Gerlach
-pep-0001.txt @warsaw @ncoghlan
-pep-0001-process_flow.png @warsaw @ncoghlan
-pep-0001/ @warsaw @ncoghlan
-# pep-0002.txt
-pep-0003.txt @jeremyhylton
-pep-0004.txt @brettcannon
-# pep-0005.txt
-# pep-0006.txt
-pep-0007.txt @gvanrossum @warsaw
-pep-0008.txt @gvanrossum @warsaw @ncoghlan
-pep-0009.txt @warsaw
-pep-0010.txt @warsaw
-pep-0011.txt @brettcannon
-pep-0012.rst @brettcannon @warsaw
-pep-0012/ @brettcannon
-# pep-0013.rst is owned by the entire core team.
+peps/pep-0001.rst @warsaw @ncoghlan
+peps/pep-0001-process_flow.png @warsaw @ncoghlan
+peps/pep-0001/ @warsaw @ncoghlan
+# peps/pep-0002.rst
+peps/pep-0003.rst @jeremyhylton
+peps/pep-0004.rst @brettcannon
+# peps/pep-0005.rst
+# peps/pep-0006.rst
+peps/pep-0007.rst @gvanrossum @warsaw
+peps/pep-0008.rst @gvanrossum @warsaw @ncoghlan
+peps/pep-0009.rst @warsaw
+peps/pep-0010.rst @warsaw
+peps/pep-0011.rst @brettcannon
+peps/pep-0012.rst @brettcannon @warsaw
+peps/pep-0012/ @brettcannon
+# peps/pep-0013.rst is owned by the entire core team.
# ...
-pep-0020.txt @tim-one
+peps/pep-0020.rst @tim-one
# ...
-pep-0042.txt @jeremyhylton
+peps/pep-0042.rst @jeremyhylton
# ...
-pep-0100.txt @malemburg
-pep-0101.txt @Yhg1s @pablogsal @ambv @ned-deily
-pep-0102.txt @warsaw @gvanrossum
-# pep-0103.txt
+peps/pep-0100.rst @malemburg
+peps/pep-0101.rst @Yhg1s @pablogsal @ambv @ned-deily
+peps/pep-0102.rst @warsaw @gvanrossum
+# peps/pep-0103.rst
# ...
-pep-0160.txt @freddrake
+peps/pep-0160.rst @freddrake
# ...
-pep-0200.txt @jeremyhylton
-pep-0201.txt @warsaw
-pep-0202.txt @warsaw
-pep-0203.txt @Yhg1s
-pep-0204.txt @Yhg1s
-pep-0205.txt @freddrake
-# pep-0206.txt
-pep-0207.txt @gvanrossum
-pep-0208.txt @nascheme @malemburg
-# pep-0209.txt
-# pep-0210.txt
-# pep-0211.txt
-# pep-0212.txt
-# pep-0213.txt
-pep-0214.txt @warsaw
-# pep-0215.txt
-# pep-0216.txt
-# pep-0217.txt
-pep-0218.txt @rhettinger
-# pep-0219.txt
-# pep-0220.txt
-pep-0221.txt @Yhg1s
-# pep-0222.txt
-pep-0223.txt @tim-one
-pep-0224.txt @malemburg
-# pep-0225.txt
-pep-0226.txt @jeremyhylton
-pep-0227.txt @jeremyhylton
-pep-0228.txt @gvanrossum
-# pep-0229.txt
-pep-0230.txt @gvanrossum
-pep-0231.txt @warsaw
-pep-0232.txt @warsaw
-# pep-0233.txt
-pep-0234.txt @gvanrossum
-pep-0235.txt @tim-one
-pep-0236.txt @tim-one
-pep-0237.txt @gvanrossum
-pep-0238.txt @gvanrossum
-# pep-0239.txt
-# pep-0240.txt
-# pep-0241.txt
-# pep-0242.txt
-# pep-0243.txt
-# pep-0244.txt
-# pep-0245.txt
-pep-0246.txt @aleaxit
-# pep-0247.txt
-pep-0248.txt @malemburg
-pep-0249.txt @malemburg
-pep-0250.txt @pfmoore
-pep-0251.txt @warsaw @gvanrossum
-pep-0252.txt @gvanrossum
-pep-0253.txt @gvanrossum
-pep-0254.txt @gvanrossum
-pep-0255.txt @nascheme @tim-one
-# pep-0256.txt
-pep-0257.txt @gvanrossum
-# pep-0258.txt
-pep-0259.txt @gvanrossum
-pep-0260.txt @gvanrossum
-# pep-0261.txt
-# pep-0262.txt
-pep-0263.txt @malemburg
-# pep-0264.txt
-# pep-0265.txt
-# pep-0266.txt
-pep-0267.txt @jeremyhylton
-# pep-0268.txt
-# pep-0269.txt
-# pep-0270.txt
-# pep-0271.txt
-# pep-0272.txt
-# pep-0273.txt
-pep-0274.txt @warsaw
-pep-0275.txt @malemburg
-# pep-0276.txt
-# pep-0277.txt
-pep-0278.txt @jackjansen
-pep-0279.txt @rhettinger
-pep-0280.txt @gvanrossum
-# pep-0281.txt
-pep-0282.txt @vsajip
-pep-0283.txt @gvanrossum
-# pep-0284.txt
-pep-0285.txt @gvanrossum
-# pep-0286.txt
-# pep-0287.txt
-pep-0288.txt @rhettinger
-pep-0289.txt @rhettinger
-pep-0290.txt @rhettinger
-# pep-0291.txt
-pep-0292.txt @warsaw
-pep-0293.txt @doerwalter
-# pep-0294.txt
-# pep-0295.txt
-# pep-0296.txt
-pep-0297.txt @malemburg
-pep-0298.txt @theller
-# pep-0299.txt
-# pep-0301.txt
-pep-0302.txt @pfmoore
-# pep-0303.txt
-# pep-0304.txt
-# pep-0305.txt
-pep-0306.txt @jackdied @ncoghlan @benjaminp
-pep-0307.txt @gvanrossum @tim-one
-pep-0308.txt @gvanrossum @rhettinger
-# pep-0309.txt
-pep-0310.txt @pfmoore
-pep-0311.txt @mhammond
-pep-0312.txt @aleaxit
-# pep-0313.txt
-# pep-0314.txt
-pep-0315.txt @rhettinger
-# pep-0316.txt
-# pep-0317.txt
-# pep-0318.txt
-# pep-0319.txt
-pep-0320.txt @warsaw @rhettinger
-# pep-0321.txt
-pep-0322.txt @rhettinger
-pep-0323.txt @aleaxit
-# pep-0324.txt
-# pep-0325.txt
-pep-0326.txt @terryjreedy
-pep-0327.txt @facundobatista
-# pep-0328.txt
-pep-0329.txt @rhettinger
-# pep-0330.txt
-# pep-0331.txt
-# pep-0332.txt
-# pep-0333.txt
-# pep-0334.txt
-# pep-0335.txt
-# pep-0336.txt
-# pep-0337.txt
-pep-0338.txt @ncoghlan
-pep-0339.txt @brettcannon
-pep-0340.txt @gvanrossum
-pep-0341.txt @birkenfeld
-pep-0342.txt @gvanrossum
-pep-0343.txt @gvanrossum @ncoghlan
-# pep-0344.txt
-# pep-0345.txt
-pep-0346.txt @ncoghlan
-# pep-0347.txt
-pep-0348.txt @brettcannon
-pep-0349.txt @nascheme
-# pep-0350.txt
-pep-0351.txt @warsaw
-pep-0352.txt @brettcannon @gvanrossum
-# pep-0353.txt
-# pep-0354.txt
-# pep-0355.txt
-pep-0356.txt @gvanrossum
-# pep-0357.txt
-pep-0358.txt @nascheme @gvanrossum
-# pep-0359.txt
-pep-0360.txt @brettcannon
-pep-0361.txt @warsaw
-pep-0362.txt @brettcannon @1st1 @larryhastings
-# pep-0363.txt
-pep-0364.txt @warsaw
-# pep-0365.txt
-pep-0366.txt @ncoghlan
-# pep-0367.txt
-# pep-0368.txt
-pep-0369.txt @tiran
-pep-0370.txt @tiran
-# pep-0371.txt
-pep-0372.txt @mitsuhiko @rhettinger
-pep-0373.txt @benjaminp
-pep-0374.txt @brettcannon @avassalotti @warsaw
-pep-0375.txt @benjaminp
-# pep-0376.txt
-pep-0377.txt @ncoghlan
-pep-0378.txt @rhettinger
-# pep-0379.txt
-# pep-0380.txt
-# pep-0381.txt
-# pep-0382.txt
-# pep-0383.txt
-# pep-0384.txt
-pep-0385.txt @pitrou @birkenfeld
-# pep-0386.txt
-pep-0387.txt @benjaminp @vstinner
-# pep-0389.txt
-# pep-0390.txt
-pep-0391.txt @vsajip
-pep-0392.txt @birkenfeld
-# pep-0393.txt
-pep-0394.txt @ncoghlan @warsaw @encukou @willingc
-pep-0395.txt @ncoghlan
-pep-0396.txt @warsaw
-pep-0397.txt @mhammond
-pep-0398.txt @birkenfeld
-pep-0399.txt @brettcannon
-pep-0400.txt @vstinner
-pep-0401.txt @warsaw @brettcannon
-# pep-0402.txt
-pep-0403.txt @ncoghlan
-pep-0404.txt @warsaw
-# pep-0405.txt
-pep-0406.txt @ncoghlan
-pep-0407.txt @pitrou @birkenfeld @warsaw
-pep-0408.txt @ncoghlan @eliben
-pep-0409.txt @ethanfurman
-pep-0410.txt @vstinner
-pep-0411.txt @ncoghlan @eliben
-pep-0412.txt @markshannon
-pep-0413.txt @ncoghlan
-pep-0414.txt @mitsuhiko @ncoghlan
-pep-0415.txt @benjaminp
-pep-0416.txt @vstinner
-pep-0417.txt @voidspace
-pep-0418.txt @vstinner
-pep-0418/ @vstinner
-# pep-0419.txt
-pep-0420.txt @ericvsmith
-pep-0421.txt @ericsnowcurrently
-pep-0422.txt @ncoghlan
-# pep-0423.txt
-pep-0424.txt @alex
-# pep-0425.txt
-pep-0426.txt @ncoghlan @dstufft
-pep-0426/ @ncoghlan @dstufft
-# pep-0427.txt
-pep-0428.txt @pitrou
-pep-0429.txt @larryhastings
-pep-0430.txt @ncoghlan
-# pep-0431.txt
-pep-0432.txt @ncoghlan @vstinner @ericsnowcurrently
-pep-0433.txt @vstinner
-pep-0433/ @vstinner
-pep-0434.txt @terryjreedy
-pep-0435.txt @warsaw @eliben @ethanfurman
-pep-0436.txt @larryhastings
-# pep-0437.txt
-# pep-0438.txt
-# pep-0439.txt
-pep-0440.txt @ncoghlan @dstufft
-pep-0441.txt @pfmoore
-pep-0442.txt @pitrou
-pep-0443.txt @ambv
-pep-0444.txt @mitsuhiko
-pep-0445.txt @vstinner
-pep-0446.txt @vstinner
-pep-0446/ @vstinner
-pep-0447.txt @ronaldoussoren
-# pep-0448.txt
-pep-0449.txt @dstufft
-# pep-0450.txt @stevendaprano
-pep-0451.txt @ericsnowcurrently
-pep-0452.txt @tiran
-pep-0453.txt @dstufft @ncoghlan
-pep-0454.txt @vstinner
-pep-0455.txt @pitrou
-pep-0456.txt @tiran
-pep-0457.txt @larryhastings
-# pep-0458.txt, pep-0458-1.png
-pep-0459.txt @ncoghlan
-pep-0460.txt @pitrou
-pep-0461.txt @ethanfurman
-pep-0462.txt @ncoghlan
-# pep-0463.txt
-pep-0464.txt @dstufft
-pep-0465.txt @njsmith
-pep-0465/ @njsmith
-pep-0466.txt @ncoghlan
-pep-0467.txt @ncoghlan @ethanfurman
-pep-0468.txt @ericsnowcurrently
-pep-0469.txt @ncoghlan
-pep-0470.txt @dstufft
-# pep-0471.txt
-# pep-0472.txt
-# pep-0473.txt
-pep-0474.txt @ncoghlan
-pep-0475.txt @vstinner
-pep-0476.txt @alex
-pep-0477.txt @dstufft @ncoghlan
-pep-0478.txt @larryhastings
-pep-0479.txt @gvanrossum
-# pep-0480.txt, pep-0480-1.png
-pep-0481.txt @dstufft
-pep-0482.txt @ambv
-pep-0483.txt @gvanrossum @ilevkivskyi
-pep-0484.txt @gvanrossum @ambv
-# pep-0485.txt
-pep-0486.txt @pfmoore
-# pep-0487.txt
-pep-0488.txt @brettcannon
-pep-0489.txt @encukou @scoder @ncoghlan
-pep-0490.txt @vstinner
-# pep-0491.txt
-pep-0492.txt @1st1
-pep-0493.txt @ncoghlan @malemburg
-pep-0494.txt @ned-deily
-pep-0495.txt @abalkin @tim-one
-pep-0495-gap.png @abalkin @tim-one
-pep-0495-gap.svg @abalkin @tim-one
-pep-0495-fold.svg @abalkin @tim-one
-pep-0495-fold-2.png @abalkin @tim-one
-pep-0495-daylightsavings.png @abalkin @tim-one
-# pep-0496.txt
-# pep-0497.txt
-pep-0498.txt @ericvsmith
-# pep-0499.txt
-pep-0500.txt @abalkin @tim-one
-pep-0501.txt @ncoghlan
-# pep-0502.txt
-pep-0503.txt @dstufft
-pep-0504.txt @ncoghlan
-pep-0505.rst @zooba
-pep-0505/ @zooba
-# pep-0506.txt @stevendaprano
-pep-0507.txt @warsaw
-pep-0508.txt @rbtcollins
-pep-0509.txt @vstinner
-pep-0510.txt @vstinner
-pep-0511.txt @vstinner
-pep-0512.txt @brettcannon
-pep-0513.txt @njsmith
-pep-0514.txt @zooba
-pep-0515.txt @birkenfeld @serhiy-storchaka
-pep-0516.txt @rbtcollins @njsmith
-pep-0517.txt @njsmith
-pep-0518.txt @brettcannon @njsmith @dstufft
-pep-0519.txt @brettcannon
-pep-0520.txt @ericsnowcurrently
-pep-0521.txt @njsmith
-pep-0522.txt @ncoghlan @njsmith
-pep-0523.txt @brettcannon @DinoV
-pep-0524.txt @vstinner
-pep-0525.txt @1st1
-pep-0525-1.png @1st1
-pep-0526.txt @ilevkivskyi @lisroach @gvanrossum
-pep-0527.txt @dstufft
-pep-0528.txt @zooba
-pep-0529.txt @zooba
-pep-0530.txt @1st1
-pep-0531.txt @ncoghlan
-pep-0532.txt @ncoghlan
-pep-0532/ @ncoghlan
-pep-0533.txt @njsmith
-pep-0534.txt @encukou @ncoghlan
-pep-0535.txt @ncoghlan
-# pep-0536.txt
-pep-0537.txt @ned-deily
-pep-0538.txt @ncoghlan
-# pep-0539.txt
-pep-0540.txt @vstinner
-pep-0541.txt @ambv
-# pep-0542.txt
-pep-0543.rst @tiran
-pep-0544.txt @ilevkivskyi @ambv
-pep-0545.txt @JulienPalard @methane @vstinner
-pep-0546.txt @vstinner
-pep-0547.rst @encukou
-pep-0548.rst @bitdancer
-pep-0549.rst @larryhastings
-pep-0550.rst @1st1
-pep-0550-lookup_hamt.png @1st1
-pep-0550-hamt_vs_dict.png @1st1
-pep-0550-hamt_vs_dict-v2.png @1st1
-pep-0551.rst @zooba
-pep-0552.rst @benjaminp
-pep-0553.rst @warsaw
-pep-0554.rst @ericsnowcurrently
-# pep-0555.rst
-pep-0556.rst @pitrou
-pep-0557.rst @ericvsmith
-pep-0558.rst @ncoghlan
-pep-0559.rst @warsaw
-pep-0560.rst @ilevkivskyi
-# pep-0561.rst
-pep-0562.rst @ilevkivskyi
-pep-0563.rst @ambv
-pep-0564.rst @vstinner
-pep-0565.rst @ncoghlan
-# pep-0566.rst
-pep-0567.rst @1st1
-pep-0568.rst @njsmith
-pep-0569.rst @ambv
-pep-0570.rst @larryhastings @pablogsal
-# pep-0571.rst
-pep-0572.rst @tim-one @gvanrossum
-pep-0573.rst @encukou @ncoghlan @ericsnowcurrently
-pep-0574.rst @pitrou
-# pep-0575.rst
-pep-0576.rst @markshannon
-pep-0577.rst @ncoghlan
-pep-0578.rst @zooba
-# pep-0579.rst
-# pep-0580.rst
-pep-0581.rst @Mariatta
-pep-0582.rst @kushaldas @zooba @dstufft @ncoghlan
-# pep-0583.rst
-pep-0584.rst @brandtbucher # @stevendaprano
-pep-0585.rst @ambv
-pep-0586.rst @ilevkivskyi
-pep-0587.rst @vstinner @ncoghlan
-pep-0588.rst @Mariatta
-pep-0589.rst @gvanrossum
-pep-0590.rst @markshannon
-pep-0591.rst @ilevkivskyi
-pep-0592.rst @dstufft
-pep-0593.rst @ilevkivskyi
-pep-0594.rst @tiran @brettcannon
-pep-0595.rst @ezio-melotti @berkerpeksag
-pep-0596.rst @ambv
-pep-0597.rst @methane
-pep-0598.rst @ncoghlan
-pep-0599.rst @pfmoore
-pep-0600.rst @njsmith
-pep-0601.txt @isidentical
-pep-0602.rst @ambv
-pep-0602-example-release-calendar.png @ambv
-pep-0602-example-release-calendar.pptx @ambv
-pep-0602-overlapping-support-matrix.png @ambv
-pep-0602-overlapping-support-matrix.pptx @ambv
-pep-0603.rst @1st1
-pep-0603-lookup_hamt.png @1st1
-pep-0603-hamt_vs_dict.png @1st1
-# pep-0604.rst
-pep-0605.rst @zooba @ncoghlan
-pep-0605-example-release-calendar.png @zooba @ncoghlan
-pep-0605-overlapping-support-matrix.png @zooba @ncoghlan
-pep-0605/ @zooba @ncoghlan
-pep-0606.rst @vstinner
-pep-0607.rst @ambv @zooba @ncoghlan
-pep-0608.rst @vstinner
-pep-0609.rst @pganssle
-pep-0610.rst @cjerdonek
-pep-0611.rst @markshannon
-pep-0612.rst @gvanrossum
-pep-0613.rst @gvanrossum
-pep-0614.rst @brandtbucher
-pep-0615.rst @pganssle
-pep-0616.rst @ericvsmith
-pep-0617.rst @gvanrossum @pablogsal @lysnikolaou
-pep-0618.rst @brandtbucher
-pep-0619.rst @pablogsal
-pep-0620.rst @vstinner
-pep-0621.rst @brettcannon @pganssle
-pep-0622.rst @brandtbucher @ilevkivskyi @gvanrossum
-pep-0623.rst @methane
-pep-0624.rst @methane
-pep-0625.rst @pfmoore
-pep-0626.rst @markshannon
-pep-0627.rst @encukou
-pep-0628.txt @ncoghlan
-pep-0629.rst @dstufft
-pep-0630.rst @encukou
-pep-0631.rst @pganssle
-pep-0632.rst @zooba
-pep-0633.rst @brettcannon
-pep-0634.rst @brandtbucher @gvanrossum
-pep-0635.rst @brandtbucher @gvanrossum
-pep-0636.rst @brandtbucher @gvanrossum
-# pep-0637.rst @stevendaprano
-pep-0638.rst @markshannon
-pep-0639.rst @CAM-Gerlach
-pep-0640.rst @Yhg1s
-pep-0641.rst @zooba @warsaw @brettcannon
-pep-0642.rst @ncoghlan
-pep-0643.rst @pfmoore
-pep-0644.rst @tiran
-pep-0645.rst @gvanrossum
-pep-0646.rst @gvanrossum
-pep-0647.rst @gvanrossum
-pep-0648.rst @pablogsal
-pep-0649.rst @larryhastings
-pep-0650.rst @brettcannon
-pep-0651.rst @markshannon
-pep-0652.rst @encukou
-pep-0653.rst @markshannon
-pep-0654.rst @1st1 @gvanrossum @iritkatriel
-pep-0655.rst @gvanrossum
-pep-0656.rst @brettcannon
-pep-0657.rst @pablogsal @isidentical @ammaraskar
-pep-0658.rst @brettcannon
-pep-0659.rst @markshannon
-pep-0660.rst @pfmoore
-pep-0661.rst @taleinat
-pep-0662.rst @brettcannon
-pep-0662/ @brettcannon
-pep-0663.txt @ethanfurman
-pep-0664.rst @pablogsal
-pep-0665.rst @brettcannon
-# pep-0666.txt
-pep-0667.rst @markshannon
-pep-0668.rst @dstufft
-pep-0669.rst @markshannon
-pep-0670.rst @vstinner @erlend-aasland
-pep-0671.rst @rosuav
-pep-0672.rst @encukou
-pep-0673.rst @jellezijlstra
-pep-0674.rst @vstinner
-pep-0675.rst @jellezijlstra
-pep-0676.rst @AA-Turner @Mariatta
-pep-0677.rst @gvanrossum
-pep-0678.rst @iritkatriel
-pep-0679.rst @pablogsal
-pep-0680.rst @encukou
-pep-0681.rst @jellezijlstra
-pep-0682.rst @mdickinson
-pep-0683.rst @ericsnowcurrently
-pep-0684.rst @ericsnowcurrently
-# pep-0684.rst
-pep-0685.rst @brettcannon
-pep-0686.rst @methane
-pep-0687.rst @encukou @erlend-aasland
-pep-0688.rst @jellezijlstra
-pep-0689.rst @encukou
-pep-0690.rst @warsaw
-pep-0691.rst @dstufft
-pep-0692.rst @jellezijlstra
-pep-0693.rst @Yhg1s
-pep-0694.rst @dstufft
-pep-0695.rst @gvanrossum
-pep-0696.rst @jellezijlstra
-pep-0697.rst @encukou
-pep-0698.rst @jellezijlstra
-pep-0699.rst @Fidget-Spinner
-pep-0700.rst @pfmoore
-pep-0701.rst @pablogsal @isidentical @lysnikolaou
-pep-0702.rst @jellezijlstra
-pep-0703.rst @ambv
-pep-0704.rst @brettcannon @pradyunsg
-pep-0705.rst @pablogsal
-pep-0706.rst @encukou
-pep-0707.rst @iritkatriel
-pep-0708.rst @dstufft
-pep-0709.rst @carljm
-pep-0710.rst @dstufft
-pep-0711.rst @njsmith
-pep-0712.rst @ericvsmith
-pep-0713.rst @ambv
-pep-0714.rst @dstufft
-pep-0715.rst @dstufft
-pep-0717.rst @dstufft
-pep-0718.rst @gvanrossum
-pep-0719.rst @Yhg1s
-pep-0720.rst @FFY00
-pep-0721.rst @encukou
-pep-0722.rst @pfmoore
-pep-0723.rst @AA-Turner
-pep-0725.rst @pradyunsg
+peps/pep-0200.rst @jeremyhylton
+peps/pep-0201.rst @warsaw
+peps/pep-0202.rst @warsaw
+peps/pep-0203.rst @Yhg1s
+peps/pep-0204.rst @Yhg1s
+peps/pep-0205.rst @freddrake
+# peps/pep-0206.rst
+peps/pep-0207.rst @gvanrossum
+peps/pep-0208.rst @nascheme @malemburg
+# peps/pep-0209.rst
+# peps/pep-0210.rst
+# peps/pep-0211.rst
+# peps/pep-0212.rst
+# peps/pep-0213.rst
+peps/pep-0214.rst @warsaw
+# peps/pep-0215.rst
+# peps/pep-0216.rst
+# peps/pep-0217.rst
+peps/pep-0218.rst @rhettinger
+# peps/pep-0219.rst
+# peps/pep-0220.rst
+peps/pep-0221.rst @Yhg1s
+# peps/pep-0222.rst
+peps/pep-0223.rst @tim-one
+peps/pep-0224.rst @malemburg
+# peps/pep-0225.rst
+peps/pep-0226.rst @jeremyhylton
+peps/pep-0227.rst @jeremyhylton
+peps/pep-0228.rst @gvanrossum
+# peps/pep-0229.rst
+peps/pep-0230.rst @gvanrossum
+peps/pep-0231.rst @warsaw
+peps/pep-0232.rst @warsaw
+# peps/pep-0233.rst
+peps/pep-0234.rst @gvanrossum
+peps/pep-0235.rst @tim-one
+peps/pep-0236.rst @tim-one
+peps/pep-0237.rst @gvanrossum
+peps/pep-0238.rst @gvanrossum
+# peps/pep-0239.rst
+# peps/pep-0240.rst
+# peps/pep-0241.rst
+# peps/pep-0242.rst
+# peps/pep-0243.rst
+# peps/pep-0244.rst
+# peps/pep-0245.rst
+peps/pep-0246.rst @aleaxit
+# peps/pep-0247.rst
+peps/pep-0248.rst @malemburg
+peps/pep-0249.rst @malemburg
+peps/pep-0250.rst @pfmoore
+peps/pep-0251.rst @warsaw @gvanrossum
+peps/pep-0252.rst @gvanrossum
+peps/pep-0253.rst @gvanrossum
+peps/pep-0254.rst @gvanrossum
+peps/pep-0255.rst @nascheme @tim-one
+# peps/pep-0256.rst
+peps/pep-0257.rst @gvanrossum
+# peps/pep-0258.rst
+peps/pep-0259.rst @gvanrossum
+peps/pep-0260.rst @gvanrossum
+# peps/pep-0261.rst
+# peps/pep-0262.rst
+peps/pep-0263.rst @malemburg
+# peps/pep-0264.rst
+# peps/pep-0265.rst
+# peps/pep-0266.rst
+peps/pep-0267.rst @jeremyhylton
+# peps/pep-0268.rst
+# peps/pep-0269.rst
+# peps/pep-0270.rst
+# peps/pep-0271.rst
+# peps/pep-0272.rst
+# peps/pep-0273.rst
+peps/pep-0274.rst @warsaw
+peps/pep-0275.rst @malemburg
+# peps/pep-0276.rst
+# peps/pep-0277.rst
+peps/pep-0278.rst @jackjansen
+peps/pep-0279.rst @rhettinger
+peps/pep-0280.rst @gvanrossum
+# peps/pep-0281.rst
+peps/pep-0282.rst @vsajip
+peps/pep-0283.rst @gvanrossum
+# peps/pep-0284.rst
+peps/pep-0285.rst @gvanrossum
+# peps/pep-0286.rst
+# peps/pep-0287.rst
+peps/pep-0288.rst @rhettinger
+peps/pep-0289.rst @rhettinger
+peps/pep-0290.rst @rhettinger
+# peps/pep-0291.rst
+peps/pep-0292.rst @warsaw
+peps/pep-0293.rst @doerwalter
+# peps/pep-0294.rst
+# peps/pep-0295.rst
+# peps/pep-0296.rst
+peps/pep-0297.rst @malemburg
+peps/pep-0298.rst @theller
+# peps/pep-0299.rst
+# peps/pep-0301.rst
+peps/pep-0302.rst @pfmoore
+# peps/pep-0303.rst
+# peps/pep-0304.rst
+# peps/pep-0305.rst
+peps/pep-0306.rst @jackdied @ncoghlan @benjaminp
+peps/pep-0307.rst @gvanrossum @tim-one
+peps/pep-0308.rst @gvanrossum @rhettinger
+# peps/pep-0309.rst
+peps/pep-0310.rst @pfmoore
+peps/pep-0311.rst @mhammond
+peps/pep-0312.rst @aleaxit
+# peps/pep-0313.rst
+# peps/pep-0314.rst
+peps/pep-0315.rst @rhettinger
+# peps/pep-0316.rst
+# peps/pep-0317.rst
+# peps/pep-0318.rst
+# peps/pep-0319.rst
+peps/pep-0320.rst @warsaw @rhettinger
+# peps/pep-0321.rst
+peps/pep-0322.rst @rhettinger
+peps/pep-0323.rst @aleaxit
+# peps/pep-0324.rst
+# peps/pep-0325.rst
+peps/pep-0326.rst @terryjreedy
+peps/pep-0327.rst @facundobatista
+# peps/pep-0328.rst
+peps/pep-0329.rst @rhettinger
+# peps/pep-0330.rst
+# peps/pep-0331.rst
+# peps/pep-0332.rst
+# peps/pep-0333.rst
+# peps/pep-0334.rst
+# peps/pep-0335.rst
+# peps/pep-0336.rst
+# peps/pep-0337.rst
+peps/pep-0338.rst @ncoghlan
+peps/pep-0339.rst @brettcannon
+peps/pep-0340.rst @gvanrossum
+peps/pep-0341.rst @birkenfeld
+peps/pep-0342.rst @gvanrossum
+peps/pep-0343.rst @gvanrossum @ncoghlan
+# peps/pep-0344.rst
+# peps/pep-0345.rst
+peps/pep-0346.rst @ncoghlan
+# peps/pep-0347.rst
+peps/pep-0348.rst @brettcannon
+peps/pep-0349.rst @nascheme
+# peps/pep-0350.rst
+peps/pep-0351.rst @warsaw
+peps/pep-0352.rst @brettcannon @gvanrossum
+# peps/pep-0353.rst
+# peps/pep-0354.rst
+# peps/pep-0355.rst
+peps/pep-0356.rst @gvanrossum
+# peps/pep-0357.rst
+peps/pep-0358.rst @nascheme @gvanrossum
+# peps/pep-0359.rst
+peps/pep-0360.rst @brettcannon
+peps/pep-0361.rst @warsaw
+peps/pep-0362.rst @brettcannon @1st1 @larryhastings
+# peps/pep-0363.rst
+peps/pep-0364.rst @warsaw
+# peps/pep-0365.rst
+peps/pep-0366.rst @ncoghlan
+# peps/pep-0367.rst
+# peps/pep-0368.rst
+peps/pep-0369.rst @tiran
+peps/pep-0370.rst @tiran
+# peps/pep-0371.rst
+peps/pep-0372.rst @mitsuhiko @rhettinger
+peps/pep-0373.rst @benjaminp
+peps/pep-0374.rst @brettcannon @avassalotti @warsaw
+peps/pep-0375.rst @benjaminp
+# peps/pep-0376.rst
+peps/pep-0377.rst @ncoghlan
+peps/pep-0378.rst @rhettinger
+# peps/pep-0379.rst
+# peps/pep-0380.rst
+# peps/pep-0381.rst
+# peps/pep-0382.rst
+# peps/pep-0383.rst
+# peps/pep-0384.rst
+peps/pep-0385.rst @pitrou @birkenfeld
+# peps/pep-0386.rst
+peps/pep-0387.rst @benjaminp @vstinner
+# peps/pep-0389.rst
+# peps/pep-0390.rst
+peps/pep-0391.rst @vsajip
+peps/pep-0392.rst @birkenfeld
+# peps/pep-0393.rst
+peps/pep-0394.rst @ncoghlan @warsaw @encukou @willingc
+peps/pep-0395.rst @ncoghlan
+peps/pep-0396.rst @warsaw
+peps/pep-0397.rst @mhammond
+peps/pep-0398.rst @birkenfeld
+peps/pep-0399.rst @brettcannon
+peps/pep-0400.rst @vstinner
+peps/pep-0401.rst @warsaw @brettcannon
+# peps/pep-0402.rst
+peps/pep-0403.rst @ncoghlan
+peps/pep-0404.rst @warsaw
+# peps/pep-0405.rst
+peps/pep-0406.rst @ncoghlan
+peps/pep-0407.rst @pitrou @birkenfeld @warsaw
+peps/pep-0408.rst @ncoghlan @eliben
+peps/pep-0409.rst @ethanfurman
+peps/pep-0410.rst @vstinner
+peps/pep-0411.rst @ncoghlan @eliben
+peps/pep-0412.rst @markshannon
+peps/pep-0413.rst @ncoghlan
+peps/pep-0414.rst @mitsuhiko @ncoghlan
+peps/pep-0415.rst @benjaminp
+peps/pep-0416.rst @vstinner
+peps/pep-0417.rst @voidspace
+peps/pep-0418.rst @vstinner
+peps/pep-0418/ @vstinner
+# peps/pep-0419.rst
+peps/pep-0420.rst @ericvsmith
+peps/pep-0421.rst @ericsnowcurrently
+peps/pep-0422.rst @ncoghlan
+# peps/pep-0423.rst
+peps/pep-0424.rst @alex
+# peps/pep-0425.rst
+peps/pep-0426.rst @ncoghlan @dstufft
+peps/pep-0426/ @ncoghlan @dstufft
+# peps/pep-0427.rst
+peps/pep-0428.rst @pitrou
+peps/pep-0429.rst @larryhastings
+peps/pep-0430.rst @ncoghlan
+# peps/pep-0431.rst
+peps/pep-0432.rst @ncoghlan @vstinner @ericsnowcurrently
+peps/pep-0433.rst @vstinner
+peps/pep-0433/ @vstinner
+peps/pep-0434.rst @terryjreedy
+peps/pep-0435.rst @warsaw @eliben @ethanfurman
+peps/pep-0436.rst @larryhastings
+# peps/pep-0437.rst
+# peps/pep-0438.rst
+# peps/pep-0439.rst
+peps/pep-0440.rst @ncoghlan @dstufft
+peps/pep-0441.rst @pfmoore
+peps/pep-0442.rst @pitrou
+peps/pep-0443.rst @ambv
+peps/pep-0444.rst @mitsuhiko
+peps/pep-0445.rst @vstinner
+peps/pep-0446.rst @vstinner
+peps/pep-0446/ @vstinner
+peps/pep-0447.rst @ronaldoussoren
+# peps/pep-0448.rst
+peps/pep-0449.rst @dstufft
+# peps/pep-0450.rst @stevendaprano
+peps/pep-0451.rst @ericsnowcurrently
+peps/pep-0452.rst @tiran
+peps/pep-0453.rst @dstufft @ncoghlan
+peps/pep-0454.rst @vstinner
+peps/pep-0455.rst @pitrou
+peps/pep-0456.rst @tiran
+peps/pep-0457.rst @larryhastings
+# peps/pep-0458.rst, peps/pep-0458-1.png
+peps/pep-0459.rst @ncoghlan
+peps/pep-0460.rst @pitrou
+peps/pep-0461.rst @ethanfurman
+peps/pep-0462.rst @ncoghlan
+# peps/pep-0463.rst
+peps/pep-0464.rst @dstufft
+peps/pep-0465.rst @njsmith
+peps/pep-0465/ @njsmith
+peps/pep-0466.rst @ncoghlan
+peps/pep-0467.rst @ncoghlan @ethanfurman
+peps/pep-0468.rst @ericsnowcurrently
+peps/pep-0469.rst @ncoghlan
+peps/pep-0470.rst @dstufft
+# peps/pep-0471.rst
+# peps/pep-0472.rst
+# peps/pep-0473.rst
+peps/pep-0474.rst @ncoghlan
+peps/pep-0475.rst @vstinner
+peps/pep-0476.rst @alex
+peps/pep-0477.rst @dstufft @ncoghlan
+peps/pep-0478.rst @larryhastings
+peps/pep-0479.rst @gvanrossum
+# peps/pep-0480.rst, peps/pep-0480-1.png
+peps/pep-0481.rst @dstufft
+peps/pep-0482.rst @ambv
+peps/pep-0483.rst @gvanrossum @ilevkivskyi
+peps/pep-0484.rst @gvanrossum @ambv
+# peps/pep-0485.rst
+peps/pep-0486.rst @pfmoore
+# peps/pep-0487.rst
+peps/pep-0488.rst @brettcannon
+peps/pep-0489.rst @encukou @scoder @ncoghlan
+peps/pep-0490.rst @vstinner
+# peps/pep-0491.rst
+peps/pep-0492.rst @1st1
+peps/pep-0493.rst @ncoghlan @malemburg
+peps/pep-0494.rst @ned-deily
+peps/pep-0495.rst @abalkin @tim-one
+peps/pep-0495-gap.png @abalkin @tim-one
+peps/pep-0495-gap.svg @abalkin @tim-one
+peps/pep-0495-fold.svg @abalkin @tim-one
+peps/pep-0495-fold-2.png @abalkin @tim-one
+peps/pep-0495-daylightsavings.png @abalkin @tim-one
+# peps/pep-0496.rst
+# peps/pep-0497.rst
+peps/pep-0498.rst @ericvsmith
+# peps/pep-0499.rst
+peps/pep-0500.rst @abalkin @tim-one
+peps/pep-0501.rst @ncoghlan
+# peps/pep-0502.rst
+peps/pep-0503.rst @dstufft
+peps/pep-0504.rst @ncoghlan
+peps/pep-0505.rst @zooba
+peps/pep-0505/ @zooba
+# peps/pep-0506.rst @stevendaprano
+peps/pep-0507.rst @warsaw
+peps/pep-0508.rst @rbtcollins
+peps/pep-0509.rst @vstinner
+peps/pep-0510.rst @vstinner
+peps/pep-0511.rst @vstinner
+peps/pep-0512.rst @brettcannon
+peps/pep-0513.rst @njsmith
+peps/pep-0514.rst @zooba
+peps/pep-0515.rst @birkenfeld @serhiy-storchaka
+peps/pep-0516.rst @rbtcollins @njsmith
+peps/pep-0517.rst @njsmith
+peps/pep-0518.rst @brettcannon @njsmith @dstufft
+peps/pep-0519.rst @brettcannon
+peps/pep-0520.rst @ericsnowcurrently
+peps/pep-0521.rst @njsmith
+peps/pep-0522.rst @ncoghlan @njsmith
+peps/pep-0523.rst @brettcannon @DinoV
+peps/pep-0524.rst @vstinner
+peps/pep-0525.rst @1st1
+peps/pep-0525-1.png @1st1
+peps/pep-0526.rst @ilevkivskyi @lisroach @gvanrossum
+peps/pep-0527.rst @dstufft
+peps/pep-0528.rst @zooba
+peps/pep-0529.rst @zooba
+peps/pep-0530.rst @1st1
+peps/pep-0531.rst @ncoghlan
+peps/pep-0532.rst @ncoghlan
+peps/pep-0532/ @ncoghlan
+peps/pep-0533.rst @njsmith
+peps/pep-0534.rst @encukou @ncoghlan
+peps/pep-0535.rst @ncoghlan
+# peps/pep-0536.rst
+peps/pep-0537.rst @ned-deily
+peps/pep-0538.rst @ncoghlan
+# peps/pep-0539.rst
+peps/pep-0540.rst @vstinner
+peps/pep-0541.rst @ambv
+# peps/pep-0542.rst
+peps/pep-0543.rst @tiran
+peps/pep-0544.rst @ilevkivskyi @ambv
+peps/pep-0545.rst @JulienPalard @methane @vstinner
+peps/pep-0546.rst @vstinner
+peps/pep-0547.rst @encukou
+peps/pep-0548.rst @bitdancer
+peps/pep-0549.rst @larryhastings
+peps/pep-0550.rst @1st1
+peps/pep-0550-lookup_hamt.png @1st1
+peps/pep-0550-hamt_vs_dict.png @1st1
+peps/pep-0550-hamt_vs_dict-v2.png @1st1
+peps/pep-0551.rst @zooba
+peps/pep-0552.rst @benjaminp
+peps/pep-0553.rst @warsaw
+peps/pep-0554.rst @ericsnowcurrently
+# peps/pep-0555.rst
+peps/pep-0556.rst @pitrou
+peps/pep-0557.rst @ericvsmith
+peps/pep-0558.rst @ncoghlan
+peps/pep-0559.rst @warsaw
+peps/pep-0560.rst @ilevkivskyi
+# peps/pep-0561.rst
+peps/pep-0562.rst @ilevkivskyi
+peps/pep-0563.rst @ambv
+peps/pep-0564.rst @vstinner
+peps/pep-0565.rst @ncoghlan
+# peps/pep-0566.rst
+peps/pep-0567.rst @1st1
+peps/pep-0568.rst @njsmith
+peps/pep-0569.rst @ambv
+peps/pep-0570.rst @larryhastings @pablogsal
+# peps/pep-0571.rst
+peps/pep-0572.rst @tim-one @gvanrossum
+peps/pep-0573.rst @encukou @ncoghlan @ericsnowcurrently
+peps/pep-0574.rst @pitrou
+# peps/pep-0575.rst
+peps/pep-0576.rst @markshannon
+peps/pep-0577.rst @ncoghlan
+peps/pep-0578.rst @zooba
+# peps/pep-0579.rst
+# peps/pep-0580.rst
+peps/pep-0581.rst @Mariatta
+peps/pep-0582.rst @kushaldas @zooba @dstufft @ncoghlan
+# peps/pep-0583.rst
+peps/pep-0584.rst @brandtbucher # @stevendaprano
+peps/pep-0585.rst @ambv
+peps/pep-0586.rst @ilevkivskyi
+peps/pep-0587.rst @vstinner @ncoghlan
+peps/pep-0588.rst @Mariatta
+peps/pep-0589.rst @gvanrossum
+peps/pep-0590.rst @markshannon
+peps/pep-0591.rst @ilevkivskyi
+peps/pep-0592.rst @dstufft
+peps/pep-0593.rst @ilevkivskyi
+peps/pep-0594.rst @tiran @brettcannon
+peps/pep-0595.rst @ezio-melotti @berkerpeksag
+peps/pep-0596.rst @ambv
+peps/pep-0597.rst @methane
+peps/pep-0598.rst @ncoghlan
+peps/pep-0599.rst @pfmoore
+peps/pep-0600.rst @njsmith
+peps/pep-0601.rst @isidentical
+peps/pep-0602.rst @ambv
+peps/pep-0602-example-release-calendar.png @ambv
+peps/pep-0602-example-release-calendar.pptx @ambv
+peps/pep-0602-overlapping-support-matrix.png @ambv
+peps/pep-0602-overlapping-support-matrix.pptx @ambv
+peps/pep-0603.rst @1st1
+peps/pep-0603-lookup_hamt.png @1st1
+peps/pep-0603-hamt_vs_dict.png @1st1
+# peps/pep-0604.rst
+peps/pep-0605.rst @zooba @ncoghlan
+peps/pep-0605-example-release-calendar.png @zooba @ncoghlan
+peps/pep-0605-overlapping-support-matrix.png @zooba @ncoghlan
+peps/pep-0605/ @zooba @ncoghlan
+peps/pep-0606.rst @vstinner
+peps/pep-0607.rst @ambv @zooba @ncoghlan
+peps/pep-0608.rst @vstinner
+peps/pep-0609.rst @pganssle
+peps/pep-0610.rst @cjerdonek
+peps/pep-0611.rst @markshannon
+peps/pep-0612.rst @gvanrossum
+peps/pep-0613.rst @gvanrossum
+peps/pep-0614.rst @brandtbucher
+peps/pep-0615.rst @pganssle
+peps/pep-0616.rst @ericvsmith
+peps/pep-0617.rst @gvanrossum @pablogsal @lysnikolaou
+peps/pep-0618.rst @brandtbucher
+peps/pep-0619.rst @pablogsal
+peps/pep-0620.rst @vstinner
+peps/pep-0621.rst @brettcannon @pganssle
+peps/pep-0622.rst @brandtbucher @ilevkivskyi @gvanrossum
+peps/pep-0623.rst @methane
+peps/pep-0624.rst @methane
+peps/pep-0625.rst @pfmoore
+peps/pep-0626.rst @markshannon
+peps/pep-0627.rst @encukou
+peps/pep-0628.rst @ncoghlan
+peps/pep-0629.rst @dstufft
+peps/pep-0630.rst @encukou
+peps/pep-0631.rst @pganssle
+peps/pep-0632.rst @zooba
+peps/pep-0633.rst @brettcannon
+peps/pep-0634.rst @brandtbucher @gvanrossum
+peps/pep-0635.rst @brandtbucher @gvanrossum
+peps/pep-0636.rst @brandtbucher @gvanrossum
+# peps/pep-0637.rst @stevendaprano
+peps/pep-0638.rst @markshannon
+peps/pep-0639.rst @CAM-Gerlach
+peps/pep-0640.rst @Yhg1s
+peps/pep-0641.rst @zooba @warsaw @brettcannon
+peps/pep-0642.rst @ncoghlan
+peps/pep-0643.rst @pfmoore
+peps/pep-0644.rst @tiran
+peps/pep-0645.rst @gvanrossum
+peps/pep-0646.rst @gvanrossum
+peps/pep-0647.rst @gvanrossum
+peps/pep-0648.rst @pablogsal
+peps/pep-0649.rst @larryhastings
+peps/pep-0650.rst @brettcannon
+peps/pep-0651.rst @markshannon
+peps/pep-0652.rst @encukou
+peps/pep-0653.rst @markshannon
+peps/pep-0654.rst @1st1 @gvanrossum @iritkatriel
+peps/pep-0655.rst @gvanrossum
+peps/pep-0656.rst @brettcannon
+peps/pep-0657.rst @pablogsal @isidentical @ammaraskar
+peps/pep-0658.rst @brettcannon
+peps/pep-0659.rst @markshannon
+peps/pep-0660.rst @pfmoore
+peps/pep-0661.rst @taleinat
+peps/pep-0662.rst @brettcannon
+peps/pep-0662/ @brettcannon
+peps/pep-0663.rst @ethanfurman
+peps/pep-0664.rst @pablogsal
+peps/pep-0665.rst @brettcannon
+# peps/pep-0666.rst
+peps/pep-0667.rst @markshannon
+peps/pep-0668.rst @dstufft
+peps/pep-0669.rst @markshannon
+peps/pep-0670.rst @vstinner @erlend-aasland
+peps/pep-0671.rst @rosuav
+peps/pep-0672.rst @encukou
+peps/pep-0673.rst @jellezijlstra
+peps/pep-0674.rst @vstinner
+peps/pep-0675.rst @jellezijlstra
+peps/pep-0676.rst @AA-Turner @Mariatta
+peps/pep-0677.rst @gvanrossum
+peps/pep-0678.rst @iritkatriel
+peps/pep-0679.rst @pablogsal
+peps/pep-0680.rst @encukou
+peps/pep-0681.rst @jellezijlstra
+peps/pep-0682.rst @mdickinson
+peps/pep-0683.rst @ericsnowcurrently
+peps/pep-0684.rst @ericsnowcurrently
+# peps/pep-0684.rst
+peps/pep-0685.rst @brettcannon
+peps/pep-0686.rst @methane
+peps/pep-0687.rst @encukou @erlend-aasland
+peps/pep-0688.rst @jellezijlstra
+peps/pep-0689.rst @encukou
+peps/pep-0690.rst @warsaw
+peps/pep-0691.rst @dstufft
+peps/pep-0692.rst @jellezijlstra
+peps/pep-0693.rst @Yhg1s
+peps/pep-0694.rst @dstufft
+peps/pep-0695.rst @gvanrossum
+peps/pep-0696.rst @jellezijlstra
+peps/pep-0697.rst @encukou
+peps/pep-0698.rst @jellezijlstra
+peps/pep-0699.rst @Fidget-Spinner
+peps/pep-0700.rst @pfmoore
+peps/pep-0701.rst @pablogsal @isidentical @lysnikolaou
+peps/pep-0702.rst @jellezijlstra
+peps/pep-0703.rst @ambv
+peps/pep-0704.rst @brettcannon @pradyunsg
+peps/pep-0705.rst @pablogsal
+peps/pep-0706.rst @encukou
+peps/pep-0707.rst @iritkatriel
+peps/pep-0708.rst @dstufft
+peps/pep-0709.rst @carljm
+peps/pep-0710.rst @dstufft
+peps/pep-0711.rst @njsmith
+peps/pep-0712.rst @ericvsmith
+peps/pep-0713.rst @ambv
+peps/pep-0714.rst @dstufft
+peps/pep-0715.rst @dstufft
+peps/pep-0717.rst @dstufft
+peps/pep-0718.rst @gvanrossum
+peps/pep-0719.rst @Yhg1s
+peps/pep-0720.rst @FFY00
+peps/pep-0721.rst @encukou
+peps/pep-0722.rst @pfmoore
+peps/pep-0723.rst @AA-Turner
+peps/pep-0724.rst @jellezijlstra
+peps/pep-0725.rst @pradyunsg
+peps/pep-0726.rst @AA-Turner
+peps/pep-0727.rst @JelleZijlstra
+peps/pep-0729.rst @JelleZijlstra @hauntsaninja
+peps/pep-0730.rst @ned-deily
+peps/pep-0731.rst @gvanrossum @encukou @vstinner @zooba @iritkatriel
+peps/pep-0732.rst @Mariatta
# ...
-# pep-0754.txt
+# peps/pep-0754.rst
# ...
-pep-0801.rst @warsaw
+peps/pep-0801.rst @warsaw
# ...
-pep-3000.txt @gvanrossum
-pep-3001.txt @birkenfeld
-# pep-3002.txt
-pep-3003.txt @brettcannon @gvanrossum
+peps/pep-3000.rst @gvanrossum
+peps/pep-3001.rst @birkenfeld
+# peps/pep-3002.rst
+peps/pep-3003.rst @brettcannon @gvanrossum
# ...
-pep-3099.txt @birkenfeld
-pep-3100.txt @brettcannon
-# pep-3101.txt
-# pep-3102.txt
-pep-3103.txt @gvanrossum
-# pep-3104.txt
-pep-3105.txt @birkenfeld
-pep-3106.txt @gvanrossum
-# pep-3107.txt
-pep-3108.txt @brettcannon
-# pep-3109.txt
-# pep-3110.txt
-# pep-3111.txt
-# pep-3112.txt
-pep-3113.txt @brettcannon
-# pep-3114.txt
-# pep-3115.txt
-pep-3116.txt @gvanrossum
-pep-3117.txt @birkenfeld
-# pep-3118.txt
-pep-3119.txt @gvanrossum
-# pep-3120.txt
-# pep-3121.txt
-pep-3122.txt @brettcannon
-# pep-3123.txt
-# pep-3124.txt
-# pep-3125.txt
-pep-3126.txt @rhettinger
-# pep-3127.txt
-# pep-3128.txt
-# pep-3129.txt
-# pep-3130.txt
-# pep-3131.txt
-pep-3132.txt @birkenfeld
-# pep-3133.txt
-# pep-3134.txt
-# pep-3135.txt
-# pep-3136.txt
-pep-3137.txt @gvanrossum
-# pep-3138.txt
-pep-3139.txt @benjaminp
-# pep-3140.txt
-# pep-3141.txt
-# pep-3142.txt
-# pep-3143.txt
-# pep-3144.txt
-# pep-3145.txt
-# pep-3146.txt
-pep-3147.txt @warsaw
-pep-3147-1.dia @warsaw
-pep-3147-1.png @warsaw
-pep-3148.txt @brianquinlan
-pep-3149.txt @warsaw
-pep-3150.txt @ncoghlan
-pep-3151.txt @pitrou
-# pep-3152.txt
-# pep-3153.txt
-pep-3154.txt @pitrou
-pep-3155.txt @pitrou
-pep-3156.txt @gvanrossum
+peps/pep-3099.rst @birkenfeld
+peps/pep-3100.rst @brettcannon
+# peps/pep-3101.rst
+# peps/pep-3102.rst
+peps/pep-3103.rst @gvanrossum
+# peps/pep-3104.rst
+peps/pep-3105.rst @birkenfeld
+peps/pep-3106.rst @gvanrossum
+# peps/pep-3107.rst
+peps/pep-3108.rst @brettcannon
+# peps/pep-3109.rst
+# peps/pep-3110.rst
+# peps/pep-3111.rst
+# peps/pep-3112.rst
+peps/pep-3113.rst @brettcannon
+# peps/pep-3114.rst
+# peps/pep-3115.rst
+peps/pep-3116.rst @gvanrossum
+peps/pep-3117.rst @birkenfeld
+# peps/pep-3118.rst
+peps/pep-3119.rst @gvanrossum
+# peps/pep-3120.rst
+# peps/pep-3121.rst
+peps/pep-3122.rst @brettcannon
+# peps/pep-3123.rst
+# peps/pep-3124.rst
+# peps/pep-3125.rst
+peps/pep-3126.rst @rhettinger
+# peps/pep-3127.rst
+# peps/pep-3128.rst
+# peps/pep-3129.rst
+# peps/pep-3130.rst
+# peps/pep-3131.rst
+peps/pep-3132.rst @birkenfeld
+# peps/pep-3133.rst
+# peps/pep-3134.rst
+# peps/pep-3135.rst
+# peps/pep-3136.rst
+peps/pep-3137.rst @gvanrossum
+# peps/pep-3138.rst
+peps/pep-3139.rst @benjaminp
+# peps/pep-3140.rst
+# peps/pep-3141.rst
+# peps/pep-3142.rst
+# peps/pep-3143.rst
+# peps/pep-3144.rst
+# peps/pep-3145.rst
+# peps/pep-3146.rst
+peps/pep-3147.rst @warsaw
+peps/pep-3147-1.dia @warsaw
+peps/pep-3147-1.png @warsaw
+peps/pep-3148.rst @brianquinlan
+peps/pep-3149.rst @warsaw
+peps/pep-3150.rst @ncoghlan
+peps/pep-3151.rst @pitrou
+# peps/pep-3152.rst
+# peps/pep-3153.rst
+peps/pep-3154.rst @pitrou
+peps/pep-3155.rst @pitrou
+peps/pep-3156.rst @gvanrossum
# ...
-# pep-3333.txt
+# peps/pep-3333.rst
# ...
-pep-8000.rst @warsaw
-pep-8001.rst @brettcannon @tiran @dstufft @ericsnowcurrently @gpshead @ambv @Mariatta @njsmith @pablogsal @rhettinger @taleinat @tim-one @zware
-pep-8002.rst @warsaw @ambv @pitrou @dhellmann @willingc
-pep-8010.rst @warsaw
-pep-8011.rst @Mariatta @warsaw
-pep-8012.rst @ambv
-pep-8013.rst @zooba
-pep-8014.rst @jackjansen
-pep-8015.rst @vstinner
-pep-8016.rst @njsmith @dstufft
+peps/pep-8000.rst @warsaw
+peps/pep-8001.rst @brettcannon @tiran @dstufft @ericsnowcurrently @gpshead @ambv @Mariatta @njsmith @pablogsal @rhettinger @taleinat @tim-one @zware
+peps/pep-8002.rst @warsaw @ambv @pitrou @dhellmann @willingc
+peps/pep-8010.rst @warsaw
+peps/pep-8011.rst @Mariatta @warsaw
+peps/pep-8012.rst @ambv
+peps/pep-8013.rst @zooba
+peps/pep-8014.rst @jackjansen
+peps/pep-8015.rst @vstinner
+peps/pep-8016.rst @njsmith @dstufft
# ...
-pep-8100.rst @njsmith
-# pep-8101.rst
-# pep-8102.rst
+peps/pep-8100.rst @njsmith
+# peps/pep-8101.rst
+# peps/pep-8102.rst
diff --git a/.github/PULL_REQUEST_TEMPLATE/Add a new PEP.md b/.github/PULL_REQUEST_TEMPLATE/Add a new PEP.md
index bcc29bf74..48aaa3072 100644
--- a/.github/PULL_REQUEST_TEMPLATE/Add a new PEP.md
+++ b/.github/PULL_REQUEST_TEMPLATE/Add a new PEP.md
@@ -10,7 +10,7 @@ If your PEP is not Standards Track, remove the corresponding section.
## Basic requirements (all PEP Types)
* [ ] Read and followed [PEP 1](https://peps.python.org/1) & [PEP 12](https://peps.python.org/12)
-* [ ] File created from the [latest PEP template](https://github.com/python/peps/blob/main/pep-0012/pep-NNNN.rst?plain=1)
+* [ ] File created from the [latest PEP template](https://github.com/python/peps/blob/main/peps/pep-0012/pep-NNNN.rst?plain=1)
* [ ] PEP has next available number, & set in filename (``pep-NNNN.rst``), PR title (``PEP 123:
``) and ``PEP`` header
* [ ] Title clearly, accurately and concisely describes the content in 79 characters or less
* [ ] Core dev/PEP editor listed as ``Author`` or ``Sponsor``, and formally confirmed their approval
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index f5afc0740..fc096a0cd 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -14,6 +14,7 @@ concurrency:
env:
FORCE_COLOR: 1
+ RUFF_FORMAT: github
jobs:
pre-commit:
@@ -21,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Python 3
uses: actions/setup-python@v4
with:
@@ -35,3 +36,17 @@ jobs:
uses: pre-commit/action@v3.0.0
with:
extra_args: --all-files --hook-stage manual codespell || true
+
+ check-peps:
+ name: Run check-peps
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up Python 3
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3"
+
+ - name: Run check-peps
+ run: python check-peps.py --detailed
diff --git a/.github/workflows/render.yml b/.github/workflows/render.yml
index 01afd33f3..98dcbf730 100644
--- a/.github/workflows/render.yml
+++ b/.github/workflows/render.yml
@@ -30,7 +30,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
fetch-depth: 0 # fetch all history so that last modified date-times are accurate
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index f80254024..e71847944 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -40,7 +40,7 @@ jobs:
- "ubuntu-latest"
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
diff --git a/.gitignore b/.gitignore
index ae1196cb1..6004c5e61 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,18 +1,27 @@
-coverage.xml
-pep-0000.txt
+# PEPs
pep-0000.rst
-pep-????.html
peps.rss
+topic
+/build
+
+# Bytecode
__pycache__
-*.pyc
-*.pyo
+*.py[co]
+
+# Editors
*~
-*env
-.coverage
-.tox
+.idea
.vscode
*.swp
-/build
-/package
-/topic
+
+# Tests
+coverage.xml
+.coverage
+.tox
+
+# Virtual environments
+*env
/venv
+
+# Builds
+/sphinx-warnings.txt
\ No newline at end of file
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 9f03d60e0..c928b5971 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -52,13 +52,14 @@ repos:
- '--target-version=py310'
files: 'pep_sphinx_extensions/tests/.*'
- - repo: https://github.com/PyCQA/isort
- rev: 5.12.0
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.0.287
hooks:
- - id: isort
- name: "Sort imports with isort"
- args: ['--profile=black', '--atomic']
- files: 'pep_sphinx_extensions/tests/.*'
+ - id: ruff
+ name: "Lint with Ruff"
+ args:
+ - '--exit-non-zero-on-fix'
+ files: '^pep_sphinx_extensions/tests/'
- repo: https://github.com/tox-dev/tox-ini-fmt
rev: 1.3.1
@@ -79,16 +80,12 @@ repos:
hooks:
- id: rst-backticks
name: "Check RST: No single backticks"
- files: '^pep-\d\.txt|\.rst$'
- types: [text]
+
- id: rst-inline-touching-normal
name: "Check RST: No backticks touching text"
- files: '^pep-\d+\.txt|\.rst$'
- types: [text]
+
- id: rst-directive-colons
name: "Check RST: 2 colons after directives"
- files: '^pep-\d+\.txt|\.rst$'
- types: [text]
# Manual codespell check
- repo: https://github.com/codespell-project/codespell
@@ -101,152 +98,134 @@ repos:
# Local checks for PEP headers and more
- repo: local
hooks:
- - id: check-no-tabs
- name: "Check tabs not used in PEPs"
- language: pygrep
- entry: '\t'
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+# # Hook to run "check-peps.py"
+# - id: "check-peps"
+# name: "Check PEPs for metadata and content enforcement"
+# entry: "python check-peps.py"
+# language: "system"
+# files: "^pep-\d{4}\.(rst|txt)$"
+# require_serial: true
- id: check-required-headers
name: "PEPs must have all required headers"
language: pygrep
- entry: '(?-m:^PEP:(?=[\s\S]*\nTitle:)(?=[\s\S]*\nAuthor:)(?=[\s\S]*\nStatus:)(?=[\s\S]*\nType:)(?=[\s\S]*\nContent-Type:)(?=[\s\S]*\nCreated:))'
+ entry: '(?-m:^PEP:(?=[\s\S]*\nTitle:)(?=[\s\S]*\nAuthor:)(?=[\s\S]*\nStatus:)(?=[\s\S]*\nType:)(?=[\s\S]*\nCreated:))'
args: ['--negate', '--multiline']
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: check-header-order
name: "PEP header order must follow PEP 12"
language: pygrep
- entry: '^PEP:[^\n]+\nTitle:[^\n]+\n(Version:[^\n]+\n)?(Last-Modified:[^\n]+\n)?Author:[^\n]+\n( +\S[^\n]+\n)*(Sponsor:[^\n]+\n)?((PEP|BDFL)-Delegate:[^\n]*\n)?(Discussions-To:[^\n]*\n)?Status:[^\n]+\nType:[^\n]+\n(Topic:[^\n]+\n)?Content-Type:[^\n]+\n(Requires:[^\n]+\n)?Created:[^\n]+\n(Python-Version:[^\n]*\n)?(Post-History:[^\n]*\n( +\S[^\n]*\n)*)?(Replaces:[^\n]+\n)?(Superseded-By:[^\n]+\n)?(Resolution:[^\n]*\n)?\n'
+ entry: '^PEP:[^\n]+\nTitle:[^\n]+\n(Version:[^\n]+\n)?(Last-Modified:[^\n]+\n)?Author:[^\n]+\n( +\S[^\n]+\n)*(Sponsor:[^\n]+\n)?((PEP|BDFL)-Delegate:[^\n]*\n)?(Discussions-To:[^\n]*\n)?Status:[^\n]+\nType:[^\n]+\n(Topic:[^\n]+\n)?(Content-Type:[^\n]+\n)?(Requires:[^\n]+\n)?Created:[^\n]+\n(Python-Version:[^\n]*\n)?(Post-History:[^\n]*\n( +\S[^\n]*\n)*)?(Replaces:[^\n]+\n)?(Superseded-By:[^\n]+\n)?(Resolution:[^\n]*\n)?\n'
args: ['--negate', '--multiline']
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-pep-number
name: "'PEP' header must be a number 1-9999"
language: pygrep
entry: '(?-m:^PEP:(?:(?! +(0|[1-9][0-9]{0,3})\n)))'
args: ['--multiline']
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-title
name: "'Title' must be 1-79 characters"
language: pygrep
entry: '(?<=\n)Title:(?:(?! +\S.{1,78}\n(?=[A-Z])))'
args: ['--multiline']
- files: '^pep-\d+\.(rst|txt)$'
- exclude: '^pep-(0499)\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
+ exclude: '^peps/pep-(0499)\.rst$'
- id: validate-author
name: "'Author' must be list of 'Name , ...'"
language: pygrep
entry: '(?<=\n)Author:(?:(?!((( +|\n {1,8})[^!#$%&()*+,/:;<=>?@\[\\\]\^_`{|}~]+( <[\w!#$%&''*+\-/=?^_{|}~.]+(@| at )[\w\-.]+\.[A-Za-z0-9]+>)?)(,|(?=\n[^ ])))+\n(?=[A-Z])))'
- args: [--multiline]
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ args: ["--multiline"]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-sponsor
name: "'Sponsor' must have format 'Name '"
language: pygrep
entry: '^Sponsor:(?: (?! *[^!#$%&()*+,/:;<=>?@\[\\\]\^_`{|}~]+( <[\w!#$%&''*+\-/=?^_{|}~.]+(@| at )[\w\-.]+\.[A-Za-z0-9]+>)?$))'
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-delegate
name: "'Delegate' must have format 'Name '"
language: pygrep
entry: '^(PEP|BDFL)-Delegate: (?:(?! *[^!#$%&()*+,/:;<=>?@\[\\\]\^_`{|}~]+( <[\w!#$%&''*+\-/=?^_{|}~.]+(@| at )[\w\-.]+\.[A-Za-z0-9]+>)?$))'
- files: '^pep-\d+\.(rst|txt)$'
- exclude: '^pep-(0451)\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
+ exclude: '^peps/pep-(0451)\.rst$'
- id: validate-discussions-to
name: "'Discussions-To' must be a thread URL"
language: pygrep
entry: '^Discussions-To: (?:(?!([\w\-]+@(python\.org|googlegroups\.com))|https://((discuss\.python\.org/t/([\w\-]+/)?\d+/?)|(mail\.python\.org/pipermail/[\w\-]+/\d{4}-[A-Za-z]+/[A-Za-z0-9]+\.html)|(mail\.python\.org/archives/list/[\w\-]+@python\.org/thread/[A-Za-z0-9]+/?))$))'
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-status
name: "'Status' must be a valid PEP status"
language: pygrep
entry: '^Status:(?:(?! +(Draft|Withdrawn|Rejected|Accepted|Final|Active|Provisional|Deferred|Superseded|April Fool!)$))'
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-type
name: "'Type' must be a valid PEP type"
language: pygrep
entry: '^Type:(?:(?! +(Standards Track|Informational|Process)$))'
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-topic
name: "'Topic' must be for a valid sub-index"
language: pygrep
entry: '^Topic:(?:(?! +(Governance|Packaging|Typing|Release)(, (Governance|Packaging|Typing|Release))*$))'
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-content-type
name: "'Content-Type' must be 'text/x-rst'"
language: pygrep
entry: '^Content-Type:(?:(?! +text/x-rst$))'
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-pep-references
name: "`Requires`/`Replaces`/`Superseded-By` must be 'NNN' PEP IDs"
language: pygrep
entry: '^(Requires|Replaces|Superseded-By):(?:(?! *( (0|[1-9][0-9]{0,3})(,|$))+$))'
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-created
name: "'Created' must be a 'DD-mmm-YYYY' date"
language: pygrep
entry: '^Created:(?:(?! +([0-2][0-9]|(3[01]))-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(199[0-9]|20[0-9][0-9])$))'
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-python-version
name: "'Python-Version' must be a 'X.Y[.Z]` version"
language: pygrep
entry: '^Python-Version:(?:(?! *( [1-9]\.([0-9][0-9]?|x)(\.[1-9][0-9]?)?(,|$))+$))'
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-post-history
name: "'Post-History' must be '`DD-mmm-YYYY `__, ...'"
language: pygrep
entry: '(?<=\n)Post-History:(?:(?! ?\n|((( +|\n {1,14})(([0-2][0-9]|(3[01]))-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(199[0-9]|20[0-9][0-9])|`([0-2][0-9]|(3[01]))-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(199[0-9]|20[0-9][0-9]) `__)(,|(?=\n[^ ])))+\n(?=[A-Z\n]))))'
args: [--multiline]
- files: '^pep-\d+\.(rst|txt)$'
- types: [text]
+ files: '^peps/pep-\d+\.rst$'
- id: validate-resolution
name: "'Resolution' must be a direct thread/message URL"
language: pygrep
entry: '(?`__ for static
+a discussion venue appropriate to the PEP (such as `Typing Discourse
+`__ for static
typing, or `Packaging Discourse `__
for packaging), or `open an issue `__.
+Opening a pull request
+----------------------
+
+The PEPs repository defines a set of pull request templates, which should be
+used when opening a PR.
+
+If you use Git from the command line, you may be accustomed to creating PRs
+by following the URL that is provided after pushing a new branch. **Do not use
+this link**, as it does not provide the option to populate the PR template.
+
+However, you *can* use the ``gh`` command line tool. ``gh pr create`` will allow
+you to create a pull request, will prompt you for the template you wish to use,
+and then give you the option of continuing editing in your broswer.
+
+Alternatively, after pushing your branch, you can visit
+`https://github.com/python/peps `__, and follow
+the link in the notification about recent changes to your branch to
+create a new PR. The in-browser interface will allow you to select a PR template
+for your new PR.
Commit messages and PR titles
-----------------------------
@@ -56,7 +75,7 @@ the Readme/Contributing Guide, issue/PR template, etc., with ``Meta:``.
Sign the Contributor License Agreement
--------------------------------------
-All contributors need to sign the
+All contributors need to sign the
`PSF Contributor Agreement `_.
to ensure we legally accept your work.
diff --git a/Makefile b/Makefile
index dcbf43a19..8f973be2c 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ OUTPUT_DIR = build
SPHINXERRORHANDLING = -W --keep-going -w sphinx-warnings.txt
ALLSPHINXOPTS = -b $(BUILDER) -j $(JOBS) \
- $(SPHINXOPTS) $(SPHINXERRORHANDLING) . $(OUTPUT_DIR) $(SOURCES)
+ $(SPHINXOPTS) $(SPHINXERRORHANDLING) peps $(OUTPUT_DIR) $(SOURCES)
## html to render PEPs to "pep-NNNN.html" files
.PHONY: html
diff --git a/build.py b/build.py
index 8f0ead024..04f0b5fdb 100755
--- a/build.py
+++ b/build.py
@@ -5,6 +5,7 @@
"""Build script for Sphinx documentation"""
import argparse
+import os
from pathlib import Path
from sphinx.application import Sphinx
@@ -27,15 +28,6 @@ def create_parser():
help='Render PEPs to "index.html" files within "pep-NNNN" directories. '
'Cannot be used with "-f" or "-l".')
- # flags / options
- parser.add_argument("-w", "--fail-on-warning", action="store_true",
- help="Fail the Sphinx build on any warning.")
- parser.add_argument("-n", "--nitpicky", action="store_true",
- help="Run Sphinx in 'nitpicky' mode, "
- "warning on every missing reference target.")
- parser.add_argument("-j", "--jobs", type=int, default=1,
- help="How many parallel jobs to run (if supported). "
- "Integer, default 1.")
parser.add_argument(
"-o",
"--output-dir",
@@ -61,33 +53,23 @@ def create_index_file(html_root: Path, builder: str) -> None:
if __name__ == "__main__":
args = create_parser()
- root_directory = Path(".").absolute()
- source_directory = root_directory
+ root_directory = Path(__file__).resolve().parent
+ source_directory = root_directory / "peps"
build_directory = root_directory / args.output_dir
- doctree_directory = build_directory / ".doctrees"
# builder configuration
- if args.builder is not None:
- sphinx_builder = args.builder
- else:
- # default builder
- sphinx_builder = "html"
-
- # other configuration
- config_overrides = {}
- if args.nitpicky:
- config_overrides["nitpicky"] = True
+ sphinx_builder = args.builder or "html"
app = Sphinx(
source_directory,
confdir=source_directory,
- outdir=build_directory,
- doctreedir=doctree_directory,
+ outdir=build_directory / sphinx_builder,
+ doctreedir=build_directory / "doctrees",
buildername=sphinx_builder,
- confoverrides=config_overrides,
- warningiserror=args.fail_on_warning,
- parallel=args.jobs,
+ warningiserror=True,
+ parallel=os.cpu_count() or 1,
tags=["internal_builder"],
+ keep_going=True,
)
app.build()
diff --git a/check-peps.py b/check-peps.py
new file mode 100755
index 000000000..ea45cd161
--- /dev/null
+++ b/check-peps.py
@@ -0,0 +1,605 @@
+#!/usr/bin/env python3
+
+# This file is placed in the public domain or under the
+# CC0-1.0-Universal license, whichever is more permissive.
+
+"""check-peps: Check PEPs for common mistakes.
+
+Usage: check-peps [-d | --detailed]
+
+Only the PEPs specified are checked.
+If none are specified, all PEPs are checked.
+
+Use "--detailed" to show the contents of lines where errors were found.
+"""
+
+from __future__ import annotations
+
+import datetime as dt
+import re
+import sys
+from pathlib import Path
+
+TYPE_CHECKING = False
+if TYPE_CHECKING:
+ from collections.abc import Iterable, Iterator, KeysView, Sequence
+ from typing import TypeAlias
+
+ # (line number, warning message)
+ Message: TypeAlias = tuple[int, str]
+ MessageIterator: TypeAlias = Iterator[Message]
+
+
+# get the directory with the PEP sources
+ROOT_DIR = Path(__file__).resolve().parent
+PEP_ROOT = ROOT_DIR / "peps"
+
+# See PEP 12 for the order
+# Note we retain "BDFL-Delegate"
+ALL_HEADERS = (
+ "PEP",
+ "Title",
+ "Version",
+ "Last-Modified",
+ "Author",
+ "Sponsor",
+ "BDFL-Delegate", "PEP-Delegate",
+ "Discussions-To",
+ "Status",
+ "Type",
+ "Topic",
+ "Content-Type",
+ "Requires",
+ "Created",
+ "Python-Version",
+ "Post-History",
+ "Replaces",
+ "Superseded-By",
+ "Resolution",
+)
+REQUIRED_HEADERS = frozenset({"PEP", "Title", "Author", "Status", "Type", "Created"})
+
+# See PEP 1 for the full list
+ALL_STATUSES = frozenset({
+ "Accepted",
+ "Active",
+ "April Fool!",
+ "Deferred",
+ "Draft",
+ "Final",
+ "Provisional",
+ "Rejected",
+ "Superseded",
+ "Withdrawn",
+})
+
+# PEPs that are allowed to link directly to PEPs
+SKIP_DIRECT_PEP_LINK_CHECK = frozenset({"0009", "0287", "0676", "0684", "8001"})
+
+DEFAULT_FLAGS = re.ASCII | re.IGNORECASE # Insensitive latin
+
+# any sequence of letters or '-', followed by a single ':' and a space or end of line
+HEADER_PATTERN = re.compile(r"^([a-z\-]+):(?: |$)", DEFAULT_FLAGS)
+# any sequence of unicode letters or legal special characters
+NAME_PATTERN = re.compile(r"(?:[^\W\d_]|[ ',\-.])+(?: |$)")
+# any sequence of ASCII letters, digits, or legal special characters
+EMAIL_LOCAL_PART_PATTERN = re.compile(r"[\w!#$%&'*+\-/=?^{|}~.]+", DEFAULT_FLAGS)
+
+DISCOURSE_THREAD_PATTERN = re.compile(r"([\w\-]+/)?\d+", DEFAULT_FLAGS)
+DISCOURSE_POST_PATTERN = re.compile(r"([\w\-]+/)?\d+(/\d+)?", DEFAULT_FLAGS)
+
+MAILMAN_2_PATTERN = re.compile(r"[\w\-]+/\d{4}-[a-z]+/\d+\.html", DEFAULT_FLAGS)
+MAILMAN_3_THREAD_PATTERN = re.compile(r"[\w\-]+@python\.org/thread/[a-z0-9]+/?", DEFAULT_FLAGS)
+MAILMAN_3_MESSAGE_PATTERN = re.compile(r"[\w\-]+@python\.org/message/[a-z0-9]+/?(#[a-z0-9]+)?", DEFAULT_FLAGS)
+
+# Controlled by the "--detailed" flag
+DETAILED_ERRORS = False
+
+
+def check(filenames: Sequence[str] = (), /) -> int:
+ """The main entry-point."""
+ if filenames:
+ filenames = map(Path, filenames)
+ else:
+ filenames = PEP_ROOT.glob("pep-????.rst")
+ if (count := sum(map(check_file, filenames))) > 0:
+ s = "s" * (count != 1)
+ print(f"check-peps failed: {count} error{s}", file=sys.stderr)
+ return 1
+ return 0
+
+
+def check_file(filename: Path, /) -> int:
+ filename = filename.resolve()
+ try:
+ content = filename.read_text(encoding="utf-8")
+ except FileNotFoundError:
+ return _output_error(filename, [""], [(0, "Could not read PEP!")])
+ else:
+ lines = content.splitlines()
+ return _output_error(filename, lines, check_peps(filename, lines))
+
+
+def check_peps(filename: Path, lines: Sequence[str], /) -> MessageIterator:
+ yield from check_headers(lines)
+ for line_num, line in enumerate(lines, start=1):
+ if filename.stem.removeprefix("pep-") in SKIP_DIRECT_PEP_LINK_CHECK:
+ continue
+ yield from check_direct_links(line_num, line.lstrip())
+
+
+def check_headers(lines: Sequence[str], /) -> MessageIterator:
+ yield from _validate_pep_number(next(iter(lines), ""))
+
+ found_headers = {}
+ line_num = 0
+ for line_num, line in enumerate(lines, start=1):
+ if line.strip() == "":
+ headers_end_line_num = line_num
+ break
+ if match := HEADER_PATTERN.match(line):
+ header = match[1]
+ if header in ALL_HEADERS:
+ if header not in found_headers:
+ found_headers[match[1]] = line_num
+ else:
+ yield line_num, f"Must not have duplicate header: {header} "
+ else:
+ yield line_num, f"Must not have invalid header: {header}"
+ else:
+ headers_end_line_num = line_num
+
+ yield from _validate_required_headers(found_headers.keys())
+
+ shifted_line_nums = list(found_headers.values())[1:]
+ for i, (header, line_num) in enumerate(found_headers.items()):
+ start = line_num - 1
+ end = headers_end_line_num - 1
+ if i < len(found_headers) - 1:
+ end = shifted_line_nums[i] - 1
+ remainder = "\n".join(lines[start:end]).removeprefix(f"{header}:")
+ if remainder != "":
+ if remainder[0] not in {" ", "\n"}:
+ yield line_num, f"Headers must have a space after the colon: {header}"
+ remainder = remainder.lstrip()
+ yield from _validate_header(header, line_num, remainder)
+
+
+def _validate_header(header: str, line_num: int, content: str) -> MessageIterator:
+ if header == "Title":
+ yield from _validate_title(line_num, content)
+ elif header == "Author":
+ yield from _validate_author(line_num, content)
+ elif header == "Sponsor":
+ yield from _validate_sponsor(line_num, content)
+ elif header in {"BDFL-Delegate", "PEP-Delegate"}:
+ yield from _validate_delegate(line_num, content)
+ elif header == "Discussions-To":
+ yield from _validate_discussions_to(line_num, content)
+ elif header == "Status":
+ yield from _validate_status(line_num, content)
+ elif header == "Type":
+ yield from _validate_type(line_num, content)
+ elif header == "Topic":
+ yield from _validate_topic(line_num, content)
+ elif header == "Content-Type":
+ yield from _validate_content_type(line_num, content)
+ elif header in {"Requires", "Replaces", "Superseded-By"}:
+ yield from _validate_pep_references(line_num, content)
+ elif header == "Created":
+ yield from _validate_created(line_num, content)
+ elif header == "Python-Version":
+ yield from _validate_python_version(line_num, content)
+ elif header == "Post-History":
+ yield from _validate_post_history(line_num, content)
+ elif header == "Resolution":
+ yield from _validate_resolution(line_num, content)
+
+
+def check_direct_links(line_num: int, line: str) -> MessageIterator:
+ """Check that PEPs and RFCs aren't linked directly"""
+
+ line = line.lower()
+ if "dev/peps/pep-" in line or "peps.python.org/pep-" in line:
+ yield line_num, "Use the :pep:`NNN` role to refer to PEPs"
+ if "rfc-editor.org/rfc/" in line or "ietf.org/doc/html/rfc" in line:
+ yield line_num, "Use the :rfc:`NNN` role to refer to RFCs"
+
+
+def _output_error(filename: Path, lines: Sequence[str], errors: Iterable[Message]) -> int:
+ relative_filename = filename.relative_to(ROOT_DIR)
+ err_count = 0
+ for line_num, msg in errors:
+ err_count += 1
+
+ print(f"{relative_filename}:{line_num}: {msg}")
+ if not DETAILED_ERRORS:
+ continue
+
+ line = lines[line_num - 1]
+ print(" |")
+ print(f"{line_num: >4} | '{line}'")
+ print(" |")
+
+ return err_count
+
+
+###########################
+# PEP Header Validators #
+###########################
+
+
+def _validate_required_headers(found_headers: KeysView[str]) -> MessageIterator:
+ """PEPs must have all required headers, in the PEP 12 order"""
+
+ if missing := REQUIRED_HEADERS.difference(found_headers):
+ for missing_header in sorted(missing, key=ALL_HEADERS.index):
+ yield 1, f"Must have required header: {missing_header}"
+
+ ordered_headers = sorted(found_headers, key=ALL_HEADERS.index)
+ if list(found_headers) != ordered_headers:
+ order_str = ", ".join(ordered_headers)
+ yield 1, "Headers must be in PEP 12 order. Correct order: " + order_str
+
+
+def _validate_pep_number(line: str) -> MessageIterator:
+ """'PEP' header must be a number 1-9999"""
+
+ if not line.startswith("PEP: "):
+ yield 1, "PEP must begin with the 'PEP:' header"
+ return
+
+ pep_number = line.removeprefix("PEP: ").lstrip()
+ yield from _pep_num(1, pep_number, "'PEP:' header")
+
+
+def _validate_title(line_num: int, line: str) -> MessageIterator:
+ """'Title' must be 1-79 characters"""
+
+ if len(line) == 0:
+ yield line_num, "PEP must have a title"
+ elif len(line) > 79:
+ yield line_num, "PEP title must be less than 80 characters"
+
+
+def _validate_author(line_num: int, body: str) -> MessageIterator:
+ """'Author' must be list of 'Name , …'"""
+
+ lines = body.split("\n")
+ for offset, line in enumerate(lines):
+ if offset >= 1 and line[:9].isspace():
+ # Checks for:
+ # Author: Alice
+ # Bob
+ # ^^^^
+ # Note that len("Author: ") == 8
+ yield line_num + offset, "Author line must not be over-indented"
+ if offset < len(lines) - 1:
+ if not line.endswith(","):
+ yield line_num + offset, "Author continuation lines must end with a comma"
+ for part in line.removesuffix(",").split(", "):
+ yield from _email(line_num + offset, part, "Author")
+
+
+def _validate_sponsor(line_num: int, line: str) -> MessageIterator:
+ """'Sponsor' must have format 'Name '"""
+
+ yield from _email(line_num, line, "Sponsor")
+
+
+def _validate_delegate(line_num: int, line: str) -> MessageIterator:
+ """'Delegate' must have format 'Name '"""
+
+ if line == "":
+ return
+
+ # PEP 451
+ if ", " in line:
+ for part in line.removesuffix(",").split(", "):
+ yield from _email(line_num, part, "Delegate")
+ return
+
+ yield from _email(line_num, line, "Delegate")
+
+
+def _validate_discussions_to(line_num: int, line: str) -> MessageIterator:
+ """'Discussions-To' must be a thread URL"""
+
+ yield from _thread(line_num, line, "Discussions-To", discussions_to=True)
+ if line.startswith("https://"):
+ return
+ for suffix in "@python.org", "@googlegroups.com":
+ if line.endswith(suffix):
+ remainder = line.removesuffix(suffix)
+ if re.fullmatch(r"[\w\-]+", remainder) is None:
+ yield line_num, "Discussions-To must be a valid mailing list"
+ return
+ yield line_num, "Discussions-To must be a valid thread URL or mailing list"
+
+
+def _validate_status(line_num: int, line: str) -> MessageIterator:
+ """'Status' must be a valid PEP status"""
+
+ if line not in ALL_STATUSES:
+ yield line_num, "Status must be a valid PEP status"
+
+
+def _validate_type(line_num: int, line: str) -> MessageIterator:
+ """'Type' must be a valid PEP type"""
+
+ if line not in {"Standards Track", "Informational", "Process"}:
+ yield line_num, "Type must be a valid PEP type"
+
+
+def _validate_topic(line_num: int, line: str) -> MessageIterator:
+ """'Topic' must be for a valid sub-index"""
+
+ topics = line.split(", ")
+ unique_topics = set(topics)
+ if len(topics) > len(unique_topics):
+ yield line_num, "Topic must not contain duplicates"
+
+ if unique_topics - {"Governance", "Packaging", "Typing", "Release"}:
+ if not all(map(str.istitle, unique_topics)):
+ yield line_num, "Topic must be properly capitalised (Title Case)"
+ if unique_topics - {"governance", "packaging", "typing", "release"}:
+ yield line_num, "Topic must be for a valid sub-index"
+ if sorted(topics) != topics:
+ yield line_num, "Topic must be sorted lexicographically"
+
+
+def _validate_content_type(line_num: int, line: str) -> MessageIterator:
+ """'Content-Type' must be 'text/x-rst'"""
+
+ if line != "text/x-rst":
+ yield line_num, "Content-Type must be 'text/x-rst'"
+
+
+def _validate_pep_references(line_num: int, line: str) -> MessageIterator:
+ """`Requires`/`Replaces`/`Superseded-By` must be 'NNN' PEP IDs"""
+
+ line = line.removesuffix(",").rstrip()
+ if line.count(", ") != line.count(","):
+ yield line_num, "PEP references must be separated by comma-spaces (', ')"
+ return
+
+ references = line.split(", ")
+ for reference in references:
+ yield from _pep_num(line_num, reference, "PEP reference")
+
+
+def _validate_created(line_num: int, line: str) -> MessageIterator:
+ """'Created' must be a 'DD-mmm-YYYY' date"""
+
+ yield from _date(line_num, line, "Created")
+
+
+def _validate_python_version(line_num: int, line: str) -> MessageIterator:
+ """'Python-Version' must be an ``X.Y[.Z]`` version"""
+
+ versions = line.split(", ")
+ for version in versions:
+ if version.count(".") not in {1, 2}:
+ yield line_num, f"Python-Version must have two or three segments: {version}"
+ continue
+
+ try:
+ major, minor, micro = version.split(".", 2)
+ except ValueError:
+ major, minor = version.split(".", 1)
+ micro = ""
+
+ if major not in "123":
+ yield line_num, f"Python-Version major part must be 1, 2, or 3: {version}"
+ if not _is_digits(minor) and minor != "x":
+ yield line_num, f"Python-Version minor part must be numeric: {version}"
+ elif minor != "0" and minor[0] == "0":
+ yield line_num, f"Python-Version minor part must not have leading zeros: {version}"
+
+ if micro == "":
+ return
+ if minor == "x":
+ yield line_num, f"Python-Version micro part must be empty if minor part is 'x': {version}"
+ elif micro[0] == "0":
+ yield line_num, f"Python-Version micro part must not have leading zeros: {version}"
+ elif not _is_digits(micro):
+ yield line_num, f"Python-Version micro part must be numeric: {version}"
+
+
+def _validate_post_history(line_num: int, body: str) -> MessageIterator:
+ """'Post-History' must be '`DD-mmm-YYYY `__, …'"""
+
+ if body == "":
+ return
+
+ for offset, line in enumerate(body.removesuffix(",").split("\n"), start=line_num):
+ for post in line.removesuffix(",").strip().split(", "):
+ if not post.startswith("`") and not post.endswith(">`__"):
+ yield from _date(offset, post, "Post-History")
+ else:
+ post_date, post_url = post[1:-4].split(" <")
+ yield from _date(offset, post_date, "Post-History")
+ yield from _thread(offset, post_url, "Post-History")
+
+
+def _validate_resolution(line_num: int, line: str) -> MessageIterator:
+ """'Resolution' must be a direct thread/message URL"""
+
+ yield from _thread(line_num, line, "Resolution", allow_message=True)
+
+
+########################
+# Validation Helpers #
+########################
+
+def _pep_num(line_num: int, pep_number: str, prefix: str) -> MessageIterator:
+ if pep_number == "":
+ yield line_num, f"{prefix} must not be blank: {pep_number!r}"
+ return
+ if pep_number.startswith("0") and pep_number != "0":
+ yield line_num, f"{prefix} must not contain leading zeros: {pep_number!r}"
+ if not _is_digits(pep_number):
+ yield line_num, f"{prefix} must be numeric: {pep_number!r}"
+ elif not 0 <= int(pep_number) <= 9999:
+ yield line_num, f"{prefix} must be between 0 and 9999: {pep_number!r}"
+
+
+def _is_digits(string: str) -> bool:
+ """Match a string of ASCII digits ([0-9]+)."""
+ return string.isascii() and string.isdigit()
+
+
+def _email(line_num: int, author_email: str, prefix: str) -> MessageIterator:
+ author_email = author_email.strip()
+
+ if author_email.count("<") > 1:
+ msg = f"{prefix} entries must not contain multiple '<': {author_email!r}"
+ yield line_num, msg
+ if author_email.count(">") > 1:
+ msg = f"{prefix} entries must not contain multiple '>': {author_email!r}"
+ yield line_num, msg
+ if author_email.count("@") > 1:
+ msg = f"{prefix} entries must not contain multiple '@': {author_email!r}"
+ yield line_num, msg
+
+ author = author_email.split("<", 1)[0].rstrip()
+ if NAME_PATTERN.fullmatch(author) is None:
+ msg = f"{prefix} entries must begin with a valid 'Name': {author_email!r}"
+ yield line_num, msg
+ return
+
+ email_text = author_email.removeprefix(author)
+ if not email_text:
+ # Does not have the optional email part
+ return
+
+ if not email_text.startswith(" <") or not email_text.endswith(">"):
+ msg = f"{prefix} entries must be formatted as 'Name ': {author_email!r}"
+ yield line_num, msg
+ email_text = email_text.removeprefix(" <").removesuffix(">")
+
+ if "@" in email_text:
+ local, domain = email_text.rsplit("@", 1)
+ elif " at " in email_text:
+ local, domain = email_text.rsplit(" at ", 1)
+ else:
+ yield line_num, f"{prefix} entries must contain a valid email address: {author_email!r}"
+ return
+ if EMAIL_LOCAL_PART_PATTERN.fullmatch(local) is None or _invalid_domain(domain):
+ yield line_num, f"{prefix} entries must contain a valid email address: {author_email!r}"
+
+
+def _invalid_domain(domain_part: str) -> bool:
+ *labels, root = domain_part.split(".")
+ for label in labels:
+ if not label.replace("-", "").isalnum():
+ return True
+ return not root.isalnum() or not root.isascii()
+
+
+def _thread(line_num: int, url: str, prefix: str, *, allow_message: bool = False, discussions_to: bool = False) -> MessageIterator:
+ if allow_message and discussions_to:
+ msg = "allow_message and discussions_to cannot both be True"
+ raise ValueError(msg)
+
+ msg = f"{prefix} must be a valid thread URL"
+
+ if not url.startswith("https://"):
+ if not discussions_to:
+ yield line_num, msg
+ return
+
+ if url.startswith("https://discuss.python.org/t/"):
+ remainder = url.removeprefix("https://discuss.python.org/t/").removesuffix("/")
+
+ # Discussions-To links must be the thread itself, not a post
+ if discussions_to:
+ # The equivalent pattern is similar to '([\w\-]+/)?\d+',
+ # but the topic name must contain a non-numeric character
+
+ # We use ``str.rpartition`` as the topic name is optional
+ topic_name, _, topic_id = remainder.rpartition("/")
+ if topic_name == '' and _is_digits(topic_id):
+ return
+ topic_name = topic_name.replace("-", "0").replace("_", "0")
+ # the topic name must not be entirely numeric
+ valid_topic_name = not _is_digits(topic_name) and topic_name.isalnum()
+ if valid_topic_name and _is_digits(topic_id):
+ return
+ else:
+ # The equivalent pattern is similar to '([\w\-]+/)?\d+(/\d+)?',
+ # but the topic name must contain a non-numeric character
+ if remainder.count("/") == 2:
+ # When there are three parts, the URL must be "topic-name/topic-id/post-id".
+ topic_name, topic_id, post_id = remainder.rsplit("/", 2)
+ topic_name = topic_name.replace("-", "0").replace("_", "0")
+ valid_topic_name = not _is_digits(topic_name) and topic_name.isalnum()
+ if valid_topic_name and _is_digits(topic_id) and _is_digits(post_id):
+ # the topic name must not be entirely numeric
+ return
+ elif remainder.count("/") == 1:
+ # When there are only two parts, there's an ambiguity between
+ # "topic-name/topic-id" and "topic-id/post-id".
+ # We disambiguate by checking if the LHS is a valid name and
+ # the RHS is a valid topic ID (for the former),
+ # and then if both the LHS and RHS are valid IDs (for the latter).
+ left, right = remainder.rsplit("/")
+ left = left.replace("-", "0").replace("_", "0")
+ # the topic name must not be entirely numeric
+ left_is_name = not _is_digits(left) and left.isalnum()
+ if left_is_name and _is_digits(right):
+ return
+ elif _is_digits(left) and _is_digits(right):
+ return
+ else:
+ # When there's only one part, it must be a valid topic ID.
+ if _is_digits(remainder):
+ return
+
+ if url.startswith("https://mail.python.org/pipermail/"):
+ remainder = url.removeprefix("https://mail.python.org/pipermail/")
+ if MAILMAN_2_PATTERN.fullmatch(remainder) is not None:
+ return
+
+ if url.startswith("https://mail.python.org/archives/list/"):
+ remainder = url.removeprefix("https://mail.python.org/archives/list/")
+ if allow_message and MAILMAN_3_MESSAGE_PATTERN.fullmatch(remainder) is not None:
+ return
+ if MAILMAN_3_THREAD_PATTERN.fullmatch(remainder) is not None:
+ return
+
+ yield line_num, msg
+
+
+def _date(line_num: int, date_str: str, prefix: str) -> MessageIterator:
+ try:
+ parsed_date = dt.datetime.strptime(date_str, "%d-%b-%Y")
+ except ValueError:
+ yield line_num, f"{prefix} must be a 'DD-mmm-YYYY' date: {date_str!r}"
+ return
+ else:
+ if date_str[1] == "-": # Date must be zero-padded
+ yield line_num, f"{prefix} must be a 'DD-mmm-YYYY' date: {date_str!r}"
+ return
+
+ if parsed_date.year < 1990:
+ yield line_num, f"{prefix} must not be before Python was invented: {date_str!r}"
+ if parsed_date > (dt.datetime.now() + dt.timedelta(days=14)):
+ yield line_num, f"{prefix} must not be in the future: {date_str!r}"
+
+
+if __name__ == "__main__":
+ if {"-h", "--help", "-?"}.intersection(sys.argv[1:]):
+ print(__doc__, file=sys.stderr)
+ raise SystemExit(0)
+
+ files = {}
+ for arg in sys.argv[1:]:
+ if not arg.startswith("-"):
+ files[arg] = None
+ elif arg in {"-d", "--detailed"}:
+ DETAILED_ERRORS = True
+ else:
+ print(f"Unknown option: {arg!r}", file=sys.stderr)
+ raise SystemExit(1)
+ raise SystemExit(check(files))
diff --git a/docs/build.rst b/docs/build.rst
index ae4ac1848..d59b2f804 100644
--- a/docs/build.rst
+++ b/docs/build.rst
@@ -1,5 +1,4 @@
-..
- Author: Adam Turner
+:author: Adam Turner
Building PEPs Locally
@@ -10,8 +9,8 @@ This can also be used to check that the PEP is valid reStructuredText before
submission to the PEP editors.
The rest of this document assumes you are working from a local clone of the
-`PEPs repository `__, with
-**Python 3.9 or later** installed.
+`PEPs repository `__,
+with **Python 3.9 or later** installed.
Render PEPs locally
@@ -51,11 +50,6 @@ Render PEPs locally
(venv) PS> python build.py
- .. note::
-
- There may be a series of warnings about unreferenced citations or labels.
- Whilst these are valid warnings, they do not impact the build process.
-
4. Navigate to the ``build`` directory of your PEPs repo to find the HTML pages.
PEP 0 provides a formatted index, and may be a useful reference.
@@ -87,28 +81,8 @@ Check the validity of links within PEP sources (runs the `Sphinx linkchecker
.. code-block:: shell
- python build.py --check-links
- make check-links
-
-
-Stricter rendering
-''''''''''''''''''
-
-Run in `nit-picky `__
-mode.
-This generates warnings for all missing references.
-
-.. code-block:: shell
-
- python build.py --nitpicky
-
-Fail the build on any warning.
-As of January 2022, there are around 250 warnings when building the PEPs.
-
-.. code-block:: shell
-
- python build.py --fail-on-warning
- make fail-warning
+ python build.py --check-links
+ make check-links
``build.py`` usage
@@ -118,4 +92,4 @@ For details on the command-line options to the ``build.py`` script, run:
.. code-block:: shell
- python build.py --help
+ python build.py --help
diff --git a/docs/rendering_system.rst b/docs/rendering_system.rst
index 9a298e0e8..fc20d00df 100644
--- a/docs/rendering_system.rst
+++ b/docs/rendering_system.rst
@@ -1,6 +1,6 @@
-..
- Author: Adam Turner
+:author: Adam Turner
+..
We can't use :pep:`N` references in this document, as they use links relative
to the current file, which doesn't work in a subdirectory like this one.
@@ -9,7 +9,7 @@ An Overview of the PEP Rendering System
=======================================
This document provides an overview of the PEP rendering system, as a companion
-to :doc:`PEP 676 <../pep-0676>`.
+to `PEP 676 `__.
1. Configuration
@@ -17,14 +17,14 @@ to :doc:`PEP 676 <../pep-0676>`.
Configuration is stored in three files:
-- ``conf.py`` contains the majority of the Sphinx configuration
-- ``contents.rst`` creates the Sphinx-mandated table of contents directive
+- ``peps/conf.py`` contains the majority of the Sphinx configuration
+- ``peps/contents.rst`` contains the compulsory table of contents directive
- ``pep_sphinx_extensions/pep_theme/theme.conf`` sets the Pygments themes
The configuration:
- registers the custom Sphinx extension
-- sets both ``.txt`` and ``.rst`` suffixes to be parsed as PEPs
+- sets the ``.rst`` suffix to be parsed as PEPs
- tells Sphinx which source files to use
- registers the PEP theme, maths renderer, and template
- disables some default settings that are covered in the extension
@@ -35,7 +35,7 @@ The configuration:
----------------
``build.py`` manages the rendering process.
-Usage is covered in :doc:`build`.
+Usage is covered in `Building PEPs Locally <./build.rst>`_.
3. Extension
@@ -110,7 +110,8 @@ This overrides the built-in ``:pep:`` role to return the correct URL.
3.4.2 ``PEPHeaders`` transform
******************************
-PEPs start with a set of :rfc:`2822` headers, per :doc:`PEP 1 <../pep-0001>`.
+PEPs start with a set of :rfc:`2822` headers,
+per `PEP 1 `__.
This transform validates that the required headers are present and of the
correct data type, and removes headers not for display.
It must run before the ``PEPTitle`` transform.
@@ -122,7 +123,7 @@ It must run before the ``PEPTitle`` transform.
We generate the title node from the parsed title in the PEP headers, and make
all nodes in the document children of the new title node.
This transform must also handle parsing reStructuredText markup within PEP
-titles, such as :doc:`PEP 604 <../pep-0604>`.
+titles, such as `PEP 604 `__.
3.4.4 ``PEPContents`` transform
@@ -216,12 +217,9 @@ parse and validate that metadata.
After collecting and validating all the PEP data, the index itself is created in
three steps:
- 1. Output the header text
- 2. Output the category and numerical indices
- 3. Output the author index
-
-The ``AUTHOR_OVERRIDES.csv`` file can be used to override an author's name in
-the PEP 0 output.
+1. Output the header text
+2. Output the category and numerical indices
+3. Output the author index
We then add the newly created PEP 0 file to two Sphinx variables so that it will
be processed as a normal source document.
diff --git a/pep-0705.rst b/pep-0705.rst
deleted file mode 100644
index f62a8305c..000000000
--- a/pep-0705.rst
+++ /dev/null
@@ -1,295 +0,0 @@
-PEP: 705
-Title: TypedMapping: Type Hints for Mappings with a Fixed Set of Keys
-Author: Alice Purcell
-Sponsor: Pablo Galindo
-Discussions-To: https://discuss.python.org/t/pep-705-typedmapping/24827
-Status: Draft
-Type: Standards Track
-Topic: Typing
-Content-Type: text/x-rst
-Created: 07-Nov-2022
-Python-Version: 3.12
-Post-History: `30-Sep-2022 `__,
- `02-Nov-2022 `__,
- `14-Mar-2023 `__,
-
-
-Abstract
-========
-
-:pep:`589` defines the structural type :class:`~typing.TypedDict` for dictionaries with a fixed set of keys.
-As ``TypedDict`` is a mutable type, it is difficult to correctly annotate methods which accept read-only parameters in a way that doesn't prevent valid inputs.
-This PEP proposes a type constructor ``typing.TypedMapping`` to support this use case.
-
-Motivation
-==========
-
-Representing structured data using (potentially nested) dictionaries with string keys is a common pattern in Python programs. :pep:`589` allows these values to be type checked when the exact type is known up-front, but it is hard to write read-only code that accepts more specific variants: for instance, where fields may be subtypes or restrict a union of possible types. This is an especially common issue when writing APIs for services, which may support a wide range of input structures, and typically do not need to modify their input.
-
-For illustration, we will try to add type hints to a function ``movie_string``::
-
- def movie_string(movie: Movie) -> str:
- if movie.get("year") is None:
- return movie["name"]
- else:
- return f'{movie["name"]} ({movie["year"]})'
-
-We could define this ``Movie`` type using a ``TypedDict``::
-
- from typing import NotRequired, TypedDict
-
- class Movie(TypedDict):
- name: str
- year: NotRequired[int | None]
-
-But suppose we have another type where year is required::
-
- class MovieRecord(TypedDict):
- name: str
- year: int
-
-Attempting to pass a ``MovieRecord`` into ``movie_string`` results in the error (using mypy):
-
-.. code-block:: text
-
- Argument 1 to "movie_string" has incompatible type "MovieRecord"; expected "Movie"
-
-This particular use case should be type-safe, but the type checker correctly stops the
-user from passing a ``MovieRecord`` into a ``Movie`` parameter in the general case, because
-the ``Movie`` class has mutator methods that could potentially allow the function to break
-the type constraints in ``MovieRecord`` (e.g. with ``movie["year"] = None`` or ``del movie["year"]``).
-The problem disappears if we don't have mutator methods in ``Movie``. This could be achieved by defining an immutable interface using a :pep:`544` :class:`~typing.Protocol`::
-
- from typing import Literal, Protocol, overload
-
- class Movie(Protocol):
- @overload
- def get(self, key: Literal["name"]) -> str: ...
-
- @overload
- def get(self, key: Literal["year"]) -> int | None: ...
-
- @overload
- def __getitem__(self, key: Literal["name"]) -> str: ...
-
- @overload
- def __getitem__(self, key: Literal["year"]) -> int | None: ...
-
-This is very repetitive, easy to get wrong, and is still missing important method definitions like ``__contains__()`` and ``keys()``.
-
-Rationale
-=========
-
-The proposed ``TypedMapping`` type allows a straightforward way of defining these types that should be familiar to existing users of ``TypedDict`` and support the cases exemplified above::
-
- from typing import NotRequired, TypedMapping
-
- class Movie(TypedMapping):
- name: str
- year: NotRequired[int | None]
-
-In addition to those benefits, by flagging arguments of a function as ``TypedMapping``, it makes explicit not just to typecheckers but also to users that the function is not going to modify its inputs, which is usually a desirable property of a function interface.
-Finally, this allows bringing the benefits of ``TypedDict`` to other mapping types that are unrelated to ``dict``.
-
-Specification
-=============
-
-A ``TypedMapping`` type defines a protocol with the same methods as :class:`~collections.abc.Mapping`, but with value types determined per-key as with ``TypedDict``.
-
-Notable similarities to ``TypedDict``:
-
-* A ``TypedMapping`` protocol can be declared using class-based or alternative syntax.
-* Keys must be strings.
-* By default, all specified keys must be present in a ``TypedMapping`` instance. It is possible to override this by specifying totality, or by using ``NotRequired`` from :pep:`655`.
-* Methods are not allowed in the declaration (though they may be inherited).
-
-Notable differences from ``TypedDict``:
-
-* The runtime type of a ``TypedMapping`` object is not constrained to be a ``dict``.
-* No mutator methods (``__setitem__``, ``__delitem__``, ``update``, etc.) will be generated.
-* The ``|`` operator is not supported.
-* A class definition defines a ``TypedMapping`` protocol if and only if ``TypedMapping`` appears directly in its class bases.
-* Subclasses can narrow value types, in the same manner as other protocols.
-
-As with :pep:`589`, this PEP provides a sketch of how a type checker is expected to support type checking operations involving ``TypedMapping`` and ``TypedDict`` objects, but details are left to implementors. In particular, type compatibility should be based on structural compatibility.
-
-
-Multiple inheritance and TypedDict
-----------------------------------
-
-A type that inherits from a ``TypedMapping`` protocol and from ``TypedDict`` (either directly or indirectly):
-
-* is the structural intersection of its parents, or invalid if no such intersection exists
-* instances must be a dict subclass
-* adds mutator methods only for fields it explicitly (re)declares
-
-For example::
-
- class Movie(TypedMapping):
- name: str
- year: int | None
-
- class MovieRecord(Movie, TypedDict):
- year: int
-
- movie: MovieRecord = { "name": "Blade Runner",
- "year": 1982 }
-
- movie["year"] = 1985 # Fine; mutator methods added in definition
- movie["name"] = "Terminator" # Type check error; "name" mutator not declared
-
-Inheriting, directly or indirectly, from both ``TypedDict`` and ``Protocol`` will continue to fail at runtime, and should continue to be rejected by type checkers.
-
-
-Multiple inheritance and Protocol
----------------------------------
-
-* A type that inherits from a ``TypedMapping`` protocol and from a ``Protocol`` protocol must satisfy the protocols defined by both, but is not itself a protocol unless it inherits directly from ``TypedMapping`` or ``Protocol``.
-* A type that inherits from a ``TypedMapping`` protocol and from ``Protocol`` itself is configured as a ``Protocol``. Methods and properties may be defined; keys may not::
-
- class A(Movie, Protocol):
- # Declare a mutable property called 'year'
- # This does not affect the dictionary key 'year'
- year: str
-
-* A type that inherits from a ``Protocol`` protocol and from ``TypedMapping`` itself is configured as a ``TypedMapping``. Keys may be defined; methods and properties may not::
-
- class B(A, TypedMapping):
- # Declare a key 'year'
- # This does not affect the property 'year'
- year: int
-
-
-Type consistency rules
-----------------------
-
-Informally speaking, *type consistency* is a generalization of the is-subtype-of relation to support the ``Any`` type. It is defined more formally in :pep:`483`. This section introduces the new, non-trivial rules needed to support type consistency for ``TypedMapping`` types.
-
-First, any ``TypedMapping`` type is consistent with ``Mapping[str, object]``.
-Second, a ``TypedMapping`` or ``TypedDict`` type ``A`` is consistent with ``TypedMapping`` ``B`` if ``A`` is structurally compatible with ``B``. This is true if and only if both of these conditions are satisfied:
-
-* For each key in ``A``, ``B`` has the corresponding key and the corresponding value type in ``B`` is consistent with the value type in ``A``.
-
-* For each required key in ``A``, the corresponding key is required in ``B``.
-
-Discussion:
-
-* Value types behave covariantly, since ``TypedMapping`` objects have no mutator methods. This is similar to container types such as ``Mapping``, and different from relationships between two ``TypedDict`` types. Example::
-
- class A(TypedMapping):
- x: int | None
-
- class B(TypedDict):
- x: int
-
- def f(a: A) -> None:
- print(a['x'] or 0)
-
- b: B = {'x': 0}
- f(b) # Accepted by type checker
-
-* A ``TypedDict`` or ``TypedMapping`` type with a required key is consistent with a ``TypedMapping`` type where the same key is a non-required key, again unlike relationships between two ``TypedDict`` types. Example::
-
- class A(TypedMapping, total=False):
- x: int
-
- class B(TypedDict):
- x: int
-
- def f(a: A) -> None:
- print(a.get('x', 0))
-
- b: B = {'x': 0}
- f(b) # Accepted by type checker
-
-* A ``TypedMapping`` type ``A`` with no key ``'x'`` is not consistent with a ``TypedMapping`` type with a non-required key ``'x'``, since at runtime the key ``'x'`` could be present and have an incompatible type (which may not be visible through ``A`` due to structural subtyping). This is the same as for ``TypedDict`` types. Example::
-
- class A(TypedMapping, total=False):
- x: int
- y: int
-
- class B(TypedMapping, total=False):
- x: int
-
- class C(TypedMapping, total=False):
- x: int
- y: str
-
- def f(a: A) -> None:
- print(a.get('y') + 1)
-
- def g(b: B) -> None:
- f(b) # Type check error: 'B' incompatible with 'A'
-
- c: C = {'x': 0, 'y': 'foo'}
- g(c) # Runtime error: str + int
-
-* A ``TypedMapping`` with all ``int`` values is not consistent with ``Mapping[str, int]``, since there may be additional non-``int`` values not visible through the type, due to structural subtyping. This mirrors ``TypedDict``. Example::
-
- class A(TypedMapping):
- x: int
-
- class B(TypedMapping):
- x: int
- y: str
-
- def sum_values(m: Mapping[str, int]) -> int:
- return sum(m.values())
-
- def f(a: A) -> None:
- sum_values(a) # Type check error: 'A' incompatible with Mapping[str, int]
-
- b: B = {'x': 0, 'y': 'foo'}
- f(b) # Runtime error: int + str
-
-
-Backwards Compatibility
-=======================
-
-This PEP changes the rules for how ``TypedDict`` behaves (allowing subclasses to
-inherit from ``TypedMapping`` protocols in a way that changes the resulting
-overloads), so code that inspects ``TypedDict`` types will have to change. This
-is expected to mainly affect type-checkers.
-
-The ``TypedMapping`` type will be added to the ``typing_extensions`` module,
-enabling its use in older versions of Python.
-
-
-Security Implications
-=====================
-
-There are no known security consequences arising from this PEP.
-
-
-How to Teach This
-=================
-
-Class documentation should be added to the :mod:`typing` module's documentation, using
-that for :class:`~collections.abc.Mapping`, :class:`~typing.Protocol` and
-:class:`~typing.TypedDict` as examples. Suggested introductory sentence: "Base class
-for read-only mapping protocol classes."
-
-This PEP could be added to the others listed in the :mod:`typing` module's documentation.
-
-
-Reference Implementation
-========================
-
-No reference implementation exists yet.
-
-
-Rejected Alternatives
-=====================
-
-Several variations were considered and discarded:
-
-* A ``readonly`` parameter to ``TypedDict``, behaving much like ``TypedMapping`` but with the additional constraint that instances must be dictionaries at runtime. This was discarded as less flexible due to the extra constraint; additionally, the new type nicely mirrors the existing ``Mapping``/``Dict`` types.
-* Inheriting from a ``TypedMapping`` subclass and ``TypedDict`` resulting in mutator methods being added for all fields, not just those actively (re)declared in the class body. Discarded as less flexible, and not matching how inheritance works in other cases for ``TypedDict`` (e.g. total=False and total=True do not affect fields not specified in the class body).
-* A generic type that removes mutator methods from its parameter, e.g. ``Readonly[MovieRecord]``. This would naturally want to be defined for a wider set of types than just ``TypedDict`` subclasses, and also raises questions about whether and how it applies to nested types. We decided to keep the scope of this PEP narrower.
-* Declaring methods directly on a ``TypedMapping`` class. Methods are a kind of property, but declarations on a ``TypedMapping`` class are defining keys, so mixing the two is potentially confusing. Banning methods also makes it very easy to decide whether a ``TypedDict`` subclass can mix in a protocol or not (yes if it's just ``TypedMapping`` superclasses, no if there's a ``Protocol``).
-
-
-Copyright
-=========
-This document is placed in the public domain or under the
-CC0-1.0-Universal license, whichever is more permissive.
diff --git a/pep_sphinx_extensions/__init__.py b/pep_sphinx_extensions/__init__.py
index 672a6a452..8538b838a 100644
--- a/pep_sphinx_extensions/__init__.py
+++ b/pep_sphinx_extensions/__init__.py
@@ -28,7 +28,7 @@ def _update_config_for_builder(app: Sphinx) -> None:
app.env.document_ids = {} # For PEPReferenceRoleTitleText
app.env.settings["builder"] = app.builder.name
if app.builder.name == "dirhtml":
- app.env.settings["pep_url"] = "pep-{:0>4}"
+ app.env.settings["pep_url"] = "pep-{:0>4}/"
app.connect("build-finished", _post_build) # Post-build tasks
diff --git a/pep_sphinx_extensions/generate_rss.py b/pep_sphinx_extensions/generate_rss.py
index a7120c9d6..5e5e0b8bc 100644
--- a/pep_sphinx_extensions/generate_rss.py
+++ b/pep_sphinx_extensions/generate_rss.py
@@ -17,9 +17,6 @@ RSS_DESCRIPTION = (
"and some meta-information like release procedure and schedules."
)
-# get the directory with the PEP sources
-PEP_ROOT = Path(__file__).parent
-
def _format_rfc_2822(datetime: dt.datetime) -> str:
datetime = datetime.replace(tzinfo=dt.timezone.utc)
diff --git a/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py b/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py
index a73bd2e9e..7349f712f 100644
--- a/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py
+++ b/pep_sphinx_extensions/pep_processor/html/pep_html_builder.py
@@ -1,5 +1,3 @@
-from pathlib import Path
-
from docutils import nodes
from docutils.frontend import OptionParser
from sphinx.builders.html import StandaloneHTMLBuilder
@@ -31,10 +29,6 @@ class FileBuilder(StandaloneHTMLBuilder):
except KeyError:
title = ""
- # source filename
- file_is_rst = Path(self.env.srcdir, docname + ".rst").exists()
- source_name = f"{docname}.rst" if file_is_rst else f"{docname}.txt"
-
# local table of contents
toc_tree = self.env.tocs[docname].deepcopy()
if len(toc_tree) and len(toc_tree[0]) > 1:
@@ -46,7 +40,7 @@ class FileBuilder(StandaloneHTMLBuilder):
else:
toc = "" # PEPs with no sections -- 9, 210
- return {"title": title, "sourcename": source_name, "toc": toc, "body": body}
+ return {"title": title, "toc": toc, "body": body}
class DirectoryBuilder(FileBuilder):
diff --git a/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py b/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py
index f3a55270c..d0f1cbee2 100644
--- a/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py
+++ b/pep_sphinx_extensions/pep_processor/parsing/pep_banner_directive.py
@@ -5,7 +5,6 @@ from __future__ import annotations
from docutils import nodes
from docutils.parsers import rst
-
PYPA_SPEC_BASE_URL = "https://packaging.python.org/en/latest/specifications/"
diff --git a/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py b/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py
index 7b9c29d51..c49355fd1 100644
--- a/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py
+++ b/pep_sphinx_extensions/pep_processor/transforms/pep_footer.py
@@ -1,4 +1,4 @@
-import datetime as dt
+import time
from pathlib import Path
import subprocess
@@ -23,7 +23,7 @@ class PEPFooter(transforms.Transform):
def apply(self) -> None:
pep_source_path = Path(self.document["source"])
- if not pep_source_path.match("pep-*"):
+ if not pep_source_path.match("pep-????.???"):
return # not a PEP file, exit early
# Iterate through sections from the end of the document
@@ -54,7 +54,7 @@ class PEPFooter(transforms.Transform):
def _add_source_link(pep_source_path: Path) -> nodes.paragraph:
"""Add link to source text on VCS (GitHub)"""
- source_link = f"https://github.com/python/peps/blob/main/{pep_source_path.name}"
+ source_link = f"https://github.com/python/peps/blob/main/peps/{pep_source_path.name}"
link_node = nodes.reference("", source_link, refuri=source_link)
return nodes.paragraph("", "Source: ", link_node)
@@ -62,12 +62,10 @@ def _add_source_link(pep_source_path: Path) -> nodes.paragraph:
def _add_commit_history_info(pep_source_path: Path) -> nodes.paragraph:
"""Use local git history to find last modified date."""
try:
- since_epoch = LAST_MODIFIED_TIMES[pep_source_path.name]
+ iso_time = _LAST_MODIFIED_TIMES[pep_source_path.stem]
except KeyError:
return nodes.paragraph()
- epoch_dt = dt.datetime.fromtimestamp(since_epoch, dt.timezone.utc)
- iso_time = epoch_dt.isoformat(sep=" ")
commit_link = f"https://github.com/python/peps/commits/main/{pep_source_path.name}"
link_node = nodes.reference("", f"{iso_time} GMT", refuri=commit_link)
return nodes.paragraph("", "Last modified: ", link_node)
@@ -75,29 +73,36 @@ def _add_commit_history_info(pep_source_path: Path) -> nodes.paragraph:
def _get_last_modified_timestamps():
# get timestamps and changed files from all commits (without paging results)
- args = ["git", "--no-pager", "log", "--format=#%at", "--name-only"]
- with subprocess.Popen(args, stdout=subprocess.PIPE) as process:
- all_modified = process.stdout.read().decode("utf-8")
- process.stdout.close()
- if process.wait(): # non-zero return code
- return {}
+ args = ("git", "--no-pager", "log", "--format=#%at", "--name-only")
+ ret = subprocess.run(args, stdout=subprocess.PIPE, text=True, encoding="utf-8")
+ if ret.returncode: # non-zero return code
+ return {}
+ all_modified = ret.stdout
+
+ # remove "peps/" prefix from file names
+ all_modified = all_modified.replace("\npeps/", "\n")
# set up the dictionary with the *current* files
- last_modified = {path.name: 0 for path in Path().glob("pep-*") if path.suffix in {".txt", ".rst"}}
+ peps_dir = Path(__file__, "..", "..", "..", "..", "peps").resolve()
+ last_modified = {path.stem: "" for path in peps_dir.glob("pep-????.rst")}
# iterate through newest to oldest, updating per file timestamps
change_sets = all_modified.removeprefix("#").split("#")
for change_set in change_sets:
timestamp, files = change_set.split("\n", 1)
for file in files.strip().split("\n"):
- if file.startswith("pep-") and file[-3:] in {"txt", "rst"}:
- if last_modified.get(file) == 0:
- try:
- last_modified[file] = float(timestamp)
- except ValueError:
- pass # if float conversion fails
+ if not file.startswith("pep-") or not file.endswith((".rst", ".txt")):
+ continue # not a PEP
+ file = file[:-4]
+ if last_modified.get(file) != "":
+ continue # most recent modified date already found
+ try:
+ y, m, d, hh, mm, ss, *_ = time.gmtime(float(timestamp))
+ except ValueError:
+ continue # if float conversion fails
+ last_modified[file] = f"{y:04}-{m:02}-{d:02} {hh:02}:{mm:02}:{ss:02}"
return last_modified
-LAST_MODIFIED_TIMES = _get_last_modified_timestamps()
+_LAST_MODIFIED_TIMES = _get_last_modified_timestamps()
diff --git a/pep_sphinx_extensions/pep_theme/static/style.css b/pep_sphinx_extensions/pep_theme/static/style.css
index f3c7cb16d..36393159a 100644
--- a/pep_sphinx_extensions/pep_theme/static/style.css
+++ b/pep_sphinx_extensions/pep_theme/static/style.css
@@ -230,6 +230,25 @@ table th + th,
table td + td {
border-left: 1px solid var(--colour-background-accent-strong);
}
+/* Common column widths for PEP status tables */
+table.pep-zero-table tr td:nth-child(1) {
+ width: 5%;
+}
+table.pep-zero-table tr td:nth-child(2) {
+ width: 7%;
+}
+table.pep-zero-table tr td:nth-child(3),
+table.pep-zero-table tr td:nth-child(4){
+ width: 41%;
+}
+table.pep-zero-table tr td:nth-child(5) {
+ width: 6%;
+}
+/* Authors & Sponsors table */
+#authors-owners table td,
+#authors-owners table th {
+ width: 50%;
+}
/* Breadcrumbs rules */
section#pep-page-section > header {
diff --git a/pep_sphinx_extensions/pep_theme/templates/page.html b/pep_sphinx_extensions/pep_theme/templates/page.html
index 2831fce0c..46be8c5bb 100644
--- a/pep_sphinx_extensions/pep_theme/templates/page.html
+++ b/pep_sphinx_extensions/pep_theme/templates/page.html
@@ -43,8 +43,8 @@
Contents
{{ toc }}
- {%- if not (sourcename.startswith("pep-0000") or sourcename.startswith("topic")) %}
- Page Source (GitHub)
+ {%- if not pagename.startswith(("pep-0000", "topic")) %}
+ Page Source (GitHub)
{%- endif %}
diff --git a/pep_sphinx_extensions/pep_zero_generator/author.py b/pep_sphinx_extensions/pep_zero_generator/author.py
deleted file mode 100644
index 4425c6b3c..000000000
--- a/pep_sphinx_extensions/pep_zero_generator/author.py
+++ /dev/null
@@ -1,89 +0,0 @@
-from __future__ import annotations
-
-from typing import NamedTuple
-
-
-class _Name(NamedTuple):
- mononym: str = None
- forename: str = None
- surname: str = None
- suffix: str = None
-
-
-class Author(NamedTuple):
- """Represent PEP authors."""
- last_first: str # The author's name in Surname, Forename, Suffix order.
- nick: str # Author's nickname for PEP tables. Defaults to surname.
- email: str # The author's email address.
-
-
-def parse_author_email(author_email_tuple: tuple[str, str], authors_overrides: dict[str, dict[str, str]]) -> Author:
- """Parse the name and email address of an author."""
- name, email = author_email_tuple
- _first_last = name.strip()
- email = email.lower()
-
- if _first_last in authors_overrides:
- name_dict = authors_overrides[_first_last]
- last_first = name_dict["Surname First"]
- nick = name_dict["Name Reference"]
- return Author(last_first, nick, email)
-
- name_parts = _parse_name(_first_last)
- if name_parts.mononym is not None:
- return Author(name_parts.mononym, name_parts.mononym, email)
-
- if name_parts.suffix:
- last_first = f"{name_parts.surname}, {name_parts.forename}, {name_parts.suffix}"
- return Author(last_first, name_parts.surname, email)
-
- last_first = f"{name_parts.surname}, {name_parts.forename}"
- return Author(last_first, name_parts.surname, email)
-
-
-def _parse_name(full_name: str) -> _Name:
- """Decompose a full name into parts.
-
- If a mononym (e.g, 'Aahz') then return the full name. If there are
- suffixes in the name (e.g. ', Jr.' or 'II'), then find and extract
- them. If there is a middle initial followed by a full stop, then
- combine the following words into a surname (e.g. N. Vander Weele). If
- there is a leading, lowercase portion to the last name (e.g. 'van' or
- 'von') then include it in the surname.
-
- """
- possible_suffixes = {"Jr", "Jr.", "II", "III"}
-
- pre_suffix, _, raw_suffix = full_name.partition(",")
- name_parts = pre_suffix.strip().split(" ")
- num_parts = len(name_parts)
- suffix = raw_suffix.strip()
-
- if name_parts == [""]:
- raise ValueError("Name is empty!")
- elif num_parts == 1:
- return _Name(mononym=name_parts[0], suffix=suffix)
- elif num_parts == 2:
- return _Name(forename=name_parts[0].strip(), surname=name_parts[1], suffix=suffix)
-
- # handles rogue uncaught suffixes
- if name_parts[-1] in possible_suffixes:
- suffix = f"{name_parts.pop(-1)} {suffix}".strip()
-
- # handles von, van, v. etc.
- if name_parts[-2].islower():
- forename = " ".join(name_parts[:-2]).strip()
- surname = " ".join(name_parts[-2:])
- return _Name(forename=forename, surname=surname, suffix=suffix)
-
- # handles double surnames after a middle initial (e.g. N. Vander Weele)
- elif any(s.endswith(".") for s in name_parts):
- split_position = [i for i, x in enumerate(name_parts) if x.endswith(".")][-1] + 1
- forename = " ".join(name_parts[:split_position]).strip()
- surname = " ".join(name_parts[split_position:])
- return _Name(forename=forename, surname=surname, suffix=suffix)
-
- # default to using the last item as the surname
- else:
- forename = " ".join(name_parts[:-1]).strip()
- return _Name(forename=forename, surname=name_parts[-1], suffix=suffix)
diff --git a/pep_sphinx_extensions/pep_zero_generator/parser.py b/pep_sphinx_extensions/pep_zero_generator/parser.py
index 220ef308c..bd8bf9e68 100644
--- a/pep_sphinx_extensions/pep_zero_generator/parser.py
+++ b/pep_sphinx_extensions/pep_zero_generator/parser.py
@@ -2,13 +2,10 @@
from __future__ import annotations
-import csv
+import dataclasses
from email.parser import HeaderParser
from pathlib import Path
-import re
-from typing import TYPE_CHECKING
-from pep_sphinx_extensions.pep_zero_generator.author import parse_author_email
from pep_sphinx_extensions.pep_zero_generator.constants import ACTIVE_ALLOWED
from pep_sphinx_extensions.pep_zero_generator.constants import HIDE_STATUS
from pep_sphinx_extensions.pep_zero_generator.constants import SPECIAL_STATUSES
@@ -19,16 +16,12 @@ from pep_sphinx_extensions.pep_zero_generator.constants import TYPE_STANDARDS
from pep_sphinx_extensions.pep_zero_generator.constants import TYPE_VALUES
from pep_sphinx_extensions.pep_zero_generator.errors import PEPError
-if TYPE_CHECKING:
- from pep_sphinx_extensions.pep_zero_generator.author import Author
-
-# AUTHOR_OVERRIDES.csv is an exception file for PEP 0 name parsing
-AUTHOR_OVERRIDES: dict[str, dict[str, str]] = {}
-with open("AUTHOR_OVERRIDES.csv", "r", encoding="utf-8") as f:
- for line in csv.DictReader(f):
- full_name = line.pop("Overridden Name")
- AUTHOR_OVERRIDES[full_name] = line
+@dataclasses.dataclass(order=True, frozen=True)
+class _Author:
+ """Represent PEP authors."""
+ full_name: str # The author's name.
+ email: str # The author's email address.
class PEP:
@@ -97,7 +90,9 @@ class PEP:
self.status: str = status
# Parse PEP authors
- self.authors: list[Author] = _parse_authors(self, metadata["Author"], AUTHOR_OVERRIDES)
+ self.authors: list[_Author] = _parse_author(metadata["Author"])
+ if not self.authors:
+ raise _raise_pep_error(self, "no authors found", pep_num=True)
# Topic (for sub-indices)
_topic = metadata.get("Topic", "").lower().split(",")
@@ -144,7 +139,9 @@ class PEP:
# a tooltip representing the type and status
"shorthand": self.shorthand,
# the author list as a comma-separated with only last names
- "authors": ", ".join(author.nick for author in self.authors),
+ "authors": ", ".join(author.full_name for author in self.authors),
+ # The targeted Python-Version (if present) or the empty string
+ "python_version": self.python_version or "",
}
@property
@@ -153,7 +150,7 @@ class PEP:
return {
"number": self.number,
"title": self.title,
- "authors": ", ".join(author.nick for author in self.authors),
+ "authors": ", ".join(author.full_name for author in self.authors),
"discussions_to": self.discussions_to,
"status": self.status,
"type": self.pep_type,
@@ -175,41 +172,27 @@ def _raise_pep_error(pep: PEP, msg: str, pep_num: bool = False) -> None:
raise PEPError(msg, pep.filename)
-def _parse_authors(pep: PEP, author_header: str, authors_overrides: dict) -> list[Author]:
- """Parse Author header line"""
- authors_and_emails = _parse_author(author_header)
- if not authors_and_emails:
- raise _raise_pep_error(pep, "no authors found", pep_num=True)
- return [parse_author_email(author_tuple, authors_overrides) for author_tuple in authors_and_emails]
+jr_placeholder = ",Jr"
-author_angled = re.compile(r"(?P.+?) <(?P.+?)>(,\s*)?")
-author_paren = re.compile(r"(?P.+?) \((?P.+?)\)(,\s*)?")
-author_simple = re.compile(r"(?P[^,]+)(,\s*)?")
-
-
-def _parse_author(data: str) -> list[tuple[str, str]]:
+def _parse_author(data: str) -> list[_Author]:
"""Return a list of author names and emails."""
author_list = []
- for regex in (author_angled, author_paren, author_simple):
- for match in regex.finditer(data):
- # Watch out for suffixes like 'Jr.' when they are comma-separated
- # from the name and thus cause issues when *all* names are only
- # separated by commas.
- match_dict = match.groupdict()
- author = match_dict["author"]
- if not author.partition(" ")[1] and author.endswith("."):
- prev_author = author_list.pop()
- author = ", ".join([prev_author, author])
- if "email" not in match_dict:
- email = ""
- else:
- email = match_dict["email"]
- author_list.append((author, email))
+ data = (data.replace("\n", " ")
+ .replace(", Jr", jr_placeholder)
+ .rstrip().removesuffix(","))
+ for author_email in data.split(", "):
+ if ' <' in author_email:
+ author, email = author_email.removesuffix(">").split(" <")
+ else:
+ author, email = author_email, ""
- # If authors were found then stop searching as only expect one
- # style of author citation.
- if author_list:
- break
+ author = author.strip()
+ if author == "":
+ raise ValueError("Name is empty!")
+
+ author = author.replace(jr_placeholder, ", Jr")
+ email = email.lower()
+ author_list.append(_Author(author, email))
return author_list
diff --git a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py
index e2c1a7963..8fbf5cc7e 100644
--- a/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py
+++ b/pep_sphinx_extensions/pep_zero_generator/pep_index_generator.py
@@ -18,22 +18,22 @@ to allow it to be processed as normal.
from __future__ import annotations
import json
+import os
from pathlib import Path
from typing import TYPE_CHECKING
-from pep_sphinx_extensions.pep_zero_generator.constants import SUBINDICES_BY_TOPIC
from pep_sphinx_extensions.pep_zero_generator import parser
from pep_sphinx_extensions.pep_zero_generator import subindices
from pep_sphinx_extensions.pep_zero_generator import writer
+from pep_sphinx_extensions.pep_zero_generator.constants import SUBINDICES_BY_TOPIC
if TYPE_CHECKING:
from sphinx.application import Sphinx
from sphinx.environment import BuildEnvironment
-def _parse_peps() -> list[parser.PEP]:
+def _parse_peps(path: Path) -> list[parser.PEP]:
# Read from root directory
- path = Path(".")
peps: list[parser.PEP] = []
for file_path in path.iterdir():
@@ -41,7 +41,7 @@ def _parse_peps() -> list[parser.PEP]:
continue # Skip directories etc.
if file_path.match("pep-0000*"):
continue # Skip pre-existing PEP 0 files
- if file_path.match("pep-????.???") and file_path.suffix in {".txt", ".rst"}:
+ if file_path.match("pep-????.rst"):
pep = parser.PEP(path.joinpath(file_path).absolute())
peps.append(pep)
@@ -52,8 +52,16 @@ def create_pep_json(peps: list[parser.PEP]) -> str:
return json.dumps({pep.number: pep.full_details for pep in peps}, indent=1)
+def write_peps_json(peps: list[parser.PEP], path: Path) -> None:
+ # Create peps.json
+ json_peps = create_pep_json(peps)
+ Path(path, "peps.json").write_text(json_peps, encoding="utf-8")
+ os.makedirs(os.path.join(path, "api"), exist_ok=True)
+ Path(path, "api", "peps.json").write_text(json_peps, encoding="utf-8")
+
+
def create_pep_zero(app: Sphinx, env: BuildEnvironment, docnames: list[str]) -> None:
- peps = _parse_peps()
+ peps = _parse_peps(Path(app.srcdir))
pep0_text = writer.PEPZeroWriter().write_pep0(peps, builder=env.settings["builder"])
pep0_path = subindices.update_sphinx("pep-0000", pep0_text, docnames, env)
@@ -61,7 +69,4 @@ def create_pep_zero(app: Sphinx, env: BuildEnvironment, docnames: list[str]) ->
subindices.generate_subindices(SUBINDICES_BY_TOPIC, peps, docnames, env)
- # Create peps.json
- json_path = Path(app.outdir, "api", "peps.json").resolve()
- json_path.parent.mkdir(exist_ok=True)
- json_path.write_text(create_pep_json(peps), encoding="utf-8")
+ write_peps_json(peps, Path(app.outdir))
diff --git a/pep_sphinx_extensions/pep_zero_generator/subindices.py b/pep_sphinx_extensions/pep_zero_generator/subindices.py
index 455a49dd8..3f61b3dd4 100644
--- a/pep_sphinx_extensions/pep_zero_generator/subindices.py
+++ b/pep_sphinx_extensions/pep_zero_generator/subindices.py
@@ -2,6 +2,7 @@
from __future__ import annotations
+import os
from pathlib import Path
from typing import TYPE_CHECKING
@@ -14,8 +15,7 @@ if TYPE_CHECKING:
def update_sphinx(filename: str, text: str, docnames: list[str], env: BuildEnvironment) -> Path:
- file_path = Path(f"{filename}.rst").resolve()
- file_path.parent.mkdir(parents=True, exist_ok=True)
+ file_path = Path(env.srcdir, f"{filename}.rst")
file_path.write_text(text, encoding="utf-8")
# Add to files for builder
@@ -32,6 +32,9 @@ def generate_subindices(
docnames: list[str],
env: BuildEnvironment,
) -> None:
+ # create topic directory
+ os.makedirs(os.path.join(env.srcdir, "topic"), exist_ok=True)
+
# Create sub index page
generate_topic_contents(docnames, env)
diff --git a/pep_sphinx_extensions/pep_zero_generator/writer.py b/pep_sphinx_extensions/pep_zero_generator/writer.py
index b6171f731..f8232d0ce 100644
--- a/pep_sphinx_extensions/pep_zero_generator/writer.py
+++ b/pep_sphinx_extensions/pep_zero_generator/writer.py
@@ -2,14 +2,11 @@
from __future__ import annotations
-import datetime as dt
from typing import TYPE_CHECKING
import unicodedata
-from pep_sphinx_extensions.pep_processor.transforms.pep_headers import (
- ABBREVIATED_STATUSES,
- ABBREVIATED_TYPES,
-)
+from pep_sphinx_extensions.pep_processor.transforms.pep_headers import ABBREVIATED_STATUSES
+from pep_sphinx_extensions.pep_processor.transforms.pep_headers import ABBREVIATED_TYPES
from pep_sphinx_extensions.pep_zero_generator.constants import DEAD_STATUSES
from pep_sphinx_extensions.pep_zero_generator.constants import STATUS_ACCEPTED
from pep_sphinx_extensions.pep_zero_generator.constants import STATUS_ACTIVE
@@ -29,11 +26,10 @@ from pep_sphinx_extensions.pep_zero_generator.errors import PEPError
if TYPE_CHECKING:
from pep_sphinx_extensions.pep_zero_generator.parser import PEP
-HEADER = f"""\
+HEADER = """\
PEP: 0
Title: Index of Python Enhancement Proposals (PEPs)
-Last-Modified: {dt.date.today()}
-Author: python-dev
+Author: The PEP Editors
Status: Active
Type: Informational
Content-Type: text/x-rst
@@ -78,14 +74,22 @@ class PEPZeroWriter:
self.output.append(author_table_separator)
def emit_pep_row(
- self, *, shorthand: str, number: int, title: str, authors: str
+ self,
+ *,
+ shorthand: str,
+ number: int,
+ title: str,
+ authors: str,
+ python_version: str | None = None,
) -> None:
self.emit_text(f" * - {shorthand}")
self.emit_text(f" - :pep:`{number} <{number}>`")
self.emit_text(f" - :pep:`{title.replace('`', '')} <{number}>`")
self.emit_text(f" - {authors}")
+ if python_version is not None:
+ self.emit_text(f" - {python_version}")
- def emit_column_headers(self) -> None:
+ def emit_column_headers(self, *, include_version=True) -> None:
"""Output the column headers for the PEP indices."""
self.emit_text(".. list-table::")
self.emit_text(" :header-rows: 1")
@@ -96,6 +100,8 @@ class PEPZeroWriter:
self.emit_text(" - PEP")
self.emit_text(" - Title")
self.emit_text(" - Authors")
+ if include_version:
+ self.emit_text(" - ") # for Python-Version
def emit_title(self, text: str, *, symbol: str = "=") -> None:
self.output.append(text)
@@ -105,17 +111,25 @@ class PEPZeroWriter:
def emit_subtitle(self, text: str) -> None:
self.emit_title(text, symbol="-")
+ def emit_table(self, peps: list[PEP]) -> None:
+ include_version = any(pep.details["python_version"] for pep in peps)
+ self.emit_column_headers(include_version=include_version)
+ for pep in peps:
+ details = pep.details
+ if not include_version:
+ details.pop("python_version")
+ self.emit_pep_row(**details)
+
def emit_pep_category(self, category: str, peps: list[PEP]) -> None:
self.emit_subtitle(category)
- self.emit_column_headers()
- for pep in peps:
- self.emit_pep_row(**pep.details)
+ self.emit_table(peps)
# list-table must have at least one body row
if len(peps) == 0:
self.emit_text(" * -")
self.emit_text(" -")
self.emit_text(" -")
self.emit_text(" -")
+ self.emit_text(" -")
self.emit_newline()
def write_pep0(
@@ -149,7 +163,7 @@ class PEPZeroWriter:
target = (
f"topic/{subindex}.html"
if builder == "html"
- else f"../topic/{subindex}"
+ else f"../topic/{subindex}/"
)
self.emit_text(f"* `{subindex.title()} PEPs <{target}>`_")
self.emit_newline()
@@ -184,19 +198,21 @@ class PEPZeroWriter:
# PEPs by number
self.emit_title("Numerical Index")
- self.emit_column_headers()
- for pep in peps:
- self.emit_pep_row(**pep.details)
+ self.emit_table(peps)
self.emit_newline()
# Reserved PEP numbers
if is_pep0:
self.emit_title("Reserved PEP Numbers")
- self.emit_column_headers()
+ self.emit_column_headers(include_version=False)
for number, claimants in sorted(self.RESERVED.items()):
self.emit_pep_row(
- shorthand="", number=number, title="RESERVED", authors=claimants
+ shorthand="",
+ number=number,
+ title="RESERVED",
+ authors=claimants,
+ python_version=None,
)
self.emit_newline()
@@ -241,7 +257,7 @@ class PEPZeroWriter:
self.emit_newline()
self.emit_newline()
- pep0_string = "\n".join([str(s) for s in self.output])
+ pep0_string = "\n".join(map(str, self.output))
return pep0_string
@@ -297,22 +313,22 @@ def _verify_email_addresses(peps: list[PEP]) -> dict[str, str]:
for pep in peps:
for author in pep.authors:
# If this is the first time we have come across an author, add them.
- if author.last_first not in authors_dict:
- authors_dict[author.last_first] = set()
+ if author.full_name not in authors_dict:
+ authors_dict[author.full_name] = set()
# If the new email is an empty string, move on.
if not author.email:
continue
# If the email has not been seen, add it to the list.
- authors_dict[author.last_first].add(author.email)
+ authors_dict[author.full_name].add(author.email)
valid_authors_dict: dict[str, str] = {}
too_many_emails: list[tuple[str, set[str]]] = []
- for last_first, emails in authors_dict.items():
+ for full_name, emails in authors_dict.items():
if len(emails) > 1:
- too_many_emails.append((last_first, emails))
+ too_many_emails.append((full_name, emails))
else:
- valid_authors_dict[last_first] = next(iter(emails), "")
+ valid_authors_dict[full_name] = next(iter(emails), "")
if too_many_emails:
err_output = []
for author, emails in too_many_emails:
diff --git a/pep_sphinx_extensions/tests/conftest.py b/pep_sphinx_extensions/tests/conftest.py
new file mode 100644
index 000000000..15f3c907b
--- /dev/null
+++ b/pep_sphinx_extensions/tests/conftest.py
@@ -0,0 +1,12 @@
+import importlib.util
+import sys
+from pathlib import Path
+
+_ROOT_PATH = Path(__file__, "..", "..", "..").resolve()
+PEP_ROOT = _ROOT_PATH / "peps"
+
+# Import "check-peps.py" as "check_peps"
+CHECK_PEPS_PATH = _ROOT_PATH / "check-peps.py"
+spec = importlib.util.spec_from_file_location("check_peps", CHECK_PEPS_PATH)
+sys.modules["check_peps"] = check_peps = importlib.util.module_from_spec(spec)
+spec.loader.exec_module(check_peps)
diff --git a/pep_sphinx_extensions/tests/pep_lint/__init__.py b/pep_sphinx_extensions/tests/pep_lint/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/pep_sphinx_extensions/tests/pep_lint/test_date.py b/pep_sphinx_extensions/tests/pep_lint/test_date.py
new file mode 100644
index 000000000..2218fc2a0
--- /dev/null
+++ b/pep_sphinx_extensions/tests/pep_lint/test_date.py
@@ -0,0 +1,105 @@
+import datetime as dt
+
+import check_peps # NoQA: inserted into sys.modules in conftest.py
+import pytest
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ # valid entries
+ "01-Jan-2000",
+ "29-Feb-2016",
+ "31-Dec-2000",
+ "01-Apr-2003",
+ "01-Apr-2007",
+ "01-Apr-2009",
+ "01-Jan-1990",
+ ],
+)
+def test_validate_created(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_created(1, line)]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "date_str",
+ [
+ # valid entries
+ "01-Jan-2000",
+ "29-Feb-2016",
+ "31-Dec-2000",
+ "01-Apr-2003",
+ "01-Apr-2007",
+ "01-Apr-2009",
+ "01-Jan-1990",
+ ],
+)
+def test_date_checker_valid(date_str: str):
+ warnings = [warning for (_, warning) in check_peps._date(1, date_str, "")]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "date_str",
+ [
+ # malformed
+ "2000-01-01",
+ "01 January 2000",
+ "1 Jan 2000",
+ "1-Jan-2000",
+ "1-January-2000",
+ "Jan-1-2000",
+ "January 1 2000",
+ "January 01 2000",
+ "01/01/2000",
+ "01/Jan/2000", # 🇬🇧, 🇦🇺, 🇨🇦, 🇳🇿, 🇮🇪 , ...
+ "Jan/01/2000", # 🇺🇸
+ "1st January 2000",
+ "The First day of January in the year of Our Lord Two Thousand",
+ "Jan, 1, 2000",
+ "2000-Jan-1",
+ "2000-Jan-01",
+ "2000-January-1",
+ "2000-January-01",
+ "00 Jan 2000",
+ "00-Jan-2000",
+ ],
+)
+def test_date_checker_malformed(date_str: str):
+ warnings = [warning for (_, warning) in check_peps._date(1, date_str, "")]
+ expected = f" must be a 'DD-mmm-YYYY' date: {date_str!r}"
+ assert warnings == [expected], warnings
+
+
+@pytest.mark.parametrize(
+ "date_str",
+ [
+ # too early
+ "31-Dec-1989",
+ "01-Apr-1916",
+ "01-Jan-0020",
+ "01-Jan-0023",
+ ],
+)
+def test_date_checker_too_early(date_str: str):
+ warnings = [warning for (_, warning) in check_peps._date(1, date_str, "")]
+ expected = f" must not be before Python was invented: {date_str!r}"
+ assert warnings == [expected], warnings
+
+
+@pytest.mark.parametrize(
+ "date_str",
+ [
+ # the future
+ "31-Dec-2999",
+ "01-Jan-2042",
+ "01-Jan-2100",
+ (dt.datetime.now() + dt.timedelta(days=15)).strftime("%d-%b-%Y"),
+ (dt.datetime.now() + dt.timedelta(days=100)).strftime("%d-%b-%Y"),
+ ],
+)
+def test_date_checker_too_late(date_str: str):
+ warnings = [warning for (_, warning) in check_peps._date(1, date_str, "")]
+ expected = f" must not be in the future: {date_str!r}"
+ assert warnings == [expected], warnings
diff --git a/pep_sphinx_extensions/tests/pep_lint/test_direct_links.py b/pep_sphinx_extensions/tests/pep_lint/test_direct_links.py
new file mode 100644
index 000000000..66edc0552
--- /dev/null
+++ b/pep_sphinx_extensions/tests/pep_lint/test_direct_links.py
@@ -0,0 +1,30 @@
+import check_peps # NoQA: inserted into sys.modules in conftest.py
+import pytest
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "http://www.python.org/dev/peps/pep-0000/",
+ "https://www.python.org/dev/peps/pep-0000/",
+ "http://peps.python.org/pep-0000/",
+ "https://peps.python.org/pep-0000/",
+ ],
+)
+def test_check_direct_links_pep(line: str):
+ warnings = [warning for (_, warning) in check_peps.check_direct_links(1, line)]
+ assert warnings == ["Use the :pep:`NNN` role to refer to PEPs"], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "http://www.rfc-editor.org/rfc/rfc2324",
+ "https://www.rfc-editor.org/rfc/rfc2324",
+ "http://datatracker.ietf.org/doc/html/rfc2324",
+ "https://datatracker.ietf.org/doc/html/rfc2324",
+ ],
+)
+def test_check_direct_links_rfc(line: str):
+ warnings = [warning for (_, warning) in check_peps.check_direct_links(1, line)]
+ assert warnings == ["Use the :rfc:`NNN` role to refer to RFCs"], warnings
diff --git a/pep_sphinx_extensions/tests/pep_lint/test_email.py b/pep_sphinx_extensions/tests/pep_lint/test_email.py
new file mode 100644
index 000000000..d9f19592d
--- /dev/null
+++ b/pep_sphinx_extensions/tests/pep_lint/test_email.py
@@ -0,0 +1,238 @@
+import check_peps # NoQA: inserted into sys.modules in conftest.py
+import pytest
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "Alice",
+ "Alice,",
+ "Alice, Bob, Charlie",
+ "Alice,\nBob,\nCharlie",
+ "Alice,\n Bob,\n Charlie",
+ "Alice,\n Bob,\n Charlie",
+ "Cardinal Ximénez",
+ "Alice ",
+ "Cardinal Ximénez ",
+ ],
+ ids=repr, # the default calls str and renders newlines.
+)
+def test_validate_author(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_author(1, line)]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "Alice,\n Bob,\n Charlie",
+ "Alice,\n Bob,\n Charlie",
+ "Alice,\n Bob,\n Charlie",
+ "Alice,\n Bob",
+ ],
+ ids=repr, # the default calls str and renders newlines.
+)
+def test_validate_author_over__indented(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_author(1, line)]
+ assert {*warnings} == {"Author line must not be over-indented"}, warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "Cardinal Ximénez\nCardinal Biggles\nCardinal Fang",
+ "Cardinal Ximénez,\nCardinal Biggles\nCardinal Fang",
+ "Cardinal Ximénez\nCardinal Biggles,\nCardinal Fang",
+ ],
+ ids=repr, # the default calls str and renders newlines.
+)
+def test_validate_author_continuation(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_author(1, line)]
+ assert {*warnings} == {"Author continuation lines must end with a comma"}, warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "Alice",
+ "Cardinal Ximénez",
+ "Alice ",
+ "Cardinal Ximénez ",
+ ],
+)
+def test_validate_sponsor(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_sponsor(1, line)]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "",
+ "Alice, Bob, Charlie",
+ "Alice, Bob, Charlie,",
+ "Alice ",
+ "Cardinal Ximénez ",
+ ],
+)
+def test_validate_delegate(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_delegate(1, line)]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ ("email", "expected_warnings"),
+ [
+ # ... entries must not contain multiple '...'
+ ("Cardinal Ximénez <<", {"multiple <"}),
+ ("Cardinal Ximénez <<<", {"multiple <"}),
+ ("Cardinal Ximénez >>", {"multiple >"}),
+ ("Cardinal Ximénez >>>", {"multiple >"}),
+ ("Cardinal Ximénez <<<>>>", {"multiple <", "multiple >"}),
+ ("Cardinal Ximénez @@", {"multiple @"}),
+ ("Cardinal Ximénez <<@@@>", {"multiple <", "multiple @"}),
+ ("Cardinal Ximénez <@@@>>", {"multiple >", "multiple @"}),
+ ("Cardinal Ximénez <<@@>>", {"multiple <", "multiple >", "multiple @"}),
+ # valid names
+ ("Cardinal Ximénez", set()),
+ (" Cardinal Ximénez", set()),
+ ("\t\tCardinal Ximénez", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez\t\t", set()),
+ ("Cardinal O'Ximénez", set()),
+ ("Cardinal Ximénez, Inquisitor", set()),
+ ("Cardinal Ximénez-Biggles", set()),
+ ("Cardinal Ximénez-Biggles, Inquisitor", set()),
+ ("Cardinal T. S. I. Ximénez", set()),
+ # ... entries must have a valid 'Name'
+ ("Cardinal_Ximénez", {"valid name"}),
+ ("Cardinal Ximénez 3", {"valid name"}),
+ ("~ Cardinal Ximénez ~", {"valid name"}),
+ ("Cardinal Ximénez!", {"valid name"}),
+ ("@Cardinal Ximénez", {"valid name"}),
+ ("Cardinal_Ximénez <>", {"valid name"}),
+ ("Cardinal Ximénez 3 <>", {"valid name"}),
+ ("~ Cardinal Ximénez ~ <>", {"valid name"}),
+ ("Cardinal Ximénez! <>", {"valid name"}),
+ ("@Cardinal Ximénez <>", {"valid name"}),
+ # ... entries must be formatted as 'Name '
+ ("Cardinal Ximénez<>", {"name "}),
+ ("Cardinal Ximénez<", {"name "}),
+ ("Cardinal Ximénez <", {"name "}),
+ ("Cardinal Ximénez <", {"name "}),
+ ("Cardinal Ximénez <>", {"name "}),
+ # ... entries must contain a valid email address (missing)
+ ("Cardinal Ximénez <>", {"valid email"}),
+ ("Cardinal Ximénez <> ", {"valid email"}),
+ ("Cardinal Ximénez <@> ", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez < at > ", {"valid email"}),
+ # ... entries must contain a valid email address (local)
+ ("Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez < Cardinal Ximenez @spanish.inquisition> ", {"valid email"}),
+ ("Cardinal Ximénez <(Cardinal.Ximenez)@spanish.inquisition>", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ (
+ "Cardinal Ximénez ",
+ {"multiple <", "multiple >", "valid email"},
+ ),
+ (
+ "Cardinal Ximénez ",
+ {"multiple @", "valid email"},
+ ),
+ (r"Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez <[Cardinal.Ximenez]@spanish.inquisition>", {"valid email"}),
+ ('Cardinal Ximénez <"Cardinal"Ximenez"@spanish.inquisition>', {"valid email"}),
+ ("Cardinal Ximenez ", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ # ... entries must contain a valid email address (domain)
+ (
+ "Cardinal Ximénez ",
+ {"valid email"},
+ ),
+ ("Cardinal Ximénez ", {"valid email"}),
+ ("Cardinal Ximénez ", {"valid email"}),
+ (
+ "Cardinal Ximénez ",
+ {"valid email"},
+ ),
+ # valid name-emails
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez <{Cardinal.Ximenez}@spanish.inquisition>", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ("Cardinal Ximénez ", set()),
+ ],
+ # call str() on each parameterised value in the test ID.
+ ids=str,
+)
+def test_email_checker(email: str, expected_warnings: set):
+ warnings = [warning for (_, warning) in check_peps._email(1, email, "")]
+
+ found_warnings = set()
+ email = email.strip()
+
+ if "multiple <" in expected_warnings:
+ found_warnings.add("multiple <")
+ expected = f" entries must not contain multiple '<': {email!r}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "multiple >" in expected_warnings:
+ found_warnings.add("multiple >")
+ expected = f" entries must not contain multiple '>': {email!r}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "multiple @" in expected_warnings:
+ found_warnings.add("multiple @")
+ expected = f" entries must not contain multiple '@': {email!r}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "valid name" in expected_warnings:
+ found_warnings.add("valid name")
+ expected = f" entries must begin with a valid 'Name': {email!r}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "name " in expected_warnings:
+ found_warnings.add("name ")
+ expected = f" entries must be formatted as 'Name ': {email!r}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "valid email" in expected_warnings:
+ found_warnings.add("valid email")
+ expected = f" entries must contain a valid email address: {email!r}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if expected_warnings == set():
+ assert warnings == [], warnings
+
+ assert found_warnings == expected_warnings
diff --git a/pep_sphinx_extensions/tests/pep_lint/test_headers.py b/pep_sphinx_extensions/tests/pep_lint/test_headers.py
new file mode 100644
index 000000000..227eb5397
--- /dev/null
+++ b/pep_sphinx_extensions/tests/pep_lint/test_headers.py
@@ -0,0 +1,408 @@
+import check_peps # NoQA: inserted into sys.modules in conftest.py
+import pytest
+
+
+@pytest.mark.parametrize(
+ ("test_input", "expected"),
+ [
+ # capitalisation
+ ("Header:", "Header"),
+ ("header:", "header"),
+ ("hEADER:", "hEADER"),
+ ("hEaDeR:", "hEaDeR"),
+ # trailing spaces
+ ("Header: ", "Header"),
+ ("Header: ", "Header"),
+ ("Header: \t", "Header"),
+ # trailing content
+ ("Header: Text", "Header"),
+ ("Header: 123", "Header"),
+ ("Header: !", "Header"),
+ # separators
+ ("Hyphenated-Header:", "Hyphenated-Header"),
+ ],
+)
+def test_header_pattern(test_input, expected):
+ assert check_peps.HEADER_PATTERN.match(test_input)[1] == expected
+
+
+@pytest.mark.parametrize(
+ "test_input",
+ [
+ # trailing content
+ "Header:Text",
+ "Header:123",
+ "Header:!",
+ # colon position
+ "Header",
+ "Header : ",
+ "Header :",
+ "SemiColonHeader;",
+ # separators
+ "Underscored_Header:",
+ "Spaced Header:",
+ "Plus+Header:",
+ ],
+)
+def test_header_pattern_no_match(test_input):
+ assert check_peps.HEADER_PATTERN.match(test_input) is None
+
+
+def test_validate_required_headers():
+ found_headers = dict.fromkeys(
+ ("PEP", "Title", "Author", "Status", "Type", "Created")
+ )
+ warnings = [
+ warning for (_, warning) in check_peps._validate_required_headers(found_headers)
+ ]
+ assert warnings == [], warnings
+
+
+def test_validate_required_headers_missing():
+ found_headers = dict.fromkeys(("PEP", "Title", "Author", "Type"))
+ warnings = [
+ warning for (_, warning) in check_peps._validate_required_headers(found_headers)
+ ]
+ assert warnings == [
+ "Must have required header: Status",
+ "Must have required header: Created",
+ ], warnings
+
+
+def test_validate_required_headers_order():
+ found_headers = dict.fromkeys(
+ ("PEP", "Title", "Sponsor", "Author", "Type", "Status", "Replaces", "Created")
+ )
+ warnings = [
+ warning for (_, warning) in check_peps._validate_required_headers(found_headers)
+ ]
+ assert warnings == [
+ "Headers must be in PEP 12 order. Correct order: PEP, Title, Author, Sponsor, Status, Type, Created, Replaces"
+ ], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "!",
+ "The Zen of Python",
+ "A title that is exactly 79 characters long, but shorter than 80 characters long",
+ ],
+)
+def test_validate_title(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_title(1, line)]
+ assert warnings == [], warnings
+
+
+def test_validate_title_blank():
+ warnings = [warning for (_, warning) in check_peps._validate_title(1, "-" * 80)]
+ assert warnings == ["PEP title must be less than 80 characters"], warnings
+
+
+def test_validate_title_too_long():
+ warnings = [warning for (_, warning) in check_peps._validate_title(1, "")]
+ assert warnings == ["PEP must have a title"], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "Accepted",
+ "Active",
+ "April Fool!",
+ "Deferred",
+ "Draft",
+ "Final",
+ "Provisional",
+ "Rejected",
+ "Superseded",
+ "Withdrawn",
+ ],
+)
+def test_validate_status_valid(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_status(1, line)]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "Standards Track",
+ "Informational",
+ "Process",
+ "accepted",
+ "active",
+ "april fool!",
+ "deferred",
+ "draft",
+ "final",
+ "provisional",
+ "rejected",
+ "superseded",
+ "withdrawn",
+ ],
+)
+def test_validate_status_invalid(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_status(1, line)]
+ assert warnings == ["Status must be a valid PEP status"], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "Standards Track",
+ "Informational",
+ "Process",
+ ],
+)
+def test_validate_type_valid(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_type(1, line)]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "standards track",
+ "informational",
+ "process",
+ "Accepted",
+ "Active",
+ "April Fool!",
+ "Deferred",
+ "Draft",
+ "Final",
+ "Provisional",
+ "Rejected",
+ "Superseded",
+ "Withdrawn",
+ ],
+)
+def test_validate_type_invalid(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_type(1, line)]
+ assert warnings == ["Type must be a valid PEP type"], warnings
+
+
+@pytest.mark.parametrize(
+ ("line", "expected_warnings"),
+ [
+ # valid entries
+ ("Governance", set()),
+ ("Packaging", set()),
+ ("Typing", set()),
+ ("Release", set()),
+ ("Governance, Packaging", set()),
+ ("Packaging, Typing", set()),
+ # duplicates
+ ("Governance, Governance", {"duplicates"}),
+ ("Release, Release", {"duplicates"}),
+ ("Packaging, Packaging", {"duplicates"}),
+ ("Spam, Spam", {"duplicates", "valid"}),
+ ("lobster, lobster", {"duplicates", "capitalisation", "valid"}),
+ ("governance, governance", {"duplicates", "capitalisation"}),
+ # capitalisation
+ ("governance", {"capitalisation"}),
+ ("packaging", {"capitalisation"}),
+ ("typing", {"capitalisation"}),
+ ("release", {"capitalisation"}),
+ ("Governance, release", {"capitalisation"}),
+ # validity
+ ("Spam", {"valid"}),
+ ("lobster", {"capitalisation", "valid"}),
+ # sorted
+ ("Packaging, Governance", {"sorted"}),
+ ("Typing, Release", {"sorted"}),
+ ("Release, Governance", {"sorted"}),
+ ("spam, packaging", {"capitalisation", "valid", "sorted"}),
+ ],
+ # call str() on each parameterised value in the test ID.
+ ids=str,
+)
+def test_validate_topic(line: str, expected_warnings: set):
+ warnings = [warning for (_, warning) in check_peps._validate_topic(1, line)]
+
+ found_warnings = set()
+
+ if "duplicates" in expected_warnings:
+ found_warnings.add("duplicates")
+ expected = "Topic must not contain duplicates"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "capitalisation" in expected_warnings:
+ found_warnings.add("capitalisation")
+ expected = "Topic must be properly capitalised (Title Case)"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "valid" in expected_warnings:
+ found_warnings.add("valid")
+ expected = "Topic must be for a valid sub-index"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "sorted" in expected_warnings:
+ found_warnings.add("sorted")
+ expected = "Topic must be sorted lexicographically"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if expected_warnings == set():
+ assert warnings == [], warnings
+
+ assert found_warnings == expected_warnings
+
+
+def test_validate_content_type_valid():
+ warnings = [
+ warning for (_, warning) in check_peps._validate_content_type(1, "text/x-rst")
+ ]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "text/plain",
+ "text/markdown",
+ "text/csv",
+ "text/rtf",
+ "text/javascript",
+ "text/html",
+ "text/xml",
+ ],
+)
+def test_validate_content_type_invalid(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_content_type(1, line)]
+ assert warnings == ["Content-Type must be 'text/x-rst'"], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "0, 1, 8, 12, 20,",
+ "101, 801,",
+ "3099, 9999",
+ ],
+)
+def test_validate_pep_references(line: str):
+ warnings = [
+ warning for (_, warning) in check_peps._validate_pep_references(1, line)
+ ]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "0,1,8, 12, 20,",
+ "101,801,",
+ "3099, 9998,9999",
+ ],
+)
+def test_validate_pep_references_separators(line: str):
+ warnings = [
+ warning for (_, warning) in check_peps._validate_pep_references(1, line)
+ ]
+ assert warnings == [
+ "PEP references must be separated by comma-spaces (', ')"
+ ], warnings
+
+
+@pytest.mark.parametrize(
+ ("line", "expected_warnings"),
+ [
+ # valid entries
+ ("1.0, 2.4, 2.7, 2.8, 3.0, 3.1, 3.4, 3.7, 3.11, 3.14", set()),
+ ("2.x", set()),
+ ("3.x", set()),
+ ("3.0.1", set()),
+ # segments
+ ("", {"segments"}),
+ ("1", {"segments"}),
+ ("1.2.3.4", {"segments"}),
+ # major
+ ("0.0", {"major"}),
+ ("4.0", {"major"}),
+ ("9.0", {"major"}),
+ # minor number
+ ("3.a", {"minor numeric"}),
+ ("3.spam", {"minor numeric"}),
+ ("3.0+", {"minor numeric"}),
+ ("3.0-9", {"minor numeric"}),
+ ("9.Z", {"major", "minor numeric"}),
+ # minor leading zero
+ ("3.01", {"minor zero"}),
+ ("0.00", {"major", "minor zero"}),
+ # micro empty
+ ("3.x.1", {"micro empty"}),
+ ("9.x.1", {"major", "micro empty"}),
+ # micro leading zero
+ ("3.3.0", {"micro zero"}),
+ ("3.3.00", {"micro zero"}),
+ ("3.3.01", {"micro zero"}),
+ ("3.0.0", {"micro zero"}),
+ ("3.00.0", {"minor zero", "micro zero"}),
+ ("0.00.0", {"major", "minor zero", "micro zero"}),
+ # micro number
+ ("3.0.a", {"micro numeric"}),
+ ("0.3.a", {"major", "micro numeric"}),
+ ],
+ # call str() on each parameterised value in the test ID.
+ ids=str,
+)
+def test_validate_python_version(line: str, expected_warnings: set):
+ warnings = [
+ warning for (_, warning) in check_peps._validate_python_version(1, line)
+ ]
+
+ found_warnings = set()
+
+ if "segments" in expected_warnings:
+ found_warnings.add("segments")
+ expected = f"Python-Version must have two or three segments: {line}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "major" in expected_warnings:
+ found_warnings.add("major")
+ expected = f"Python-Version major part must be 1, 2, or 3: {line}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "minor numeric" in expected_warnings:
+ found_warnings.add("minor numeric")
+ expected = f"Python-Version minor part must be numeric: {line}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "minor zero" in expected_warnings:
+ found_warnings.add("minor zero")
+ expected = f"Python-Version minor part must not have leading zeros: {line}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "micro empty" in expected_warnings:
+ found_warnings.add("micro empty")
+ expected = (
+ f"Python-Version micro part must be empty if minor part is 'x': {line}"
+ )
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "micro zero" in expected_warnings:
+ found_warnings.add("micro zero")
+ expected = f"Python-Version micro part must not have leading zeros: {line}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "micro numeric" in expected_warnings:
+ found_warnings.add("micro numeric")
+ expected = f"Python-Version micro part must be numeric: {line}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if expected_warnings == set():
+ assert warnings == [], warnings
+
+ assert found_warnings == expected_warnings
diff --git a/pep_sphinx_extensions/tests/pep_lint/test_pep_lint.py b/pep_sphinx_extensions/tests/pep_lint/test_pep_lint.py
new file mode 100644
index 000000000..2c52fa397
--- /dev/null
+++ b/pep_sphinx_extensions/tests/pep_lint/test_pep_lint.py
@@ -0,0 +1,48 @@
+from pathlib import Path
+
+import check_peps # NoQA: inserted into sys.modules in conftest.py
+
+PEP_9002 = Path(__file__).parent.parent / "peps" / "pep-9002.rst"
+
+
+def test_with_fake_pep():
+ content = PEP_9002.read_text(encoding="utf-8").splitlines()
+ warnings = list(check_peps.check_peps(PEP_9002, content))
+ assert warnings == [
+ (1, "PEP must begin with the 'PEP:' header"),
+ (9, "Must not have duplicate header: Sponsor "),
+ (10, "Must not have invalid header: Horse-Guards"),
+ (1, "Must have required header: PEP"),
+ (1, "Must have required header: Type"),
+ (
+ 1,
+ "Headers must be in PEP 12 order. Correct order: Title, Version, "
+ "Author, Sponsor, BDFL-Delegate, Discussions-To, Status, Topic, "
+ "Content-Type, Requires, Created, Python-Version, Post-History, "
+ "Resolution",
+ ),
+ (4, "Author continuation lines must end with a comma"),
+ (5, "Author line must not be over-indented"),
+ (7, "Python-Version major part must be 1, 2, or 3: 4.0"),
+ (
+ 8,
+ "Sponsor entries must begin with a valid 'Name': "
+ r"'Sponsor:\nHorse-Guards: Parade'",
+ ),
+ (11, "Created must be a 'DD-mmm-YYYY' date: '1-Jan-1989'"),
+ (12, "Delegate entries must begin with a valid 'Name': 'Barry!'"),
+ (13, "Status must be a valid PEP status"),
+ (14, "Topic must not contain duplicates"),
+ (14, "Topic must be properly capitalised (Title Case)"),
+ (14, "Topic must be for a valid sub-index"),
+ (14, "Topic must be sorted lexicographically"),
+ (15, "Content-Type must be 'text/x-rst'"),
+ (16, "PEP references must be separated by comma-spaces (', ')"),
+ (17, "Discussions-To must be a valid thread URL or mailing list"),
+ (18, "Post-History must be a 'DD-mmm-YYYY' date: '2-Feb-2000'"),
+ (18, "Post-History must be a valid thread URL"),
+ (19, "Post-History must be a 'DD-mmm-YYYY' date: '3-Mar-2001'"),
+ (19, "Post-History must be a valid thread URL"),
+ (20, "Resolution must be a valid thread URL"),
+ (23, "Use the :pep:`NNN` role to refer to PEPs"),
+ ]
diff --git a/pep_sphinx_extensions/tests/pep_lint/test_pep_number.py b/pep_sphinx_extensions/tests/pep_lint/test_pep_number.py
new file mode 100644
index 000000000..3443f7144
--- /dev/null
+++ b/pep_sphinx_extensions/tests/pep_lint/test_pep_number.py
@@ -0,0 +1,108 @@
+import check_peps # NoQA: inserted into sys.modules in conftest.py
+import pytest
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "PEP: 0",
+ "PEP: 12",
+ ],
+)
+def test_validate_pep_number(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_pep_number(line)]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "0",
+ "PEP:12",
+ "PEP 0",
+ "PEP 12",
+ "PEP:0",
+ ],
+)
+def test_validate_pep_number_invalid_header(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_pep_number(line)]
+ assert warnings == ["PEP must begin with the 'PEP:' header"], warnings
+
+
+@pytest.mark.parametrize(
+ ("pep_number", "expected_warnings"),
+ [
+ # valid entries
+ ("0", set()),
+ ("1", set()),
+ ("12", set()),
+ ("20", set()),
+ ("101", set()),
+ ("801", set()),
+ ("3099", set()),
+ ("9999", set()),
+ # empty
+ ("", {"not blank"}),
+ # leading zeros
+ ("01", {"leading zeros"}),
+ ("001", {"leading zeros"}),
+ ("0001", {"leading zeros"}),
+ ("00001", {"leading zeros"}),
+ # non-numeric
+ ("a", {"non-numeric"}),
+ ("123abc", {"non-numeric"}),
+ ("0123A", {"leading zeros", "non-numeric"}),
+ ("0", {"non-numeric"}),
+ ("101", {"non-numeric"}),
+ ("9999", {"non-numeric"}),
+ ("𝟎", {"non-numeric"}),
+ ("𝟘", {"non-numeric"}),
+ ("𝟏𝟚", {"non-numeric"}),
+ ("𝟸𝟬", {"non-numeric"}),
+ ("-1", {"non-numeric"}),
+ ("+1", {"non-numeric"}),
+ # out of bounds
+ ("10000", {"range"}),
+ ("54321", {"range"}),
+ ("99999", {"range"}),
+ ("32768", {"range"}),
+ ],
+ # call str() on each parameterised value in the test ID.
+ ids=str,
+)
+def test_pep_num_checker(pep_number: str, expected_warnings: set):
+ warnings = [
+ warning for (_, warning) in check_peps._pep_num(1, pep_number, "")
+ ]
+
+ found_warnings = set()
+ pep_number = pep_number.strip()
+
+ if "not blank" in expected_warnings:
+ found_warnings.add("not blank")
+ expected = f" must not be blank: {pep_number!r}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "leading zeros" in expected_warnings:
+ found_warnings.add("leading zeros")
+ expected = f" must not contain leading zeros: {pep_number!r}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "non-numeric" in expected_warnings:
+ found_warnings.add("non-numeric")
+ expected = f" must be numeric: {pep_number!r}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if "range" in expected_warnings:
+ found_warnings.add("range")
+ expected = f" must be between 0 and 9999: {pep_number!r}"
+ matching = [w for w in warnings if w == expected]
+ assert matching == [expected], warnings
+
+ if expected_warnings == set():
+ assert warnings == [], warnings
+
+ assert found_warnings == expected_warnings
diff --git a/pep_sphinx_extensions/tests/pep_lint/test_post_url.py b/pep_sphinx_extensions/tests/pep_lint/test_post_url.py
new file mode 100644
index 000000000..982f4612e
--- /dev/null
+++ b/pep_sphinx_extensions/tests/pep_lint/test_post_url.py
@@ -0,0 +1,305 @@
+import check_peps # NoQA: inserted into sys.modules in conftest.py
+import pytest
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "list-name@python.org",
+ "distutils-sig@python.org",
+ "csv@python.org",
+ "python-3000@python.org",
+ "ipaddr-py-dev@googlegroups.com",
+ "python-tulip@googlegroups.com",
+ "https://discuss.python.org/t/thread-name/123456",
+ "https://discuss.python.org/t/thread-name/123456/",
+ "https://discuss.python.org/t/thread_name/123456",
+ "https://discuss.python.org/t/thread_name/123456/",
+ "https://discuss.python.org/t/123456/",
+ "https://discuss.python.org/t/123456",
+ ],
+)
+def test_validate_discussions_to_valid(line: str):
+ warnings = [
+ warning for (_, warning) in check_peps._validate_discussions_to(1, line)
+ ]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "$pecial+chars@python.org",
+ "a-discussions-to-list!@googlegroups.com",
+ ],
+)
+def test_validate_discussions_to_list_name(line: str):
+ warnings = [
+ warning for (_, warning) in check_peps._validate_discussions_to(1, line)
+ ]
+ assert warnings == ["Discussions-To must be a valid mailing list"], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "list-name@python.org.uk",
+ "distutils-sig@mail-server.example",
+ ],
+)
+def test_validate_discussions_to_invalid_list_domain(line: str):
+ warnings = [
+ warning for (_, warning) in check_peps._validate_discussions_to(1, line)
+ ]
+ assert warnings == [
+ "Discussions-To must be a valid thread URL or mailing list"
+ ], warnings
+
+
+@pytest.mark.parametrize(
+ "body",
+ [
+ "",
+ (
+ "01-Jan-2001, 02-Feb-2002,\n "
+ "03-Mar-2003, 04-Apr-2004,\n "
+ "05-May-2005,"
+ ),
+ (
+ "`01-Jan-2000 `__,\n "
+ "`11-Mar-2005 `__,\n "
+ "`21-May-2010 `__,\n "
+ "`31-Jul-2015 `__,"
+ ),
+ "01-Jan-2001, `02-Feb-2002 `__,\n03-Mar-2003",
+ ],
+)
+def test_validate_post_history_valid(body: str):
+ warnings = [warning for (_, warning) in check_peps._validate_post_history(1, body)]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123#Anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/#Anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123#Anchor123",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/#Anchor123",
+ ],
+)
+def test_validate_resolution_valid(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_resolution(1, line)]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "line",
+ [
+ "https://mail.python.org/archives/list/list-name@python.org/thread",
+ "https://mail.python.org/archives/list/list-name@python.org/message",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/",
+ "https://mail.python.org/archives/list/list-name@python.org/message/",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123#anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/#anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123/",
+ "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123/",
+ ],
+)
+def test_validate_resolution_invalid(line: str):
+ warnings = [warning for (_, warning) in check_peps._validate_resolution(1, line)]
+ assert warnings == ["Resolution must be a valid thread URL"], warnings
+
+
+@pytest.mark.parametrize(
+ "thread_url",
+ [
+ "https://discuss.python.org/t/thread-name/123456",
+ "https://discuss.python.org/t/thread-name/123456/",
+ "https://discuss.python.org/t/thread_name/123456",
+ "https://discuss.python.org/t/thread_name/123456/",
+ "https://discuss.python.org/t/thread-name/123456/654321/",
+ "https://discuss.python.org/t/thread-name/123456/654321",
+ "https://discuss.python.org/t/123456",
+ "https://discuss.python.org/t/123456/",
+ "https://discuss.python.org/t/123456/654321/",
+ "https://discuss.python.org/t/123456/654321",
+ "https://discuss.python.org/t/1",
+ "https://discuss.python.org/t/1/",
+ "https://mail.python.org/pipermail/list-name/0000-Month/0123456.html",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/",
+ ],
+)
+def test_thread_checker_valid(thread_url: str):
+ warnings = [
+ warning for (_, warning) in check_peps._thread(1, thread_url, "")
+ ]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "thread_url",
+ [
+ "http://link.example",
+ "list-name@python.org",
+ "distutils-sig@python.org",
+ "csv@python.org",
+ "python-3000@python.org",
+ "ipaddr-py-dev@googlegroups.com",
+ "python-tulip@googlegroups.com",
+ "https://link.example",
+ "https://discuss.python.org",
+ "https://discuss.python.org/",
+ "https://discuss.python.org/c/category",
+ "https://discuss.python.org/t/thread_name/123456//",
+ "https://discuss.python.org/t/thread+name/123456",
+ "https://discuss.python.org/t/thread+name/123456#",
+ "https://discuss.python.org/t/thread+name/123456/#",
+ "https://discuss.python.org/t/thread+name/123456/#anchor",
+ "https://discuss.python.org/t/thread+name/",
+ "https://discuss.python.org/t/thread+name",
+ "https://discuss.python.org/t/thread-name/123abc",
+ "https://discuss.python.org/t/thread-name/123abc/",
+ "https://discuss.python.org/t/thread-name/123456/123abc",
+ "https://discuss.python.org/t/thread-name/123456/123abc/",
+ "https://discuss.python.org/t/123/456/789",
+ "https://discuss.python.org/t/123/456/789/",
+ "https://discuss.python.org/t/#/",
+ "https://discuss.python.org/t/#",
+ "https://mail.python.org/pipermail/list+name/0000-Month/0123456.html",
+ "https://mail.python.org/pipermail/list-name/YYYY-Month/0123456.html",
+ "https://mail.python.org/pipermail/list-name/0123456/0123456.html",
+ "https://mail.python.org/pipermail/list-name/0000-Month/0123456",
+ "https://mail.python.org/pipermail/list-name/0000-Month/0123456/",
+ "https://mail.python.org/pipermail/list-name/0000-Month/",
+ "https://mail.python.org/pipermail/list-name/0000-Month",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123#anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/#anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123#anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/#anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123/",
+ ],
+)
+def test_thread_checker_invalid(thread_url: str):
+ warnings = [
+ warning for (_, warning) in check_peps._thread(1, thread_url, "")
+ ]
+ assert warnings == [" must be a valid thread URL"], warnings
+
+
+@pytest.mark.parametrize(
+ "thread_url",
+ [
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123#Anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/#Anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123#Anchor123",
+ "https://mail.python.org/archives/list/list-name@python.org/message/abcXYZ123/#Anchor123",
+ ],
+)
+def test_thread_checker_valid_allow_message(thread_url: str):
+ warnings = [
+ warning
+ for (_, warning) in check_peps._thread(
+ 1, thread_url, "", allow_message=True
+ )
+ ]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "thread_url",
+ [
+ "https://mail.python.org/archives/list/list-name@python.org/thread",
+ "https://mail.python.org/archives/list/list-name@python.org/message",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/",
+ "https://mail.python.org/archives/list/list-name@python.org/message/",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123#anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/thread/abcXYZ123/#anchor",
+ "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/message/#abcXYZ123/",
+ "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123",
+ "https://mail.python.org/archives/list/list-name@python.org/spam/abcXYZ123/",
+ ],
+)
+def test_thread_checker_invalid_allow_message(thread_url: str):
+ warnings = [
+ warning
+ for (_, warning) in check_peps._thread(
+ 1, thread_url, "", allow_message=True
+ )
+ ]
+ assert warnings == [" must be a valid thread URL"], warnings
+
+
+@pytest.mark.parametrize(
+ "thread_url",
+ [
+ "list-name@python.org",
+ "distutils-sig@python.org",
+ "csv@python.org",
+ "python-3000@python.org",
+ "ipaddr-py-dev@googlegroups.com",
+ "python-tulip@googlegroups.com",
+ "https://discuss.python.org/t/thread-name/123456",
+ "https://discuss.python.org/t/thread-name/123456/",
+ "https://discuss.python.org/t/thread_name/123456",
+ "https://discuss.python.org/t/thread_name/123456/",
+ "https://discuss.python.org/t/123456/",
+ "https://discuss.python.org/t/123456",
+ ],
+)
+def test_thread_checker_valid_discussions_to(thread_url: str):
+ warnings = [
+ warning
+ for (_, warning) in check_peps._thread(
+ 1, thread_url, "", discussions_to=True
+ )
+ ]
+ assert warnings == [], warnings
+
+
+@pytest.mark.parametrize(
+ "thread_url",
+ [
+ "https://discuss.python.org/t/thread-name/123456/000",
+ "https://discuss.python.org/t/thread-name/123456/000/",
+ "https://discuss.python.org/t/thread_name/123456/000",
+ "https://discuss.python.org/t/thread_name/123456/000/",
+ "https://discuss.python.org/t/123456/000/",
+ "https://discuss.python.org/t/12345656/000",
+ "https://discuss.python.org/t/thread-name",
+ "https://discuss.python.org/t/thread_name",
+ "https://discuss.python.org/t/thread+name",
+ ],
+)
+def test_thread_checker_invalid_discussions_to(thread_url: str):
+ warnings = [
+ warning
+ for (_, warning) in check_peps._thread(
+ 1, thread_url, "", discussions_to=True
+ )
+ ]
+ assert warnings == [" must be a valid thread URL"], warnings
+
+
+def test_thread_checker_allow_message_discussions_to():
+ with pytest.raises(ValueError, match="cannot both be True"):
+ list(
+ check_peps._thread(
+ 1, "", "", allow_message=True, discussions_to=True
+ )
+ )
diff --git a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py
index ad8cf2782..9f040c5e1 100644
--- a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py
+++ b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_footer.py
@@ -1,27 +1,29 @@
-from pathlib import Path
+import datetime as dt
from pep_sphinx_extensions.pep_processor.transforms import pep_footer
+from ...conftest import PEP_ROOT
+
def test_add_source_link():
- out = pep_footer._add_source_link(Path("pep-0008.txt"))
+ out = pep_footer._add_source_link(PEP_ROOT / "pep-0008.rst")
- assert "https://github.com/python/peps/blob/main/pep-0008.txt" in str(out)
+ assert "https://github.com/python/peps/blob/main/peps/pep-0008.rst" in str(out)
def test_add_commit_history_info():
- out = pep_footer._add_commit_history_info(Path("pep-0008.txt"))
+ out = pep_footer._add_commit_history_info(PEP_ROOT / "pep-0008.rst")
assert str(out).startswith(
"Last modified: "
- ''
+ ''
)
# A variable timestamp comes next, don't test that
assert str(out).endswith("")
def test_add_commit_history_info_invalid():
- out = pep_footer._add_commit_history_info(Path("pep-not-found.txt"))
+ out = pep_footer._add_commit_history_info(PEP_ROOT / "pep-not-found.rst")
assert str(out) == ""
@@ -31,4 +33,4 @@ def test_get_last_modified_timestamps():
assert len(out) >= 585
# Should be a Unix timestamp and at least this
- assert out["pep-0008.txt"] >= 1643124055
+ assert dt.datetime.fromisoformat(out["pep-0008"]).timestamp() >= 1643124055
diff --git a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_headers.py b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_headers.py
index 4cc45423e..772c24158 100644
--- a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_headers.py
+++ b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_headers.py
@@ -18,7 +18,7 @@ from pep_sphinx_extensions.pep_zero_generator.constants import (
@pytest.mark.parametrize(
- "test_input, expected",
+ ("test_input", "expected"),
[
("my-mailing-list@example.com", "my-mailing-list@example.com"),
("python-tulip@googlegroups.com", "https://groups.google.com/g/python-tulip"),
@@ -37,7 +37,7 @@ def test_generate_list_url(test_input, expected):
@pytest.mark.parametrize(
- "test_input, expected",
+ ("test_input", "expected"),
[
(
"https://mail.python.org/pipermail/python-3000/2006-November/004190.html",
@@ -72,7 +72,7 @@ def test_process_pretty_url(test_input, expected):
@pytest.mark.parametrize(
- "test_input, expected",
+ ("test_input", "expected"),
[
(
"https://example.com/",
@@ -94,7 +94,7 @@ def test_process_pretty_url_invalid(test_input, expected):
@pytest.mark.parametrize(
- "test_input, expected",
+ ("test_input", "expected"),
[
(
"https://mail.python.org/pipermail/python-3000/2006-November/004190.html",
@@ -129,7 +129,7 @@ def test_make_link_pretty(test_input, expected):
@pytest.mark.parametrize(
- "test_input, expected",
+ ("test_input", "expected"),
[
(STATUS_ACCEPTED, "Normative proposal accepted for implementation"),
(STATUS_ACTIVE, "Currently valid informational guidance, or an in-use process"),
@@ -155,7 +155,7 @@ def test_abbreviate_status_unknown():
@pytest.mark.parametrize(
- "test_input, expected",
+ ("test_input", "expected"),
[
(
TYPE_INFO,
diff --git a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_zero.py b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_zero.py
index 09b2effea..e25d37fd2 100644
--- a/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_zero.py
+++ b/pep_sphinx_extensions/tests/pep_processor/transform/test_pep_zero.py
@@ -5,7 +5,7 @@ from pep_sphinx_extensions.pep_processor.transforms import pep_zero
@pytest.mark.parametrize(
- "test_input, expected",
+ ("test_input", "expected"),
[
(
nodes.reference(
diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_author.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_author.py
deleted file mode 100644
index 8334b1c5f..000000000
--- a/pep_sphinx_extensions/tests/pep_zero_generator/test_author.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import pytest
-
-from pep_sphinx_extensions.pep_zero_generator import author
-from pep_sphinx_extensions.tests.utils import AUTHORS_OVERRIDES
-
-
-@pytest.mark.parametrize(
- "test_input, expected",
- [
- (
- ("First Last", "first@example.com"),
- author.Author(
- last_first="Last, First", nick="Last", email="first@example.com"
- ),
- ),
- (
- ("Guido van Rossum", "guido@example.com"),
- author.Author(
- last_first="van Rossum, Guido (GvR)",
- nick="GvR",
- email="guido@example.com",
- ),
- ),
- (
- ("Hugo van Kemenade", "hugo@example.com"),
- author.Author(
- last_first="van Kemenade, Hugo",
- nick="van Kemenade",
- email="hugo@example.com",
- ),
- ),
- (
- ("Eric N. Vander Weele", "eric@example.com"),
- author.Author(
- last_first="Vander Weele, Eric N.",
- nick="Vander Weele",
- email="eric@example.com",
- ),
- ),
- (
- ("Mariatta", "mariatta@example.com"),
- author.Author(
- last_first="Mariatta", nick="Mariatta", email="mariatta@example.com"
- ),
- ),
- (
- ("First Last Jr.", "first@example.com"),
- author.Author(
- last_first="Last, First, Jr.", nick="Last", email="first@example.com"
- ),
- ),
- pytest.param(
- ("First Last", "first at example.com"),
- author.Author(
- last_first="Last, First", nick="Last", email="first@example.com"
- ),
- marks=pytest.mark.xfail,
- ),
- ],
-)
-def test_parse_author_email(test_input, expected):
- out = author.parse_author_email(test_input, AUTHORS_OVERRIDES)
-
- assert out == expected
-
-
-def test_parse_author_email_empty_name():
- with pytest.raises(ValueError, match="Name is empty!"):
- author.parse_author_email(("", "user@example.com"), AUTHORS_OVERRIDES)
diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py
index d5ebab143..225efa73a 100644
--- a/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py
+++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_parser.py
@@ -1,9 +1,6 @@
-from pathlib import Path
-
import pytest
from pep_sphinx_extensions.pep_zero_generator import parser
-from pep_sphinx_extensions.pep_zero_generator.author import Author
from pep_sphinx_extensions.pep_zero_generator.constants import (
STATUS_ACCEPTED,
STATUS_ACTIVE,
@@ -18,83 +15,100 @@ from pep_sphinx_extensions.pep_zero_generator.constants import (
TYPE_PROCESS,
TYPE_STANDARDS,
)
-from pep_sphinx_extensions.pep_zero_generator.errors import PEPError
-from pep_sphinx_extensions.tests.utils import AUTHORS_OVERRIDES
+from pep_sphinx_extensions.pep_zero_generator.parser import _Author
+
+from ..conftest import PEP_ROOT
def test_pep_repr():
- pep8 = parser.PEP(Path("pep-0008.txt"))
+ pep8 = parser.PEP(PEP_ROOT / "pep-0008.rst")
assert repr(pep8) == ""
def test_pep_less_than():
- pep8 = parser.PEP(Path("pep-0008.txt"))
- pep3333 = parser.PEP(Path("pep-3333.txt"))
+ pep8 = parser.PEP(PEP_ROOT / "pep-0008.rst")
+ pep3333 = parser.PEP(PEP_ROOT / "pep-3333.rst")
assert pep8 < pep3333
def test_pep_equal():
- pep_a = parser.PEP(Path("pep-0008.txt"))
- pep_b = parser.PEP(Path("pep-0008.txt"))
+ pep_a = parser.PEP(PEP_ROOT / "pep-0008.rst")
+ pep_b = parser.PEP(PEP_ROOT / "pep-0008.rst")
assert pep_a == pep_b
-def test_pep_details(monkeypatch):
- pep8 = parser.PEP(Path("pep-0008.txt"))
+@pytest.mark.parametrize(
+ ("test_input", "expected"),
+ [
+ (
+ "pep-0008.rst",
+ {
+ "authors": "Guido van Rossum, Barry Warsaw, Alyssa Coghlan",
+ "number": 8,
+ "shorthand": ":abbr:`PA (Process, Active)`",
+ "title": "Style Guide for Python Code",
+ "python_version": "",
+ },
+ ),
+ (
+ "pep-0719.rst",
+ {
+ "authors": "Thomas Wouters",
+ "number": 719,
+ "shorthand": ":abbr:`IA (Informational, Active)`",
+ "title": "Python 3.13 Release Schedule",
+ "python_version": "3.13",
+ },
+ ),
+ ],
+)
+def test_pep_details(test_input, expected):
+ pep = parser.PEP(PEP_ROOT / test_input)
- assert pep8.details == {
- "authors": "GvR, Warsaw, Coghlan",
- "number": 8,
- "shorthand": ":abbr:`PA (Process, Active)`",
- "title": "Style Guide for Python Code",
- }
+ assert pep.details == expected
@pytest.mark.parametrize(
- "test_input, expected",
+ ("test_input", "expected"),
[
(
"First Last ",
- [Author(last_first="Last, First", nick="Last", email="user@example.com")],
+ [_Author(full_name="First Last", email="user@example.com")],
),
(
"First Last",
- [Author(last_first="Last, First", nick="Last", email="")],
- ),
- (
- "user@example.com (First Last)",
- [Author(last_first="Last, First", nick="Last", email="user@example.com")],
+ [_Author(full_name="First Last", email="")],
),
pytest.param(
"First Last ",
- [Author(last_first="Last, First", nick="Last", email="user@example.com")],
+ [_Author(full_name="First Last", email="user@example.com")],
marks=pytest.mark.xfail,
),
+ pytest.param(
+ " , First Last,",
+ {"First Last": ""},
+ marks=pytest.mark.xfail(raises=ValueError),
+ ),
],
)
def test_parse_authors(test_input, expected):
- # Arrange
- dummy_object = parser.PEP(Path("pep-0160.txt"))
-
# Act
- out = parser._parse_authors(dummy_object, test_input, AUTHORS_OVERRIDES)
+ out = parser._parse_author(test_input)
# Assert
assert out == expected
def test_parse_authors_invalid():
- pep = parser.PEP(Path("pep-0008.txt"))
-
- with pytest.raises(PEPError, match="no authors found"):
- parser._parse_authors(pep, "", AUTHORS_OVERRIDES)
+ with pytest.raises(ValueError, match="Name is empty!"):
+ assert parser._parse_author("")
@pytest.mark.parametrize(
- "test_type, test_status, expected",
+ ("test_type", "test_status", "expected"),
[
(TYPE_INFO, STATUS_DRAFT, ":abbr:`I (Informational, Draft)`"),
(TYPE_INFO, STATUS_ACTIVE, ":abbr:`IA (Informational, Active)`"),
@@ -112,7 +126,7 @@ def test_parse_authors_invalid():
)
def test_abbreviate_type_status(test_type, test_status, expected):
# set up dummy PEP object and monkeypatch attributes
- pep = parser.PEP(Path("pep-0008.txt"))
+ pep = parser.PEP(PEP_ROOT / "pep-0008.rst")
pep.pep_type = test_type
pep.status = test_status
diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py
index c2e15844f..75c16f624 100644
--- a/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py
+++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_pep_index_generator.py
@@ -1,10 +1,10 @@
-from pathlib import Path
-
from pep_sphinx_extensions.pep_zero_generator import parser, pep_index_generator
+from ..conftest import PEP_ROOT
+
def test_create_pep_json():
- peps = [parser.PEP(Path("pep-0008.txt"))]
+ peps = [parser.PEP(PEP_ROOT / "pep-0008.rst")]
out = pep_index_generator.create_pep_json(peps)
diff --git a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py
index 19eeca2d9..1ccf8c418 100644
--- a/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py
+++ b/pep_sphinx_extensions/tests/pep_zero_generator/test_writer.py
@@ -30,18 +30,18 @@ def test_pep_zero_writer_emit_title():
@pytest.mark.parametrize(
- "test_input, expected",
+ ("test_input", "expected"),
[
(
"pep-9000.rst",
{
- "Fussyreverend, Francis": "one@example.com",
- "Soulfulcommodore, Javier": "two@example.com",
+ "Francis Fussyreverend": "one@example.com",
+ "Javier Soulfulcommodore": "two@example.com",
},
),
(
"pep-9001.rst",
- {"Fussyreverend, Francis": "", "Soulfulcommodore, Javier": ""},
+ {"Francis Fussyreverend": "", "Javier Soulfulcommodore": ""},
),
],
)
diff --git a/pep_sphinx_extensions/tests/peps/pep-9002.rst b/pep_sphinx_extensions/tests/peps/pep-9002.rst
new file mode 100644
index 000000000..208569e03
--- /dev/null
+++ b/pep_sphinx_extensions/tests/peps/pep-9002.rst
@@ -0,0 +1,23 @@
+PEP:9002
+Title: Nobody expects the example PEP!
+Author: Cardinal Ximénez ,
+ Cardinal Biggles
+ Cardinal Fang
+Version: 4.0
+Python-Version: 4.0
+Sponsor:
+Sponsor:
+Horse-Guards: Parade
+Created: 1-Jan-1989
+BDFL-Delegate: Barry!
+Status: Draught
+Topic: Inquisiting, Governance, Governance, packaging
+Content-Type: video/quicktime
+Requires: 0020,1,2,3, 7, 8
+Discussions-To: MR ALBERT SPIM, I,OOO,OO8 LONDON ROAD, OXFORD
+Post-History: `2-Feb-2000 `__
+ `3-Mar-2001 `__
+Resolution:
+
+
+https://peps.python.org/pep-9002.html
diff --git a/pep_sphinx_extensions/tests/utils.py b/pep_sphinx_extensions/tests/utils.py
deleted file mode 100644
index 19167d552..000000000
--- a/pep_sphinx_extensions/tests/utils.py
+++ /dev/null
@@ -1,6 +0,0 @@
-AUTHORS_OVERRIDES = {
- "Guido van Rossum": {
- "Surname First": "van Rossum, Guido (GvR)",
- "Name Reference": "GvR",
- },
-}
diff --git a/conf.py b/peps/conf.py
similarity index 87%
rename from conf.py
rename to peps/conf.py
index 95a1debd4..09b9b3ed3 100644
--- a/conf.py
+++ b/peps/conf.py
@@ -3,10 +3,12 @@
"""Configuration for building PEPs using Sphinx."""
+import os
from pathlib import Path
import sys
-sys.path.append(str(Path(".").absolute()))
+_ROOT = Path(__file__).resolve().parent.parent
+sys.path.append(os.fspath(_ROOT))
# -- Project information -----------------------------------------------------
@@ -25,7 +27,6 @@ extensions = [
# The file extensions of source files. Sphinx uses these suffixes as sources.
source_suffix = {
".rst": "pep",
- ".txt": "pep",
}
# List of patterns (relative to source dir) to ignore when looking for source files.
@@ -34,7 +35,6 @@ include_patterns = [
"contents.rst",
# PEP files
"pep-????.rst",
- "pep-????.txt",
# PEP ancillary files
"pep-????/*.rst",
# Documentation
@@ -60,11 +60,13 @@ intersphinx_disabled_reftypes = []
# -- Options for HTML output -------------------------------------------------
+_PSE_PATH = _ROOT / "pep_sphinx_extensions"
+
# HTML output settings
html_math_renderer = "maths_to_html" # Maths rendering
# Theme settings
-html_theme_path = ["pep_sphinx_extensions"]
+html_theme_path = [os.fspath(_PSE_PATH)]
html_theme = "pep_theme" # The actual theme directory (child of html_theme_path)
html_use_index = False # Disable index (we use PEP 0)
html_style = "" # must be defined here or in theme.conf, but is unused
@@ -72,4 +74,4 @@ html_permalinks = False # handled in the PEPContents transform
html_baseurl = "https://peps.python.org" # to create the CNAME file
gettext_auto_build = False # speed-ups
-templates_path = ["pep_sphinx_extensions/pep_theme/templates"] # Theme template relative paths from `confdir`
+templates_path = [os.fspath(_PSE_PATH / "pep_theme" / "templates")] # Theme template relative paths from `confdir`
diff --git a/contents.rst b/peps/contents.rst
similarity index 97%
rename from contents.rst
rename to peps/contents.rst
index 3aa0d788d..d791f08f8 100644
--- a/contents.rst
+++ b/peps/contents.rst
@@ -14,6 +14,5 @@ This is an internal Sphinx page; please go to the :doc:`PEP Index `.
:glob:
:caption: PEP Table of Contents (needed for Sphinx):
- docs/*
pep-*
topic/*
diff --git a/pep-0001.txt b/peps/pep-0001.rst
similarity index 97%
rename from pep-0001.txt
rename to peps/pep-0001.rst
index 82ff18ea0..e691648e7 100644
--- a/pep-0001.txt
+++ b/peps/pep-0001.rst
@@ -1,9 +1,8 @@
PEP: 1
Title: PEP Purpose and Guidelines
-Author: Barry Warsaw, Jeremy Hylton, David Goodger, Nick Coghlan
+Author: Barry Warsaw, Jeremy Hylton, David Goodger, Alyssa Coghlan
Status: Active
Type: Process
-Content-Type: text/x-rst
Created: 13-Jun-2000
Post-History: 21-Mar-2001, 29-Jul-2002, 03-May-2003, 05-May-2012,
07-Apr-2013
@@ -136,8 +135,8 @@ forums, and attempts to build community consensus around the idea. The PEP
champion (a.k.a. Author) should first attempt to ascertain whether the idea is
PEP-able. Posting to the `Ideas category`_ of the `Python Discourse`_ is usually
the best way to go about this, unless a more specialized venue is appropriate,
-such as `Typing-SIG`_ for static typing or the `Packaging category`_ of the
-Python Discourse for packaging issues.
+such as the `Typing category`_ (for static typing ideas)
+or `Packaging category`_ (for packaging ideas) on the Python Discourse.
Vetting an idea publicly before going as far as writing a PEP is meant
to save the potential author time. Many ideas have been brought
@@ -207,7 +206,7 @@ The standard PEP workflow is:
It also provides a complete introduction to reST markup that is used
in PEPs. Approval criteria are:
- * It sound and complete. The ideas must make technical sense. The
+ * It is sound and complete. The ideas must make technical sense. The
editors do not consider whether they seem likely to be accepted.
* The title accurately describes the content.
* The PEP's language (spelling, grammar, sentence structure, etc.)
@@ -284,8 +283,9 @@ The `PEPs category`_ of the `Python Discourse`_
is the preferred choice for most new PEPs,
whereas historically the `Python-Dev`_ mailing list was commonly used.
Some specialized topics have specific venues, such as
-`Typing-SIG`_ for typing PEPs or the `Packaging category`_ on the Python
-Discourse for packaging PEPs. If the PEP authors are unsure of the best venue,
+the `Typing category`_ and the `Packaging category`_ on the Python
+Discourse for typing and packaging PEPs, respectively.
+If the PEP authors are unsure of the best venue,
the PEP Sponsor and PEP editors can advise them accordingly.
If a PEP undergoes a significant re-write or other major, substantive
@@ -296,7 +296,7 @@ pointing to this new thread.
If it is not chosen as the discussion venue,
a brief announcement post should be made to the `PEPs category`_
-with at least a link to the rendered PEP and the `Discussions-To` thread
+with at least a link to the rendered PEP and the ``Discussions-To`` thread
when the draft PEP is committed to the repository
and if a major-enough change is made to trigger a new thread.
@@ -609,7 +609,6 @@ optional and are described below. All other headers are required.
Withdrawn | Final | Superseded>
Type:
* Topic:
- * Content-Type: text/x-rst
* Requires:
Created:
* Python-Version:
@@ -648,7 +647,7 @@ out.
The PEP-Delegate field is used to record the individual appointed by the
Steering Council to make the final decision on whether or not to approve or
reject a PEP. (The delegate's email address is currently omitted due to a
-limitation in the email address masking for reStructuredText PEPs)
+limitation in the email address masking for reStructuredText PEPs.)
*Note: The Resolution header is required for Standards Track PEPs
only. It contains a URL that should point to an email message or
@@ -667,11 +666,6 @@ The optional Topic header lists the special topic, if any,
the PEP belongs under.
See the :ref:`topic-index` for the existing topics.
-The format of a PEP is specified with a Content-Type header.
-All PEPs must use reStructuredText (see :pep:`12`),
-and have a value of ``text/x-rst``, the default.
-Previously, plaintext PEPs used ``text/plain`` (see :pep:`9`).
-
The Created header records the date that the PEP was assigned a
number, while Post-History is used to record the dates of and corresponding
URLs to the Discussions-To threads for the PEP, with the former as the
@@ -859,7 +853,7 @@ Footnotes
.. _PEPs category: https://discuss.python.org/c/peps/
-.. _Typing-SIG: https://mail.python.org/mailman3/lists/typing-sig.python.org/
+.. _Typing category: https://discuss.python.org/c/typing/
.. _Packaging category: https://discuss.python.org/c/packaging/
@@ -877,13 +871,3 @@ Copyright
This document is placed in the public domain or under the
CC0-1.0-Universal license, whichever is more permissive.
-
-
-..
- Local Variables:
- mode: indented-text
- indent-tabs-mode: nil
- sentence-end-double-space: t
- fill-column: 70
- coding: utf-8
- End:
diff --git a/pep-0001/process_flow.svg b/peps/pep-0001/process_flow.svg
similarity index 100%
rename from pep-0001/process_flow.svg
rename to peps/pep-0001/process_flow.svg
diff --git a/pep-0002.txt b/peps/pep-0002.rst
similarity index 100%
rename from pep-0002.txt
rename to peps/pep-0002.rst
diff --git a/pep-0003.txt b/peps/pep-0003.rst
similarity index 100%
rename from pep-0003.txt
rename to peps/pep-0003.rst
diff --git a/pep-0004.txt b/peps/pep-0004.rst
similarity index 100%
rename from pep-0004.txt
rename to peps/pep-0004.rst
diff --git a/pep-0005.txt b/peps/pep-0005.rst
similarity index 100%
rename from pep-0005.txt
rename to peps/pep-0005.rst
diff --git a/pep-0006.txt b/peps/pep-0006.rst
similarity index 99%
rename from pep-0006.txt
rename to peps/pep-0006.rst
index ca6a6e74c..fd5389929 100644
--- a/pep-0006.txt
+++ b/peps/pep-0006.rst
@@ -45,7 +45,7 @@ Prohibitions
Bug fix releases are required to adhere to the following restrictions:
-1. There must be zero syntax changes. All `.pyc` and `.pyo` files must
+1. There must be zero syntax changes. All ``.pyc`` and ``.pyo`` files must
work (no regeneration needed) with all bugfix releases forked off
from a major release.
diff --git a/pep-0007.txt b/peps/pep-0007.rst
similarity index 100%
rename from pep-0007.txt
rename to peps/pep-0007.rst
diff --git a/pep-0008.txt b/peps/pep-0008.rst
similarity index 99%
rename from pep-0008.txt
rename to peps/pep-0008.rst
index 6c4ac9099..05aa89614 100644
--- a/pep-0008.txt
+++ b/peps/pep-0008.rst
@@ -4,7 +4,7 @@ Version: $Revision$
Last-Modified: $Date$
Author: Guido van Rossum ,
Barry Warsaw ,
- Nick Coghlan
+ Alyssa Coghlan
Status: Active
Type: Process
Content-Type: text/x-rst
diff --git a/pep-0009.txt b/peps/pep-0009.rst
similarity index 100%
rename from pep-0009.txt
rename to peps/pep-0009.rst
diff --git a/pep-0010.txt b/peps/pep-0010.rst
similarity index 100%
rename from pep-0010.txt
rename to peps/pep-0010.rst
diff --git a/pep-0011.txt b/peps/pep-0011.rst
similarity index 99%
rename from pep-0011.txt
rename to peps/pep-0011.rst
index ffbd2e766..63131c3a2 100644
--- a/pep-0011.txt
+++ b/peps/pep-0011.rst
@@ -8,7 +8,7 @@ Content-Type: text/x-rst
Created: 07-Jul-2002
Post-History: `18-Aug-2007 `__,
`14-May-2014 `__,
- `20-Feb-2015 `__,
+ `20-Feb-2015 `__,
`10-Mar-2022 `__,
diff --git a/pep-0012.rst b/peps/pep-0012.rst
similarity index 99%
rename from pep-0012.rst
rename to peps/pep-0012.rst
index 7ad01dc43..073a74dc0 100644
--- a/pep-0012.rst
+++ b/peps/pep-0012.rst
@@ -5,7 +5,6 @@ Author: David Goodger ,
Brett Cannon
Status: Active
Type: Process
-Content-Type: text/x-rst
Created: 05-Aug-2002
Post-History: `30-Aug-2002 `__
@@ -174,7 +173,6 @@ your PEP):
Status: Draft
Type: [Standards Track | Informational | Process]
Topic: *[Governance | Packaging | Release | Typing]
- Content-Type: text/x-rst
Requires: *[NNN]
Created: [DD-MMM-YYYY]
Python-Version: *[M.N]
diff --git a/pep-0012/pep-NNNN.rst b/peps/pep-0012/pep-NNNN.rst
similarity index 98%
rename from pep-0012/pep-NNNN.rst
rename to peps/pep-0012/pep-NNNN.rst
index 011616f6f..9b922b10a 100644
--- a/pep-0012/pep-NNNN.rst
+++ b/peps/pep-0012/pep-NNNN.rst
@@ -7,7 +7,6 @@ Discussions-To:
Status:
Type:
Topic:
-Content-Type: text/x-rst
Requires:
Created:
Python-Version:
diff --git a/pep-0013.rst b/peps/pep-0013.rst
similarity index 100%
rename from pep-0013.rst
rename to peps/pep-0013.rst
diff --git a/pep-0020.txt b/peps/pep-0020.rst
similarity index 100%
rename from pep-0020.txt
rename to peps/pep-0020.rst
diff --git a/pep-0042.txt b/peps/pep-0042.rst
similarity index 100%
rename from pep-0042.txt
rename to peps/pep-0042.rst
diff --git a/pep-0100.txt b/peps/pep-0100.rst
similarity index 100%
rename from pep-0100.txt
rename to peps/pep-0100.rst
diff --git a/pep-0101.txt b/peps/pep-0101.rst
similarity index 77%
rename from pep-0101.txt
rename to peps/pep-0101.rst
index b2bbfde93..664c90a04 100644
--- a/pep-0101.txt
+++ b/peps/pep-0101.rst
@@ -20,12 +20,12 @@ purring little creatures up, and ride them into town, with some of their
buddies firmly attached to your bare back, anchored by newly sharpened
claws. At least they're cute, you remind yourself.
-Actually, no that's a slight exaggeration . The Python release
+Actually, no, that's a slight exaggeration 😉 The Python release
process has steadily improved over the years and now, with the help of our
amazing community, is really not too difficult. This PEP attempts to
-collect, in one place, all the steps needed to make a Python release. It
-is organized as a recipe and you can actually print this out and check
-items off as you complete them.
+collect, in one place, all the steps needed to make a Python release.
+Most of the steps are now automated or guided by automation, so manually
+following this list is no longer necessary.
Things You'll Need
==================
@@ -41,25 +41,23 @@ Here's a hopefully-complete list.
* A bunch of software:
- * "release.py", the Python release manager's friend. It's in the
- python/release-tools repo on GitHub. It doesn't pip install
- or have any sort of install process--you'll have to put it on
- your path yourself, or just run it with a relative path, or
- whatever.
+ * A checkout of the `python/release-tools
+ `_ repo.
+ It contains a ``requirements.txt`` file that you need to install
+ dependencies from first. Afterwards, you can fire up scripts in the
+ repo, covered later in this PEP.
- * "blurb", the Misc/NEWS management tool. The release process
- currently uses three blurb subcommands:
- release, merge, and export. Installable via pip3.
-
- * "virtualenv". The release script installs Sphinx in a virtualenv
- when building the docs (for 2.7 and 3.5+).
+ * ``blurb``, the
+ `Misc/NEWS `_
+ management tool. You can pip install it.
* A fairly complete installation of a recent TeX distribution,
such as texlive. You need that for building the PDF docs.
-* Access to ``downloads.nyc1.psf.io``, the server that hosts download files,
- and ``docs.nyc1.psf.io``, the server that hosts the documentation.
- You'll be uploading files directly here.
+* Access to servers where you will upload files:
+
+ * ``downloads.nyc1.psf.io``, the server that hosts download files; and
+ * ``docs.nyc1.psf.io``, the server that hosts the documentation.
* Administrator access to ``https://github.com/python/cpython``.
@@ -89,7 +87,8 @@ Types of Releases
There are several types of releases you will need to make. These include:
* ``alpha``
-* ``beta``
+* ``begin beta``, also known as ``beta 1``, also known as ``new branch``
+* ``beta 2+``
* ``release candidate 1``
* ``release candidate 2+``
* ``final``
@@ -105,8 +104,8 @@ organization of the cpython git repository, the *main* branch is always
the target for new features. At some point in the release cycle of the
next feature release, a **new branch** release is made which creates a
new separate branch for stabilization and later maintenance of the
-current in-progress feature release (x.y.0) and the *main* branch is modified
-to build a new version (which will eventually be released as x.y+1.0).
+current in-progress feature release (``3.n.0``) and the *main* branch is modified
+to build a new version (which will eventually be released as ``3.n+1.0``).
While the **new branch** release step could occur at one of several points
in the release cycle, current practice is for it to occur at feature code
cutoff for the release which is scheduled for the first beta release.
@@ -114,7 +113,7 @@ cutoff for the release which is scheduled for the first beta release.
In the descriptions that follow, steps specific to release types are
labeled accordingly, for now, **new branch** and **final**.
-How to Make A Release
+How To Make A Release
=====================
Here are the steps taken to make a Python release. Some steps are more
@@ -129,12 +128,10 @@ release. The roles and their current experts are:
- Thomas Wouters (NL)
- Pablo Galindo Salgado (UK)
- Łukasz Langa (PL)
- - Ned Deily (US)
* WE = Windows - Steve Dower
* ME = Mac - Ned Deily (US)
* DE = Docs - Julien Palard (Central Europe)
-* IE = Idle Expert - Terry Reedy (US)
.. note:: It is highly recommended that the RM contact the Experts the day
before the release. Because the world is round and everyone lives
@@ -146,49 +143,42 @@ release. The roles and their current experts are:
In rare cases where the expert for Windows or Mac is MIA, you may add
a message "(Platform) binaries will be provided shortly" and proceed.
-XXX: We should include a dependency graph to illustrate the steps that can
-be taken in parallel, or those that depend on other steps.
-
As much as possible, the release steps are automated and guided by the
release script, which is available in a separate repository:
https://github.com/python/release-tools
We use the following conventions in the examples below. Where a release
-number is given, it is of the form ``X.Y.ZaN``, e.g. 3.3.0a3 for Python 3.3.0
+number is given, it is of the form ``3.X.YaN``, e.g. 3.13.0a3 for Python 3.13.0
alpha 3, where "a" == alpha, "b" == beta, "rc" == release candidate.
-Release tags are named ``vX.Y.ZaN``. The branch name for minor release
-maintenance branches is ``X.Y``.
+Release tags are named ``v3.X.YaN``. The branch name for minor release
+maintenance branches is ``3.X``.
This helps by performing several automatic editing steps, and guides you
to perform some manual editing steps.
-- Log into irc.libera.chat and join the #python-dev channel.
+- Log into Discord and join the Python Core Devs server. Ask Thomas
+ or Łukasz for an invite.
You probably need to coordinate with other people around the world.
- This IRC channel is where we've arranged to meet.
+ This communication channel is where we've arranged to meet.
- Check to see if there are any showstopper bugs.
- Go to https://bugs.python.org and look for any open bugs that can block
- this release. You're looking at the Priority of the open bugs for the
- release you're making; here are the relevant definitions:
+ Go to https://github.com/python/cpython/issues and look for any open
+ bugs that can block this release. You're looking at two relevant labels:
- release blocker
+ release-blocker
Stops the release dead in its tracks. You may not
make any release with any open release blocker bugs.
- deferred blocker
+ deferred-blocker
Doesn't block this release, but it will block a
future release. You may not make a final or
candidate release with any open deferred blocker
bugs.
- critical
- Important bugs that should be fixed, but which does not block
- a release.
-
Review the release blockers and either resolve them, bump them down to
deferred, or stop the release and ask for community assistance. If
you're making a final or candidate release, do the same with any open
@@ -212,7 +202,7 @@ to perform some manual editing steps.
within it (called the "release clone" from now on). You can use the same
GitHub fork you use for cpython development. Using the standard setup
recommended in the Python Developer's Guide, your fork would be referred
- to as `origin` and the standard cpython repo as `upstream`. You will
+ to as ``origin`` and the standard cpython repo as ``upstream``. You will
use the branch on your fork to do the release engineering work, including
tagging the release, and you will use it to share with the other experts
for making the binaries.
@@ -244,22 +234,22 @@ to perform some manual editing steps.
- Consider running ``autoconf`` using the currently accepted standard version
in case ``configure`` or other autoconf-generated files were last
committed with a newer or older version and may contain spurious or
- harmful differences. Currently, autoconf 2.69 is our de facto standard.
+ harmful differences. Currently, autoconf 2.71 is our de facto standard.
if there are differences, commit them.
- Make sure the ``SOURCE_URI`` in ``Doc/tools/extensions/pyspecific.py``
- points to the right branch in the git repository (``main`` or ``X.Y``).
+ points to the right branch in the git repository (``main`` or ``3.X``).
For a **new branch** release, change the branch in the file from *main*
- to the new release branch you are about to create (``X.Y``).
+ to the new release branch you are about to create (``3.X``).
- Bump version numbers via the release script::
- $ .../release-tools/release.py --bump X.Y.ZaN
+ $ .../release-tools/release.py --bump 3.X.YaN
- Reminder: X, Y, Z, and N should be integers.
+ Reminder: X, Y, and N should be integers.
a should be one of "a", "b", or "rc" (e.g. "3.4.3rc1").
For **final** releases omit the aN ("3.4.3"). For the first
- release of a new version Z should be 0 ("3.6.0").
+ release of a new version Y should be 0 ("3.6.0").
This automates updating various release numbers, but you will have to
modify a few files manually. If your $EDITOR environment variable is
@@ -285,11 +275,8 @@ to perform some manual editing steps.
Properties). This isn't a C include file, it's a Windows
"resource file" include file.
-- Check with the IE (if there is one ) to be sure that
- Lib/idlelib/NEWS.txt has been similarly updated.
-
- For a **final** major release, edit the first paragraph of
- Doc/whatsnew/X.Y.rst to include the actual release date; e.g. "Python
+ Doc/whatsnew/3.X.rst to include the actual release date; e.g. "Python
2.5 was released on August 1, 2003." There's no need to edit this for
alpha or beta releases.
@@ -298,22 +285,14 @@ to perform some manual editing steps.
You should not see any files. I.e. you better not have any uncommitted
changes in your working directory.
-- Tag the release for X.Y.ZaN::
+- Tag the release for 3.X.YaN::
- $ .../release-tools/release.py --tag X.Y.ZaN
+ $ .../release-tools/release.py --tag 3.X.YaN
- This executes a `git tag` command with the `-s` option so that the
+ This executes a ``git tag`` command with the ``-s`` option so that the
release tag in the repo is signed with your gpg key. When prompted
choose the private key you use for signing release tarballs etc.
-- For a **new branch** release, add it to the ``VERSIONS`` list of
- `docsbuild scripts`_, so that the new maintenance branch is now
- ``pre-release`` and add the new ``in development`` version.
-
-- For a **final** major release, update the ``VERSIONS`` list of
- `docsbuild scripts`_: the release branch must be changed from
- ``pre-release`` to ``stable``.
-
- For **begin security-only mode** and **end-of-life** releases, review the
two files and update the versions accordingly in all active branches.
@@ -321,11 +300,11 @@ to perform some manual editing steps.
the source gzip and xz tarballs,
documentation tar and zip files, and gpg signature files::
- $ .../release-tools/release.py --export X.Y.ZaN
+ $ .../release-tools/release.py --export 3.X.YaN
This can take a while for **final** releases, and it will leave all the
- tarballs and signatures in a subdirectory called ``X.Y.ZaN/src``, and the
- built docs in ``X.Y.ZaN/docs`` (for **final** releases).
+ tarballs and signatures in a subdirectory called ``3.X.YaN/src``, and the
+ built docs in ``3.X.YaN/docs`` (for **final** releases).
Note that the script will sign your release with Sigstore. Please use
your **@python.org** email address for this. See here for more information:
@@ -368,20 +347,16 @@ to perform some manual editing steps.
- Notify the experts that they can start building binaries.
-- STOP STOP STOP STOP STOP STOP STOP STOP
+.. warning::
- At this point you must receive the "green light" from other experts in
- order to create the release. There are things you can do while you wait
+ **STOP**: at this point you must receive the "green light" from other experts
+ in order to create the release. There are things you can do while you wait
though, so keep reading until you hit the next STOP.
- The WE generates and publishes the Windows files using the Azure
Pipelines build scripts in ``.azure-pipelines/windows-release/``,
currently set up at https://dev.azure.com/Python/cpython/_build?definitionId=21.
- Note that this build requires a separate VM containing the code signing
- certificate. This VM is managed by the WE to ensure only official releases
- have access to the certificate.
-
The build process runs in multiple stages, with each stage's output being
available as a downloadable artifact. The stages are:
@@ -420,7 +395,7 @@ to perform some manual editing steps.
over there. Our policy is that every Python version gets its own
directory, but each directory contains all releases of that version.
- - On downloads.nyc1.psf.io, cd /srv/www.python.org/ftp/python/X.Y.Z
+ - On downloads.nyc1.psf.io, ``cd /srv/www.python.org/ftp/python/3.X.Y``
creating it if necessary. Make sure it is owned by group 'downloads'
and group-writable.
@@ -434,33 +409,28 @@ to perform some manual editing steps.
- Use ``gpg --verify`` to make sure they got uploaded intact.
- If this is a **final** or rc release: Move the doc zips and tarballs to
- ``/srv/www.python.org/ftp/python/doc/X.Y.Z[rcA]``, creating the directory
+ ``/srv/www.python.org/ftp/python/doc/3.X.Y[rcA]``, creating the directory
if necessary, and adapt the "current" symlink in ``.../doc`` to point to
that directory. Note though that if you're releasing a maintenance
release for an older version, don't change the current link.
- If this is a **final** or rc release (even a maintenance release), also
- unpack the HTML docs to ``/srv/docs.python.org/release/X.Y.Z[rcA]`` on
+ unpack the HTML docs to ``/srv/docs.python.org/release/3.X.Y[rcA]`` on
docs.nyc1.psf.io. Make sure the files are in group ``docs`` and are
- group-writeable. If it is a release of a security-fix-only version,
- tell the DE to start a build (``security-fixes`` and ``EOL`` version
- are not built daily).
+ group-writeable.
- Let the DE check if the docs are built and work all right.
- - If this is a **final** major release: Tell the DE to adapt redirects for
- docs.python.org/X.Y in the nginx config for docs.python.org.
-
- Note both the documentation and downloads are behind a caching CDN. If
you change archives after downloading them through the website, you'll
need to purge the stale data in the CDN like this::
- $ curl -X PURGE https://www.python.org/ftp/python/2.7.5/Python-2.7.5.tar.xz
+ $ curl -X PURGE https://www.python.org/ftp/python/3.12.0/Python-3.12.0.tar.xz
You should always purge the cache of the directory listing as people
use that to browse the release files::
- $ curl -X PURGE https://www.python.org/ftp/python/2.7.5/
+ $ curl -X PURGE https://www.python.org/ftp/python/3.12.0/
- For the extra paranoid, do a completely clean test of the release.
This includes downloading the tarball from www.python.org.
@@ -475,18 +445,20 @@ to perform some manual editing steps.
To ensure that the regression test suite passes. If not, you
screwed up somewhere!
-- STOP STOP STOP STOP STOP STOP STOP STOP
+.. warning::
- - Have you gotten the green light from the WE?
+ **STOP** and confirm:
- - Have you gotten the green light from the ME?
+ - Have you gotten the green light from the WE?
- - Have you gotten the green light from the DE?
+ - Have you gotten the green light from the ME?
+
+ - Have you gotten the green light from the DE?
If green, it's time to merge the release engineering branch back into
the main repo.
-- In order to push your changes to Github, you'll have to temporarily
+- In order to push your changes to GitHub, you'll have to temporarily
disable branch protection for administrators. Go to the
``Settings | Branches`` page:
@@ -511,18 +483,18 @@ the main repo.
# 2. Else, for all other releases, checkout the
# appropriate release branch.
- $ git checkout X.Y
+ $ git checkout 3.X
# Fetch the newly created and signed tag from your clone repo
- $ git fetch --tags git@github.com:your-github-id/cpython.git vX.Y.ZaN
+ $ git fetch --tags git@github.com:your-github-id/cpython.git v3.X.YaN
# Merge the temporary release engineering branch back into
- $ git merge --no-squash vX.Y.ZaN
+ $ git merge --no-squash v3.X.YaN
$ git commit -m 'Merge release engineering branch'
- If this is a **new branch** release, i.e. first beta,
now create the new release branch::
- $ git checkout -b X.Y
+ $ git checkout -b 3.X
Do any steps needed to setup the new release branch, including:
@@ -532,13 +504,13 @@ the main repo.
- For *all* releases, do the guided post-release steps with the
release script.::
- $ .../release-tools/release.py --done X.Y.ZaN
+ $ .../release-tools/release.py --done 3.X.YaN
- For a **final** or **release candidate 2+** release, you may need to
do some post-merge cleanup. Check the top-level ``README.rst``
and ``include/patchlevel.h`` files to ensure they now reflect
the desired post-release values for on-going development.
- The patchlevel should be the release tag with a `+`.
+ The patchlevel should be the release tag with a ``+``.
Also, if you cherry-picked changes from the standard release
branch into the release engineering branch for this release,
you will now need to manual remove each blurb entry from
@@ -546,8 +518,8 @@ the main repo.
into the release you are working on since that blurb entry
is now captured in the merged x.y.z.rst file for the new
release. Otherwise, the blurb entry will appear twice in
- the `changelog.html` file, once under `Python next` and again
- under `x.y.z`.
+ the ``changelog.html`` file, once under ``Python next`` and again
+ under ``x.y.z``.
- Review and commit these changes::
@@ -621,27 +593,27 @@ the main repo.
$ git push --tags git@github.com:python/cpython.git main
# For a **new branch** release, i.e. first beta:
- $ git push --dry-run --tags git@github.com:python/cpython.git X.Y
+ $ git push --dry-run --tags git@github.com:python/cpython.git 3.X
$ git push --dry-run --tags git@github.com:python/cpython.git main
# If it looks OK, take the plunge. There's no going back!
- $ git push --tags git@github.com:python/cpython.git X.Y
+ $ git push --tags git@github.com:python/cpython.git 3.X
$ git push --tags git@github.com:python/cpython.git main
# For all other releases:
- $ git push --dry-run --tags git@github.com:python/cpython.git X.Y
+ $ git push --dry-run --tags git@github.com:python/cpython.git 3.X
# If it looks OK, take the plunge. There's no going back!
- $ git push --tags git@github.com:python/cpython.git X.Y
+ $ git push --tags git@github.com:python/cpython.git 3.X
- If this is a **new branch** release, add a ``Branch protection rule``
- for the newly created branch (X.Y). Look at the values for the previous
- release branch (X.Y-1) and use them as a template.
+ for the newly created branch (3.X). Look at the values for the previous
+ release branch (3.X-1) and use them as a template.
https://github.com/python/cpython/settings/branches/
- Also, add a ``needs backport to X.Y`` label to the Github repo.
+ Also, add a ``needs backport to 3.X`` label to the GitHub repo.
https://github.com/python/cpython/labels
- You can now re-enable enforcement of branch settings against administrators
- on Github. Go back to the ``Settings | Branch`` page:
+ on GitHub. Go back to the ``Settings | Branch`` page:
https://github.com/python/cpython/settings/branches/
@@ -692,10 +664,8 @@ with RevSys.)
Keep a copy in your home directory on dl-files and
keep it fresh.
- If new types of files are added to the release
- (e.g. the web-based installers or redistributable zip
- files added to Python 3.5) someone will need to update
- add-to-pydotorg.py so it recognizes these new files.
+ If new types of files are added to the release, someone will need to
+ update add-to-pydotorg.py so it recognizes these new files.
(It's best to update add-to-pydotorg.py when file types
are removed, too.)
@@ -712,22 +682,22 @@ with RevSys.)
- If this is a **final** release:
- Add the new version to the *Python Documentation by Version*
- page `https://www.python.org/doc/versions/` and
+ page ``https://www.python.org/doc/versions/`` and
remove the current version from any 'in development' section.
- - For X.Y.Z, edit all the previous X.Y releases' page(s) to
+ - For 3.X.Y, edit all the previous X.Y releases' page(s) to
point to the new release. This includes the content field of the
- `Downloads -> Releases` entry for the release::
+ ``Downloads -> Releases`` entry for the release::
- Note: Python x.y.m has been superseded by
- `Python x.y.n `_.
+ Note: Python 3.x.(y-1) has been superseded by
+ `Python 3.x.y `_.
And, for those releases having separate release page entries
(phasing these out?), update those pages as well,
- e.g. `download/releases/x.y.z`::
+ e.g. ``download/releases/3.x.y``::
- Note: Python x.y.m has been superseded by
- `Python x.y.n `_.
+ Note: Python 3.x.(y-1) has been superseded by
+ `Python 3.x.y `_.
- Update the "Current Pre-release Testing Versions web page".
@@ -739,12 +709,11 @@ with RevSys.)
Every time you make a release, one way or another you'll
have to update this page:
- - If you're releasing a version before *x.y.0*,
- or *x.y.z release candidate N,*
+ - If you're releasing a version before *3.x.0*,
you should add it to this page, removing the previous pre-release
- of version *x.y* as needed.
+ of version *3.x* as needed.
- - If you're releasing *x.y.z final*, you need to remove the pre-release
+ - If you're releasing *3.x.0 final*, you need to remove the pre-release
version from this page.
This is in the "Pages" category on the Django-based website, and finding
@@ -764,15 +733,12 @@ with RevSys.)
should go. And yes you should be able to click on the link above then
press the shiny, exciting "Edit this page" button.
- - Other steps (other update for new web site)??
-
-- Write the announcement for the mailing lists. This is the
+- Write the announcement on https://discuss.python.org/. This is the
fuzzy bit because not much can be automated. You can use an earlier
announcement as a template, but edit it for content!
-
-- Once the announcement is ready, send it to the following
- addresses:
+- Once the announcement is up on Discourse, send an equivalent to the
+ following mailing lists:
python-list@python.org
python-announce@python.org
@@ -783,29 +749,19 @@ with RevSys.)
To add a new entry, go to
`your Blogger home page, here. `_
-- Send email to python-committers informing them that the release has been
- published and a reminder about any relevant changes in policy
- based on the phase of the release cycle. In particular,
- if this is a **new branch** release, remind everyone that the
- new release branch exists and that they need to start
- considering whether to backport to it when merging changes to
- main.
+- Update any release PEPs (e.g. 719) with the release dates.
-- Update any release PEPs (e.g. 361) with the release dates.
+- Update the labels on https://github.com/python/cpython/issues:
-- Update the tracker at https://bugs.python.org:
-
- - Flip all the deferred blocker issues back to release blocker
+ - Flip all the deferred-blocker issues back to release-blocker
for the next release.
- - Add version X.Y+1 as when version X.Y enters alpha.
+ - Add version 3.X+1 as when version 3.X enters alpha.
- - Change non-doc RFEs to version X.Y+1 when version X.Y enters beta.
+ - Change non-doc feature requests to version 3.X+1 when version 3.X
+ enters beta.
- - Add ``X.Yregression`` keyword (https://bugs.python.org/keyword)
- when version X.Y enters beta.
-
- - Update 'behavior' issues from versions that your release make
+ - Update issues from versions that your release makes
unsupported to the next supported version.
- Review open issues, as this might find lurking showstopper bugs,
@@ -817,13 +773,8 @@ with RevSys.)
pieces of the development infrastructure are updated for the new branch.
These include:
- - Update the issue tracker for the new branch.
-
- * Add the new version to the versions list (contact the tracker
- admins?).
-
- * Add a `regressions keyword `_
- for the release
+ - Update the issue tracker for the new branch: add the new version to
+ the versions list.
- Update the devguide to reflect the new branches and versions.
@@ -831,12 +782,10 @@ with RevSys.)
`downloads page `_.
(See https://github.com/python/pythondotorg/issues/1302)
- - Ensure buildbots are defined for the new branch (contact zware).
+ - Ensure buildbots are defined for the new branch (contact Łukasz
+ or Zach Ware).
- - Ensure the daily docs build scripts are updated to include
- the new branch (contact DE).
-
- - Ensure the various Github bots are updated, as needed, for the
+ - Ensure the various GitHub bots are updated, as needed, for the
new branch, in particular, make sure backporting to the new
branch works (contact core-workflow team)
https://github.com/python/core-workflow/issues
@@ -883,16 +832,6 @@ else does them. Some of those tasks include:
- Optionally making a final release to publish any remaining unreleased
changes.
-- Update the ``VERSIONS`` list of `docsbuild scripts`_: change the
- version state to ``EOL``.
-
-- On the docs download server (docs.nyc1.psf.io), ensure the top-level
- symlink points to the upload of unpacked html docs from final release::
-
- cd /srv/docs.python.org
- ls -l 3.3
- lrwxrwxrwx 1 nad docs 13 Sep 6 21:38 3.3 -> release/3.3.7
-
- Freeze the state of the release branch by creating a tag of its current HEAD
and then deleting the branch from the cpython repo. The current HEAD should
be at or beyond the final security release for the branch::
@@ -904,12 +843,12 @@ else does them. Some of those tasks include:
- If all looks good, delete the branch. This may require the assistance of
someone with repo administrator privileges::
- git push upstream --delete 3.3 # or perform from Github Settings page
+ git push upstream --delete 3.3 # or perform from GitHub Settings page
- Remove the release from the list of "Active Python Releases" on the Downloads
page. To do this, log in to the admin page for python.org, navigate to Boxes,
- and edit the `downloads-active-releases` entry. Simply strip out the relevant
- paragraph of HTML for your release. (You'll probably have to do the `curl -X PURGE`
+ and edit the ``downloads-active-releases`` entry. Simply strip out the relevant
+ paragraph of HTML for your release. (You'll probably have to do the ``curl -X PURGE``
trick to purge the cache if you want to confirm you made the change correctly.)
- Add retired notice to each release page on python.org for the retired branch.
@@ -923,31 +862,20 @@ else does them. Some of those tasks include:
list (https://devguide.python.org/devcycle/#end-of-life-branches) and update
or remove references to the branch elsewhere in the devguide.
-- Retire the release from the bugs.python.org issue tracker. Tasks include:
+- Retire the release from the issue tracker. Tasks include:
- * remove branch from tracker list of versions
+ * remove version label from list of versions
- * remove any release-release keywords (3.3regressions)
+ * remove the "needs backport to" label for the retired version
* review and dispose of open issues marked for this branch
- Note, with the likely future migration of bug tracking from the current
- Roundup bugs.python.org to Github issues and with the impending end-of-life
- of Python 2.7, it probably makes sense to avoid unnecessary churn for
- currently and about-to-be retired 3.x branches by deferring any major
- wholesale changes to existing issues until the migration process is
- clarified.
-
- In practice, you're probably not going to do this yourself, you're going
- to ask one of the bpo maintainers to do it for you (e.g. Ezio Melotti,
- Zachary Ware.)
-
- Announce the branch retirement in the usual places:
- * mailing lists (python-committers, python-dev, python-list, python-announcements)
-
* discuss.python.org
+ * mailing lists (python-dev, python-list, python-announcements)
+
* Python Dev blog
- Enjoy your retirement and bask in the glow of a job well done!
@@ -956,12 +884,12 @@ else does them. Some of those tasks include:
Windows Notes
=============
-NOTE, have Steve Dower review; probably obsolete.
-
Windows has a MSI installer, various flavors of Windows have
"special limitations", and the Windows installer also packs
-precompiled "foreign" binaries (Tcl/Tk, expat, etc). So Windows
-testing is tiresome but very necessary.
+precompiled "foreign" binaries (Tcl/Tk, expat, etc).
+
+The installer is tested as part of the Azure Pipeline. In the past,
+those steps were performed manually. We're keeping this for posterity.
Concurrent with uploading the installer, the WE installs Python
from it twice: once into the default directory suggested by the
@@ -994,9 +922,6 @@ Copyright
This document has been placed in the public domain.
-.. _docsbuild scripts:
- https://github.com/python/docsbuild-scripts/blob/main/build_docs.py
-
..
Local Variables:
mode: indented-text
diff --git a/pep-0102.txt b/peps/pep-0102.rst
similarity index 100%
rename from pep-0102.txt
rename to peps/pep-0102.rst
diff --git a/pep-0103.txt b/peps/pep-0103.rst
similarity index 100%
rename from pep-0103.txt
rename to peps/pep-0103.rst
diff --git a/pep-0160.txt b/peps/pep-0160.rst
similarity index 100%
rename from pep-0160.txt
rename to peps/pep-0160.rst
diff --git a/pep-0200.txt b/peps/pep-0200.rst
similarity index 100%
rename from pep-0200.txt
rename to peps/pep-0200.rst
diff --git a/pep-0201.txt b/peps/pep-0201.rst
similarity index 99%
rename from pep-0201.txt
rename to peps/pep-0201.rst
index 71454d9ae..7b1c77af3 100644
--- a/pep-0201.txt
+++ b/peps/pep-0201.rst
@@ -46,8 +46,8 @@ Lockstep For-Loops
Lockstep for-loops are non-nested iterations over two or more
sequences, such that at each pass through the loop, one element from
each sequence is taken to compose the target. This behavior can
-already be accomplished in Python through the use of the map() built-
-in function::
+already be accomplished in Python through the use of the map() built-in
+function::
>>> a = (1, 2, 3)
>>> b = (4, 5, 6)
diff --git a/pep-0202.txt b/peps/pep-0202.rst
similarity index 100%
rename from pep-0202.txt
rename to peps/pep-0202.rst
diff --git a/pep-0203.txt b/peps/pep-0203.rst
similarity index 100%
rename from pep-0203.txt
rename to peps/pep-0203.rst
diff --git a/pep-0204.txt b/peps/pep-0204.rst
similarity index 100%
rename from pep-0204.txt
rename to peps/pep-0204.rst
diff --git a/pep-0205.txt b/peps/pep-0205.rst
similarity index 99%
rename from pep-0205.txt
rename to peps/pep-0205.rst
index d746d7b02..e16c2d3dc 100644
--- a/pep-0205.txt
+++ b/peps/pep-0205.rst
@@ -185,8 +185,8 @@ Implementation Strategy
=======================
The implementation of weak references will include a list of
-reference containers that must be cleared for each weakly-
-referencable object. If the reference is from a weak dictionary,
+reference containers that must be cleared for each weakly-referencable
+object. If the reference is from a weak dictionary,
the dictionary entry is cleared first. Then, any associated
callback is called with the object passed as a parameter. Once
all callbacks have been called, the object is finalized and
diff --git a/pep-0206.txt b/peps/pep-0206.rst
similarity index 100%
rename from pep-0206.txt
rename to peps/pep-0206.rst
diff --git a/pep-0207.txt b/peps/pep-0207.rst
similarity index 100%
rename from pep-0207.txt
rename to peps/pep-0207.rst
diff --git a/pep-0208.txt b/peps/pep-0208.rst
similarity index 100%
rename from pep-0208.txt
rename to peps/pep-0208.rst
diff --git a/pep-0209.txt b/peps/pep-0209.rst
similarity index 98%
rename from pep-0209.txt
rename to peps/pep-0209.rst
index f3ffd2f93..c91a15f0a 100644
--- a/pep-0209.txt
+++ b/peps/pep-0209.rst
@@ -12,9 +12,9 @@ Post-History:
Abstract
========
-This PEP proposes a redesign and re-implementation of the multi-
-dimensional array module, Numeric, to make it easier to add new
-features and functionality to the module. Aspects of Numeric 2
+This PEP proposes a redesign and re-implementation of the
+multi-dimensional array module, Numeric, to make it easier to add
+new features and functionality to the module. Aspects of Numeric 2
that will receive special attention are efficient access to arrays
exceeding a gigabyte in size and composed of inhomogeneous data
structures or records. The proposed design uses four Python
@@ -128,8 +128,8 @@ Some planned features are:
automatically handle alignment and representational issues
when data is accessed or operated on. There are two
approaches to implementing records; as either a derived array
- class or a special array type, depending on your point-of-
- view. We defer this discussion to the Open Issues section.
+ class or a special array type, depending on your point-of-view.
+ We defer this discussion to the Open Issues section.
2. Additional array types
@@ -265,8 +265,8 @@ The design of Numeric 2 has four primary classes:
_ufunc.compute(slice, data, func, swap, conv)
The 'func' argument is a CFuncObject, while the 'swap' and 'conv'
- arguments are lists of CFuncObjects for those arrays needing pre-
- or post-processing, otherwise None is used. The data argument is
+ arguments are lists of CFuncObjects for those arrays needing pre- or
+ post-processing, otherwise None is used. The data argument is
a list of buffer objects, and the slice argument gives the number
of iterations for each dimension along with the buffer offset and
step size for each array and each dimension.
diff --git a/pep-0210.txt b/peps/pep-0210.rst
similarity index 100%
rename from pep-0210.txt
rename to peps/pep-0210.rst
diff --git a/pep-0211.txt b/peps/pep-0211.rst
similarity index 100%
rename from pep-0211.txt
rename to peps/pep-0211.rst
diff --git a/pep-0212.txt b/peps/pep-0212.rst
similarity index 100%
rename from pep-0212.txt
rename to peps/pep-0212.rst
diff --git a/pep-0213.txt b/peps/pep-0213.rst
similarity index 100%
rename from pep-0213.txt
rename to peps/pep-0213.rst
diff --git a/pep-0214.txt b/peps/pep-0214.rst
similarity index 100%
rename from pep-0214.txt
rename to peps/pep-0214.rst
diff --git a/pep-0215.txt b/peps/pep-0215.rst
similarity index 100%
rename from pep-0215.txt
rename to peps/pep-0215.rst
diff --git a/pep-0216.txt b/peps/pep-0216.rst
similarity index 100%
rename from pep-0216.txt
rename to peps/pep-0216.rst
diff --git a/pep-0217.txt b/peps/pep-0217.rst
similarity index 100%
rename from pep-0217.txt
rename to peps/pep-0217.rst
diff --git a/pep-0218.txt b/peps/pep-0218.rst
similarity index 100%
rename from pep-0218.txt
rename to peps/pep-0218.rst
diff --git a/pep-0219.txt b/peps/pep-0219.rst
similarity index 100%
rename from pep-0219.txt
rename to peps/pep-0219.rst
diff --git a/pep-0220.txt b/peps/pep-0220.rst
similarity index 100%
rename from pep-0220.txt
rename to peps/pep-0220.rst
diff --git a/pep-0221.txt b/peps/pep-0221.rst
similarity index 100%
rename from pep-0221.txt
rename to peps/pep-0221.rst
diff --git a/pep-0222.txt b/peps/pep-0222.rst
similarity index 100%
rename from pep-0222.txt
rename to peps/pep-0222.rst
diff --git a/pep-0223.txt b/peps/pep-0223.rst
similarity index 100%
rename from pep-0223.txt
rename to peps/pep-0223.rst
diff --git a/pep-0224.txt b/peps/pep-0224.rst
similarity index 100%
rename from pep-0224.txt
rename to peps/pep-0224.rst
diff --git a/pep-0225.txt b/peps/pep-0225.rst
similarity index 100%
rename from pep-0225.txt
rename to peps/pep-0225.rst
diff --git a/pep-0226.txt b/peps/pep-0226.rst
similarity index 100%
rename from pep-0226.txt
rename to peps/pep-0226.rst
diff --git a/pep-0227.txt b/peps/pep-0227.rst
similarity index 100%
rename from pep-0227.txt
rename to peps/pep-0227.rst
diff --git a/pep-0228.txt b/peps/pep-0228.rst
similarity index 100%
rename from pep-0228.txt
rename to peps/pep-0228.rst
diff --git a/pep-0229.txt b/peps/pep-0229.rst
similarity index 100%
rename from pep-0229.txt
rename to peps/pep-0229.rst
diff --git a/pep-0230.txt b/peps/pep-0230.rst
similarity index 100%
rename from pep-0230.txt
rename to peps/pep-0230.rst
diff --git a/pep-0231.txt b/peps/pep-0231.rst
similarity index 100%
rename from pep-0231.txt
rename to peps/pep-0231.rst
diff --git a/pep-0232.txt b/peps/pep-0232.rst
similarity index 100%
rename from pep-0232.txt
rename to peps/pep-0232.rst
diff --git a/pep-0233.txt b/peps/pep-0233.rst
similarity index 100%
rename from pep-0233.txt
rename to peps/pep-0233.rst
diff --git a/pep-0234.txt b/peps/pep-0234.rst
similarity index 100%
rename from pep-0234.txt
rename to peps/pep-0234.rst
diff --git a/pep-0235.txt b/peps/pep-0235.rst
similarity index 97%
rename from pep-0235.txt
rename to peps/pep-0235.rst
index f152caa9c..d5a374afa 100644
--- a/pep-0235.txt
+++ b/peps/pep-0235.rst
@@ -125,8 +125,8 @@ A. If the ``PYTHONCASEOK`` environment variable exists, same as
B. Else search ``sys.path`` for the first case-sensitive match; raise
``ImportError`` if none found.
-#B is the same rule as is used on Unix, so this will improve cross-
-platform portability. That's good. #B is also the rule the Mac
+#B is the same rule as is used on Unix, so this will improve
+cross-platform portability. That's good. #B is also the rule the Mac
and Cygwin folks want (and wanted enough to implement themselves,
multiple times, which is a powerful argument in PythonLand). It
can't cause any existing non-exceptional Windows import to fail,
diff --git a/pep-0236.txt b/peps/pep-0236.rst
similarity index 100%
rename from pep-0236.txt
rename to peps/pep-0236.rst
diff --git a/pep-0237.txt b/peps/pep-0237.rst
similarity index 100%
rename from pep-0237.txt
rename to peps/pep-0237.rst
diff --git a/pep-0238.txt b/peps/pep-0238.rst
similarity index 100%
rename from pep-0238.txt
rename to peps/pep-0238.rst
diff --git a/pep-0239.txt b/peps/pep-0239.rst
similarity index 100%
rename from pep-0239.txt
rename to peps/pep-0239.rst
diff --git a/pep-0240.txt b/peps/pep-0240.rst
similarity index 100%
rename from pep-0240.txt
rename to peps/pep-0240.rst
diff --git a/pep-0241.txt b/peps/pep-0241.rst
similarity index 100%
rename from pep-0241.txt
rename to peps/pep-0241.rst
diff --git a/pep-0242.txt b/peps/pep-0242.rst
similarity index 100%
rename from pep-0242.txt
rename to peps/pep-0242.rst
diff --git a/pep-0243.txt b/peps/pep-0243.rst
similarity index 100%
rename from pep-0243.txt
rename to peps/pep-0243.rst
diff --git a/pep-0244.txt b/peps/pep-0244.rst
similarity index 100%
rename from pep-0244.txt
rename to peps/pep-0244.rst
diff --git a/pep-0245.txt b/peps/pep-0245.rst
similarity index 100%
rename from pep-0245.txt
rename to peps/pep-0245.rst
diff --git a/pep-0246.txt b/peps/pep-0246.rst
similarity index 100%
rename from pep-0246.txt
rename to peps/pep-0246.rst
diff --git a/pep-0247.txt b/peps/pep-0247.rst
similarity index 100%
rename from pep-0247.txt
rename to peps/pep-0247.rst
diff --git a/pep-0248.txt b/peps/pep-0248.rst
similarity index 100%
rename from pep-0248.txt
rename to peps/pep-0248.rst
diff --git a/pep-0249.txt b/peps/pep-0249.rst
similarity index 99%
rename from pep-0249.txt
rename to peps/pep-0249.rst
index 629a8ba89..d8a409cc5 100644
--- a/pep-0249.txt
+++ b/peps/pep-0249.rst
@@ -938,8 +938,8 @@ Cursor\ `.lastrowid`_
Connection\ `.autocommit`_
Attribute to query and set the autocommit mode of the connection.
- Return ``True`` if the connection is operating in autocommit (non-
- transactional) mode. Return ``False`` if the connection is
+ Return ``True`` if the connection is operating in autocommit
+ (non-transactional) mode. Return ``False`` if the connection is
operating in manual commit (transactional) mode.
Setting the attribute to ``True`` or ``False`` adjusts the
diff --git a/pep-0250.txt b/peps/pep-0250.rst
similarity index 100%
rename from pep-0250.txt
rename to peps/pep-0250.rst
diff --git a/pep-0251.txt b/peps/pep-0251.rst
similarity index 100%
rename from pep-0251.txt
rename to peps/pep-0251.rst
diff --git a/pep-0252.txt b/peps/pep-0252.rst
similarity index 100%
rename from pep-0252.txt
rename to peps/pep-0252.rst
diff --git a/pep-0253.txt b/peps/pep-0253.rst
similarity index 100%
rename from pep-0253.txt
rename to peps/pep-0253.rst
diff --git a/pep-0254.txt b/peps/pep-0254.rst
similarity index 100%
rename from pep-0254.txt
rename to peps/pep-0254.rst
diff --git a/pep-0255.txt b/peps/pep-0255.rst
similarity index 100%
rename from pep-0255.txt
rename to peps/pep-0255.rst
diff --git a/pep-0256.txt b/peps/pep-0256.rst
similarity index 100%
rename from pep-0256.txt
rename to peps/pep-0256.rst
diff --git a/pep-0257.txt b/peps/pep-0257.rst
similarity index 100%
rename from pep-0257.txt
rename to peps/pep-0257.rst
diff --git a/pep-0258.txt b/peps/pep-0258.rst
similarity index 100%
rename from pep-0258.txt
rename to peps/pep-0258.rst
diff --git a/pep-0259.txt b/peps/pep-0259.rst
similarity index 100%
rename from pep-0259.txt
rename to peps/pep-0259.rst
diff --git a/pep-0260.txt b/peps/pep-0260.rst
similarity index 100%
rename from pep-0260.txt
rename to peps/pep-0260.rst
diff --git a/pep-0261.txt b/peps/pep-0261.rst
similarity index 100%
rename from pep-0261.txt
rename to peps/pep-0261.rst
diff --git a/pep-0262.txt b/peps/pep-0262.rst
similarity index 100%
rename from pep-0262.txt
rename to peps/pep-0262.rst
diff --git a/pep-0263.txt b/peps/pep-0263.rst
similarity index 100%
rename from pep-0263.txt
rename to peps/pep-0263.rst
diff --git a/pep-0264.txt b/peps/pep-0264.rst
similarity index 100%
rename from pep-0264.txt
rename to peps/pep-0264.rst
diff --git a/pep-0265.txt b/peps/pep-0265.rst
similarity index 100%
rename from pep-0265.txt
rename to peps/pep-0265.rst
diff --git a/pep-0266.txt b/peps/pep-0266.rst
similarity index 100%
rename from pep-0266.txt
rename to peps/pep-0266.rst
diff --git a/pep-0267.txt b/peps/pep-0267.rst
similarity index 100%
rename from pep-0267.txt
rename to peps/pep-0267.rst
diff --git a/pep-0268.txt b/peps/pep-0268.rst
similarity index 100%
rename from pep-0268.txt
rename to peps/pep-0268.rst
diff --git a/pep-0269.txt b/peps/pep-0269.rst
similarity index 100%
rename from pep-0269.txt
rename to peps/pep-0269.rst
diff --git a/pep-0270.txt b/peps/pep-0270.rst
similarity index 100%
rename from pep-0270.txt
rename to peps/pep-0270.rst
diff --git a/pep-0271.txt b/peps/pep-0271.rst
similarity index 100%
rename from pep-0271.txt
rename to peps/pep-0271.rst
diff --git a/pep-0272.txt b/peps/pep-0272.rst
similarity index 100%
rename from pep-0272.txt
rename to peps/pep-0272.rst
diff --git a/pep-0273.txt b/peps/pep-0273.rst
similarity index 100%
rename from pep-0273.txt
rename to peps/pep-0273.rst
diff --git a/pep-0274.txt b/peps/pep-0274.rst
similarity index 100%
rename from pep-0274.txt
rename to peps/pep-0274.rst
diff --git a/pep-0275.txt b/peps/pep-0275.rst
similarity index 100%
rename from pep-0275.txt
rename to peps/pep-0275.rst
diff --git a/pep-0276.txt b/peps/pep-0276.rst
similarity index 100%
rename from pep-0276.txt
rename to peps/pep-0276.rst
diff --git a/pep-0277.txt b/peps/pep-0277.rst
similarity index 100%
rename from pep-0277.txt
rename to peps/pep-0277.rst
diff --git a/pep-0278.txt b/peps/pep-0278.rst
similarity index 100%
rename from pep-0278.txt
rename to peps/pep-0278.rst
diff --git a/pep-0279.txt b/peps/pep-0279.rst
similarity index 100%
rename from pep-0279.txt
rename to peps/pep-0279.rst
diff --git a/pep-0280.txt b/peps/pep-0280.rst
similarity index 100%
rename from pep-0280.txt
rename to peps/pep-0280.rst
diff --git a/pep-0281.txt b/peps/pep-0281.rst
similarity index 100%
rename from pep-0281.txt
rename to peps/pep-0281.rst
diff --git a/pep-0282.txt b/peps/pep-0282.rst
similarity index 99%
rename from pep-0282.txt
rename to peps/pep-0282.rst
index a328a01b3..36c6730eb 100644
--- a/pep-0282.txt
+++ b/peps/pep-0282.rst
@@ -613,7 +613,7 @@ References
http://java.sun.com/j2se/1.4/docs/guide/util/logging/
.. [2] log4j: a Java logging package
- http://jakarta.apache.org/log4j/docs/index.html
+ https://logging.apache.org/log4j/
.. [3] Protomatter's Syslog
http://protomatter.sourceforge.net/1.1.6/index.html
diff --git a/pep-0283.txt b/peps/pep-0283.rst
similarity index 100%
rename from pep-0283.txt
rename to peps/pep-0283.rst
diff --git a/pep-0284.txt b/peps/pep-0284.rst
similarity index 98%
rename from pep-0284.txt
rename to peps/pep-0284.rst
index 48c476f23..08fedf5ab 100644
--- a/pep-0284.txt
+++ b/peps/pep-0284.rst
@@ -1,9 +1,7 @@
PEP: 284
Title: Integer for-loops
-Version: $Revision$
-Last-Modified: $Date$
Author: David Eppstein ,
- Greg Ewing
+ Gregory Ewing
Status: Rejected
Type: Standards Track
Content-Type: text/x-rst
@@ -264,12 +262,3 @@ Copyright
=========
This document has been placed in the public domain.
-
-
-
-..
- Local Variables:
- mode: indented-text
- indent-tabs-mode: nil
- fill-column: 70
- End:
diff --git a/pep-0285.txt b/peps/pep-0285.rst
similarity index 100%
rename from pep-0285.txt
rename to peps/pep-0285.rst
diff --git a/pep-0286.txt b/peps/pep-0286.rst
similarity index 100%
rename from pep-0286.txt
rename to peps/pep-0286.rst
diff --git a/pep-0287.txt b/peps/pep-0287.rst
similarity index 100%
rename from pep-0287.txt
rename to peps/pep-0287.rst
diff --git a/pep-0288.txt b/peps/pep-0288.rst
similarity index 100%
rename from pep-0288.txt
rename to peps/pep-0288.rst
diff --git a/pep-0289.txt b/peps/pep-0289.rst
similarity index 100%
rename from pep-0289.txt
rename to peps/pep-0289.rst
diff --git a/pep-0290.txt b/peps/pep-0290.rst
similarity index 100%
rename from pep-0290.txt
rename to peps/pep-0290.rst
diff --git a/pep-0291.txt b/peps/pep-0291.rst
similarity index 100%
rename from pep-0291.txt
rename to peps/pep-0291.rst
diff --git a/pep-0292.txt b/peps/pep-0292.rst
similarity index 100%
rename from pep-0292.txt
rename to peps/pep-0292.rst
diff --git a/pep-0293.txt b/peps/pep-0293.rst
similarity index 100%
rename from pep-0293.txt
rename to peps/pep-0293.rst
diff --git a/pep-0294.txt b/peps/pep-0294.rst
similarity index 100%
rename from pep-0294.txt
rename to peps/pep-0294.rst
diff --git a/pep-0295.txt b/peps/pep-0295.rst
similarity index 100%
rename from pep-0295.txt
rename to peps/pep-0295.rst
diff --git a/pep-0296.txt b/peps/pep-0296.rst
similarity index 100%
rename from pep-0296.txt
rename to peps/pep-0296.rst
diff --git a/pep-0297.txt b/peps/pep-0297.rst
similarity index 100%
rename from pep-0297.txt
rename to peps/pep-0297.rst
diff --git a/pep-0298.txt b/peps/pep-0298.rst
similarity index 100%
rename from pep-0298.txt
rename to peps/pep-0298.rst
diff --git a/pep-0299.txt b/peps/pep-0299.rst
similarity index 100%
rename from pep-0299.txt
rename to peps/pep-0299.rst
diff --git a/pep-0301.txt b/peps/pep-0301.rst
similarity index 100%
rename from pep-0301.txt
rename to peps/pep-0301.rst
diff --git a/pep-0302.txt b/peps/pep-0302.rst
similarity index 99%
rename from pep-0302.txt
rename to peps/pep-0302.rst
index bdea0a363..29f9f799d 100644
--- a/pep-0302.txt
+++ b/peps/pep-0302.rst
@@ -428,7 +428,7 @@ built-in import mechanism". They simply won't invoke any import hooks. A new
if loader is not None:
loader.load_module(fullname)
-In the case of a "basic" import, one the `imp.find_module()` function would
+In the case of a "basic" import, one the ``imp.find_module()`` function would
handle, the loader object would be a wrapper for the current output of
``imp.find_module()``, and ``loader.load_module()`` would call
``imp.load_module()`` with that output.
diff --git a/pep-0303.txt b/peps/pep-0303.rst
similarity index 100%
rename from pep-0303.txt
rename to peps/pep-0303.rst
diff --git a/pep-0304.txt b/peps/pep-0304.rst
similarity index 100%
rename from pep-0304.txt
rename to peps/pep-0304.rst
diff --git a/pep-0305.txt b/peps/pep-0305.rst
similarity index 100%
rename from pep-0305.txt
rename to peps/pep-0305.rst
diff --git a/pep-0306.txt b/peps/pep-0306.rst
similarity index 97%
rename from pep-0306.txt
rename to peps/pep-0306.rst
index f066e44ff..c4d4a0bd9 100644
--- a/pep-0306.txt
+++ b/peps/pep-0306.rst
@@ -2,7 +2,7 @@ PEP: 306
Title: How to Change Python's Grammar
Version: $Revision$
Last-Modified: $Date$
-Author: Michael Hudson , Jack Diederich , Nick Coghlan , Benjamin Peterson
+Author: Michael Hudson , Jack Diederich , Alyssa Coghlan , Benjamin Peterson
Status: Withdrawn
Type: Informational
Content-Type: text/x-rst
diff --git a/pep-0307.txt b/peps/pep-0307.rst
similarity index 100%
rename from pep-0307.txt
rename to peps/pep-0307.rst
diff --git a/pep-0308.txt b/peps/pep-0308.rst
similarity index 100%
rename from pep-0308.txt
rename to peps/pep-0308.rst
diff --git a/pep-0309.txt b/peps/pep-0309.rst
similarity index 100%
rename from pep-0309.txt
rename to peps/pep-0309.rst
diff --git a/pep-0310.txt b/peps/pep-0310.rst
similarity index 99%
rename from pep-0310.txt
rename to peps/pep-0310.rst
index 09a389711..a327def99 100644
--- a/pep-0310.txt
+++ b/peps/pep-0310.rst
@@ -238,7 +238,7 @@ could be mentioned here.
https://mail.python.org/pipermail/python-dev/2003-August/037795.html
.. [3] Thread on python-dev with subject
- `[Python-Dev] pre-PEP: Resource-Release Support for Generators`
+ ``[Python-Dev] pre-PEP: Resource-Release Support for Generators``
starting at
https://mail.python.org/pipermail/python-dev/2003-August/037803.html
diff --git a/pep-0311.txt b/peps/pep-0311.rst
similarity index 100%
rename from pep-0311.txt
rename to peps/pep-0311.rst
diff --git a/pep-0312.txt b/peps/pep-0312.rst
similarity index 100%
rename from pep-0312.txt
rename to peps/pep-0312.rst
diff --git a/pep-0313.txt b/peps/pep-0313.rst
similarity index 100%
rename from pep-0313.txt
rename to peps/pep-0313.rst
diff --git a/pep-0314.txt b/peps/pep-0314.rst
similarity index 100%
rename from pep-0314.txt
rename to peps/pep-0314.rst
diff --git a/pep-0315.txt b/peps/pep-0315.rst
similarity index 100%
rename from pep-0315.txt
rename to peps/pep-0315.rst
diff --git a/pep-0316.txt b/peps/pep-0316.rst
similarity index 100%
rename from pep-0316.txt
rename to peps/pep-0316.rst
diff --git a/pep-0317.txt b/peps/pep-0317.rst
similarity index 100%
rename from pep-0317.txt
rename to peps/pep-0317.rst
diff --git a/pep-0318.txt b/peps/pep-0318.rst
similarity index 100%
rename from pep-0318.txt
rename to peps/pep-0318.rst
diff --git a/pep-0319.txt b/peps/pep-0319.rst
similarity index 100%
rename from pep-0319.txt
rename to peps/pep-0319.rst
diff --git a/pep-0320.txt b/peps/pep-0320.rst
similarity index 100%
rename from pep-0320.txt
rename to peps/pep-0320.rst
diff --git a/pep-0321.txt b/peps/pep-0321.rst
similarity index 100%
rename from pep-0321.txt
rename to peps/pep-0321.rst
diff --git a/pep-0322.txt b/peps/pep-0322.rst
similarity index 100%
rename from pep-0322.txt
rename to peps/pep-0322.rst
diff --git a/pep-0323.txt b/peps/pep-0323.rst
similarity index 100%
rename from pep-0323.txt
rename to peps/pep-0323.rst
diff --git a/pep-0324.txt b/peps/pep-0324.rst
similarity index 100%
rename from pep-0324.txt
rename to peps/pep-0324.rst
diff --git a/pep-0325.txt b/peps/pep-0325.rst
similarity index 100%
rename from pep-0325.txt
rename to peps/pep-0325.rst
diff --git a/pep-0326.txt b/peps/pep-0326.rst
similarity index 99%
rename from pep-0326.txt
rename to peps/pep-0326.rst
index bf5959a8f..20ddc6f12 100644
--- a/pep-0326.txt
+++ b/peps/pep-0326.rst
@@ -268,7 +268,7 @@ following problem [5]_:
and ``B``.
Such an algorithm is a 7 line modification to the `DijkstraSP_table`_
-algorithm given above (modified lines prefixed with `*`)::
+algorithm given above (modified lines prefixed with ``*``)::
def DijkstraSP_table(graph, S, T):
table = {} #3
diff --git a/pep-0327.txt b/peps/pep-0327.rst
similarity index 100%
rename from pep-0327.txt
rename to peps/pep-0327.rst
diff --git a/pep-0328.txt b/peps/pep-0328.rst
similarity index 100%
rename from pep-0328.txt
rename to peps/pep-0328.rst
diff --git a/pep-0329.txt b/peps/pep-0329.rst
similarity index 91%
rename from pep-0329.txt
rename to peps/pep-0329.rst
index 7b9f99b3c..b59e9c588 100644
--- a/pep-0329.txt
+++ b/peps/pep-0329.rst
@@ -49,14 +49,14 @@ of performance.
There are currently over a hundred instances of ``while 1`` in the
library. They were not replaced with the more readable ``while True``
because of performance reasons (the compiler cannot eliminate the test
-because `True` is not known to always be a constant). Conversion of
+because ``True`` is not known to always be a constant). Conversion of
True to a constant will clarify the code while retaining performance.
Many other basic Python operations run much slower because of global
lookups. In try/except statements, the trapped exceptions are
dynamically looked up before testing whether they match.
Similarly, simple identity tests such as ``while x is not None``
-require the `None` variable to be re-looked up on every pass.
+require the ``None`` variable to be re-looked up on every pass.
Builtin lookups are especially egregious because the enclosing global
scope must be checked first. These lookup chains devour cache space
that is best used elsewhere.
@@ -69,7 +69,7 @@ Proposal
========
Add a module called codetweaks.py which contains two functions,
-`bind_constants()` and `bind_all()`. The first function performs
+``bind_constants()`` and ``bind_all()``. The first function performs
constant binding and the second recursively applies it to every
function and class in a target module.
@@ -80,7 +80,7 @@ the end of the script::
codetweaks.bind_all(sys.modules[__name__])
In addition to binding builtins, there are some modules (like
-`sre_compile`) where it also makes sense to bind module variables
+``sre_compile``) where it also makes sense to bind module variables
as well as builtins into constants.
@@ -97,17 +97,17 @@ Questions and Answers
Every function has attributes with its bytecodes (the language of
the Python virtual machine) and a table of constants. The bind
- function scans the bytecodes for a `LOAD_GLOBAL` instruction and
+ function scans the bytecodes for a ``LOAD_GLOBAL`` instruction and
checks to see whether the value is already known. If so, it adds
that value to the constants table and replaces the opcode with
- `LOAD_CONSTANT`.
+ ``LOAD_CONSTANT``.
3. When does it work?
When a module is imported for the first time, python compiles the
bytecode and runs the binding optimization. Subsequent imports
just re-use the previous work. Each session repeats this process
- (the results are not saved in `pyc` files).
+ (the results are not saved in ``pyc`` files).
4. How do you know this works?
@@ -117,7 +117,7 @@ Questions and Answers
5. What if the module defines a variable shadowing a builtin?
This does happen. For instance, True can be redefined at the module
- level as `True = (1==1)`. The sample implementation below detects the
+ level as ``True = (1==1)``. The sample implementation below detects the
shadowing and leaves the global lookup unchanged.
6. Are you the first person to recognize that most global lookups are for
@@ -130,22 +130,22 @@ Questions and Answers
implementations?
Either do this before importing a module, or just reload the
- module, or disable `codetweaks.py` (it will have a disable flag).
+ module, or disable ``codetweaks.py`` (it will have a disable flag).
8. How susceptible is this module to changes in Python's byte coding?
- It imports `opcode.py` to protect against renumbering. Also, it
- uses `LOAD_CONST` and `LOAD_GLOBAL` which are fundamental and have
+ It imports ``opcode.py`` to protect against renumbering. Also, it
+ uses ``LOAD_CONST`` and ``LOAD_GLOBAL`` which are fundamental and have
been around forever. That notwithstanding, the coding scheme could
change and this implementation would have to change along with
- modules like `dis` which also rely on the current coding scheme.
+ modules like ``dis`` which also rely on the current coding scheme.
9. What is the effect on startup time?
I could not measure a difference. None of the startup modules are
bound except for warnings.py. Also, the binding function is very
fast, making just a single pass over the code string in search of
- the `LOAD_GLOBAL` opcode.
+ the ``LOAD_GLOBAL`` opcode.
Sample Implementation
diff --git a/pep-0330.txt b/peps/pep-0330.rst
similarity index 100%
rename from pep-0330.txt
rename to peps/pep-0330.rst
diff --git a/pep-0331.txt b/peps/pep-0331.rst
similarity index 100%
rename from pep-0331.txt
rename to peps/pep-0331.rst
diff --git a/pep-0332.txt b/peps/pep-0332.rst
similarity index 100%
rename from pep-0332.txt
rename to peps/pep-0332.rst
diff --git a/pep-0333.txt b/peps/pep-0333.rst
similarity index 99%
rename from pep-0333.txt
rename to peps/pep-0333.rst
index d0c6e8377..e57f89254 100644
--- a/pep-0333.txt
+++ b/peps/pep-0333.rst
@@ -596,9 +596,9 @@ Variable Value
``wsgi.input`` An input stream (file-like object) from which
the HTTP request body can be read. (The server
or gateway may perform reads on-demand as
- requested by the application, or it may pre-
- read the client's request body and buffer it
- in-memory or on disk, or use any other
+ requested by the application, or it may
+ pre-read the client's request body and buffer
+ it in-memory or on disk, or use any other
technique for providing such an input stream,
according to its preference.)
@@ -1341,8 +1341,8 @@ use only language features available in the target version, use
Optional Platform-Specific File Handling
----------------------------------------
-Some operating environments provide special high-performance file-
-transmission facilities, such as the Unix ``sendfile()`` call.
+Some operating environments provide special high-performance
+file-transmission facilities, such as the Unix ``sendfile()`` call.
Servers and gateways **may** expose this functionality via an optional
``wsgi.file_wrapper`` key in the ``environ``. An application
**may** use this "file wrapper" to convert a file or file-like object
diff --git a/pep-0334.txt b/peps/pep-0334.rst
similarity index 100%
rename from pep-0334.txt
rename to peps/pep-0334.rst
diff --git a/pep-0335.txt b/peps/pep-0335.rst
similarity index 100%
rename from pep-0335.txt
rename to peps/pep-0335.rst
diff --git a/pep-0336.txt b/peps/pep-0336.rst
similarity index 100%
rename from pep-0336.txt
rename to peps/pep-0336.rst
diff --git a/pep-0337.txt b/peps/pep-0337.rst
similarity index 100%
rename from pep-0337.txt
rename to peps/pep-0337.rst
diff --git a/pep-0338.txt b/peps/pep-0338.rst
similarity index 99%
rename from pep-0338.txt
rename to peps/pep-0338.rst
index 81a665541..f452ebdce 100644
--- a/pep-0338.txt
+++ b/peps/pep-0338.rst
@@ -2,7 +2,7 @@ PEP: 338
Title: Executing modules as scripts
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan
+Author: Alyssa Coghlan
Status: Final
Type: Standards Track
Content-Type: text/x-rst
diff --git a/pep-0339.txt b/peps/pep-0339.rst
similarity index 99%
rename from pep-0339.txt
rename to peps/pep-0339.rst
index 18e97d023..434a159c4 100644
--- a/pep-0339.txt
+++ b/peps/pep-0339.rst
@@ -550,7 +550,7 @@ References
----------
.. [Aho86] Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman.
- `Compilers: Principles, Techniques, and Tools`,
+ ``Compilers: Principles, Techniques, and Tools``,
http://www.amazon.com/exec/obidos/tg/detail/-/0201100886/104-0162389-6419108
.. [Wang97] Daniel C. Wang, Andrew W. Appel, Jeff L. Korn, and Chris
diff --git a/pep-0340.txt b/peps/pep-0340.rst
similarity index 99%
rename from pep-0340.txt
rename to peps/pep-0340.rst
index e6873a204..ab645a614 100644
--- a/pep-0340.txt
+++ b/peps/pep-0340.rst
@@ -554,7 +554,7 @@ In no useful order: Alex Martelli, Barry Warsaw, Bob Ippolito,
Brett Cannon, Brian Sabbey, Chris Ryland, Doug Landauer, Duncan
Booth, Fredrik Lundh, Greg Ewing, Holger Krekel, Jason Diamond,
Jim Jewett, Josiah Carlson, Ka-Ping Yee, Michael Chermside,
-Michael Hudson, Neil Schemenauer, Nick Coghlan, Paul Moore,
+Michael Hudson, Neil Schemenauer, Alyssa Coghlan, Paul Moore,
Phillip Eby, Raymond Hettinger, Georg Brandl, Samuele
Pedroni, Shannon Behrens, Skip Montanaro, Steven Bethard, Terry
Reedy, Tim Delaney, Aahz, and others. Thanks all for the valuable
diff --git a/pep-0341.txt b/peps/pep-0341.rst
similarity index 100%
rename from pep-0341.txt
rename to peps/pep-0341.rst
diff --git a/pep-0342.txt b/peps/pep-0342.rst
similarity index 100%
rename from pep-0342.txt
rename to peps/pep-0342.rst
diff --git a/pep-0343.txt b/peps/pep-0343.rst
similarity index 99%
rename from pep-0343.txt
rename to peps/pep-0343.rst
index 8e18d8f79..7256b2a35 100644
--- a/pep-0343.txt
+++ b/peps/pep-0343.rst
@@ -2,7 +2,7 @@ PEP: 343
Title: The "with" Statement
Version: $Revision$
Last-Modified: $Date$
-Author: Guido van Rossum, Nick Coghlan
+Author: Guido van Rossum, Alyssa Coghlan
Status: Final
Type: Standards Track
Content-Type: text/x-rst
@@ -25,7 +25,7 @@ Author's Note
=============
This PEP was originally written in first person by Guido, and
-subsequently updated by Nick Coghlan to reflect later discussion
+subsequently updated by Alyssa (Nick) Coghlan to reflect later discussion
on python-dev. Any first person references are from Guido's
original.
@@ -938,7 +938,7 @@ References
.. [6] Proposal to use the PEP 342 enhanced generator API directly
https://mail.python.org/pipermail/python-dev/2005-October/056969.html
-.. [7] Guido lets me (Nick Coghlan) talk him into a bad idea ;)
+.. [7] Guido lets me (Alyssa Coghlan) talk him into a bad idea ;)
https://mail.python.org/pipermail/python-dev/2005-October/057018.html
.. [8] Guido raises some exception handling questions
diff --git a/pep-0344.txt b/peps/pep-0344.rst
similarity index 99%
rename from pep-0344.txt
rename to peps/pep-0344.rst
index c2c4f0efb..de5fc298d 100644
--- a/pep-0344.txt
+++ b/peps/pep-0344.rst
@@ -85,8 +85,8 @@ exception, the exception must be retained implicitly. To support intentional
translation of an exception, there must be a way to chain exceptions
explicitly. This PEP addresses both.
-Several attribute names for chained exceptions have been suggested on Python-
-Dev [2]_, including ``cause``, ``antecedent``, ``reason``, ``original``,
+Several attribute names for chained exceptions have been suggested on
+Python-Dev [2]_, including ``cause``, ``antecedent``, ``reason``, ``original``,
``chain``, ``chainedexc``, ``xc_chain``, ``excprev``, ``previous`` and
``precursor``. For an explicitly chained exception, this PEP suggests
``__cause__`` because of its specific meaning. For an implicitly chained
diff --git a/pep-0345.txt b/peps/pep-0345.rst
similarity index 99%
rename from pep-0345.txt
rename to peps/pep-0345.rst
index 876f5c0f2..a9a9f359b 100644
--- a/pep-0345.txt
+++ b/peps/pep-0345.rst
@@ -32,7 +32,7 @@ These fields are "Requires-Python", "Requires-External", "Requires-Dist",
"Platform" field. Three new fields were also added: "Maintainer",
"Maintainer-email" and "Project-URL".
-Last, this new version also adds `environment markers`.
+Last, this new version also adds ``environment markers``.
Fields
======
@@ -137,7 +137,7 @@ parser.
Example::
Description: This project provides powerful math functions
- |For example, you can use `sum()` to sum numbers:
+ |For example, you can use ``sum()`` to sum numbers:
|
|Example::
|
diff --git a/pep-0346.txt b/peps/pep-0346.rst
similarity index 99%
rename from pep-0346.txt
rename to peps/pep-0346.rst
index 4666ff6c9..b656b96ff 100644
--- a/pep-0346.txt
+++ b/peps/pep-0346.rst
@@ -2,7 +2,7 @@ PEP: 346
Title: User Defined ("``with``") Statements
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan
+Author: Alyssa Coghlan
Status: Withdrawn
Type: Standards Track
Content-Type: text/x-rst
diff --git a/pep-0347.txt b/peps/pep-0347.rst
similarity index 100%
rename from pep-0347.txt
rename to peps/pep-0347.rst
diff --git a/pep-0348.txt b/peps/pep-0348.rst
similarity index 99%
rename from pep-0348.txt
rename to peps/pep-0348.rst
index d72229047..2c3d7cdc8 100644
--- a/pep-0348.txt
+++ b/peps/pep-0348.rst
@@ -436,7 +436,7 @@ was used.
Acknowledgements
================
-Thanks to Robert Brewer, Josiah Carlson, Nick Coghlan, Timothy
+Thanks to Robert Brewer, Josiah Carlson, Alyssa Coghlan, Timothy
Delaney, Jack Diedrich, Fred L. Drake, Jr., Philip J. Eby, Greg Ewing,
James Y. Knight, MA Lemburg, Guido van Rossum, Stephen J. Turnbull,
Raymond Hettinger, and everyone else I missed for participating in the
diff --git a/pep-0349.txt b/peps/pep-0349.rst
similarity index 100%
rename from pep-0349.txt
rename to peps/pep-0349.rst
diff --git a/pep-0350.txt b/peps/pep-0350.rst
similarity index 100%
rename from pep-0350.txt
rename to peps/pep-0350.rst
diff --git a/pep-0351.txt b/peps/pep-0351.rst
similarity index 100%
rename from pep-0351.txt
rename to peps/pep-0351.rst
diff --git a/pep-0352.txt b/peps/pep-0352.rst
similarity index 100%
rename from pep-0352.txt
rename to peps/pep-0352.rst
diff --git a/pep-0353.txt b/peps/pep-0353.rst
similarity index 100%
rename from pep-0353.txt
rename to peps/pep-0353.rst
diff --git a/pep-0354.txt b/peps/pep-0354.rst
similarity index 100%
rename from pep-0354.txt
rename to peps/pep-0354.rst
diff --git a/pep-0355.txt b/peps/pep-0355.rst
similarity index 100%
rename from pep-0355.txt
rename to peps/pep-0355.rst
diff --git a/pep-0356.txt b/peps/pep-0356.rst
similarity index 100%
rename from pep-0356.txt
rename to peps/pep-0356.rst
diff --git a/pep-0357.txt b/peps/pep-0357.rst
similarity index 100%
rename from pep-0357.txt
rename to peps/pep-0357.rst
diff --git a/pep-0358.txt b/peps/pep-0358.rst
similarity index 100%
rename from pep-0358.txt
rename to peps/pep-0358.rst
diff --git a/pep-0359.txt b/peps/pep-0359.rst
similarity index 99%
rename from pep-0359.txt
rename to peps/pep-0359.rst
index a2aa6d410..342f5fa77 100644
--- a/pep-0359.txt
+++ b/peps/pep-0359.rst
@@ -327,7 +327,7 @@ Keyword
-------
Does the ``make`` keyword break too much code? Originally, the make
-statement used the keyword ``create`` (a suggestion due to Nick
+statement used the keyword ``create`` (a suggestion due to Alyssa
Coghlan). However, investigations into the standard library [8]_ and
Zope+Plone code [9]_ revealed that ``create`` would break a lot more
code, so ``make`` was adopted as the keyword instead. However, there
diff --git a/pep-0360.txt b/peps/pep-0360.rst
similarity index 100%
rename from pep-0360.txt
rename to peps/pep-0360.rst
diff --git a/pep-0361.txt b/peps/pep-0361.rst
similarity index 100%
rename from pep-0361.txt
rename to peps/pep-0361.rst
diff --git a/pep-0362.txt b/peps/pep-0362.rst
similarity index 100%
rename from pep-0362.txt
rename to peps/pep-0362.rst
diff --git a/pep-0363.txt b/peps/pep-0363.rst
similarity index 100%
rename from pep-0363.txt
rename to peps/pep-0363.rst
diff --git a/pep-0364.txt b/peps/pep-0364.rst
similarity index 100%
rename from pep-0364.txt
rename to peps/pep-0364.rst
diff --git a/pep-0365.txt b/peps/pep-0365.rst
similarity index 100%
rename from pep-0365.txt
rename to peps/pep-0365.rst
diff --git a/pep-0366.txt b/peps/pep-0366.rst
similarity index 99%
rename from pep-0366.txt
rename to peps/pep-0366.rst
index 73eeb61f4..20a8a7280 100644
--- a/pep-0366.txt
+++ b/peps/pep-0366.rst
@@ -2,7 +2,7 @@ PEP: 366
Title: Main module explicit relative imports
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan
+Author: Alyssa Coghlan
Status: Final
Type: Standards Track
Content-Type: text/x-rst
diff --git a/pep-0367.txt b/peps/pep-0367.rst
similarity index 97%
rename from pep-0367.txt
rename to peps/pep-0367.rst
index 89ca58778..168db7a1e 100644
--- a/pep-0367.txt
+++ b/peps/pep-0367.rst
@@ -122,10 +122,10 @@ Should ``super`` actually become a keyword?
With this proposal, ``super`` would become a keyword to the same extent that
``None`` is a keyword. It is possible that further restricting the ``super``
-name may simplify implementation, however some are against the actual keyword-
-ization of super. The simplest solution is often the correct solution and the
-simplest solution may well not be adding additional keywords to the language
-when they are not needed. Still, it may solve other open issues.
+name may simplify implementation, however some are against the actual
+keyword-ization of super. The simplest solution is often the correct solution
+and the simplest solution may well not be adding additional keywords to the
+language when they are not needed. Still, it may solve other open issues.
Closed Issues
@@ -513,10 +513,10 @@ super(self, \*args) or __super__(self, \*args)
This solution only solves the problem of the type indication, does not handle
differently named super methods, and is explicit about the name of the
instance. It is less flexible without being able to enacted on other method
-names, in cases where that is needed. One use case this fails is where a base-
-class has a factory classmethod and a subclass has two factory classmethods,
-both of which needing to properly make super calls to the one in the base-
-class.
+names, in cases where that is needed. One use case this fails is where a
+base-class has a factory classmethod and a subclass has two factory
+classmethods, both of which needing to properly make super calls to the one
+in the base-class.
super.foo(self, \*args)
-----------------------
diff --git a/pep-0368.txt b/peps/pep-0368.rst
similarity index 100%
rename from pep-0368.txt
rename to peps/pep-0368.rst
diff --git a/pep-0369.txt b/peps/pep-0369.rst
similarity index 97%
rename from pep-0369.txt
rename to peps/pep-0369.rst
index 40caa8c66..cdca12230 100644
--- a/pep-0369.txt
+++ b/peps/pep-0369.rst
@@ -42,11 +42,11 @@ as post import hooks.
Use cases
=========
-A use case for a post import hook is mentioned in Nick Coghlan's initial
+A use case for a post import hook is mentioned in Alyssa (Nick) Coghlan's initial
posting [2]_. about callbacks on module import. It was found during the
development of Python 3.0 and its ABCs. We wanted to register classes
like decimal.Decimal with an ABC but the module should not be imported
-on every interpreter startup. Nick came up with this example::
+on every interpreter startup. Alyssa came up with this example::
@imp.when_imported('decimal')
def register(decimal):
@@ -261,7 +261,7 @@ documentation updates and additional unit tests.
Acknowledgments
===============
-Nick Coghlan, for proof reading and the initial discussion
+Alyssa Coghlan, for proof reading and the initial discussion
Phillip J. Eby, for his implementation in PEAK and help with my own implementation
diff --git a/pep-0370.txt b/peps/pep-0370.rst
similarity index 100%
rename from pep-0370.txt
rename to peps/pep-0370.rst
diff --git a/pep-0371.txt b/peps/pep-0371.rst
similarity index 100%
rename from pep-0371.txt
rename to peps/pep-0371.rst
diff --git a/pep-0372.txt b/peps/pep-0372.rst
similarity index 100%
rename from pep-0372.txt
rename to peps/pep-0372.rst
diff --git a/pep-0373.txt b/peps/pep-0373.rst
similarity index 100%
rename from pep-0373.txt
rename to peps/pep-0373.rst
diff --git a/pep-0374.txt b/peps/pep-0374.rst
similarity index 99%
rename from pep-0374.txt
rename to peps/pep-0374.rst
index f6228d857..49c944e8f 100644
--- a/pep-0374.txt
+++ b/peps/pep-0374.rst
@@ -274,8 +274,8 @@ This identity may be associated with a full name.
All of the DVCSs will query the system to get some approximation to
this information, but that may not be what you want. They also
-support setting this information on a per-user basis, and on a per-
-project basis. Convenience commands to set these attributes vary,
+support setting this information on a per-user basis, and on a
+per-project basis. Convenience commands to set these attributes vary,
but all allow direct editing of configuration files.
Some VCSs support end-of-line (EOL) conversions on checkout/checkin.
diff --git a/pep-0375.txt b/peps/pep-0375.rst
similarity index 100%
rename from pep-0375.txt
rename to peps/pep-0375.rst
diff --git a/pep-0376.txt b/peps/pep-0376.rst
similarity index 99%
rename from pep-0376.txt
rename to peps/pep-0376.rst
index 5cc2bfc8f..60119c69e 100644
--- a/pep-0376.txt
+++ b/peps/pep-0376.rst
@@ -7,7 +7,7 @@ Topic: Packaging
Content-Type: text/x-rst
Created: 22-Feb-2009
Python-Version: 2.7, 3.2
-Post-History: `22-Jun-2009 `__
+Post-History: `22-Jun-2009 `__
.. canonical-pypa-spec:: :ref:`packaging:core-metadata`
diff --git a/pep-0377.txt b/peps/pep-0377.rst
similarity index 99%
rename from pep-0377.txt
rename to peps/pep-0377.rst
index ef3184bc3..749d3d4d5 100644
--- a/pep-0377.txt
+++ b/peps/pep-0377.rst
@@ -2,7 +2,7 @@ PEP: 377
Title: Allow __enter__() methods to skip the statement body
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan
+Author: Alyssa Coghlan
Status: Rejected
Type: Standards Track
Content-Type: text/x-rst
diff --git a/pep-0378.txt b/peps/pep-0378.rst
similarity index 98%
rename from pep-0378.txt
rename to peps/pep-0378.rst
index da2293915..7077fc55e 100644
--- a/pep-0378.txt
+++ b/peps/pep-0378.rst
@@ -44,8 +44,8 @@ task easier for many users.
.. _`Babel`: http://babel.edgewall.org/
-Main Proposal (from Nick Coghlan, originally called Proposal I)
-===============================================================
+Main Proposal (from Alyssa Coghlan, originally called Proposal I)
+=================================================================
A comma will be added to the format() specifier mini-language::
diff --git a/pep-0379.txt b/peps/pep-0379.rst
similarity index 100%
rename from pep-0379.txt
rename to peps/pep-0379.rst
diff --git a/pep-0380.txt b/peps/pep-0380.rst
similarity index 100%
rename from pep-0380.txt
rename to peps/pep-0380.rst
diff --git a/pep-0381.txt b/peps/pep-0381.rst
similarity index 89%
rename from pep-0381.txt
rename to peps/pep-0381.rst
index 2bfad7c1e..6aac3a78c 100644
--- a/pep-0381.txt
+++ b/peps/pep-0381.rst
@@ -1,8 +1,6 @@
PEP: 381
Title: Mirroring infrastructure for PyPI
-Version: $Revision$
-Last-Modified: $Date$
-Author: Tarek Ziadé , Martin v. Löwis
+Author: Tarek Ziadé , Martin von Löwis
Status: Withdrawn
Type: Standards Track
Topic: Packaging
@@ -39,8 +37,8 @@ Rationale
=========
PyPI is hosting over 6000 projects and is used on a daily basis
-by people to build applications. Especially systems like `easy_install`
-and `zc.buildout` make intensive usage of PyPI.
+by people to build applications. Especially systems like ``easy_install``
+and ``zc.buildout`` make intensive usage of PyPI.
For people making intensive use of PyPI, it can act as a single point
of failure. People have started to set up some mirrors, both private
@@ -76,19 +74,19 @@ last host name. Mirror operators should use a static address,
and report planned changes to that address in advance to
distutils-sig.
-The new mirror also appears at `http://pypi.python.org/mirrors`
+The new mirror also appears at ``http://pypi.python.org/mirrors``
which is a human-readable page that gives the list of mirrors.
This page also explains how to register a new mirror.
Statistics page
:::::::::::::::
-PyPI provides statistics on downloads at `/stats`. This page is
+PyPI provides statistics on downloads at ``/stats``. This page is
calculated daily by PyPI, by reading all mirrors' local stats and
summing them.
-The stats are presented in daily or monthly files, under `/stats/days`
-and `/stats/months`. Each file is a `bzip2` file with these formats:
+The stats are presented in daily or monthly files, under ``/stats/days``
+and ``/stats/months``. Each file is a ``bzip2`` file with these formats:
- YYYY-MM-DD.bz2 for daily files
- YYYY-MM.bz2 for monthly files
@@ -182,7 +180,7 @@ that represents the last synchronisation date the mirror maintains.
The date is provided in GMT time, using the ISO 8601 format [#iso8601]_.
Each mirror will be responsible to maintain its last modified date.
-This page must be located at : `/last-modified` and must be a
+This page must be located at : ``/last-modified`` and must be a
text/plain page.
Local statistics
@@ -194,7 +192,7 @@ display the grand total.
These statistics are in CSV-like form, with a header in the first
line. It needs to obey :pep:`305`. Basically, it should be
-readable by Python's `csv` module.
+readable by Python's ``csv`` module.
The fields in this file are:
@@ -211,26 +209,26 @@ The content will look like this::
...
The counting starts the day the mirror is launched, and there is one
-file per day, compressed using the `bzip2` format. Each file is named
-like the day. For example, `2008-11-06.bz2` is the file for the 6th of
+file per day, compressed using the ``bzip2`` format. Each file is named
+like the day. For example, ``2008-11-06.bz2`` is the file for the 6th of
November 2008.
-They are then provided in a folder called `days`. For example:
+They are then provided in a folder called ``days``. For example:
- /local-stats/days/2008-11-06.bz2
- /local-stats/days/2008-11-07.bz2
- /local-stats/days/2008-11-08.bz2
-This page must be located at `/local-stats`.
+This page must be located at ``/local-stats``.
How a mirror should synchronize with PyPI
=========================================
-A mirroring protocol called `Simple Index` was described and
+A mirroring protocol called ``Simple Index`` was described and
implemented by Martin v. Loewis and Jim Fulton, based on how
-`easy_install` works. This section synthesizes it and gives a few
-relevant links, plus a small part about `User-Agent`.
+``easy_install`` works. This section synthesizes it and gives a few
+relevant links, plus a small part about ``User-Agent``.
The mirroring protocol
::::::::::::::::::::::
@@ -269,7 +267,7 @@ How a client can use PyPI and its mirrors
:::::::::::::::::::::::::::::::::::::::::
Clients that are browsing PyPI should be able to use alternative
-mirrors, by getting the list of the mirrors using `last.pypi.python.org`.
+mirrors, by getting the list of the mirrors using ``last.pypi.python.org``.
Code example::
@@ -311,7 +309,7 @@ runs their own server where people might get the project package.
However, it is strongly encouraged that a public package index follows
PyPI and Distutils protocols.
-In other words, the `register` and `upload` command should be
+In other words, the ``register`` and ``upload`` command should be
compatible with any package index server out there.
Software that are compatible with PyPI and Distutils so far:
@@ -376,13 +374,3 @@ Copyright
=========
This document has been placed in the public domain.
-
-
-..
- Local Variables:
- mode: indented-text
- indent-tabs-mode: nil
- sentence-end-double-space: t
- fill-column: 70
- coding: utf-8
- End:
diff --git a/pep-0382.txt b/peps/pep-0382.rst
similarity index 97%
rename from pep-0382.txt
rename to peps/pep-0382.rst
index 520c33c01..ecbbaeacc 100644
--- a/pep-0382.txt
+++ b/peps/pep-0382.rst
@@ -1,8 +1,6 @@
PEP: 382
Title: Namespace Packages
-Version: $Revision$
-Last-Modified: $Date$
-Author: Martin v. Löwis
+Author: Martin von Löwis
Status: Rejected
Type: Standards Track
Content-Type: text/x-rst
@@ -215,13 +213,3 @@ Copyright
=========
This document has been placed in the public domain.
-
-
-..
- Local Variables:
- mode: indented-text
- indent-tabs-mode: nil
- sentence-end-double-space: t
- fill-column: 70
- coding: utf-8
- End:
diff --git a/pep-0383.txt b/peps/pep-0383.rst
similarity index 99%
rename from pep-0383.txt
rename to peps/pep-0383.rst
index e13c7b953..cce198367 100644
--- a/pep-0383.txt
+++ b/peps/pep-0383.rst
@@ -1,6 +1,6 @@
PEP: 383
Title: Non-decodable Bytes in System Character Interfaces
-Author: Martin v. Löwis
+Author: Martin von Löwis
Status: Final
Type: Standards Track
Content-Type: text/x-rst
diff --git a/pep-0384.txt b/peps/pep-0384.rst
similarity index 98%
rename from pep-0384.txt
rename to peps/pep-0384.rst
index 7c7b4e495..867173da9 100644
--- a/pep-0384.txt
+++ b/peps/pep-0384.rst
@@ -1,8 +1,6 @@
PEP: 384
Title: Defining a Stable ABI
-Version: $Revision$
-Last-Modified: $Date$
-Author: Martin v. Löwis
+Author: Martin von Löwis
Status: Final
Type: Standards Track
Content-Type: text/x-rst
@@ -375,13 +373,3 @@ Copyright
=========
This document has been placed in the public domain.
-
-
-..
- Local Variables:
- mode: indented-text
- indent-tabs-mode: nil
- sentence-end-double-space: t
- fill-column: 70
- coding: utf-8
- End:
diff --git a/pep-0385.txt b/peps/pep-0385.rst
similarity index 100%
rename from pep-0385.txt
rename to peps/pep-0385.rst
diff --git a/pep-0386.txt b/peps/pep-0386.rst
similarity index 97%
rename from pep-0386.txt
rename to peps/pep-0386.rst
index aa7f964cb..6197dbc8a 100644
--- a/pep-0386.txt
+++ b/peps/pep-0386.rst
@@ -25,9 +25,9 @@ Motivation
In Python there are no real restrictions yet on how a project should manage its
versions, and how they should be incremented.
-Distutils provides a `version` distribution meta-data field but it is freeform and
+Distutils provides a ``version`` distribution meta-data field but it is freeform and
current users, such as PyPI usually consider the latest version pushed as the
-`latest` one, regardless of the expected semantics.
+``latest`` one, regardless of the expected semantics.
Distutils will soon extend its capabilities to allow distributions to express a
dependency on other distributions through the ``Requires-Dist`` metadata field
@@ -271,8 +271,8 @@ a particular package was using and to provide tools on top of PyPI.
Distutils classes are not really used in Python projects, but the
Setuptools function is quite widespread because it's used by tools like
-`easy_install` [#ezinstall]_, `pip` [#pip]_ or `zc.buildout` [#zc.buildout]_
-to install dependencies of a given project.
+``easy_install`` [#ezinstall]_, ``pip`` [#pip]_ or ``zc.buildout``
+[#zc.buildout]_ to install dependencies of a given project.
While Setuptools *does* provide a mechanism for comparing/sorting versions,
it is much preferable if the versioning spec is such that a human can make a
@@ -292,7 +292,7 @@ The new versioning algorithm
During Pycon, members of the Python, Ubuntu and Fedora community worked on
a version standard that would be acceptable for everyone.
-It's currently called `verlib` and a prototype lives at [#prototype]_.
+It's currently called ``verlib`` and a prototype lives at [#prototype]_.
The pseudo-format supported is::
@@ -362,9 +362,9 @@ Note that ``c`` is the preferred marker for third party projects.
NormalizedVersion
-----------------
-The `NormalizedVersion` class is used to hold a version and to compare it with
-others. It takes a string as an argument, that contains the representation of
-the version::
+The ``NormalizedVersion`` class is used to hold a version and to compare it
+with others. It takes a string as an argument, that contains the representation
+of the version::
>>> from verlib import NormalizedVersion
>>> version = NormalizedVersion('1.0')
diff --git a/pep-0387.txt b/peps/pep-0387.rst
similarity index 100%
rename from pep-0387.txt
rename to peps/pep-0387.rst
diff --git a/pep-0389.txt b/peps/pep-0389.rst
similarity index 100%
rename from pep-0389.txt
rename to peps/pep-0389.rst
diff --git a/pep-0390.txt b/peps/pep-0390.rst
similarity index 98%
rename from pep-0390.txt
rename to peps/pep-0390.rst
index f10d4fd53..e8c1f77d1 100644
--- a/pep-0390.txt
+++ b/peps/pep-0390.rst
@@ -3,7 +3,7 @@ Title: Static metadata for Distutils
Version: $Revision$
Last-Modified: $Date$
Author: Tarek Ziadé
-BDFL-Delegate: Nick Coghlan
+BDFL-Delegate: Alyssa Coghlan
Discussions-To: distutils-sig@python.org
Status: Rejected
Type: Standards Track
@@ -25,7 +25,7 @@ Rejection Notice
================
As distutils2 is no longer going to be incorporated into the standard
-library, this PEP was rejected by Nick Coghlan in late April, 2013.
+library, this PEP was rejected by Alyssa Coghlan in late April, 2013.
A replacement PEP based on :pep:`426` (metadata 2.0) will be created that
defines the minimum amount of information needed to generate an sdist
@@ -166,8 +166,8 @@ Impact on PKG-INFO generation and PEP 314
=========================================
When ``PKG-INFO`` is generated by Distutils, every field that relies on a
-condition will have that condition written at the end of the line, after a `;`
-separator::
+condition will have that condition written at the end of the line, after a
+``;`` separator::
Metadata-Version: 1.2
Name: distribute
diff --git a/pep-0391.txt b/peps/pep-0391.rst
similarity index 97%
rename from pep-0391.txt
rename to peps/pep-0391.rst
index d6050e30f..407ecb4b4 100644
--- a/pep-0391.txt
+++ b/peps/pep-0391.rst
@@ -383,7 +383,7 @@ Dictionary Schema - Detail
The dictionary passed to ``dictConfig()`` must contain the following
keys:
-* `version` - to be set to an integer value representing the schema
+* ``version`` - to be set to an integer value representing the schema
version. The only valid value at present is 1, but having this key
allows the schema to evolve while still preserving backwards
compatibility.
@@ -395,7 +395,7 @@ custom instantiation is required. If so, the mechanism described
above is used to instantiate; otherwise, the context is used to
determine how to instantiate.
-* `formatters` - the corresponding value will be a dict in which each
+* ``formatters`` - the corresponding value will be a dict in which each
key is a formatter id and each value is a dict describing how to
configure the corresponding Formatter instance.
@@ -403,7 +403,7 @@ determine how to instantiate.
(with defaults of ``None``) and these are used to construct a
``logging.Formatter`` instance.
-* `filters` - the corresponding value will be a dict in which each key
+* ``filters`` - the corresponding value will be a dict in which each key
is a filter id and each value is a dict describing how to configure
the corresponding Filter instance.
@@ -411,7 +411,7 @@ determine how to instantiate.
empty string) and this is used to construct a ``logging.Filter``
instance.
-* `handlers` - the corresponding value will be a dict in which each
+* ``handlers`` - the corresponding value will be a dict in which each
key is a handler id and each value is a dict describing how to
configure the corresponding Handler instance.
@@ -451,7 +451,7 @@ determine how to instantiate.
``logging.handlers.RotatingFileHandler`` with the keyword arguments
``filename='logconfig.log', maxBytes=1024, backupCount=3``.
-* `loggers` - the corresponding value will be a dict in which each key
+* ``loggers`` - the corresponding value will be a dict in which each key
is a logger name and each value is a dict describing how to
configure the corresponding Logger instance.
@@ -470,11 +470,11 @@ determine how to instantiate.
The specified loggers will be configured according to the level,
propagation, filters and handlers specified.
-* `root` - this will be the configuration for the root logger.
+* ``root`` - this will be the configuration for the root logger.
Processing of the configuration will be as for any logger, except
that the ``propagate`` setting will not be applicable.
-* `incremental` - whether the configuration is to be interpreted as
+* ``incremental`` - whether the configuration is to be interpreted as
incremental to the existing configuration. This value defaults to
``False``, which means that the specified configuration replaces the
existing configuration with the same semantics as used by the
@@ -483,10 +483,10 @@ determine how to instantiate.
If the specified value is ``True``, the configuration is processed
as described in the section on `Incremental Configuration`_, below.
-* `disable_existing_loggers` - whether any existing loggers are to be
+* ``disable_existing_loggers`` - whether any existing loggers are to be
disabled. This setting mirrors the parameter of the same name in
``fileConfig()``. If absent, this parameter defaults to ``True``.
- This value is ignored if `incremental` is ``True``.
+ This value is ignored if ``incremental`` is ``True``.
A Working Example
-----------------
diff --git a/pep-0392.txt b/peps/pep-0392.rst
similarity index 100%
rename from pep-0392.txt
rename to peps/pep-0392.rst
diff --git a/pep-0393.txt b/peps/pep-0393.rst
similarity index 98%
rename from pep-0393.txt
rename to peps/pep-0393.rst
index 2bd4d83db..bee0319fd 100644
--- a/pep-0393.txt
+++ b/peps/pep-0393.rst
@@ -1,8 +1,6 @@
PEP: 393
Title: Flexible String Representation
-Version: $Revision$
-Last-Modified: $Date$
-Author: Martin v. Löwis
+Author: Martin von Löwis
Status: Final
Type: Standards Track
Content-Type: text/x-rst
@@ -463,13 +461,3 @@ Copyright
=========
This document has been placed in the public domain.
-
-
-..
- Local Variables:
- mode: indented-text
- indent-tabs-mode: nil
- sentence-end-double-space: t
- fill-column: 70
- coding: utf-8
- End:
diff --git a/pep-0394.txt b/peps/pep-0394.rst
similarity index 99%
rename from pep-0394.txt
rename to peps/pep-0394.rst
index 7e6110112..f3ffcd7d0 100644
--- a/pep-0394.txt
+++ b/peps/pep-0394.rst
@@ -3,7 +3,7 @@ Title: The "python" Command on Unix-Like Systems
Version: $Revision$
Last-Modified: $Date$
Author: Kerrick Staley ,
- Nick Coghlan ,
+ Alyssa Coghlan ,
Barry Warsaw ,
Petr Viktorin ,
Miro Hrončok ,
@@ -361,7 +361,7 @@ References
.. [6] PEP 394 - Clarification of what "python" command should invoke
(https://mail.python.org/pipermail/python-dev/2014-September/136374.html)
-.. [7] PEP 394: Allow the `python` command to not be installed, and other
+.. [7] PEP 394: Allow the ``python`` command to not be installed, and other
minor edits
(https://github.com/python/peps/pull/630)
diff --git a/pep-0395.txt b/peps/pep-0395.rst
similarity index 99%
rename from pep-0395.txt
rename to peps/pep-0395.rst
index 04e848206..f270183c8 100644
--- a/pep-0395.txt
+++ b/peps/pep-0395.rst
@@ -2,7 +2,7 @@ PEP: 395
Title: Qualified Names for Modules
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan
+Author: Alyssa Coghlan
Status: Withdrawn
Type: Standards Track
Content-Type: text/x-rst
diff --git a/pep-0396.txt b/peps/pep-0396.rst
similarity index 100%
rename from pep-0396.txt
rename to peps/pep-0396.rst
diff --git a/pep-0397.txt b/peps/pep-0397.rst
similarity index 98%
rename from pep-0397.txt
rename to peps/pep-0397.rst
index b0b170a56..bec6ac504 100644
--- a/pep-0397.txt
+++ b/peps/pep-0397.rst
@@ -1,9 +1,7 @@
PEP: 397
Title: Python launcher for Windows
-Version: $Revision: a57419aee37d $
-Last-Modified: $Date: 2012/06/19 15:13:49 $
Author: Mark Hammond ,
- Martin v. Löwis
+ Martin von Löwis
Status: Final
Type: Standards Track
Content-Type: text/x-rst
@@ -420,13 +418,3 @@ Copyright
=========
This document has been placed in the public domain.
-
-
-..
- Local Variables:
- mode: indented-text
- indent-tabs-mode: nil
- sentence-end-double-space: t
- fill-column: 70
- coding: utf-8
- End:
diff --git a/pep-0398.txt b/peps/pep-0398.rst
similarity index 100%
rename from pep-0398.txt
rename to peps/pep-0398.rst
diff --git a/pep-0399.txt b/peps/pep-0399.rst
similarity index 97%
rename from pep-0399.txt
rename to peps/pep-0399.rst
index 3fe730c98..a87ee2a10 100644
--- a/pep-0399.txt
+++ b/peps/pep-0399.rst
@@ -161,9 +161,9 @@ could be added.
To also help with compatibility, C code should use abstract APIs on
objects to prevent accidental dependence on specific types. For
instance, if a function accepts a sequence then the C code should
-default to using `PyObject_GetItem()` instead of something like
-`PyList_GetItem()`. C code is allowed to have a fast path if the
-proper `PyList_CheckExact()` is used, but otherwise APIs should work
+default to using ``PyObject_GetItem()`` instead of something like
+``PyList_GetItem()``. C code is allowed to have a fast path if the
+proper ``PyList_CheckExact()`` is used, but otherwise APIs should work
with any object that duck types to the proper interface instead of a
specific type.
diff --git a/pep-0400.txt b/peps/pep-0400.rst
similarity index 100%
rename from pep-0400.txt
rename to peps/pep-0400.rst
diff --git a/pep-0401.txt b/peps/pep-0401.rst
similarity index 100%
rename from pep-0401.txt
rename to peps/pep-0401.rst
diff --git a/pep-0402.txt b/peps/pep-0402.rst
similarity index 98%
rename from pep-0402.txt
rename to peps/pep-0402.rst
index 0d8a95440..318726599 100644
--- a/pep-0402.txt
+++ b/peps/pep-0402.rst
@@ -1,8 +1,6 @@
PEP: 402
Title: Simplified Package Layout and Partitioning
-Version: $Revision$
-Last-Modified: $Date$
-Author: P.J. Eby
+Author: Phillip J. Eby
Status: Rejected
Type: Standards Track
Topic: Packaging
@@ -534,7 +532,7 @@ Specifically the proposed changes and additions to ``pkgutil`` are:
The implementation of this function does a simple top-down traversal
of ``sys.virtual_package_paths``, and performs any necessary
``get_subpath()`` calls to identify what path entries need to be
- added to the virtual path for that package, given that `path_entry`
+ added to the virtual path for that package, given that ``path_entry``
has been added to ``sys.path``. (Or, in the case of sub-packages,
adding a derived subpath entry, based on their parent package's
virtual path.)
@@ -547,7 +545,7 @@ Specifically the proposed changes and additions to ``pkgutil`` are:
* A new ``iter_virtual_packages(parent='')`` function to allow
top-down traversal of virtual packages from
``sys.virtual_package_paths``, by yielding the child virtual
- packages of `parent`. For example, calling
+ packages of ``parent``. For example, calling
``iter_virtual_packages("zope")`` might yield ``zope.app``
and ``zope.products`` (if they are virtual packages listed in
``sys.virtual_package_paths``), but **not** ``zope.foo.bar``.
@@ -664,13 +662,3 @@ Copyright
=========
This document has been placed in the public domain.
-
-
-..
- Local Variables:
- mode: indented-text
- indent-tabs-mode: nil
- sentence-end-double-space: t
- fill-column: 70
- coding: utf-8
- End:
diff --git a/pep-0403.txt b/peps/pep-0403.rst
similarity index 99%
rename from pep-0403.txt
rename to peps/pep-0403.rst
index e91f00bb0..aadaff6c4 100644
--- a/pep-0403.txt
+++ b/peps/pep-0403.rst
@@ -2,7 +2,7 @@ PEP: 403
Title: General purpose decorator clause (aka "@in" clause)
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan
+Author: Alyssa Coghlan
Status: Deferred
Type: Standards Track
Content-Type: text/x-rst
diff --git a/pep-0404.txt b/peps/pep-0404.rst
similarity index 100%
rename from pep-0404.txt
rename to peps/pep-0404.rst
diff --git a/pep-0405.txt b/peps/pep-0405.rst
similarity index 99%
rename from pep-0405.txt
rename to peps/pep-0405.rst
index 22e0a2624..8c95d1c1d 100644
--- a/pep-0405.txt
+++ b/peps/pep-0405.rst
@@ -3,7 +3,7 @@ Title: Python Virtual Environments
Version: $Revision$
Last-Modified: $Date$
Author: Carl Meyer
-BDFL-Delegate: Nick Coghlan
+BDFL-Delegate: Alyssa Coghlan
Status: Final
Type: Standards Track
Topic: Packaging
diff --git a/pep-0406.txt b/peps/pep-0406.rst
similarity index 99%
rename from pep-0406.txt
rename to peps/pep-0406.rst
index c290980b3..be1ffaeac 100644
--- a/pep-0406.txt
+++ b/peps/pep-0406.rst
@@ -2,7 +2,7 @@ PEP: 406
Title: Improved Encapsulation of Import State
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan , Greg Slodkowicz
+Author: Alyssa Coghlan , Greg Slodkowicz
Status: Withdrawn
Type: Standards Track
Content-Type: text/x-rst
diff --git a/pep-0407.txt b/peps/pep-0407.rst
similarity index 100%
rename from pep-0407.txt
rename to peps/pep-0407.rst
diff --git a/pep-0408.txt b/peps/pep-0408.rst
similarity index 99%
rename from pep-0408.txt
rename to peps/pep-0408.rst
index bc34c0139..788d7f417 100644
--- a/pep-0408.txt
+++ b/peps/pep-0408.rst
@@ -2,7 +2,7 @@ PEP: 408
Title: Standard library __preview__ package
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan ,
+Author: Alyssa Coghlan ,
Eli Bendersky
Status: Rejected
Type: Standards Track
diff --git a/pep-0409.txt b/peps/pep-0409.rst
similarity index 100%
rename from pep-0409.txt
rename to peps/pep-0409.rst
diff --git a/pep-0410.txt b/peps/pep-0410.rst
similarity index 100%
rename from pep-0410.txt
rename to peps/pep-0410.rst
diff --git a/pep-0411.txt b/peps/pep-0411.rst
similarity index 99%
rename from pep-0411.txt
rename to peps/pep-0411.rst
index 8bee39e6b..e4969dc43 100644
--- a/pep-0411.txt
+++ b/peps/pep-0411.rst
@@ -2,7 +2,7 @@ PEP: 411
Title: Provisional packages in the Python standard library
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan ,
+Author: Alyssa Coghlan ,
Eli Bendersky
Status: Superseded
Type: Informational
diff --git a/pep-0412.txt b/peps/pep-0412.rst
similarity index 100%
rename from pep-0412.txt
rename to peps/pep-0412.rst
diff --git a/pep-0413.txt b/peps/pep-0413.rst
similarity index 99%
rename from pep-0413.txt
rename to peps/pep-0413.rst
index 933972b21..f2778b256 100644
--- a/pep-0413.txt
+++ b/peps/pep-0413.rst
@@ -2,7 +2,7 @@ PEP: 413
Title: Faster evolution of the Python Standard Library
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan
+Author: Alyssa Coghlan
Status: Withdrawn
Type: Process
Content-Type: text/x-rst
diff --git a/pep-0414.txt b/peps/pep-0414.rst
similarity index 99%
rename from pep-0414.txt
rename to peps/pep-0414.rst
index d8ef45f61..7b62aae4f 100644
--- a/pep-0414.txt
+++ b/peps/pep-0414.rst
@@ -3,7 +3,7 @@ Title: Explicit Unicode Literal for Python 3.3
Version: $Revision$
Last-Modified: $Date$
Author: Armin Ronacher ,
- Nick Coghlan
+ Alyssa Coghlan
Status: Final
Type: Standards Track
Content-Type: text/x-rst
@@ -102,7 +102,7 @@ Author's Note
This PEP was originally written by Armin Ronacher, and Guido's approval was
given based on that version.
-The currently published version has been rewritten by Nick Coghlan to
+The currently published version has been rewritten by Alyssa Coghlan to
include additional historical details and rationale that were taken into
account when Guido made his decision, but were not explicitly documented in
Armin's version of the PEP.
diff --git a/pep-0415.txt b/peps/pep-0415.rst
similarity index 96%
rename from pep-0415.txt
rename to peps/pep-0415.rst
index 48715a21f..a8a695cfd 100644
--- a/pep-0415.txt
+++ b/peps/pep-0415.rst
@@ -3,7 +3,7 @@ Title: Implement context suppression with exception attributes
Version: $Revision$
Last-Modified: $Date$
Author: Benjamin Peterson
-BDFL-Delegate: Nick Coghlan
+BDFL-Delegate: Alyssa Coghlan
Status: Final
Type: Standards Track
Content-Type: text/x-rst
@@ -28,7 +28,7 @@ instances.
PEP Acceptance
==============
-This PEP was accepted by Nick Coghlan on the 14th of May, 2012.
+This PEP was accepted by Alyssa Coghlan on the 14th of May, 2012.
Rationale
diff --git a/pep-0416.txt b/peps/pep-0416.rst
similarity index 100%
rename from pep-0416.txt
rename to peps/pep-0416.rst
diff --git a/pep-0417.txt b/peps/pep-0417.rst
similarity index 100%
rename from pep-0417.txt
rename to peps/pep-0417.rst
diff --git a/pep-0418.txt b/peps/pep-0418.rst
similarity index 99%
rename from pep-0418.txt
rename to peps/pep-0418.rst
index bcf698ec8..b728a3fb3 100644
--- a/pep-0418.txt
+++ b/peps/pep-0418.rst
@@ -1,8 +1,9 @@
PEP: 418
Title: Add monotonic time, performance counter, and process time functions
-Version: $Revision$
-Last-Modified: $Date$
-Author: Cameron Simpson , Jim Jewett , Stephen J. Turnbull , Victor Stinner
+Author: Cameron Simpson ,
+ Jim J. Jewett ,
+ Stephen J. Turnbull ,
+ Victor Stinner
Status: Final
Type: Standards Track
Content-Type: text/x-rst
@@ -1640,14 +1641,3 @@ Copyright
=========
This document has been placed in the public domain.
-
-
-
-..
- Local Variables:
- mode: indented-text
- indent-tabs-mode: nil
- sentence-end-double-space: t
- fill-column: 70
- coding: utf-8
- End:
diff --git a/pep-0418/bench_time.c b/peps/pep-0418/bench_time.c
similarity index 100%
rename from pep-0418/bench_time.c
rename to peps/pep-0418/bench_time.c
diff --git a/pep-0418/clock_resolution.py b/peps/pep-0418/clock_resolution.py
similarity index 100%
rename from pep-0418/clock_resolution.py
rename to peps/pep-0418/clock_resolution.py
diff --git a/pep-0418/clockutils.py b/peps/pep-0418/clockutils.py
similarity index 100%
rename from pep-0418/clockutils.py
rename to peps/pep-0418/clockutils.py
diff --git a/pep-0419.txt b/peps/pep-0419.rst
similarity index 100%
rename from pep-0419.txt
rename to peps/pep-0419.rst
diff --git a/pep-0420.txt b/peps/pep-0420.rst
similarity index 98%
rename from pep-0420.txt
rename to peps/pep-0420.rst
index 0f0baa733..ea20501ab 100644
--- a/pep-0420.txt
+++ b/peps/pep-0420.rst
@@ -444,7 +444,7 @@ lacking an ``__init__.py`` file. Such a directory will now be
imported as a namespace package, whereas in prior Python versions an
ImportWarning would be raised.
-Nick Coghlan presented a list of his objections to this proposal [4]_.
+Alyssa (Nick) Coghlan presented a list of her objections to this proposal [4]_.
They are:
1. Implicit package directories go against the Zen of Python.
@@ -458,7 +458,7 @@ They are:
4. Implicit package directories will permanently entrench current
newbie-hostile behavior in ``__main__``.
-Nick later gave a detailed response to his own objections [5]_, which
+Alyssa later gave a detailed response to her own objections [5]_, which
is summarized here:
1. The practicality of this PEP wins over other proposals and the
@@ -500,7 +500,7 @@ Dynamic path computation
------------------------
Guido raised a concern that automatic dynamic path computation was an
-unnecessary feature [8]_. Later in that thread, PJ Eby and Nick
+unnecessary feature [8]_. Later in that thread, PJ Eby and Alyssa
Coghlan presented arguments as to why dynamic computation would
minimize surprise to Python users. The conclusion of that discussion
has been included in this PEP's Rationale section.
@@ -622,10 +622,10 @@ References
.. [3] PyCon 2012 Namespace Package discussion outcome
(https://mail.python.org/pipermail/import-sig/2012-March/000421.html)
-.. [4] Nick Coghlan's objection to the lack of marker files or directories
+.. [4] Alyssa Coghlan's objection to the lack of marker files or directories
(https://mail.python.org/pipermail/import-sig/2012-March/000423.html)
-.. [5] Nick Coghlan's response to his initial objections
+.. [5] Alyssa Coghlan's response to her initial objections
(https://mail.python.org/pipermail/import-sig/2012-April/000464.html)
.. [6] Martin v. Löwis's suggestion to make ``encodings`` a namespace
diff --git a/pep-0421.txt b/peps/pep-0421.rst
similarity index 99%
rename from pep-0421.txt
rename to peps/pep-0421.rst
index e1287ea30..1f5a410ed 100644
--- a/pep-0421.txt
+++ b/peps/pep-0421.rst
@@ -169,7 +169,7 @@ Non-Required Attributes
Earlier versions of this PEP included a required attribute called
``metadata`` that held any non-required, per-implementation data
-[#Nick]_. However, this proved to be an unnecessary addition
+[#Alyssa]_. However, this proved to be an unnecessary addition
considering the purpose of ``sys.implementation``.
Ultimately, non-required attributes are virtually ignored in this PEP.
@@ -502,7 +502,7 @@ References
.. [#javatest] The use of ``os.name`` as 'java' in the stdlib test suite.
http://hg.python.org/cpython/file/2f563908ebc5/Lib/test/support.py#l512
-.. [#Nick] Nick Coghlan's proposal for ``sys.implementation.metadata``:
+.. [#Alyssa] Alyssa (Nick) Coghlan's proposal for ``sys.implementation.metadata``:
https://mail.python.org/pipermail/python-ideas/2012-May/014984.html
.. [#Barry] Feedback from Barry Warsaw:
diff --git a/pep-0422.txt b/peps/pep-0422.rst
similarity index 99%
rename from pep-0422.txt
rename to peps/pep-0422.rst
index 655dc78e8..dad61a6e0 100644
--- a/pep-0422.txt
+++ b/peps/pep-0422.rst
@@ -2,7 +2,7 @@ PEP: 422
Title: Simpler customisation of class creation
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan ,
+Author: Alyssa Coghlan ,
Daniel Urban
Status: Withdrawn
Type: Standards Track
diff --git a/pep-0423.txt b/peps/pep-0423.rst
similarity index 99%
rename from pep-0423.txt
rename to peps/pep-0423.rst
index 094fef505..0eba9486c 100644
--- a/pep-0423.txt
+++ b/peps/pep-0423.rst
@@ -631,7 +631,7 @@ already been registered:
* in the `Python Standard Library`_.
-* inside projects at `PyPI`. There is currently no helper for that.
+* inside projects at ``PyPI``. There is currently no helper for that.
Notice that the more projects follow the `use a single name`_ rule,
the easier is the verification.
diff --git a/pep-0424.txt b/peps/pep-0424.rst
similarity index 100%
rename from pep-0424.txt
rename to peps/pep-0424.rst
diff --git a/pep-0425.txt b/peps/pep-0425.rst
similarity index 85%
rename from pep-0425.txt
rename to peps/pep-0425.rst
index e627d5c98..d1fd39d17 100644
--- a/pep-0425.txt
+++ b/peps/pep-0425.rst
@@ -3,7 +3,7 @@ Title: Compatibility Tags for Built Distributions
Version: $Revision$
Last-Modified: 07-Aug-2012
Author: Daniel Holth
-BDFL-Delegate: Nick Coghlan
+BDFL-Delegate: Alyssa Coghlan
Status: Final
Type: Standards Track
Topic: Packaging
@@ -30,7 +30,7 @@ they will be included in filenames.
PEP Acceptance
==============
-This PEP was accepted by Nick Coghlan on 17th February, 2013.
+This PEP was accepted by Alyssa Coghlan on 17th February, 2013.
Rationale
@@ -71,7 +71,7 @@ For example, the tag py27-none-any indicates compatible with Python 2.7
Use
===
-The `wheel` built package format includes these tags in its filenames,
+The ``wheel`` built package format includes these tags in its filenames,
of the form ``{distribution}-{version}(-{build tag})?-{python tag}-{abi
tag}-{platform tag}.whl``. Other package formats may have their own
conventions.
@@ -91,31 +91,31 @@ a distribution. Major implementations have abbreviated codes, initially:
* pp: PyPy
* jy: Jython
-Other Python implementations should use `sys.implementation.name`.
+Other Python implementations should use ``sys.implementation.name``.
-The version is `py_version_nodot`. CPython gets away with no dot,
-but if one is needed the underscore `_` is used instead. PyPy should
-probably use its own versions here `pp18`, `pp19`.
+The version is ``py_version_nodot``. CPython gets away with no dot,
+but if one is needed the underscore ``_`` is used instead. PyPy should
+probably use its own versions here ``pp18``, ``pp19``.
-The version can be just the major version `2` or `3` `py2`, `py3` for
+The version can be just the major version ``2`` or ``3`` ``py2``, ``py3`` for
many pure-Python distributions.
-Importantly, major-version-only tags like `py2` and `py3` are not
-shorthand for `py20` and `py30`. Instead, these tags mean the packager
+Importantly, major-version-only tags like ``py2`` and ``py3`` are not
+shorthand for ``py20`` and ``py30``. Instead, these tags mean the packager
intentionally released a cross-version-compatible distribution.
A single-source Python 2/3 compatible distribution can use the compound
-tag `py2.py3`. See `Compressed Tag Sets`, below.
+tag ``py2.py3``. See ``Compressed Tag Sets``, below.
ABI Tag
-------
The ABI tag indicates which Python ABI is required by any included
extension modules. For implementation-specific ABIs, the implementation
-is abbreviated in the same way as the Python Tag, e.g. `cp33d` would be
+is abbreviated in the same way as the Python Tag, e.g. ``cp33d`` would be
the CPython 3.3 ABI with debugging.
-The CPython stable ABI is `abi3` as in the shared library suffix.
+The CPython stable ABI is ``abi3`` as in the shared library suffix.
Implementations with a very unstable ABI may use the first 6 bytes (as
8 base64-encoded characters) of the SHA-256 hash of their source code
@@ -126,8 +126,8 @@ decide how to best use the ABI tag.
Platform Tag
------------
-The platform tag is simply `distutils.util.get_platform()` with all
-hyphens `-` and periods `.` replaced with underscore `_`.
+The platform tag is simply ``distutils.util.get_platform()`` with all
+hyphens ``-`` and periods ``.`` replaced with underscore ``_``.
* win32
* linux_i386
@@ -139,7 +139,7 @@ Use
The tags are used by installers to decide which built distribution
(if any) to download from a list of potential built distributions.
The installer maintains a list of (pyver, abi, arch) tuples that it
-will support. If the built distribution's tag is `in` the list, then
+will support. If the built distribution's tag is ``in`` the list, then
it can be installed.
It is recommended that installers try to choose the most feature complete
@@ -147,7 +147,7 @@ built distribution available (the one most specific to the installation
environment) by default before falling back to pure Python versions
published for older Python releases. Installers are also recommended to
provide a way to configure and re-order the list of allowed compatibility
-tags; for example, a user might accept only the `*-none-any` tags to only
+tags; for example, a user might accept only the ``*-none-any`` tags to only
download built packages that advertise themselves as being pure Python.
Another desirable installer feature might be to include "re-compile from
@@ -181,8 +181,8 @@ older version of Python):
Sometimes there will be more than one supported built distribution for a
particular version of a package. For example, a packager could release
-a package tagged `cp33-abi3-linux_x86_64` that contains an optional C
-extension and the same distribution tagged `py3-none-any` that does not.
+a package tagged ``cp33-abi3-linux_x86_64`` that contains an optional C
+extension and the same distribution tagged ``py3-none-any`` that does not.
The index of the tag in the supported tags list breaks the tie, and the
package with the C extension is installed in preference to the package
without because that tag appears first in the list.
@@ -194,7 +194,7 @@ To allow for compact filenames of bdists that work with more than
one compatibility tag triple, each tag in a filename can instead be a
'.'-separated, sorted, set of tags. For example, pip, a pure-Python
package that is written to run under Python 2 and 3 with the same source
-code, could distribute a bdist with the tag `py2.py3-none-any`.
+code, could distribute a bdist with the tag ``py2.py3-none-any``.
The full list of simple tags is::
for x in pytag.split('.'):
@@ -212,8 +212,8 @@ FAQ
What tags are used by default?
Tools should use the most-preferred architecture dependent tag
- e.g. `cp33-cp33m-win32` or the most-preferred pure python tag
- e.g. `py33-none-any` by default. If the packager overrides the
+ e.g. ``cp33-cp33m-win32`` or the most-preferred pure python tag
+ e.g. ``py33-none-any`` by default. If the packager overrides the
default it indicates that they intended to provide cross-Python
compatibility.
@@ -227,7 +227,7 @@ What tag do I use if my distribution uses a feature exclusive to the newest vers
older release ``beaglevote-1.1.0`` that does not use the new feature,
to get a compatible build.
-Why isn't there a `.` in the Python version number?
+Why isn't there a ``.`` in the Python version number?
CPython has lasted 20+ years without a 3-digit major release. This
should continue for some time. Other implementations may use _ as
a delimiter, since both - and . delimit the surrounding filename.
@@ -283,7 +283,7 @@ References
Acknowledgements
================
-The author thanks Paul Moore, Nick Coghlan, Marc Abramowitz, and
+The author thanks Paul Moore, Alyssa Coghlan, Marc Abramowitz, and
Mr. Michele Lacchia for their valuable help and advice.
Copyright
diff --git a/pep-0426.txt b/peps/pep-0426.rst
similarity index 99%
rename from pep-0426.txt
rename to peps/pep-0426.rst
index 5163310de..6653ecdba 100644
--- a/pep-0426.txt
+++ b/peps/pep-0426.rst
@@ -2,7 +2,7 @@ PEP: 426
Title: Metadata for Python Software Packages 2.0
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan ,
+Author: Alyssa Coghlan ,
Daniel Holth ,
Donald Stufft
BDFL-Delegate: Donald Stufft
diff --git a/pep-0426/pepsort.py b/peps/pep-0426/pepsort.py
similarity index 100%
rename from pep-0426/pepsort.py
rename to peps/pep-0426/pepsort.py
diff --git a/pep-0426/pydist-schema.json b/peps/pep-0426/pydist-schema.json
similarity index 100%
rename from pep-0426/pydist-schema.json
rename to peps/pep-0426/pydist-schema.json
diff --git a/pep-0427.txt b/peps/pep-0427.rst
similarity index 99%
rename from pep-0427.txt
rename to peps/pep-0427.rst
index d75ac752a..921a6258c 100644
--- a/pep-0427.txt
+++ b/peps/pep-0427.rst
@@ -3,7 +3,7 @@ Title: The Wheel Binary Package Format 1.0
Version: $Revision$
Last-Modified: $Date$
Author: Daniel Holth
-BDFL-Delegate: Nick Coghlan
+BDFL-Delegate: Alyssa Coghlan
Discussions-To: distutils-sig@python.org
Status: Final
Type: Standards Track
@@ -35,7 +35,7 @@ PEP Acceptance
==============
This PEP was accepted, and the defined wheel version updated to 1.0, by
-Nick Coghlan on 16th February, 2013 [1]_
+Alyssa Coghlan on 16th February, 2013 [1]_
Rationale
diff --git a/pep-0428.txt b/peps/pep-0428.rst
similarity index 100%
rename from pep-0428.txt
rename to peps/pep-0428.rst
diff --git a/pep-0429.txt b/peps/pep-0429.rst
similarity index 100%
rename from pep-0429.txt
rename to peps/pep-0429.rst
diff --git a/pep-0430.txt b/peps/pep-0430.rst
similarity index 99%
rename from pep-0430.txt
rename to peps/pep-0430.rst
index d00e498c2..6bf2f03a6 100644
--- a/pep-0430.txt
+++ b/peps/pep-0430.rst
@@ -2,7 +2,7 @@ PEP: 430
Title: Migrating to Python 3 as the default online documentation
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan
+Author: Alyssa Coghlan
BDFL-Delegate: Georg Brandl
Status: Final
Type: Informational
diff --git a/pep-0431.txt b/peps/pep-0431.rst
similarity index 99%
rename from pep-0431.txt
rename to peps/pep-0431.rst
index 070e41eda..1b313bd14 100644
--- a/pep-0431.txt
+++ b/peps/pep-0431.rst
@@ -188,13 +188,13 @@ This function takes a name string that must be a string specifying a
valid zoneinfo time zone, i.e. "US/Eastern", "Europe/Warsaw" or "Etc/GMT".
If not given, the local time zone will be looked up. If an invalid zone name
is given, or the local time zone can not be retrieved, the function raises
-`UnknownTimeZoneError`.
+``UnknownTimeZoneError``.
The function also takes an optional path to the location of the zoneinfo
database which should be used. If not specified, the function will look for
databases in the following order:
-1. Check if the `tzdata-update` module is installed, and then use that
+1. Check if the ``tzdata-update`` module is installed, and then use that
database.
2. Use the database in ``/usr/share/zoneinfo``, if it exists.
diff --git a/pep-0432.txt b/peps/pep-0432.rst
similarity index 99%
rename from pep-0432.txt
rename to peps/pep-0432.rst
index 6feef5977..676ca96fe 100644
--- a/pep-0432.txt
+++ b/peps/pep-0432.rst
@@ -2,7 +2,7 @@ PEP: 432
Title: Restructuring the CPython startup sequence
Version: $Revision$
Last-Modified: $Date$
-Author: Nick Coghlan ,
+Author: Alyssa Coghlan ,
Victor Stinner ,
Eric Snow
Discussions-To: capi-sig@python.org
diff --git a/pep-0433.txt b/peps/pep-0433.rst
similarity index 100%
rename from pep-0433.txt
rename to peps/pep-0433.rst
diff --git a/pep-0433/bench_cloexec.py b/peps/pep-0433/bench_cloexec.py
similarity index 100%
rename from pep-0433/bench_cloexec.py
rename to peps/pep-0433/bench_cloexec.py
diff --git a/pep-0433/openbsd_bug.py b/peps/pep-0433/openbsd_bug.py
similarity index 100%
rename from pep-0433/openbsd_bug.py
rename to peps/pep-0433/openbsd_bug.py
diff --git a/pep-0434.txt b/peps/pep-0434.rst
similarity index 99%
rename from pep-0434.txt
rename to peps/pep-0434.rst
index b754d2a48..95a072258 100644
--- a/pep-0434.txt
+++ b/peps/pep-0434.rst
@@ -4,7 +4,7 @@ Version: $Revision$
Last-Modified: $Date$
Author: Todd Rovito ,
Terry Reedy
-BDFL-Delegate: Nick Coghlan
+BDFL-Delegate: Alyssa Coghlan
Status: Active
Type: Informational
Content-Type: text/x-rst
diff --git a/pep-0435.txt b/peps/pep-0435.rst
similarity index 100%
rename from pep-0435.txt
rename to peps/pep-0435.rst
diff --git a/pep-0436.txt b/peps/pep-0436.rst
similarity index 99%
rename from pep-0436.txt
rename to peps/pep-0436.rst
index c1a7f277e..7528edb3f 100644
--- a/pep-0436.txt
+++ b/peps/pep-0436.rst
@@ -693,7 +693,7 @@ Notes / TBD
currently under discussion. Argument Clinic will add support for
the prototype when it becomes viable.
-* Nick Coghlan suggests that we a) only support at most one left-optional
+* Alyssa Coghlan suggests that we a) only support at most one left-optional
group per function, and b) in the face of ambiguity, prefer the left
group over the right group. This would solve all our existing use cases
including range().
@@ -757,7 +757,7 @@ The PEP author wishes to thank Ned Batchelder for permission to
shamelessly rip off his clever design for Cog--"my favorite tool
that I've never gotten to use". Thanks also to everyone who provided
feedback on the [bugtracker issue] and on python-dev. Special thanks
-to Nick Coglan and Guido van Rossum for a rousing two-hour in-person
+to Alyssa (Nick) Coghlan and Guido van Rossum for a rousing two-hour in-person
deep dive on the topic at PyCon US 2013.
diff --git a/pep-0437.txt b/peps/pep-0437.rst
similarity index 100%
rename from pep-0437.txt
rename to peps/pep-0437.rst
diff --git a/pep-0438.txt b/peps/pep-0438.rst
similarity index 99%
rename from pep-0438.txt
rename to peps/pep-0438.rst
index 30ee2d530..4b2aff25e 100644
--- a/pep-0438.txt
+++ b/peps/pep-0438.rst
@@ -451,7 +451,7 @@ Donald Stufft for pushing away from external hosting and offering to
implement both a Pull Request for the necessary PyPI changes and the
analysis tool to drive the transition phase 1.
-Marc-Andre Lemburg, Nick Coghlan and catalog-sig in general for
+Marc-Andre Lemburg, Alyssa Coghlan and catalog-sig in general for
thinking through issues regarding getting rid of "external hosting".
diff --git a/pep-0439.txt b/peps/pep-0439.rst
similarity index 98%
rename from pep-0439.txt
rename to peps/pep-0439.rst
index d354c3da4..a354e9673 100644
--- a/pep-0439.txt
+++ b/peps/pep-0439.rst
@@ -3,7 +3,7 @@ Title: Inclusion of implicit pip bootstrap in Python installation
Version: $Revision$
Last-Modified: $Date$
Author: Richard Jones
-BDFL-Delegate: Nick Coghlan
+BDFL-Delegate: Alyssa Coghlan
Discussions-To: distutils-sig@python.org
Status: Rejected
Type: Standards Track
@@ -189,8 +189,8 @@ Implementation
==============
The changes to pip required by this PEP are being tracked in that project's
-issue tracker [2]_. Most notably, the addition of --bootstrap and --bootstrap-
-to-system to the pip command-line.
+issue tracker [2]_. Most notably, the addition of --bootstrap and
+--bootstrap-to-system to the pip command-line.
It would be preferable that the pip and setuptools projects distribute a wheel
format download.
@@ -234,7 +234,7 @@ References
Acknowledgments
===============
-Nick Coghlan for his thoughts on the proposal and dealing with the Red
+Alyssa Coghlan for her thoughts on the proposal and dealing with the Red
Hat issue.
Jannis Leidel and Carl Meyer for their thoughts. Marcus Smith for feedback.
diff --git a/pep-0440.txt b/peps/pep-0440.rst
similarity index 98%
rename from pep-0440.txt
rename to peps/pep-0440.rst
index 05ef4df20..b8f2e5b42 100644
--- a/pep-0440.txt
+++ b/peps/pep-0440.rst
@@ -1,8 +1,8 @@
PEP: 440
Title: Version Identification and Dependency Specification
-Author: Nick Coghlan ,
+Author: Alyssa Coghlan ,
Donald Stufft
-BDFL-Delegate: Nick Coghlan