Package: defrost
defrostNOTE: this package was originally calledpipfreezebut was renamed to avoid
confusion with the commandpip freeze.Defrost is a command line tool to check if the output of thepip freezecommand complies with a set of package requirements defined in a YAML file.Usagedefrost --helpFirst define a set of package requirements in a YAML file,requirements.yml.---requirements:-requirement:foobar>=1.0reason:foobar pre-1.0 is no longer supported, please upgrade to 1.x-requirement:ordereddict<0.0reason:OrderedDict is part of Python 2.7 and above. If you are still running Python 2.6, please upgrade!Then you can pipe the output ofpip freezeto defrost while providing the YAML file.$ 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.xDefrost can also take the pip freeze output as stdin by passing a dash sign-as argument in place of the pip freeze output file.$ 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.xYou can also check whether the YAML file provided is valid withdefrost-lint.$ defrost-lint requirements.ymlInstallpip install defrostLibraryThere are 3 fundamental objects available:PipFreeze: a pythonic container of packages that takes a pip freeze
output as input.Package: represents a package instance at an exact version (pinned)
held by a PipFreeze container (e.g.foo==1.2)Requirement: a requirement for a package represents one version
or a range of versions for a given package, e.g.foo>=2.0is a
requirement for all versions of foo greater or equal to 2.0.foowithout
a version specifier would mean all versions offoo.PipFreezePipFreeze takes a pip freeze output as input and builds packages internally.>>>fromdefrostimportPipFreeze>>>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'inpip_freezeTrue# test presence of any version of package zoo>>>'zoo'inpip_freezeFalse# test can also be done with a Package instance>>>Package('foo==0.1')inpip_freezeFalse# ... or with a Requirement>>>Requirement('bar>=2.0')inpip_freezeTruePackage deprecationYou can mark packages as deprecated by loading the YAML requirements file and
passing the result of it toPipFreeze.load_requirements(). Packages present
in PipFreeze will be marked as deprecated if they don’t satisfy the loaded
requirements. You can also provide an optional reason to why a package is
deprecated.>>>pip_freeze=PipFreeze("""\foobar==0.8
bar==2.0
ordereddict==1.1
""")>>>importyaml>>>reqs=yaml.load(open('my-reqs.yaml'))>>>pip_freeze.load_requirements(reqs)>>>pip_freeze.deprecated[Package(foobar==0.8),Package(ordereddict==1.1)]>>>forpackageinpip_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=foobarpre-1.0isnolongersupported,pleaseupgradeto1.xPackage(ordereddict==1.1):deprecated=True,deprecated_by=Requirement(ordereddict<0.0),reason=ordereddictispartofPython2.7andabove.IfyouarestillrunningPython2.6,pleaseupgrade!PackagePackages take an exact package version as input.>>>fromdefrostimportPackage>>>package=Package('foo==1.2')>>>package.name'foo'>>>package.version'1.2'If you don’t pass an exact version in your requirement it will raise aValueError.>>>package=Package('foo')>>>Package('foo')Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>...ValueError:foodoesnotrepresentanexactpackageversion;theformatshouldbefoo==1.0You can also manually deprecate packages:>>>package=Package('foo==1.2')>>>package.deprecatedFalse>>>package.deprecate(reason='because')>>>package.deprecatedTrue>>>package.deprecation_reason'because'RequirementA requirement represents a range of package versions.>>>fromdefrostimportRequirement>>>req=Requirement('foo>=1.0,<2.0')>>>req.name'foo'>>>req.specifier[('>=','1.0'),('<','2.0')]Requirements play well with packages. Using the Python operatorin, you
can check if a package satifies a requirement.>>>req=Requirement('foo>=1.0')>>>Package('foo==1.0')inreqTrue>>>Package('foo==2.0')inreqTrue>>>Package('foo==0.1')inreqFalse0.4.0implementPipFreeze.__getitem__andPipFreeze.get().0.3.2gracefully handle blank lines and lines starting with dash
(https://github.com/SurveyMonkey/defrost/pull/14)0.3.1gracefully handle comments that may be present in pip freeze output0.3.0introducedefrost-lintcommand to test the validity of requirement files.0.2.0remove attributesPackage.rawandRequirement.raw, instead usePackage.__str__()andRequirement.__str__().ignore links found in pip freeze output (-f or -e lines)Introduce the notion of deprecation severity.Package.deprecate()now
takes a severity kwarg which defaults to"error"and a requirement entry
in the YAML file now accepts an optionalseveritywhich can be set toerrororwarn. This affects the exit status code for the command line
interface.PipFreeze.load_requirements()would choke if a reason was not provided0.1.0add attributePackage.deprecated_bymethodPackage.deprecate()takes an optionaldeprecated_byargument.add command line utility to list deprecated packages given a requirement file
and a pip freeze output file.rename project pipfreeze to defrost to avoid confusion with the commandpip freeze.0.0.4sort packages on name and then version such thatfoo==2.0comes beforefoo-bar==1.0which is not the case when both are treated as plain
strings.0.0.3implementRequirementimplementPackageimplementPipFreeze.__contains__()implementPipFreeze.__len__()drop py26 supportremovePipFreeze.satisfies_requirement()implementPipFreeze.load_requirements()0.0.2implementPipFreeze.__bool__()(py3) andPipFreeze.__nonzero__()(py2)implementPipFreeze.__iter__()0.0.1implementpipfreeze.PipFreeze