<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Python on yothinix</title><link>https://yothinix-com.pages.dev/tags/python/</link><description>Recent content in Python on yothinix</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Fri, 18 Feb 2022 13:49:56 +0700</lastBuildDate><atom:link href="https://yothinix-com.pages.dev/tags/python/index.xml" rel="self" type="application/rss+xml"/><item><title>My first PyCon US experience (2021, Online)</title><link>https://yothinix-com.pages.dev/my-first-pycon-us-experience-2021-online/</link><pubDate>Mon, 24 May 2021 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/my-first-pycon-us-experience-2021-online/</guid><description>&lt;p&gt;หลายปีที่แล้วผมเคยพูดไว้ว่า &lt;a href="https://yothinix-com.pages.dev/why-i-love-python-so-much/"&gt;หนึ่งในสิ่งที่ผมชอบเกี่ยวกับภาษา Python ที่สุดคือ Community ครับ&lt;/a&gt; และผ่านมาหลายปี ผมก็ยังยืนยันคำเดิมว่า Python Community เป็นหนึ่งใน Tech community ที่เปิดรับและเป็นมิตรมากที่สุดที่หนึ่งครับ และงานใหญ่ที่สุดประจำปีของชาว Python คืองาน PyCon US หรือหลาย ครั้งก็เรียกกันแค่ PyCon เพราะที่นี่เป็น Original ก่อนจะมี regional PyCon ต่าง ไม่ว่าจะเป็น &lt;a href="https://ep2021.europython.eu/"&gt;Euro Python&lt;/a&gt;, &lt;a href="https://2021.pycon.org.au/"&gt;PyCon AU&lt;/a&gt;, &lt;a href="https://th.pycon.org/"&gt;PyCon APAC&lt;/a&gt; หรือ &lt;a href="https://th.pycon.org/"&gt;PyCon Thailand&lt;/a&gt; ครับ&lt;/p&gt;
&lt;p&gt;และอย่างที่เรารู้กันดีว่าปี 2021 นี้ยังเป็นอีกปีที่การระบาดของไวรัส COVID-19 ทำให้นี่เป็นปีที่สองที่ PyCon US จัด Online ครับ ซึ่งข้อดีคือ ทำให้เราๆ ที่ไม่ได้อยู่ US สามารถร่วม Conference ได้เพียงแค่มี Computer / Internet เท่านั้นครับ แต่ข้อเสียคือ Timezone จะลำบากหน่อย เพราะเวลา US แทบจะกลับด้านกลางวันกลางคืนกับเวลาไทยเลย&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yothinix-com.pages.dev/my-first-pycon-us-experience-2021-online/1-nG1ixR9VB4Ymg63g8H_QCw_hu_e395f98d65feeab2.webp"
srcset="https://yothinix-com.pages.dev/my-first-pycon-us-experience-2021-online/1-nG1ixR9VB4Ymg63g8H_QCw_hu_bf9d75267b90677f.webp 480w, https://yothinix-com.pages.dev/my-first-pycon-us-experience-2021-online/1-nG1ixR9VB4Ymg63g8H_QCw_hu_e395f98d65feeab2.webp 960w"
sizes="(max-width: 960px) 100vw, 960px"
width="960" height="776"
alt=""
loading="lazy" decoding="async"&gt;
&lt;em&gt;วิธีการ Scout หัวข้อผมก็ง่ายๆ ครับทำ Spreadsheet แล้วก็เรียงตาม timeline สำคัญคือ Track ไหนเวลาไหน&lt;/em&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>หลายปีที่แล้วผมเคยพูดไว้ว่า <a href="/why-i-love-python-so-much/">หนึ่งในสิ่งที่ผมชอบเกี่ยวกับภาษา Python ที่สุดคือ Community ครับ</a> และผ่านมาหลายปี ผมก็ยังยืนยันคำเดิมว่า Python Community เป็นหนึ่งใน Tech community ที่เปิดรับและเป็นมิตรมากที่สุดที่หนึ่งครับ และงานใหญ่ที่สุดประจำปีของชาว Python คืองาน PyCon US หรือหลาย ครั้งก็เรียกกันแค่ PyCon เพราะที่นี่เป็น Original ก่อนจะมี regional PyCon ต่าง ไม่ว่าจะเป็น <a href="https://ep2021.europython.eu/">Euro Python</a>, <a href="https://2021.pycon.org.au/">PyCon AU</a>, <a href="https://th.pycon.org/">PyCon APAC</a> หรือ <a href="https://th.pycon.org/">PyCon Thailand</a> ครับ</p>
<p>และอย่างที่เรารู้กันดีว่าปี 2021 นี้ยังเป็นอีกปีที่การระบาดของไวรัส COVID-19 ทำให้นี่เป็นปีที่สองที่ PyCon US จัด Online ครับ ซึ่งข้อดีคือ ทำให้เราๆ ที่ไม่ได้อยู่ US สามารถร่วม Conference ได้เพียงแค่มี Computer / Internet เท่านั้นครับ แต่ข้อเสียคือ Timezone จะลำบากหน่อย เพราะเวลา US แทบจะกลับด้านกลางวันกลางคืนกับเวลาไทยเลย</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-nG1ixR9VB4Ymg63g8H_QCw_hu_e395f98d65feeab2.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-nG1ixR9VB4Ymg63g8H_QCw_hu_bf9d75267b90677f.webp 480w, /my-first-pycon-us-experience-2021-online/1-nG1ixR9VB4Ymg63g8H_QCw_hu_e395f98d65feeab2.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="776"
       alt=""
       loading="lazy" decoding="async">
<em>วิธีการ Scout หัวข้อผมก็ง่ายๆ ครับทำ Spreadsheet แล้วก็เรียงตาม timeline สำคัญคือ Track ไหนเวลาไหน</em></p>
<h1 id="การเตรยมตว">การเตรียมตัว</h1>
<p>ก่อนจะถึง Conference หลังจากที่เรา Sign up ในเว็บไซต์ PyCon US (ซึ่งปรับใหม่แทบทุกปี) เราก็คอยติดตามข่าวดูได้ตลอดครับว่ามี Tutorial หรือ Talk อะไรบ้าง ซึ่งหัวข้อจะเยอะมาก และหลายๆ หัวข้อที่เราสนใจก็มักจะมาในเวลาเดียวกันแต่อยู่คนละ Track เพราะฉะนั้น ช่วงสัปดาห์ก่อนวันงานจะเป็นช่วงที่ผมวางแผนว่า อยากจะเข้าไปฟัง ไป Discuss ใน Talk ไหนบ้าง เพื่อที่พอถึงวันงานจะได้ไม่ต้องมาเลือกแบบรีบๆ ครับ</p>
<p>ซึ่งสิ่งสำคัญอย่างนึงที่ผมค้นพบเลยคือ วางแผนเรื่อง Timezone ดีๆ ครับ เพราะใน Official PyCon US website จะแสดงเวลาเป็น US หมด แล้วผมมาค้นพบอีกทีตอนวันงานว่า Talk ที่อยากฟังจะอยู่ตอนใกล้ๆ เช้าเวลาไทย อะไรแบบนี้ ทำให้พลาดไป</p>
<p>นอกจากหัวข้อที่ผมเตรียมตัวแล้ว อีกสิ่งหนึ่งที่เตรียมคือเวลานอนครับ จากประสบการณ์ <a href="https://by.pycon.org/">PyCon Belarus</a> กับ <a href="https://2021.pycascades.com/">PyCascade</a> ในช่วงต้นปีที่ผ่านมา ผมไม่เคยอยู่ได้เกินครึ่งงาน เพราะว่าสลบก่อนจากผลของ Different Timezone ครับ</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-o7U8_n3X4qBXvcbA1HDl9w_hu_8fd980391ad2a34f.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-o7U8_n3X4qBXvcbA1HDl9w_hu_64433a4f05181b78.webp 480w, /my-first-pycon-us-experience-2021-online/1-o7U8_n3X4qBXvcbA1HDl9w_hu_8fd980391ad2a34f.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="474"
       alt=""
       loading="lazy" decoding="async">
<em>หน้าเว็บของ Hubilio ครับ จะเห็นว่าจำลองส่วนต่างๆ ของ Conference มาไว้ตรงเมนูหมดเลย</em></p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-hi7u6QazkdRat3sCi0-3Ew_hu_cad80df90ddafb58.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-hi7u6QazkdRat3sCi0-3Ew_hu_6d9f02df9f05b716.webp 480w, /my-first-pycon-us-experience-2021-online/1-hi7u6QazkdRat3sCi0-3Ew_hu_cad80df90ddafb58.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="488"
       alt=""
       loading="lazy" decoding="async">
<em>ช่วง​ Conference Day พอถึงเวลาแต่ละ Talk จะมี Schedule มาแจ้งเตือนครับ</em></p>
<h1 id="conference-day">Conference Day</h1>
<p>Conference Day ของ PyCon US ปีนี้ตรงกับคืนวันศุกร์ที่ 14 ถึงเช้าวันเสาร์ที่ 15 และคืนวันเสาร์ที่ 15 ถึงเช้าวันอาทิตย์ที่ 16 ครับ ซึ่งวันศุกร์จะเหนื่อยๆ หน่อย เพราะไปทำงานมาทั้งวัน แล้วมาต่อ Conference ในตอนกลางคืน ซึ่งช่วงสัปดาห์ของ PyConUS จะเร่ิมด้วย Tutorial กับ Language Summit ก่อนครับ แต่ผม Sign up สอง event นั้นไม่ทันก็เลยไม่ได้ร่วม ครับโดย Platform ที่ PyCon US เลือกใช้คือ <a href="https://hubilo.com/">Hubilio</a> ครับ โดยทีมจะส่ง link ในการเข้างานมาให้ตั้งแต่ช่วงต้นสัปดาห์ครับ</p>
<p>ซึ่งใน Platform Hubilio นี่ก็มีตัวเลือกให้เราเล่นหลากหลายมาก จำลองมาจากงาน Conference จริงๆ ครับ ไม่ว่าจะเป็น Lounge หรือ Sponsor Booth ที่เราสามารถไปเยี่ยมชมหน้าเพจที่ custom มาโดยเฉพาะของ Sponsor ครับ รวมถึงเข้าไป Say Hi หรือนัดเวลาคุยกับพนักงานจาก Sponsor Booth ได้ด้วยครับ เหมือนเราไปคุยกับคนที่บูธจริงๆ เลย</p>
<p>นอกจากนั้นแล้วด้วยความที่ Talk จะถูก Pre-record มาก่อนทำให้เราสามารถดูย้อนหลังได้ด้วยครับ ซึ่งมี Sponsor Workshop ที่ผมอยากฟังมากคือ Blackfire: Debugging Performance in Python and Django applications ก็สามารถกดเข้าไปดูย้อนหลังได้ครับ</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-HhM-2lJFtaVCP7LxqJFjiA_hu_6f935c4b0cbe66bc.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-HhM-2lJFtaVCP7LxqJFjiA_hu_c9c95c1c4295fcc2.webp 480w, /my-first-pycon-us-experience-2021-online/1-HhM-2lJFtaVCP7LxqJFjiA_hu_6f935c4b0cbe66bc.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="keynote-imaging-rembrandts-the-night-watch-at-5um-resolution-717-gp-with-python--robert-erdmann-erdmann">Keynote: Imaging Rembrandt’s The Night Watch at 5um Resolution (717 GP) with Python — Robert Erdmann (@erdmann)</h2>
<p>เป็น Talk ที่มาเล่าถึง <a href="https://www.rijksmuseum.nl/en/whats-on/exhibitions/operation-night-watch">Operation Night Watch</a> ครับ ซึ่งเป็นโปรเจ็คการฟื้นฟูภาพ The Night Watch ของ Rembrant ครับ ซึ่งใน Talk เล่าถึงเทคนิคในการฟื้นฟูภาพที่ทีมนี้ใช้กัน ที่ผมขอเรียกว่าจุดสูงสุดของสาขา Image Processing เลยครับ ตั้งแต่การใช้กล้อง Hasselblad 100MP ถ่ายแต่ละส่วนของภาพ หรือใช้ Laser Rangefinder ในการวัดมุมของผืนผ้าใบของภาพ เพื่อสร้าง 3D Map รวมไปถึงเทคนิคในการ Optimization ผ่าน Machine Learning ต่างๆ เรียกได้ว่าถ้าใครหาแรงบันดาลใจในการทำ Image Processing ผมแนะนำ Talk นี้เลยครับ</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-kTRvdXdKgQoVy90bOsUxfg_hu_9dfa2f677b442c4f.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-kTRvdXdKgQoVy90bOsUxfg_hu_b6476927b2680355.webp 480w, /my-first-pycon-us-experience-2021-online/1-kTRvdXdKgQoVy90bOsUxfg_hu_9dfa2f677b442c4f.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="generating-buzz-with-realtime-fm-audio-synthesis--łukasz-langa-llanga">Generating buzz with realtime FM audio synthesis — Łukasz Langa (@llanga)</h2>
<p>Talk นี้พาผมเข้าไปโลกดนตรี synthesis ครับผ่านการเขียนโค้ดสร้าง sine wave จาก Python แล้วเริ่มทำ filter frequency modulate แล้วทำเป็นเสียงผ่าน MIDI interface ครับ ผมชอบ Talk นี้ตรงที่ใช้ Feature ของ Python ใหม่ๆ หลายอย่างเลยทั้ง @dataclasses, Type annotation ที่ไม่ต้อง import Typing แล้วหรือ Generator ที่เราใช้ๆ กันทั่วไปนี่แหละครับ ส่วนตัวผมไม่ค่อยมีความรู้เรื่องดนตรีเลยไม่ค่อยเข้าใจเท่าไรเรื่อง Pitch, note, Envelop function แต่คนที่สนใจเรื่องดนตรีผมว่าน่าจะชอบมากครับ</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-Zw6aS6mjv2yRoVl75ou1Wg_hu_5812a7cbf421f8c6.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-Zw6aS6mjv2yRoVl75ou1Wg_hu_8442a056583dc9e9.webp 480w, /my-first-pycon-us-experience-2021-online/1-Zw6aS6mjv2yRoVl75ou1Wg_hu_5812a7cbf421f8c6.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="writing-good-documentation-for-developers--meredydd-luff">Writing Good Documentation for Developers — Meredydd Luff</h2>
<p>ตอนแรกผมเข้าอีก Talk นึงเรื่อง NumPy API แล้วผมฟังแล้วไม่ค่อยเกท เลยเปลี่ยนมาเข้า Talk นี้แทน แล้วสนุกดีครับ คือใน Talk เค้ามองว่า <em>Documentation is content marketing</em> ของ Software เรา ซึ่งคนอื่น Care มั้ยไม่รู้ แต่เค้าแคร์เพราะเป็นการสร้างประสบการณ์ที่ดีให้กับคนที่มาใช้ Software เรา นอกจากนั้นการที่เค้ามอง Document usage ตามความเป็นจริงทั้ง zoom-in ที่ลงรายละเอียดขึ้นเรื่อยๆ จาก Tutorial, How-to เรื่อยไปจน API Docs หรือ Zoom-out ที่กลับด้านกัน ทำให้เราเข้าใจวิธีการเขียน journey ของการใช้งาน Document ได้ชัดมากครับ อีกจุดนึงที่ชอบของ Talk นี้คือวิธีการแบ่งประเภท Documents ตาม purpose ของมันจะช่วยให้เราโฟกัสกับการเขียนได้ดียิ่งขึ้นครับ และตอบโจทย์คนที่ใช้งานมากยิ่งขึ้น</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-JY79ST-sqa6987w0XtjZ8g_hu_16e726fe72f08f53.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-JY79ST-sqa6987w0XtjZ8g_hu_b67fc8c162f41da0.webp 480w, /my-first-pycon-us-experience-2021-online/1-JY79ST-sqa6987w0XtjZ8g_hu_16e726fe72f08f53.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="zero-to-production-ready-best-practice-process-for-docker-packaging--itamar-turner-trauring-itamarst">Zero to production-ready best practice process for docker packaging — Itamar Turner-Trauring (@itamarst)</h2>
<p>หลายๆ คนน่าจะรู้จักเว็บไซต์ <a href="https://pythonspeed.com/">Python=&gt;Speed</a> กันใช่มั้ยครับ ที่ชอบพูดถึงเรื่อง Infrastructure เกี่ยวกับ Python โดย Talk นี้มาจากเจ้าของเดียวกันครับ ซึ่งพูดถึง Practices ที่เราควรทำเวลา Packaging Python docker แต่ด้วยความที่ Talk จำกัดเวลาแค่ 25 นาที ทำให้เค้าพูดถึงได้แค่บางส่วน ที่กลั่นมาแล้วว่าช่วยให้ชีวิตดีขึ้นแน่นอน เป็น Big Picture ที่เรียงตาม Priority มาให้แล้ว ส่วนตัวผมได้รู้เทคนิคใหม่สองเทคนิคคือ เราสามารถเปิด PYTHONFAULTHANDLER=1 เพื่อให้ CPython interpreter แสดง error ในชั้นที่ interface กับภาษา C ได้ครับ ซึ่งหลายๆ Library ใช้อยู่ไม่ว่าจะเป็น NumPy หรือ Matplotlib หรืออีกเทคนิคนึงคือ เราสามารถ Pre-compile pyc bytecode ได้ตั้งแต่ build Docker image ครับ ซึ่งช่วยลด start-up time ของ Docker Image เราได้ดีเลยทีเดียว</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-vf2FmNK9rdccTZ0Q9kuq2A_hu_286acab79b710caa.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-vf2FmNK9rdccTZ0Q9kuq2A_hu_24ba9d05202d5524.webp 480w, /my-first-pycon-us-experience-2021-online/1-vf2FmNK9rdccTZ0Q9kuq2A_hu_286acab79b710caa.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="restarting-pyjion-a-general-purpose-jit-for-python--is-it-worth-it--anthony-shaw-anthonypjshaw">Restarting Pyjion, a general-purpose JIT for Python — is it worth it? — Anthony Shaw (@anthonypjshaw)</h2>
<p>Talk นี้ผมไม่ได้ดูสดครับ เพราะหลับไปก่อน (ตี 4 เวลาไทยวันนั้น) แต่ข้อดีของ Online Conference คือ “เราสามารถมาดูย้อนหลังได้ครับ” ซึ่งผมก็มาดูย้อนหลังวันเสาร์ตอนกลางวัน แล้วน่าสนใจมากทีเดียว โดย Talk นี้เป็นการเพิ่มความเร็วในการทำงานของ Python ผ่าน <a href="https://github.com/tonybaloney/Pyjion">Pyjion</a> ซึ่งเป็น specialize JIT แทนตัวปกติที่มาจากภาษาครับ ซึ่ง JIT ตัวนี้จะช่วย optimize การทำงานบางส่วนของ CPython ให้เร็วขึ้นได้ เพียงแค่ pip install pyjion แล้ว import ไปใช้งานแค่นั้นเองครับ โดยรองรับ cross-platform ตั้งแต่ x86 — ARM เลย ซึ่งเทคนิคที่ Pyjion ใช้คือการ Profile โค้ดที่เคยรันแล้ว Optimize code ให้รันในรอบต่อๆ ไป ซึ่งเป็นเทคนิคคล้ายๆ กับ PyPy เลยครับเรียกว่า Profile Guided Compilation (PGC) ส่วนตัวอย่างใน Talk มีตั้งแต่ง่ายๆ อย่าง function เดี่ยวๆ ไปจนถึงการเอาไปใช้แก้ปัญหา n-body problem ซึ่งเร็วขึ้นถึง 33% เลยครับ</p>
<p>ผมจำได้ว่าผมเห็น Tweet นี้ของ @PyCon แล้วหลังจากนั้นผมจำอะไรไม่ได้อีกเลยของวันแรกครับ</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Reminder that your body and health is important, if it&#39;s getting a little late where you are, or you simply need a break, don&#39;t fret!<br><br>All sessions are available for viewing at any time in the platform after they have been presented.<br><br>Take time to hydrate, stretch, eat, or sleep.</p>&mdash; PyCon US (@pycon) <a href="https://twitter.com/pycon/status/1393295255320023040?ref_src=twsrc%5Etfw">May 14, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p><img src="/my-first-pycon-us-experience-2021-online/1-UAZhtBtMW8pmeV95jNMhEQ_hu_4ffe4a6fa5656fcc.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-UAZhtBtMW8pmeV95jNMhEQ_hu_7ced2ba9d1c5ac8c.webp 480w, /my-first-pycon-us-experience-2021-online/1-UAZhtBtMW8pmeV95jNMhEQ_hu_4ffe4a6fa5656fcc.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="virtual-lighting-talks-may-15">Virtual Lighting Talks (May 15)</h2>
<p>ส่วนตัวผมพลาด Lighting talks วันแรกไปเพราะหลับไปก่อน แต่วันที่สองเป็น Session แรกเลย ได้เก็บมาครับ ซึ่งมีตั้งแต่ Promote Regional PyCon อย่าง <a href="https://www.pylatam.org/">PyCon Latam</a>, <a href="https://pycon.cl/">PyCon Chile</a>, หรืองานอย่าง <a href="https://adventofcode.com/">Advent of Code </a>เรื่อยไปถึงเทคนิคการใช้ Jupyter Notebook, pytest Parameterize tests หรือ f-string หรือ Promote Framework ที่ตัวเองทำอยู่ไม่ว่าจะเป็น</p>
<ul>
<li><a href="https://github.com/CommittedTeam/CommitCanvas">CommitCanvas</a> ที่ช่วยให้เรา commit เป็นรูปแบบที่เราตกลงกันในทีมผ่าน ML Model ที่เรียนรู้จาก Git commit history ของเรา</li>
<li><a href="https://apiflask.com/">APIFlask</a> ซึ่งเป็น Framework ที่สมน้ำสมเนื้อกับ FastAPI มาก</li>
<li><a href="https://github.com/direnv/direnv">Direnv</a> ช่วยให้เรา Config environment ตามโปรเจ็คแล้วอ่านตาม directory ในเครื่องเรา</li>
<li><a href="https://github.com/asottile/all-repos">All-repos</a> ช่วยให้เราทำงานกับ multi-repo git ได้ง่ายขึ้นผ่าน batch operation</li>
</ul>
<p><img src="/my-first-pycon-us-experience-2021-online/1-Kisd1i3JBAjDnca3OydxuA_hu_5578c1eea57d74a7.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-Kisd1i3JBAjDnca3OydxuA_hu_e649c05cbe60a770.webp 480w, /my-first-pycon-us-experience-2021-online/1-Kisd1i3JBAjDnca3OydxuA_hu_5578c1eea57d74a7.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="keynote-pythonization-of-healthcare--akshay-sharma">Keynote: Pythonization of Healthcare — Akshay Sharma</h2>
<p>Talk นี้พูดถึง Healthcare industry ที่กำลังเปลี่ยนไปด้วยพลังของ Python ครับซึ่งมีประเด็นสำคัญคือ การ shift paradigm ไปที่ compute first ซึ่งก็มือถือของเราๆ ท่านๆ แทนที่จะใช้ Mainframe ที่มี format ข้อมูลหลากหลายและทำงานด้วยยากครับ ซึ่งมันเกิดขึ้นได้เพราะยุค Pandemic นี้เราแทบจะลบ Geographic Constraint ออกไปได้เพราะทุกคนเข้าถึงโทรศัพท์และอินเตอร์เน็ตแล้ว อีกสิ่งหนึ่งที่ผมชอบมากคือ Concept <a href="https://www.juiceanalytics.com/writing/4-components-of-the-data-fluency-framework">Data Fluency</a> ของการที่ใช้ Jupyter Notebook เป็นตัวกลาง format เดียวในการคุยกันตั้งแต่ data engineer, scientist, finance/operation ไปจนถึง Clinician ครับ</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-SSVR_d1NK5GNVy6T0-_4EQ_hu_8da18e21e63fd19e.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-SSVR_d1NK5GNVy6T0-_4EQ_hu_8892c354d86b61d9.webp 480w, /my-first-pycon-us-experience-2021-online/1-SSVR_d1NK5GNVy6T0-_4EQ_hu_8da18e21e63fd19e.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="packaging-python-in-2021--jeremiah-paige-ucodery">Packaging Python in 2021 — Jeremiah Paige (@ucodery)</h2>
<p>Talk นี้จริงๆ โฟกัสที่ pyproject.toml ซึ่งเป็นมาตรฐานใหม่ของไฟล์โปรเจ็คใน Python แทน setup.py แต่ผมว่าสิ่งที่ผมชอบมากของ Talk นี้คือการที่พาเราไปดูวิวัฒนาการของ Packaging ตั้งแต่ distutils มาจนถึงปัจจุบันครับ เลยทำให้เราเข้าใจมากขึ้นว่าที่มีอยู่ปัจจุบันเนี่ย มันอาจจะไม่ดีที่สุด แต่มันก็แก้ปัญหามาหลายอย่างแล้ว ใน Talk ยังมีคำแนะนำเกี่ยวกับการ Migrate project จาก build tools เก่าๆ มา pyproject.toml อยู่ด้วยครับ</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-aIlfQZzHVWuPL8L4-Lu6ng_hu_62ef4941428ca0ea.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-aIlfQZzHVWuPL8L4-Lu6ng_hu_ea74aa7348adad91.webp 480w, /my-first-pycon-us-experience-2021-online/1-aIlfQZzHVWuPL8L4-Lu6ng_hu_62ef4941428ca0ea.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="python-performance-at-scale--making-python-faster-at-instagram--dino-viehland">Python Performance at Scale — Making Python Faster at Instagram — Dino Viehland</h2>
<p>ผมอยากบอกว่านี่เป็นหนึ่งใน Talk ที่ผมตั้งตารอคอยที่สุดของงานเลยครับ (เพราะผมไม่ได้สมัคร Language Summit ไป) แต่ใน Talk นี้เราได้เห็นเลยว่า Instagram ก็ยังคงไม่เปลี่ยนไปมากจากที่เราเคยฟังใน Talk ปีที่ผ่านๆ มาครับ โดยยังคงเป็น Django รันอยู่บน uWSGI อยู่ครับ Talk นี้มี Technical terms เยอะมากเกี่ยวกับ CPython interpreters แต่เราได้เห็นเลยว่าแต่ละจุดที่ Optimize ไปมันช่วยเพิ่ม Performance ได้กี่ % ซึ่งสิ่งที่น่าสนใจคือ Metrics ที่เค้าใช้วัดคือ RPS (Request per second underload) ครับ​ซึ่งวัดบน Production จริงๆ ด้วย อีกส่วนที่น่าสนใจคือในส่วนที่เค้ายัง Experiment อยู่ครับ ซึ่งผมสนใจมากตรง Static Python ครับ ซึ่งเป็นความพยายามในการทำให้ Python ได้ Performance ที่ดีขึ้นพอๆ กับ MyPyC หรือ Cython แต่ยังคงเขียนด้วย syntax เดิมๆ ของ Python อยู่</p>
<p>พอจบ Talk ผมไป join ห้อง discussion ต่อครับเลยได้รู้รายละเอียดนิดหน่อย เพิ่มขึ้นมาคือ โปรเจ็ค Cinder นี้ใช้คนแค่ 20 คนทำมา 3 ปีครับ และเป้าหมายคือการย้าย computation time ลงไปใน JIT ให้มากที่สุด ใน session มีคนถามถึง HHVM ซึ่งเป็นรัน time ของ Hack ด้วยว่าเคยมีแพลนจะแปลง Python ไป HHVM มั้ย ซึ่งเค้าก็บอกว่า สุดท้ายแล้วมันก็ไม่คุ้มที่จะทำทุกอย่างให้เป็นอย่างเดียวครับ</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-5-If7u4XkaeQXVwah3lYjg_hu_da0b3daf6016105b.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-5-If7u4XkaeQXVwah3lYjg_hu_bbc087b1399c82d8.webp 480w, /my-first-pycon-us-experience-2021-online/1-5-If7u4XkaeQXVwah3lYjg_hu_da0b3daf6016105b.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="gradual-typing-in-practice--maggie-moss">Gradual Typing in Practice — Maggie Moss</h2>
<p>ผมฟัง Talk เกี่ยวกับ Type annotation มาทุกปี แต่ Talk นี้เป็นครั้งแรกที่ผมเห็น <a href="https://pyre-check.org/">Pyre</a> แบบใช้งานจริงๆ ครับ ซึ่งเป็น Type checker จาก Facebook ที่ออกมาซักพักละ ซึ่งการได้เห็นฟีเจอร์อย่าง pyre-upgrade, strict mode, infer ก็ทำให้อยากปรับไปใช้ตัวนี้แทน mypy ที่ใช้มานานอยู่มากแล้วครับ อีกส่วนที่น่าสนใจคือ gradual typing strategy ที่ทีมนี้ใช้อย่างเช่น การมี dashboard ในการ track type coverage, การให้เวลา engineer เพื่อเพิ่ม type โดยเฉพาะ, ​การ on board new engineer ให้คุ้นเคยกับงานที่ใช้ type แต่แรกเลย หรืออย่างในเรื่องของ Metrics ที่ตัว pyre statistics มี built-in มาให้ครับ แล้วเค้าเก็บข้อมูลตัวนี้ลง Dashboard ไว้ดูในทีมทุกวันเลยว่าเพิ่มขึ้นเท่าไรแล้วครับ</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-bYsUhKqyVP8n78ak6_mDcA_hu_b0e631fa95c7a3b2.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-bYsUhKqyVP8n78ak6_mDcA_hu_ef35ccf6009c5ac7.webp 480w, /my-first-pycon-us-experience-2021-online/1-bYsUhKqyVP8n78ak6_mDcA_hu_b0e631fa95c7a3b2.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="unexpected-execution-wild-ways-code-execution-can-occur-in-python--graham-bleaney-ibrahim-mohamed">Unexpected Execution: Wild Ways Code Execution can Occur in Python — Graham Bleaney, Ibrahim Mohamed</h2>
<p>เรียกได้ว่าเป็นเรื่องบังเอิญมากที่ Talk ในวันที่ 2 ผมเข้าของ Facebook / Instagram หมดเลย (ตอนแรกนึกว่าแค่ 2 Talks บนแต่ Talks นี้เดินสุ่มๆ เข้ามา โดย Talk นี้พูดเกี่ยวกับเรื่อง Remote Code Execution (RCE) ครับว่ามันเกิดขึ้นได้ อย่างไรบ้างตั้งแต่ Pickle, Untrusted input (ซึ่งผมเพิ่งรู้ว่า underlying มัน implement eval() อยู่ทำให้ execute code ได้) ไปจนถึง upload file ซึ่งมี <a href="https://github.com/gbleaney/python_security">GitHub repository</a> ที่เค้าทำไว้ให้ลองเล่นพวก Vulnerability พวกนี้ด้วยครับ สำหรับผมได้ key takeaway จาก Talk นี้คืออย่า import untrusted code เด็ดขาดและจงแยก Data กับ Code ออกจากกันให้ชัดเจนครับ</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-45Oa75zlpHV1zrcez10-FQ_hu_79a5b1c5d2fe258f.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-45Oa75zlpHV1zrcez10-FQ_hu_bffcf318592c3b23.webp 480w, /my-first-pycon-us-experience-2021-online/1-45Oa75zlpHV1zrcez10-FQ_hu_79a5b1c5d2fe258f.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="540"
       alt=""
       loading="lazy" decoding="async"></p>
<h2 id="python-steering-council-and-psf-community-address">Python Steering Council and PSF Community Address</h2>
<p>Session สุดท้ายของ Conference Day ครับ ซึ่ง Steering Council มาเล่าให้ฟังหลายๆ เรื่องผมขอสรุปเป็น bullet ละกันเพราะมีหลายเรื่องมาก</p>
<ul>
<li><strong>Long Term plan</strong> — ทาง Steering Council มองในเรื่อง Compatibility concern กับ Maintainability เป็นหลักครับ รองลงมาเป็นเรื่อง Performance ซึ่งก็มีหลายๆ คนทำเรื่องนี้อยู่เช่นทีม PyPy ส่วนในเรื่องการศึกษาก็พยายามที่จะทำให้ Python ยัง easier to access และปรับปรุงคุณภาพ Document และ error message ต่อไปครับ</li>
<li><strong>Short term plan</strong> — คงหนีไม่พ้น Python 3.10 ที่กำลังจะออกเร็วๆ นี้ครับที่เพิ่มหลายๆ เรื่องไม่ว่าจะเป็น Pattern matching, parenthesized context manager, typing/performance improvement, better debugging และ Deprecate distutils ที่อยู่กับ Python มานานครับ สิ่งที่น่าสนใจอีกอย่างคือ Python 3.10 เป็นเวอร์ชั่นแรกที่ Cover PEP มากที่สุดตั้งแต่ release มาด้วยครับ</li>
</ul>
<p>สิ่งที่น่าสนใจอีกอย่างที่มีคนถามคือ ไหนๆ เราก็มี type แล้ว Python เราจะเปลี่ยนไปเป็นภาษา Static มั้ยซึ่ง Steering Council ยังยืนยันว่า “<em>Python</em> จะไม่มีวันเป็น <em>Static Type language</em> ครับ แต่ยังคงเป็น <em>Optional Static Type</em> ต่อไป”</p>
<p><img src="/my-first-pycon-us-experience-2021-online/1-W8WNkFpqW0N6COYUHteYLA_hu_126978112c5b2c2.webp"
       srcset="/my-first-pycon-us-experience-2021-online/1-W8WNkFpqW0N6COYUHteYLA_hu_a36ecafd24a4aec5.webp 480w, /my-first-pycon-us-experience-2021-online/1-W8WNkFpqW0N6COYUHteYLA_hu_126978112c5b2c2.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="551"
       alt=""
       loading="lazy" decoding="async">
<em>ตัวอย่างของ Open networking table ครับ ในห้องนึงก็จะจำกัด 10 หรือ 4 คนแล้วก็ใช้ได้โดยตรงจาก Browser</em></p>
<h1 id="in-summary">In Summary</h1>
<p>ต้องบอกว่าถึงแม้ PyCon US จะจัด Online ทำให้เราเข้าถึงงานได้ง่ายขึ้นจากที่ไหนก็ได้ในโลก แต่ต้องยอมรับว่าพอมันเป็นงาน Online หลายๆ อย่างมันก็ขาดหายไป และสำหรับ Introvert แบบผมนี่ ผมบอกได้เลยครับว่า การที่จะกลั้นใจกดเข้าไป join Open space นี่มันใช้พลังหนักมาก ซึ่งหลายๆ คนน่าจะเข้าใจจาก Zoom fatique กัน แต่ก็เป็นประสบการณ์ที่ดีครับที่ได้คุยกันคนที่อยู่อีกฟากโลกทั้งจากอเมริกาและแคนาดาครับ อีกสิ่งหนึ่งที่ไม่ได้หายไป แต่ลำบากขึ้นคือ Swag ครับ ซึ่งอย่างเสื้อกับสติ๊กเกอร์ก็ต้องกดสั่งแยก ส่วนพวกตาม Sponsor Booth ก็ต้องกรอกฟอร์มครับไม่ได้หยิบง่าย เหมือนแต่ก่อน</p>
<p>ก็หวังว่าประสบการณ์ที่ผมเล่ามานี่ จะมีประโยชน์กับใครก็ตามที่สนใจร่วม Online Conference ต่อๆ ไปนะครับ ซึ่งจากสถานการณ์ COVID-19 ในปัจจุบัน ผมว่าน่าจะอีกนานเลยกว่าเราจะได้กลับไปหา Conference แบบ Physical อีกครั้งครับและสุดท้าย อยากปิดด้วยวิดีโอเดียวกับที่ปิดในงานครับ ผมเชื่อว่าใครได้ดูวิดีโอนี้จะเริ่มเข้าใจว่า Python Community มันพิเศษและแตกต่างจากหลายๆ Tech Community ยังไง ลองดูจากลิ้งค์ข้างล่างได้เลยครับ</p>
<iframe width="200" height="113" src="https://www.youtube.com/embed/4HfZoalB0Cs?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p><em>Article written by:</em> <em><strong>Yothin Muangsommuk</strong></em>*, organizer of PyCon APAC 2021 For more information on* <em><strong>PyCon APAC 2021</strong></em>*, checkout:* <a href="https://th.pycon.org/"><em>https://th.pycon.org/</em></a></p>
<hr>
<p>Original post at: <a href="https://medium.com/pyconth/my-first-pycon-us-experience-2021-online-2731b3cc15fd">https://medium.com/pyconth/my-first-pycon-us-experience-2021-online-2731b3cc15fd</a></p>
]]></content:encoded></item><item><title>Backup Django ง่ายกว่านี้ไม่มีอีกแล้วด้วย django-dbbackup</title><link>https://yothinix-com.pages.dev/django-dbbackup/</link><pubDate>Sun, 17 May 2020 14:29:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/django-dbbackup/</guid><description>&lt;p&gt;ช่วงนี้ผมต้องมาขึ้น Django project ใหม่กับทีมครับ ซึ่งพอขึ้น Project ใหม่ หนึ่งใน Development workflow ที่มาคู่กันคือ การต้องเอา Database จาก Production กลับมาใช้ที่ Local development ให้ได้ เพื่อที่จะ debug ปัญหาหลายๆ อย่างได้กับ Data บน Production หรือ เพื่อความสะดวกสบายในการ Development ครับ&lt;/p&gt;
&lt;p&gt;ทีนี้ที่ผ่านมามันไม่ค่อยมีปัญหาเพราะ Database ผมมักจะใช้ PostgreSQL ซึ่งอาจจะอยู่ใน database Instance ของตัวเอง อยู่บน Container ของตัวเอง ฯลฯ ซึ่งก็ใช้ &lt;code&gt;pg_dump&lt;/code&gt; กับ &lt;code&gt;pg_restore&lt;/code&gt; คู่กันง่ายๆ มาตลอด ไม่มีปัญหายเว้นอัพเกรด PostgreSQL major version ที่ไฟล์ format เปลี่ยนนิดหน่อยก็ตามอัพเกรด client กัน&lt;/p&gt;
&lt;p&gt;ปัญหามันอยู่ที่ Media files ครับ ซึ่งถ้าเลือกได้ ผมจะเลือกใช้ &lt;a href="https://github.com/jschneier/django-storages"&gt;django-storages&lt;/a&gt; เพื่อที่จะ offload ตัว media file ไปเก็บไว้ใน object storage เช่น Amazon s3 หรือ Google Cloud Storage ครับ แต่ใน use case ที่เราเลือกไม่ได้ต้องเก็บไฟล์ลง server เท่านั้น เราจะทำยังไงหละ&lt;/p&gt;</description><content:encoded><![CDATA[<p>ช่วงนี้ผมต้องมาขึ้น Django project ใหม่กับทีมครับ ซึ่งพอขึ้น Project ใหม่ หนึ่งใน Development workflow ที่มาคู่กันคือ การต้องเอา Database จาก Production กลับมาใช้ที่ Local development ให้ได้ เพื่อที่จะ debug ปัญหาหลายๆ อย่างได้กับ Data บน Production หรือ เพื่อความสะดวกสบายในการ Development ครับ</p>
<p>ทีนี้ที่ผ่านมามันไม่ค่อยมีปัญหาเพราะ Database ผมมักจะใช้ PostgreSQL ซึ่งอาจจะอยู่ใน database Instance ของตัวเอง อยู่บน Container ของตัวเอง ฯลฯ ซึ่งก็ใช้ <code>pg_dump</code> กับ <code>pg_restore</code> คู่กันง่ายๆ มาตลอด ไม่มีปัญหายเว้นอัพเกรด PostgreSQL major version ที่ไฟล์ format เปลี่ยนนิดหน่อยก็ตามอัพเกรด client กัน</p>
<p>ปัญหามันอยู่ที่ Media files ครับ ซึ่งถ้าเลือกได้ ผมจะเลือกใช้ <a href="https://github.com/jschneier/django-storages">django-storages</a> เพื่อที่จะ offload ตัว media file ไปเก็บไว้ใน object storage เช่น Amazon s3 หรือ Google Cloud Storage ครับ แต่ใน use case ที่เราเลือกไม่ได้ต้องเก็บไฟล์ลง server เท่านั้น เราจะทำยังไงหละ</p>
<p>พอมี Use case แบบนี้แวบแรกที่ผมคิดออกคือ <code>rsync</code> เลยครับ ง่ายๆ บ้านๆ sync directory ที่ต้องเก็บ Media กลับมาลงใน local แต่ผมตั้งคำถามกับตัวเองว่ามันมีวิธีอื่นมั้ย มันเลยเกิด post นี้ขึ้นนี่แหละครับ</p>
<h2 id="django-database-backup"><strong>Django Database Backup</strong></h2>
<p>ผมค้นไปเจอ <a href="https://django-dbbackup.readthedocs.io/en/stable/index.html">django-dbbackup</a> เพราะคิดว่าจะทำยังไงถึงจะ backup database / media files ได้พร้อมกันเลย ไม่ต้องมานั่งทำทีละอย่าง เรียกได้ว่า รันคำสั่งเดียวปุ๊ปได้ Data พร้อมใช้งานใน local เลย ซึ่งสารภาพว่าแวบแรกก็นึกว่าจะเขียน Ansible playbook ไปเลย แต่ถ้าทีมไม่ได้มี Technical ลึกหละ</p>
<p>ตัว Django Database Backup นี่เป็น Package ที่ไม่ได้ซับซ้อนอะไรเลยครับ ไม่ได้ Reinvent the wheel การ backup ขึ้นมาใหม่ เป็นไอเดียง่ายๆ แค่ dump / restore ไฟล์ อาจจะรวม compresion กับ encryption ขึ้นมานิดหน่อย แต่ไม่ได้สลับซับซ้อนอะไรเลย โดยตัว Package จะเป็น extension app ของ Django ที่ provide management command ต่างๆ มาให้เราทำงานได้ง่ายขึ้นครับ</p>
<p>วิธีลงไม่ยากแค่สั่ง pip install django-dbbackup หรือจะเพิ่ม dependencies ลงใน requirements.txt, Pipfile, pyproject.toml เอาที่สะดวกเลยครับ พอลงเสร็จแล้วมีจุดที่เราต้อง config เบื้องต้นเพิ่มใน Django settings file เรา 2 อย่าง</p>
<p>อย่างแรกเลยคือให้เราเพิ่ม INSTALLED_APPS ชื่อ dbbackup ลงไปครับ ซึ่งจะเอาไว้ตรงไหนก็ได้ order ไม่สำคัญ</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl">  <span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="o">...</span>
</span></span><span class="line"><span class="cl">      <span class="s1">&#39;dbbackup&#39;</span><span class="p">,</span>  <span class="c1"># django-dbbackup</span>
</span></span><span class="line"><span class="cl">  <span class="p">)</span>
</span></span></code></pre></div><p>อย่างที่สองคือ เราต้องเพิ่ม settings เพื่อที่จะบอกว่า Backup เราเนี่ยจะเก็บไว้ที่ไหน​ซึ่งสามารถเก็บไว้ได้ทั้ง Amazon S3, Dropbox, FTP แต่ในเคสง่ายๆ เราเก็บไว้ใน File System ในโปรเจ็คเราก็ได้ครับหน้าตาประมาณนี้</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl">  <span class="n">DBBACKUP_STORAGE</span> <span class="o">=</span> <span class="s1">&#39;django.core.files.storage.FileSystemStorage&#39;</span>
</span></span><span class="line"><span class="cl">  <span class="n">DBBACKUP_STORAGE_OPTIONS</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;location&#39;</span><span class="p">:</span> <span class="s1">&#39;/app/backups&#39;</span><span class="p">}</span>
</span></span></code></pre></div><p>ตรงจุดนี้ระวังนิดนึงนะครับมี bug ใน document ตรง DBBACKUP_STORAGE มันจะชี้ไปที่ <code>dbbackup.storage.filesystem_storage</code> ซึ่งที่ถูกต้องคือ <code>django.core.files.storage.FileSystemStorage</code> ครับ</p>
<h2 id="usage"><strong>Usage</strong></h2>
<p>หลังจากที่เราติดตั้งเสร็จแล้ว config เสร็จแล้วทีนี้เราก็สามารถใช้งาน Django database backup ได้แล้วครับ ซึ่งมันไม่ได้แค่ backup database ตามชื่อ แต่ครอบคลุมไปถึง Media ด้วย</p>
<h3 id="backup--restore-media">Backup / restore Media</h3>
<p>ถ้าเราจะ Backup ตัว Media file เราก็ใช้ management command <code>mediabackup</code> ได้เลยครับตัว output จะออกมาคล้ายๆ ตัวอย่างข้างล่างเลย คือเป็นไฟล์ compress ของ media ใน Django app เราครับ</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python manage.py mediabackup
</span></span><span class="line"><span class="cl">Writing file to 7b23e710c576-2020-05-17-044731.tar
</span></span></code></pre></div><p>ส่วนถ้าเราอยากจะ restore ก็แค่ใช้ command <code>mediarestore</code> ครับ ซึ่งสามารถเลือกไฟล์เองก็ได้ แต่ถ้า structure ของไฟล์ไม่ต่างกันเราสามารถเรียกได้เลยครับ แล้วตัว Django dbbackup มันฉลาดพอจะเลือกไฟล์ล่าสุดมา restore ครับ รวมถึงถ้าไม่มี directory ก็จะสร้างให้หมดเลยด้วย</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python manage.py mediarestore
</span></span><span class="line"><span class="cl">Restoring backup <span class="k">for</span> media files
</span></span><span class="line"><span class="cl">Finding latest backup
</span></span><span class="line"><span class="cl">Restoring: 7b23e710c576-2020-05-17-044843.tar
</span></span><span class="line"><span class="cl">Are you sure you want to <span class="k">continue</span>? <span class="o">[</span>Y/n<span class="o">]</span> Y
</span></span><span class="line"><span class="cl">some_media_path/image1.png uploaded
</span></span><span class="line"><span class="cl">some_media_path/image2.png uploaded
</span></span><span class="line"><span class="cl">some_media_path/image3.png uploaded
</span></span></code></pre></div><h3 id="backup--restore-database">Backup / Restore Database</h3>
<p>ในส่วนของ Backup database จะมีความยุ่งยากกว่า Media นิดนึงตรงที่เราต้องมี client ของ Database ตัวนั้นจริงๆ อยู่ในเครื่องที่เราจะรัน command นี้ด้วยครับเช่น เคสผมใช้ PostgreSQL ก็ต้องมี <code>postgresql-client</code> ในเครื่องก่อน มันถึงจะพาเพื่อนอย่าง <code>pg_dump</code>, <code>pg_restore</code> มาด้วย แต่ข้อควรระวังอีกอย่างคือ ลง postgrsql-client ให้มันตรงกับ version PosgreSQL ที่เราใช้ด้วยนะครับ ในเคสนี้ผมแค่สั่ง <code>apt install postgresql-client-12</code> ก็เรียบร้อยครับ</p>
<p>พอเรามี client ในเครื่องแล้วที่เหลือก็ง่ายเลย แทนที่เราจะต้องมาสั่ง pg_dump ด้วย option ยาวๆ เราก็ใช้ management command <code>dbbackup</code> สั่ง โดยตัว Django dbbackup ก็จะไปดูด database settings</p>
<p>ของเรามา fill ให้ไม่ต้องมาจำเอง</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python <span class="o">[</span>manage.py<span class="o">](</span>http://manage.py/<span class="o">)</span> dbbackup
</span></span><span class="line"><span class="cl">Backing Up Database: postgres
</span></span><span class="line"><span class="cl">Writing file to default-7b23e710c576-2020-05-17-050714.psql
</span></span></code></pre></div><p>ส่วนวิธี restore ก็จะเก่งเหมือน Media restore ที่รู้จักไฟล์ล่าสุดครับ ส่วน command ก็สั้นๆ แค่ <code>dbrestore</code> พอสั่งเสร็จเราก็ได้ database backup มาใช้ละ</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ python manage.py dbrestore
</span></span><span class="line"><span class="cl">Finding latest backup
</span></span><span class="line"><span class="cl">Restoring backup <span class="k">for</span> database <span class="s1">&#39;default&#39;</span> and server <span class="s1">&#39;None&#39;</span>
</span></span><span class="line"><span class="cl">Restoring: default-7b23e710c576-2020-05-17-050714.psql
</span></span><span class="line"><span class="cl">Restore tempfile created: 62.2 KiB
</span></span><span class="line"><span class="cl">Are you sure you want to <span class="k">continue</span>? <span class="o">[</span>Y/n<span class="o">]</span> Y
</span></span></code></pre></div><p>จบแล้วครับ ง่ายๆ แค่นี้เลย จริงๆ ตัว Django dbbackup ยังทำอย่างอื่นได้อีกทั้ง encryption , filename prefix หรือ จะตั้ง limit ให้เก็บแค่กี่ไฟล์ล่าสุดก็ได้ ก็ลองอ่านได้ใน Documentation ครับเขียนไว้ค่อนข้างอ่านง่ายเลย ก็หวังว่าชีวิตจะง่ายขึ้นกันนะครับ หลังจากนี้ 🐍🐮</p>
<h2 id="reference"><strong>Reference</strong></h2>
<ul>
<li><a href="https://github.com/django-dbbackup/django-dbbackup">https://github.com/django-dbbackup/django-dbbackup</a></li>
<li><a href="https://django-dbbackup.readthedocs.io/en/stable/">https://django-dbbackup.readthedocs.io/en/stable/</a></li>
</ul>
]]></content:encoded></item><item><title>10 Python libraries ที่เราชอบในปี 2018</title><link>https://yothinix-com.pages.dev/10-python-libraries-we-like-2018/</link><pubDate>Sat, 29 Dec 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/10-python-libraries-we-like-2018/</guid><description>&lt;p&gt;เป็นธรรมเนียมที่พึ่งสร้างเป็นปีที่สองกันครับว่า เราจะมามองย้อนกลับไปในปี 2018 ที่กำลังจะผ่านพ้นไปว่า Python Libraries ตัวไหนที่เราชอบบ้าง &lt;a href="https://yothinix-com.pages.dev/10-python-libraries-we-like-2017/"&gt;ของปีที่แล้วเราคัดมา 10 Libraries&lt;/a&gt; ปีนี้เราก็จะคัดมาอีก 10 เหมือนกันครับ แต่ลำดับไม่มีผลอะไรนะครับ ไปดูกันเลย&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yothinix-com.pages.dev/10-python-libraries-we-like-2018/0-4sRfrH8NrmrgqQIm_hu_1b3907a1451dd553.webp"
srcset="https://yothinix-com.pages.dev/10-python-libraries-we-like-2018/0-4sRfrH8NrmrgqQIm_hu_8b8e0a7608b29e28.webp 480w, https://yothinix-com.pages.dev/10-python-libraries-we-like-2018/0-4sRfrH8NrmrgqQIm_hu_1b3907a1451dd553.webp 960w"
sizes="(max-width: 960px) 100vw, 960px"
width="960" height="352"
alt=""
loading="lazy" decoding="async"&gt;
&lt;em&gt;Source: &lt;a href="https://github.com/ambv/black"&gt;https://github.com/ambv/black&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h1 id="1-black--the-uncompromising-code-formatter"&gt;\1. Black — The uncompromising code formatter&lt;/h1&gt;
&lt;p&gt;Source: &lt;a href="https://github.com/ambv/black"&gt;https://github.com/ambv/black&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ในสมัยก่อนพอพูดถึง Formatter ของ Python เราจะนึกถึงแค่ &lt;a href="https://github.com/google/yapf"&gt;yapf&lt;/a&gt; เป็นหลัก รองลงมาก็ &lt;a href="https://pypi.org/project/autopep8/"&gt;autopep8&lt;/a&gt; ซึ่งก็มีฐานผู้ใช้ระดับนึง ปีนี้เรามีเจ้าใหม่เข้ามาในตลาดครับ ซึ่งก็คือ Black นี่เอง&lt;/p&gt;
&lt;p&gt;จุดเด่นของ Black คือ just work ครับลงปั๊ปใช้ได้เลย หรือถ้าอยากจะ config ก็ได้นิดหน่อย อีกจุดเด่นที่ทุกคนที่ได้ลองใช้ Black พูดถึงและมีทั้งชอบและไม่ชอบคือใช้ double quotes (“) มากกว่า single quotes (‘) ครับ แต่หลายๆ คนพอใช้แล้วก็ยังพิมพ์ single quotes เหมือนเดิมรวมทั้งผมด้วย แล้วปล่อยให้ Black มันจัดการไปครับ นอกจากนั้นแล้วตัว Black ยัง Optimize ให้ใช้กับ syntax ใหม่ๆ ที่มีใน Python 3.6+ และ stub file สำหรับเขียน type signature ของ function ด้วยครับ&lt;/p&gt;</description><content:encoded><![CDATA[<p>เป็นธรรมเนียมที่พึ่งสร้างเป็นปีที่สองกันครับว่า เราจะมามองย้อนกลับไปในปี 2018 ที่กำลังจะผ่านพ้นไปว่า Python Libraries ตัวไหนที่เราชอบบ้าง <a href="/10-python-libraries-we-like-2017/">ของปีที่แล้วเราคัดมา 10 Libraries</a> ปีนี้เราก็จะคัดมาอีก 10 เหมือนกันครับ แต่ลำดับไม่มีผลอะไรนะครับ ไปดูกันเลย</p>
<p><img src="/10-python-libraries-we-like-2018/0-4sRfrH8NrmrgqQIm_hu_1b3907a1451dd553.webp"
       srcset="/10-python-libraries-we-like-2018/0-4sRfrH8NrmrgqQIm_hu_8b8e0a7608b29e28.webp 480w, /10-python-libraries-we-like-2018/0-4sRfrH8NrmrgqQIm_hu_1b3907a1451dd553.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="352"
       alt=""
       loading="lazy" decoding="async">
<em>Source: <a href="https://github.com/ambv/black">https://github.com/ambv/black</a></em></p>
<h1 id="1-black--the-uncompromising-code-formatter">\1. Black — The uncompromising code formatter</h1>
<p>Source: <a href="https://github.com/ambv/black">https://github.com/ambv/black</a></p>
<p>ในสมัยก่อนพอพูดถึง Formatter ของ Python เราจะนึกถึงแค่ <a href="https://github.com/google/yapf">yapf</a> เป็นหลัก รองลงมาก็ <a href="https://pypi.org/project/autopep8/">autopep8</a> ซึ่งก็มีฐานผู้ใช้ระดับนึง ปีนี้เรามีเจ้าใหม่เข้ามาในตลาดครับ ซึ่งก็คือ Black นี่เอง</p>
<p>จุดเด่นของ Black คือ just work ครับลงปั๊ปใช้ได้เลย หรือถ้าอยากจะ config ก็ได้นิดหน่อย อีกจุดเด่นที่ทุกคนที่ได้ลองใช้ Black พูดถึงและมีทั้งชอบและไม่ชอบคือใช้ double quotes (“) มากกว่า single quotes (‘) ครับ แต่หลายๆ คนพอใช้แล้วก็ยังพิมพ์ single quotes เหมือนเดิมรวมทั้งผมด้วย แล้วปล่อยให้ Black มันจัดการไปครับ นอกจากนั้นแล้วตัว Black ยัง Optimize ให้ใช้กับ syntax ใหม่ๆ ที่มีใน Python 3.6+ และ stub file สำหรับเขียน type signature ของ function ด้วยครับ</p>
<p>ในปีที่ผ่านมาหลายๆ OSS โปรเจ็คได้ adopt Black เป็น codestyle (ล่าสุดก็ <a href="https://hypothesis.readthedocs.io/en/latest/changes.html#v3-83-2">Hypothesis</a> ครับ) สำหรับใครที่ลังเลอยู่ Black ก็มี <a href="https://black.now.sh/">playground</a> ให้ลองเล่นนะครับ เผื่อจะช่วยให้ตัดสินใจง่ายขึ้น</p>
<p><img src="/10-python-libraries-we-like-2018/0-sz-yRrPO0_AGb1up_hu_4e564767bdae3159.webp"
       srcset="/10-python-libraries-we-like-2018/0-sz-yRrPO0_AGb1up_hu_4e564767bdae3159.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="273"
       alt=""
       loading="lazy" decoding="async">
<em>Source: <a href="https://github.com/tonybaloney/wily">https://github.com/tonybaloney/wily</a></em></p>
<h1 id="2-wily--a-command-line-application-for-tracking-reporting-on-complexity-of-python-tests-and-applications">\2. Wily — A command-line application for tracking, reporting on complexity of Python tests and applications</h1>
<p>Source: <a href="https://github.com/tonybaloney/wily">https://github.com/tonybaloney/wily</a></p>
<p>Code complexity เป็นเรื่องหนึ่งที่ถูกหยิบขึ้นมาคุยใน Code Review บ่อยครับ แต่หลายๆ ครั้งเราไม่ค่อยมี proof เท่าไร และมักจะเป็นความรู้สึกมากกว่า Wily จะเข้ามาช่วยเราแก้ปัญหาในเรื่องนี้ครับ</p>
<p>Wily เป็น Library ที่ช่วยเราอ่าน Complexity ของ Code แล้วสร้าง report ให้เราครับ ความเจ๋งคือมันสร้าง report ได้เยอะมากตั้งแต่ command line output ยัน html graph เลยครับ โดย Metric ที่ Wily ดูมีตั้งแต่ Line of code, Cyclomatic complexity ไปจนถึง Maintainability index เลยครับ</p>
<p>ก่อนหน้านี้มี Library ที่วัด Metric code อยู่ครับคือ <a href="https://github.com/rubik/radon">Radon</a> กับ <a href="https://github.com/klen/pylama">pylama</a> แต่ปฏิเสธไม่ได้จริงๆ ว่า report กับ Statistic feature ของ Wily นี่มัน Game changer จริงๆ</p>
<p><img src="/10-python-libraries-we-like-2018/0-eLyd8mkI5goeHAh8.gif" alt="" loading="lazy">
<em>source: <a href="https://github.com/benfred/py-spy">https://github.com/benfred/py-spy</a></em></p>
<h1 id="3-py-spy--a-sampling-profiler-for-python-program">\3. py-spy — A sampling profiler for Python program</h1>
<p>Source: <a href="https://github.com/benfred/py-spy">https://github.com/benfred/py-spy</a></p>
<p>ปัญหา Optimization เป็นปัญหานึงที่เราชาว Developer ต้องเจอกันเป็นประจำใช่มั้ยครับ แต่ก่อนเราจะ Optimize อะไรซักอย่างเราต้อง Measure มันให้ได้ก่อน ซึ่งวิธีการ Measure ก็มีหลายแบบโดยอาจจะไปแปะๆ log time เอาไว้ แต่ถ้ามันช้าใน Production หละการจะไปแปะๆ log time เอาไว้มันก็ทำไม่ได้เลยใช่มั้ยครับ นั่นแหละครับคือสิ่งที่ py-spy มาแก้ให้เรา</p>
<p>py-spy ก็เป็น Profiler อีกตัวนึงครับ ความเจ๋งของมันก็คือ เราไม่ต้องแก้ code อะไรเลยเราสามารถจะ profiling ตัว Python process ที่กำลังรันอยู่หรือจะรัน script ผ่าน py-spy ก็ได้ครับ ซึ่งตัว py-spy จะ provide interface คล้ายๆ กับ top ที่เราคุ้นเคยกันเพื่อแสดงว่า function/method ไหนที่กินเวลาเรามากที่สุดครับ</p>
<p><img src="/10-python-libraries-we-like-2018/0-bMcrNggxTTe8Aed_hu_ddb600bd00d6a190.webp"
       srcset="/10-python-libraries-we-like-2018/0-bMcrNggxTTe8Aed_hu_ddb600bd00d6a190.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="145"
       alt=""
       loading="lazy" decoding="async">
<em>Source: <a href="https://itsdangerous.palletsprojects.com/en/1.1.x/">https://itsdangerous.palletsprojects.com/en/1.1.x/</a></em></p>
<h1 id="4-itsdangerous--various-helpers-to-pass-trusted-data-to-untrusted-environments-and-back">\4. itsdangerous — Various helpers to pass trusted data to untrusted environments and back.</h1>
<p>Source: <a href="https://github.com/pallets/itsdangerous">https://github.com/pallets/itsdangerous</a></p>
<p>โลกนี้อยู่ยากครับ ยิ่งต้องส่งข้อมูลไปมาผ่าน network ยิ่งต้องสันนิษฐานว่ามีโอกาสที่จะมีคนมาเปิดข้อมูล เลยทำให้เราต้องหาวิธีที่จะป้องกันไม่ให้คนเปิดข้อมูลสำคัญๆ นั้นได้ซึ่งส่วนใหญ่ก็เข้ารหัสกัน แต่จะทำยังไงก่อนหน้านี้ถ้าต้องทำอะไรแนวๆ นี้เราก็จะ implement เองซะส่วนใหญ่ครับจาก tools ที่ standard library มีให้เอามาประกอบๆ กัน แต่ตอนนี้เรามีคนทำให้แล้วครับ</p>
<p><em>itsdangerous</em> เป็น set ของ utils ที่ช่วยเราเข้า/ถอดรหัสข้อมูลที่ sensitive ครับโดยใช้ HMAC / SHA-512 เป็นตัว sign message ของเรา ตัว library ได้แรงบันดาลใจมาจาก Django’s signing module เพราะฉะนั้น API เลยค่อนข้างจะคล้ายๆ กันมากครับ นอกจากนั้นแล้วยังรองรับมาตรฐาน JSON Web Signature ด้วยครับ</p>
<p><img src="/10-python-libraries-we-like-2018/0-LmkeQwQ-Hl4KW5LR.gif" alt="" loading="lazy">
<em>Source: <a href="https://github.com/sdispater/poetry">https://github.com/sdispater/poetry</a></em></p>
<h1 id="5-poetry--dependency-management-for-python">\5. Poetry — Dependency Management for Python</h1>
<p>Source: <a href="https://github.com/sdispater/poetry">https://github.com/sdispater/poetry</a></p>
<p>ปีนี้ถ้าจะไม่พูดถึง Poetry ก็เหมือนจะขาดอะไรไป อย่างหลังจากปีที่แล้ว pipenv ได้ครองตลาดไปและ PyPI แนะนำว่าเป็น Package management ที่ควรใช้ แต่สำหรับคนที่ใช้ pipenv มาซักระยะจะเจอปัญหาที่สำคัญอย่างนึงคือ มันช้าครับ ตอนสร้าง Lockfile ค่อนข้างจะช้ามาก แต่นอกจากปัญหาฝั่ง user แล้วในส่วนของ pipenv เองนั้นก็ค่อนข้างจะซับซ้อนขึ้นเรื่อยๆ จน scale ยากครับ ผู้ท้าชิงตำแหน่งนี้ของปีนี้คือ Poetry ครับ</p>
<p>Poetry เห็นข้อเสียหลายๆ อย่างของ pipenv และนำเสนอแนวทางใหม่ในการจัดการ dependencies ครับ โดย Poetry เลือกที่จะใช้ pyproject.toml ตามมาตรฐาน <a href="https://www.python.org/dev/peps/pep-0518/">PEP 518</a> เป็นไฟล์หลักและมี poetry.lock เพิ่มขึ้นมาครับ ตัว Interface CLI นอกจาก add / install / update / remove มาตรฐานแล้ว ก็ยัง provide interface สำหรับจัดการ package ขึ้น PyPI ด้วยครับ build หรือ publish หรือสร้าง virtualenv ให้สำหรับ local environment ก็มีครับและที่สำคัญที่สุด generate lock ไฟล์เร็วมาก</p>
<p>ถ้าใครใช้ pipenv แล้วรู้สึกเหนื่อยๆ อืดๆ ลองเปลี่ยนมาใช้ poetry ดูครับโลกจะเปลี่ยนไปมากเลย</p>
<p><img src="/10-python-libraries-we-like-2018/0-i7n7_S4BnZz-kKHi_hu_ba072f1bcbe3c53e.webp"
       srcset="/10-python-libraries-we-like-2018/0-i7n7_S4BnZz-kKHi_hu_441ce97aef52e931.webp 480w, /10-python-libraries-we-like-2018/0-i7n7_S4BnZz-kKHi_hu_ba072f1bcbe3c53e.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="320"
       alt=""
       loading="lazy" decoding="async">
<em>Source: <a href="https://github.com/kennethreitz/responder">https://github.com/kennethreitz/responder</a></em></p>
<h1 id="6-responder--a-familiar-http-service-framework-for-python">\6. Responder — a familiar HTTP Service Framework for Python</h1>
<p>Source: <a href="https://python-responder.org/en/latest/">https://python-responder.org/en/latest/</a></p>
<p>หลังจากปีที่แล้ว Kenneth Reitz ได้ทำให้โลกรู้จักกับ pipenv ไปแล้ว ปีนี้เค้ากลับมากับ responder ครับ (และ <a href="https://github.com/kennethreitz/bruce-operator">Bruce</a> ที่ค่อยๆ เงียบหายไป)</p>
<p>ตัว Responder ดึงจุดเด่นจาก Framework อื่นมาเช่น Route แบบ Flask, Mutate Request/Response cycle แบบ Falcon, รองรับ WSGI interface และ ASGI interface ผ่าน Starlette, รองรับ graphQL ผ่าน graphene, รองรับ OpenAPI Schema ฯลฯ เรียกได้ว่า Interface สมัยใหม่ของ webservice แทบจะรองรับหมดแล้วครับสำหรับ Framework ตัวนี้</p>
<p><img src="/10-python-libraries-we-like-2018/1-RaQcslVeacs_rs4GNiBzQg_hu_eab73c3f6a967dd3.webp"
       srcset="/10-python-libraries-we-like-2018/1-RaQcslVeacs_rs4GNiBzQg_hu_eab73c3f6a967dd3.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="180"
       alt=""
       loading="lazy" decoding="async"></p>
<h1 id="7-cursive_re--readable-regular-expressions-for-python-36-and-up">\7. Cursive_re — Readable regular expressions for Python 3.6 and up.</h1>
<p>Source: <a href="https://github.com/Bogdanp/cursive_re">https://github.com/Bogdanp/cursive_re</a></p>
<p>เขียน Regular Expression เป็นเรื่องยากครับ จะเขียนทีก็ต้องมาเปิด Document ทีว่าเขียนยังไง บางทีขี้เกียจเขียนก็ search หาเอาก็มี ปีนี้ผมผ่านไปเจอ cursive_re ครับและจะทำให้ชีวิตการเขียน Regular expression ของเราง่ายขึ้น</p>
<p>ตัว cursive_re จะแทนที่ Regular Expression syntax เราด้วย set ของ utils function ที่เราสามารถจะ compose ออกมาเป็น regular expression ได้ครับ ก็ช่วยให้เขียน pattern matching ง่ายขึ้นนิดหน่อย</p>
<p><img src="/10-python-libraries-we-like-2018/0-97TvORq1UOZd6Gkb_hu_70133c458486b337.webp"
       srcset="/10-python-libraries-we-like-2018/0-97TvORq1UOZd6Gkb_hu_70133c458486b337.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="142"
       alt=""
       loading="lazy" decoding="async">
<em>Source: <a href="https://github.com/Delgan/loguru">https://github.com/Delgan/loguru</a></em></p>
<h1 id="8-loguru--python-logging-made-stupidly-simple">\8. Loguru — Python logging made (stupidly) simple</h1>
<p>Source: <a href="https://github.com/Delgan/loguru">https://github.com/Delgan/loguru</a></p>
<p>หลายๆ ครั้งใน Program เราต้องมีการใส่ log ไว้ใช่มั้ยครับ จุดประสงค์หลักคือเพื่อให้การ debug หรือ monitor ภายหลังสะดวกขึ้น ซึ่งตัว Python เองก็มี Standard library — Logging ไว้ให้อยู่แล้ว แต่โดยตัวมันเองถ้าไม่ config อะไรเลยก็ทำงานไม่ค่อยต่างจาก print() ฟังก์ชั่นเท่าไร</p>
<p>ตัว Loguru เป็น utils เล็กๆ ที่ provide interface ที่เราจะพ่น Log ไว้ให้ผ่าน logger function ที่เราเอาไปแปะไว้ใน function / class method ที่ต้องการครับ โดยตัว loguru จะสร้าง default format มาให้ out of the box เลยซึ่งจะเพิ่ม วันเวลา และ function ที่ execute ออกมาให้ด้วยนอกจาก message ครับ แต่ที่ซื้อผมได้มากที่สุดนี่คือมันมีสีนี่แหละทำให้ log มันน่าอ่านขึ้นมากครับ นอกจากนั้นแล้วตัว exception มันยังสามารถเปิดให้ catch value ของ variable ไว้ได้ด้วยครับ มีประโยชน์มากในการ debug ต่อไป</p>
<p><img src="/10-python-libraries-we-like-2018/0-BZkqmaRnkL6T2dDw_hu_b1b5c915f9d9e0e9.webp"
       srcset="/10-python-libraries-we-like-2018/0-BZkqmaRnkL6T2dDw_hu_b1b5c915f9d9e0e9.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="241"
       alt=""
       loading="lazy" decoding="async">
<em>Source: <a href="https://pyre-check.org/">https://pyre-check.org/</a></em></p>
<h1 id="9-pyre--a-performant-type-checker-for-python-3">\9. Pyre — A performant type-checker for Python 3</h1>
<p>Source: <a href="https://pyre-check.org/">https://pyre-check.org/</a></p>
<p>โลกของ Typing ใน Python ก็ยังมีพัฒนาการเรื่อยๆ ครับ ปีที่แล้วเราเจอ MonkeyType จาก Instagram ที่ช่วย generate type signature ให้เราโดยที่เราไม่ต้องไปไล่เขียนทุกไฟล์เอง ในปีนี้เรามี Pyre จาก Facebook (ซึ่งน่าจะมาจากทีมเดียวกัน) และมันน่าสนใจมากเลยทีเดียว</p>
<p>Pyre เป็น Type checker เช่นเดียวกับ mypy ครับ ซึ่งทางทีมโฆษณาไว้ว่าเร็วกว่า mypy มากๆ เพราะมันจะเช็คแค่ dependencies ที่เกี่ยวกับโค้ดที่แก้ นอกจากนั้นแล้วยังรองรับ <a href="https://github.com/facebook/watchman">Watchman</a> ซึ่งเป็น file watcher ที่ Facebook พัฒนาขึ้นทำให้เราแทบจะ automate การรัน type checker ได้เลย</p>
<p><img src="/10-python-libraries-we-like-2018/1-0oJ-HJyA5Pkl8v6NeMXG0Q_hu_a853fbe2f270ecf0.webp"
       srcset="/10-python-libraries-we-like-2018/1-0oJ-HJyA5Pkl8v6NeMXG0Q_hu_b3307ce6d7367b7c.webp 480w, /10-python-libraries-we-like-2018/1-0oJ-HJyA5Pkl8v6NeMXG0Q_hu_68254ad8cf9c7bc8.webp 960w, /10-python-libraries-we-like-2018/1-0oJ-HJyA5Pkl8v6NeMXG0Q_hu_a853fbe2f270ecf0.webp 1440w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="1440" height="921"
       alt=""
       loading="lazy" decoding="async"></p>
<h1 id="10-responses--a-utility-for-mocking-out-the-python-requests-library">\10. Responses — A utility for mocking out the Python Requests library</h1>
<p>Source: <a href="https://github.com/getsentry/responses">https://github.com/getsentry/responses</a></p>
<p>Responses อาจจะไม่ใช้ Library ที่เกิดในปีนี้ แต่เป็น Library ที่เราค้นพบในปีนี้ที่เปลี่ยนวิธีการเขียนเทสของทีมไปเลย ซึ่งก่อนหน้านี้เราก็เคยเขียนบล็อกอธิบายความดีงามของมันไปแล้ว แต่ถ้าใครยังไม่เคยอ่านก็ตามไปที่ลิ้งข้างล่างเลยครับ</p>
<blockquote>
<p><a href="/mock-python-request-with-responses/">Mock requests แบบสวยๆ ด้วย responses</a>
สิ่งหนึ่งที่เราเจอไม่ว่าจะช้าหรือเร็วคือ เมื่อเขียน Python ไปซักพักเราต้องยุ่งกับการยิง HTTP request ไปหา service ข้างนอก ซึ่ง Library ที่นิยมที่สุดในการทำสิ่งนี้ใน Python ก็คงหนีไม่พ้น requests นะครับ สมมติเรามีฟังก์
— Yothinix, Yothin Muangsommuk</p>
</blockquote>
<h1 id="worth-mentioning">Worth mentioning</h1>
<p>ยังมี Package อีกหลายตัวครับที่เราชอบ แต่เราจะไม่ลงรายละเอียดมากก็จะขอ List ไว้ตรงนี้ละกันครับ</p>
<ul>
<li>ปีที่ผ่านมานอกจาก Responder แล้วยังมี API Framework เกิดขึ้นมาอีกหลายตัวครับ ที่อาศัย async ในการเพิ่มความเร็ว service ซึ่งมีสองสามตัวที่น่าสนใจมากที่เกิดขึ้นในปีนี้คือ <a href="https://moltenframework.com/">molten</a> กับ <a href="https://vibora.io/">Vibora</a> ครับ และที่ไม่พูดถึงไม่ได้เลยคือ <a href="https://github.com/encode/starlette">Starlette</a> ครับ</li>
<li>จะเห็นว่า Trend package ที่ชอบปีนี้ส่วนใหญ่มาในแนว utils เล็กๆ ซึ่งช่วยให้งานใหญ่ๆ เราทำงานง่ายขึ้น มีอีกหลายตัวที่ผมคัดมาแต่ไม่ได้พูดถึงเพราะซ้ำแนวกัน อย่างเช่น <a href="https://github.com/BNMetrics/logme">Logme</a> ที่เอาไว้ใช้แทน logger แต่ก็แพ้ความสามารถของ <em>Loguru</em> ไป เป็นต้น</li>
<li><a href="https://github.com/santinic/pampy">Pampy</a> — เป็น Library ไว้ทำ Pattern matching อันนี้เพิ่งออกมาได้ไม่กี่นาน แต่ดูดีเลยทีเดียว มีเก็บไว้ในคลังเอาไว้แก้โจทย์ algorithm ได้</li>
</ul>
<hr>
<p>Original post at: <a href="https://yothinix.medium.com/10-python-libraries-%E0%B8%97%E0%B8%B5%E0%B9%88%E0%B9%80%E0%B8%A3%E0%B8%B2%E0%B8%8A%E0%B8%AD%E0%B8%9A%E0%B9%83%E0%B8%99%E0%B8%9B%E0%B8%B5-2018-2b003ada90d4">https://yothinix.medium.com/10-python-libraries-ที่เราชอบในปี-2018-2b003ada90d4</a></p>
]]></content:encoded></item><item><title>PEP 8016 and the future of Python govenance</title><link>https://yothinix-com.pages.dev/pep-8016-and-the-future-of-python-govenance/</link><pubDate>Wed, 19 Dec 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/pep-8016-and-the-future-of-python-govenance/</guid><description>&lt;p&gt;อย่างที่ทุกคนรู้นะครับว่า Guido ได้ถอดตัวออกจากการเป็น BDFL Role ที่เป็นมาอย่างยาวนานในช่วงกลางปีที่ผ่านมา แล้วการออกนั้นถึงแม้จะไม่ได้ effect กับ user อย่างเราๆ ท่านๆ แต่มีผลมากกับ Core developer ที่คอยดูแล CPython กับ Python Interpreter อยู่ครับ&lt;/p&gt;
&lt;p&gt;ด้วยเหตุนี้เองประมาณเดือนสิงหาคมที่ผ่านมาทาง Core Dev หลายๆ คนจึงช่วยๆ กันร่างมาตรฐาน &lt;em&gt;PEP 8001 — Python Governance Voting process&lt;/em&gt; ขึ้นมาเป็นอันดับแรกครับ ซึ่งจะพูดถึงวิธีการ vote มาตรฐาน Governance ก่อน โดยจะเปิดให้ Core dev 94 คนเป็นคน vote เพื่อเลือกมาตรฐาน Governance model สำหรับอนาคตต่อไป ในระหว่างนั้นก็ได้มี Core dev หลายๆ คนเสนอมาตรฐานหลายๆ มาตรฐานขึ้นมาหลายๆ ตัวครับ&lt;/p&gt;
&lt;p&gt;จนกระทั่งเดือนธันวาคมระหว่างวันที่ 1–16 จะเป็นช่วงเวลาที่คณะกรรมการการเลือกตั้งเปิดให้โหวตมาตรฐานแต่ละตัวที่มีคนเสนอมา จากที่ติดตามใน twitter นี่บอกได้เลยครับว่า หลายๆ Core dev รอกันจนวันสุดท้ายถึงตัดสินใจ และปิดโหวตในวันที่ 17 ที่ผ่านมานี่เองครับและมาตรฐานที่ได้รับเลือกคือ &lt;em&gt;PEP8016 — The Steering Council Model&lt;/em&gt; ครับและเราจะไปดูรายละเอียดของมาตรฐานตัวนี้กันใน blog นี้ครับ&lt;/p&gt;</description><content:encoded><![CDATA[<p>อย่างที่ทุกคนรู้นะครับว่า Guido ได้ถอดตัวออกจากการเป็น BDFL Role ที่เป็นมาอย่างยาวนานในช่วงกลางปีที่ผ่านมา แล้วการออกนั้นถึงแม้จะไม่ได้ effect กับ user อย่างเราๆ ท่านๆ แต่มีผลมากกับ Core developer ที่คอยดูแล CPython กับ Python Interpreter อยู่ครับ</p>
<p>ด้วยเหตุนี้เองประมาณเดือนสิงหาคมที่ผ่านมาทาง Core Dev หลายๆ คนจึงช่วยๆ กันร่างมาตรฐาน <em>PEP 8001 — Python Governance Voting process</em> ขึ้นมาเป็นอันดับแรกครับ ซึ่งจะพูดถึงวิธีการ vote มาตรฐาน Governance ก่อน โดยจะเปิดให้ Core dev 94 คนเป็นคน vote เพื่อเลือกมาตรฐาน Governance model สำหรับอนาคตต่อไป ในระหว่างนั้นก็ได้มี Core dev หลายๆ คนเสนอมาตรฐานหลายๆ มาตรฐานขึ้นมาหลายๆ ตัวครับ</p>
<p>จนกระทั่งเดือนธันวาคมระหว่างวันที่ 1–16 จะเป็นช่วงเวลาที่คณะกรรมการการเลือกตั้งเปิดให้โหวตมาตรฐานแต่ละตัวที่มีคนเสนอมา จากที่ติดตามใน twitter นี่บอกได้เลยครับว่า หลายๆ Core dev รอกันจนวันสุดท้ายถึงตัดสินใจ และปิดโหวตในวันที่ 17 ที่ผ่านมานี่เองครับและมาตรฐานที่ได้รับเลือกคือ <em>PEP8016 — The Steering Council Model</em> ครับและเราจะไปดูรายละเอียดของมาตรฐานตัวนี้กันใน blog นี้ครับ</p>
<h1 id="pep-8016--the-steering-council-model">PEP 8016 — The Steering Council Model</h1>
<p>หลักการคร่าวๆ ของ PEP8016 คือถึงแม้ Steering council จะมีอำนาจที่กว้างขวางมาก แต่ก็สนับสนุนให้ใช้อำนาจให้น้อยที่สุดเท่าที่จะเป็นไปได้ และแทนที่จะใช้อำนาจนั้นในการตัดสินใจแทน community ให้เลือกที่จะสร้าง process ที่จะกำหนดมาตรฐานต่อๆ ไป นอกจากนั้นแล้วยังส่งเสริมให้แบ่งการตัดสินใจในมาตรฐานเรื่องใหญ่ๆ ให้เป็นเรื่องเล็กๆ ที่จะสามารถตัดสินใจได้แยกจากกันได้</p>
<p>โดยหัวใจหลักของ The Steering Council Model แบ่งออกเป็น 4 ข้อคือ<br>
* Be boring<br>
* Be simple<br>
* Be comprehensive<br>
* Be flexible and light-weight</p>
<p>ทีนี้คำถามต่อไปก็คือ ใครจะมาเป็น The Steering council นี้ ใน PEP8016 ระบุไว้ว่า ต้องมี 5 committee ครับ โดยมีหน้าที่ดังนี้ครับ<br>
* รักษาคุณภาพและความเสถียรของ Python language กับ Python interpreter<br>
* ส่งเสริมให้การ contribute เข้าถึงได้ง่ายและยั่งยืน<br>
* รักษาความสัมพันธ์ระหว่าง core team กับ PSF<br>
* วางมาตรฐานการตัดสินใจของ PEP ในอนาคต<br>
* หาความเห็นพ้องร่วมกันระหว่าง contributer กับ core team<br>
* เป็น Court of final appeal ในกรณีที่การตัดสินใจด้วยวิธีอื่นๆ ไม่เวิร์คแล้ว</p>
<p>จุดที่น่าสนใจอีกจุดหนึ่งที่ผมเห็นในมาตรฐานนี้คือการเลือกตัว Coucil ครับ ซึ่ง ใครสามารถเสนอตัวเองขึ้นมาหรือ core dev เป็นคนเสนอขึ้นมาครับ นอกจากนั้นแล้วพูดถึงเรื่อง Conflict of interest ซึ่งเป็นการป้องกันบริษัทใดๆ nominate การตัดสินใจของ Council ครับโดย สามารถให้สมาชิกของ Council มาจากบริษัทเดียวกันได้มากที่สุด 2 คน ถ้าตอนเลือก council ได้ top 5 แล้ว 3 คนมาจากบริษัทเดียวกันคนที่อยู่อันดับ 3 จากบริษัทเดียวกันจะถูกปัดตกแล้วอันดับ 6 จะถูกเลื่อนขึ้นมาครับ</p>
<p>ตัวมาตรฐาน PEP 8016 ยังไม่หมดแค่นี้นะครับ ยังมีการพูดถึงการให้ออกจาก council ในกรณีต่างๆ รวมถึงบทบาทของ Core team ด้วย ใครสนใจศึกษาเพิ่มเติมไปตามได้ตามลิ้งค์ข้างล่างเลยครับ</p>
<h1 id="reference">Reference</h1>
<p><a href="https://discuss.python.org/t/python-governance-vote-december-2018-results/546">https://discuss.python.org/t/python-governance-vote-december-2018-results/546</a><br>
<a href="https://www.python.org/dev/peps/pep-8016/">https://www.python.org/dev/peps/pep-8016/</a></p>
<hr>
<p>Original post at: <a href="https://medium.com/pythonbycow/pep-8016-and-the-future-of-python-govenance-dabd2362dd42">https://medium.com/pythonbycow/pep-8016-and-the-future-of-python-govenance-dabd2362dd42</a></p>
]]></content:encoded></item><item><title>เขียนงูให้วัวกลัวรายสัปดาห์ ฉบับที่ 2</title><link>https://yothinix-com.pages.dev/python-weekly-2/</link><pubDate>Thu, 27 Sep 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/python-weekly-2/</guid><description>&lt;h2 id="ขาวประจำสปดาห"&gt;ข่าวประจำสัปดาห์&lt;/h2&gt;
&lt;h2 id="dropbox-complete-migrate-to-python-3"&gt;Dropbox complete migrate to Python 3&lt;/h2&gt;
&lt;p&gt;เวลานี้คงไม่มีใครไม่รู้จัก Dropbox นะครับ แต่อาจจะมีคนไม่รู้ว่า Dropbox เป็นหนึ่งในบริษัทที่ใช้ Python ใหญ่ที่สุดในโลก เฉพาะโค้ดของตัว Application Dropbox นี่ก็เกิน 1 ล้านบรรทัดแล้วครับ&lt;/p&gt;
&lt;p&gt;แต่ว่าถึงจะใช้ Python ใหญ่ที่สุดในโลกโค้ดของที่นั่นก็ยังเป็น Python 2 อยู่ครับ ซึ่งทาง Dropbox เองก็วางแผน Migrate มาตั้งแต่ปี 2015 แล้ว จนถึงวันนี้ ถ้าใครใช้ Application dropbox เวอร์ชั่นล่าสุด ตัวโค้ดที่รันอยู่ข้างล่างก็มีพื้นฐานจาก Python 3.5 เวอร์ชั่นพิเศษแล้วครับ ซึ่งทางบล็อกนี้อธิบายขั้นตอนการ Roll out ตัวโค้ดจาก Python 2.7 -&amp;gt; Python 3 และปัญหาที่เจอคร่าวๆ ครับ&lt;/p&gt;
&lt;p&gt;นอกจากนั้นแล้ว บล็อกนี้เป็นหนึ่งในซีรีย์บล็อกที่จะตามมาอีกหลายบล็อกจาก Dropbox เกี่ยวกับการ Migrate ไปใช้ Python 3 ก็คอยติดตามกันต่อไปได้ครับ&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://dropbox.tech/application/how-we-rolled-out-one-of-the-largest-python-3-migrations-ever"&gt;How we rolled out one of the largest Python 3 migrations ever&lt;/a&gt;
— Dropbox, Max Bélanger&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="ขาวประจำสปดาห">ข่าวประจำสัปดาห์</h2>
<h2 id="dropbox-complete-migrate-to-python-3">Dropbox complete migrate to Python 3</h2>
<p>เวลานี้คงไม่มีใครไม่รู้จัก Dropbox นะครับ แต่อาจจะมีคนไม่รู้ว่า Dropbox เป็นหนึ่งในบริษัทที่ใช้ Python ใหญ่ที่สุดในโลก เฉพาะโค้ดของตัว Application Dropbox นี่ก็เกิน 1 ล้านบรรทัดแล้วครับ</p>
<p>แต่ว่าถึงจะใช้ Python ใหญ่ที่สุดในโลกโค้ดของที่นั่นก็ยังเป็น Python 2 อยู่ครับ ซึ่งทาง Dropbox เองก็วางแผน Migrate มาตั้งแต่ปี 2015 แล้ว จนถึงวันนี้ ถ้าใครใช้ Application dropbox เวอร์ชั่นล่าสุด ตัวโค้ดที่รันอยู่ข้างล่างก็มีพื้นฐานจาก Python 3.5 เวอร์ชั่นพิเศษแล้วครับ ซึ่งทางบล็อกนี้อธิบายขั้นตอนการ Roll out ตัวโค้ดจาก Python 2.7 -&gt; Python 3 และปัญหาที่เจอคร่าวๆ ครับ</p>
<p>นอกจากนั้นแล้ว บล็อกนี้เป็นหนึ่งในซีรีย์บล็อกที่จะตามมาอีกหลายบล็อกจาก Dropbox เกี่ยวกับการ Migrate ไปใช้ Python 3 ก็คอยติดตามกันต่อไปได้ครับ</p>
<blockquote>
<p><a href="https://dropbox.tech/application/how-we-rolled-out-one-of-the-largest-python-3-migrations-ever">How we rolled out one of the largest Python 3 migrations ever</a>
— Dropbox, Max Bélanger</p>
</blockquote>
<h1 id="the-state-of-developer-ecosystem-survey-in-2018">The State of Developer Ecosystem Survey in 2018</h1>
<p>Poll ประจำปีของทาง Jetbrains นะครับ ในส่วนของ Python ปีนี้การใช้งาน Python3 เกิน 75% ของทั้งหมดแล้วครับ และงานที่ใช้ภาษา Python อันดับหนึ่งเลยคือ Data analysis ตามมาด้วย Web Development และ Machine Learning ตามลำดับ</p>
<p>ในส่วนของ Library ที่ใช้งานมากที่สุดจะเป็นเซ็ต Data Science อยู่อันดับหนึ่งเลยครับ ซึ่งประกอบด้วย NumPy, matplotlib, SciPy และ Panda อันดับต่อมาคือ Django, Flask และ Requests ตามลำดับครับ</p>
<blockquote>
<p><a href="https://www.jetbrains.com/research/devecosystem-2018/python/">Python in 2018 - The State of Developer Ecosystem by JetBrains</a>
Over 1400+ developers share their insights on modern Python programming. Keep up with the most relevant technologies and frameworks in this infographic!
— JetBrains</p>
</blockquote>
<h1 id="more-coverage-on-cpython-core-developer-sprint-2018">More coverage on CPython Core Developer Sprint 2018</h1>
<p>ถ้าใครติดตามเขียนงูให้วัวกลัวรายสัปดาห์ ของสัปดาห์ที่แล้วจะเห็นว่าเราพูดถึงเรื่อง Core Developer Sprint เยอะหน่อย ซึ่งสัปดาห์นี้ก็มีบล็อกที่เกี่ยวข้องออกมาถึง 3 บล็อกเลยครับ ถ้าใครสนใจเกี่ยวกับการตัดสินใจเกี่ยวกับอนาคตภาษาหรือเรื่อง Implementation Detail ของภาษาก็น่าติดตามมากเลยครับ</p>
<p>บล็อกแรกเป็น Part 2 ของคุณ Mariatta นะครับ ตอนนี้เน้นพูดถึง PEP581, Contributor License Agreement และ f-string issues ครับ</p>
<blockquote>
<p><a href="https://mariatta.ca/core-sprint-2018-part-2.html">Python Core Sprint 2018: Part Two</a>
Read up on Part one first. Here are additional discussions and projects that I got involved with during the sprint. PEP 581 PEP 581 is a PEP I wrote about using GitHub issues instead of Roundup as CPython’s issue tracker. During the sprint, I discussed this topic mainly with Ezio …
— mariatta.ca, Mariatta</p>
</blockquote>
<p>บล็อกที่สองเป็นของทาง Python Software Foundation เองครับ จะพูดถึงภาพรวมของ Core Developer Sprint ครับ</p>
<blockquote>
<p><a href="https://pyfound.blogspot.com/2018/09/cpython-core-developer-sprint-2018.html">CPython Core Developer Sprint 2018</a>
This September, twenty-nine core committers arrived at Microsoft’s main campus in Redmond, Washington, USA for the now-annual core developer&hellip;
— Ewa Jodlowska</p>
</blockquote>
<p>บล็อกสุดท้ายเป็นของคุณ <em>Neil Schemenauer</em> ตัวนี้ค่อนข้างจะลงลึกไปในเรื่อง Implementation Detail ของ CPython ครับว่าจะทำยังไงให้ Python 3.8 จะเร็วขึ้นได้มากกว่าเดิม</p>
<blockquote>
<p><a href="http://python.ca/nas/python/core_sprints/2018.html">Python Core Developer Sprint 2018</a></p>
</blockquote>
<h1 id="why-emulating-cpython-c-api-is-so-hard">Why Emulating CPython C API is so hard</h1>
<p>บล็อกนี้จะพาเราไปรู้จัก cpyext API ของ PyPy ซึ่งเป็น API ที่เอาไว้ต่อกับ C API ของตัว CPython จริงๆ ครับ จะช่วยให้เราเข้าใจขึ้นว่าทำไม library บางตัวถึงรันช้าขึ้นเมื่ออยู่บน PyPy</p>
<blockquote>
<p><a href="https://morepypy.blogspot.com/2018/09/inside-cpyext-why-emulating-cpython-c.html">Inside cpyext: Why emulating CPython C API is so Hard</a>
cpyext is PyPy’s subsystem which provides a compatibility layer to compile and run CPython C extensions inside PyPy. Often people ask &hellip;
— official C API</p>
</blockquote>
<h1 id="apistar-as-a-cross-framework-api-tool">APIStar as a cross-framework API Tool</h1>
<p>ต้องบอกว่า APIStar นี่เปลี่ยนทิศทางโปรเจ็คไปมาหลายครั้งจนผมเองก็เริ่มจำไม่ได้แล้วว่าตกลงมันทำอะไรได้บ้าง พอมาเห็น Tweet นี้จากคุณ Tom Christie ซึ่งเป็นคนสร้าง APIStar ก็ทำให้เราพอจะมองเห็นทิศทางของโปรเจ็คได้บ้างครับว่าจะเป็นไปในทาง API tools ที่ทำหน้าที่สร้าง Documents, validate API Schema, Mock server หรือเป็น API Client เอง</p>
<p>นอกจากนั้นแล้วยังแยกส่วนของ Server ออกมาเพราะอีกโปรเจ็คนึงของบริษัท Encode นี้คือ Starlette โฟกัสในส่วนของ ASGI Server ได้ดีกว่า APIStar ครับ</p>
<p>ส่วนใครที่กำลังสงสัยว่า อ่าวแล้ว Django REST Framework จะไปในทิศทางไหน ในทวีตยังบอกด้วยครับว่าตัว DRF จะเริ่มย้ายจาก coreapi schema ไปใช้ OpenAPI Schema แทนครับ</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I&#39;m going to be trimming all the server stuff out of API Star, and releasing it instead as a framework-agnositic set of API tools for generating API docs, validating schemas, using as a client library, etc...<a href="https://t.co/ZQFf3hDuxg">https://t.co/ZQFf3hDuxg</a></p>&mdash; Tom Christie (@starletdreaming) <a href="https://twitter.com/starletdreaming/status/1043119773591199744?ref_src=twsrc%5Etfw">September 21, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<h1 id="pycon-2019-call-for-proposals">PyCon 2019 Call for Proposals</h1>
<p>สำหรับงานใหญ่ประจำปีอย่าง PyCon ปีหน้าก็เริ่มรับ Talk Proposal แล้วนะครับ ปีหน้าจัดวันที่ 1–9 พฤษภาคม ใครสนใจรายละเอียดหรือ Guideline ในการส่งสามารถกดดูได้ที่ลิ้งค์ข้างล่างเลยครับ</p>
<blockquote>
<p><a href="https://us.pycon.org/2019/speaking/">Speak at PyCon | PyCon 2019 in Cleveland, Ohio</a>
— PyCon 2019 in Cleveland, Ohio</p>
</blockquote>
<p>หรือถ้าใครอยากดูตัวอย่างของ Talk Proposal คุณ Mariatta ก็ได้ทำ documents ตัว Talk Proposal ที่เค้าเคยส่งไว้ที่นี่ครับ</p>
<blockquote>
<p><a href="https://talk-talk-talk.readthedocs.io/en/latest/">Talk Proposals by Mariatta — talk-talk-talk documentation</a>
— talk-talk-talk</p>
</blockquote>
<h1 id="auth0-join-hacktoberfest-2018">Auth0 join #Hacktoberfest 2018</h1>
<p>คงไม่ต้องแนะนำกันมากนะครับสำหรับ auth0 ซึ่งเป็น identity provider ที่น่าจะมีคนใช้เยอะระดับนึงเลย ผมลองดูๆ ใน <a href="https://github.com/auth0">https://github.com/auth0</a> ก็มี Python repository อยู่บ้างโดยเฉพาะ auth0-python ใครสนใจก็ไปช่วย contribute เอาเสื้อกันได้ครับ</p>
<blockquote>
<p><a href="https://auth0.com/blog/celebrate-hacktoberfest-with-auth0/">Celebrate Open-Source Software and Hacktoberfest 2018 with Auth0</a>
Auth0 is to excited join Hacktoberfest 2018, a month-long celebration and supporting of open-source software by Digital Ocean, Github, an&hellip;
— Auth0 - Blog, Kim Noel</p>
</blockquote>
<h1 id="python-book-40-of-at-manning-publishing">Python book 40% of at Manning publishing</h1>
<p>ทาง Manning ได้ออก special page ให้กับคุณ Naomi Ceder ซึ่งเป็น Chair of PSF นะครับมีหลายเล่มน่าสนใจ ก็ไปจับจองกันได้ตามลิ้งค์ข้างล่างเลยครับ</p>
<blockquote>
<p><a href="https://deals.manning.com/naomis-picks/">Naomi’s Picks | Special deals</a>
— Special deals</p>
</blockquote>
<h1 id="humble-book-bundle-learn-you-some-code">Humble book bundle: Learn you some code</h1>
<p>แพ๊คใหม่ของ Humble book bundle นะครับ มีหนังสือ Python อยู่สองสามเล่มเช่น Automate the boring stuff with Python, Python crash course และ Python Playground ใครสนใจก็ไปกดกันได้ครับ ถือว่าเป็นการช่วยองค์กรการกุศลและยังได้หนังสือดีๆ มาอ่านด้วย</p>
<blockquote>
<p><a href="https://www.humblebundle.com/books/learn-you-some-code-books">Humble Book Bundle: Learn You Some Code by No Starch Press</a>
Pay what you want for awesome ebooks and support charity!
— Humble Bundle</p>
</blockquote>
<h2 id="ซอรฟแวรอพเดท">ซอร์ฟแวร์อัพเดท</h2>
<h1 id="pytest-381">Pytest 3.8.1</h1>
<p>สำหรับ Library test ยอดนิยมอย่าง pytest ใน release นี้ออกมาแก้ bug อย่างเดียวเลยครับ แต่บั๊กใหญ่ใน release นี้คือมัน discover test ใน __init__.py แล้วมันระเบิดเพราะว่าไม่มี method len() ครับ นอกจากนั้นยังเพิ่มหน้า Deprecate and Removal ใน Document ด้วยเพื่อช่วยให้คนที่ใช้ Pytest เวอร์ชั่นเก่าๆ อัพเดทง่ายขึ้นครับ</p>
<blockquote>
<p><a href="https://github.com/pytest-dev/pytest">pytest/CHANGELOG.rst at main · pytest-dev/pytest</a>
The pytest framework makes it easy to write small tests, yet scales to support complex functional testing - pytest/CHANGELOG.rst at main · pytest-dev/pytest
— GitHub, pytest-dev</p>
</blockquote>
<h1 id="black-189b0">Black 18.9b0</h1>
<p>สำหรับ code formatter มาแรงอย่าง Black หลังจากห่างหายการอัพเดทไปนานเวอร์ชั่นนี้ได้เพิ่มความสามารถในการ format ตัวเลขให้มี _ (numerical literal) ที่มีตั้งแต่ Python 3.6 ขึ้นไปได้ และอื่นๆ อีกครับ</p>
<blockquote>
<p><a href="https://github.com/psf/black">GitHub - psf/black: The uncompromising Python code formatter</a>
The uncompromising Python code formatter. Contribute to psf/black development by creating an account on GitHub.
— GitHub, psf</p>
</blockquote>
<h1 id="scikit-learn-0200">Scikit-learn 0.20.0</h1>
<p>Release ล่าสุดของ Scikit-learn นี้จะเป็นเวอร์ชั่นสุดท้ายที่รองรับ Python 2.7 และ Python 3.4 ลงไปนะครับ เวอร์ชั่นหน้าจะต้องการ Python 3.5 หรือมากกว่า รายละเอียดเพิ่มเติมเกี่ยวกับฟีเจอร์ใหม่ สามารถติดตามได้ใน Document ข้างล่างครับ</p>
<blockquote>
<p><a href="https://scikit-learn/stable/whats_new.html">Release History</a>
Release notes for all scikit-learn releases are linked in this page. Tip: Subscribe to scikit-learn releases on libraries.io to be notified when new versions are released. Version 1.0.2, Version 1&hellip;.
— scikit-learn</p>
</blockquote>
<h1 id="datasette-025">Datasette 0.25</h1>
<p>สำหรับใครที่ไม่รู้จักนะครับ Datasette ช่วยให้เราสร้าง JSON read only API จาก database sqlite ได้ด้วยคำสั่งเดียว ซึ่งในเวอร์ชั่นนี้ได้แก้คำสั่ง published ให้เลือกได้ว่าเราจะใช้ heroku หรือ now ครับ นอกจากนั้นแล้วยังเปลี่ยนไปใช้ pysqlite3 ในการเชื่อมต่อกับ sqlite ทำให้สามารถใช้กับ sqlite เวอร์ชั่นล่าสุดอย่าง 3.25.0 ได้ด้วยครับ ยังมีฟีเจอร์อื่นๆ ที่เพิ่มขึ้นอีกนอกจากนี้ สามารถอ่านเพิ่มเติมได้ที่ release note ข้างล่างเลยครับ</p>
<blockquote>
<p><a href="https://docs.datasette.io/en/stable/changelog.html#v0-25">Changelog — Datasette documentation</a></p>
</blockquote>
<h1 id="twine-1121">Twine 1.12.1</h1>
<p>ในเวอร์ชั่นใหม่ของ twine ได้เพิ่ม command $ twine check ขึ้นมาครับ ช่วยให้เราสามารถเช็ค README file ว่าตรงกับ format ที่ PyPI อ่านได้รึเปล่าครับ</p>
<blockquote>
<p><a href="https://packaging.python.org/en/latest/guides/making-a-pypi-friendly-readme.html">Making a PyPI-friendly README — Python Packaging User Guide</a>
— Logo</p>
</blockquote>
<h1 id="logme-121">LogMe 1.2.1</h1>
<p>ผมเพิ่งรู้จัก LogMe เมื่อเร็วๆ นี้เองครับ เป็น Library ที่ช่วยให้เขียน Log ใน Python ได้ง่ายขึ้นเพียงแค่แปะ decorator ใครสนใจก็ไปลองใช้กันได้ครับ</p>
<blockquote>
<p><a href="https://github.com/BNMetrics/logme">GitHub - BNMetrics/logme: Python Logging For Humans (Also supports configurable color logging for the terminal!)</a>
Python Logging For Humans (Also supports configurable color logging for the terminal!) - GitHub - BNMetrics/logme: Python Logging For Humans (Also supports configurable color logging for the termin&hellip;
— GitHub, BNMetrics</p>
</blockquote>
<h1 id="click-70">Click 7.0</h1>
<p>สำหรับ Library ทำ command line ยอดฮิตอีกตัวนะครับ ในเวอร์ชั่นนี้สามารถทำ native autocomplete ใน zsh ได้แล้ว รวมถึง autocomplete ตัว choice ด้วย นอกจากนี้ยังเพิ่ม DateTime และ FloatRange สำหรับ input type ครับ</p>
<p>อีกส่วนหนึ่งที่สำคัญใน release นี้คือการย้าย document หลักของโปรเจ็คไปไว้ที่ readthedoc ครับ</p>
<blockquote>
<p><a href="https://palletsprojects.com/blog/click-7-0-released/">Click 7.0 Released</a>
— Pallets</p>
</blockquote>
<p>หมดแล้วครับสำหรับสัปดาห์นี้แล้วพบกันใหม่สัปดาห์หน้าครับ</p>
<hr>
<p>Original post at: <a href="https://medium.com/pythonbycow/%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B8%87%E0%B8%B9%E0%B9%83%E0%B8%AB%E0%B9%89%E0%B8%A7%E0%B8%B1%E0%B8%A7%E0%B8%81%E0%B8%A5%E0%B8%B1%E0%B8%A7%E0%B8%A3%E0%B8%B2%E0%B8%A2%E0%B8%AA%E0%B8%B1%E0%B8%9B%E0%B8%94%E0%B8%B2%E0%B8%AB%E0%B9%8C-%E0%B8%89%E0%B8%9A%E0%B8%B1%E0%B8%9A%E0%B8%97%E0%B8%B5%E0%B9%88-2-ebabd95bb532">https://medium.com/pythonbycow/เขียนงูให้วัวกลัวรายสัปดาห์-ฉบับที่-2-ebabd95bb532</a></p>
]]></content:encoded></item><item><title>เขียนงูให้วัวกลัวรายสัปดาห์ ฉบับที่ 1</title><link>https://yothinix-com.pages.dev/python-news-weekly-1/</link><pubDate>Fri, 21 Sep 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/python-news-weekly-1/</guid><description>&lt;p&gt;ไอเดียนี้เริ่มจากอาทิตย์ที่แล้ว ที่รวบข่าวไว้ในโพสๆ เดียว แล้วก็เกิดไอเดียว่า ทำไมไม่ทำเป็น Newsletter เลยหละ มันเลยเป็นที่มาของโพสนี้และโพสต่อๆ ไปครับ โดย​ &lt;em&gt;“เขียนงูให้วัวกลัว รายสัปดาห์”&lt;/em&gt; เราจะโฟกัสเฉพาะข่าวที่เกี่ยวข้องกับ Python Community, Core Language / 3rd Parties Release และอื่นๆ ที่มันเกี่ยวข้องกับ Python programming language ครับ&lt;/p&gt;
&lt;h1 id="python-core-sprint-2018"&gt;Python Core Sprint 2018&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://yothinix-com.pages.dev/python-news-weekly-1/1-B_8HrIjnpdeiPJK2p8YOEg_hu_71f7be265dc53592.webp"
srcset="https://yothinix-com.pages.dev/python-news-weekly-1/1-B_8HrIjnpdeiPJK2p8YOEg_hu_aaef0f626711cec8.webp 480w, https://yothinix-com.pages.dev/python-news-weekly-1/1-B_8HrIjnpdeiPJK2p8YOEg_hu_71f7be265dc53592.webp 960w"
sizes="(max-width: 960px) 100vw, 960px"
width="960" height="642"
alt=""
loading="lazy" decoding="async"&gt;
&lt;em&gt;Image credit: &lt;a href="https://twitter.com/VictorStinner/status/1041219533439217665"&gt;https://twitter.com/VictorStinner/status/1041219533439217665&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;ทุกๆ ปี Core Python developers จากทั่วทุกมุมโลกจะมารวมตัวกันโดยนัดหมาย 7 วันเพื่อคุยกันในหลายๆ เรื่อง ปีนี้เป็นครั้งที่ 3 ที่จัดขึ้นครับ&lt;/p&gt;
&lt;p&gt;ซึ่งผมก็ไม่รู้ทั้งหมดว่าเค้าคุยอะไรกันบ้าง แต่คุณ Mariatta Wijaya ซึ่งเป็นหนึ่งใน Core developer ได้สรุปไว้คร่าวๆ ครับ สนใจก็ตามไปอ่านได้ที่ลิ้งค์นี้เลย (ยังรอ Part two อยู่ T_T)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://mariatta.ca/core-sprint-2018-part-1.html"&gt;Python Core Sprint 2018: Part One&lt;/a&gt;
For the past week (September 9-14), I’ve been down in Bellevue, WA for my second Core Python sprint. The sprint is hosted by Microsoft, and funded by The PSF. Thanks Last year, I was only able to stay for the sprint for three days. This year I’m able to stay …
— mariatta.ca, Mariatta&lt;/p&gt;</description><content:encoded><![CDATA[<p>ไอเดียนี้เริ่มจากอาทิตย์ที่แล้ว ที่รวบข่าวไว้ในโพสๆ เดียว แล้วก็เกิดไอเดียว่า ทำไมไม่ทำเป็น Newsletter เลยหละ มันเลยเป็นที่มาของโพสนี้และโพสต่อๆ ไปครับ โดย​ <em>“เขียนงูให้วัวกลัว รายสัปดาห์”</em> เราจะโฟกัสเฉพาะข่าวที่เกี่ยวข้องกับ Python Community, Core Language / 3rd Parties Release และอื่นๆ ที่มันเกี่ยวข้องกับ Python programming language ครับ</p>
<h1 id="python-core-sprint-2018">Python Core Sprint 2018</h1>
<p><img src="/python-news-weekly-1/1-B_8HrIjnpdeiPJK2p8YOEg_hu_71f7be265dc53592.webp"
       srcset="/python-news-weekly-1/1-B_8HrIjnpdeiPJK2p8YOEg_hu_aaef0f626711cec8.webp 480w, /python-news-weekly-1/1-B_8HrIjnpdeiPJK2p8YOEg_hu_71f7be265dc53592.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="642"
       alt=""
       loading="lazy" decoding="async">
<em>Image credit: <a href="https://twitter.com/VictorStinner/status/1041219533439217665">https://twitter.com/VictorStinner/status/1041219533439217665</a></em></p>
<p>ทุกๆ ปี Core Python developers จากทั่วทุกมุมโลกจะมารวมตัวกันโดยนัดหมาย 7 วันเพื่อคุยกันในหลายๆ เรื่อง ปีนี้เป็นครั้งที่ 3 ที่จัดขึ้นครับ</p>
<p>ซึ่งผมก็ไม่รู้ทั้งหมดว่าเค้าคุยอะไรกันบ้าง แต่คุณ Mariatta Wijaya ซึ่งเป็นหนึ่งใน Core developer ได้สรุปไว้คร่าวๆ ครับ สนใจก็ตามไปอ่านได้ที่ลิ้งค์นี้เลย (ยังรอ Part two อยู่ T_T)</p>
<blockquote>
<p><a href="https://mariatta.ca/core-sprint-2018-part-1.html">Python Core Sprint 2018: Part One</a>
For the past week (September 9-14), I’ve been down in Bellevue, WA for my second Core Python sprint. The sprint is hosted by Microsoft, and funded by The PSF. Thanks Last year, I was only able to stay for the sprint for three days. This year I’m able to stay …
— mariatta.ca, Mariatta</p>
</blockquote>
<p>นอกจากนั้นแล้วปีนี้ เรายังมี Core Python Developer เพิ่มขึ้นอีก 2 คน และความเจ๋งยิ่งกว่านั้นคือ เป็นผู้หญิงทั้งคู่เลยครับนั่นทำให้จำนวน Core Python Developer ที่เป็นผู้หญิงนั่นเพิ่มขึ้น 2 เท่าเลยทีเดียว (จาก 2 เป็น 4 คน) ก็ขอแสดงความยินดีกับคุณ Lisa Roasch และ Emily Morehouse-Valcarcel ด้วยครับ</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Lisa Roasch and Emily Morehouse-Valcarcel <a href="https://twitter.com/emilyemorehouse?ref_src=twsrc%5Etfw">@emilyemorehouse</a> have been promoted as CPython core developers! Welcome on board. We doubled our number of women core devs (2 to 4) 😁 Nice move towards more diversity in Python. <a href="https://t.co/gckjfOyYPd">pic.twitter.com/gckjfOyYPd</a></p>&mdash; Victor Stinner 🐍 (@VictorStinner) <a href="https://twitter.com/VictorStinner/status/1040731541796614145?ref_src=twsrc%5Etfw">September 14, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<h1 id="linus-torvalds-stepping-down-temporary">Linus Torvalds stepping down temporary</h1>
<p>ข่าวนี้อาจจะไม่ค่อยเกี่ยวกับ Python เท่าไร แต่ก็นับว่าเป็นเรื่องที่ดีครับที่ Linus ยอมลดราความโหดลงบ้าง ที่น่าสนใจเกี่ยวกับบทความนี้คือ มีการพูดถึงเรื่อง Diversity ใน Python Core developer ด้วยครับ ซึ่งเปิดโลกผมมากเพราะไม่เคยรู้มาก่อนเลยว่า Guido สนับสนุน Diversity ถึงขนาดยอมเป็น Mentor ให้เลย ติดตามอ่านเต็มๆ ได้ในบทความครับ</p>
<blockquote>
<p><a href="https://www.newyorker.com/science/elements/after-years-of-abusive-e-mails-the-creator-of-linux-steps-aside">After Years of Abusive E-mails, the Creator of Linux Steps Aside</a>
The celebrated coder Linus Torvalds, known for the operating system he created and his aggressive style of communication, says he is seeking help.
— The New Yorker, Condé Nast</p>
</blockquote>
<h1 id="90-of-top-1440-pypi-package-support-python-3">90% of top 1440 PyPI package support Python 3</h1>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I pimped py3readiness and worked with <a href="https://twitter.com/brettsky?ref_src=twsrc%5Etfw">@brettsky</a> to add more false positives to caniusepython3. About 90% of the top 1440 <a href="https://twitter.com/hashtag/PyPI?src=hash&amp;ref_src=twsrc%5Etfw">#PyPI</a> downloads support <a href="https://twitter.com/hashtag/Python?src=hash&amp;ref_src=twsrc%5Etfw">#Python</a> 3. <a href="https://t.co/mZHQyYsvh7">https://t.co/mZHQyYsvh7</a> <a href="https://t.co/HOuGWJHq99">pic.twitter.com/HOuGWJHq99</a></p>&mdash; Christian Heimes (@ChristianHeimes) <a href="https://twitter.com/ChristianHeimes/status/1040738989970345985?ref_src=twsrc%5Etfw">September 14, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>นับวันก็ยิ่งใกล้ปี 2020 เข้าไปทุกขณะนะครับ ซึ่งเป็นปีที่ Python จะหยุด Support Python2.7 ซึ่งเป็น release สุดท้ายของ Python 2 จาก tweet ล่าสุดของคุณ Christian Heimes นะครับ Software ที่มียอด Download สูงสุด 1440 packages ใน PyPI ในขณะนี้ support Python3 ไปแล้วกว่า 90% และ Top 360 packages นั้น support ถึง 99% แล้วครับ ใครยังไม่อัพเกรดก็ใกล้ถึงเวลาแล้ว อย่าชะล่าใจนะครับ ส่วนใครอยากรู้ว่า Package ไหนรองรับได้สามารถไปดูได้ที่ Python 3 readiness ตามลิ้งข้างล่างเลยครับ</p>
<blockquote>
<p><a href="https://tiran.github.io/py3readiness/#.Yg8zuu5BzFx">Python 3 Readiness - Python 3 support table for most popular Python packages</a>
— Python 3 support table for most popular Python packages</p>
</blockquote>
<h1 id="python-taking-over-as-a-major-programming-language-for-astronomy">Python taking over as a major programming language for Astronomy</h1>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Python is taking over astronomy, 2018Q3 edition: the curve keeps getting steeper! Updated in collaboration with <a href="https://twitter.com/_russrussruss?ref_src=twsrc%5Etfw">@_russrussruss</a> and <a href="https://twitter.com/astrowizicist?ref_src=twsrc%5Etfw">@astrowizicist</a>.<br><br>CC <a href="https://twitter.com/jakevdp?ref_src=twsrc%5Etfw">@jakevdp</a> <a href="https://twitter.com/astrofrog?ref_src=twsrc%5Etfw">@astrofrog</a> <a href="https://twitter.com/BeaumontChris?ref_src=twsrc%5Etfw">@BeaumontChris</a> <a href="https://t.co/thJryG2q2R">pic.twitter.com/thJryG2q2R</a></p>&mdash; Juan Nunez-Iglesias (@jnuneziglesias) <a href="https://twitter.com/jnuneziglesias/status/1042327103134261248?ref_src=twsrc%5Etfw">September 19, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>ผลพวงจากการที่ Python เป็นภาษาที่มีอัตราเติบโตสูงสุดทางฝั่ง Data Science ทางฝั่ง Astronomy นี่ก็ไม่น้อยหน้าเหมือนกัน ซึ่งได้แซง IDL กับ Matlab ไปเป็นที่เรียบร้อยแล้วครับ ถ้าใครอยากรู้ว่าสถิตินี้คำนวนยังไง สามารถไปเล่น Notebook ได้ที่ลิ้งค์นี้เลยครับ</p>
<blockquote>
<p><a href="https://github.com/jni/programming-languages-in-astronomy">programming-languages-in-astronomy/programming-languages-in-ADS.ipynb at 1df4ec72defaa0b66a22ac2837131ca2850107ba · jni/programming-languages-in-astronomy</a>
Analysis of programming language mentions in astronomy papers in ADS - programming-languages-in-astronomy/programming-languages-in-ADS.ipynb at 1df4ec72defaa0b66a22ac2837131ca2850107ba · jni/progra&hellip;
— GitHub, jni</p>
</blockquote>
<h1 id="new-asyncio-official-documentation">New Asyncio official documentation</h1>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">🔥 Big news! 🔥<br><br>asyncio documentation has been rewritten from scratch! Read the new version here: <a href="https://t.co/Hoa08x3Y3Z">https://t.co/Hoa08x3Y3Z</a>.<br><br>Huge thanks to <a href="https://twitter.com/WillingCarol?ref_src=twsrc%5Etfw">@WillingCarol</a>, <a href="https://twitter.com/elprans?ref_src=twsrc%5Etfw">@elprans</a>, and <a href="https://twitter.com/andrew_svetlov?ref_src=twsrc%5Etfw">@andrew_svetlov</a> for support, ideas, and reviews!<br><br>Thread 👇 <a href="https://t.co/5kDxkUboVC">pic.twitter.com/5kDxkUboVC</a></p>&mdash; Yury Selivanov (@1st1) <a href="https://twitter.com/1st1/status/1041855362402541568?ref_src=twsrc%5Etfw">September 18, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>ถ้าใครได้ลองเขียน Python แบบ Async ในช่วงสองปีที่ผ่านมาน่าจะประสบปัญหาเดียวกับผมว่า Document มันอ่านโคตรยากเลยครับ เหมือนเขียนมาเพื่อให้เราไปช่วย Implement ตัว Library เองยังไงยังงั้น</p>
<p>ซึ่งทางคุณ Yury Selivanov นี่ก็ไม่ได้นิ่งนอนใจนะครับ ในฐานะคนที่ผลักดัน asyncio มาตั้งแต่แรก ได้ประกาศก้องว่าเราเขียนมันใหม่หมดเลย ลบความงงงวยที่เคยเขียนก่อนหน้านั้นทิ้งไปทั้งหมด</p>
<p>ผมเข้าไปอ่านนิดหน่อยแล้วเห็นความแตกต่างอย่างเห็นได้ชัดคือแยกส่วนคือ High level / Low level API ออกจากกันอย่างชัดเจน ทำให้คนที่สนใจจะนำไปใช้ไม่ต้องรู้ Low level อย่าง Event loop หรือ Future object ก็ได้ครับ</p>
<p>ใครสนใจก็เข้าไปอ่านได้ที่ลิ้งค์ข้างล่างเลยครับ</p>
<blockquote>
<p><a href="https://docs.python.org/3/library/asyncio.html">asyncio — Asynchronous I/O — Python 3.10.2 documentation</a>
— Logo</p>
</blockquote>
<h1 id="sneak-peak-on-requests-30">Sneak peak on Requests 3.0</h1>
<p><br>
คงไม่ต้องแนะนำกันแล้วใช่มั้ยครับ สำหรับ Library ที่ทุกคนตั้งแต่คนเขียน Script Python เล็กๆ ไปจนถึงทำ Data warehouse ขนาดใหญ่ต้องผ่านมือมาทุกคน ซึ่งหลังจากประกาศขอ Funding ไปเมื่อหลายเดือนก่อน ตอนนี้คุณ Kenneth Reitz ก็เริ่มแง้มๆ แผนของ Requests 3.0 ซึ่งเป็น Version หน้าของ Library ตัวนี้ออกมาให้ชมกัน</p>
<p>หลักๆ คือ Support Python 3.6+ ซึ่งผมเข้าใจว่าให้รองรับกับ Asynchronous programming ส่วนหนึ่ง และอีกส่วนหนึ่งคือแตก Library low level ออกไปเป็น Library ใหม่ชื่อ requestscore ซึ่งมีไว้เพื่อสถานการณ์ที่ I NEED TO SEND AS MANY REQUESTS AS POSSIBLE AS EFFICIENTLY AS POSSIBLE ตามนั้นเลยครับ</p>
<p>นอกจาก Requests ทางคุณ Kenneth Reitz กำลังพัฒนา Library ตัวใหม่อยู่นะครับ ซึ่งเค้านิยามว่าเป็น Buildpack แบบHeroku บน Kubernetes ซึ่งผมเข้าใจว่าก็น่าจะเป็นงานหลักของเค้าเพราะทาง DigitalOcean ที่ทำงานปัจจุบันของคุณ Kenneth Reitz ก็เพิ่งเปิดตัว Kubernetes ไปได้ไม่นาน ใครสนใจก็ติดตามได้ที่ลิ้งค์ข้างล่างครับ</p>
<blockquote>
<p><a href="https://github.com/kennethreitz-archive/bruce-operator">GitHub - kennethreitz-archive/bruce-operator: The BRUCE operator.</a>
The BRUCE operator. Contribute to kennethreitz-archive/bruce-operator development by creating an account on GitHub.
— GitHub, kennethreitz-archive</p>
</blockquote>
<h1 id="new-mypy-release">New MyPy Release</h1>
<p>สำหรับ Type checker มาตรฐานอุตสาหกรรม Python อย่าง MyPy ก็ยังมีอัพเดทเรื่อยๆ นะครับในอัพเดทนี้รองรับการเช็ค Type ใน Callable Protocol และแก้บั๊กอีกจำนวนหนึ่ง รายละเอียดเพิ่มเติมตามลิ้งค์ข้างล่างเลยครับ</p>
<blockquote>
<p><a href="http://mypy-lang.blogspot.com/2018/09/mypy-0630-released.html">Mypy 0.630 Released</a>
We’ve just uploaded mypy 0.630 to the Python Package Index ( PyPI ). Mypy is an optional static type checker for Python. This release inc&hellip;
— Ivan</p>
</blockquote>
<h1 id="new-tox-release">New Tox release</h1>
<p>อันนี้ข่าวล่าวันนี้เลย Tox ออกเวอร์ชั่นใหม่นะครับ 3.4.0 มีฟีเจอร์ใหม่ๆ อย่างเช่น เพิ่ม option commands_pre และ commands_post, รองรับไฟล์ pyproject.toml ซึ่งเป็นมาตรฐานใหม่ของ Python package (PEP 518) และอื่นๆ อีก</p>
<blockquote>
<p><a href="https://tox.readthedocs.io/en/latest/changelog.html">Changelog history — tox 3.4.0 documentation</a>
— Logo</p>
</blockquote>
<h1 id="beta-release-for-ipython-70">Beta Release for IPython 7.0</h1>
<p>หลายๆ คนอาจจะไม่รู้ตัวนะครับว่าตัวเองใช้ IPython อยู่ แต่จริงๆ มันคือ engine เบื้องหลังของ Jupyter Notebook ครับ ซึ่งใน Beta release ล่าสุดได้เพิ่มความสามารถในการรองรับ syntax async / await แล้วครับ</p>
<p>แต่ความสามารถใหม่นี่ก็ทำให้เกิดบั๊กใน magics ของ IPython อย่าง %%timeit เกิด Syntax Error เมื่อใช้ autoawait ข้างบนนะครับ ซึ่งทางยังรอคนแก้บั๊กใครสนใจก็ไปช่วยแก้กันได้ครับ</p>
<blockquote>
<p><a href="https://ipython.readthedocs.io/en/stable/interactive/autoawait.html">Asynchronous in REPL: Autoawait — IPython 8.1.0.dev documentation</a></p>
</blockquote>
<h1 id="microsoft-joining-hacktoberfest-2018">Microsoft joining Hacktoberfest 2018</h1>
<p>ยิ่งใกล้เดือนตุลาคม เราก็ยิ่งเตรียมใจและ Text Editor คู่ใจเพื่อเตรียมรับกับเทศกาล Hacktoberfest ประจำปีนะครับ ซึ่งปีนี้ Microsoft ได้มาร่วมด้วย ซึ่งตามธรรมเนียมครับ Microsoft แจกเสื้อ Limited Edition ด้วย ใครสนใจก็เตรียมตัวให้ดีนะครับ</p>
<blockquote>
<p><a href="https://cloudblogs.microsoft.com/opensource/2018/09/18/hacktoberfest-2018-microsoft/">We’re joining Hacktoberfest 2018 - Microsoft Open Source Blog</a>
As part of Hacktoberfest, we’ll recognize anyone who submits an October pull request to a Microsoft open source project with a limited-edition t-shirt.
— Microsoft Open Source Blog, Bernd Verst</p>
</blockquote>
<p>ผมไล่ๆ ดูใน Opensource projects ของ Microsoft นี่มีหลายตัวที่น่าสนใจเลยทีเดียว แต่ที่น่าสนใจสุดคงไม่พ้น Python Extension for VSCode นะครับ สำหรับใครที่สนใจ Contribute ให้ Microsoft ในส่วนของ Python สามารถไล่ดู Project ได้ตามลิ้งข้างล่างเลยครับ</p>
<blockquote>
<p><a href="https://opensource.microsoft.com">Microsoft Open Source</a>
Microsoft Open Source: get involved in open source communities, discover projects and ecosystems Microsoft is involved in, and learn about the Microsoft open source program
— Microsoft Open Source</p>
</blockquote>
<p>ปล.จริงๆ วันอังคารที่ผ่านมาเป็นกำหนด Python 3.7.1 final release นะครับ แต่มีปัญหานิดหน่อยกับ implementation ของ C locale coercion (PEP 538) ในนาทีสุดท้ายเลยต้องเลื่อน release ออกไปซึ่งคาดว่าน่าจะเป็นวันที่ 28 กันยายนนี้ ก็คอยติดตามกันครับ</p>
<hr>
<p>Original post at: <a href="https://medium.com/pythonbycow/%E0%B9%80%E0%B8%82%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B8%87%E0%B8%B9%E0%B9%83%E0%B8%AB%E0%B9%89%E0%B8%A7%E0%B8%B1%E0%B8%A7%E0%B8%81%E0%B8%A5%E0%B8%B1%E0%B8%A7%E0%B8%A3%E0%B8%B2%E0%B8%A2%E0%B8%AA%E0%B8%B1%E0%B8%9B%E0%B8%94%E0%B8%B2%E0%B8%AB%E0%B9%8C-%E0%B8%89%E0%B8%9A%E0%B8%B1%E0%B8%9A%E0%B8%97%E0%B8%B5%E0%B9%88-1-2423a65e8a02">https://medium.com/pythonbycow/เขียนงูให้วัวกลัวรายสัปดาห์-ฉบับที่-1-2423a65e8a02</a></p>
]]></content:encoded></item><item><title>Share ประสบการณ์ Upgrade Python 3.7</title><link>https://yothinix-com.pages.dev/upgrade-python-3-7/</link><pubDate>Sat, 08 Sep 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/upgrade-python-3-7/</guid><description>&lt;p&gt;ถ้าจะมีงานหนึ่งที่ผมทำแล้วรู้สึกสนุกและท้าทายทุกครั้งที่อยู่ที่ Pronto Tools ก็คือการอัพเกรดเวอร์ชั่น Python นี่แหละครับ ตอนผมเข้ามาทำงานใหม่ๆ ทีมใช้ Python 3.5 อยู่ปีที่แล้วเลยอัพเกรดเป็น 3.6 และในปีนี้เนื่องในโอกาส Python 3.7 ออก เราก็รอแปปนึงจนคิดว่าอะไรๆ พร้อมแล้ว ถึงจะอัพเกรด&lt;/p&gt;
&lt;h1 id="ทำไมถงตองอพเกรด"&gt;ทำไมถึงต้องอัพเกรด&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;เพราะเราอยากใช้ของใหม่ๆ ครับ&lt;/strong&gt; อันนี้เหตุผลสั้นๆ เลย เราอยากใช้ &lt;strong&gt;breakpoint()&lt;/strong&gt; ตัวใหม่ เราอยากใช้ &lt;strong&gt;dataclasses&lt;/strong&gt; เราอยากใช้ &lt;code&gt;from __future__ import annotations&lt;/code&gt; และอื่นๆ อีกมากมาย นี่ยังไม่รวมถึง Library ต่างๆ ที่เกี่ยวข้องที่บาง Library ทำมาเพื่อ Python 3.7+ แล้ว ถึงแม้ว่า Python 3.6 กว่าจะ &lt;em&gt;end of life&lt;/em&gt; ก็ตั้งปี 2021 แต่รีบๆ อัพเกรดไว้ก็ไม่เสียหายครับ&lt;/p&gt;
&lt;p&gt;ข้อดีอีกอย่างของการอัพเกรดในช่วงนี้คือ หา Issues ง่ายครับหลายๆ Library ที่เราพึ่งพาอยู่ในโปรเจ็คเราก็ยังมีอีกหลายคนที่ต้องการอัพเกรดเหมือนกัน แต่ถ้าหาไม่เจอ นี่ก็เป็นโอกาสอันดีครับที่จะได้ไป Contribute ให้ Library หลายๆ ตัวให้รองรับ Python 3.7 ในตัว&lt;/p&gt;</description><content:encoded><![CDATA[<p>ถ้าจะมีงานหนึ่งที่ผมทำแล้วรู้สึกสนุกและท้าทายทุกครั้งที่อยู่ที่ Pronto Tools ก็คือการอัพเกรดเวอร์ชั่น Python นี่แหละครับ ตอนผมเข้ามาทำงานใหม่ๆ ทีมใช้ Python 3.5 อยู่ปีที่แล้วเลยอัพเกรดเป็น 3.6 และในปีนี้เนื่องในโอกาส Python 3.7 ออก เราก็รอแปปนึงจนคิดว่าอะไรๆ พร้อมแล้ว ถึงจะอัพเกรด</p>
<h1 id="ทำไมถงตองอพเกรด">ทำไมถึงต้องอัพเกรด</h1>
<p><strong>เพราะเราอยากใช้ของใหม่ๆ ครับ</strong> อันนี้เหตุผลสั้นๆ เลย เราอยากใช้ <strong>breakpoint()</strong> ตัวใหม่ เราอยากใช้ <strong>dataclasses</strong> เราอยากใช้ <code>from __future__ import annotations</code> และอื่นๆ อีกมากมาย นี่ยังไม่รวมถึง Library ต่างๆ ที่เกี่ยวข้องที่บาง Library ทำมาเพื่อ Python 3.7+ แล้ว ถึงแม้ว่า Python 3.6 กว่าจะ <em>end of life</em> ก็ตั้งปี 2021 แต่รีบๆ อัพเกรดไว้ก็ไม่เสียหายครับ</p>
<p>ข้อดีอีกอย่างของการอัพเกรดในช่วงนี้คือ หา Issues ง่ายครับหลายๆ Library ที่เราพึ่งพาอยู่ในโปรเจ็คเราก็ยังมีอีกหลายคนที่ต้องการอัพเกรดเหมือนกัน แต่ถ้าหาไม่เจอ นี่ก็เป็นโอกาสอันดีครับที่จะได้ไป Contribute ให้ Library หลายๆ ตัวให้รองรับ Python 3.7 ในตัว</p>
<h1 id="how-to-upgrade-แบบไมเจบตว">How to upgrade แบบไม่เจ็บตัว</h1>
<p>อย่างแรกเลยครับ ถ้าอยากอุ่นใจ codebase เราควรจะมี Unit test ครับ ซึ่งสิ่งหนึ่งที่ผมเรียนรู้จากช่วงอัพเกรดที่ผ่านมาคือ codebase ของ SimpleSat ที่เราดูแลอยู่บาง service มี coverage อยู่ที่ประมาณ 97% files, 98% lines covered เลยครับ ส่วนตัวผมเองเลยค่อนข้างอุ่นใจไประดับนึงละ</p>
<p>เนื่องจากว่า environment เราอยู่บน Docker 100% โนะ วิธีอัพเกรดคือแค่เปลี่ยน base image จาก Python 3.6 เป็น Python 3.7 แล้วก็ลอง Build images ของทุก microservice service ใหม่ดู จากนั้นก็รัน docker-compose stack ใน local แล้วดูว่าเกิดอะไรขึ้น ข้างล่างนี่คือ List ของปัญหาที่เราเจอกับ Library ที่เราใช้อยู่ครับ</p>
<h2 id="uwsgi">uWSGI</h2>
<p>เมื่อประมาณ 2 เดือนที่แล้วเราก็เพิ่งอัพเกรด uWSGI เป็นเวอร์ชั่น 2.0.17 พอมาถึงวันที่เราเปลี่ยนมาใช้ Python 3.7 ระเบิดครับ เหตุผลเพราะว่า C-API PyOS_AfterFork มันดัน Deprecate ใน Python 3.7 ครับ โชคดีที่ Issue นี้มีคนแก้ไว้แล้วและ uWSGI ได้ออก release 2.0.17.1 มาแก้ปัญหานี้แล้วเรียบร้อยครับ</p>
<blockquote>
<p><a href="https://github.com/unbit/uwsgi/issues/1813">Python 3.7.0: PyOS_AfterFork is deprecated · Issue #1813 · unbit/uwsgi</a>
Since Python 3.7.0 the PyOS_AfterFork is deprecated. uwsgi is using this function in python_plugin.c.
— GitHub, unbit</p>
</blockquote>
<h2 id="pytoolz">PyToolz</h2>
<p>สำหรับคนที่ไม่รู้จักนะครับ PyToolz เป็น Library functional programming ที่ได้รับความนิยมมากตัวหนึ่งใน Python และเราใช้มันในหลายๆ ส่วนของ codebase เราครับ เวอร์ชั่นที่เราใช้อยู่คือ 0.8.2 พออัพเกรดมาใช้ Python 3.7 สิ่งที่เราเจอคือ</p>
<blockquote>
<p>SyntaxError: Generator expression must be parenthesized</p>
</blockquote>
<p>ซึ่งโค้ดบางส่วนใน Library ยังเขียน Generator expression แบบไม่มีวงเล็บอยู่นั่นเองครับ ซึ่งเป็น Change in behavior หนึ่งใน Python 3.7 นะครับ</p>
<blockquote>
<p><em>Python 3.7 now correctly raises a <code>SyntaxError</code>, as a generator expression always needs to be directly inside a set of parentheses and cannot have a comma on either side, and the duplication of the parentheses can be omitted only on calls. (Contributed by Serhiy Storchaka in <a href="https://bugs.python.org/issue32012">bpo-32012</a>and <a href="https://bugs.python.org/issue32023">bpo-32023</a>.)</em></p>
</blockquote>
<p>แต่ก็โชคดีเหมือนกันครับที่ Library ออก patch มาแก้ไขเรื่องนี้แล้วเพียงแค่อัพไป release 0.9.0 ก็ไม่มีปัญหานี้แล้วครับ</p>
<blockquote>
<p><a href="https://github.com/pytoolz/toolz/issues/404">python 3.7 compatibility bug · Issue #404 · pytoolz/toolz</a>
In the conda&rsquo;s vendored version of toolz, when testing against python 3.7, I got this error Traceback (most recent call last): File &ldquo;/opt/conda-py37/lib/python3.7/site-packages/conda/excep&hellip;
— GitHub, pytoolz</p>
</blockquote>
<h2 id="django">Django</h2>
<p>เนื่องจากสถาปัตยกรรมของเราเป็น Microservice โนะแล้ว แต่ละ service ก็เกิดก่อนหลังไม่พร้อมกันเลยมีบางตัวที่ใช้ Django ไม่ตรงกับตัวอื่น ปัญหานี้เจอใน Django 1.11.x ครับและเป็นปัญหาเดียวกับ PyToolz เลยคือ <code>Generator expression must be parenthesized</code> ซึ่งก็มีคนเปิด issue ไว้แล้วทีนี่</p>
<blockquote>
<p><a href="https://github.com/django/django/commit/931c60c5216bd71bc11f489e00e063331cf21f40">Refs #28814 &ndash; Fixed “SyntaxError: Generator expression must be paren… · django/django@931c60c</a>
…thesized” on Python 3.7. Due to <a href="https://bugs.python.org/issue32012">https://bugs.python.org/issue32012</a>.
— GitHub, django</p>
</blockquote>
<p>แต่ตัวนี้โชคร้ายหน่อยตรงที่ Maintainer ของ Django ไม่อัพเดทให้กับ 1.11 แล้วเนื่องจากหมด Mainstream support ไปแล้วครับ</p>
<blockquote>
<p>Per <a href="https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django">the FAQ</a>, Django 1.11.x is not compatible with Python 3.7.<br>
<br>
Django 1.11.x reached <a href="https://www.djangoproject.com/download/#supported-versions">end of mainstream support</a> on December 2, 2017 and it receives only data loss and security fixes until its end of life.</p>
</blockquote>
<p>เพราะฉะนั้นในเคสนี้ เราเลยเหลือทางเลือกทางเดียวคือ อัพเกรด Django เลยครับจาก 1.11 กระโดดไปเป็น 2.1 ซึ่งเป็นเวอร์ชั่นล่าสุดเลย แต่เนื่องจากเราอัพเกรด Django เพราะฉะนั้น Library ที่เราใช้ที่เกี่ยวข้องกับ Django อย่างเช่น Django REST Framework, django-filter, etc. ก็เลยต้องอัพตามไปด้วย แต่โดยรวมแล้วก็ไม่มีปัญหาอะไรครับ นอกจากต้องเพิ่มอาร์กิวเม้นต์ <strong>on_delete</strong> เข้าไปใน <strong>ForeignKey</strong> ของ Django ด้วย</p>
<h2 id="freezegun">Freezegun</h2>
<p>Freezegun ก็เป็น Library ตัวนึงที่เราใช้งานสูงมากครับ ช่วยให้เราเขียน Unit test ที่มีเวลาเข้ามาเกี่ยวข้องได้ง่ายขึ้นมาก เวอร์ชั่นที่เราใช้อยู่ปัจจุบันคือ 0.3.9 ครับ ซึ่งพออัพเกรดมาใช้ Python 3.7 ก็เจอปัญหาเลยว่า</p>
<blockquote>
<p>AttributeError: module &lsquo;uuid&rsquo; has no attribute &lsquo;_uuid_generate_time&rsquo;</p>
</blockquote>
<p>เคสนี้ก็ยังโชคดีอยู่ครับที่ตัว Library ออก patch มาแก้ไขเรียบร้อยแล้วเพียงแค่อัพเกรดเป็น 0.3.10 ก็ไม่เจอปัญหานี้แล้วครับ แต่เคสนี้เป็นเคสที่แปลกมากอย่างนึงคือ ผมพยายามหาใน Changelog ของ Python 3.7 แต่ไม่มีที่ไหนพูดถึง Remove attribute <strong>_uuid_generate_time</strong> เลยครับ</p>
<blockquote>
<p><a href="https://github.com/spulec/freezegun/issues/225">AttributeError: module ‘uuid’ has no attribute ‘_uuid_generate_time’ on Python 3.7.0b1 · Issue #225 · spulec/freezegun</a>
The upcoming Python 3.7 version drops the internal _uuid_generate_time function in the uuid module, which makes freezegun fail on import: Python 3.7.0b1+ (heads/3.7:7f38637853, Feb 1 2018, 13:09:53&hellip;
— GitHub, spulec</p>
</blockquote>
<h2 id="dropbox">Dropbox</h2>
<p>ในเคสของ Dropbox SDK ปัญหาค่อนข้างจะตรงไปตรงมาครับคือ ใน codebase ของตัว Library ยังมีตัวแปรบางตัวใช้คำว่า async ซึ่งใน Python 3.7 กลายมาเป็น Reserved keywords แล้ว อันนี้ก็อัพเดทไปใช้เวอร์ชั่นล่าสุด 9.0.0 ก็ไม่มีปัญหานี้แล้วครับ</p>
<blockquote>
<p><a href="https://github.com/dropbox/dropbox-sdk-python/issues/145">Failure to import on Python 3.7.0b4 · Issue #145 · dropbox/dropbox-sdk-python</a>
async is now a keyword leading to: import: &lsquo;dropbox&rsquo; Traceback (most recent call last): File &ldquo;/opt/conda/conda-bld/dropbox_1525570948590/test_tmp/run_test.py&rdquo;, line 2, in &lt;modu&hellip;
— GitHub, dropbox</p>
</blockquote>
<h2 id="flake8">Flake8</h2>
<p>พอเราเปลี่ยนมาใช้ Python 3.7 ตัว Flake8 จากที่รันเงียบๆ อยู่ดีๆ ก็มี Warning เพิ่มขึ้นมาว่า</p>
<blockquote>
<p>FutureWarning: Possible nested set at position 1<br>
EXTRANEOUS_WHITESPACE_REGEX = re.compile(r&rsquo;[[({] | []}),;:]&rsquo;)</p>
</blockquote>
<p>ซึ่งก็มีคนไปเปิด issues ไว้แล้วครับที่ Pycodestyle (ตัว Flake8 ขี่อยู่บน Library อีกสามตัวหนึ่งในนั้นคือ Pycodestyle ระหว่างนี้เราก็ได้แต่รอ Flake8 ออกเวอร์ชั่นใหม่ ก็ทนรำคาญไปอีกนิดหน่อย แต่โดยรวมแล้วก็ยังทำงานได้ปกติครับ</p>
<blockquote>
<p><a href="https://github.com/PyCQA/pycodestyle/issues/728">FutureWarning: Possible nested set for EXTRANEOUS_WHITESPACE_REGEX · Issue #728 · PyCQA/pycodestyle</a>
When running pycodestyle 2.3.1 with Python 3.7, I get: /home/florian/proj/qutebrowser/git/.tox/flake8/lib/python3.7/site-packages/pycodestyle.py:113: FutureWarning: Possible nested set at position &hellip;
— GitHub, PyCQA</p>
</blockquote>
<h2 id="celery">Celery</h2>
<p>ตัว Celery นี่เป็นเคสที่ปวดหัวที่สุดละครับ คือตัว Package หลักที่อยู่ใน PyPI ยังไม่ support Python 3.7 จนมีคนไปโวยวายเยอะมาก ว่าทำไมไม่ support ฟะ ก็น่าจะมีคนใช้เยอะนิ ซึ่งจริงๆ ใน Master branch ของตัว Library เองก็มีคนแก้ปัญหา compatibility กับ Python 3.7 แล้วนะครับ ปัญหาเล็กมากแค่เรื่อง async keywords เหมือนเคส Dropbox เลย แต่ทาง Maintainer ของ Celery ก็ไม่ยอมออก Release เล็กๆ ออกมาแก้เรื่องนี้ (คงจะรอจน release 4.3 ออกอย่างไวสุดก็เดือนหน้า) ครับ</p>
<blockquote>
<p><a href="https://github.com/celery/celery/issues/4500">Support `async` keyword in python 3.7 · Issue #4500 · celery/celery</a>
Checklist I have included the output of celery -A proj report in the issue. (if you are not able to do this, then at least specify the Celery version affected). I have verified that the issue exist&hellip;
— GitHub, celery</p>
</blockquote>
<p>ระหว่างนี้ ถ้าอยากใช้ Celery กับ Python 3.7 ก็แนะนำให้ pip จาก GitHub ที่ commit นี้ไปก่อนนะครับจนกว่า Celery 4.3.x จะออก</p>
<blockquote>
<p>pip install git+<a href="https://github.com/celery/celery.git@ced86ea58859e9f704cc781c59ea3e137b199638">https://github.com/celery/celery.git@ced86ea58859e9f704cc781c59ea3e137b199638</a></p>
</blockquote>
<p>ส่วนถ้าใครอยากอ่านดราม่าใน Celery ก็ติดตามได้ที่ issues นี้เลยครับ</p>
<blockquote>
<p><a href="https://github.com/celery/celery/issues/4957">Celery release cycle · Issue #4957 · celery/celery</a>
There is no reasonable release cycle for Celery. If something is broken, it could be broken in stable version for a very long time, even if it&rsquo;s actually fixed at master. Steps to reproduce Fix&hellip;
— GitHub, celery</p>
</blockquote>
<p>หลังจากอัพเกรดจนทุก Library ใช้งานได้ปกติแล้ว Unit test ผ่านหมด เราก็ยังไม่ไว้ใจ 100% ครับ วันต่อมาหลังจากเรา Deploy ตัว Docker image ใหม่ที่อัพเกรดแล้วไปเครื่อง development เราทำ Manual testing ทุกฟีเจอร์ที่เกี่ยวข้องกับแอพเลย ซึ่งโชคดีที่ไม่เจอปัญหาอะไรที่ร้ายแรง หรือเกี่ยวข้องโดยตรงจากการอัพเดทครับ เราเลยอัพเกรดขึ้น Production ในบ่ายวันนั้นเลย ซึ่งก็ยังไม่เจอปัญหาอะไรมาจนถึงปัจจุบัน</p>
<h1 id="upgrade-แลวไดอะไรบาง">Upgrade แล้วได้อะไรบ้าง</h1>
<p>อันนี้เป็นสิ่งที่ผมนึกได้สุดท้ายก่อนที่เราจะกดอัพเกรดเครื่อง Development ครับคือพยายามเก็บ Resource ทุกอย่างว่าก่อนและหลัง Deploy เปลี่ยนไปมากแค่ไหนและข้างล่างนี่คือ สิ่งที่เกิดขึ้นครับ</p>
<p><img src="/upgrade-python-3-7/1-6_5F_P7B4qRK-9OydODnBA_hu_3ea266861aa2e235.webp"
       srcset="/upgrade-python-3-7/1-6_5F_P7B4qRK-9OydODnBA_hu_eadd0988eb179097.webp 480w, /upgrade-python-3-7/1-6_5F_P7B4qRK-9OydODnBA_hu_3ea266861aa2e235.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="594"
       alt=""
       loading="lazy" decoding="async"></p>
<p>จะเห็นว่า Memory Usage ลดลงอย่างเห็นได้ชัดมากๆ เกือบ 3 GB เลยทีเดียว ถึงแม้วันต่อมามันจะพุ่งมาเฉลี่ยอยู่ที่ ~5GB แต่ก็ไม่ขึ้นไปแตะ 6.75GB เหมือนก่อนอัพเกรดเลยครับ นอกจากนั้นแล้วตอนที่ดู Monitor ใน Datadog สิ่งที่เห็นอีกอย่างนึงคือ Load Average โดยรวมต่อ container ลดลงอย่างเห็นได้ชัดครับ ซึ่งค่อนข้างจะสอดคล้องกับผลที่ได้จาก Benchmark ใน Blog ข้างล่างนี้ครับ</p>
<blockquote>
<p><a href="https://hackernoon.com/which-is-the-fastest-version-of-python-2ae7c61a6b2b">Which is the fastest version of Python? | HackerNoon</a>
Of course, “it depends”, but what does it depend on and how can you assess which is the fastest version of Python for your application? Is Python 3 slower than Python 2? Which version of Python 3 is the fastest and what other options do you have for speed? Using the performance suite utility The cor…
— Hackernoon logo, Anthony Shaw</p>
</blockquote>
<h1 id="สรป">สรุป</h1>
<p><strong>การอัพเกรดมีความเสี่ยงนะครับ โปรดใช้ความระมัดระวังในการอัพเกรด</strong> แต่ความคุ้มค่าที่ได้มาก็คุ้มที่จะเหนื่อยอยู่ครับทั้งฟีเจอร์ใหม่ๆ ของภาษาและ Library ที่เกี่ยวข้อง</p>
<p>อีกอย่างที่สำคัญและอยากจะฝากไว้คือ Unit Test ครับ เราเขียน Unit Test ไม่ใช่แค่ให้มันผ่านๆ ไป แต่หัวใจของมันคือทำให้เรามั่นใจว่า ตัว Unit ของ Software เราจะยังทำงานเหมือนเดิม ถ้าเราทำการเปลี่ยนแปลงอะไรๆ ใน codebase ครับ</p>
<p>ก็ขอบคุณทุกคนที่อ่านมาจนถึงบรรทัดนี้ครับ หวังว่าจะเป็นประโยชน์แล้วก็ช่วยให้คนที่กำลังลังเลจะใช้ Python 3.7 สบายใจขึ้น แล้วพบกันใหม่ Entry หน้าสวัสดีครับ</p>
<hr>
<p>Original post at: <a href="https://yothinix.medium.com/share-%E0%B8%9B%E0%B8%A3%E0%B8%B0%E0%B8%AA%E0%B8%9A%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%93%E0%B9%8C-upgrade-python-3-7-3f27300d966d">https://yothinix.medium.com/share-ประสบการณ์-upgrade-python-3-7-3f27300d966d</a></p>
]]></content:encoded></item><item><title>สร้าง Load Test ง่ายๆ ด้วย Locust</title><link>https://yothinix-com.pages.dev/python-load-test-with-locust/</link><pubDate>Wed, 29 Aug 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/python-load-test-with-locust/</guid><description>&lt;p&gt;#pythontricks วันนี้ครับ พอดีวันนี้มีปัญหากับ API แล้วต้องทำ Load test แบบง่ายๆ เร็วๆ เลยไปเจอ &lt;a href="https://locust.io/"&gt;locustio&lt;/a&gt; มาครับ และมันง่ายมากเลย&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;Locust&lt;/strong&gt; เป็น Load testing tool ตัวนึงครับ ผมไม่เคยใช้ตัวอื่นแต่พอมาใช้ตัวนี้ วันนี้ เช้านี้ บอกได้เลยว่ามันใช้ง่ายมากครับ เพียงแค่เราสร้าง &lt;strong&gt;TaskSet&lt;/strong&gt; ขึ้นมา โดย TaskSet เนี่ยจะเป็นคล้ายๆ Test Case ว่าเราจะทำอะไรกับ Server บ้าง ในเคสนี้ก็คือยิง HTTP Request ครับ ลักษณะการเขียนจะคล้ายๆ กับพวกเทสของ Django หรือ DRF เลยคือเป็น self.client.&amp;lt;method&amp;gt;&lt;br&gt;
&lt;br&gt;
พอเราเขียน TaskSet เสร็จแล้วเราก็ต้องสร้างอีก Class นึงครับเป็น &lt;strong&gt;Locust class&lt;/strong&gt; ซึ่ง Class นี้จะเป็นตัวแทนของ User ที่ใช้ TaskSet อีกทีนึง ซึ่งเราสามารถกำหนด min_wait และ max_wait ได้ซึ่งจะเป็นค่าที่ตัว Locust ใช้สุ่มในการ Generate Task ขึ้นมาครับ พอเราเขียนเสร็จแล้วหน้าตาของ locustfile.py ก็จะประมาณนี้&lt;/p&gt;</description><content:encoded><![CDATA[<p>#pythontricks วันนี้ครับ พอดีวันนี้มีปัญหากับ API แล้วต้องทำ Load test แบบง่ายๆ เร็วๆ เลยไปเจอ <a href="https://locust.io/">locustio</a> มาครับ และมันง่ายมากเลย<br>
<br>
<strong>Locust</strong> เป็น Load testing tool ตัวนึงครับ ผมไม่เคยใช้ตัวอื่นแต่พอมาใช้ตัวนี้ วันนี้ เช้านี้ บอกได้เลยว่ามันใช้ง่ายมากครับ เพียงแค่เราสร้าง <strong>TaskSet</strong> ขึ้นมา โดย TaskSet เนี่ยจะเป็นคล้ายๆ Test Case ว่าเราจะทำอะไรกับ Server บ้าง ในเคสนี้ก็คือยิง HTTP Request ครับ ลักษณะการเขียนจะคล้ายๆ กับพวกเทสของ Django หรือ DRF เลยคือเป็น self.client.&lt;method&gt;<br>
<br>
พอเราเขียน TaskSet เสร็จแล้วเราก็ต้องสร้างอีก Class นึงครับเป็น <strong>Locust class</strong> ซึ่ง Class นี้จะเป็นตัวแทนของ User ที่ใช้ TaskSet อีกทีนึง ซึ่งเราสามารถกำหนด min_wait และ max_wait ได้ซึ่งจะเป็นค่าที่ตัว Locust ใช้สุ่มในการ Generate Task ขึ้นมาครับ พอเราเขียนเสร็จแล้วหน้าตาของ locustfile.py ก็จะประมาณนี้</p>
<p><img src="/python-load-test-with-locust/1-GfNHFkfWBN9NKrEO031Oyw_hu_499efd21ce82da37.webp"
       srcset="/python-load-test-with-locust/1-GfNHFkfWBN9NKrEO031Oyw_hu_502f6c169b3cd4d1.webp 480w, /python-load-test-with-locust/1-GfNHFkfWBN9NKrEO031Oyw_hu_499efd21ce82da37.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="592"
       alt=""
       loading="lazy" decoding="async"></p>
<p>พอเราได้ Locustfile แล้วทีนี้เราก็ต้องสั่งรันครับ ซึ่งง่ายมากเพียงแค่สั่ง</p>
<blockquote>
<p>locust -f locustfile.py - -host=&lt;hostname&gt;</p>
</blockquote>
<p>แล้วตัว Locust จะรัน Server ขึ้นมาครับ เราสามารถเข้าไปได้ที่ localhost:8089 โดยมันจะให้เราใส่จำนวน Concurrent user ที่เราต้องการจะยิง แล้วก็อัตราการ Spawn user ขึ้นมาว่ากี่ user / วินาที ครับพอใส่ข้อมูลเรียบร้อยมันก็จะยิงทันทีเลยครับหน้าตาของตัว Server ก็จะประมาณนี้</p>
<p><img src="/python-load-test-with-locust/1-R68RSolcoBMKo288hco_Qg_hu_aec9c6be3e6b7af8.webp"
       srcset="/python-load-test-with-locust/1-R68RSolcoBMKo288hco_Qg_hu_18ed4429834c30a0.webp 480w, /python-load-test-with-locust/1-R68RSolcoBMKo288hco_Qg_hu_aec9c6be3e6b7af8.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="536"
       alt=""
       loading="lazy" decoding="async">
<em>หน้าสรุป Request ทั้งหมดที่ยิง</em></p>
<p><img src="/python-load-test-with-locust/1-Lx_SgpkNo1plcm7AU7BYvQ_hu_93070dad1f3ad5a.webp"
       srcset="/python-load-test-with-locust/1-Lx_SgpkNo1plcm7AU7BYvQ_hu_fbdf56d8057a9b92.webp 480w, /python-load-test-with-locust/1-Lx_SgpkNo1plcm7AU7BYvQ_hu_93070dad1f3ad5a.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="536"
       alt=""
       loading="lazy" decoding="async">
<em>มี Chart ให้ดูอัตราการโหลดด้วย</em></p>
<p>ก็สั้นๆ ประมาณนี้ครับ เพิ่งลองได้ไม่ถึงวันเลยเล่าได้แค่นี้ แต่ก็นับว่าเป็นเครื่องมือที่ยิงได้โหดพอสมควรเลยทีเดียว ทำเอา CPU ผมวิ่งจี๋เลย ถ้าอยากศึกษาเพิ่มเติมแนะนำที่เว็บของตัว Library เลยครับตามที่อยู่ข้างล่าง แล้วพบกันใหม่ Post หน้าครับ</p>
<blockquote>
<p><a href="https://locust.io">Locust.io</a>
An open source load testing tool. Define user behaviour with Python code, and swarm your system with millions of simultaneous users.
— Locust, Jonatan Heyman</p>
</blockquote>
<hr>
<p>Original post at: <a href="https://medium.com/pythonbycow/%E0%B8%AA%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%87-load-test-%E0%B8%87%E0%B9%88%E0%B8%B2%E0%B8%A2%E0%B9%86-%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2-locust-2d3123f2e8d2">https://medium.com/pythonbycow/สร้าง-load-test-ง่ายๆ-ด้วย-locust-2d3123f2e8d2</a></p>
]]></content:encoded></item><item><title>Patch ยังไงให้อ่านรู้เรื่อง</title><link>https://yothinix-com.pages.dev/readable-python-patching/</link><pubDate>Sat, 18 Aug 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/readable-python-patching/</guid><description>&lt;p&gt;สิ่งหนึ่งที่เราจะเจอหลังจากเขียน Unit Test มาได้ซักพักคือ มันจะมีบางอย่างที่เราควบคุมมันไม่ได้ครับ บางอย่างนั้นอาจจะเป็นไปได้ตั้งแต่ ค่าสุ่ม, เวลา, การอ่านเขียนไฟล์,​ การแก้ไข Database อะไรอย่างนี้เป็นต้น&lt;/p&gt;
&lt;p&gt;พอเรามาเจออะไรพวกนี้ มันจะเกิดคำถามขึ้นมาทันทีว่า แล้วเราจะเทสมันยังไง ถ้ามันเปลี่ยนตลอดเวลา คำตอบของคำถามนั้นก็คือ เราต้อง Mock มันครับ ซึ่ง Python มี standard library ไว้จัดการเรื่องนี้ครับคือ unittest.mock.patch&lt;/p&gt;
&lt;p&gt;Patch นั้นมีหลายท่า ก่อนหน้านี้ผมเคยเล่าให้ฟังบางส่วนแล้วว่าเราจะจัดการกับการ Patch หลายๆ module ยังไง ซึ่งใช้ &lt;strong&gt;ExitStack()&lt;/strong&gt; มาช่วยในการจัดการ context สนใจไปอ่านต่อได้ที่นี่ครับ&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://yothinix-com.pages.dev/python-exitstack/"&gt;Python - ExitStack แบบสั้นๆ&lt;/a&gt;
วันที่ 7 ของ #PythonTricksEveryday วันนี้ขอเสนอ ExitStack() ครับ มาช้าหน่อยนะครับวันนี้ มัวแต่ตื่นเต้น 1,000 likes โอเค เข้าเรื่องดีกว่า ก่อนจะไปรู้จัก ExitStack เราต้องรู้จักสิ่งที่เรียกว่า context manager ก่อนครับ context manager
— Yothinix, Yothin Muangsommuk&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;แต่จริงๆ เราสามารถใช้ patch ได้ถึง 3 แบบเลย แล้วแต่สถานการณ์ครับ&lt;/p&gt;</description><content:encoded><![CDATA[<p>สิ่งหนึ่งที่เราจะเจอหลังจากเขียน Unit Test มาได้ซักพักคือ มันจะมีบางอย่างที่เราควบคุมมันไม่ได้ครับ บางอย่างนั้นอาจจะเป็นไปได้ตั้งแต่ ค่าสุ่ม, เวลา, การอ่านเขียนไฟล์,​ การแก้ไข Database อะไรอย่างนี้เป็นต้น</p>
<p>พอเรามาเจออะไรพวกนี้ มันจะเกิดคำถามขึ้นมาทันทีว่า แล้วเราจะเทสมันยังไง ถ้ามันเปลี่ยนตลอดเวลา คำตอบของคำถามนั้นก็คือ เราต้อง Mock มันครับ ซึ่ง Python มี standard library ไว้จัดการเรื่องนี้ครับคือ unittest.mock.patch</p>
<p>Patch นั้นมีหลายท่า ก่อนหน้านี้ผมเคยเล่าให้ฟังบางส่วนแล้วว่าเราจะจัดการกับการ Patch หลายๆ module ยังไง ซึ่งใช้ <strong>ExitStack()</strong> มาช่วยในการจัดการ context สนใจไปอ่านต่อได้ที่นี่ครับ</p>
<blockquote>
<p><a href="/python-exitstack/">Python - ExitStack แบบสั้นๆ</a>
วันที่ 7 ของ #PythonTricksEveryday วันนี้ขอเสนอ ExitStack() ครับ มาช้าหน่อยนะครับวันนี้ มัวแต่ตื่นเต้น 1,000 likes โอเค เข้าเรื่องดีกว่า ก่อนจะไปรู้จัก ExitStack เราต้องรู้จักสิ่งที่เรียกว่า context manager ก่อนครับ context manager
— Yothinix, Yothin Muangsommuk</p>
</blockquote>
<p>แต่จริงๆ เราสามารถใช้ patch ได้ถึง 3 แบบเลย แล้วแต่สถานการณ์ครับ</p>
<h1 id="patch-decorator">patch decorator</h1>
<p>แบบแรกคือ ใช้เป็น decorator ครับแบบนี้จะเหมาะกับ การที่เรา patch ฟังก์ชั่นจำนวนน้อยๆ ซึ่งพอมันน้อยเนี่ยมันจะยังไม่รบกวน test function signature มาก ทำให้เรา ยังพออ่านได้อยู่ว่า Test Case นั้นชื่ออะไร</p>
<p><img src="/readable-python-patching/1-TJKEDuoWKpAMbFasnLK7BQ_hu_2e0a0249fb85c0d.webp"
       srcset="/readable-python-patching/1-TJKEDuoWKpAMbFasnLK7BQ_hu_1077ba29f266953c.webp 480w, /readable-python-patching/1-TJKEDuoWKpAMbFasnLK7BQ_hu_2e0a0249fb85c0d.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="662"
       alt=""
       loading="lazy" decoding="async"></p>
<h1 id="patch-context">patch context</h1>
<p>แบบที่สอง น่าจะเคยเห็นมาจาก Tricks ข้างบนแล้วนะครับ คือเราใช้ภายใต้ context manager แทน แบบนี้ทำให้เราไม่ต้องมี decorator มากวนใจตรง function signature แล้วครับ ตัว patch จะถูกใช้ใน test function เลย แต่ข้อเสียคือ เราก็จะเสีย indent ไปนิดหน่อยตอนเราสั่งรัน function ที่เราจะเทส</p>
<p><img src="/readable-python-patching/1-e_frPpTEgycEDG9d9H6Uzw_hu_889b4594f78bf0d4.webp"
       srcset="/readable-python-patching/1-e_frPpTEgycEDG9d9H6Uzw_hu_b908d4db78b2ce8d.webp 480w, /readable-python-patching/1-e_frPpTEgycEDG9d9H6Uzw_hu_889b4594f78bf0d4.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="638"
       alt=""
       loading="lazy" decoding="async"></p>
<h1 id="patch-manually">patch manually</h1>
<p>แบบสุดท้าย คือเราจะสั่ง patch เองครับผ่าน method start() และหยุด patch ผ่าน stop() พอเราสั่ง patch แบบนี้แล้ว มันเปิดโอกาสให้เราทำอะไรได้หลายๆ อย่างมากเช่น เรา patch ไว้ตั้งแต่ <strong>setUp</strong> เลย ถ้าฟังก์ชั่นนี้ต้อง patch ทุก TestCase ซึ่งจะช่วยลด Duplication ของ patch ใน code ไปได้ หรือเราอยากให้ TestCase เรามี indent น้อยๆ ก็จะช่วยได้เหมือนกัน</p>
<p><img src="/readable-python-patching/1-AnjP7mWfJWCQn4EjsCkfZA_hu_b56045a0ba86ab7a.webp"
       srcset="/readable-python-patching/1-AnjP7mWfJWCQn4EjsCkfZA_hu_fa3937a220d26063.webp 480w, /readable-python-patching/1-AnjP7mWfJWCQn4EjsCkfZA_hu_b56045a0ba86ab7a.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="802"
       alt=""
       loading="lazy" decoding="async"></p>
<p>แต่พลังที่ยิ่งใหญ่มาพร้อมกับความรับผิดชอบที่ใหญ่ยิ่งครับ วิธีนี้สำคัญสุดเลยคือ <strong>ต้องอย่าลืมหยุด patch</strong> ครับ จะสังเกตุว่า ตอนเราใช้ decorator หรือ context manager เราไม่เคยต้องกังวลเรื่องนี้เลย เป็นเพราะว่าพอเราใช้สองอย่างนั้น พอออกจาก context มันจะหยุด path ให้เราอัตโนมัติครับ</p>
<p>ขอสรุปสั้นๆ อีกทีละกันว่าเราควรควรใช้ Patch ท่าไหนตอนไหน</p>
<ul>
<li><strong>patch decorator</strong> ใช้เวลาที่เรา patch แค่หนึ่งฟังก์ชั่น</li>
<li><strong>patch as context manager</strong> ใช้เวลาที่เราจะ patch หลายๆ ฟังก์ชั่น</li>
<li><strong>patch manually start / stop</strong> ใช้เวลาต้อง patch เหมือนๆ กันทุกฟังก์ชั่นใน Test Suite หรือลดความซ้ำซ้อนของโค้ด</li>
</ul>
<p>เป็นยังไงกันบ้างครับ การจะ Mock นี่ไม่ใช่เรื่องเล็กๆ เลย ข้อเสียของ patch ของ Python อีกอย่างนึงคือ <a href="https://docs.python.org/3/library/unittest.mock.html">Official Document</a> อ่านยากมากครับ กว่าจะเข้าใจวิธีใช้ ต้องบอกว่าเทคนิคนี้ผมก็อ่านๆ มาจากหลายๆ Blog เหมือนกันครับ ใครสนใจศึกษาเพิ่มเติมก็ลองดูได้ตามลิ้งข้างล่างเลยครับ</p>
<h1 id="reference">Reference</h1>
<blockquote>
<p><a href="https://chase-seibert.github.io/blog/2015/06/25/python-mocking-cookbook.html">Python Mock Cookbook</a>
The python mock library is one of the awesome things about working in Python. No matter what code you’re unit testing, it’s possible to mock out various pieces with very little test code. That being said, it’s sometimes difficult to figure out the exact syntax for your situation. I attribute this to…
— Chase Seibert Blog, Chase Seibert</p>
</blockquote>
<blockquote>
<p><a href="https://www.pythonsheets.com/notes/python-tests.html">Test — pysheeet</a>
— Logo</p>
</blockquote>
<blockquote>
<p><a href="https://treyhunner.com/2014/10/the-many-flavors-of-mock-dot-patch/">The many flavors of mock.patch</a>
I write a lot of unit tests. Unfortunately, my code often requires monkey patching to be properly unit tested. I frequently use the patch function …
— Trey Hunner, Trey Hunner</p>
</blockquote>
<hr>
<p>Original post at: <a href="https://medium.com/pythonbycow/patch-%E0%B8%A2%E0%B8%B1%E0%B8%87%E0%B9%84%E0%B8%87%E0%B9%83%E0%B8%AB%E0%B9%89%E0%B8%AD%E0%B9%88%E0%B8%B2%E0%B8%99%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B9%80%E0%B8%A3%E0%B8%B7%E0%B9%88%E0%B8%AD%E0%B8%87-8d504b01b1ec">https://medium.com/pythonbycow/patch-ยังไงให้อ่านรู้เรื่อง-8d504b01b1ec</a></p>
]]></content:encoded></item><item><title>Python - ExitStack แบบสั้นๆ</title><link>https://yothinix-com.pages.dev/python-exitstack/</link><pubDate>Tue, 31 Jul 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/python-exitstack/</guid><description>&lt;p&gt;วันที่ 7 ของ &lt;a href="https://www.facebook.com/hashtag/pythontrickseveryday?__eep__=6&amp;amp;__tn__=*NK*F"&gt;#PythonTricksEveryday&lt;/a&gt; วันนี้ขอเสนอ ExitStack() ครับ&lt;br&gt;
มาช้าหน่อยนะครับวันนี้ มัวแต่ตื่นเต้น 1,000 likes&lt;/p&gt;
&lt;p&gt;โอเค เข้าเรื่องดีกว่า ก่อนจะไปรู้จัก ExitStack เราต้องรู้จักสิ่งที่เรียกว่า context manager ก่อนครับ context manager เนี่ยจะเป็นตัวจำกัดการเข้าถึงและปล่อย Resource หนึ่งๆ ซึ่ง keyword ที่เราคุ้นเคยที่สุดน่าจะเป็น with ใช่มั้ยครับ ตัว Resource ที่เราพูดถึงกันนี้ง่ายที่สุดก็น่าจะเป็นไฟล์ หรือการต่อ database อะไรเทือกนี้ใช่มั้ยครับ&lt;br&gt;
&lt;br&gt;
ทีนี้เวลาเราจะเปิดไฟล์หลายๆ ไฟล์ สิ่งที่เกิดขึ้นคือมันก็จะเกิดอาการ with ซ้อน with ไปเรื่อยๆ จนกระทั่ง Python 3.3 ได้เพิ่ม ExitStack() เข้าไปใน contextlib ครับโดย ExitStack() ตัวนี้จะช่วยจัดการเกี่ยวกับ context manager ได้ดียิ่งขึ้นกว่า nested with ที่เคยใช้กันมา&lt;br&gt;
&lt;br&gt;
แต่ในเคสที่ผมกำลังพูดถึงนี่คือการเขียน Unit Test ครับและเป็นเทสที่มี Mock เข้ามาเกี่ยวข้องด้วย และที่พิเศษกว่านั้นคือต้อง Mock เยอะๆ ด้วยครับ&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;จะเห็นว่า example_function เรามีของที่มี side effect แล้วเราต้อง Mock() อยู่สองอย่างใช่มั้ยครับคือ randint และ datetime.now() แต่ก่อนตอนผมเขียน Unit Test ที่ต้อง Mock อะไรแบบนี้ ผมจะไปเหมือน test case แรกเลยครับ คือใช้เป็น decorator patch() แปะอยู่บนหัวของ test case วิธีนี้ใช้ง่ายครับ แต่จะเริ่มมีปัญหาตามมาเมื่อเริ่ม Mock() มากกว่าหนึ่งตัว&lt;br&gt;
&lt;br&gt;
ปัญหาแรกคือ มือใหม่จะสับสนมากว่าที่ patch เรียงๆ กันเนี่ย argument ของ test case มันคือตัวไหน สำหรับคนที่ยังไม่รู้นะครับ argument ของ decorator จะเรียงจากในไปนอกครับ&lt;/p&gt;</description><content:encoded><![CDATA[<p>วันที่ 7 ของ <a href="https://www.facebook.com/hashtag/pythontrickseveryday?__eep__=6&amp;__tn__=*NK*F">#PythonTricksEveryday</a> วันนี้ขอเสนอ ExitStack() ครับ<br>
มาช้าหน่อยนะครับวันนี้ มัวแต่ตื่นเต้น 1,000 likes</p>
<p>โอเค เข้าเรื่องดีกว่า ก่อนจะไปรู้จัก ExitStack เราต้องรู้จักสิ่งที่เรียกว่า context manager ก่อนครับ context manager เนี่ยจะเป็นตัวจำกัดการเข้าถึงและปล่อย Resource หนึ่งๆ ซึ่ง keyword ที่เราคุ้นเคยที่สุดน่าจะเป็น with ใช่มั้ยครับ ตัว Resource ที่เราพูดถึงกันนี้ง่ายที่สุดก็น่าจะเป็นไฟล์ หรือการต่อ database อะไรเทือกนี้ใช่มั้ยครับ<br>
<br>
ทีนี้เวลาเราจะเปิดไฟล์หลายๆ ไฟล์ สิ่งที่เกิดขึ้นคือมันก็จะเกิดอาการ with ซ้อน with ไปเรื่อยๆ จนกระทั่ง Python 3.3 ได้เพิ่ม ExitStack() เข้าไปใน contextlib ครับโดย ExitStack() ตัวนี้จะช่วยจัดการเกี่ยวกับ context manager ได้ดียิ่งขึ้นกว่า nested with ที่เคยใช้กันมา<br>
<br>
แต่ในเคสที่ผมกำลังพูดถึงนี่คือการเขียน Unit Test ครับและเป็นเทสที่มี Mock เข้ามาเกี่ยวข้องด้วย และที่พิเศษกว่านั้นคือต้อง Mock เยอะๆ ด้วยครับ</p>
<hr>
<p>จะเห็นว่า example_function เรามีของที่มี side effect แล้วเราต้อง Mock() อยู่สองอย่างใช่มั้ยครับคือ randint และ datetime.now() แต่ก่อนตอนผมเขียน Unit Test ที่ต้อง Mock อะไรแบบนี้ ผมจะไปเหมือน test case แรกเลยครับ คือใช้เป็น decorator patch() แปะอยู่บนหัวของ test case วิธีนี้ใช้ง่ายครับ แต่จะเริ่มมีปัญหาตามมาเมื่อเริ่ม Mock() มากกว่าหนึ่งตัว<br>
<br>
ปัญหาแรกคือ มือใหม่จะสับสนมากว่าที่ patch เรียงๆ กันเนี่ย argument ของ test case มันคือตัวไหน สำหรับคนที่ยังไม่รู้นะครับ argument ของ decorator จะเรียงจากในไปนอกครับ</p>
<p>ปัญหาที่สองคือ ถ้า decorator เยอะมากขึ้นเรื่อยๆ เราจะเริ่มหา test case ไม่เจอครับ เพราะ function signature เรามีแต่ decorator แถมยิ่ง patch decorator มากตัว arguments ของ test case ก็มากตามไปด้วยครับ</p>
<hr>
<p>จะเห็นว่าในเคสที่สองผมใช้ ExitStack() ร่วมกับ context manager ในการประกาศ patch แทน ซึ่งถามว่าบรรทัดมันน้อยลงมั้ย ก็ไม่ แต่สิ่งที่เราได้กลับมาคือชื่อ test case หรือ function signature เรา clean มากครับ ทำให้มองหาเทสที่จะเจอได้ง่าย และเรายังสามารถแบ่ง statement ในเทสเป็น Arrange / Act / Assert ได้เหมือนเดิมครับ<br>
<br>
ต้องบอกว่า Trick นี้ผมไปเจอโดยบังเอิญ เพราะเกิดจากปัญหาที่ผมพูดถึงข้างต้นนั่นแหละครับ จริงๆ พี่ @zkan เคยเขียน Blog พูดถึงเรื่องนี้ตอนผมเอามาใช้กับทีม <a href="https://www.facebook.com/prontotools/?__tn__=kK*F">Pronto Tools</a> ได้ซักพัก ถ้าใครอ่านตรงนี้แล้วงงๆ ลองไปอ่านที่พี่กานต์เขียนได้ครับ</p>
<h2 id="reference">Reference</h2>
<p>- Blog เกี่ยวกับ ExitStack() โดย @zkan <a href="https://l.facebook.com/l.php?u=https%3A%2F%2Fbit.ly%2F2Kegi3D%3Ffbclid%3DIwAR2v_Ttn3gQSeggWFtfTGcrKHOGHrN8CKY3Vno2lTE9j6GyyJvW9V85xaII&amp;h=AT1mlZYuXsJcwN8-0KEkLLO_lvOLEl_2A13PwGvLt6-qJO103RzrrfE6NMOA4ikm-SwLPmRxJi0Fl_fi7w7rGIQuweg61lhlpOxSY2NTDLNXveV3fdq54b6OOr06zoOktnGCk2wEDwIDDNIJYbcI8LQ&amp;__tn__=-UK*F">https://bit.ly/2Kegi3D</a><br>
- <a href="https://docs.python.org/3/library/contextlib.html?fbclid=IwAR23qbb-5-n-3ayVtOjd_M3J_hJ4fFAP7wT55g1vArEOoYPuscJZ_aQPc00">https://docs.python.org/3/library/contextlib.html</a></p>
<hr>
<p>Original post at: <a href="https://www.facebook.com/writepythontoscarecow/photos/a.206798910040303/233059164080944/?type=3&amp;theater">https://www.facebook.com/writepythontoscarecow/photos/a.206798910040303/233059164080944/?type=3&amp;theater</a></p>
]]></content:encoded></item><item><title>Why I love Python so much</title><link>https://yothinix-com.pages.dev/why-i-love-python-so-much/</link><pubDate>Tue, 31 Jul 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/why-i-love-python-so-much/</guid><description>&lt;p&gt;ในโอกาสที่เพจ &lt;a href="https://www.facebook.com/writepythontoscarecow/"&gt;เขียนงูให้วัวกลัว&lt;/a&gt; ครบ 1000 likes ผมเลยคิดได้ว่า เออ อยู่ดีๆ ผมก็มาทำเพจเอามันส์ อยากเขียนอะไรก็เขียน แล้วก็มาสงสัยกับตัวเองบางครั้งว่า ทำไมเราถึงมีความรู้สึกอยากจะทำเพจนี้มากขนาดนี้ ผมเลยมองย้อนกลับมาหาตัวเองว่า ทำไม เราถึงชอบภาษานี้มากขนาดนี้ มันมีเหตุผลอะไร ผมจะพาไปไล่ดูครับว่าทำไมผมถึงรักภาษานี้มากและอาจจะเป็นเหตุผลให้คุณรักภาษานี้เหมือนกันก็ได้&lt;/p&gt;
&lt;h1 id="beautiful-is-better-than-ugly-"&gt;Beautiful is better than ugly 💄&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://yothinix-com.pages.dev/why-i-love-python-so-much/1-dypAPjPDUB2bVoMJzkMtfw_hu_1586b6ed741baad9.webp"
srcset="https://yothinix-com.pages.dev/why-i-love-python-so-much/1-dypAPjPDUB2bVoMJzkMtfw_hu_9a9ecb2cfaae3566.webp 480w, https://yothinix-com.pages.dev/why-i-love-python-so-much/1-dypAPjPDUB2bVoMJzkMtfw_hu_1586b6ed741baad9.webp 960w"
sizes="(max-width: 960px) 100vw, 960px"
width="960" height="185"
alt=""
loading="lazy" decoding="async"&gt;
&lt;em&gt;hello world แบบ Python นะครับ&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;ส่วนแรกที่ผมชอบเกี่ยวกับภาษานี้คือ Semantic มันครับ เรื่องนี้ต้องย้อนไปถึง Design Philosophy ของตัวภาษาเลยว่ามันถูกออกแบบมาให้เป็นภาษาที่อ่านได้ง่ายมากๆ โดยใช้ keyword ภาษาอังกฤษ แทนที่จะใช้เครื่องหมายต่างๆ รวมไปถึงใช้ Indentation แทนที่จะใช้ curry bracket ในการกำหนด scope เป็นต้น&lt;/p&gt;
&lt;p&gt;ด้วยตัวภาษาเองยังเป็นภาษา Multi-paradigm ทำให้รองรับรูปแบบการเขียนโปรแกรมหลายรูปแบบมากตั้งแต่ Imperative, Object Oriented, Functional, Procedural และ Reflective ทำให้เราไม่ถูกจำกัดแนวคิดในการแก้ปัญหาต่างๆ ด้วยภาษานี้ถึงแม้มันจะขัดกับ Zen of Python ข้อ &lt;em&gt;There should be one — and preferably only one — obvious way to do it.&lt;/em&gt; ก็เถอะ&lt;/p&gt;</description><content:encoded><![CDATA[<p>ในโอกาสที่เพจ <a href="https://www.facebook.com/writepythontoscarecow/">เขียนงูให้วัวกลัว</a> ครบ 1000 likes ผมเลยคิดได้ว่า เออ อยู่ดีๆ ผมก็มาทำเพจเอามันส์ อยากเขียนอะไรก็เขียน แล้วก็มาสงสัยกับตัวเองบางครั้งว่า ทำไมเราถึงมีความรู้สึกอยากจะทำเพจนี้มากขนาดนี้ ผมเลยมองย้อนกลับมาหาตัวเองว่า ทำไม เราถึงชอบภาษานี้มากขนาดนี้ มันมีเหตุผลอะไร ผมจะพาไปไล่ดูครับว่าทำไมผมถึงรักภาษานี้มากและอาจจะเป็นเหตุผลให้คุณรักภาษานี้เหมือนกันก็ได้</p>
<h1 id="beautiful-is-better-than-ugly-">Beautiful is better than ugly 💄</h1>
<p><img src="/why-i-love-python-so-much/1-dypAPjPDUB2bVoMJzkMtfw_hu_1586b6ed741baad9.webp"
       srcset="/why-i-love-python-so-much/1-dypAPjPDUB2bVoMJzkMtfw_hu_9a9ecb2cfaae3566.webp 480w, /why-i-love-python-so-much/1-dypAPjPDUB2bVoMJzkMtfw_hu_1586b6ed741baad9.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="185"
       alt=""
       loading="lazy" decoding="async">
<em>hello world แบบ Python นะครับ</em></p>
<p>ส่วนแรกที่ผมชอบเกี่ยวกับภาษานี้คือ Semantic มันครับ เรื่องนี้ต้องย้อนไปถึง Design Philosophy ของตัวภาษาเลยว่ามันถูกออกแบบมาให้เป็นภาษาที่อ่านได้ง่ายมากๆ โดยใช้ keyword ภาษาอังกฤษ แทนที่จะใช้เครื่องหมายต่างๆ รวมไปถึงใช้ Indentation แทนที่จะใช้ curry bracket ในการกำหนด scope เป็นต้น</p>
<p>ด้วยตัวภาษาเองยังเป็นภาษา Multi-paradigm ทำให้รองรับรูปแบบการเขียนโปรแกรมหลายรูปแบบมากตั้งแต่ Imperative, Object Oriented, Functional, Procedural และ Reflective ทำให้เราไม่ถูกจำกัดแนวคิดในการแก้ปัญหาต่างๆ ด้วยภาษานี้ถึงแม้มันจะขัดกับ Zen of Python ข้อ <em>There should be one — and preferably only one — obvious way to do it.</em> ก็เถอะ</p>
<p>นอกจากนี้แล้วตัวภาษาเองยังมี Coding Style (<a href="https://www.python.org/dev/peps/pep-0008/">PEP8</a>), Zen of Python (<a href="https://www.python.org/dev/peps/pep-0020/">PEP20</a>), Linter (<a href="http://flake8.pycqa.org/en/latest/">Flake8</a>, <a href="https://www.pylint.org/">PyLint</a>) รวมไปถึง Formatter (<a href="https://github.com/google/yapf">yapf</a>, <a href="https://github.com/ambv/black">Black</a>) ฯลฯ อีกหลายอย่างที่ช่วยเราในเรื่อง Code Convention ถึงแม้ว่าภาษาสมัยใหม่หลายภาษาจะมีของพวกนี้มาให้ในตัว แต่อย่างน้อย Python ก็มีเครื่องมือพวกนี้ให้เลือกใช้หลากหลาย และทำให้โค้ดเราเป็นไปในทางเดียวกันครับ</p>
<h1 id="cheeseshop-">CheeseShop 🧀</h1>
<p>ถ้าใครไม่รู้จัก CheeseShop นะครับ มันคือ codename ของ PyPI หรือ <strong>Python Package Index</strong> เอง ส่วนนี้สำคัญยังไง สิ่งที่สำคัญอย่างนึงของทุกภาษาคือ Package repository ครับ ทำให้เราทำงานแบบ Modular programming ได้ครับ</p>
<p>Modular Programming คือ concept ที่ว่าเราไม่ต้องเขียนทุกอย่างขึ้นมาเองใหม่ทั้งหมด ปัญหาบางปัญหามีคนแก้ไปแล้ว เราก็ไปเอาโค้ดเค้ามาใช้ ซึ่ง ณ ตอนที่เขียนอยู่นี่ PyPI มี Package ให้เราเลือกใช้อยู่ทั้งสิ้น 147,551 projects ครับ ไม่น้อยเลยทีเดียว ตั้งแต่ Library เล็กๆ ที่ใช้แก้ปัญหาดึงค่าของจาก Dictionary ออกมา ไปจนถึง Library ในการทำ Machine Learning คำนวณกลศาสตร์ระหว่างดาวเคราะห์เลยทีเดียว</p>
<p>จริงๆ PyPI เคยเป็นหนึ่งในจุดอ่อนของ Python เหมือนกันนะครับ ด้วยหน้าตาที่โบราณมาก จนผมไม่เคยคิดจะไปหา Project ในนั้นเลย แต่เมื่อไม่กี่เดือนก่อน PyPI เพิ่ง Rewrite ใหม่ทั้งหมดบน Pyramid Framework แล้วกลายเป็น PyPI อย่างที่เราเห็นทุกวันนี้ครับ น่าใช้ขึ้นมากเลยทีเดียว</p>
<p><img src="/why-i-love-python-so-much/1-GuqlT4ly0pUvFTbmvV1Hfg_hu_8db153cc76797824.webp"
       srcset="/why-i-love-python-so-much/1-GuqlT4ly0pUvFTbmvV1Hfg_hu_960cc2ef209d0036.webp 480w, /why-i-love-python-so-much/1-GuqlT4ly0pUvFTbmvV1Hfg_hu_8db153cc76797824.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="782"
       alt=""
       loading="lazy" decoding="async">
<em>หน้าตาปัจจุบันของ <a href="https://pypi.org/">https://pypi.org/</a> ครับ</em></p>
<h1 id="community-">Community 🙋‍♂️🙋‍♀️</h1>
<p>ความเจ๋งของ Python Community อย่างนึงคือ มันไม่ค่อยมีดราม่าครับ นานๆ ทีจะมี อย่างเช่นกรณี PEP 572 — Assignment Expressions และ Guido ประกาศลาพักไม่มีกำหนดจากตำแหน่ง BDFL ตลอดมาก็แทบไม่มีดราม่าเลยครับ นอกจากนั้นแล้วทั่วโลกยังมีงาน PyCon จัดตั้งแต่ United State มาจนถึง Australia และล่าสุดในไทยเราก็เพิ่งมีจัด PyCon Thailand ครับ</p>
<blockquote>
<p><a href="https://stackoverflow.blog/2017/09/06/incredible-growth-python/">The Incredible Growth of Python</a>
When we focus on high-income countries, the growth of Python is even larger than it might appear from tools like Stack Overflow Trends.
— Stack Overflow Blog, David Robinson</p>
</blockquote>
<p>ในส่วนของการเติบโตนั้น Python เป็นภาษาที่มีอัตราการเติบโตเร็วที่สุดในปีนี้เลยครับ จาก Stack Overflow Trends ซึ่งมามองในอีกมุมนึง มันดีรึเปล่าหว่า เป็นเพราะมีคนไปถามเยอะ หรือตัวภาษามันมีปัญหาบางอย่าง เรื่องนี้ก็มองได้หลายมุมเหมือนกัน</p>
<h1 id="django-">Django 🎸</h1>
<p><img src="/why-i-love-python-so-much/1-4ii0PMQ89R04XYQWSHaUKg_hu_9f5267ecdb4b1448.webp"
       srcset="/why-i-love-python-so-much/1-4ii0PMQ89R04XYQWSHaUKg_hu_9f5267ecdb4b1448.webp 162w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="162" height="200"
       alt=""
       loading="lazy" decoding="async">
<em>Django Reinhardt นักกีตาร์ (ชื่อ Framework เอามาจากคนนี้แหละ)</em></p>
<p>อันนี้เพราะว่างานผมอาจจะเกี่ยวข้องกับทาง Web Application เลยมีเรื่องนี้เข้ามาเกี่ยวข้องครับ คือ Django เนี่ยเป็น Web Framework ที่เป็นหนึ่งใน Goto ถ้าใช้ Python ครับอีกตัวก็ Flask แต่ก็แล้วแต่ลักษณะงานด้วย ตัว Django เองเนี่ย สามารถสร้าง Databases แล้วทำเป็น REST API และมีหน้า Admin สวยๆ ไว้จัดการภายในไม่กี่นาที ต้องขอบคุณพลังของ <a href="http://www.django-rest-framework.org/">Django REST Framework</a> ด้วยอีกตัวนึงที่ทำให้การสร้าง REST API มันไวขนาดนี้</p>
<p>นอกจากนั้นแล้วตัว Django เองยัง Extends ได้อีกเยอะมาก ซึ่งมากแค่ไหนก็ลองดูได้ที่เว็บนี้เลยครับ</p>
<blockquote>
<p><a href="https://github.com/wsvincent/awesome-django">GitHub - wsvincent/awesome-django: A curated list of awesome things related to Django</a>
A curated list of awesome things related to Django - GitHub - wsvincent/awesome-django: A curated list of awesome things related to Django
— GitHub, wsvincent</p>
</blockquote>
<p>ส่วนเรื่อง Maturity ก็ไม่ต้องกังวลครับเพราะยังมีบริษัทระดับโลกยังใช้งาน Django อยู่คือ Instagram และตัว Framework เองก็ยังพัฒนาอยู่เรื่อยๆ ทำให้ไม่ต้องห่วงว่าวันนี้ พรุ่งนี้ Django ที่เราใช้มันจะตกยุคนะครับ</p>
<p>เท่าที่คิดออกมันก็ประมาณนี้ครับ ช่วงที่ผ่านมาอาจจะมีปันใจไปให้ภาษาอื่นบ้าง แต่ภาษานี้ก็เป็นที่หนึ่งในใจมาตลอดครับ สุดท้ายนี้ต้องขอบคุณทุกคนมากๆ นะครับที่มารับชมเพจเล็กๆ เพจนี้ ใจผมเองก็อยากจะเล่าเรื่องต่างๆ เกี่ยวกับตัวภาษาออกมาให้มากๆ เพราะโดยตัวภาษาเองก็มีอะไรให้พูดถึงได้ไม่หมด ไม่สิ้นเลยครับ แล้วพบกันในเพจ สวัสดีครับ</p>
<blockquote>
<p><a href="https://www.facebook.com/writepythontoscarecow/">เขียนงูให้วัวกลัว</a>
เขียนงูให้วัวกลัว. 5,199 likes · 1 talking about this. เล่าทุกเรื่องเกี่ยวกับไพธอน ตกลงวัวตัวผู้หรือตัวเมีย
— Home</p>
</blockquote>
<p>ปล.ตอนนี้ทางเพจมีกิจกรรมให้ร่วมสนุกกันนะครับ เพียงแค่เขียนบทความเกี่ยวกับภาษา Python อะไรก็ได้ แล้วแปะไว้ใน comment ของโพสนี้ <a href="https://bit.ly/2M7Jqvb">https://bit.ly/2M7Jqvb</a> ภายในวันที่ 6 สิงหาคมนี้ ทางผมจะสุ่มแจก Key ของ PyCharm Profession Edition: 6 month นะครับ มาร่วมสนุกกันได้ครับ</p>
<hr>
<p>Original Post at: <a href="https://yothinix.medium.com/why-i-love-python-so-much-a47e24855088">https://yothinix.medium.com/why-i-love-python-so-much-a47e24855088</a></p>
]]></content:encoded></item><item><title>Dedent your multiline string</title><link>https://yothinix-com.pages.dev/python-dedent-your-multiline-string/</link><pubDate>Thu, 26 Jul 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/python-dedent-your-multiline-string/</guid><description>&lt;p&gt;วันที่ 2 ของ #PythonTricksEveryday นะครับ ไหนๆ ก็เป็นวันสุดท้ายของการทำงานก่อนจะถึงวันหยุดยาว ขอแนะนำด้วย Tricks เล็กๆ ที่จะช่วยให้การทำงานกับ Multiline String เราดีขึ้นครับ&lt;/p&gt;
&lt;p&gt;สมมติว่าเรามี String ยาวๆ ที่ต้องมี Indent สวยๆ เช่น Email หรือ Code snippet อย่างในภาพ แล้วเราต้องการนำมันไปใช้งานเช่นส่งอีเมล์หรือ Print report อะไรแบบนี้&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yothinix-com.pages.dev/python-dedent-your-multiline-string/1-W1kbbb4iiGbP7KXb_BUwBQ_hu_128cbfc369b23ee7.webp"
srcset="https://yothinix-com.pages.dev/python-dedent-your-multiline-string/1-W1kbbb4iiGbP7KXb_BUwBQ_hu_5e24f6a3354edd98.webp 480w, https://yothinix-com.pages.dev/python-dedent-your-multiline-string/1-W1kbbb4iiGbP7KXb_BUwBQ_hu_128cbfc369b23ee7.webp 960w"
sizes="(max-width: 960px) 100vw, 960px"
width="960" height="527"
alt=""
loading="lazy" decoding="async"&gt;
&lt;em&gt;จะเห็นว่าพอ print ค่าออกมาแล้ว string ที่เราเก็บไว้มี space ติดมาด้วย&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;สิ่งที่เกิดขึ้นคือ Multiline String ของ Python จะนับ tab ที่เราเว้นไว้ทางซ้ายด้วย เหมือนในฟังก์ชั่น process_something() ซึ่งถ้าเราไม่อยากให้มันเยื้องแล้ว Print ออกมาสวยๆ เราก็ต้องทิ้งเยื้องไป เหมือนในฟังก์ชั่น process_something_without_padding() ซึ่งพอเราทำแบบนี้ ผมว่าทุกคนน่าจะรู้สึกทันทีว่า เออมันเวิร์คนะแต่ Indent มั่วไปหมดเลย พ้น definition ของ function ไปอีก ยิ่งถ้าเป็น Method ที่อยู่ใน class ยิ่งไม่อยากจะคิดเลย&lt;/p&gt;</description><content:encoded><![CDATA[<p>วันที่ 2 ของ #PythonTricksEveryday นะครับ ไหนๆ ก็เป็นวันสุดท้ายของการทำงานก่อนจะถึงวันหยุดยาว ขอแนะนำด้วย Tricks เล็กๆ ที่จะช่วยให้การทำงานกับ Multiline String เราดีขึ้นครับ</p>
<p>สมมติว่าเรามี String ยาวๆ ที่ต้องมี Indent สวยๆ เช่น Email หรือ Code snippet อย่างในภาพ แล้วเราต้องการนำมันไปใช้งานเช่นส่งอีเมล์หรือ Print report อะไรแบบนี้</p>
<p><img src="/python-dedent-your-multiline-string/1-W1kbbb4iiGbP7KXb_BUwBQ_hu_128cbfc369b23ee7.webp"
       srcset="/python-dedent-your-multiline-string/1-W1kbbb4iiGbP7KXb_BUwBQ_hu_5e24f6a3354edd98.webp 480w, /python-dedent-your-multiline-string/1-W1kbbb4iiGbP7KXb_BUwBQ_hu_128cbfc369b23ee7.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="527"
       alt=""
       loading="lazy" decoding="async">
<em>จะเห็นว่าพอ print ค่าออกมาแล้ว string ที่เราเก็บไว้มี space ติดมาด้วย</em></p>
<p>สิ่งที่เกิดขึ้นคือ Multiline String ของ Python จะนับ tab ที่เราเว้นไว้ทางซ้ายด้วย เหมือนในฟังก์ชั่น process_something() ซึ่งถ้าเราไม่อยากให้มันเยื้องแล้ว Print ออกมาสวยๆ เราก็ต้องทิ้งเยื้องไป เหมือนในฟังก์ชั่น process_something_without_padding() ซึ่งพอเราทำแบบนี้ ผมว่าทุกคนน่าจะรู้สึกทันทีว่า เออมันเวิร์คนะแต่ Indent มั่วไปหมดเลย พ้น definition ของ function ไปอีก ยิ่งถ้าเป็น Method ที่อยู่ใน class ยิ่งไม่อยากจะคิดเลย</p>
<p><img src="/python-dedent-your-multiline-string/1-hRZNrUwbHHSYMs690g_qzQ_hu_7a7e6f8fff06a06e.webp"
       srcset="/python-dedent-your-multiline-string/1-hRZNrUwbHHSYMs690g_qzQ_hu_63c21ef4a754cfdc.webp 480w, /python-dedent-your-multiline-string/1-hRZNrUwbHHSYMs690g_qzQ_hu_7a7e6f8fff06a06e.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="579"
       alt=""
       loading="lazy" decoding="async">
<em>ถ้าจะกำจัด space ข้างหน้า string เราวิธีทั่วไปก็ทำแบบนี้ครับ</em></p>
<p>ทีนี้ถ้าเรายังอยากเก็บ Multiline String โดยที่ยังรักษา indent ของ function เราให้เป็นไปในทางเดียวกันอยู่ เราก็มีตัวเลือกหลายทางครับเช่น เอาไปเก็บแยกเป็นตัวแปรไว้ข้างนอก function ไปเลย หรือโหลดจากไฟล์อื่นเข้ามาอ่านก็ได้ แต่ผมคิดว่าการทำแบบนั้นมันเป็นแค่การเลี่ยงปัญหา ไม่ใช่การแก้ปัญหาจริงๆ</p>
<p>Python มีวิธีในการแก้ปัญหาเรื่องนี้ครับ โดยใน standard library ที่ติดตัวมากับภาษามี Library ตัวนึงที่ชื่อว่า textwrap เอาไว้ทำงานเกี่ยวกับเรื่องแนวนี้ ซึ่งสิ่งที่เราต้องการก็คือ method ที่ชื่อว่า dedent ครับ เมื่อเราครอบ Multiline String ด้วย textwrap.dedent() เนี่ย สิ่งที่มันทำก็คือ มันจะลบ Leading space ออกจาก string ของเราทุกบรรทัดครับ ซึ่งทำให้เรากลับมาเขียน Multiline String สวยๆ ได้แบบฟังก์ชั่น process_something_with_dedent() เลยครับ</p>
<p><img src="/python-dedent-your-multiline-string/1-aRGrlAUg_yzLRTGdjcmTKA_hu_691243ad230930b0.webp"
       srcset="/python-dedent-your-multiline-string/1-aRGrlAUg_yzLRTGdjcmTKA_hu_ad438361dc33eb2f.webp 480w, /python-dedent-your-multiline-string/1-aRGrlAUg_yzLRTGdjcmTKA_hu_691243ad230930b0.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="606"
       alt=""
       loading="lazy" decoding="async">
<em>แบบใช้ textwrap.dedent() จะเห็นว่า space ข้างหน้าถูกลบหายไป แล้วยังรักษา indent ถัดมาอยู่ด้วย</em></p>
<p>จริงๆ textwrap library นี่ยังทำอะไรได้อีกหลายอย่างเลยนะครับ สนใจก็คลิกไปอ่าน Official document ได้ที่นี่เลยครับ</p>
<blockquote>
<p><a href="https://docs.python.org/3/library/textwrap.html">textwrap — Text wrapping and filling — Python 3.7.12 documentation</a></p>
</blockquote>
<hr>
<p>Original post at: <a href="https://yothinix.medium.com/dedent-your-multiline-string-b7fc8f41b286">https://yothinix.medium.com/dedent-your-multiline-string-b7fc8f41b286</a></p>
]]></content:encoded></item><item><title>The Power of Any / All</title><link>https://yothinix-com.pages.dev/the-power-of-any-all/</link><pubDate>Wed, 25 Jul 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/the-power-of-any-all/</guid><description>&lt;p&gt;วันที่ 1 ของ #PythonTricksEveryday นะครับ วันนี้เปิดด้วยหนึ่งในเทคนิคที่ พอรู้แล้วก็ใช้ได้ตลอดเลย มันคือ built-in function ที่ชื่อว่า all() และ any() ครับ ไปดูสถานการณ์เลยดีกว่า&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yothinix-com.pages.dev/the-power-of-any-all/1-G1PX7wqGzCchAo8-EQ5CJg_hu_8bf2ff2e000f114d.webp"
srcset="https://yothinix-com.pages.dev/the-power-of-any-all/1-G1PX7wqGzCchAo8-EQ5CJg_hu_8bf2ff2e000f114d.webp 480w"
sizes="(max-width: 960px) 100vw, 960px"
width="480" height="162"
alt=""
loading="lazy" decoding="async"&gt;&lt;/p&gt;
&lt;p&gt;สถานการณ์ที่เรามักจะเจอกันบ่อยๆ คือ เราต้องเขียน if ที่มี condition เยอะมากๆ อย่างในตัวอย่างนี้ก็ 5 conditions ซึ่ง บางทีรูปแบบที่มันอยู่อาจจะอยู่ยากกว่านี้ก็ได้ เช่น เป็น if แยกกันหลายๆ อันหรือ if ซ้อนใน if ให้เราลองพยายาม normalize ให้มันเหลือ if เดียวแล้วให้ความสัมพันธ์ของมันเหลือแค่ and / or&lt;/p&gt;
&lt;p&gt;พอเรา normalize ความสัมพันธ์ของแต่ละ condition จนเหมือนภาพข้างบนแล้ว สิ่งที่เกิดขึ้นก็คือ Linter ด่าครับ ยาวเกิน 80 บรรทัดอะไรก็ว่าไป ซึ่งเราก็จะต้องตบมันเข้ามาให้ไม่เกิน 80 บรรทัด โค้ดข้างล่างนี้ผมใช้ &lt;a href="https://github.com/ambv/black"&gt;Black&lt;/a&gt; ช่วย Format ให้นะครับหน้าตาก็จะประมาณนี้&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yothinix-com.pages.dev/the-power-of-any-all/1-Ta8sZe-W44kc8errZ7vvPw_hu_12d78e26eb7ff15.webp"
srcset="https://yothinix-com.pages.dev/the-power-of-any-all/1-Ta8sZe-W44kc8errZ7vvPw_hu_12d78e26eb7ff15.webp 480w"
sizes="(max-width: 960px) 100vw, 960px"
width="480" height="476"
alt=""
loading="lazy" decoding="async"&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>วันที่ 1 ของ #PythonTricksEveryday นะครับ วันนี้เปิดด้วยหนึ่งในเทคนิคที่ พอรู้แล้วก็ใช้ได้ตลอดเลย มันคือ built-in function ที่ชื่อว่า all() และ any() ครับ ไปดูสถานการณ์เลยดีกว่า</p>
<p><img src="/the-power-of-any-all/1-G1PX7wqGzCchAo8-EQ5CJg_hu_8bf2ff2e000f114d.webp"
       srcset="/the-power-of-any-all/1-G1PX7wqGzCchAo8-EQ5CJg_hu_8bf2ff2e000f114d.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="162"
       alt=""
       loading="lazy" decoding="async"></p>
<p>สถานการณ์ที่เรามักจะเจอกันบ่อยๆ คือ เราต้องเขียน if ที่มี condition เยอะมากๆ อย่างในตัวอย่างนี้ก็ 5 conditions ซึ่ง บางทีรูปแบบที่มันอยู่อาจจะอยู่ยากกว่านี้ก็ได้ เช่น เป็น if แยกกันหลายๆ อันหรือ if ซ้อนใน if ให้เราลองพยายาม normalize ให้มันเหลือ if เดียวแล้วให้ความสัมพันธ์ของมันเหลือแค่ and / or</p>
<p>พอเรา normalize ความสัมพันธ์ของแต่ละ condition จนเหมือนภาพข้างบนแล้ว สิ่งที่เกิดขึ้นก็คือ Linter ด่าครับ ยาวเกิน 80 บรรทัดอะไรก็ว่าไป ซึ่งเราก็จะต้องตบมันเข้ามาให้ไม่เกิน 80 บรรทัด โค้ดข้างล่างนี้ผมใช้ <a href="https://github.com/ambv/black">Black</a> ช่วย Format ให้นะครับหน้าตาก็จะประมาณนี้</p>
<p><img src="/the-power-of-any-all/1-Ta8sZe-W44kc8errZ7vvPw_hu_12d78e26eb7ff15.webp"
       srcset="/the-power-of-any-all/1-Ta8sZe-W44kc8errZ7vvPw_hu_12d78e26eb7ff15.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="476"
       alt=""
       loading="lazy" decoding="async"></p>
<p>โอเค อ่านง่ายกว่าตะกี้หน่อยๆ พอเราเห็นแบบนี้ปั๊ป เห้ยนี้มัน List นี่นา เราต้องทำอะไรบางอย่างเกี่ยวกับ List ได้สิ ถ้าเราเอา and / or ออกไปอะไรจะเกิดขึ้นน้า</p>
<h1 id="สวสด-all--any">สวัสดี All / Any</h1>
<p>all() / any() น่าจะเป็น built-in function ที่อยู่คู่บุญ Python มานาน นานแค่ไหนผมก็ไม่รู้เหมือนกัน เพราะตั้งแต่ผมมาเขียนมันก็มีให้ใช้แล้ว แต่เพิ่งมาตระหนักว่ามันใช้อย่างนี้ได้ก็ปีที่แล้วนี่เอง ตัว function มันจะทำงานแบบนี้ครับ (method เอามาจาก <a href="https://docs.python.org/3/library/functions.html#all">Official document</a> นะครับ)</p>
<p><img src="/the-power-of-any-all/1-36VtPZqdexEqCXkd7x5VFg_hu_5c9e596ae4c5f213.webp"
       srcset="/the-power-of-any-all/1-36VtPZqdexEqCXkd7x5VFg_hu_5c9e596ae4c5f213.webp 279w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="279" height="298"
       alt=""
       loading="lazy" decoding="async"></p>
<p>ตัว Signature ของทั้งสอง function นั้นรับ Iterable object เหมือนกันครับ ซึ่งถ้าไม่ใช่ object ที่เรา implement เองแล้วมี __iter__ กับ next() method เราก็ใช้ List / Tuple ธรรมดาๆ ได้ครับ</p>
<p>คำอธิบายของ All คือ จะ return True ถ้าทุกค่าเป็น True หรือ iterable เราเนี่ยส่งมาเป็นค่าว่าง ส่วน Any จะสลับกันคือ จะ return True ถ้ามี element อย่างน้อยตัวนึงมีค่าความจริงเป็น True ถ้า iterable ว่างจะ return False</p>
<p>ทีนี้เราจะเอามันมาใช้กับ if ยาวๆ เราได้ไงครับ ไปดูตัวอย่างข้างล่างได้เลย</p>
<p><img src="/the-power-of-any-all/1-PN4aaM5ZiH3O8VDxjbPuIA_hu_8ad1a13f953a26ae.webp"
       srcset="/the-power-of-any-all/1-PN4aaM5ZiH3O8VDxjbPuIA_hu_8ad1a13f953a26ae.webp 304w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="304" height="336"
       alt=""
       loading="lazy" decoding="async"></p>
<p>จะเห็นว่าแทนที่ผมจะเชื่อมแต่ละ condition ด้วย and / or ผมก็ยัดมันใส่ List / Tuple เอาไว้เลย แล้วตรง if ผมก็ใช้ all ครอบ List / Tuple ของ condition เอา แค่นี้ก็เรียบร้อยครับ</p>
<h1 id="ขอควรระวง">ข้อควรระวัง</h1>
<p>เพราะว่าเราย้าย expression ไปไว้ใน predicates List / Tuple แล้วจะมีปัญหาใหม่ตามมาคือ ถ้า if ที่เราเขียนตอนแรกเราอิง lazy evaluation หมายถึง ถ้าพังตัวแรกแล้วดีดออกจาก if เลย ซึ่งส่วนใหญ่จะเป็นเคส and ถ้า condition ที่ตามมา depends กับ condition ก่อนหน้า โค้ดเราจะระเบิดทันทีครับ</p>
<p><img src="/the-power-of-any-all/1-3_zUKDwItjg6Xvh9fvn77Q_hu_5e1a14395459004b.webp"
       srcset="/the-power-of-any-all/1-3_zUKDwItjg6Xvh9fvn77Q_hu_ee02a2df9ae0b632.webp 480w, /the-power-of-any-all/1-3_zUKDwItjg6Xvh9fvn77Q_hu_5e1a14395459004b.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="661"
       alt=""
       loading="lazy" decoding="async"></p>
<p>จากตัวอย่างนะครับ สมมติเรามีสถานการณ์คล้ายๆ แบบนี้คือ <strong>is_customer_active()</strong> และ <strong>is_vip_customer()</strong> ต้องการ <strong>customer_id</strong> ไม่งั้นระเบิดทั้งคู่ เราสามารถ move lazy evaluate มาเช็คใน predicate ก่อนได้ครับอย่างเช่น customer_id and is_customer_active(customer_id) ถ้า <strong>customer_id</strong> ไม่มีค่าเนี่ย expression นี้ก็จะเป็น <strong>False</strong> ไปเลย</p>
<p>จบแล้วครับ ข้อควรระวังอีกข้อนึงที่อยากฝากไว้คือ เวลาเรารู้เทคนิคใหม่ๆ แล้ว พอเราพยายามเอาไป Apply กับปัญหาที่ตัวเองใช้ อย่าลืมย้อนกลับมาดูด้วยนะครับว่า ถ้าเทียบกันแล้ววิธีใหม่กับวิธีเก่า เราหรือทีมโอเคกับแบบไหนมากกว่ากัน มันไม่มีวิธีไหนที่แก้ปัญหาได้ทุกอย่างครับ เหมือนกับ any / all ก็ไม่เหมาะกับบาง Use case เพราะฉะนั้น ใช้ด้วยความระมัดระวังนะครับ</p>
<hr>
<p>Original post at: <a href="https://yothinix.medium.com/the-power-of-any-all-ba219ef5c6cf">https://yothinix.medium.com/the-power-of-any-all-ba219ef5c6cf</a></p>
]]></content:encoded></item><item><title>Mock requests แบบสวยๆ ด้วย responses</title><link>https://yothinix-com.pages.dev/mock-python-request-with-responses/</link><pubDate>Tue, 24 Jul 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/mock-python-request-with-responses/</guid><description>&lt;p&gt;สิ่งหนึ่งที่เราเจอไม่ว่าจะช้าหรือเร็วคือ เมื่อเขียน Python ไปซักพักเราต้องยุ่งกับการยิง HTTP request ไปหา service ข้างนอก ซึ่ง Library ที่นิยมที่สุดในการทำสิ่งนี้ใน Python ก็คงหนีไม่พ้น requests นะครับ&lt;/p&gt;
&lt;p&gt;สมมติเรามีฟังก์ชั่น process_something ที่ทำหน้าที่ยิง requests ไปหา service ข้างนอกแล้วคืนของออกมาเป็น dictionary หน้าตาประมาณนี้&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yothinix-com.pages.dev/mock-python-request-with-responses/1-cbENO9XyXZ-BBITVEfzeog_hu_6d35393857ada90f.webp"
srcset="https://yothinix-com.pages.dev/mock-python-request-with-responses/1-cbENO9XyXZ-BBITVEfzeog_hu_6d35393857ada90f.webp 464w"
sizes="(max-width: 960px) 100vw, 960px"
width="464" height="354"
alt=""
loading="lazy" decoding="async"&gt;
&lt;em&gt;process_something.py&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;ถ้าเขียนแบบสมัยก่อน เราก็จะต้อง patch ตัว requests.get แล้วสร้าง Mock() object มารับ return_value หน้าตาประมาณนี้&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yothinix-com.pages.dev/mock-python-request-with-responses/1-uaFBxo2JLN2fwgswycfd1A_hu_bdb37363f45e44a1.webp"
srcset="https://yothinix-com.pages.dev/mock-python-request-with-responses/1-uaFBxo2JLN2fwgswycfd1A_hu_bdb37363f45e44a1.webp 480w"
sizes="(max-width: 960px) 100vw, 960px"
width="480" height="326"
alt=""
loading="lazy" decoding="async"&gt;&lt;/p&gt;
&lt;p&gt;ซึ่งพอทำแบบนี้บ่อยๆ เราก็เริ่มเห็น Pattern ซ้ำๆ ครับว่าต้อง Mock status_code นะ json() call นะหรือแม้กระทั่ง content type กับ headers ในบางเคส&lt;/p&gt;
&lt;p&gt;วิวัฒนาการถัดมาของการ mock requests คือ พอเราเห็น pattern ซ้ำๆ เราก็จับมันมาทำ utils function ครับ ซึ่งหน้าตามันก็จะออกมาประมาณนี้&lt;/p&gt;</description><content:encoded><![CDATA[<p>สิ่งหนึ่งที่เราเจอไม่ว่าจะช้าหรือเร็วคือ เมื่อเขียน Python ไปซักพักเราต้องยุ่งกับการยิง HTTP request ไปหา service ข้างนอก ซึ่ง Library ที่นิยมที่สุดในการทำสิ่งนี้ใน Python ก็คงหนีไม่พ้น requests นะครับ</p>
<p>สมมติเรามีฟังก์ชั่น process_something ที่ทำหน้าที่ยิง requests ไปหา service ข้างนอกแล้วคืนของออกมาเป็น dictionary หน้าตาประมาณนี้</p>
<p><img src="/mock-python-request-with-responses/1-cbENO9XyXZ-BBITVEfzeog_hu_6d35393857ada90f.webp"
       srcset="/mock-python-request-with-responses/1-cbENO9XyXZ-BBITVEfzeog_hu_6d35393857ada90f.webp 464w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="464" height="354"
       alt=""
       loading="lazy" decoding="async">
<em>process_something.py</em></p>
<p>ถ้าเขียนแบบสมัยก่อน เราก็จะต้อง patch ตัว requests.get แล้วสร้าง Mock() object มารับ return_value หน้าตาประมาณนี้</p>
<p><img src="/mock-python-request-with-responses/1-uaFBxo2JLN2fwgswycfd1A_hu_bdb37363f45e44a1.webp"
       srcset="/mock-python-request-with-responses/1-uaFBxo2JLN2fwgswycfd1A_hu_bdb37363f45e44a1.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="326"
       alt=""
       loading="lazy" decoding="async"></p>
<p>ซึ่งพอทำแบบนี้บ่อยๆ เราก็เริ่มเห็น Pattern ซ้ำๆ ครับว่าต้อง Mock status_code นะ json() call นะหรือแม้กระทั่ง content type กับ headers ในบางเคส</p>
<p>วิวัฒนาการถัดมาของการ mock requests คือ พอเราเห็น pattern ซ้ำๆ เราก็จับมันมาทำ utils function ครับ ซึ่งหน้าตามันก็จะออกมาประมาณนี้</p>
<p><img src="/mock-python-request-with-responses/1-6B7RIcDXdmmxXDZOpasfUQ_hu_7990626b1a2954e2.webp"
       srcset="/mock-python-request-with-responses/1-6B7RIcDXdmmxXDZOpasfUQ_hu_7990626b1a2954e2.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="229"
       alt=""
       loading="lazy" decoding="async"></p>
<p>แต่วิธีนี้ก็ยังต้องใช้ร่วมกับ assert_called_once_with เพื่อที่จะรับประกันว่าการที่เรา mock เนี่ยมันถูกใช้งานทุกครั้ง ไม่ใช่ mock free</p>
<h1 id="responses">Responses</h1>
<p>ผมไปเจอ Package นี้ตอนกด Discovery ใน GitHub แล้วคน Star เยอะมาก (ณ เวลาเขียนก็ 1955 Stars) แล้วคนสร้างก็ไม่ใช่ใครที่ไหนไกล เป็น Sentry ซึ่งเป็น service ที่เราใช้ในการ catch exception เรานั่นเอง (สนใจอ่าน blog ว่าเราใช้ Sentry ยังไงบ้างได้<a href="https://medium.com/prontotools/%E0%B8%88%E0%B8%B1%E0%B8%94%E0%B8%81%E0%B8%B2%E0%B8%A3-error-%E0%B8%82%E0%B8%AD%E0%B8%87-django-%E0%B8%AD%E0%B8%A2%E0%B9%88%E0%B8%B2%E0%B8%87%E0%B8%A1%E0%B8%B5%E0%B8%9B%E0%B8%A3%E0%B8%B0%E0%B8%AA%E0%B8%B4%E0%B8%97%E0%B8%98%E0%B8%B4%E0%B8%A0%E0%B8%B2%E0%B8%9E%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2-sentry-1561ab80623e">ที่น</a>ี่ครับ) วิธีลงก็ง่ายมากครับเหมือน library Python ทั่วไปคือ</p>
<p>$ pip install responses</p>
<p>หลังจากเราลง Package นี้ไปแล้วเราก็สามารถใช้มันในการ Mock response object ของ HTTP request ที่เราเรียกได้แล้วครับ หน้าตาก็จะประมาณนี้</p>
<p><img src="/mock-python-request-with-responses/1-0oJ-HJyA5Pkl8v6NeMXG0Q_hu_7cb41fabd35d312e.webp"
       srcset="/mock-python-request-with-responses/1-0oJ-HJyA5Pkl8v6NeMXG0Q_hu_7540163d14a5a7b8.webp 480w, /mock-python-request-with-responses/1-0oJ-HJyA5Pkl8v6NeMXG0Q_hu_7cb41fabd35d312e.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="613"
       alt=""
       loading="lazy" decoding="async">
<em>test_process_something.py</em></p>
<p>จะเห็นว่าหน้าตา signature ของ responses.add ค่อนข้างจะใกล้เคียงกับ ที่เราเคย mock ก่อนหน้านี้เลยคือรับ HTTP METHOD, URL, JSON return และ status code ซึ่งตัว responses เองเนี่ยสามารถใช้ได้ทั้งแบบ decorator แบบในภาพและแบบ context manager ผ่าน responses.RequestsMock() ก็ได้ครับ</p>
<p>ความเจ๋งอีกอย่างนึงที่ responses ทำให้เราก็คือ เราไม่ต้องมานั่งเช็คว่า assert_called_once_with ตัว mock request เราแล้วครับ เพราะว่าตัว Library เองจะจัดการให้เลยผ่าน flag ที่ชื่อว่า <strong>assert_all_requests_are_fired</strong> ซึ่งค่า default ของมันจะเป็น True อยู่แล้ว แต่เราจะใช้ความสามารถนี้ได้ต้องใช้ responses.RequestsMock() หรือใช้ผ่าน context manager นะครับ</p>
<p>นอกจากจะ assert request ให้เราแล้ว อีกความสามารถนึงที่เจ๋งมากคือ เราสามารถเพิ่ม callback function ให้มัน return response แบบ dynamic ได้ครับ หน้าตาก็ประมาณนี้ (ตัวอย่างผมเอามาจาก README.md ของ Library นะครับ)</p>
<p><img src="/mock-python-request-with-responses/1-GUNzH-unOTxm9dSSCgIrsQ_hu_9e6048fbe99532ea.webp"
       srcset="/mock-python-request-with-responses/1-GUNzH-unOTxm9dSSCgIrsQ_hu_9e6048fbe99532ea.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="413"
       alt=""
       loading="lazy" decoding="async"></p>
<p>ยังมีความสามารถอื่นๆ อีกนะครับที่ผมยังไม่ได้พูดถึง แต่ที่พูดถึงมานี่คือ Use Case ที่ทีมเราเอามาใช้แล้ว มันสะดวกและสวยมาก ถ้าอยากศึกษาเพิ่มเติมตามไปดูได้ที่ GitHub repo ของ Responses เลยครับ</p>
<blockquote>
<p><a href="https://github.com/getsentry/responses">GitHub - getsentry/responses: A utility for mocking out the Python Requests library.</a>
A utility for mocking out the Python Requests library. - GitHub - getsentry/responses: A utility for mocking out the Python Requests library.
— GitHub, getsentry</p>
</blockquote>
<hr>
<p>Original post at: <a href="https://yothinix.medium.com/mock-requests-%E0%B9%81%E0%B8%9A%E0%B8%9A%E0%B8%AA%E0%B8%A7%E0%B8%A2%E0%B9%86-%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2-responses-736e5f74b7f9">https://yothinix.medium.com/mock-requests-แบบสวยๆ-ด้วย-responses-736e5f74b7f9</a></p>
]]></content:encoded></item><item><title>มารู้จัก Data classes กันครับ</title><link>https://yothinix-com.pages.dev/getting-start-with-dataclasses-in-python/</link><pubDate>Mon, 16 Jul 2018 00:00:00 +0700</pubDate><guid>https://yothinix-com.pages.dev/getting-start-with-dataclasses-in-python/</guid><description>&lt;p&gt;เกือบจะไม่ได้มาเขียนต่อกันละสำหรับ Part 2 ของ dataclass ตอนที่หนึ่งอยู่ที่ &lt;a href="https://www.facebook.com/writepythontoscarecow/photos/a.206798910040303.1073741829.206323933421134/208169593236568/?type=3&amp;amp;theater"&gt;โพสน&lt;/a&gt;ี้ นะครับ แต่เพื่อไม่ให้เป็นการเสียเวลาไปมากกว่านี้ เราไปต่อกันที่ Part 2 เลยครับ&lt;/p&gt;
&lt;p&gt;ตอนที่แล้วเราได้รู้จัก dataclass ได้รู้ถึงเหตุผลว่าทำไมถึงเกิดมันขึ้นมา ตอนนี้เรามาจะมาโฟกัสกันว่า เราจะใช้ dataclass กับโค้ดเรายังไงครับ&lt;/p&gt;
&lt;p&gt;&lt;img src="https://yothinix-com.pages.dev/getting-start-with-dataclasses-in-python/1-qsBciri74At9SXPxlHy0WQ_hu_8d04e01d13e2bb7a.webp"
srcset="https://yothinix-com.pages.dev/getting-start-with-dataclasses-in-python/1-qsBciri74At9SXPxlHy0WQ_hu_62a9280381654e07.webp 480w, https://yothinix-com.pages.dev/getting-start-with-dataclasses-in-python/1-qsBciri74At9SXPxlHy0WQ_hu_8d04e01d13e2bb7a.webp 960w"
sizes="(max-width: 960px) 100vw, 960px"
width="960" height="479"
alt=""
loading="lazy" decoding="async"&gt;
&lt;em&gt;ตัวอย่างการใช้งาน dataclass&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;อย่างแรกที่เราเห็นเลยคือ เราไม่ต้องเขียน __init__ method กันอีกแล้วครับ ตัว dataclass จะ generate โค้ดส่วนนั้นให้ และอีกอย่างที่เราสังเกตุเห็นเลยคือ dataclass ใช้ประโยชน์จาก Type hint เต็มๆ อย่างที่เราเห็นการประกาศ Attribute ข้างต้นจะมีการประกาศ Type ประกบด้วยทุกตัว ทำให้เราสามารถเข้าใจ Attribute แต่ละตัวได้ทันทีว่าใช้ Type อะไรโดยไม่ต้องเดา&lt;/p&gt;
&lt;p&gt;อย่างที่สองครับ Representation ตัว dataclass เนี่ยนอกจากจะ generate __init__ ให้เราแล้วอีกตัวที่ทำให้คือ __repr__ ครับ ซึ่งตัว dataclass เนี่ยจะใช้ข้อมูลจาก attribute ที่เรา define ไว้มาสร้างให้ซึ่งช่วยเพิ่มความสะดวกให้เราและทำให้เราเลิกคิดไปได้หนึ่งเรื่อง หน้าตาก็จะประมาณนี้ครับ&lt;/p&gt;</description><content:encoded><![CDATA[<p>เกือบจะไม่ได้มาเขียนต่อกันละสำหรับ Part 2 ของ dataclass ตอนที่หนึ่งอยู่ที่ <a href="https://www.facebook.com/writepythontoscarecow/photos/a.206798910040303.1073741829.206323933421134/208169593236568/?type=3&amp;theater">โพสน</a>ี้ นะครับ แต่เพื่อไม่ให้เป็นการเสียเวลาไปมากกว่านี้ เราไปต่อกันที่ Part 2 เลยครับ</p>
<p>ตอนที่แล้วเราได้รู้จัก dataclass ได้รู้ถึงเหตุผลว่าทำไมถึงเกิดมันขึ้นมา ตอนนี้เรามาจะมาโฟกัสกันว่า เราจะใช้ dataclass กับโค้ดเรายังไงครับ</p>
<p><img src="/getting-start-with-dataclasses-in-python/1-qsBciri74At9SXPxlHy0WQ_hu_8d04e01d13e2bb7a.webp"
       srcset="/getting-start-with-dataclasses-in-python/1-qsBciri74At9SXPxlHy0WQ_hu_62a9280381654e07.webp 480w, /getting-start-with-dataclasses-in-python/1-qsBciri74At9SXPxlHy0WQ_hu_8d04e01d13e2bb7a.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="479"
       alt=""
       loading="lazy" decoding="async">
<em>ตัวอย่างการใช้งาน dataclass</em></p>
<p>อย่างแรกที่เราเห็นเลยคือ เราไม่ต้องเขียน __init__ method กันอีกแล้วครับ ตัว dataclass จะ generate โค้ดส่วนนั้นให้ และอีกอย่างที่เราสังเกตุเห็นเลยคือ dataclass ใช้ประโยชน์จาก Type hint เต็มๆ อย่างที่เราเห็นการประกาศ Attribute ข้างต้นจะมีการประกาศ Type ประกบด้วยทุกตัว ทำให้เราสามารถเข้าใจ Attribute แต่ละตัวได้ทันทีว่าใช้ Type อะไรโดยไม่ต้องเดา</p>
<p>อย่างที่สองครับ Representation ตัว dataclass เนี่ยนอกจากจะ generate __init__ ให้เราแล้วอีกตัวที่ทำให้คือ __repr__ ครับ ซึ่งตัว dataclass เนี่ยจะใช้ข้อมูลจาก attribute ที่เรา define ไว้มาสร้างให้ซึ่งช่วยเพิ่มความสะดวกให้เราและทำให้เราเลิกคิดไปได้หนึ่งเรื่อง หน้าตาก็จะประมาณนี้ครับ</p>
<p><img src="/getting-start-with-dataclasses-in-python/1-0PEpeDPLOhUpZ5lmW5y-WA_hu_5a29c11e0cb381fe.webp"
       srcset="/getting-start-with-dataclasses-in-python/1-0PEpeDPLOhUpZ5lmW5y-WA_hu_d4a5e06839cf4e26.webp 480w, /getting-start-with-dataclasses-in-python/1-0PEpeDPLOhUpZ5lmW5y-WA_hu_5a29c11e0cb381fe.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="299"
       alt=""
       loading="lazy" decoding="async">
<em>ตัวอย่าง repr ที่ปริ้นต์ออกมาเมื่อใช้และไม่ใช้งาน dataclass</em></p>
<p>รวมถึงถ้าเราจะดู Type ของแต่ละ Attribute ก็สามารถดูได้ผ่าน method __annotations__ ครับ</p>
<p><img src="/getting-start-with-dataclasses-in-python/1-0gxzxrH-qPnrreO1IDq0iA_hu_ba8801040f7678e0.webp"
       srcset="/getting-start-with-dataclasses-in-python/1-0gxzxrH-qPnrreO1IDq0iA_hu_ba8801040f7678e0.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="291"
       alt=""
       loading="lazy" decoding="async">
<em>ตัวอย่างผลลัพธ์ที่ได้จาก method __annotations__</em></p>
<p>ถามว่ามีไว้ทำไม ลองคิดภาพว่าเราต้อง pdb เข้าไป debug แล้ว __repr__ ไม่ได้ implement หรือเราไม่รู้ type ของแต่ละ attribute ดูสิครับ เราต้องมานั่งเดาว่า Instance ไหนคือตัวไหน มีค่าอะไร หรือแต่ละค่าเป็น type อะไร แต่พอเรามี Method พวกนี้มาให้แล้ว เราไม่ต้องเดาแล้วครับ</p>
<p>นอกจากสร้าง representation ให้แล้ว ตัว data class ยังสร้าง comparison method ให้ด้วยเช่น __lt__ , __le__ , __gt__ and __ge__ แต่ว่าเราต้องเพิ่ม argument <strong>order=True</strong> ใน decorator ของ dataclass ด้วยนะครับ มันถึงจะสร้าง method พวกนี้ให้</p>
<p><img src="/getting-start-with-dataclasses-in-python/1-MEy97fdW-uRTzcfNGoToOw_hu_d9b404ebe89dc80a.webp"
       srcset="/getting-start-with-dataclasses-in-python/1-MEy97fdW-uRTzcfNGoToOw_hu_d9b404ebe89dc80a.webp 480w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="480" height="390"
       alt=""
       loading="lazy" decoding="async">
<em>ตัวอย่างการเพิ่ม order ทำให้ dataclass compare ค่าใน instance ได้</em></p>
<p>โดยมันจะอ่านค่าจาก attribute ของ instance เราแล้วเอามา compare กับ instance อื่นได้ทั้ง &lt;, &lt;=, &gt;, &gt;= ส่วน == นั้นทำได้อยู่แล้วครับจาก dataclass ไม่ต้องมาเปิดผ่าน order</p>
<p>แต่ของที่ generate ขึ้นมารึจะสู้เราเขียนเอง ข้อเสียของ comparison method ที่มัน generate ให้คือมันไม่ฉลาดครับ ถ้าเราเอา class Team ที่เขียนข้างบนไปใช้ เราจะพบกับความประหลาด จนสงสัยว่ามันเทียบอะไร ยังไงของมัน นั่นทำให้เราต้องระบุค่าของแต่ละ attribute ผ่าน field() API ที่ dataclass สร้างมาให้ครับ</p>
<p>field() API นี่ สำหรับคนเคยใช้ ORM มาจะรู้สึกคุ้นหน้าคุ้นตามาก แต่ไม่เหมือนซะทีเดียว เพราะ field API นี่จะใช้ในการระบุ behavior ของ attribute ของ class แต่ละตัวว่าจะเอาไปใส่ใน representation รึเปล่า จะใช้ compare ด้วยมั้ย จะให้ attribute นี้เป็น immutable รึเปล่าหรือแม้กระทั่งใส่ metadata ไว้อธิบายว่า field นี้เอาไว้ทำอะไรก็ได้ครับ หน้าตาก็จะประมาณนี้</p>
<p><img src="/getting-start-with-dataclasses-in-python/1-AcVwd8dhJShMi4f-0EeeWg_hu_8355589fa80e6b4.webp"
       srcset="/getting-start-with-dataclasses-in-python/1-AcVwd8dhJShMi4f-0EeeWg_hu_5e0670488cf1c588.webp 480w, /getting-start-with-dataclasses-in-python/1-AcVwd8dhJShMi4f-0EeeWg_hu_8355589fa80e6b4.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="468"
       alt=""
       loading="lazy" decoding="async">
<em>ตัวอย่างการใช้ field() API สำหรับกำหนดพฤติกรรมของ attribute</em></p>
<p>เรื่อง immutable นี่ ถ้าเราอยากให้ทั้ง dataclass เราไม่สามารถแก้ไขข้อมูลได้เช่นเอาไว้เก็บ constant หรือ setting ต่างๆ เราสามารถระบุได้ใน decorator argument ว่า <strong>frozen=True</strong> ครับ อารมณ์เดียวกับ namedTuple เลย</p>
<p><img src="/getting-start-with-dataclasses-in-python/1--EwAwgnddK9fApoO15VRkA_hu_9759b3536ee12d33.webp"
       srcset="/getting-start-with-dataclasses-in-python/1--EwAwgnddK9fApoO15VRkA_hu_a2d606421f93ae49.webp 480w, /getting-start-with-dataclasses-in-python/1--EwAwgnddK9fApoO15VRkA_hu_9759b3536ee12d33.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="318"
       alt=""
       loading="lazy" decoding="async">
<em>ตัวอย่างการใช้ frozen ทำให้ dataclass เป็น immutable object</em></p>
<p>เคสต่อมาคือ เราอยากให้หลังจากที่เรา instantiate dataclass แล้วอยากให้มันทำการคำนวนบางอย่าง ถ้าเป็นสมัยก่อนเราต้องสร้าง method ซักอย่างขึ้นมาใน class แล้วเรียกมันใน __init__ ใช่มั้ยครับ ในเคสของ dataclass เราสามารถกำหนดพฤติกรรมตรงนั้นได้ผ่าน method ที่ชื่อว่า __post_init__ ครับ</p>
<p><img src="/getting-start-with-dataclasses-in-python/1-3pEA-x6ZVSztKMss-8cUEw_hu_70a4a0dad54588aa.webp"
       srcset="/getting-start-with-dataclasses-in-python/1-3pEA-x6ZVSztKMss-8cUEw_hu_359f5b761d629425.webp 480w, /getting-start-with-dataclasses-in-python/1-3pEA-x6ZVSztKMss-8cUEw_hu_70a4a0dad54588aa.webp 960w"
       sizes="(max-width: 960px) 100vw, 960px"
       width="960" height="504"
       alt=""
       loading="lazy" decoding="async">
<em>ตัวอย่างการใช้ __post_init__ กับ dataclass</em></p>
<p>ก็ประมาณนี้ครับ dataclass น่าจะครอบคลุมการใช้งานพื้นฐาน ถ้าอยากจะใช้งานลึกซึ้งมากกว่านี้เช่น Inheritance, __slot__ หรืออยากเข้าใจที่มาที่ไปมากกว่านี้ผมแนะนำ Talk ของ Raymond Hettinger ที่นี่เลยครับ</p>
<iframe width="200" height="113" src="https://www.youtube.com/embed/T-TwcmT6Rcw?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>หรือถ้าขี้เกียจฟังไปอ่าน Blog ที่ผมสรุปเนื้อหาที่เข้าใจได้ที่นี่ครับ</p>
<blockquote>
<p><a href="/100daysofpycon2018-day3-dataclasses-the-code-generator-to-end-all-code-generators/">#100DaysOfPyCon2018 Day3: Dataclasses: The code generator to end all code generators</a>
Key takeawaysSphinx ก็เอามาใช้ทำ Presentation ได้ แถมได้ document ที่อ่านง่ายกลับไปดูทีหลังได้ด้วยCode generator: tools that write code for you based on specificationdataclasses มี learning curve ต่ำมาก ถ้ามองสามารถมองได้สองมุมคือ data holder เหมือน namedTuple หรือเป็น boilerplate เอาไว้เขี
— Yothinix, Yothin Muangsommuk</p>
</blockquote>
<p>และเหมือนเดิมครับ ผมยังเชียร์ให้อ่าน Official Document ครับที่นี่</p>
<blockquote>
<p><a href="https://docs.python.org/3/library/dataclasses.html">dataclasses — Data Classes — Python 3.10.2 documentation</a>
— Logo</p>
</blockquote>
<hr>
<p>Original post at: <a href="https://yothinix.medium.com/%E0%B8%A1%E0%B8%B2%E0%B8%A3%E0%B8%B9%E0%B9%89%E0%B8%88%E0%B8%B1%E0%B8%81-data-classes-%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B8%84%E0%B8%A3%E0%B8%B1%E0%B8%9A-4cb8e1eb5f6b">https://yothinix.medium.com/มารู้จัก-data-classes-กันครับ-4cb8e1eb5f6b</a></p>
]]></content:encoded></item></channel></rss>