Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-devpi-common for openSUSE:Factory checked in at 2021-08-03 22:48:57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-devpi-common (Old) and /work/SRC/openSUSE:Factory/.python-devpi-common.new.1899 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-devpi-common" Tue Aug 3 22:48:57 2021 rev:2 rq:909946 version:3.6.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-devpi-common/python-devpi-common.changes 2019-09-27 14:46:17.405101509 +0200 +++ /work/SRC/openSUSE:Factory/.python-devpi-common.new.1899/python-devpi-common.changes 2021-08-03 22:49:31.396440235 +0200 @@ -1,0 +2,10 @@ +Mon Aug 2 13:13:26 UTC 2021 - Mark??ta Machov?? <mmach...@suse.com> + +- Update to 3.6.0 + * support data-yanked attribute in HTMLPage parser. + * Replace ???cached_property??? with ???lazy??? package, which uses __dict__ + directly for much faster reads. + * Hide password from URL representation. + * Allow replacement of individual netloc parts with URL.replace method. + +------------------------------------------------------------------- Old: ---- devpi-common-3.4.0.tar.gz New: ---- devpi-common-3.6.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-devpi-common.spec ++++++ --- /var/tmp/diff_new_pack.IdG8Ys/_old 2021-08-03 22:49:31.944439574 +0200 +++ /var/tmp/diff_new_pack.IdG8Ys/_new 2021-08-03 22:49:31.948439569 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-devpi-common # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-devpi-common -Version: 3.4.0 +Version: 3.6.0 Release: 0 Summary: Utilities jointly used by devpi-server and devpi-client License: MIT @@ -33,6 +33,7 @@ BuildArch: noarch # SECTION test requirements BuildRequires: %{python_module py >= 1.4.20} +BuildRequires: %{python_module lazy} BuildRequires: %{python_module pytest} BuildRequires: %{python_module requests >= 2.3.0} # /SECTION ++++++ devpi-common-3.4.0.tar.gz -> devpi-common-3.6.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/CHANGELOG new/devpi-common-3.6.0/CHANGELOG --- old/devpi-common-3.4.0/CHANGELOG 2019-06-28 10:45:14.000000000 +0200 +++ new/devpi-common-3.6.0/CHANGELOG 2020-09-13 12:09:14.000000000 +0200 @@ -2,6 +2,28 @@ .. towncrier release notes start +3.6.0 (2020-09-13) +================== + +Features +-------- + +- Hide password from URL representation. + +- Allow replacement of individual netloc parts with URL.replace method. + + +3.5.0 (2020-05-04) +================== + +Features +-------- + +- fix #792: support data-yanked attribute in HTMLPage parser. + +- Replace "cached_property" with "lazy" package, which uses __dict__ directly for much faster reads. + + 3.4.0 (2019-06-28) ================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/PKG-INFO new/devpi-common-3.6.0/PKG-INFO --- old/devpi-common-3.4.0/PKG-INFO 2019-06-28 10:45:15.000000000 +0200 +++ new/devpi-common-3.6.0/PKG-INFO 2020-09-13 12:09:18.000000000 +0200 @@ -1,11 +1,11 @@ Metadata-Version: 1.2 Name: devpi-common -Version: 3.4.0 +Version: 3.6.0 Summary: utilities jointly used by devpi-server and devpi-client Home-page: https://github.com/devpi/devpi Maintainer: Holger Krekel Maintainer-email: hol...@merlinux.eu -License: UNKNOWN +License: MIT Description: This package contains utility functions used by devpi-server and devpi-client. @@ -20,49 +20,53 @@ .. towncrier release notes start - 3.4.0 (2019-06-28) + 3.6.0 (2020-09-13) ================== Features -------- - - Added full query string support to URL object. + - Hide password from URL representation. + - Allow replacement of individual netloc parts with URL.replace method. - 3.3.2 (2019-04-04) + + 3.5.0 (2020-05-04) ================== - Bug Fixes - --------- + Features + -------- - - Fix #641: support change of return code from string to integer in tox 3.8.x. + - fix #792: support data-yanked attribute in HTMLPage parser. + - Replace "cached_property" with "lazy" package, which uses __dict__ directly for much faster reads. - 3.3.1 (2018-09-18) + + 3.4.0 (2019-06-28) ================== - Bug Fixes - --------- + Features + -------- - - Fix uploading documentation in devpi-client < 4.1.0. + - Added full query string support to URL object. - 3.3.0 (2018-09-08) + 3.3.2 (2019-04-04) ================== - Features - -------- + Bug Fixes + --------- - - Add parsing of data-requires-python to link parser. Thanks to Sergey Kolosov + - Fix #641: support change of return code from string to integer in tox 3.8.x. - 3.2.3 (2018-05-04) + 3.3.1 (2018-09-18) ================== - Deprecations and Removals - ------------------------- + Bug Fixes + --------- - - remove unused vendored _verlib.py module + - Fix uploading documentation in devpi-client < 4.1.0. Platform: UNKNOWN @@ -71,3 +75,9 @@ Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/devpi_common/__init__.py new/devpi-common-3.6.0/devpi_common/__init__.py --- old/devpi-common-3.4.0/devpi_common/__init__.py 2019-06-28 10:45:14.000000000 +0200 +++ new/devpi-common-3.6.0/devpi_common/__init__.py 2020-09-13 12:09:14.000000000 +0200 @@ -1,2 +1,2 @@ # -__version__ = '3.4.0' +__version__ = '3.6.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/devpi_common/metadata.py new/devpi-common-3.6.0/devpi_common/metadata.py --- old/devpi-common-3.4.0/devpi_common/metadata.py 2019-06-28 10:45:14.000000000 +0200 +++ new/devpi-common-3.6.0/devpi_common/metadata.py 2020-09-13 12:09:14.000000000 +0200 @@ -3,6 +3,7 @@ import py from pkg_resources import parse_version, Requirement from .types import CompareMixin +from .types import cached_property from .validation import normalize_name @@ -122,11 +123,17 @@ class Version(CompareMixin): def __init__(self, versionstring): self.string = versionstring - self.cmpval = parse_version(versionstring) + + @cached_property + def cmpval(self): + return parse_version(self.string) def __str__(self): return self.string + def __repr__(self): + return "Version(%r)" % self.string + def is_prerelease(self): if hasattr(self.cmpval, 'is_prerelease'): return self.cmpval.is_prerelease diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/devpi_common/types.py new/devpi-common-3.6.0/devpi_common/types.py --- old/devpi-common-3.4.0/devpi_common/types.py 2019-06-28 10:45:14.000000000 +0200 +++ new/devpi-common-3.6.0/devpi_common/types.py 2020-09-13 12:09:14.000000000 +0200 @@ -1,4 +1,5 @@ from __future__ import absolute_import, unicode_literals +from lazy import lazy as cached_property # noqa from types import FunctionType import hashlib import operator @@ -26,23 +27,6 @@ return wrap -def cached_property(f): - """returns a cached property that is calculated by function f""" - def get(self): - try: - return self._property_cache[f] - except AttributeError: - self._property_cache = {} - except KeyError: - pass - x = self._property_cache[f] = f(self) - return x - - def set(self, val): - propcache = self.__dict__.setdefault("_property_cache", {}) - propcache[f] = val - return property(get, set) - class CompareMixin(object): def _cmp(self, other, op): return op(self.cmpval, other.cmpval) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/devpi_common/url.py new/devpi-common-3.6.0/devpi_common/url.py --- old/devpi-common-3.4.0/devpi_common/url.py 2019-06-28 10:45:14.000000000 +0200 +++ new/devpi-common-3.6.0/devpi_common/url.py 2020-09-13 12:09:14.000000000 +0200 @@ -40,11 +40,17 @@ __bool__ = __nonzero__ + def __str__(self): + return self.url + def __repr__(self): - c = repr(self.url.encode("utf8")) + cloaked = self + if self.password: + cloaked = self.replace(password="****") + cloaked = repr(cloaked.url.encode("utf8")) if sys.version_info >= (3,0): - c = c.lstrip("b") - return "<URL %s>" % c + cloaked = cloaked.lstrip("b") + return "URL(%s)" % cloaked def __eq__(self, other): return self.url == getattr(other, "url", other) @@ -76,6 +82,38 @@ def replace(self, **kwargs): _parsed = self._parsed url = [] + if set(kwargs).intersection(('username', 'password', 'hostname', 'port')): + netloc = "" + if "username" in kwargs: + if kwargs["username"]: + netloc += kwargs["username"] + elif self.username: + netloc += self.username + if "password" in kwargs: + if kwargs["password"]: + netloc += ":" + kwargs["password"] + elif self.password: + netloc += ":" + self.password + if netloc: + netloc += "@" + if "hostname" in kwargs: + if not kwargs["hostname"]: + raise ValueError("Can't use empty 'hostname'.") + netloc += kwargs["hostname"] + else: + if self.hostname: + netloc += self.hostname + if "port" in kwargs: + if kwargs["port"]: + netloc += ":%s" % kwargs["port"] + elif self.port: + netloc += ":%s" % self.port + if netloc != self.netloc: + if "netloc" in kwargs: + raise ValueError( + "Can't use 'netloc' together with any of " + "'username', 'password', 'hostname', 'port'.") + kwargs["netloc"] = netloc for field in ('scheme', 'netloc', 'path', 'query', 'fragment'): value = kwargs.get(field, getattr(_parsed, field)) if field == 'query': diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/devpi_common/vendor/_pip.py new/devpi-common-3.6.0/devpi_common/vendor/_pip.py --- old/devpi-common-3.4.0/devpi_common/vendor/_pip.py 2019-06-28 10:45:14.000000000 +0200 +++ new/devpi-common-3.6.0/devpi_common/vendor/_pip.py 2020-09-13 12:09:14.000000000 +0200 @@ -79,7 +79,8 @@ continue pyrequire = anchor.get('data-requires-python') - yield Link(url, self, requires_python=pyrequire) + yanked = 'data-yanked' in anchor + yield Link(url, self, requires_python=pyrequire, yanked=yanked) def rel_links(self, rels=('homepage', 'download')): for url in self.explicit_rel_links(rels): @@ -132,18 +133,23 @@ class Link(object): # CHANGED from PIP original: store requires_python - def __init__(self, url, comes_from=None, requires_python=None): + def __init__(self, url, comes_from=None, requires_python=None, yanked=False): self.url = url self.comes_from = comes_from self.requires_python = requires_python if requires_python else None + self.yanked = yanked def __str__(self): if self.requires_python: rp = ' (requires-python:%s)' % self.requires_python else: rp = '' + if self.yanked: + yanked = ' (yanked)' + else: + yanked = '' if self.comes_from: - return '%s (from %s)%s' % (self.url, self.comes_from, rp) + return '%s (from %s)%s%s' % (self.url, self.comes_from, rp, yanked) else: return str(self.url) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/devpi_common.egg-info/PKG-INFO new/devpi-common-3.6.0/devpi_common.egg-info/PKG-INFO --- old/devpi-common-3.4.0/devpi_common.egg-info/PKG-INFO 2019-06-28 10:45:15.000000000 +0200 +++ new/devpi-common-3.6.0/devpi_common.egg-info/PKG-INFO 2020-09-13 12:09:18.000000000 +0200 @@ -1,11 +1,11 @@ Metadata-Version: 1.2 Name: devpi-common -Version: 3.4.0 +Version: 3.6.0 Summary: utilities jointly used by devpi-server and devpi-client Home-page: https://github.com/devpi/devpi Maintainer: Holger Krekel Maintainer-email: hol...@merlinux.eu -License: UNKNOWN +License: MIT Description: This package contains utility functions used by devpi-server and devpi-client. @@ -20,49 +20,53 @@ .. towncrier release notes start - 3.4.0 (2019-06-28) + 3.6.0 (2020-09-13) ================== Features -------- - - Added full query string support to URL object. + - Hide password from URL representation. + - Allow replacement of individual netloc parts with URL.replace method. - 3.3.2 (2019-04-04) + + 3.5.0 (2020-05-04) ================== - Bug Fixes - --------- + Features + -------- - - Fix #641: support change of return code from string to integer in tox 3.8.x. + - fix #792: support data-yanked attribute in HTMLPage parser. + - Replace "cached_property" with "lazy" package, which uses __dict__ directly for much faster reads. - 3.3.1 (2018-09-18) + + 3.4.0 (2019-06-28) ================== - Bug Fixes - --------- + Features + -------- - - Fix uploading documentation in devpi-client < 4.1.0. + - Added full query string support to URL object. - 3.3.0 (2018-09-08) + 3.3.2 (2019-04-04) ================== - Features - -------- + Bug Fixes + --------- - - Add parsing of data-requires-python to link parser. Thanks to Sergey Kolosov + - Fix #641: support change of return code from string to integer in tox 3.8.x. - 3.2.3 (2018-05-04) + 3.3.1 (2018-09-18) ================== - Deprecations and Removals - ------------------------- + Bug Fixes + --------- - - remove unused vendored _verlib.py module + - Fix uploading documentation in devpi-client < 4.1.0. Platform: UNKNOWN @@ -71,3 +75,9 @@ Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/devpi_common.egg-info/SOURCES.txt new/devpi-common-3.6.0/devpi_common.egg-info/SOURCES.txt --- old/devpi-common-3.4.0/devpi_common.egg-info/SOURCES.txt 2019-06-28 10:45:15.000000000 +0200 +++ new/devpi-common-3.6.0/devpi_common.egg-info/SOURCES.txt 2020-09-13 12:09:18.000000000 +0200 @@ -2,6 +2,7 @@ LICENSE MANIFEST.in README.rst +pyproject.toml setup.cfg setup.py tox.ini diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/devpi_common.egg-info/requires.txt new/devpi-common-3.6.0/devpi_common.egg-info/requires.txt --- old/devpi-common-3.4.0/devpi_common.egg-info/requires.txt 2019-06-28 10:45:15.000000000 +0200 +++ new/devpi-common-3.6.0/devpi_common.egg-info/requires.txt 2020-09-13 12:09:18.000000000 +0200 @@ -1,2 +1,3 @@ -requests>=2.3.0 +lazy py>=1.4.20 +requests>=2.3.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/pyproject.toml new/devpi-common-3.6.0/pyproject.toml --- old/devpi-common-3.4.0/pyproject.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/devpi-common-3.6.0/pyproject.toml 2020-09-13 12:09:14.000000000 +0200 @@ -0,0 +1,26 @@ +[tool.towncrier] +package = "devpi_common" +filename = "CHANGELOG" +directory = "news/" +title_format = "{version} ({project_date})" +template = "news/_template.rst" + + [[tool.towncrier.type]] + directory = "removal" + name = "Deprecations and Removals" + showcontent = true + + [[tool.towncrier.type]] + directory = "feature" + name = "Features" + showcontent = true + + [[tool.towncrier.type]] + directory = "bugfix" + name = "Bug Fixes" + showcontent = true + + [[tool.towncrier.type]] + directory = "other" + name = "Other Changes" + showcontent = true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/setup.py new/devpi-common-3.6.0/setup.py --- old/devpi-common-3.4.0/setup.py 2019-06-28 10:45:14.000000000 +0200 +++ new/devpi-common-3.6.0/setup.py 2020-09-13 12:09:14.000000000 +0200 @@ -3,11 +3,15 @@ import io import os import re +import sys -from setuptools import setup, find_packages +from setuptools import setup def get_changelog(): + if 'bdist_rpm' in sys.argv: + # exclude changelog when building rpm + return "" text = io.open(os.path.join(here, 'CHANGELOG'), encoding='utf-8').read() header_matches = list(re.finditer('^=+$', text, re.MULTILINE)) # until fifth header @@ -26,17 +30,24 @@ name="devpi-common", description="utilities jointly used by devpi-server and devpi-client", long_description="\n\n".join([README, CHANGELOG]), - version='3.4.0', - packages=find_packages(), - install_requires=["requests>=2.3.0", "py>=1.4.20"], + version='3.6.0', + packages=['devpi_common', 'devpi_common.vendor'], + install_requires=[ + "lazy", + "py>=1.4.20", + "requests>=2.3.0"], url="https://github.com/devpi/devpi", maintainer="Holger Krekel", maintainer_email="hol...@merlinux.eu", + license="MIT", classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", - ], + "Programming Language :: Python :: Implementation :: PyPy", + ] + [ + ("Programming Language :: Python :: %s" % x) + for x in "2.7 3.4 3.5 3.6 3.7".split()], ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/testing/test_url.py new/devpi-common-3.6.0/testing/test_url.py --- old/devpi-common-3.4.0/testing/test_url.py 2019-06-28 10:45:14.000000000 +0200 +++ new/devpi-common-3.6.0/testing/test_url.py 2020-09-13 12:09:14.000000000 +0200 @@ -20,10 +20,16 @@ def test_repr(self): d = URL("http://host.com/path") - assert repr(d) == "<URL 'http://host.com/path'>" + assert repr(d) == "URL('http://host.com/path')" d = URL("http://host.com/path?foo=bar") - assert repr(d) == "<URL 'http://host.com/path?foo=bar'>" + assert repr(d) == "URL('http://host.com/path?foo=bar')" assert d.query == "foo=bar" + d = URL("http://foo:b...@host.com/path") + assert repr(d) == "URL('http://foo:****@host.com/path')" + + def test_str(self): + d = URL("http://foo:b...@host.com/path") + assert str(d) == "http://foo:b...@host.com/path" def test_parentbasename(self): d = URL("http://codespeak.net/simple/basename/") @@ -240,6 +246,46 @@ # trying to change something not existing does nothing assert url.replace(foo='https').url == "http://qwe/foo?bar=ham#hash" + def test_replace_netloc_parts(self): + url = URL("http://example.com") + assert url.replace(username="foo").url == "http://f...@example.com" + assert url.replace(password="foo").url == "http://:f...@example.com" + assert url.replace(hostname="foo").url == "http://foo" + assert url.replace(port="8080").url == "http://example.com:8080" + # original shouldn't have changed + assert url.url == "http://example.com" + url = URL("http://b...@example.com") + assert url.replace(username="foo").url == "http://f...@example.com" + assert url.replace(password="foo").url == "http://bar:f...@example.com" + assert url.replace(hostname="foo").url == "http://bar@foo" + assert url.replace(port="8080").url == "http://b...@example.com:8080" + # original shouldn't have changed + assert url.url == "http://b...@example.com" + url = URL("http://bar:sec...@example.com") + assert url.replace(username="foo").url == "http://foo:sec...@example.com" + assert url.replace(password="foo").url == "http://bar:f...@example.com" + assert url.replace(hostname="foo").url == "http://bar:secret@foo" + assert url.replace(port="8080").url == "http://bar:sec...@example.com:8080" + # original shouldn't have changed + assert url.url == "http://bar:sec...@example.com" + url = URL("http://example.com:8080") + assert url.replace(username="foo").url == "http://f...@example.com:8080" + assert url.replace(password="foo").url == "http://:f...@example.com:8080" + assert url.replace(hostname="foo").url == "http://foo:8080" + assert url.replace(port="1234").url == "http://example.com:1234" + # original shouldn't have changed + assert url.url == "http://example.com:8080" + url = URL("http://bar:sec...@example.com:8080") + assert url.replace(username=None).url == "http://:sec...@example.com:8080" + assert url.replace(password=None).url == "http://b...@example.com:8080" + with pytest.raises(ValueError): + url.replace(hostname=None) + assert url.replace(port=None).url == "http://bar:sec...@example.com" + with pytest.raises(ValueError): + url.replace(hostname="foo", netloc="bar") + # original shouldn't have changed + assert url.url == "http://bar:sec...@example.com:8080" + def test_replace_nothing(self): url = URL("http://qwe/foo?bar=ham#hash") new_url = url.replace() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/devpi-common-3.4.0/tox.ini new/devpi-common-3.6.0/tox.ini --- old/devpi-common-3.4.0/tox.ini 2019-06-28 10:45:14.000000000 +0200 +++ new/devpi-common-3.6.0/tox.ini 2020-09-13 12:09:14.000000000 +0200 @@ -1,19 +1,18 @@ [pytest] norecursedirs = attic .tox -addopts = -ra --flake8 -W once::DeprecationWarning +addopts = -r a --flake8 -W once::DeprecationWarning -W once::pytest.PytestDeprecationWarning flake8-ignore = * E501 setup.py E121 E123 *.py E114 E116 E126 E127 E128 E202 E225 E226 E227 E231 E261 E265 E266 E272 E301 E302 E303 E305 E306 E741 W391 -rsyncdirs = devpi testing -rsyncignore = .tox [tox] -envlist = py27,py34,py35,pypy +envlist = py27,py34,py38,pypy,pypy3 [testenv] -deps = pytest +deps = py34: colorama<=0.4.1 ; sys_platform == 'win32' + pytest pytest-flake8 commands = py.test {posargs}