使用CI测试
你的pr一旦提交完毕就会自动在在Travis-CI,Appveyour上面运行测试,如果你想在提交之前测试,最好设置一个hook在你的github仓库。点击这里查看介绍。
所有的build都是绿色之后才可能被合并,如果测试未通过,你可以直接点击X号去看失败的测试,这里是一个绿色build的例子:
注意:
一旦你推送你的fork,CI会自动运行测试脚本,Appveyor将会自动取消对当前pr的任何非当前运行的测试。你对TC/CC可以使用自动取消功能。
测试驱动开发/测试驱动代码
pandas很在意测试,并且鼓励对于提高TDD的贡献,这种开发依靠短开发周期的循环,首先开发者完成一个自动执行的定义了新功能的测试用例,然后为了通过测试所需的最小代码。所以,在你写任何代码之前,你应该写你的测试,通常情况下测试可以来自原来的github的issue中。无论如何,考虑更多的使用用例和相关的测试。
增加测试通常是最常见的请求在代码被推送到pandas之后,因此,养成一个提前写测试的习惯是值得的,这样就不会成为一个issue。
和其他的包一样,pandas使用了pytest库和numpytestging中的使用的扩展。
注意:最早支持pytest的版本是3.1.0
编写测试
所有的测试代码都放在test子文件夹,这个文件夹中还包含了测试通用的例子,我们建议看看他们去寻找一些灵感。如果你的测试需要其他文件/网络的参与,点击这里。
pandas.util.test模块含有很多的assert方法,是为了能够很好的表达Series/Df对象是否相等。验证你的代码是否正确最容易的方法就是明确的构造出你的期望值,然后比较实际的结果和你期望的结果。
def test_pivot(self):
data = {
'index' : ['A', 'B', 'C', 'C', 'B', 'A'],
'columns' : ['One', 'One', 'One', 'Two', 'Two', 'Two'],
'values' : [1., 2., 3., 3., 2., 1.]
}
frame = DataFrame(data)
pivoted = frame.pivot(index='index', columns='columns', values='values')
expected = DataFrame({
'One' : {'A' : 1., 'B' : 2., 'C' : 3.},
'Two' : {'A' : 1., 'B' : 2., 'C' : 3.}
})
assert_frame_equal(pivoted, expected)
过渡到pytest
pandas 已存在的测试都是通过类的形式写的,通常你看到的测试都是包含在类中:
class TestReallyCoolFeature(object):
....
但是从目前开始,将过渡到使用pytest框架的函数式上,pytest提供了丰富的测试框架,使得测试和开发更为容易。因此你写的方法将会是这样
使用pytest
下面的例子包含了很多独立的测试来阐明pytest多样的特性,你将会喜欢下面这些特性。
- 函数的格式:测试格式都是test_* 而且只需要固定参数/可变参数
- pytest.mark可以设置test方法的元数据,例如skip/xfail
- 使用parametrize: 可以同时测试多个例子。
- 想在参数上面打个mark,可以使用pytest.param(...,marks=...)这样的语法
- fixture,定义对象的代码,在每个测试的基础上。???
- 使用assert来真实测试???
- tm。assert_series_equal 来比较对象
- 典型的格式去构造你期望的和对结果的比较
将下面命名为test_cool_feature.py并房子pandas/tests结构中一个合适的位置
import pytest
import numpy as np
import pandas as pd
from pandas.util import testing as tm
@pytest.mark.parametrize('dtype', ['int8', 'int16', 'int32', 'int64'])
def test_dtypes(dtype):
assert str(np.dtype(dtype)) == dtype
@pytest.mark.parametrize('dtype', ['float32',
pytest.param('int16', marks=pytest.mark.skip),
pytest.param('int32',
marks=pytest.mark.xfail(reason='to show how it works'))])
def test_mark(dtype):
assert str(np.dtype(dtype)) == 'float32'
@pytest.fixture
def series():
return pd.Series([1, 2, 3])
@pytest.fixture(params=['int8', 'int16', 'int32', 'int64'])
def dtype(request):
return request.param
def test_series(series, dtype):
result = series.astype(dtype)
assert result.dtype == dtype
expected = pd.Series([1, 2, 3], dtype=dtype)
tm.assert_series_equal(result, expected)
上面的运行结果如下:
可以通过测试的名字拿到用参数表示的测试,例如下面的命令 :只运行了匹配了int8的测试
运行测试集
直接在你的git clone的仓库里运行下面的命令就可以直接测试
测试集是比较消耗时间的,差不多20分钟跑完。建议只针对修改的部分运行测试子集
最方便的方式就是
或者采用下面这种格式:
使用pytest-xdist,这个包可以加速测试在多核机器上,安装命令如下
同时还有两个脚本的帮助,脚本采用4个线程完成测试
在unix衍生系列上面直接输入
在windows上直接输入
可以明显缩短提交前的本地测试时间。
pytest的文档在这里。
以后你可以直接运行
直接在导入的pandas中运行测试。
运行性能测试集
性能当然很重要,所以要考虑被引入的代码有没有导致性能下降。pandas目前正在逐步迁移到asv benchmarks为了更简单的监控pandas重要操作的性能。这些bm放在pandas/asv_bench文件夹中,同时支持py2/py3
为了使用asv,你需要conda/virtualenv/。详情见这里
安装asv:
如要运行bm,进入asv_bench文件夹运行
HEAD可以被替换成你想用的分支,你也可以报告超过10%bm的报告。命令默认采用conda作为bm的环境,如果你想用虚拟环境:
-E XXX 操作可以增加在所有的asv命令后面。默认的值定义在asv.conf.json
完整的测试集运行时间可能到1个小时,最大3GB的RAM,在提交pr的时候只粘贴10%的结果就足够了为了证明没有引起预期的性能下降。-b参数指定了特定bm,后面跟的参数是一个正则表达式,例如只想在pandas/aasv_bench/benchmarks/groupby.py文件中运行测试:
如果只想运行一个文件中的特定集合,可以使用。来作为分隔符
那么只运行了groupy_agg_builtins的bm。
也可以直接运行bm测试集通过当前已安装的pandas版本,如果你没有虚拟环境/conda的情况会特别有用,或者你是通过setup.py 开发方式。与之对应的构建你就需要设置pythonpath变量。例如PYTHONPATH="$PWD/.." asv [remaining arguments]。如果你存在python环境:
使用一个特定的python编译器
将会把标准错误显示出来,使用的$PATH变量中的python
写bm和使用asv可以点击这里。
Documenting your code
所有的变化应该反映在doc/soure/whatsnew/vx.xy.txt发布说明的文件夹。这个文件包含了一个持续的发布更改记录。你的所有修复,优化,比较大的变化。确保在你的条码当中包含Github issue的编号
如果你的代码是为了功能优化,你就需要在文档中加入使用例子。具体点击这里。可能的话,versionadded命令也要加上,这个是用来让用户知道功能什么时候会被加进去。他的sphinx语法是:
贡献你的修改
提交代码
将样式修改单独放到一个commit中,这样可读性更好。
一旦你代码有了更改,通过下面命令可以看到
创建了一个新文件,暂时还没有被git追踪到,下面命令可以被git追踪到
输入git status的输出大概是下面这样
最终。提交到你的本地仓库,并且尽量用解释性的注释,pandas对于提交信息有一个前缀列表,下面是一些常用的前缀以及与之对应的说明:
- ENH:增强
- BUG:bug fix
- DOC: 对文档的修改
-TST : 对test的修改
-BLD: 对构建/脚本的更改 - PERF: 性能的增强
- CLN: 代码的整洁修改
以下的是对commit信息的规定,请参考对应的issues用的是#1234/GH1234这种格式,尽管样式不谁很重要,但还是推荐前者。
- 一行小于80字符
- 一个空行
- 可选,一个commit body
你可以commit到你的仓库用下面命令
合并commit
如果你有多个commit需要合并,那就要用到'squashing''rebasing',这是包维护者经常用的因为这样提交log会更紧凑。
git rebase -i HEAD~#
代表的是你想合并的commit的数量,然后就可以自由选择想要哪些commit了
squash 到master分支:
在一个commit上面使用s命令代表squash,即保留。f代表fixup,即合并commit信息。
你需要强制推送到远端
推送你的更改
如果你想在Github页面显示你的更改,推送你forked的分支
origin是你远程仓库的名字,你可以看到你的远程仓库
如果你增加了上面所说的上游仓库你将会看到
现在你的代码就到了Github上面,但是还不算pandas的一部分,为了这个目的,需要在Github上面提交pr
审阅你的代码
当你已经检查完了自己的代码,提交一个pr,在此之前再三确认,你已经完全按照文档中的说明。完成了对代码格式测试,性能测试和文档的要求,再三确认你更改的部分。
1 在你的。GitHub上面进行操作。
2 点击branch按钮
3 点击Compare按钮
4 选择base 和 compare按钮,如有必要,
这个请求将会发送到仓库的维护者,他们将会检查你的代码。
如果你接下来还想继续更改,你可以在你的分支上直接进行修改,修改完之后把他们推到github上面,pr会自动进行更新。push的操作如下
这将会自动更新把带有你最新代码的p
r并再次进行CI测试。
删除已经合并的分支(可选)
一旦你的分支被合并到上游,你可能不想要你的分支了。首先。把上游的master分支合并到你的分支,这样的话git再删除你的分支就会变得安全。
然后你可以使用
确保你使用的是小写d。否则。git不会警告你如果你的分支还没有被合进去。
在github上面的分支当然仍然存在,所以通过下面命令可以删除。