From 07fac0628c0fed1d99d2217ede407083dd593e65 Mon Sep 17 00:00:00 2001 From: Hugo Date: Tue, 14 Aug 2018 16:26:15 +0300 Subject: [PATCH] Drop support for legacy Python 2 --- .travis.yml | 9 +----- CHANGELOG.md | 3 ++ README.md | 12 ++++---- clonedigger.sh | 4 --- pylast/__init__.py | 67 +++++++++++++++++++++++-------------------- pylast/version.py | 2 +- setup.py | 42 ++++++++++++++++++++++----- tests/test_user.py | 2 +- tests/unicode_test.py | 11 ++++--- tox.ini | 18 ++---------- 10 files changed, 90 insertions(+), 80 deletions(-) delete mode 100755 clonedigger.sh diff --git a/.travis.yml b/.travis.yml index 806ff26..1ab965b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,12 +15,8 @@ env: matrix: include: - - python: 2.7 - env: TOXENV=py2lint - - python: 2.7 - env: TOXENV=py27 - python: 3.6 - env: TOXENV=py3lint + env: TOXENV=lint - python: 3.7 env: TOXENV=py37 dist: xenial @@ -33,13 +29,10 @@ matrix: env: TOXENV=py34 - python: pypy3 env: TOXENV=pypy3 - - python: pypy - env: TOXENV=pypy - python: 3.8-dev env: TOXENV=py38dev dist: xenial allow_failures: - - env: TOXENV=pypy - env: TOXENV=pypy3 fast_finish: true diff --git a/CHANGELOG.md b/CHANGELOG.md index f801aff..3c8d300 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - This changelog file ([#273]) +### Removed + +* Support for Python 2.7 ([#265]) ## [2.4.0] - 2018-08-08 ### Deprecated diff --git a/README.md b/README.md index 89334f7..13d8b64 100644 --- a/README.md +++ b/README.md @@ -29,12 +29,12 @@ Or from requirements.txt: Note: -* pylast >= 3.0.0 will likely only support Python 3.4+ ([#265](https://github.com/pylast/pylast/issues/265)) -* pyLast >= 2.2.0 supports Python 2.7.10+, 3.4, 3.5, 3.6, 3.7. -* pyLast >= 2.0.0 < 2.2.0 supports Python 2.7.10+, 3.4, 3.5, 3.6. -* pyLast >= 1.7.0 < 2.0.0 supports Python 2.7, 3.3, 3.4, 3.5, 3.6. -* pyLast >= 1.0.0 < 1.7.0 supports Python 2.7, 3.3, 3.4. -* pyLast >= 0.5 < 1.0.0 supports Python 2, 3. +* pylast 3.0.0+ supports Python 3.4+ ([#265](https://github.com/pylast/pylast/issues/265)) +* pyLast 2.2.0 - 2.4.0 supports Python 2.7.10+, 3.4, 3.5, 3.6, 3.7. +* pyLast 2.0.0 - 2.1.0 supports Python 2.7.10+, 3.4, 3.5, 3.6. +* pyLast 1.7.0 - 1.9.0 supports Python 2.7, 3.3, 3.4, 3.5, 3.6. +* pyLast 1.0.0 - 1.6.0 supports Python 2.7, 3.3, 3.4. +* pyLast 0.5 supports Python 2, 3. * pyLast < 0.5 supports Python 2. Features diff --git a/clonedigger.sh b/clonedigger.sh deleted file mode 100755 index 96dc493..0000000 --- a/clonedigger.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -clonedigger pylast -grep -E "Clones detected|lines are duplicates" output.html -exit 0 diff --git a/pylast/__init__.py b/pylast/__init__.py index b2ffa37..1e988bf 100644 --- a/pylast/__init__.py +++ b/pylast/__init__.py @@ -25,13 +25,13 @@ import collections import hashlib import logging import shelve -import six import ssl import sys import tempfile import time -import warnings import xml.dom +import html.entities +from http.client import HTTPSConnection from . import version @@ -44,24 +44,33 @@ __email__ = "amr.hassan@gmail.com" __version__ = version.__version__ if sys.version_info < (3,): - warnings.warn( - "You are using pylast with Python 2. " - "Pylast will soon be Python 3 only. " - "More info: https://github.com/pylast/pylast/issues/265", - UserWarning, + raise ImportError( + """pylast 3.0 and above are no longer compatible with Python 2. + +This is pylast {} and you are using Python {}. +Make sure you have pip >= 9.0 and setuptools >= 24.2 and retry: + + $ pip install --upgrade pip setuptools + +Other choices: + +- Upgrade to Python 3. + +- Install an older version of pylast: + +$ pip install 'pylast<3.0' + +For more information: + +https://github.com/pylast/pylast/issues/265 +""".format( + version, ".".join([str(v) for v in sys.version_info[:3]]) + ) ) - -if sys.version_info.major == 2: - import htmlentitydefs - from httplib import HTTPSConnection - from urllib import quote_plus as url_quote_plus else: - import html.entities as htmlentitydefs - from http.client import HTTPSConnection + # Keep importable on Python 2 for a while to show ImportError from urllib.parse import quote_plus as url_quote_plus - unichr = chr - STATUS_INVALID_SERVICE = 2 STATUS_INVALID_METHOD = 3 @@ -123,7 +132,7 @@ SCROBBLE_MODE_SKIPPED = "S" # Delay time in seconds from section 4.4 of https://www.last.fm/api/tos DELAY_TIME = 0.2 -# Python >3.4 and >2.7.9 has sane defaults +# Python >3.4 has sane defaults SSL_CONTEXT = ssl.create_default_context() logger = logging.getLogger(__name__) @@ -1118,10 +1127,10 @@ class _BaseObject(object): def __hash__(self): # Convert any ints (or whatever) into strings - values = map(six.text_type, self._get_params().values()) + values = map(str, self._get_params().values()) return hash(self.network) + hash( - six.text_type(type(self)) + str(type(self)) + "".join(list(self._get_params().keys()) + list(values)).lower() ) @@ -1649,7 +1658,7 @@ class Artist(_BaseObject, _Taggable): return "pylast.Artist({}, {})".format(repr(self.get_name()), repr(self.network)) def __unicode__(self): - return six.text_type(self.get_name()) + return str(self.get_name()) @_string_output def __str__(self): @@ -2690,22 +2699,18 @@ def md5(text): def _unicode(text): - if isinstance(text, six.binary_type): - return six.text_type(text, "utf-8") - elif isinstance(text, six.text_type): + if isinstance(text, bytes): + return str(text, "utf-8") + elif isinstance(text, str): return text else: - return six.text_type(text) + return str(text) def _string(string): - """For Python2 routines that can only process str type.""" if isinstance(string, str): return string - casted = six.text_type(string) - if sys.version_info.major == 2: - casted = casted.encode("utf-8") - return casted + return str(string) def cleanup_nodes(doc): @@ -2864,9 +2869,9 @@ def _unescape_htmlentity(string): # string = _unicode(string) - mapping = htmlentitydefs.name2codepoint + mapping = html.entities.name2codepoint for key in mapping: - string = string.replace("&%s;" % key, unichr(mapping[key])) + string = string.replace("&%s;" % key, chr(mapping[key])) return string diff --git a/pylast/version.py b/pylast/version.py index ddb9d9b..88717cc 100644 --- a/pylast/version.py +++ b/pylast/version.py @@ -1,2 +1,2 @@ # Master version for pylast -__version__ = "2.5.0.dev0" +__version__ = "3.0.0.dev0" diff --git a/setup.py b/setup.py index 4cb8aa8..78832c1 100755 --- a/setup.py +++ b/setup.py @@ -1,21 +1,50 @@ #!/usr/bin/env python -from setuptools import find_packages, setup +from __future__ import print_function +import sys -with open("README.md") as f: - long_description = f.read() +from setuptools import find_packages, setup version_dict = {} with open("pylast/version.py") as f: exec(f.read(), version_dict) version = version_dict["__version__"] + +if sys.version_info < (3, 4): + error = """pylast 3.0 and above are no longer compatible with Python 2. + +This is pylast {} and you are using Python {}. +Make sure you have pip >= 9.0 and setuptools >= 24.2 and retry: + + $ pip install --upgrade pip setuptools + +Other choices: + +- Upgrade to Python 3. + +- Install an older version of pylast: + +$ pip install 'pylast<3.0' + +For more information: + +https://github.com/pylast/pylast/issues/265 +""".format( + version, ".".join([str(v) for v in sys.version_info[:3]]) + ) + print(error, file=sys.stderr) + sys.exit(1) + +with open("README.md") as f: + long_description = f.read() + + setup( name="pylast", long_description=long_description, long_description_content_type="text/markdown", version=version, author="Amr Hassan and Contributors", - install_requires=["six"], tests_require=[ "coverage", "flaky", @@ -34,17 +63,16 @@ setup( "Topic :: Internet", "Topic :: Multimedia :: Sound/Audio", "Topic :: Software Development :: Libraries :: Python Modules", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ], - python_requires=">=2.7.10, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", + python_requires=">=3.4", keywords=["Last.fm", "music", "scrobble", "scrobbling"], packages=find_packages(exclude=("tests*",)), license="Apache2", diff --git a/tests/test_user.py b/tests/test_user.py index 835d131..1e7c76d 100755 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -67,7 +67,7 @@ class TestPyLastUser(TestPyLastWithLastFm): else: # Old way # Just check date because of timezones - self.assertIn(u"2002-11-20 ", registered) + self.assertIn("2002-11-20 ", registered) def test_get_user_unixtime_registration(self): # Arrange diff --git a/tests/unicode_test.py b/tests/unicode_test.py index 5aab7c1..062f37f 100644 --- a/tests/unicode_test.py +++ b/tests/unicode_test.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import mock import pytest -import six import pylast @@ -13,9 +12,9 @@ def mock_network(): @pytest.mark.parametrize( "artist", [ - u"\xe9lafdasfdsafdsa", - u"ééééééé", - pylast.Artist(u"B\xe9l", mock_network()), + "\xe9lafdasfdsafdsa", + "ééééééé", + pylast.Artist("B\xe9l", mock_network()), "fdasfdsafsaf not unicode", ], ) @@ -24,7 +23,7 @@ def test_get_cache_key(artist): request._get_cache_key() -@pytest.mark.parametrize("obj", [pylast.Artist(u"B\xe9l", mock_network())]) +@pytest.mark.parametrize("obj", [pylast.Artist("B\xe9l", mock_network())]) def test_cast_and_hash(obj): - assert type(six.text_type(obj)) is six.text_type + assert type(str(obj)) is str assert isinstance(hash(obj), int) diff --git a/tox.ini b/tox.ini index 22cc282..fe07234 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27, py37, py36, py35, py34, pypy, pypy3, py38dev +envlist = py37, py36, py35, py34, pypy3, py38dev recreate = False [testenv] @@ -25,21 +25,7 @@ commands = {posargs} deps = flake8 pep8-naming -commands = - flake8 . - -[testenv:py2lint] -deps = - {[testenv:lint]deps} - clonedigger -commands = - {[testenv:lint]commands} - ./clonedigger.sh - -[testenv:py3lint] -deps = - {[testenv:lint]deps} black commands = - {[testenv:lint]commands} + flake8 . black --check --diff .