1 คะแนน โดย GN⁺ 1 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • 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 ความคิดเห็น

 
GN⁺ 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 ซื้อกิจการไปแล้ว

    • เคยคาดหวังกับ ty แต่สุดท้ายเลิกใช้ เพราะมัน ตามหลัง basedpyright อยู่มาก ปัญหาไม่ใช่แค่รายการตรวจสอบมีน้อย แต่ false positive นั้นร้ายแรง และยังไม่มีฟีเจอร์ baselining ซึ่งมีประโยชน์มากกับโค้ดเบสขนาดใหญ่
      uv กับ Ruff ยอดเยี่ยม และหวังว่า ty จะไปถึงระดับนั้นได้สักวัน
  • น่าประหลาดใจที่ผู้คนตื่นเต้นกับ เครื่องมือตำรวจไวยากรณ์ ที่ต่างฝ่ายต่างนำกฎตามอำเภอใจมาใช้ และแม้แต่เรื่องว่าโค้ด Python ที่ดีคืออะไรยังตกลงกันไม่ได้
    มันรวมดิกชันนารีหลายบรรทัดให้เป็นบรรทัดเดียวจนทำลายเจตนาของคอมเมนต์ แล้วก็แก้แค่รูปแบบจุกจิกอย่างช่องว่างสองช่องกับเครื่องหมายคำพูดคู่ ปัญหาจริง ๆ ไม่ใช่ช่องว่างท้ายบรรทัดหรือการจัดเรียง import แต่เป็น list comprehension 10 บรรทัดที่อ่านยาก ซึ่งเครื่องมือพวกนี้จับไม่ได้
    ที่ทำงานใช้ pylint, flake8, black, Ruff และทุกการเปลี่ยนแปลงทำให้เกิดคอมมิตเป็นร้อย ๆ อัน เอาพลังงานนั้นไปใช้กับอย่างอื่นน่าจะดีกว่า

    • จุดประสงค์ของเครื่องมือแบบนี้คือทำให้เรา โฟกัสกับปัญหาจริง การทำให้การตัดสินใจเรื่อง lint เป็นอัตโนมัติ ช่วยไม่ต้องเสียพลังความคิดถกเถียงเรื่องรูปแบบใน PR
      ถ้ายอมรับผลการรันอัตโนมัติตามนั้น ก็ถอนตัวจากการถกเรื่อง lint ได้ แต่ในองค์กรที่ไม่มีเครื่องมือแบบนี้ เราต้องเสียเวลาจริงไปกับการคิดและถกเรื่องรูปแบบ
    • ความรู้สึกต่อต้านที่ว่า linter ทำให้เสียเวลาดูจะเกินระดับที่สมเหตุสมผลไปแล้ว ในภาคสนามมีหลักฐานเพียงพอว่ามันช่วยประหยัดเวลาเสียมากกว่า และสุดท้ายประเด็นหลักก็แค่ บางครั้ง linter ทำการเปลี่ยนแปลงที่เราไม่ชอบ เท่านั้น
      ในการพัฒนาแบบทีม จำเป็นต้องฟังความเห็นรอบข้างมากกว่าผลักดันรสนิยมส่วนตัวอย่างหนัก และทบทวนลำดับความสำคัญระหว่างการทำงานร่วมกันกับความเป็นช่างฝีมือ
    • Ruff รู้จักคอมเมนต์ท้ายบรรทัด จึงคงแต่ละรายการไว้คนละบรรทัด และเพิ่มแค่ คอมมาต่อท้ายกับช่องว่าง เท่านั้น ถ้ามีคอมมาต่อท้ายอยู่แล้ว มันก็จะไม่รวมบรรทัด และผลลัพธ์ที่ยกมาดูเหมือนมาจาก Black
      พฤติกรรมที่รวมบรรทัดทั้งที่มีคอมเมนต์ท้ายบรรทัดดูไม่เหมาะสม เครื่องหมายคำพูดคู่ใน Python เป็นเพียงการเลือกสไตล์ และถ้าข้างในสตริงแบบเครื่องหมายคำพูดเดี่ยวมีเครื่องหมายคำพูดคู่อยู่ Ruff ก็จะปล่อยไว้ตามเดิม
    • เครื่องมือแบบนี้กลับช่วย ประหยัดพลังงานของทีม ถ้าไม่มีเครื่องมือ นักพัฒนาแต่ละคนจะมีมาตรฐานเรื่องรูปแบบ คุณภาพโค้ด และความอ่านง่ายต่างกัน จนถกเถียงกันไม่รู้จบ ดังนั้นปล่อยให้ Ruff จัดการดีกว่า
    • ที่มันถูกรวมเป็นบรรทัดเดียวก็เพราะ ลืมใส่คอมมาหลังรายการสุดท้าย อย่างน้อยใน Black ถ้าคงคอมมาต่อท้ายไว้ รายการต่าง ๆ จะไม่ถูกบีบอัด แต่ผมพบว่ามันทำลายรูปแบบที่ตั้งใจไว้บ่อย จึงไม่ผูกมันเข้ากับโค้ดของผมอีกแล้ว
  • ถ้า Go มีเครื่องมือแบบ Ruff ก็คงดี มีเครื่องมือยอดเยี่ยมออกมาในหลายภาษา แต่ ecosystem ของ Go กระจัดกระจาย และยังไม่มีเครื่องมือที่รู้สึกว่าสมบูรณ์เท่า Ruff, Oxc, Biome, Mago

    • Go มี Go Analysis Framework ที่ดีกว่า: https://pkg.go.dev/golang.org/x/tools/go/analysis
      มันค่อนข้างใหม่จึงยังไม่เป็นที่รู้จักมากนัก แต่เป็นรากฐานของ 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 ที่ไม่แม่นยำ
    • เมื่อไม่นานมานี้บรรยากาศกลับตรงกันข้ามเลย ชุมชน Python ลำบากเพราะขาดเครื่องมือ และทุกคนอยากได้ gofmt สำหรับ Python Ruff ไม่ใช่ formatter แต่เป็น linter ถึงอย่างนั้นทิศทางการพัฒนาล่าสุดของ ecosystem Python ก็น่ายินดี
    • ไม่ค่อยเข้าใจที่บอกว่า ecosystem ของ Go กระจัดกระจาย Go มี เครื่องมือ formatting และ linting อย่างเป็นทางการ และตัวภาษาเองก็จงใจถูกจำกัดไว้ เพื่อให้แม้แต่มือใหม่เขียนก็ออกมาเป็นรูปแบบสม่ำเสมอ
      ต่างจาก Python หรือ TypeScript ที่เครื่องมือทางการไม่ได้บังคับสไตล์เฉพาะ ใน Go จึงยากที่จะเห็นผลลัพธ์แบบพลิกโฉมเหมือนตอนเริ่มใช้ Ruff หรือ Biome
    • Go เป็นหนึ่งใน ecosystem เครื่องมือภาษาที่ดีที่สุดที่ใช้ได้แม้ไม่มี IDE ขนาดใหญ่ และ golangci-lint ก็ครอบคลุมมากทีเดียว ตัว distribution ของ Go เองก็แก้ปัญหาไปแล้วหลายส่วน
    • golangci-lint มีมานานแล้วและถูกใช้อย่างแพร่หลาย
  • การเปิดใช้ กฎ 413 ข้อ เป็นค่าเริ่มต้นถือเป็นการเปลี่ยนแปลงที่ดี เพราะโปรเจกต์ส่วนใหญ่จะได้ lint ที่มีประโยชน์โดยไม่ต้องไปแตะการตั้งค่า

    • แต่ก็ยังน่าสงสัยว่า การที่โปรเจกต์เดิมจู่ ๆ มี คำเตือนที่อาจเกิดขึ้น 413 รายการ ถาโถมเข้ามาจะมีประโยชน์จริงหรือไม่ และดูเหมาะกับโปรเจกต์ใหม่มากกว่า
      ช่วงนี้คงมอบหมายให้เอเจนต์แก้คำเตือน lint ทั้งหมดตามเกณฑ์ที่กำหนด แล้วปล่อยไว้สักไม่กี่ชั่วโมงก็จัดการได้ แต่การวินิจฉัยแบบละเอียดที่ Ruff ให้มานั้นก็เป็นสิ่งที่น่ายินดี
  • Ruff เองก็ต้องมีฟีเจอร์คล้าย stateVersion ของ Nix เพื่อกำหนดชุดค่าเริ่มต้นที่จะนำไปใช้ เวลอัปเดต Ruff ในหลายรีโพซิทอรี ทุกครั้งที่มีกฎเริ่มต้นใหม่เพิ่มเข้ามา ก็ต้องรีบปิดทันทีหรือแก้รายการที่ละเมิด ทำให้คาดเดาผลลัพธ์ได้ยาก
    จะเขียนกฎทั้งหมดที่จะเปิดใช้ไว้ใน allowlist ก็ได้ แต่การคงการตั้งค่าให้เรียบง่าย แล้วค่อยเพิ่มเวอร์ชันสถานะเมื่อทุกคนมีเวลาลงแรงสักสองสามชั่วโมง น่าจะดีกว่า

    • วิธีที่เหมาะกว่าคือการ ตรึงเวอร์ชัน Ruff ที่ต้องการไว้ใน pyproject.toml ของแต่ละโปรเจกต์ แต่ละโปรเจกต์ก็อัปเวอร์ชันเมื่อพร้อมได้ จึงไม่ต้องประสานงานหลายโปรเจกต์พร้อมกัน และถ้าโปรเจกต์หนึ่งตามไม่ทัน โปรเจกต์อื่นก็ไม่ถูกขวาง
    • ตามต้นฉบับ ชุดกฎเริ่มต้น ของ Ruff ไม่ได้เปลี่ยนมานานเกิน 2 ปีแล้ว และการเปลี่ยนแปลงครั้งล่าสุดคือ v0.1.0
      https://github.com/astral-sh/ruff/releases/tag/v0.1.0
  • ในยุคของการเขียนโค้ดด้วยเอเจนต์ linting ที่เข้มงวด สำคัญกว่าที่เคย และอยากเห็นเครื่องมือแบบ forbidigo ในภาษาที่มากขึ้น

    • กำลังอัปเกรดหลายโปรเจกต์อยู่ แต่ก็รู้สึกซับซ้อน ตอนเขียนโค้ดเอง เราใช้สัญชาตญาณตัดสินได้ว่าควรข้ามหรือเพิกเฉยต่อกฎเมื่อใด แต่ในโปรเจกต์ที่เปิดใช้กฎ pylint แทบทั้งหมด โค้ดกลับอ่านยากขึ้นเพราะมีทริกหลบเลี่ยงเพื่อให้ pylint พอใจ
      เอเจนต์เขียนโค้ดเองก็ใช้โทเคนไปมากกับการแก้ปัญหาเล็ก ๆ น้อย ๆ หรือถ้าเทสต์ล้มเหลวก็อาจปิดใช้ไปเลย แม้จะเริ่มเชื่อถือความถูกต้องโดยรวมของผลลัพธ์จาก AI แล้ว แต่ วิจารณญาณด้านคุณภาพโค้ด ยังเชื่อได้ยากอยู่ดี
  • ถึงจะมีกฎมากถึง 413 ข้อ แต่ทุกครั้งที่เข้าร่วมโค้ดเบสใหม่ ก็ยังต้องถกเถียงสามเรื่องเดิม ๆ เกี่ยวกับการเรียง import ซ้ำแล้วซ้ำอีก

  • ดีใจที่ดูเหมือนตอนนี้แนะนำให้ใช้แบบ ไม่ต้องตั้งค่า แล้ว ใน .ruff.toml ใหม่ แค่ใส่ line-length = 300 ก็พอ