Drop support for legacy Python 2
This commit is contained in:
parent
21ccdeb9fb
commit
d1726830c3
|
@ -15,12 +15,8 @@ env:
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- python: 2.7
|
|
||||||
env: TOXENV=py2lint
|
|
||||||
- python: 2.7
|
|
||||||
env: TOXENV=py27
|
|
||||||
- python: 3.6
|
- python: 3.6
|
||||||
env: TOXENV=py3lint
|
env: TOXENV=lint
|
||||||
- python: 3.7
|
- python: 3.7
|
||||||
env: TOXENV=py37
|
env: TOXENV=py37
|
||||||
dist: xenial
|
dist: xenial
|
||||||
|
@ -33,14 +29,11 @@ matrix:
|
||||||
env: TOXENV=py34
|
env: TOXENV=py34
|
||||||
- python: pypy3
|
- python: pypy3
|
||||||
env: TOXENV=pypy3
|
env: TOXENV=pypy3
|
||||||
- python: pypy
|
|
||||||
env: TOXENV=pypy
|
|
||||||
- python: 3.6-dev
|
- python: 3.6-dev
|
||||||
env: TOXENV=py36dev
|
env: TOXENV=py36dev
|
||||||
- python: 3.7-dev
|
- python: 3.7-dev
|
||||||
env: TOXENV=py37dev
|
env: TOXENV=py37dev
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- env: TOXENV=pypy
|
|
||||||
- env: TOXENV=pypy3
|
- env: TOXENV=pypy3
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Added
|
### Added
|
||||||
- This changelog file ([#273])
|
- This changelog file ([#273])
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
* Support for Python 2.7 ([#265])
|
||||||
|
|
||||||
## [2.4.0] - 2018-08-08
|
## [2.4.0] - 2018-08-08
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
12
README.md
12
README.md
|
@ -29,12 +29,12 @@ Or from requirements.txt:
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
|
|
||||||
* pylast >= 3.0.0 will likely only support Python 3.4+ ([#265](https://github.com/pylast/pylast/issues/265))
|
* pylast 3.0.0+ supports 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.2.0 - 2.4.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 2.0.0 - 2.1.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.7.0 - 1.9.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 1.0.0 - 1.6.0 supports Python 2.7, 3.3, 3.4.
|
||||||
* pyLast >= 0.5 < 1.0.0 supports Python 2, 3.
|
* pyLast 0.5 supports Python 2, 3.
|
||||||
* pyLast < 0.5 supports Python 2.
|
* pyLast < 0.5 supports Python 2.
|
||||||
|
|
||||||
Features
|
Features
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
clonedigger pylast
|
|
||||||
grep -E "Clones detected|lines are duplicates" output.html
|
|
||||||
exit 0
|
|
|
@ -25,13 +25,13 @@ import collections
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
import shelve
|
import shelve
|
||||||
import six
|
|
||||||
import ssl
|
import ssl
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import warnings
|
|
||||||
import xml.dom
|
import xml.dom
|
||||||
|
import html.entities
|
||||||
|
from http.client import HTTPSConnection
|
||||||
|
|
||||||
from . import version
|
from . import version
|
||||||
|
|
||||||
|
@ -44,24 +44,33 @@ __email__ = "amr.hassan@gmail.com"
|
||||||
__version__ = version.__version__
|
__version__ = version.__version__
|
||||||
|
|
||||||
if sys.version_info < (3,):
|
if sys.version_info < (3,):
|
||||||
warnings.warn(
|
raise ImportError(
|
||||||
"You are using pylast with Python 2. "
|
"""pylast 3.0 and above are no longer compatible with Python 2.
|
||||||
"Pylast will soon be Python 3 only. "
|
|
||||||
"More info: https://github.com/pylast/pylast/issues/265",
|
This is pylast {} and you are using Python {}.
|
||||||
UserWarning,
|
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:
|
else:
|
||||||
import html.entities as htmlentitydefs
|
# Keep importable on Python 2 for a while to show ImportError
|
||||||
from http.client import HTTPSConnection
|
|
||||||
from urllib.parse import quote_plus as url_quote_plus
|
from urllib.parse import quote_plus as url_quote_plus
|
||||||
|
|
||||||
unichr = chr
|
|
||||||
|
|
||||||
|
|
||||||
STATUS_INVALID_SERVICE = 2
|
STATUS_INVALID_SERVICE = 2
|
||||||
STATUS_INVALID_METHOD = 3
|
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 in seconds from section 4.4 of https://www.last.fm/api/tos
|
||||||
DELAY_TIME = 0.2
|
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()
|
SSL_CONTEXT = ssl.create_default_context()
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -1118,10 +1127,10 @@ class _BaseObject(object):
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
# Convert any ints (or whatever) into strings
|
# 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(
|
return hash(self.network) + hash(
|
||||||
six.text_type(type(self))
|
str(type(self))
|
||||||
+ "".join(list(self._get_params().keys()) + list(values)).lower()
|
+ "".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))
|
return "pylast.Artist({}, {})".format(repr(self.get_name()), repr(self.network))
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return six.text_type(self.get_name())
|
return str(self.get_name())
|
||||||
|
|
||||||
@_string_output
|
@_string_output
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -2690,22 +2699,18 @@ def md5(text):
|
||||||
|
|
||||||
|
|
||||||
def _unicode(text):
|
def _unicode(text):
|
||||||
if isinstance(text, six.binary_type):
|
if isinstance(text, bytes):
|
||||||
return six.text_type(text, "utf-8")
|
return str(text, "utf-8")
|
||||||
elif isinstance(text, six.text_type):
|
elif isinstance(text, str):
|
||||||
return text
|
return text
|
||||||
else:
|
else:
|
||||||
return six.text_type(text)
|
return str(text)
|
||||||
|
|
||||||
|
|
||||||
def _string(string):
|
def _string(string):
|
||||||
"""For Python2 routines that can only process str type."""
|
|
||||||
if isinstance(string, str):
|
if isinstance(string, str):
|
||||||
return string
|
return string
|
||||||
casted = six.text_type(string)
|
return str(string)
|
||||||
if sys.version_info.major == 2:
|
|
||||||
casted = casted.encode("utf-8")
|
|
||||||
return casted
|
|
||||||
|
|
||||||
|
|
||||||
def cleanup_nodes(doc):
|
def cleanup_nodes(doc):
|
||||||
|
@ -2864,9 +2869,9 @@ def _unescape_htmlentity(string):
|
||||||
|
|
||||||
# string = _unicode(string)
|
# string = _unicode(string)
|
||||||
|
|
||||||
mapping = htmlentitydefs.name2codepoint
|
mapping = html.entities.name2codepoint
|
||||||
for key in mapping:
|
for key in mapping:
|
||||||
string = string.replace("&%s;" % key, unichr(mapping[key]))
|
string = string.replace("&%s;" % key, chr(mapping[key]))
|
||||||
|
|
||||||
return string
|
return string
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
# Master version for pylast
|
# Master version for pylast
|
||||||
__version__ = "2.5.0.dev0"
|
__version__ = "3.0.0.dev0"
|
||||||
|
|
42
setup.py
42
setup.py
|
@ -1,21 +1,50 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from setuptools import find_packages, setup
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
|
||||||
with open("README.md") as f:
|
from setuptools import find_packages, setup
|
||||||
long_description = f.read()
|
|
||||||
|
|
||||||
version_dict = {}
|
version_dict = {}
|
||||||
with open("pylast/version.py") as f:
|
with open("pylast/version.py") as f:
|
||||||
exec(f.read(), version_dict)
|
exec(f.read(), version_dict)
|
||||||
version = version_dict["__version__"]
|
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(
|
setup(
|
||||||
name="pylast",
|
name="pylast",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
version=version,
|
version=version,
|
||||||
author="Amr Hassan <amr.hassan@gmail.com> and Contributors",
|
author="Amr Hassan <amr.hassan@gmail.com> and Contributors",
|
||||||
install_requires=["six"],
|
|
||||||
tests_require=[
|
tests_require=[
|
||||||
"coverage",
|
"coverage",
|
||||||
"flaky",
|
"flaky",
|
||||||
|
@ -34,17 +63,16 @@ setup(
|
||||||
"Topic :: Internet",
|
"Topic :: Internet",
|
||||||
"Topic :: Multimedia :: Sound/Audio",
|
"Topic :: Multimedia :: Sound/Audio",
|
||||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||||
"Programming Language :: Python :: 2",
|
|
||||||
"Programming Language :: Python :: 2.7",
|
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.4",
|
"Programming Language :: Python :: 3.4",
|
||||||
"Programming Language :: Python :: 3.5",
|
"Programming Language :: Python :: 3.5",
|
||||||
"Programming Language :: Python :: 3.6",
|
"Programming Language :: Python :: 3.6",
|
||||||
"Programming Language :: Python :: 3.7",
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
"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"],
|
keywords=["Last.fm", "music", "scrobble", "scrobbling"],
|
||||||
packages=find_packages(exclude=("tests*",)),
|
packages=find_packages(exclude=("tests*",)),
|
||||||
license="Apache2",
|
license="Apache2",
|
||||||
|
|
|
@ -67,7 +67,7 @@ class TestPyLastUser(TestPyLastWithLastFm):
|
||||||
else:
|
else:
|
||||||
# Old way
|
# Old way
|
||||||
# Just check date because of timezones
|
# 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):
|
def test_get_user_unixtime_registration(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import mock
|
import mock
|
||||||
import pytest
|
import pytest
|
||||||
import six
|
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
|
@ -13,9 +12,9 @@ def mock_network():
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"artist",
|
"artist",
|
||||||
[
|
[
|
||||||
u"\xe9lafdasfdsafdsa",
|
"\xe9lafdasfdsafdsa",
|
||||||
u"ééééééé",
|
"ééééééé",
|
||||||
pylast.Artist(u"B\xe9l", mock_network()),
|
pylast.Artist("B\xe9l", mock_network()),
|
||||||
"fdasfdsafsaf not unicode",
|
"fdasfdsafsaf not unicode",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -24,7 +23,7 @@ def test_get_cache_key(artist):
|
||||||
request._get_cache_key()
|
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):
|
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)
|
assert isinstance(hash(obj), int)
|
||||||
|
|
18
tox.ini
18
tox.ini
|
@ -1,5 +1,5 @@
|
||||||
[tox]
|
[tox]
|
||||||
envlist = py27, py37, py36, py35, py34, pypy, pypy3, py36dev, py37dev
|
envlist = py37, py36, py35, py34, pypy3, py36dev, py37dev
|
||||||
recreate = False
|
recreate = False
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
|
@ -25,21 +25,7 @@ commands = {posargs}
|
||||||
deps =
|
deps =
|
||||||
flake8
|
flake8
|
||||||
pep8-naming
|
pep8-naming
|
||||||
commands =
|
|
||||||
flake8 .
|
|
||||||
|
|
||||||
[testenv:py2lint]
|
|
||||||
deps =
|
|
||||||
{[testenv:lint]deps}
|
|
||||||
clonedigger
|
|
||||||
commands =
|
|
||||||
{[testenv:lint]commands}
|
|
||||||
./clonedigger.sh
|
|
||||||
|
|
||||||
[testenv:py3lint]
|
|
||||||
deps =
|
|
||||||
{[testenv:lint]deps}
|
|
||||||
black
|
black
|
||||||
commands =
|
commands =
|
||||||
{[testenv:lint]commands}
|
flake8 .
|
||||||
black --check --diff .
|
black --check --diff .
|
||||||
|
|
Loading…
Reference in a new issue