strategy:
fail-fast: false
matrix:
- python: ["2.7", "3.5", "3.6", "3.7", "3.8", "pypy3"]
+ python: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "pypy3"]
os: [ubuntu-latest, windows-latest]
include:
- python: "2.7"
tox_env: "py37-pytest30"
- python: "3.8"
tox_env: "py38-pytest30"
+ - python: "3.9"
+ tox_env: "py39-pytest30"
- python: "pypy3"
tox_env: "pypy3-pytest30"
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v2
- name: Set up Python
- uses: actions/setup-python@v1
+ uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- - name: Install tox
- run: |
- python -m pip install --upgrade pip
- pip install tox
- name: Test
run: |
- tox -e ${{ matrix.tox_env }}
+ pipx run tox -e ${{ matrix.tox_env }}
deploy:
needs: build
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v2
- name: Set up Python
- uses: actions/setup-python@v1
+ uses: actions/setup-python@v2
with:
python-version: "3.7"
- name: Install wheel
+1.11.0 (2021-11-04)
+===================
+
+- Support Python 3.11
+- Support ``NO_COLOR`` environment variable
+- Update vendored apipkg: 1.5 => 2.0
+
1.10.0 (2020-12-12)
===================
- `py-dev developers list`_ and `commit mailing list`_.
-- #pylib on irc.freenode.net IRC channel for random questions.
+- ``#pytest`` `on irc.libera.chat <ircs://irc.libera.chat:6697/#pytest>`_ IRC
+ channel for random questions (using an IRC client, `via webchat
+ <https://web.libera.chat/#pytest>`_, or `via Matrix
+ <https://matrix.to/#/%23pytest:libera.chat>`_).
- `issue tracker`_ use the issue tracker to report
bugs or request features.
return True
if os.environ.get('PY_COLORS') == '0':
return False
+ if 'NO_COLOR' in os.environ:
+ return False
return hasattr(file, 'isatty') and file.isatty() \
and os.environ.get('TERM') != 'dumb' \
and not (sys.platform.startswith('java') and os._name == 'nt')
+++ /dev/null
-Metadata-Version: 2.1
-Name: apipkg
-Version: 1.5
-Summary: apipkg: namespace control and lazy-import mechanism
-Home-page: https://github.com/pytest-dev/apipkg
-Author: holger krekel
-Maintainer: Ronny Pfannschmidt
-Maintainer-email: opensource@ronnypfannschmidt.de
-License: MIT License
-Platform: unix
-Platform: linux
-Platform: osx
-Platform: cygwin
-Platform: win32
-Classifier: Development Status :: 4 - Beta
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Operating System :: POSIX
-Classifier: Operating System :: Microsoft :: Windows
-Classifier: Operating System :: MacOS :: MacOS X
-Classifier: Topic :: Software Development :: Libraries
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
-
-Welcome to apipkg!
-------------------------
-
-With apipkg you can control the exported namespace of a Python package and
-greatly reduce the number of imports for your users.
-It is a `small pure Python module`_ that works on CPython 2.7 and 3.4+,
-Jython and PyPy. It cooperates well with Python's ``help()`` system,
-custom importers (PEP302) and common command-line completion tools.
-
-Usage is very simple: you can require 'apipkg' as a dependency or you
-can copy paste the ~200 lines of code into your project.
-
-
-Tutorial example
--------------------
-
-Here is a simple ``mypkg`` package that specifies one namespace
-and exports two objects imported from different modules::
-
- # mypkg/__init__.py
- import apipkg
- apipkg.initpkg(__name__, {
- 'path': {
- 'Class1': "_mypkg.somemodule:Class1",
- 'clsattr': "_mypkg.othermodule:Class2.attr",
- }
- }
-
-The package is initialized with a dictionary as namespace.
-
-You need to create a ``_mypkg`` package with a ``somemodule.py``
-and ``othermodule.py`` containing the respective classes.
-The ``_mypkg`` is not special - it's a completely
-regular Python package.
-
-Namespace dictionaries contain ``name: value`` mappings
-where the value may be another namespace dictionary or
-a string specifying an import location. On accessing
-an namespace attribute an import will be performed::
-
- >>> import mypkg
- >>> mypkg.path
- <ApiModule 'mypkg.path'>
- >>> mypkg.path.Class1 # '_mypkg.somemodule' gets imported now
- <class _mypkg.somemodule.Class1 at 0xb7d428fc>
- >>> mypkg.path.clsattr # '_mypkg.othermodule' gets imported now
- 4 # the value of _mypkg.othermodule.Class2.attr
-
-The ``mypkg.path`` namespace and its two entries are
-loaded when they are accessed. This means:
-
-* lazy loading - only what is actually needed is ever loaded
-
-* only the root "mypkg" ever needs to be imported to get
- access to the complete functionality
-
-* the underlying modules are also accessible, for example::
-
- from mypkg.sub import Class1
-
-
-Including apipkg in your package
---------------------------------------
-
-If you don't want to add an ``apipkg`` dependency to your package you
-can copy the `apipkg.py`_ file somewhere to your own package,
-for example ``_mypkg/apipkg.py`` in the above example. You
-then import the ``initpkg`` function from that new place and
-are good to go.
-
-.. _`small pure Python module`:
-.. _`apipkg.py`: https://github.com/pytest-dev/apipkg/blob/master/src/apipkg/__init__.py
-
-Feedback?
------------------------
-
-If you have questions you are welcome to
-
-* join the #pylib channel on irc.freenode.net
-* create an issue on https://github.com/pytest-dev/apipkg/issues
-
-have fun,
-holger krekel
-
-
+++ /dev/null
-../../../../home/ran/.cache/pycache/tmp/pip-target-oxds71ih/lib/python/apipkg/__init__.cpython-39.pyc,,\r
-../../../../home/ran/.cache/pycache/tmp/pip-target-oxds71ih/lib/python/apipkg/version.cpython-39.pyc,,\r
-apipkg-1.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4\r
-apipkg-1.5.dist-info/METADATA,sha256=tIG1DSBzSeqmSRpOKHSEBmT1eOPdK8xK01xAIADuks4,3800\r
-apipkg-1.5.dist-info/RECORD,,\r
-apipkg-1.5.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0\r
-apipkg-1.5.dist-info/WHEEL,sha256=gduuPyBvFJQSQ0zdyxF7k0zynDXbIbvg5ZBHoXum5uk,110\r
-apipkg-1.5.dist-info/top_level.txt,sha256=3TGS6nmN7kjxhUK4LpPCB3QkQI34QYGrT0ZQGWajoZ8,7\r
-apipkg/__init__.py,sha256=VogR4mDwYmeOdJnjGi-RoMB1qJnD6_puDYj_nRolzhM,6707\r
-apipkg/version.py,sha256=YN6DnKyEPqjDAauJuwJRG9vlKbWVLd9gAbH7mkQXXNo,114\r
+++ /dev/null
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.31.1)
-Root-Is-Purelib: true
-Tag: py2-none-any
-Tag: py3-none-any
-
--- /dev/null
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
--- /dev/null
+Metadata-Version: 2.1
+Name: apipkg
+Version: 2.0.0
+Summary: apipkg: namespace control and lazy-import mechanism
+Home-page: https://github.com/pytest-dev/apipkg
+Author: holger krekel
+Maintainer: Ronny Pfannschmidt
+Maintainer-email: opensource@ronnypfannschmidt.de
+License: MIT
+Platform: unix
+Platform: linux
+Platform: osx
+Platform: cygwin
+Platform: win32
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Topic :: Software Development :: Libraries
+Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7
+Description-Content-Type: text/x-rst
+License-File: LICENSE
+
+Welcome to apipkg !
+-------------------
+
+With apipkg you can control the exported namespace of a Python package and
+greatly reduce the number of imports for your users.
+It is a `small pure Python module`_ that works on CPython 2.7 and 3.4+,
+Jython and PyPy. It cooperates well with Python's ``help()`` system,
+custom importers (PEP302) and common command-line completion tools.
+
+Usage is very simple: you can require 'apipkg' as a dependency or you
+can copy paste the ~200 lines of code into your project.
+
+
+Tutorial example
+-------------------
+
+Here is a simple ``mypkg`` package that specifies one namespace
+and exports two objects imported from different modules::
+
+
+ # mypkg/__init__.py
+ import apipkg
+ apipkg.initpkg(__name__, {
+ 'path': {
+ 'Class1': "_mypkg.somemodule:Class1",
+ 'clsattr': "_mypkg.othermodule:Class2.attr",
+ }
+ }
+
+The package is initialized with a dictionary as namespace.
+
+You need to create a ``_mypkg`` package with a ``somemodule.py``
+and ``othermodule.py`` containing the respective classes.
+The ``_mypkg`` is not special - it's a completely
+regular Python package.
+
+Namespace dictionaries contain ``name: value`` mappings
+where the value may be another namespace dictionary or
+a string specifying an import location. On accessing
+an namespace attribute an import will be performed::
+
+ >>> import mypkg
+ >>> mypkg.path
+ <ApiModule 'mypkg.path'>
+ >>> mypkg.path.Class1 # '_mypkg.somemodule' gets imported now
+ <class _mypkg.somemodule.Class1 at 0xb7d428fc>
+ >>> mypkg.path.clsattr # '_mypkg.othermodule' gets imported now
+ 4 # the value of _mypkg.othermodule.Class2.attr
+
+The ``mypkg.path`` namespace and its two entries are
+loaded when they are accessed. This means:
+
+* lazy loading - only what is actually needed is ever loaded
+
+* only the root "mypkg" ever needs to be imported to get
+ access to the complete functionality
+
+* the underlying modules are also accessible, for example::
+
+ from mypkg.sub import Class1
+
+
+Including apipkg in your package
+--------------------------------------
+
+If you don't want to add an ``apipkg`` dependency to your package you
+can copy the `apipkg.py`_ file somewhere to your own package,
+for example ``_mypkg/apipkg.py`` in the above example. You
+then import the ``initpkg`` function from that new place and
+are good to go.
+
+.. _`small pure Python module`:
+.. _`apipkg.py`: https://github.com/pytest-dev/apipkg/blob/master/src/apipkg/__init__.py
+
+Feedback?
+-----------------------
+
+If you have questions you are welcome to
+
+* join the **#pytest** channel on irc.libera.chat_
+ (using an IRC client, via webchat_, or via Matrix_).
+* create an issue on the bugtracker_
+
+.. _irc.libera.chat: ircs://irc.libera.chat:6697/#pytest
+.. _webchat: https://web.libera.chat/#pytest
+.. _matrix: https://matrix.to/#/%23pytest:libera.chat
+.. _bugtracker: https://github.com/pytest-dev/apipkg/issues
+
+
--- /dev/null
+apipkg-2.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4\r
+apipkg-2.0.0.dist-info/LICENSE,sha256=6J7tEHTTqUMZi6E5uAhE9bRFuGC7p0qK6twGEFZhZOo,1054\r
+apipkg-2.0.0.dist-info/METADATA,sha256=GqNwkxraK5UTxObLVXTLc2UqktOPwZnKqdk2ThzHX0A,4292\r
+apipkg-2.0.0.dist-info/RECORD,,\r
+apipkg-2.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0\r
+apipkg-2.0.0.dist-info/WHEEL,sha256=WzZ8cwjh8l0jtULNjYq1Hpr-WCqCRgPr--TX4P5I1Wo,110\r
+apipkg-2.0.0.dist-info/top_level.txt,sha256=3TGS6nmN7kjxhUK4LpPCB3QkQI34QYGrT0ZQGWajoZ8,7\r
+apipkg/__init__.py,sha256=gpbD3O57S9f-LsO2e-XwI6IGISayicfnCq3B5y_8frg,6978\r
+apipkg/__pycache__/__init__.cpython-39.pyc,,\r
+apipkg/__pycache__/version.cpython-39.pyc,,\r
+apipkg/version.py,sha256=bgZFg-f3UKhgE-z2w8RoFrwqRBzJBZkM4_jKFiYB9eU,142\r
--- /dev/null
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.37.0)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+
import sys
from types import ModuleType
-from .version import version as __version__
+from .version import version as __version__ # NOQA:F401
def _py_abspath(path):
special version of abspath
that will leave paths from jython jars alone
"""
- if path.startswith('__pyclasspath__'):
+ if path.startswith("__pyclasspath__"):
return path
else:
"""try to get the version of the named distribution,
returs None on failure"""
from pkg_resources import get_distribution, DistributionNotFound
+
try:
dist = get_distribution(name)
except DistributionNotFound:
attr = attr or {}
oldmod = sys.modules.get(pkgname)
d = {}
- f = getattr(oldmod, '__file__', None)
+ f = getattr(oldmod, "__file__", None)
if f:
f = _py_abspath(f)
- d['__file__'] = f
- if hasattr(oldmod, '__version__'):
- d['__version__'] = oldmod.__version__
- if hasattr(oldmod, '__loader__'):
- d['__loader__'] = oldmod.__loader__
- if hasattr(oldmod, '__path__'):
- d['__path__'] = [_py_abspath(p) for p in oldmod.__path__]
- if hasattr(oldmod, '__package__'):
- d['__package__'] = oldmod.__package__
- if '__doc__' not in exportdefs and getattr(oldmod, '__doc__', None):
- d['__doc__'] = oldmod.__doc__
+ d["__file__"] = f
+ if hasattr(oldmod, "__version__"):
+ d["__version__"] = oldmod.__version__
+ if hasattr(oldmod, "__loader__"):
+ d["__loader__"] = oldmod.__loader__
+ if hasattr(oldmod, "__path__"):
+ d["__path__"] = [_py_abspath(p) for p in oldmod.__path__]
+ if hasattr(oldmod, "__package__"):
+ d["__package__"] = oldmod.__package__
+ if "__doc__" not in exportdefs and getattr(oldmod, "__doc__", None):
+ d["__doc__"] = oldmod.__doc__
+ d["__spec__"] = getattr(oldmod, "__spec__", None)
d.update(attr)
if hasattr(oldmod, "__dict__"):
oldmod.__dict__.update(d)
mod = ApiModule(pkgname, exportdefs, implprefix=pkgname, attr=d)
sys.modules[pkgname] = mod
# eagerload in bypthon to avoid their monkeypatching breaking packages
- if 'bpython' in sys.modules or eager:
+ if "bpython" in sys.modules or eager:
for module in list(sys.modules.values()):
if isinstance(module, ApiModule):
module.__dict__
+ return mod
def importobj(modpath, attrname):
"""imports a module, then resolves the attrname on it"""
- module = __import__(modpath, None, None, ['__doc__'])
+ module = __import__(modpath, None, None, ["__doc__"])
if not attrname:
return module
class ApiModule(ModuleType):
"""the magical lazy-loading module standing"""
+
def __docget(self):
try:
return self.__doc
except AttributeError:
- if '__doc__' in self.__map__:
- return self.__makeattr('__doc__')
+ if "__doc__" in self.__map__:
+ return self.__makeattr("__doc__")
def __docset(self, value):
self.__doc = value
+
__doc__ = property(__docget, __docset)
def __init__(self, name, importspec, implprefix=None, attr=None):
self.__name__ = name
- self.__all__ = [x for x in importspec if x != '__onfirstaccess__']
+ self.__all__ = [x for x in importspec if x != "__onfirstaccess__"]
self.__map__ = {}
self.__implprefix__ = implprefix or name
if attr:
setattr(self, name, val)
for name, importspec in importspec.items():
if isinstance(importspec, dict):
- subname = '%s.%s' % (self.__name__, name)
+ subname = "{}.{}".format(self.__name__, name)
apimod = ApiModule(subname, importspec, implprefix)
sys.modules[subname] = apimod
setattr(self, name, apimod)
else:
- parts = importspec.split(':')
+ parts = importspec.split(":")
modpath = parts.pop(0)
attrname = parts and parts[0] or ""
- if modpath[0] == '.':
+ if modpath[0] == ".":
modpath = implprefix + modpath
if not attrname:
- subname = '%s.%s' % (self.__name__, name)
+ subname = "{}.{}".format(self.__name__, name)
apimod = AliasModule(subname, modpath)
sys.modules[subname] = apimod
- if '.' not in name:
+ if "." not in name:
setattr(self, name, apimod)
else:
self.__map__[name] = (modpath, attrname)
def __repr__(self):
repr_list = []
- if hasattr(self, '__version__'):
+ if hasattr(self, "__version__"):
repr_list.append("version=" + repr(self.__version__))
- if hasattr(self, '__file__'):
- repr_list.append('from ' + repr(self.__file__))
+ if hasattr(self, "__file__"):
+ repr_list.append("from " + repr(self.__file__))
if repr_list:
- return '<ApiModule %r %s>' % (self.__name__, " ".join(repr_list))
- return '<ApiModule %r>' % (self.__name__,)
+ return "<ApiModule {!r} {}>".format(self.__name__, " ".join(repr_list))
+ return "<ApiModule {!r}>".format(self.__name__)
def __makeattr(self, name):
"""lazily compute value for name or raise AttributeError if unknown."""
# print "makeattr", self.__name__, name
target = None
- if '__onfirstaccess__' in self.__map__:
- target = self.__map__.pop('__onfirstaccess__')
+ if "__onfirstaccess__" in self.__map__:
+ target = self.__map__.pop("__onfirstaccess__")
importobj(*target)()
try:
modpath, attrname = self.__map__[name]
except KeyError:
- if target is not None and name != '__onfirstaccess__':
+ if target is not None and name != "__onfirstaccess__":
# retry, onfirstaccess might have set attrs
return getattr(self, name)
raise AttributeError(name)
def __dict__(self):
# force all the content of the module
# to be loaded when __dict__ is read
- dictdescr = ModuleType.__dict__['__dict__']
+ dictdescr = ModuleType.__dict__["__dict__"]
dict = dictdescr.__get__(self)
if dict is not None:
- hasattr(self, 'some')
+ hasattr(self, "some")
for name in self.__all__:
try:
self.__makeattr(name)
mod.append(x)
return mod[0]
- class AliasModule(ModuleType):
+ x = modpath + ("." + attrname if attrname else "")
+ repr_result = "<AliasModule {!r} for {!r}>".format(modname, x)
+ class AliasModule(ModuleType):
def __repr__(self):
- x = modpath
- if attrname:
- x += "." + attrname
- return '<AliasModule %r for %r>' % (modname, x)
+ return repr_result
def __getattribute__(self, name):
try:
return getattr(getmod(), name)
except ImportError:
- return None
+ if modpath == "pytest" and attrname is None:
+ # hack for pylibs py.test
+ return None
+ else:
+ raise
def __setattr__(self, name, value):
setattr(getmod(), name, value)
# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
-version = '1.5'
+version = '2.0.0'
+version_tuple = (2, 0, 0)
-../../../../home/ran/.cache/pycache/tmp/pip-target-oxds71ih/lib/python/iniconfig/__init__.cpython-39.pyc,,\r
iniconfig-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4\r
iniconfig-1.1.1.dist-info/LICENSE,sha256=KvaAw570k_uCgwNW0dPfGstaBgM8ui3sehniHKp3qGY,1061\r
iniconfig-1.1.1.dist-info/METADATA,sha256=_4-oFKpRXuZv5rzepScpXRwhq6DzqsgbnA5ZpgMUMcs,2405\r
iniconfig-1.1.1.dist-info/top_level.txt,sha256=7KfM0fugdlToj9UW7enKXk2HYALQD8qHiyKtjhSzgN8,10\r
iniconfig/__init__.py,sha256=-pBe5AF_6aAwo1CxJQ8i_zJq6ejc6IxHta7qk2tNJhY,5208\r
iniconfig/__init__.pyi,sha256=-4KOctzq28ohRmTZsqlH6aylyFqsNKxYqtk1dteypi4,1205\r
+iniconfig/__pycache__/__init__.cpython-39.pyc,,\r
iniconfig/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0\r
--- /dev/null
+[build-system]
+requires = [
+ "setuptools",
+ "setuptools_scm[toml]",
+]
+build-backend = "setuptools.build_meta"
description='library with cross-python path, ini-parsing, io, code, log facilities',
long_description=open('README.rst').read(),
use_scm_version={"write_to": "py/_version.py"},
- setup_requires=["setuptools-scm"],
+ setup_requires=["setuptools_scm"],
url='https://py.readthedocs.io/',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
- python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
+ python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
author='holger krekel, Ronny Pfannschmidt, Benjamin Peterson and others',
author_email='pytest-dev@python.org',
classifiers=['Development Status :: 6 - Mature',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
+ 'Programming Language :: Python :: 3.9',
+ 'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
],
tw.line("hello", bold=True)
s = f.getvalue()
assert s == "hello\n"
+
+def test_should_do_markup(monkeypatch):
+ monkeypatch.delenv("PY_COLORS", raising=False)
+ monkeypatch.delenv("NO_COLOR", raising=False)
+
+ should_do_markup = terminalwriter.should_do_markup
+
+ f = py.io.TextIO()
+ f.isatty = lambda: True
+
+ assert should_do_markup(f) is True
+
+ # NO_COLOR without PY_COLORS.
+ monkeypatch.setenv("NO_COLOR", "0")
+ assert should_do_markup(f) is False
+ monkeypatch.setenv("NO_COLOR", "1")
+ assert should_do_markup(f) is False
+ monkeypatch.setenv("NO_COLOR", "any")
+ assert should_do_markup(f) is False
+
+ # PY_COLORS overrides NO_COLOR ("0" and "1" only).
+ monkeypatch.setenv("PY_COLORS", "1")
+ assert should_do_markup(f) is True
+ monkeypatch.setenv("PY_COLORS", "0")
+ assert should_do_markup(f) is False
+ # Uses NO_COLOR.
+ monkeypatch.setenv("PY_COLORS", "any")
+ assert should_do_markup(f) is False
+ monkeypatch.delenv("NO_COLOR")
+ assert should_do_markup(f) is True
+
+ # Back to defaults.
+ monkeypatch.delenv("PY_COLORS")
+ assert should_do_markup(f) is True
+ f.isatty = lambda: False
+ assert should_do_markup(f) is False
mypath = py.path.local(__file__).new(ext=".py")
-win = sys.platform.startswith('win')
-pytestmark = pytest.mark.skipif(win and LooseVersion(pytest.__version__) >= LooseVersion('3.1'),
+pytestmark = pytest.mark.skipif(LooseVersion(pytest.__version__) >= LooseVersion('3.1'),
reason='apiwarn is not compatible with pytest >= 3.1 (#162)')