Python 任务自动化工具:nox 的配置与 API

Stella981
• 阅读 690

👆  “ Python猫 ” ,一个值得加星标的 公众号

Python 任务自动化工具:nox 的配置与 API

英文 | Configuration & API

出处 | nox 官方文档

译者 | 豌豆花下猫@Python猫

Github地址:https://github.com/chinesehuazhou/nox\_doc\_cn

声明:本翻译基于CC BY-NC-SA 4.0授权协议,内容略有改动,转载请保留原文出处,请勿用于商业或非法用途。

接上篇 《更好用的 Python 任务自动化工具:nox 官方教程

Noxfile

Nox 默认在一个名为noxfile.py的文件中查找配置。在运行 nox 时,你可以使用 --noxfile参数指定其它的文件。

定义会话

格式:session(func=None, python=None, py=None, reuse_venv=None, name=None, venv_backend=None),将被装饰的函数指定为一个会话。

Nox 会话是通过被@nox.session装饰的标准 Python 函数来配置的。例如:

import nox@nox.sessiondef tests(session):    session.run('pytest')

会话描述

你可以使用文档字符串向会话中添加一个描述。第一行内容会在列出会话时显示。例如:

import nox@nox.sessiondef tests(session):    """Run the test suite."""    session.run('pytest')

nox --list命令将显示出:

$ nox --listAvailable sessions:* tests -> Run the test suite.

会话名称

默认情况下,Nox 使用被装饰函数的名称作为会话的名称。这对于绝大多数项目都非常有效,但是,如果需要,你也可以使用 @nox.session 的 name 参数来自定义会话的名称。例如:

import nox@nox.session(name="custom-name")def a_very_long_function_name(session):    print("Hello!")

nox --list 命令将显示:

$ nox --listAvailable sessions:* custom-name

你可以告诉 nox 使用自定义的名称运行会话:

$ nox --session "custom-name"Hello!

配置会话的virtualenv

默认情况下,Nox 在为每个会话创建一个新的 virtualenv 时,会使用 Nox 所用的同一个解释器。如果你使用 Python 3.6 安装了 nox,则 nox 将默认在所有会话中使用 Python 3.6。

通过给 @nox.session 指定 python 参数(或其别名 py),你可以告诉 nox 使用不同的 Python 解释器/版本:

@nox.session(python='2.7')def tests(session):    pass

你还可以告诉 Nox 使用多个 Python 解释器运行你的会话。Nox 将为指定的每个解释器创建一个单独的 virtualenv 并运行会话。例如,下面的会话将运行两次——一次使用 Python 2.7,一次使用 Python 3.6:

@nox.session(python=['2.7', '3.6'])def tests(session):    pass

当你提供一个版本号时,Nox 会自动添加 python 来确定可执行文件的名称。但是,Nox 也可以接受完整的可执行名称。如果你想使用 pypy 来测试,例如:

@nox.session(python=['2.7', '3.6', 'pypy-6.0'])def tests(session):    pass

当准备你的会话时,Nox 将为每个解释器创建单独的会话。你可以在运行 nox --list 的时候看到这些会话。例如这个 Noxfile:

@nox.session(python=['2.7', '3.5', '3.6', '3.7'])def tests(session):    pass

将产生这些会话:

* tests-2.7* tests-3.5* tests-3.6* tests-3.7

注意,这个扩展发生在参数化之前,所以你仍然可以对多个解释器的会话进行参数化。

如果你想完全禁止创建 virtualenv,你可以设置 python 参数为 False:

@nox.session(python=False)def tests(session):    pass

最后,你还可以指定每次都重用 virtualenv,而不是重新创建:

@nox.session(    python=['2.7', '3.6'],    reuse_venv=True)def tests(session):    pass

将参数传入会话

通常往测试会话中传递参数是很有用的。下面是一个简单示例,演示了如何使用参数对特定文件作测试:

@nox.sessiondef test(session):    session.install('pytest')    if session.posargs:        test_files = session.posargs    else:        test_files = ['test_a.py', 'test_b.py']    session.run('pytest', *test_files)

现在如果你运行:

nox

那么 nox 将运行:

pytest test_a.py test_b.py

但如果你运行:

nox -- test_c.py

那么 nox 将运行:

pytest test_c.py

参数化会话

会话的参数可以用nox.parametrize() 装饰器来作参数化。下面是一个典型的参数化安装 Django 版本的例子:

@nox.session@nox.parametrize('django', ['1.9', '2.0'])def tests(session, django):    session.install(f'django=={django}')    session.run('pytest')

当你运行nox时,它会创建两个不同的会话:

$ noxnox > Running session tests(django='1.9')nox > pip install django==1.9...nox > Running session tests(djano='2.0')nox > pip install django==2.0

nox.parametrize() 的接口和用法故意跟pytest的参数化 相类似。

格式:parametrize(arg_names, arg_values_list, ids=None)

作用是参数化一个会话。

将 arg_values_list 列表赋给对应的 arg_names,为装饰的会话函数添加新的调用。参数化在会话发现期间执行,每次调用都作为 nox 的单个会话出现。

参数:

  • arg_names ( Sequence[str])——一系列参数名称

  • arg_values_list ( Sequence[Union[Any, Tuple]])——参数值列表决定了使用不同参数值调用会话的频率。如果只指定了一个参数名,那么这就是一个简单的值列表,例如[1,2,3]。如果指定了 N 个参数名,这必须是一个 N 元组的列表,其中每个元素为其各自的参数名指定一个值,例如 [(1,'a'), (2,'b')]。

  • ids ( Sequence[str]) ——可选项,一系列测试 id,被参数化的参数使用。

你也可以堆叠装饰器,令其产生组合了参数的会话,例如:

@nox.session@nox.parametrize('django', ['1.9', '2.0'])@nox.parametrize('database', ['postgres', 'mysql'])def tests(session, django, database):    ...

如果运行nox —list,你将看到它生成了以下的会话集:

* tests(database='postgres', django='1.9')* tests(database='mysql', django='1.9')* tests(database='postgres', django='2.0')* tests(database='mysql', django='2.0')

如果你只想运行一个参数化会话,请参阅"指定参数化会话"部分。

为参数化的会话起友好的名称

自动生成的参数化会话的名称,如tests(django='1.9', database='postgres'),即使用关键字过滤,也可能很长且很难处理。

在此场景中,可以为参数化会话提供辅助的自定义 id 。这两个例子是等价的:

@nox.session@nox.parametrize('django',    ['1.9', '2.0'],    ids=['old', 'new'])def tests(session, django):    ...

@nox.session@nox.parametrize('django', [    nox.param('1.9', id='old'),    nox.param('2.0', id='new'),])def tests(session, django):    ...

当运行nox --list时,你将看到它们的新 id:

* tests(old)* tests(new)

你可以用nox --sessions "tests(old)",以此类推。

这也适用于堆叠参数化。id 是在组合期间组合的。例如:

@nox.session@nox.parametrize(    'django',    ['1.9', '2.0'],    ids=["old", "new"])@nox.parametrize(    'database',    ['postgres', 'mysql'],    ids=["psql", "mysql"])def tests(session, django, database):    ...

运行nox --list时会产生这些会话:

* tests(psql, old)* tests(mysql, old)* tests(psql, new)* tests(mysql, new)

会话对象

Nox 将使用 Session 类的一个实例来调用你的会话函数。

class Session(runner)

会话对象被传递到用户自定义的每个会话函数中。

这是在 Nox 会话中安装软件包和运行命令的主要途径。

  • bin¶——virtualenv 的 bin 目录

  • cd( dir)¶——chdir() 的一个别名

  • chdir( dir)¶——更改当前的工作目录

  • conda_install(*args, **kwargs)¶

    调用conda install来在会话环境中的安装软件包。

    直接安装软件包:

    session.conda_install('pandas')session.conda_install('numpy', 'scipy')session.conda_install('--channel=conda-forge', 'dask==2.1.0')
    

    根据 requirements.txt 文件来安装软件包:

    session.conda_install('--file', 'requirements.txt')session.conda_install('--file', 'requirements-dev.txt')
    

    不破坏 conda 已安装的依赖而安装软件包:

    session.install('.', '--no-deps')# Install in editable mode.session.install('-e', '.', '--no-deps')
    

    剩下的关键字参数跟 run() 相同。

  • env¶——一个环境变量的字典,传给所有的命令。

  • error(*args, **kwargs)¶——立即中止会话并随意地记录一个错误。

  • install(*args, **kwargs)¶ ——调用 pip 在会话的 virtualenv 里安装包。

    直接安装包:

    session.install('pytest')session.install('requests', 'mock')session.install('requests[security]==2.9.1')
    

    根据 requirements.txt 文件来安装软件包:

    session.install('-r', 'requirements.txt')session.install('-r', 'requirements-dev.txt')
    

    安装当前的包:

    session.install('.')# Install in editable mode.session.install('-e', '.')
    

    剩下的关键字参数跟 run() 相同。

  • interactive¶ ——如果 Nox 在交互式会话中运行,则返回 True,否则返回 False。

  • log(*args, **kwargs)¶——在会话期间输出一份日志。

  • notify( target)¶ ——将给定的会话放在队列的末尾。

    此方法是幂等的;对同一会话的多次通知无效。

    参数:target (Union[str, Callable])——需要通知的会话。这可以指定适当的字符串(与nox -s 的使用相同)或使用函数对象。

  • posargs¶ ——用于设置从命令行上传给 nox 的额外参数。

  • python¶ ——传给 @nox.session的 Python 版本。

  • run( args, env=None, kwargs)¶ ——运行一个命令。

    命令必须安装字符串列表指定,例如:

    session.run('pytest', '-k', 'fast', 'tests/')session.run('flake8', '--import-order-style=google')
    

    你不能把所有东西都当作一个字符串传递。例如,不可以这样:

    session.run('pytest -k fast tests/')
    

    你可以用 env 为命令设置环境变量:

    session.run(  'bash', '-c', 'echo $SOME_ENV',  env={'SOME_ENV': 'Hello'})
    

    你还可以使用 success_codes ,告诉 nox 将非零退出码视为成功。例如,如果你想将 pytest 的“tests discovered, but none selected”错误视为成功:

    session.run(  'pytest', '-k', 'not slow',  success_codes=[0, 5])
    

    在 Windows 上,像 del这样的内置命令不能直接调用,但是你可以使用 cmd /c 来调用它们:

    session.run('cmd', '/c', 'del', 'docs/modules.rst')
    

    参数:

  • env ( dict or None)——用于向命令公开的环境变量字典。默认情况下,传递所有环境变量。

  • silent ( bool) ——静默命令输出,除非命令失败。默认为 False。

  • success_codes ( list, tuple, or None)——一系列被认为是成功的返回码。默认情况下,只有 0 被认为是成功的。

  • external ( bool) ——如果为 False(默认值),那么不在 virtualenv 路径中的程序将发出告警。如果为 True,则不会发出告警。这些告警可以使用 --error-on-external-run将其转换为错误。这对没有 virtualenv 的会话没有影响。

  • skip(*args, **kwargs)¶ ——立即跳出会话,并随意记录一个告警。

  • virtualenv¶ ——运行所有命令的 virtualenv。

修改 Noxfile 中的 Nox 行为

Nox 有各种命令行参数,可用于修改其行为。其中一些还可以在 Noxfile 中使用 nox.options 指定。例如,如果你想将 Nox 的 virtualenvs 存储在不同的目录中,而不需要每次都将它传递给 nox:

import noxnox.options.envdir = ".cache"@nox.sessiondef tests(session):    ...

或者,如果你想提供一组默认运行的会话:

import noxnox.options.sessions = ["lint", "tests-3.6"]...

以下的选项可以在 Noxfile 中指定:

  • nox.options.envdir 等同于指定 –envdir.

  • nox.options.sessions 等同于指定 -s or –sessions.

  • nox.options.keywords 等同于指定 -k or –keywords.

  • nox.options.reuse_existing_virtualenvs 等同于指定 –reuse-existing-virtualenvs 。通过在调用时指定 --no-reuse-existing-virtualenvs ,你可以强制取消它。

  • nox.options.stop_on_first_error 等同于指定 –stop-on-first-error. 通过在调用时指定 --no-stop-on-first-error,你可以强制取消它。

  • nox.options.error_on_missing_interpreters 等同于指定 –error-on-missing-interpreters 。通过在调用时指定 --no-error-on-missing-interpreters ,你可以强制取消它。

  • nox.options.error_on_external_run 等同于指定 –error-on-external-run. 通过在调用时指定 --no-error-on-external-run ,你可以强制取消它。

  • nox.options.report 等同于指定 –report。

在调用 nox 时,命令行上指定的任何选项都优先于 Noxfile 中指定的选项。如果在命令行上指定了--sessions--keywords,那么在 Noxfile 中指定的两个选项都将被忽略。

Python 任务自动化工具:nox 的配置与 API

Python 任务自动化工具:nox 的配置与 API

译者简介:豌豆花下猫,生于广东毕业于武大,现为苏漂程序员,有一些极客思维,也有一些人文情怀,有一些温度,还有一些态度。

优质文章,推荐阅读:

更好用的 Python 任务自动化工具:nox 官方教程

Android 手机如何改造成 Linux 服务器?

Python 为什么要保留显式的 self ?

编程语言之问:何时该借用,何时该创造?

Python 任务自动化工具:nox 的配置与 API

感谢创作者的好文Python 任务自动化工具:nox 的配置与 API

本文分享自微信公众号 - Python猫(python_cat)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
2年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这