# -*- coding: utf-8 -*-
# Copyright 2018 Joshua Bronson. All Rights Reserved.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.


u"""Compatibility helpers.

.. py:attribute:: PY2

    True iff running on Python < 3.

.. py:attribute:: PYPY

    True iff running on PyPy.

.. py:attribute:: viewkeys

    ``viewkeys(x) → x.viewkeys() if PY2 else x.keys()``

.. py:attribute:: viewvalues

    ``viewvalues(x) → x.viewvalues() if PY2 else x.values()``

.. py:attribute:: viewitems

    ``viewitems(x) → x.viewitems() if PY2 else x.items()``

.. py:attribute:: iterkeys

    ``iterkeys(x) → x.iterkeys() if PY2 else iter(x.keys())``

.. py:attribute:: itervalues

    ``itervalues(x) → x.itervalues() if PY2 else iter(x.values())``

.. py:attribute:: iteritems

    ``iteritems(x) → x.iteritems() if PY2 else iter(x.items())``

.. py:attribute:: izip

    ``itertools.izip() if PY2 else zip``

"""

from operator import methodcaller
from platform import python_implementation
from sys import version_info
from warnings import warn

PYMAJOR, PYMINOR = version_info[:2]
PY2 = PYMAJOR == 2
PYIMPL = python_implementation()
CPY = PYIMPL == 'CPython'
PYPY = PYIMPL == 'PyPy'
DICTS_ORDERED = PYPY or (CPY and (PYMAJOR, PYMINOR) >= (3, 6))

# Without the following, pylint gives lots of false positives.
# pylint: disable=invalid-name,unused-import,ungrouped-imports,no-name-in-module

if PY2:

    if PYMINOR < 7:  # pragma: no cover
        warn('Python < 2.7 is unsupported.')

    viewkeys = methodcaller('viewkeys')
    viewvalues = methodcaller('viewvalues')
    viewitems = methodcaller('viewitems')

    iterkeys = methodcaller('iterkeys')
    itervalues = methodcaller('itervalues')
    iteritems = methodcaller('iteritems')

    # abstractproperty deprecated in Python 3.3 in favor of using @property with @abstractmethod.
    # Before 3.3, this silently fails to detect when an abstract property has not been overridden.
    from abc import abstractproperty

    from itertools import izip

    # In Python 3, the collections ABCs were moved into collections.abc, which does not exist in
    # Python 2. Support for importing them directly from collections is dropped in Python 3.8.
    from collections import (  # noqa: F401 (imported but unused)
        Mapping, MutableMapping, KeysView, ItemsView)

else:
    # Assume Python 3 when not PY2, but explicitly check before showing this warning.
    if PYMAJOR == 3 and PYMINOR < 3:  # pragma: no cover
        warn('Python3 < 3.3 is unsupported.')

    viewkeys = methodcaller('keys')
    viewvalues = methodcaller('values')
    viewitems = methodcaller('items')

    def _compose(f, g):
        return lambda x: f(g(x))

    iterkeys = _compose(iter, viewkeys)
    itervalues = _compose(iter, viewvalues)
    iteritems = _compose(iter, viewitems)

    from abc import abstractmethod
    abstractproperty = _compose(property, abstractmethod)

    izip = zip

    from collections.abc import (  # noqa: F401 (imported but unused)
        Mapping, MutableMapping, KeysView, ItemsView)
