mirror of https://github.com/streamlink/streamlink
setup: drop iso-639/iso3166, default to pycountry
- drop iso-639 and iso3166 dependencies in favor of pycountry - remove the `STREAMLINK_USE_PYCOUNTRY` env var switch from setup.py - move dependencies list from setup.py to setup.cfg - update utils.l10n and its tests - update Windows installer config - update docs
This commit is contained in:
parent
9d371d9f3d
commit
aabd6af718
|
@ -284,10 +284,9 @@ Name Notes
|
|||
|
||||
**Automatically installed by the setup script**
|
||||
--------------------------------------------------------------------------------
|
||||
`iso-639`_ Used for localization settings, provides language information
|
||||
`iso3166`_ Used for localization settings, provides country information
|
||||
`isodate`_ Used for parsing ISO8601 strings
|
||||
`lxml`_ Used for processing HTML and XML data
|
||||
`pycountry`_ Used for localization settings, provides country and language data
|
||||
`pycryptodome`_ Used for decrypting encrypted streams
|
||||
`PySocks`_ Used for SOCKS Proxies
|
||||
`requests`_ Used for making any kind of HTTP/HTTPS request
|
||||
|
@ -301,20 +300,9 @@ Name Notes
|
|||
- HLS streams optionally need to get remuxed depending on the stream selection.
|
||||
==================================== ===========================================
|
||||
|
||||
Alternative dependencies
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
With this environment variable it is possible to use `pycountry`_ instead of `iso-639`_ and `iso3166`_.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ export STREAMLINK_USE_PYCOUNTRY="true"
|
||||
|
||||
.. _Python: https://www.python.org/
|
||||
.. _python-setuptools: https://setuptools.pypa.io/en/latest/
|
||||
|
||||
.. _iso-639: https://pypi.org/project/iso-639/
|
||||
.. _iso3166: https://pypi.org/project/iso3166/
|
||||
.. _isodate: https://pypi.org/project/isodate/
|
||||
.. _lxml: https://lxml.de/
|
||||
.. _pycountry: https://pypi.org/project/pycountry/
|
||||
|
|
|
@ -6,7 +6,6 @@ set -ex
|
|||
|
||||
python -m pip install --disable-pip-version-check --upgrade pip setuptools
|
||||
python -m pip install --upgrade -r dev-requirements.txt
|
||||
python -m pip install pycountry
|
||||
# https://github.com/streamlink/streamlink/issues/4021
|
||||
python -m pip install brotli
|
||||
python -m pip install -e .
|
||||
|
|
|
@ -89,11 +89,10 @@ format=bundled
|
|||
|
||||
[Include]
|
||||
packages=pkg_resources
|
||||
iso639
|
||||
pycountry
|
||||
pypi_wheels=certifi==2021.5.30
|
||||
charset-normalizer==2.0.4
|
||||
idna==3.2
|
||||
iso3166==1.0.1
|
||||
isodate==0.6.0
|
||||
lxml==4.6.4
|
||||
pycryptodome==3.10.1
|
||||
|
|
|
@ -38,6 +38,14 @@ python_requires = >=3.6, <4
|
|||
package_dir =
|
||||
=src
|
||||
packages = find:
|
||||
install_requires =
|
||||
isodate
|
||||
lxml >=4.6.4,<5.0
|
||||
pycountry
|
||||
pycryptodome >=3.4.3,<4
|
||||
PySocks !=1.5.7,>=1.5.6
|
||||
requests >=2.26.0,<3.0
|
||||
websocket-client >=1.2.1,<2.0
|
||||
|
||||
[options.packages.find]
|
||||
where = src
|
||||
|
|
20
setup.py
20
setup.py
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
from os import environ, path
|
||||
from os import path
|
||||
from sys import argv, exit, version_info
|
||||
from textwrap import dedent
|
||||
|
||||
|
@ -38,23 +38,6 @@ if "test" in argv:
|
|||
"""))
|
||||
|
||||
|
||||
deps = [
|
||||
"isodate",
|
||||
"lxml>=4.6.4,<5.0",
|
||||
"pycryptodome>=3.4.3,<4",
|
||||
"PySocks!=1.5.7,>=1.5.6",
|
||||
"requests>=2.26.0,<3.0",
|
||||
"websocket-client>=1.2.1,<2.0",
|
||||
]
|
||||
|
||||
# for localization
|
||||
if environ.get("STREAMLINK_USE_PYCOUNTRY"):
|
||||
deps.append("pycountry")
|
||||
else:
|
||||
deps.append("iso-639")
|
||||
deps.append("iso3166")
|
||||
|
||||
|
||||
def is_wheel_for_windows():
|
||||
if "bdist_wheel" in argv:
|
||||
names = ["win32", "win-amd64", "cygwin"]
|
||||
|
@ -96,7 +79,6 @@ data_files = [
|
|||
setup(
|
||||
version=versioneer.get_version(),
|
||||
cmdclass=versioneer.get_cmdclass(),
|
||||
install_requires=deps,
|
||||
entry_points=entry_points,
|
||||
data_files=data_files,
|
||||
)
|
||||
|
|
|
@ -1,20 +1,11 @@
|
|||
import locale
|
||||
import logging
|
||||
|
||||
|
||||
try:
|
||||
from iso639 import languages
|
||||
from iso3166 import countries
|
||||
|
||||
PYCOUNTRY = False
|
||||
except ImportError: # pragma: no cover
|
||||
from pycountry import languages, countries
|
||||
|
||||
PYCOUNTRY = True
|
||||
from pycountry import countries, languages
|
||||
|
||||
DEFAULT_LANGUAGE = "en"
|
||||
DEFAULT_COUNTRY = "US"
|
||||
DEFAULT_LANGUAGE_CODE = "{0}_{1}".format(DEFAULT_LANGUAGE, DEFAULT_COUNTRY)
|
||||
DEFAULT_LANGUAGE_CODE = f"{DEFAULT_LANGUAGE}_{DEFAULT_COUNTRY}"
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -30,14 +21,16 @@ class Country:
|
|||
@classmethod
|
||||
def get(cls, country):
|
||||
try:
|
||||
if PYCOUNTRY:
|
||||
c = countries.lookup(country)
|
||||
return Country(c.alpha_2, c.alpha_3, c.numeric, c.name, getattr(c, "official_name", c.name))
|
||||
else:
|
||||
c = countries.get(country)
|
||||
return Country(c.alpha2, c.alpha3, c.numeric, c.name, c.apolitical_name)
|
||||
c = countries.lookup(country)
|
||||
return Country(
|
||||
c.alpha_2,
|
||||
c.alpha_3,
|
||||
c.numeric,
|
||||
c.name,
|
||||
getattr(c, "official_name", c.name)
|
||||
)
|
||||
except (LookupError, KeyError):
|
||||
raise LookupError("Invalid country code: {0}".format(country))
|
||||
raise LookupError(f"Invalid country code: {country}")
|
||||
|
||||
def __eq__(self, other):
|
||||
return (
|
||||
|
@ -66,38 +59,23 @@ class Language:
|
|||
@classmethod
|
||||
def get(cls, language):
|
||||
try:
|
||||
if PYCOUNTRY:
|
||||
lang = (languages.get(alpha_2=language)
|
||||
or languages.get(alpha_3=language)
|
||||
or languages.get(bibliographic=language)
|
||||
or languages.get(name=language))
|
||||
if not lang:
|
||||
raise KeyError(language)
|
||||
return Language(
|
||||
# some languages don't have an alpha_2 code
|
||||
getattr(lang, "alpha_2", ""),
|
||||
lang.alpha_3,
|
||||
lang.name,
|
||||
getattr(lang, "bibliographic", "")
|
||||
)
|
||||
else:
|
||||
lang = None
|
||||
if len(language) == 2:
|
||||
lang = languages.get(alpha2=language)
|
||||
elif len(language) == 3:
|
||||
for code_type in ['part2b', 'part2t', 'part3']:
|
||||
try:
|
||||
lang = languages.get(**{code_type: language})
|
||||
break
|
||||
except KeyError:
|
||||
pass
|
||||
if not lang:
|
||||
raise KeyError(language)
|
||||
else:
|
||||
raise KeyError(language)
|
||||
return Language(lang.alpha2, lang.part3, lang.name, lang.part2b or lang.part2t)
|
||||
lang = (
|
||||
languages.get(alpha_2=language)
|
||||
or languages.get(alpha_3=language)
|
||||
or languages.get(bibliographic=language)
|
||||
or languages.get(name=language)
|
||||
)
|
||||
if not lang:
|
||||
raise KeyError(language)
|
||||
return Language(
|
||||
# some languages don't have an alpha_2 code
|
||||
getattr(lang, "alpha_2", ""),
|
||||
lang.alpha_3,
|
||||
lang.name,
|
||||
getattr(lang, "bibliographic", "")
|
||||
)
|
||||
except (LookupError, KeyError):
|
||||
raise LookupError("Invalid language code: {0}".format(language))
|
||||
raise LookupError(f"Invalid language code: {language}")
|
||||
|
||||
def __eq__(self, other):
|
||||
return (
|
||||
|
@ -130,7 +108,7 @@ class Localization:
|
|||
def _parse_locale_code(self, language_code):
|
||||
parts = language_code.split("_", 1)
|
||||
if len(parts) != 2 or len(parts[0]) != 2 or len(parts[1]) != 2:
|
||||
raise LookupError("Invalid language code: {0}".format(language_code))
|
||||
raise LookupError(f"Invalid language code: {language_code}")
|
||||
return self.get_language(parts[0]), self.get_country(parts[1])
|
||||
|
||||
@language_code.setter
|
||||
|
@ -156,7 +134,7 @@ class Localization:
|
|||
self._language_code = DEFAULT_LANGUAGE_CODE
|
||||
else:
|
||||
raise
|
||||
log.debug("Language code: {0}".format(self._language_code))
|
||||
log.debug(f"Language code: {self._language_code}")
|
||||
|
||||
def equivalent(self, language=None, country=None):
|
||||
equivalent = True
|
||||
|
|
|
@ -3,23 +3,8 @@ from unittest.mock import patch
|
|||
|
||||
import streamlink.utils.l10n as l10n
|
||||
|
||||
try:
|
||||
import iso639 # noqa: F401
|
||||
import iso3166 # noqa: F401
|
||||
|
||||
ISO639 = True
|
||||
except ImportError: # pragma: no cover
|
||||
ISO639 = False
|
||||
|
||||
try:
|
||||
import pycountry # noqa: F401
|
||||
|
||||
PYCOUNTRY = True
|
||||
except ImportError: # pragma: no cover
|
||||
PYCOUNTRY = False
|
||||
|
||||
|
||||
class LocalizationTestsMixin:
|
||||
class TestLocalization(unittest.TestCase):
|
||||
def test_language_code_us(self):
|
||||
locale = l10n.Localization("en_US")
|
||||
self.assertEqual("en_US", locale.language_code)
|
||||
|
@ -117,29 +102,6 @@ class LocalizationTestsMixin:
|
|||
self.assertEqual(a.name, "Desano")
|
||||
self.assertEqual(a.bibliographic, "")
|
||||
|
||||
|
||||
@unittest.skipIf(not ISO639, "iso639+iso3166 modules are required to test iso639+iso3166 Localization")
|
||||
class TestLocalization(LocalizationTestsMixin, unittest.TestCase):
|
||||
def setUp(self):
|
||||
l10n.PYCOUNTRY = False
|
||||
|
||||
def test_pycountry(self):
|
||||
self.assertEqual(False, l10n.PYCOUNTRY)
|
||||
|
||||
|
||||
@unittest.skipIf(not PYCOUNTRY, "pycountry module required to test pycountry Localization")
|
||||
class TestLocalizationPyCountry(LocalizationTestsMixin, unittest.TestCase):
|
||||
"""Duplicate of all the Localization tests but using PyCountry instead of the iso* modules"""
|
||||
|
||||
def setUp(self):
|
||||
from pycountry import languages, countries
|
||||
l10n.countries = countries
|
||||
l10n.languages = languages
|
||||
l10n.PYCOUNTRY = True
|
||||
|
||||
def test_pycountry(self):
|
||||
self.assertEqual(True, l10n.PYCOUNTRY)
|
||||
|
||||
# issue #3057: generic "en" lookups via pycountry yield the "En" language, but not "English"
|
||||
def test_language_en(self):
|
||||
english_a = l10n.Localization.get_language("en")
|
||||
|
|
Loading…
Reference in New Issue