- Ruff v0.16.0 ลินเตอร์และฟอร์แมตเตอร์สำหรับ Python ที่เขียนด้วย Rust เพิ่มจำนวนกฎที่เปิดใช้งานโดยค่าเริ่มต้นจาก 59 เป็น 413 รายการ ทำให้ตรวจพบข้อผิดพลาดทางไวยากรณ์และข้อผิดพลาดรันไทม์ที่เกิดขึ้นทันทีได้กว้างขึ้นโดยไม่ต้องตั้งค่าเพิ่มเติม
- รองรับการ ฟอร์แมตบล็อกโค้ด Python ใน Markdown ที่ระบุเป็น
python, py, pyi, pycon เป็นต้น และใช้กับ Quarto notebook ได้ด้วย
- เพิ่ม
ruff: ignore และ ruff: file-ignore เพื่อกดการรายงานการวินิจฉัยในบรรทัดโค้ดเชิงตรรกะหรือทั้งไฟล์ได้ และสามารถแทรกคอมเมนต์อัตโนมัติด้วย --add-ignore
check และ format --check จะแสดงการแก้ไขเป็น diff ใต้การวินิจฉัยเริ่มต้น และการตรวจของฟอร์แมตเตอร์ก็รองรับรูปแบบเอาต์พุตสำหรับ JSON รวมถึงคอมเมนต์ใน GitHub/GitLab CI
- ส่วนใหญ่สามารถอัปเกรดได้โดยไม่ต้องเปลี่ยนแปลงมาก แต่ควรตรวจสอบผลกระทบของกฎเริ่มต้นที่เพิ่มขึ้นและ การเปลี่ยนแปลงเอาต์พุต JSON ที่ค่าบางรายการอาจเป็น
null ต่อการตั้งค่าและเครื่องมืออัตโนมัติเดิม
ขยายกฎเริ่มต้นเป็น 413 รายการ
- Ruff v0.16.0 เป็นลินเตอร์และฟอร์แมตเตอร์ Python ความเร็วสูงที่เขียนด้วย Rust สามารถติดตั้งได้จาก PyPI หรือด้วย
uv tool install ruff@latest
- กฎทั้งหมดของ Ruff เพิ่มจาก 708 รายการในสมัย v0.1.0 เป็น 968 รายการ แต่กฎที่เปิดใช้งานโดยค่าเริ่มต้นยังคงอยู่ที่ 59 รายการมาตลอด
- v0.16 ขยายกฎเริ่มต้นเป็น 413 รายการ เพื่อให้ตรวจพบปัญหาร้ายแรง รวมถึงข้อผิดพลาดทางไวยากรณ์และข้อผิดพลาดรันไทม์ที่เกิดขึ้นทันที โดยไม่ต้องตั้งค่าเพิ่มเติม
- รวมถึงกฎหมวด
B ของ flake8-bugbear, UP ของ pyupgrade และกฎหมวด RUF ของ Ruff เอง
- ดูรายการทั้งหมดได้ในเอกสาร Default Rules
- โปรเจกต์ที่ใช้
select หรือ extend-select อยู่แล้วก็สามารถตรวจสอบกฎที่มีประโยชน์ซึ่งอาจไม่เคยรู้มาก่อนผ่านกฎเริ่มต้นชุดใหม่ได้
- หากต้องการย้อนกลับไปใช้กฎเริ่มต้นเดิม ให้ตั้งค่าดังนี้
[lint]
select = ["E4", "E7", "E9", "F"]
- การเปลี่ยนแปลงครั้งนี้เชื่อมโยงกับงานระยะยาวเรื่อง การจัดประเภทกฎใหม่ และงานที่เกี่ยวข้องจะยังดำเนินต่อไป
การฟอร์แมตบล็อกโค้ด Markdown
ruff format จะฟอร์แมต บล็อกโค้ดแบบ fenced ของ Python ที่อยู่ในไฟล์ Markdown
- info string ที่รองรับคือ
python, py, python3, py3, pyi, pycon
pyi จะถูกประมวลผลในรูปแบบไฟล์ stub
pycon จะถูกประมวลผลในรูปแบบเซสชัน REPL
- ที่เหลือจะถูกฟอร์แมตเหมือนไฟล์ Python ปกติ
- แม้ชื่อภาษาจะถูกล้อมด้วยวงเล็บปีกกา เช่น
{python} ก็ยังรู้จำได้ จึงใช้กับ Quarto notebook ได้ด้วย
- หากใช้ส่วนขยาย
.qmd อาจต้องตั้งค่า mapping ของ extension
- ภายในบล็อกโค้ดสามารถใช้
fmt: off และ fmt: on เพื่อกดการฟอร์แมตบางส่วนได้
- พื้นที่เอกสาร Markdown ทั้งหมดสามารถยกเว้นได้ด้วยคอมเมนต์ HTML
<!-- fmt: off --> และ <!-- fmt: on -->
- หากต้องการยกเว้นไฟล์ Markdown ทั้งหมด ให้ระบุ glob เช่น
*.md ใน extend-exclude
- ดูรายละเอียดพฤติกรรมได้ในเอกสาร การฟอร์แมตโค้ด Markdown
คอมเมนต์กดการวินิจฉัยแบบใหม่
- ต่อจากการกดแบบช่วงด้วย
ruff: disable·ruff: enable ใน v0.15, v0.16 เพิ่ม ruff: ignore และ ruff: file-ignore
ruff: ignore สามารถกดการวินิจฉัยในบรรทัดเดียวกันได้เหมือน noqa หรือเขียนเป็นคอมเมนต์เดี่ยวเพื่อให้มีผลกับบรรทัดเชิงตรรกะถัดไปทั้งบรรทัด
- ในส่วนหัวฟังก์ชันที่เขียนหลายบรรทัด ตั้งแต่
def ถึงเครื่องหมายโคลอนจะถือเป็นบรรทัดเชิงตรรกะเดียว
ruff: file-ignore กดการวินิจฉัยที่ระบุทั้งไฟล์ได้เหมือน ruff: noqa
- ในคอมเมนต์กดแต่ละรายการ สามารถเขียน เหตุผลที่ใช้ ต่อท้ายรหัสกฎได้
- ตัวเลือก CLI
--add-ignore จะเพิ่มคอมเมนต์ ruff: ignore ที่จำเป็นให้อัตโนมัติ
- ในโหมด preview สามารถใช้ ชื่อกฎ เช่น
unused-import แทนรหัสอย่าง F401 ได้
- ข้อกำหนดคอมเมนต์ทั้งหมดสรุปไว้ในเอกสาร Ruff linter
diff การแก้ไขและรูปแบบเอาต์พุต
- ก่อนหน้านี้
check และ format รองรับ --diff อยู่แล้ว แต่ทำงานแยกจากการวินิจฉัยทั่วไป จึงไม่ได้แสดงพร้อมกับการวินิจฉัยที่บอกเหตุผลของการแก้ไข
- เอาต์พุต
full เริ่มต้นของ v0.16 จะแสดงการแก้ไขที่เป็นไปได้จากลินเตอร์และฟอร์แมตเตอร์เป็น diff ใต้การวินิจฉัย
format --check ก็สามารถใช้รูปแบบเอาต์พุตทั้งหมดที่ลินเตอร์รองรับได้
- สร้าง JSON สำหรับให้เครื่องอ่านได้
- แสดงผลในรูปแบบที่ GitHub และ GitLab เรนเดอร์เป็นคอมเมนต์ใน CI ได้
- รูปแบบที่รองรับดูได้จากความช่วยเหลือของ CLI และเอกสาร รูปแบบเอาต์พุต
ความเข้ากันได้และการทำให้เสถียร
- breaking changes ใน v0.16 มีจำนวนน้อย ดังนั้นส่วนใหญ่สามารถอัปเดตได้โดยไม่ต้องเปลี่ยนโค้ดหรือการตั้งค่ามากนัก
filename, location, end_location, fix.edits[].location, fix.edits[].end_location ในเอาต์พุต JSON อาจเป็น null แทนการใช้สตริงว่างหรือแถว 1 คอลัมน์ 1 เป็นค่าเริ่มต้น
- ปัจจุบันการวินิจฉัยที่ได้รับผลกระทบมีน้อยมาก แต่ในกฎอนาคตอาจพบได้บ่อยขึ้น
- กฎ 12 รายการเปลี่ยนจาก preview เป็นสถานะ stable
- ความเข้ากันได้ของ signature ฟังก์ชัน Airflow 3
AIR303, ประกาศลิขสิทธิ์ CPY001, การแปลง float FURB164, min/max ที่เรียงลำดับแล้ว FURB192
- การเชื่อมสตริงใน collection literal
ISC004, การบันทึกข้อยกเว้นนอก exception handler LOG004, ประเภทคืนค่า bool ที่ไม่ถูกต้อง PLE0304
- อาร์กิวเมนต์ตำแหน่งมากเกินไป
PLR0917, การคืนค่า StopIteration PLR1708, ตำแหน่งของ None ใน Union RUF036
- การเข้าถึง annotation ใน dictionary ของคลาส
RUF063, รายการซ้ำใน __all__ RUF068
- พฤติกรรมที่เสถียรแล้ว ของกฎเดิมบางส่วนก็ถูกนำมาใช้เป็นค่าเริ่มต้น
BLE001 จะถูกกดแม้บันทึกข้อยกเว้นด้วยเมธอด logging อื่นนอกจาก critical, error, exception
FA102 ตรวจ API ที่เข้ากันได้กับ PEP 585 เพิ่มเติม เช่น collections.abc
INT001·INT002·INT003 ตรวจรูปแบบการใช้งานทั่วไปด้วย เช่น การกำหนด gettext ให้กับ builtins._
S310 ตีความการ bind string literal ในเครื่องเพื่อลด false positive
S508·S509 รองรับ API ที่แนะนำของ PySNMP รุ่นใหม่
UP019 รู้จักไม่เพียง typing.Text แต่รวมถึง typing_extensions.Text ด้วย
- ดูการเปลี่ยนแปลงทั้งหมดได้ที่ GitHub release
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ผมอัปเกรด โปรเจกต์ Python ขนาดประมาณ 3,000 บรรทัด จาก v0.15.x เป็นเวอร์ชันใหม่ ใช้เวลาไม่นาน และมันพบปัญหาหลายอย่างที่เวอร์ชันก่อนหน้าพลาดไป ทำให้คุณภาพโค้ดดีขึ้นด้วย
การแก้ไขด้วยมือ ตามข้อเสนอแนะ: https://github.com/nickjj/plutus/commit/9af66d31f98bef841588...
เปิดใช้กฎความยาวบรรทัดอีกครั้ง: https://github.com/nickjj/plutus/commit/21789f89bbcee37913c1...
บังคับให้ตัวแปรที่ไม่ได้ใช้มีคำนำหน้า
_: https://github.com/nickjj/plutus/commit/a272c77b932e1c78558a...การแก้ไขอัตโนมัติของ Ruff: https://github.com/nickjj/plutus/commit/6fe69cf88385ebdf9b8c...
ดีใจที่ Ruff, ty, uv ยังถูกพัฒนาอย่างคึกคัก แม้ Astral จะถูก OpenAI ซื้อกิจการไปแล้ว
uv กับ Ruff ยอดเยี่ยม และหวังว่า ty จะไปถึงระดับนั้นได้สักวัน
น่าประหลาดใจที่ผู้คนตื่นเต้นกับ เครื่องมือตำรวจไวยากรณ์ ที่ต่างฝ่ายต่างนำกฎตามอำเภอใจมาใช้ และแม้แต่เรื่องว่าโค้ด Python ที่ดีคืออะไรยังตกลงกันไม่ได้
มันรวมดิกชันนารีหลายบรรทัดให้เป็นบรรทัดเดียวจนทำลายเจตนาของคอมเมนต์ แล้วก็แก้แค่รูปแบบจุกจิกอย่างช่องว่างสองช่องกับเครื่องหมายคำพูดคู่ ปัญหาจริง ๆ ไม่ใช่ช่องว่างท้ายบรรทัดหรือการจัดเรียง import แต่เป็น list comprehension 10 บรรทัดที่อ่านยาก ซึ่งเครื่องมือพวกนี้จับไม่ได้
ที่ทำงานใช้ pylint, flake8, black, Ruff และทุกการเปลี่ยนแปลงทำให้เกิดคอมมิตเป็นร้อย ๆ อัน เอาพลังงานนั้นไปใช้กับอย่างอื่นน่าจะดีกว่า
ถ้ายอมรับผลการรันอัตโนมัติตามนั้น ก็ถอนตัวจากการถกเรื่อง lint ได้ แต่ในองค์กรที่ไม่มีเครื่องมือแบบนี้ เราต้องเสียเวลาจริงไปกับการคิดและถกเรื่องรูปแบบ
ในการพัฒนาแบบทีม จำเป็นต้องฟังความเห็นรอบข้างมากกว่าผลักดันรสนิยมส่วนตัวอย่างหนัก และทบทวนลำดับความสำคัญระหว่างการทำงานร่วมกันกับความเป็นช่างฝีมือ
พฤติกรรมที่รวมบรรทัดทั้งที่มีคอมเมนต์ท้ายบรรทัดดูไม่เหมาะสม เครื่องหมายคำพูดคู่ใน Python เป็นเพียงการเลือกสไตล์ และถ้าข้างในสตริงแบบเครื่องหมายคำพูดเดี่ยวมีเครื่องหมายคำพูดคู่อยู่ Ruff ก็จะปล่อยไว้ตามเดิม
ถ้า Go มีเครื่องมือแบบ Ruff ก็คงดี มีเครื่องมือยอดเยี่ยมออกมาในหลายภาษา แต่ ecosystem ของ Go กระจัดกระจาย และยังไม่มีเครื่องมือที่รู้สึกว่าสมบูรณ์เท่า Ruff, Oxc, Biome, Mago
มันค่อนข้างใหม่จึงยังไม่เป็นที่รู้จักมากนัก แต่เป็นรากฐานของ go fix และ go vet และดูเหมือนทีม Go กำลังทำให้ผู้เขียนโมดูลกำหนด analysis pass แบบกำหนดเองที่ทำงานอัตโนมัติเมื่อรัน go fix ได้ง่ายขึ้น
ด้วย struct
analysis.Analyzerสามารถเข้าถึง AST, type, ข้อมูล SSA และผสานข้อมูลระหว่าง analyzer ได้ เมื่อคอมไพล์เป็นไบนารีแล้วส่งให้ go fix toolchain ก็จะจัดการแม้แต่ caching ที่ซับซ้อนให้ ทีม Go สร้างเองและรวมไว้ใน toolchain ดังนั้นในระยะยาว เครื่องมืออย่าง golangci-lint ก็มีแนวโน้มสูงที่จะถูกรวมเข้ากับเฟรมเวิร์กนี้คุณลองสั่ง AI agent ให้เขียน analyzer ของ Go Analysis แล้วขับด้วย go fix ได้ และในโปรเจกต์ของผมเองก็ใช้มันบังคับใช้กฎหลายข้อแบบอัตโนมัติและกำหนดผลได้แน่นอน แทนคำแนะนำ Markdown ที่ไม่แม่นยำ
gofmtสำหรับ Python Ruff ไม่ใช่ formatter แต่เป็น linter ถึงอย่างนั้นทิศทางการพัฒนาล่าสุดของ ecosystem Python ก็น่ายินดีต่างจาก Python หรือ TypeScript ที่เครื่องมือทางการไม่ได้บังคับสไตล์เฉพาะ ใน Go จึงยากที่จะเห็นผลลัพธ์แบบพลิกโฉมเหมือนตอนเริ่มใช้ Ruff หรือ Biome
การเปิดใช้ กฎ 413 ข้อ เป็นค่าเริ่มต้นถือเป็นการเปลี่ยนแปลงที่ดี เพราะโปรเจกต์ส่วนใหญ่จะได้ lint ที่มีประโยชน์โดยไม่ต้องไปแตะการตั้งค่า
ช่วงนี้คงมอบหมายให้เอเจนต์แก้คำเตือน lint ทั้งหมดตามเกณฑ์ที่กำหนด แล้วปล่อยไว้สักไม่กี่ชั่วโมงก็จัดการได้ แต่การวินิจฉัยแบบละเอียดที่ Ruff ให้มานั้นก็เป็นสิ่งที่น่ายินดี
Ruff เองก็ต้องมีฟีเจอร์คล้าย stateVersion ของ Nix เพื่อกำหนดชุดค่าเริ่มต้นที่จะนำไปใช้ เวลอัปเดต Ruff ในหลายรีโพซิทอรี ทุกครั้งที่มีกฎเริ่มต้นใหม่เพิ่มเข้ามา ก็ต้องรีบปิดทันทีหรือแก้รายการที่ละเมิด ทำให้คาดเดาผลลัพธ์ได้ยาก
จะเขียนกฎทั้งหมดที่จะเปิดใช้ไว้ใน allowlist ก็ได้ แต่การคงการตั้งค่าให้เรียบง่าย แล้วค่อยเพิ่มเวอร์ชันสถานะเมื่อทุกคนมีเวลาลงแรงสักสองสามชั่วโมง น่าจะดีกว่า
pyproject.tomlของแต่ละโปรเจกต์ แต่ละโปรเจกต์ก็อัปเวอร์ชันเมื่อพร้อมได้ จึงไม่ต้องประสานงานหลายโปรเจกต์พร้อมกัน และถ้าโปรเจกต์หนึ่งตามไม่ทัน โปรเจกต์อื่นก็ไม่ถูกขวางhttps://github.com/astral-sh/ruff/releases/tag/v0.1.0
ในยุคของการเขียนโค้ดด้วยเอเจนต์ linting ที่เข้มงวด สำคัญกว่าที่เคย และอยากเห็นเครื่องมือแบบ forbidigo ในภาษาที่มากขึ้น
เอเจนต์เขียนโค้ดเองก็ใช้โทเคนไปมากกับการแก้ปัญหาเล็ก ๆ น้อย ๆ หรือถ้าเทสต์ล้มเหลวก็อาจปิดใช้ไปเลย แม้จะเริ่มเชื่อถือความถูกต้องโดยรวมของผลลัพธ์จาก AI แล้ว แต่ วิจารณญาณด้านคุณภาพโค้ด ยังเชื่อได้ยากอยู่ดี
ถึงจะมีกฎมากถึง 413 ข้อ แต่ทุกครั้งที่เข้าร่วมโค้ดเบสใหม่ ก็ยังต้องถกเถียงสามเรื่องเดิม ๆ เกี่ยวกับการเรียง import ซ้ำแล้วซ้ำอีก
ดีใจที่ดูเหมือนตอนนี้แนะนำให้ใช้แบบ ไม่ต้องตั้งค่า แล้ว ใน
.ruff.tomlใหม่ แค่ใส่line-length = 300ก็พอ