一个用于审计pip freeze输出并测试版本要求的工具
项目描述
defrost
注意:这个包最初叫做 pipfreeze,但为了避免与命令 pip freeze 混淆,已重命名。
Defrost是一个命令行工具,用于检查pip freeze命令的输出是否满足在YAML文件中定义的一组包要求。
用法
defrost --help
首先在YAML文件中定义一组包要求,requirements.yml。
---
requirements:
- requirement: foobar>=1.0
reason: foobar pre-1.0 is no longer supported, please upgrade to 1.x
- requirement: ordereddict<0.0
reason: OrderedDict is part of Python 2.7 and above. If you are still running Python 2.6, please upgrade!
然后,您可以将pip freeze的输出通过管道传递给defrost,同时提供YAML文件。
$ pip freeze > freeze.out
$ defrost requirements.yml freeze.out
Package(foobar==1.2) does not satisfy Requirement(foobar>=2.0): foobar pre-1.0 is no longer supported, please upgrade to 1.x
Defrost还可以通过将短横线 - 作为参数传递,代替pip freeze输出文件,将pip freeze输出作为stdin。
$ pip freeze | defrost requirements.yml -
Package(foobar==1.2) does not satisfy Requirement(foobar>=2.0): foobar pre-1.0 is no longer supported, please upgrade to 1.x
您还可以使用 defrost-lint 来检查提供的YAML文件是否有效。
$ defrost-lint requirements.yml
安装
pip install defrost
库
有3个基本对象可用
PipFreeze:一个接受pip freeze输出作为输入的Python容器。
Package:表示一个由PipFreeze容器(例如,foo==1.2)持有的精确版本(固定)的包实例
需求:一个包的需求表示特定包的一个版本或一系列版本,例如 foo>=2.0 是对所有 2.0 及以上版本的 foo 的需求。没有版本指定符的 foo 表示所有版本的 foo。
PipFreeze
PipFreeze 接收 pip freeze 输出作为输入并内部构建包。
>>> from defrost import PipFreeze
>>> pip_freeze_output = """\
foo==1.2.3
bar==2.0
"""
>>> pip_freeze = PipFreeze(pip_freeze_output)
>>> len(pip_freeze)
2
>>> list(pip_freeze)
[Package(foo==1.2.3), Package(bar==2.0)]
# test presence of package foo that is less or equal to v2.0
>>> 'foo<=2.0' in pip_freeze
True
# test presence of any version of package zoo
>>> 'zoo' in pip_freeze
False
# test can also be done with a Package instance
>>> Package('foo==0.1') in pip_freeze
False
# ... or with a Requirement
>>> Requirement('bar>=2.0') in pip_freeze
True
包弃用
您可以通过加载 YAML 需求文件并将结果传递给 PipFreeze.load_requirements() 来标记包为弃用。如果 PipFreeze 中的包不满足加载的需求,则这些包将被标记为弃用。您还可以提供一个可选的理由来解释为什么包被弃用。
>>> pip_freeze = PipFreeze("""\
foobar==0.8
bar==2.0
ordereddict==1.1
""")
>>> import yaml
>>> reqs = yaml.load(open('my-reqs.yaml'))
>>> pip_freeze.load_requirements(reqs)
>>> pip_freeze.deprecated
[Package(foobar==0.8), Package(ordereddict==1.1)]
>>> for package in pip_freeze.deprecated:
... print("%s: deprecated=%s, deprecated_by=%s, reason=%s" % (
package, package.deprecated, package.deprecated_by, package.deprecation_reason
))
...
Package(foobar==0.8): deprecated=True, deprecated_by=Requirement(foobar>=1.0), reason=foobar pre-1.0 is no longer supported, please upgrade to 1.x
Package(ordereddict==1.1): deprecated=True, deprecated_by=Requirement(ordereddict<0.0), reason=ordereddict is part of Python 2.7 and above. If you are still running Python 2.6, please upgrade!
包
包接受精确的包版本作为输入。
>>> from defrost import Package
>>> package = Package('foo==1.2')
>>> package.name
'foo'
>>> package.version
'1.2'
如果您在需求中没有传递精确的版本,则会引发一个 ValueError。
>>> package = Package('foo')
>>> Package('foo')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
...
ValueError: foo does not represent an exact package version; the format should be foo==1.0
您还可以手动弃用包
>>> package = Package('foo==1.2')
>>> package.deprecated
False
>>> package.deprecate(reason='because')
>>> package.deprecated
True
>>> package.deprecation_reason
'because'
需求
需求表示一系列包版本。
>>> from defrost import Requirement
>>> req = Requirement('foo>=1.0,<2.0')
>>> req.name
'foo'
>>> req.specifier
[('>=', '1.0'), ('<', '2.0')]
需求与包配合良好。使用 Python 操作符 in,您可以检查一个包是否满足需求。
>>> req = Requirement('foo>=1.0')
>>> Package('foo==1.0') in req
True
>>> Package('foo==2.0') in req
True
>>> Package('foo==0.1') in req
False
0.4.0
实现 PipFreeze.__getitem__ 和 PipFreeze.get()。
0.3.2
优雅地处理空白行和以破折号开头的行(https://github.com/SurveyMonkey/defrost/pull/14)
0.3.1
优雅地处理 pip freeze 输出中可能存在的注释
0.3.0
引入 defrost-lint 命令以测试需求文件的有效性。
0.2.0
移除属性 Package.raw 和 Requirement.raw,而是使用 Package.__str__() 和 Requirement.__str__()。
忽略 pip freeze 输出中找到的链接(-f 或 -e 行)
引入弃用严重性的概念。现在 Package.deprecate() 接收一个默认为 "error" 的 severity 关键字参数,并且 YAML 文件中的需求条目现在接受一个可选的 severity,可以设置为 error 或 warn。这会影响命令行界面的退出状态码。
PipFreeze.load_requirements() 如果未提供理由则会失败
0.1.0
添加属性 Package.deprecated_by
方法 Package.deprecate() 接收一个可选的 deprecated_by 参数。
添加命令行实用程序以列出给定需求文件和 pip freeze 输出文件的弃用包。
将项目 pipfreeze 重命名为 defrost 以避免与命令 pip freeze 混淆。
0.0.4
按名称和版本对包进行排序,以便 foo==2.0 在 foo-bar==1.0 之前,后者在将两者视为纯字符串时并不总是如此。
0.0.3
实现 Requirement
实现 Package
实现 PipFreeze.__contains__()
实现 PipFreeze.__len__()
停止支持 py26
移除 PipFreeze.satisfies_requirement()
实现 PipFreeze.load_requirements()
0.0.2
实现 PipFreeze.__bool__()(py3)和 PipFreeze.__nonzero__()(py2)
实现 PipFreeze.__iter__()
0.0.1
实现 pipfreeze.PipFreeze