想象一下情况:您已经编写了一些很棒的Python代码,该代码可产生美丽的图形作为输出。您自然地将该图保存为graph.png
。您每次进行次要修改,都会运行几次代码。您下周/月/年回到它。您知道如何创建该图吗?什么输入数据?哪个版本的代码?如果您像我一样,那么答案通常会令人沮丧地“不”。当然,然后,您浪费了很多时间试图弄清楚自己的创建方式,甚至放弃,也从未在那张期刊论文中使用它,以赢得诺贝尔奖……
这次演讲将介绍食谱(来自食谱和Python ),这是一个python模块,可以使您免于这种情况! (尽管不能保证您的纸张会赢得诺贝尔奖!)在您的Python文件的顶部增加一系列代码,食谱将使您的代码每次运行记录到数据库,并跟踪输入文件,输出文件和代码的版本,然后让您查询此数据库,以了解实际上如何创建graph.png
。
最简单的安装方法是简单地运行
pip install recipy
另外,您可以克隆此存储库并运行:
python setup.py install
如果您想手动安装依赖项(如果您按照上述说明,应自动安装它们),请运行:
pip install -r requirements.txt
您可以通过运行以前的版本升级:
pip install -U recipy
要了解自上次发行以来发生了什么变化,请参阅ChangElog
注意:以上(未发行的)配方版本需要安装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
和浏览器窗口即可使用一个接口打开,您可以使用该界面来搜索所有食谱“运行”:
如果要记录使用内置打开或编写文件的文件的输入和输出,则需要做更多的工作。要么使用recipy.open
(仅需要在脚本的顶部import recipy
),要么from recipy import open
,然后只使用open
。需要此解决方法,因为许多库在内部使用内置打开,而您只想记录您自己打开的文件。
如果您使用Python 2,则可以将encoding
参数传递给recipy.open
。在这种情况下, codecs
用于使用适当的编码打开文件。
一旦您的数据库中有一些运行,就可以“注释”这些运行,并带有任何要保留的注释。这对于录制运行良好的录制或您遇到的特定问题可能特别有用。这可以从GUI中的“详细信息”页面或运行
recipy annotate
它将打开一个编辑器,以允许您编写将附加到运行中的笔记。然后在搜索运行时通过命令行和GUI可查看这些。
命令行界面中也有其他功能: recipy --help
来查看其他选项。您可以查看diffs,查看创建具有给定名称的文件的所有运行,基于ID搜索,显示最新条目等:
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
配置默认文本编辑器,当食谱需要您输入消息时将使用。例如,如果在Windows上使用Notepadquiet
- 不要打印任何消息port
- 指定用于GUI的端口[data]
file_diff_outputs
如果执行脚本之前的输出文件存在,则存储旧输出和新输出文件之间的差异[database]
path = /path/to/file.json
to/file.json-将路径设置为数据库文件[ignored metadata]
diff
不要将git diff
的输出存储在元数据中以进行配方运行git
不要在元数据中存储与git(原始,提交,回购等)有关的任何内容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 , DataFrame.to_stata , DataFrame.to_pickle , Panel.to_excel , Panel.to_hdf , Panel.to_msgpack , Panel.to_pickle , Series.to_csv , Series.to_hdf , 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 , nifti2.Nifti2Image.from_filename , freesurfer.mghformat.MGHImage.from_filename , spm99analyze.Spm99AnalyzeImage.from_filename , minc1.Minc1Image.from_filename , minc2.Minc2Image.from_filename , analyze.AnalyzeImage.from_filename , parrec.PARRECImage.from_filename , spm2analyze.Spm2AnalyzeImage.from_filename | nifti1.Nifti1Image.to_filename , nifti2.Nifti2Image.to_filename , freesurfer.mghformat.MGHImage.to_filename , spm99analyze.Spm99AnalyzeImage.to_filename , minc1.Minc1Image.to_filename , minc2.Minc2Image.to_filename , analyze.AnalyzeImage.to_filename , parrec.PARRECImage.to_filename , spm2analyze.Spm2AnalyzeImage.to_filename |
但是,上面的代码示例显示了编写课程以包装新模块的容易 - 因此,请随时提交拉动请求,以使食谱与您最喜欢的科学模块合作!
食谱的测试框架在integration_test
中。测试框架已设计为在Python 2.7+和Python 3+下运行。有关更多信息,请参见配方测试框架。
测试框架在以下平台上运行: