ลองนึกภาพสถานการณ์: คุณได้เขียนรหัส Python ที่ยอดเยี่ยมซึ่งสร้างกราฟที่สวยงามเป็นเอาต์พุต คุณบันทึกกราฟนั้นตามธรรมชาติพอเช่น graph.png
คุณเรียกใช้รหัสสองสามครั้งทุกครั้งที่ทำการปรับเปลี่ยนเล็กน้อย คุณกลับมาในสัปดาห์หน้า/เดือน/ปี คุณรู้หรือไม่ว่าคุณสร้างกราฟนั้นอย่างไร? ข้อมูลอินพุตอะไร รหัสของคุณเวอร์ชันใด หากคุณเป็นอะไรอย่างฉันคำตอบก็มักจะน่าผิดหวังคือ“ ไม่” แน่นอนว่าคุณเสียเวลาไปกับการพยายามหาวิธีที่คุณสร้างขึ้นมาหรือแม้แต่ยอมแพ้และไม่เคยใช้มันในเอกสารวารสารที่จะชนะรางวัลโนเบล ...
การพูดคุยนี้จะแนะนำผู้รับ (จาก สูตร และ Python ) โมดูล Python ที่จะช่วยคุณจากสถานการณ์นี้! (แม้ว่าจะไม่สามารถรับประกันได้ว่ากระดาษที่ได้ของคุณจะได้รับรางวัลโนเบล!) ด้วยการเพิ่มรหัสบรรทัดเดียวไปยังด้านบนของไฟล์ Python ของคุณ ไฟล์อินพุตไฟล์เอาต์พุตและเวอร์ชันของรหัสของคุณจากนั้นให้คุณสอบถามฐานข้อมูลนี้เพื่อค้นหาว่าคุณสร้าง graph.png
จริงอย่างไร
วิธีที่ง่ายที่สุดในการติดตั้งคือเพียงแค่เรียกใช้
pip install recipy
หรือคุณสามารถโคลนพื้นที่เก็บข้อมูลนี้และเรียกใช้:
python setup.py install
หากคุณต้องการติดตั้งการอ้างอิงด้วยตนเอง (ควรติดตั้งโดยอัตโนมัติหากคุณทำตามคำแนะนำด้านบน) จากนั้นเรียกใช้:
pip install -r requirements.txt
คุณสามารถอัพเกรดจากรุ่นก่อนหน้าโดยการรัน:
pip install -U recipy
หากต้องการทราบว่ามีอะไรเปลี่ยนแปลงตั้งแต่การเปิดตัวครั้งล่าสุดให้ดูการเปลี่ยนแปลง
หมายเหตุ: รุ่นก่อนหน้า (ยังไม่เผยแพร่) ต้องการ MongoDB ที่จะติดตั้งและตั้งค่าด้วยตนเอง ไม่จำเป็นต้องใช้อีกต่อไปเนื่องจากใช้ฐานข้อมูล Python บริสุทธิ์ (TinyDB) แทน นอกจากนี้ GUI ยังรวมอยู่ในตัวแทนอย่างเต็มที่และไม่จำเป็นต้องติดตั้งแยกต่างหาก
เพียงเพิ่มบรรทัดต่อไปนี้ไปที่ด้านบนของสคริปต์ Python ของคุณ:
import recipy
โปรดทราบว่านี่ จะต้อง เป็นบรรทัด บนสุด ของสคริปต์ของคุณก่อนที่คุณจะนำเข้าสิ่งอื่นใด
จากนั้นเพียงเรียกใช้สคริปต์ของคุณตามปกติและข้อมูลทั้งหมดจะถูกลงชื่อเข้าใช้ในฐานข้อมูล TinyDB (ไม่ต้องกังวลฐานข้อมูลจะถูกสร้างขึ้นโดยอัตโนมัติหากจำเป็น) จากนั้นคุณสามารถใช้สคริปต์ recipy
เพื่อสอบถามฐานข้อมูลได้อย่างรวดเร็วเพื่อค้นหาว่ารหัสของคุณผลิตไฟล์เอาต์พุตอะไร ตัวอย่างเช่นหากคุณเรียกใช้รหัสบางอย่างเช่นนี้:
import recipy
import numpy
arr = numpy . arange ( 10 )
arr = arr + 500
numpy . save ( 'test.npy' , arr )
(หมายเหตุการเพิ่ม import recipy
ที่จุดเริ่มต้นของสคริปต์ - แต่ไม่มีการเปลี่ยนแปลงอื่น ๆ จากสคริปต์มาตรฐาน)
อีกวิธีหนึ่งให้เรียกใช้สคริปต์ที่ไม่ได้แก้ไขด้วย python -m recipy SCRIPT [ARGS ...]
เพื่อเปิดใช้งานการบันทึกผู้รับ สิ่งนี้เรียกใช้จุดเข้าร่วมโมดูลของผู้รับซึ่งดูแลผู้รับการนำเข้าให้คุณก่อนเรียกใช้สคริปต์ของคุณ
มันจะผลิตผลลัพธ์ที่เรียกว่า test.npy
หากต้องการค้นหารายละเอียดของการรันที่สร้างไฟล์นี้คุณสามารถค้นหาได้โดยใช้
recipy search test.npy
และจะแสดงข้อมูลดังต่อไปนี้:
Created by robin on 2015-05-25 19:00:15.631000
Ran /Users/robin/code/recipy/example_script.py using /usr/local/opt/python/bin/python2.7
Git: commit 91a245e5ea82f33ae58380629b6586883cca3ac4, in repo /Users/robin/code/recipy, with origin [email protected]:recipy/recipy.git
Environment: Darwin-14.3.0-x86_64-i386-64bit, python 2.7.9 (default, Feb 10 2015, 03:28:08)
Inputs:
Outputs:
/Users/robin/code/recipy/test.npy
ทางเลือกอื่นในการดูสิ่งนี้คือการใช้ GUI เพียงเรียกใช้ recipy gui
และหน้าต่างเบราว์เซอร์จะเปิดด้วยอินเทอร์เฟซที่คุณสามารถใช้เพื่อค้นหา 'Runs' ของผู้รับทั้งหมด:
หากคุณต้องการบันทึกอินพุตและเอาต์พุตของไฟล์ที่อ่านหรือเขียนด้วยการเปิดในตัวคุณต้องทำงานเพิ่มอีกเล็กน้อย ใช้ recipy.open
(ต้องการเฉพาะ import recipy
ที่อยู่ด้านบนของสคริปต์ของคุณ) หรือเพิ่ม from recipy import open
และใช้ open
วิธีแก้ปัญหานี้เป็นสิ่งจำเป็นเนื่องจากไลบรารีหลายแห่งใช้การเปิดในตัวภายในและคุณต้องการบันทึกไฟล์ที่คุณเปิดอย่างชัดเจน
หากคุณใช้ Python 2 คุณสามารถผ่านพารามิเตอร์ encoding
ไปยัง recipy.open
ในกรณีนี้ใช้ codecs
เพื่อเปิดไฟล์ด้วยการเข้ารหัสที่เหมาะสม
เมื่อคุณมีการรันในฐานข้อมูลของคุณแล้วคุณสามารถ 'ใส่คำอธิบายประกอบ' เหล่านี้ด้วยบันทึกย่อใด ๆ ที่คุณต้องการเก็บไว้ สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับการบันทึกว่าทำงานได้ดีหรือปัญหาเฉพาะที่คุณพบ สามารถทำได้จากหน้า 'รายละเอียด' ใน GUI หรือโดยการรัน
recipy annotate
ซึ่งจะเปิดตัวแก้ไขเพื่อให้คุณสามารถเขียนโน้ตที่จะแนบกับการรัน สิ่งเหล่านี้จะสามารถดูได้ผ่านบรรทัดคำสั่งและ GUI เมื่อค้นหาการรัน
มีคุณสมบัติอื่น ๆ ในอินเทอร์เฟซบรรทัดคำสั่งด้วย: recipy --help
เพื่อดูตัวเลือกอื่น ๆ คุณสามารถดู diffs ดูการรันทั้งหมดที่สร้างไฟล์ด้วยชื่อที่กำหนดค้นหาตามรหัสแสดงรายการล่าสุดและอื่น ๆ :
recipy - a frictionless provenance tool for Python
Usage:
recipy search [options] <outputfile>
recipy latest [options]
recipy gui [options]
recipy annotate [<idvalue>]
recipy (-h | --help)
recipy --version
Options:
-h --help Show this screen
--version Show version
-a --all Show all results (otherwise just latest result given)
-f --fuzzy Use fuzzy searching on filename
-r --regex Use regex searching on filename
-i --id Search based on (a fragment of) the run ID
-v --verbose Be verbose
-d --diff Show diff
-j --json Show output as JSON
--no-browser Do not open browser window
--debug Turn on debugging mode
ผู้รับจัดเก็บการกำหนดค่าทั้งหมดและฐานข้อมูลเองใน ~/.recipy
ไฟล์การกำหนดค่าหลักของผู้รับอยู่ในโฟลเดอร์นี้เรียกว่า recipyrc
รูปแบบไฟล์การกำหนดค่านั้นง่ายมากและขึ้นอยู่กับไฟล์ Windows INI - และการมีไฟล์การกำหนดค่าเป็นทางเลือกอย่างสมบูรณ์: ค่าเริ่มต้นจะทำงานได้ดีโดยไม่มีไฟล์การกำหนดค่า
ตัวอย่างการกำหนดค่าคือ:
[ignored metadata]
diff
[general]
debug
สิ่งนี้เพียงแค่สั่งให้ผู้รับไม่บันทึกข้อมูล git diff
เมื่อบันทึกข้อมูลเมตาเกี่ยวกับการเรียกใช้และยังพิมพ์ข้อความการดีบัก (ซึ่งอาจมีประโยชน์จริงๆถ้าคุณพยายามหาว่าทำไมฟังก์ชั่นบางอย่างจึงไม่ได้รับการแก้ไข) ในขณะนี้ตัวเลือกที่เป็นไปได้เท่านั้นคือ:
[general]
debug
- ข้อความแก้ไขข้อบกพร่องeditor = vi
- กำหนดค่าตัวแก้ไขข้อความเริ่มต้นที่จะใช้เมื่อผู้รับต้องการให้คุณพิมพ์ในข้อความ ใช้ Notepad ถ้าอยู่บน Windows เป็นตัวอย่างquiet
- อย่าพิมพ์ข้อความใด ๆport
- ระบุพอร์ตที่จะใช้สำหรับ GUI[data]
file_diff_outputs
- จัดเก็บ diff ระหว่างเอาต์พุตเก่าและไฟล์เอาต์พุตใหม่หากไฟล์เอาต์พุตมีอยู่ก่อนที่สคริปต์จะถูกเรียกใช้งาน[database]
path = /path/to/file.json
- ตั้งค่าพา ธ ไปยังไฟล์ฐานข้อมูล[ignored metadata]
diff
- อย่าเก็บเอาต์พุตของ git diff
ในข้อมูลเมตาสำหรับการทำงานของผู้รับgit
- อย่าเก็บอะไรที่เกี่ยวข้องกับ Git (Origin, Commit, Repo ฯลฯ ) ในข้อมูลเมตาสำหรับการทำงานของผู้รับinput_hashes
- อย่าคำนวณและเก็บ sha -1 แฮชของไฟล์อินพุตoutput_hashes
- อย่าคำนวณและเก็บ sha -1 แฮชของไฟล์เอาต์พุต[ignored inputs]
numpy
) เพื่อสั่งให้ผู้รับ ไม่ บันทึกอินพุตจากโมดูลนี้หรือ all
เพื่อละเว้นอินพุตจากโมดูลทั้งหมด[ignored outputs]
numpy
) เพื่อสั่งให้ผู้รับ ไม่ บันทึกเอาต์พุตจากโมดูลนี้หรือ all
เพื่อละเว้นผลลัพธ์จากโมดูลทั้งหมด โดยค่าเริ่มต้นข้อมูลเมตาทั้งหมดจะถูกเก็บไว้ (เช่นไม่มีการละเว้นข้อมูลเมตา) และไม่แสดงข้อความการดีบัก ไฟล์ .recipyrc
ในไดเรกทอรีปัจจุบันมีความสำคัญเหนือกว่าไฟล์ ~/.recipy/recipyrc
ทำให้สามารถจัดการการกำหนดค่าต่อโครงการได้อย่างง่ายดาย
หมายเหตุ: ไม่มีไฟล์การกำหนดค่าเริ่มต้นที่มาพร้อมกับผู้รับดังนั้นหากคุณต้องการกำหนดค่าสิ่งใดก็ตามคุณจะต้องสร้างไฟล์ที่จัดรูปแบบอย่างถูกต้องด้วยตัวคุณเอง
เมื่อคุณนำเข้าผู้รับจะเพิ่มคลาสจำนวนหนึ่งให้กับ sys.meta_path
สิ่งเหล่านี้จะถูกใช้โดย Python ซึ่งเป็นส่วนหนึ่งของขั้นตอนการนำเข้าสำหรับโมดูล คลาสที่เราเพิ่มเป็นคลาสที่ได้จาก PatchImporter
มักใช้อินเตอร์เฟสที่ง่ายขึ้นโดย PatchSimple
ซึ่งช่วยให้เราสามารถห่อฟังก์ชั่นที่ทำอินพุต/เอาต์พุตในฟังก์ชั่นที่เรียกว่าผู้รับก่อนเข้าสู่ระบบ
โดยทั่วไปความซับซ้อนส่วนใหญ่จะถูกซ่อนอยู่ใน PatchImporter
และ PatchSimple
(รวมถึง utils.py
) ดังนั้นรหัสจริงที่จะห่อโมดูลเช่น numpy
ค่อนข้างง่าย:
# Inherit from PatchSimple
class PatchNumpy ( PatchSimple ):
# Specify the full name of the module
modulename = 'numpy'
# List functions that are involved in input/output
# these can be anything that can go after "modulename."
# so they could be something like "pyplot.savefig" for example
input_functions = [ 'genfromtxt' , 'loadtxt' , 'load' , 'fromfile' ]
output_functions = [ 'save' , 'savez' , 'savez_compressed' , 'savetxt' ]
# Define the functions that will be used to wrap the input/output
# functions.
# In this case we are calling the log_input function to log it to the DB
# and we are giving it the 0th argument from the function (because all of
# the functions above take the filename as the 0th argument), and telling
# it that it came from numpy.
input_wrapper = create_wrapper ( log_input , 0 , 'numpy' )
output_wrapper = create_wrapper ( log_output , 0 , 'numpy' )
คลาสเช่นนี้จะต้องดำเนินการสำหรับแต่ละโมดูลที่มีอินพุต/เอาต์พุตต้องการการบันทึก ในขณะนี้ฟังก์ชั่นอินพุตและเอาต์พุตต่อไปนี้ได้รับการแก้ไข:
ตารางนี้แสดงรายการโมดูลตัวแทนมีแพตช์สำหรับและฟังก์ชันอินพุตและเอาต์พุตที่ได้รับการแก้ไข
โมดูล | ฟังก์ชันอินพุต | ฟังก์ชันเอาต์พุต |
---|---|---|
pandas | read_csv , read_table , read_excel , read_hdf , read_pickle , read_stata , read_msgpack | DataFrame.to_csv , DataFrame.to_excel , DataFrame.to_hdf , DataFrame.to_msgpack Series.to_csv DataFrame.to_stata Series.to_hdf DataFrame.to_pickle Series.to_msgpack Panel.to_excel , Panel.to_hdf , Panel.to_pickle , Panel.to_msgpack Series.to_msgpack , Series.to_pickle |
matplotlib.pyplot | savefig | |
numpy | genfromtxt , loadtxt , fromfile | save , savez , savez_compressed , savetxt |
lxml.etree | parse iterparse | |
bs4 | BeautifulSoup | |
gdal | Open | Driver.Create , Driver.CreateCopy |
sklearn | datasets.load_svmlight_file | datasets.dump_svmlight_file |
nibabel | nifti1.Nifti1Image.from_filename minc1.Minc1Image.from_filename nifti2.Nifti2Image.from_filename , freesurfer.mghformat.MGHImage.from_filename , spm99analyze.Spm99AnalyzeImage.from_filename minc2.Minc2Image.from_filename , analyze.AnalyzeImage.from_filename , parrec.PARRECImage.from_filename , spm2analyze.Spm2AnalyzeImage.from_filename | nifti1.Nifti1Image.to_filename minc1.Minc1Image.to_filename nifti2.Nifti2Image.to_filename minc2.Minc2Image.to_filename freesurfer.mghformat.MGHImage.to_filename , spm99analyze.Spm99AnalyzeImage.to_filename , analyze.AnalyzeImage.to_filename , parrec.PARRECImage.to_filename , spm2analyze.Spm2AnalyzeImage.to_filename |
อย่างไรก็ตามตัวอย่างโค้ดด้านบนแสดงให้เห็นว่าการเขียนคลาสเป็นเรื่องง่ายเพียงใดเพื่อห่อโมดูลใหม่ - โปรดอย่าลังเลที่จะส่งคำขอดึงเพื่อให้ผู้รับทำงานกับโมดูลทางวิทยาศาสตร์ที่คุณชื่นชอบ!
กรอบการทดสอบของผู้รับอยู่ใน integration_test
เฟรมเวิร์กทดสอบได้รับการออกแบบให้ทำงานภายใต้ Python 2.7+ และ Python 3+ สำหรับข้อมูลเพิ่มเติมดูกรอบการทดสอบผู้รับ
เฟรมเวิร์กทดสอบทำงานบนแพลตฟอร์มต่อไปนี้: