File pandas-datareader-pr978-setup.patch of Package python-pandas-datareader
From 4d697317e637b3345ca753d990eb81f7676efcda Mon Sep 17 00:00:00 2001
From: Kevin Sheppard <kevin.k.sheppard@gmail.com>
Date: Tue, 24 Oct 2023 08:51:10 +0100
Subject: [PATCH 1/8] MAINT: Modernize setup
Move away from setup.py
Bump requirements
Update CI
Rerun black, isort, flake8
---
MANIFEST.in | 2 -
azure-pipelines.yml | 2 -
ci/azure/azure_template_posix.yml | 25 +-
ci/azure/azure_template_windows.yml | 20 +-
ci/pypi-install.sh | 17 -
pandas_datareader/__init__.py | 5 +-
pandas_datareader/_utils.py | 4 +-
pandas_datareader/_version.py | 556 -----
pandas_datareader/av/forex.py | 1 -
pandas_datareader/base.py | 1 -
pandas_datareader/compat/__init__.py | 3 +-
pandas_datareader/famafrench.py | 2 -
pandas_datareader/fred.py | 4 +-
pandas_datareader/io/sdmx.py | 3 -
.../tests/av/test_av_time_series.py | 1 -
.../tests/io/data/jsdmx/__init__.py | 0
.../tests/io/data/sdmx/__init__.py | 0
pandas_datareader/tests/io/test_jsdmx.py | 2 +-
pandas_datareader/tests/test_fred.py | 1 -
pandas_datareader/tests/test_wb.py | 5 -
.../tests/yahoo/data/__init__.py | 0
pandas_datareader/tests/yahoo/test_options.py | 4 +-
pandas_datareader/wb.py | 5 +-
pandas_datareader/yahoo/daily.py | 1 -
pandas_datareader/yahoo/options.py | 2 -
pyproject.toml | 88 +
requirements-dev.txt | 6 +-
requirements.txt | 2 +-
setup.cfg | 74 -
setup.py | 18 -
tox.ini | 10 -
versioneer.py | 1886 -----------------
32 files changed, 126 insertions(+), 2624 deletions(-)
delete mode 100644 ci/pypi-install.sh
delete mode 100644 pandas_datareader/_version.py
create mode 100644 pandas_datareader/tests/io/data/jsdmx/__init__.py
create mode 100644 pandas_datareader/tests/io/data/sdmx/__init__.py
create mode 100644 pandas_datareader/tests/yahoo/data/__init__.py
create mode 100644 pyproject.toml
delete mode 100644 setup.cfg
delete mode 100644 setup.py
delete mode 100644 tox.ini
delete mode 100644 versioneer.py
Index: pandas-datareader-0.10.0/MANIFEST.in
===================================================================
--- pandas-datareader-0.10.0.orig/MANIFEST.in
+++ pandas-datareader-0.10.0/MANIFEST.in
@@ -3,8 +3,6 @@ include LICENSE.md
include requirements.txt
include requirements-dev.txt
include pandas_datareader/*.py
-
include pandas_datareader/tests/*.py
include pandas_datareader/tests/data/*
-include versioneer.py
include pandas_datareader/_version.py
Index: pandas-datareader-0.10.0/pandas_datareader/__init__.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/__init__.py
+++ pandas-datareader-0.10.0/pandas_datareader/__init__.py
@@ -1,7 +1,7 @@
import os
import sys
-from ._version import get_versions
+from ._version import __version__
from .data import (
DataReader,
Options,
@@ -32,9 +32,6 @@ from .data import (
PKG = os.path.dirname(__file__)
-__version__ = get_versions()["version"]
-del get_versions
-
__all__ = [
"__version__",
"get_components_yahoo",
Index: pandas-datareader-0.10.0/pandas_datareader/_utils.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/_utils.py
+++ pandas-datareader-0.10.0/pandas_datareader/_utils.py
@@ -46,8 +46,8 @@ def _sanitize_dates(start, end):
try:
start = to_datetime(start)
end = to_datetime(end)
- except (TypeError, ValueError):
- raise ValueError("Invalid date format.")
+ except (TypeError, ValueError) as exc:
+ raise ValueError("Invalid date format.") from exc
if start > end:
raise ValueError("start must be an earlier date than end")
return start, end
Index: pandas-datareader-0.10.0/pandas_datareader/av/forex.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/av/forex.py
+++ pandas-datareader-0.10.0/pandas_datareader/av/forex.py
@@ -30,7 +30,6 @@ class AVForexReader(AlphaVantage):
def __init__(
self, symbols=None, retry_count=3, pause=0.1, session=None, api_key=None
):
-
super(AVForexReader, self).__init__(
symbols=symbols,
start=None,
@@ -57,7 +56,7 @@ class AVForexReader(AlphaVantage):
"Please input a currency pair "
"formatted 'FROM/TO' or a list of "
"currency symbols"
- )
+ ) from e
@property
def function(self):
@@ -89,8 +88,8 @@ class AVForexReader(AlphaVantage):
def _read_lines(self, out):
try:
df = pd.DataFrame.from_dict(out[self.data_key], orient="index")
- except KeyError:
- raise RemoteDataError()
+ except KeyError as exc:
+ raise RemoteDataError() from exc
df.sort_index(ascending=True, inplace=True)
df.index = [id[3:] for id in df.index]
return df
Index: pandas-datareader-0.10.0/pandas_datareader/base.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/base.py
+++ pandas-datareader-0.10.0/pandas_datareader/base.py
@@ -1,4 +1,5 @@
import datetime
+from io import StringIO
import time
from urllib.parse import urlencode
import warnings
@@ -13,13 +14,6 @@ from pandas_datareader._utils import (
_init_session,
_sanitize_dates,
)
-from pandas_datareader.compat import (
- PANDAS_0230,
- StringIO,
- binary_type,
- bytes_to_str,
- string_types,
-)
class _BaseReader(object):
@@ -57,7 +51,6 @@ class _BaseReader(object):
session=None,
freq=None,
):
-
self.symbols = symbols
start, end = _sanitize_dates(start or self.default_start_date, end)
@@ -125,8 +118,8 @@ class _BaseReader(object):
"{} request returned no data; check URL for invalid "
"inputs: {}".format(service, self.url)
)
- if isinstance(text, binary_type):
- out.write(bytes_to_str(text))
+ if isinstance(text, bytes):
+ out.write(text.decode("utf-8"))
else:
out.write(text)
out.seek(0)
@@ -249,7 +242,7 @@ class _DailyBaseReader(_BaseReader):
def read(self):
"""Read data"""
# If a single symbol, (e.g., 'GOOG')
- if isinstance(self.symbols, (string_types, int)):
+ if isinstance(self.symbols, (str, int)):
df = self._read_one_data(self.url, params=self._get_params(self.symbols))
# Or multiple symbols, (e.g., ['GOOG', 'AAPL', 'MSFT'])
elif isinstance(self.symbols, DataFrame):
@@ -269,7 +262,7 @@ class _DailyBaseReader(_BaseReader):
passed.append(sym)
except (IOError, KeyError):
msg = "Failed to read symbol: {0!r}, replacing with NaN."
- warnings.warn(msg.format(sym), SymbolWarning)
+ warnings.warn(msg.format(sym), SymbolWarning, stacklevel=2)
failed.append(sym)
if len(passed) == 0:
@@ -281,16 +274,13 @@ class _DailyBaseReader(_BaseReader):
df_na[:] = np.nan
for sym in failed:
stocks[sym] = df_na
- if PANDAS_0230:
result = concat(stocks, sort=True).unstack(level=0)
- else:
- result = concat(stocks).unstack(level=0)
- result.columns.names = ["Attributes", "Symbols"]
+ result.columns.names = ["Attributes", "Symbols"]
return result
- except AttributeError:
+ except AttributeError as exc:
# cannot construct a panel with just 1D nans indicating no data
msg = "No data fetched using {0!r}"
- raise RemoteDataError(msg.format(self.__class__.__name__))
+ raise RemoteDataError(msg.format(self.__class__.__name__)) from exc
def _in_chunks(seq, size):
Index: pandas-datareader-0.10.0/pandas_datareader/compat/__init__.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/compat/__init__.py
+++ pandas-datareader-0.10.0/pandas_datareader/compat/__init__.py
@@ -1,4 +1,3 @@
-from distutils.version import LooseVersion
from functools import reduce
from io import StringIO
from urllib.error import HTTPError
@@ -8,33 +7,19 @@ from pandas.api.types import is_list_lik
from pandas.io import common as com
from pandas.testing import assert_frame_equal
-PANDAS_VERSION = LooseVersion(pd.__version__)
-
-PANDAS_0210 = PANDAS_VERSION >= LooseVersion("0.21.0")
-PANDAS_0220 = PANDAS_VERSION >= LooseVersion("0.22.0")
-PANDAS_0230 = PANDAS_VERSION >= LooseVersion("0.23.0")
__all__ = [
"HTTPError",
"StringIO",
- "PANDAS_0210",
- "PANDAS_0220",
- "PANDAS_0230",
"get_filepath_or_buffer",
- "str_to_bytes",
- "string_types",
"assert_frame_equal",
"is_list_like",
"is_number",
- "lmap",
- "lrange",
- "concat",
"reduce",
]
def get_filepath_or_buffer(filepath_or_buffer, encoding=None, compression=None):
-
# Dictionaries are no longer considered valid inputs
# for "get_filepath_or_buffer" starting in pandas >= 0.20.0
if isinstance(filepath_or_buffer, dict):
@@ -49,34 +34,3 @@ def get_filepath_or_buffer(filepath_or_b
filepath_or_buffer, encoding=encoding, compression=None
)
return tmp
-
-
-string_types = (str,)
-binary_type = bytes
-
-
-def str_to_bytes(s, encoding=None):
- if isinstance(s, bytes):
- return s
- return s.encode(encoding or "ascii")
-
-
-def bytes_to_str(b, encoding=None):
- return b.decode(encoding or "utf-8")
-
-
-def lmap(*args, **kwargs):
- return list(map(*args, **kwargs))
-
-
-def lrange(*args, **kwargs):
- return list(range(*args, **kwargs))
-
-
-def concat(*args, **kwargs):
- """
- Shim to wokr around sort keyword
- """
- if not PANDAS_0230 and "sort" in kwargs:
- del kwargs["sort"]
- return pd.concat(*args, **kwargs)
Index: pandas-datareader-0.10.0/pandas_datareader/famafrench.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/famafrench.py
+++ pandas-datareader-0.10.0/pandas_datareader/famafrench.py
@@ -6,7 +6,7 @@ from zipfile import ZipFile
from pandas import read_csv, to_datetime
from pandas_datareader.base import _BaseReader
-from pandas_datareader.compat import StringIO, lmap
+from pandas_datareader.compat import StringIO
_URL = "http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/"
_URL_PREFIX = "ftp/"
@@ -75,7 +75,6 @@ class FamaFrenchReader(_BaseReader):
return super(FamaFrenchReader, self).read()
def _read_one_data(self, url, params):
-
params = {
"index_col": 0,
"parse_dates": [0],
@@ -84,13 +83,12 @@ class FamaFrenchReader(_BaseReader):
# headers in these files are not valid
if self.symbols.endswith("_Breakpoints"):
-
if self.symbols.find("-") > -1:
c = ["<=0", ">0"]
else:
c = ["Count"]
r = list(range(0, 105, 5))
- params["names"] = ["Date"] + c + list(zip(r, r[1:]))
+ params["names"] = ["Date"] + c + list(zip(r, r[1:], strict=True))
if self.symbols != "Prior_2-12_Breakpoints":
params["skiprows"] = 1
@@ -146,11 +144,11 @@ class FamaFrenchReader(_BaseReader):
"""
try:
from lxml.html import document_fromstring
- except ImportError:
+ except ImportError as exc:
raise ImportError(
"Please install lxml if you want to use the "
"get_datasets_famafrench function"
- )
+ ) from exc
response = self.session.get(_URL + "data_library.html")
root = document_fromstring(response.content)
@@ -164,4 +162,4 @@ class FamaFrenchReader(_BaseReader):
if ds.startswith(_URL_PREFIX) and ds.endswith(_URL_SUFFIX)
]
- return lmap(lambda x: x[len(_URL_PREFIX) : -len(_URL_SUFFIX)], datasets)
+ return list(map(lambda x: x[len(_URL_PREFIX) : -len(_URL_SUFFIX)], datasets))
Index: pandas-datareader-0.10.0/pandas_datareader/fred.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/fred.py
+++ pandas-datareader-0.10.0/pandas_datareader/fred.py
@@ -50,15 +50,17 @@ class FredReader(_BaseReader):
)
try:
return data.truncate(self.start, self.end)
- except KeyError: # pragma: no cover
+ except KeyError as exc: # pragma: no cover
if data.iloc[3].name[7:12] == "Error":
raise IOError(
"Failed to get the data. Check that "
"{0!r} is a valid FRED series.".format(name)
- )
+ ) from exc
raise
df = concat(
- [fetch_data(url, n) for url, n in zip(urls, names)], axis=1, join="outer"
+ [fetch_data(url, n) for url, n in zip(urls, names, strict=True)],
+ axis=1,
+ join="outer",
)
return df
Index: pandas-datareader-0.10.0/pandas_datareader/io/sdmx.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/io/sdmx.py
+++ pandas-datareader-0.10.0/pandas_datareader/io/sdmx.py
@@ -7,7 +7,7 @@ import zipfile
import pandas as pd
-from pandas_datareader.compat import HTTPError, str_to_bytes
+from pandas_datareader.compat import HTTPError
from pandas_datareader.io.util import _read_content
_STRUCTURE = "{http://www.sdmx.org/resources/sdmxml/schemas/v2_1/structure}"
@@ -53,11 +53,11 @@ def read_sdmx(path_or_buf, dtype="float6
try:
structure = _get_child(root, _MESSAGE + "Structure")
- except ValueError:
+ except ValueError as exc:
# get zipped path
result = list(root.iter(_COMMON + "Text"))[1].text
if not result.startswith("http"):
- raise ValueError(result)
+ raise ValueError(result) from exc
for _ in range(60):
# wait zipped data is prepared
@@ -72,7 +72,7 @@ def read_sdmx(path_or_buf, dtype="float6
"Unable to download zipped data within 60 secs, "
"please download it manually from: {0}"
)
- raise ValueError(msg.format(result))
+ raise ValueError(msg.format(result)) from exc
idx_name = structure.get("dimensionAtObservation")
dataset = _get_child(root, _DATASET)
@@ -97,7 +97,6 @@ def read_sdmx(path_or_buf, dtype="float6
def _construct_series(values, name, dsd=None):
-
# ts defines attributes to be handled as times
times = dsd.ts if dsd is not None else []
@@ -105,7 +104,6 @@ def _construct_series(values, name, dsd=
raise ValueError("Data contains no 'Series'")
results = []
for value in values:
-
if name in times:
tvalue = [v[0] for v in value]
try:
@@ -121,7 +119,6 @@ def _construct_series(values, name, dsd=
def _construct_index(keys, dsd=None):
-
# code defines a mapping to key's internal code to its representation
codes = dsd.codes if dsd is not None else {}
@@ -237,8 +234,10 @@ def _read_zipped_sdmx(path_or_buf):
"""Unzipp data contains SDMX-XML"""
data = _read_content(path_or_buf)
+ if not isinstance(data, bytes):
+ data = data.encode("ascii")
zp = BytesIO()
- zp.write(str_to_bytes(data))
+ zp.write(data)
f = zipfile.ZipFile(zp)
files = f.namelist()
assert len(files) == 1
Index: pandas-datareader-0.10.0/pandas_datareader/tests/av/test_av_time_series.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/av/test_av_time_series.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/av/test_av_time_series.py
@@ -114,7 +114,6 @@ class TestAVTimeSeries(object):
@staticmethod
def _helper_df_weekly_monthly(df, adj=False):
-
expected1 = df.loc["2015-02-27"]
assert expected1["close"] == 128.46
assert expected1["high"] == 133.60
Index: pandas-datareader-0.10.0/pandas_datareader/tests/io/test_jsdmx.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/io/test_jsdmx.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/io/test_jsdmx.py
@@ -7,7 +7,6 @@ import pandas as pd
from pandas import testing as tm
import pytest
-from pandas_datareader.compat import PANDAS_0210
from pandas_datareader.io import read_jsdmx
pytestmark = pytest.mark.stable
@@ -18,7 +17,6 @@ def dirpath(datapath):
return datapath("io", "data")
-@pytest.mark.skipif(not PANDAS_0210, reason="Broken on old pandas")
def test_tourism(dirpath):
# OECD -> Industry and Services -> Inbound Tourism
result = read_jsdmx(os.path.join(dirpath, "jsdmx", "tourism.json"))
@@ -74,7 +72,6 @@ def test_tourism(dirpath):
tm.assert_frame_equal(jp[visitors], expected)
-@pytest.mark.skipif(not PANDAS_0210, reason="Broken on old pandas")
def test_land_use(dirpath):
# OECD -> Environment -> Resources Land Use
result = read_jsdmx(os.path.join(dirpath, "jsdmx", "land_use.json"))
@@ -148,7 +145,6 @@ def test_land_use(dirpath):
tm.assert_frame_equal(result[exp_col], expected)
-@pytest.mark.skipif(not PANDAS_0210, reason="Broken on old pandas")
def test_quartervalue(dirpath):
# https://stats.oecd.org/sdmx-json/data/QNA/AUS+AUT+BEL+CAN+CHL.GDP+B1_
# GE.CUR+VOBARSA.Q/all?startTime=2009-Q1&endTime=2011-Q4
@@ -170,7 +166,7 @@ def test_quartervalue(dirpath):
"2011-10-01",
],
dtype="datetime64[ns]",
- name=u"Period",
+ name="Period",
freq=None,
)
tm.assert_index_equal(result.index, expected)
Index: pandas-datareader-0.10.0/pandas_datareader/tests/test_fred.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/test_fred.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/test_fred.py
@@ -13,7 +13,6 @@ pytestmark = pytest.mark.stable
class TestFred(object):
def test_fred(self):
-
# Raises an exception when DataReader can't
# get a 200 response from FRED.
@@ -55,7 +54,7 @@ class TestFred(object):
def test_invalid_series(self):
name = "NOT A REAL SERIES"
- with pytest.raises(Exception):
+ with pytest.raises(Exception): # noqa: B017
web.get_data_fred(name)
def test_fred_multi(self): # pragma: no cover
Index: pandas-datareader-0.10.0/pandas_datareader/tests/test_wb.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/test_wb.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/test_wb.py
@@ -6,8 +6,6 @@ from pandas import testing as tm
import pytest
import requests
-from pandas_datareader._testing import skip_on_exception
-from pandas_datareader._utils import RemoteDataError
from pandas_datareader.wb import (
WorldBankReader,
download,
@@ -21,7 +19,6 @@ pytestmark = pytest.mark.stable
class TestWB(object):
def test_wdi_search(self):
-
# Test that a name column exists, and that some results were returned
# ...without being too strict about what the actual contents of the
# results actually are. The fact that there are some, is good enough.
@@ -45,7 +42,6 @@ class TestWB(object):
assert result.name.str.contains("GDP").any()
def test_wdi_download(self):
-
# Test a bad indicator with double (US), triple (USA),
# standard (CA, MX), non standard (KSV),
# duplicated (US, US, USA), and unknown (BLA) country codes
@@ -64,9 +60,9 @@ class TestWB(object):
"NY.GDP.PCAP.CD": {
("Canada", "2004"): 32000.0,
("Canada", "2003"): 28000.0,
- ("Kosovo", "2004"): 2000.0,
- ("Kosovo", "2003"): 2000.0,
- ("Mexico", "2004"): 7000.0,
+ ("Kosovo", "2004"): np.nan,
+ ("Kosovo", "2003"): np.nan,
+ ("Mexico", "2004"): 8000.0,
("Mexico", "2003"): 7000.0,
("United States", "2004"): 42000.0,
("United States", "2003"): 39000.0,
@@ -101,20 +97,20 @@ class TestWB(object):
tm.assert_frame_equal(result, expected)
def test_wdi_download_str(self):
-
# These are the expected results, rounded (robust against
# data revisions in the future).
expected = {
"NY.GDP.PCAP.CD": {
("Japan", "2004"): 38000.0,
("Japan", "2003"): 35000.0,
- ("Japan", "2002"): 32000.0,
+ ("Japan", "2002"): 33000.0,
("Japan", "2001"): 34000.0,
("Japan", "2000"): 39000.0,
}
}
expected = pd.DataFrame(expected)
expected = expected.sort_index()
+ expected.index.names = ("country", "year")
cntry_codes = "JP"
inds = "NY.GDP.PCAP.CD"
@@ -152,8 +148,8 @@ class TestWB(object):
result = download(
country=cntry_codes, indicator=inds, start=2003, end=2004, errors="warn"
)
- assert isinstance(result, pd.DataFrame)
- assert len(result), 2
+ assert isinstance(result, pd.DataFrame)
+ assert len(result), 2
cntry_codes = ["USA"]
inds = ["NY.GDP.PCAP.CD", "BAD_INDICATOR"]
@@ -172,11 +168,10 @@ class TestWB(object):
result = download(
country=cntry_codes, indicator=inds, start=2003, end=2004, errors="warn"
)
- assert isinstance(result, pd.DataFrame)
- assert len(result) == 2
+ assert isinstance(result, pd.DataFrame)
+ assert len(result) == 2
def test_wdi_download_w_retired_indicator(self):
-
cntry_codes = ["CA", "MX", "US"]
# Despite showing up in the search feature, and being listed online,
# the api calls to GDPPCKD don't work in their own query builder, nor
@@ -192,7 +187,7 @@ class TestWB(object):
inds = ["GDPPCKD"]
with pytest.raises(ValueError):
- result = download(
+ download(
country=cntry_codes,
indicator=inds,
start=2003,
@@ -200,21 +195,12 @@ class TestWB(object):
errors="ignore",
)
- # If it ever gets here, it means WB unretired the indicator.
- # even if they dropped it completely, it would still
- # get caught above
- # or the WB API changed somehow in a really
- # unexpected way.
- if len(result) > 0: # pragma: no cover
- pytest.skip("Invalid results")
-
def test_wdi_download_w_crash_inducing_countrycode(self):
-
cntry_codes = ["CA", "MX", "US", "XXX"]
inds = ["NY.GDP.PCAP.CD"]
with pytest.raises(ValueError):
- result = download(
+ download(
country=cntry_codes,
indicator=inds,
start=2003,
@@ -222,13 +208,6 @@ class TestWB(object):
errors="ignore",
)
- # If it ever gets here, it means the country code XXX
- # got used by WB
- # or the WB API changed somehow in a really
- # unexpected way.
- if len(result) > 0: # pragma: no cover
- pytest.skip("Invalid results")
-
def test_wdi_get_countries(self):
result1 = get_countries()
result2 = WorldBankReader().get_countries()
@@ -267,7 +246,7 @@ class TestWB(object):
assert sorted(result.columns) == sorted(exp_col)
assert len(result) > 10000
- @skip_on_exception(RemoteDataError)
+ @pytest.mark.xfail(reason="World Bank API changed, no data returned")
def test_wdi_download_monthly(self):
expected = {
"COPPER": {
Index: pandas-datareader-0.10.0/pandas_datareader/tests/yahoo/test_options.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/yahoo/test_options.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/yahoo/test_options.py
@@ -18,7 +18,6 @@ def aapl():
@pytest.fixture
def month():
-
# AAPL has monthlies
today = datetime.today()
month = today.month + 1
@@ -31,7 +30,6 @@ def month():
@pytest.fixture
def year():
-
# AAPL has monthlies
today = datetime.today()
year = today.year
@@ -100,7 +98,7 @@ class TestYahooOptions(object):
]
)
tm.assert_index_equal(df.columns, exp_columns)
- assert df.index.names == [u"Strike", u"Expiry", u"Type", u"Symbol"]
+ assert df.index.names == ["Strike", "Expiry", "Type", "Symbol"]
dtypes = [
np.dtype(x)
Index: pandas-datareader-0.10.0/pandas_datareader/wb.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/wb.py
+++ pandas-datareader-0.10.0/pandas_datareader/wb.py
@@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
+from functools import reduce
import warnings
import numpy as np
import pandas as pd
from pandas_datareader.base import _BaseReader
-from pandas_datareader.compat import lrange, reduce, string_types
# This list of country codes was pulled from wikipedia during October 2014.
# While some exceptions do exist, it is the best proxy for countries supported
@@ -562,10 +562,9 @@ class WorldBankReader(_BaseReader):
session=None,
errors="warn",
):
-
if symbols is None:
symbols = ["NY.GDP.MKTP.CD", "NY.GNS.ICTR.ZS"]
- elif isinstance(symbols, string_types):
+ elif isinstance(symbols, str):
symbols = [symbols]
super(WorldBankReader, self).__init__(
@@ -579,7 +578,7 @@ class WorldBankReader(_BaseReader):
if countries is None:
countries = ["MX", "CA", "US"]
- elif isinstance(countries, string_types):
+ elif isinstance(countries, str):
countries = [countries]
bad_countries = np.setdiff1d(countries, country_codes)
@@ -590,7 +589,9 @@ class WorldBankReader(_BaseReader):
raise ValueError("Invalid Country Code(s): %s" % tmp)
if errors == "warn":
warnings.warn(
- "Non-standard ISO " "country codes: %s" % tmp, UserWarning
+ "Non-standard ISO country codes: %s" % tmp,
+ UserWarning,
+ stacklevel=2,
)
freq_symbols = ["M", "Q", "A", None]
@@ -654,9 +655,9 @@ class WorldBankReader(_BaseReader):
except ValueError as e:
msg = str(e) + " Indicator: " + indicator
if self.errors == "raise":
- raise ValueError(msg)
+ raise ValueError(msg) from e
elif self.errors == "warn":
- warnings.warn(msg)
+ warnings.warn(msg, stacklevel=2)
# Confirm we actually got some data, and build Dataframe
if len(data) > 0:
@@ -769,7 +770,7 @@ class WorldBankReader(_BaseReader):
# Clean output
data = data.sort_values(by="id")
- data.index = pd.Index(lrange(data.shape[0]))
+ data.index = pd.Index(list(range((data.shape[0]))))
# cache
_cached_series = data.copy()
@@ -820,7 +821,7 @@ def download(
end=2005,
freq=None,
errors="warn",
- **kwargs
+ **kwargs,
):
"""
Download data series from the World Bank's World Development Indicators
@@ -865,7 +866,7 @@ def download(
end=end,
freq=freq,
errors=errors,
- **kwargs
+ **kwargs,
).read()
Index: pandas-datareader-0.10.0/pandas_datareader/yahoo/daily.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/yahoo/daily.py
+++ pandas-datareader-0.10.0/pandas_datareader/yahoo/daily.py
@@ -151,9 +151,9 @@ class YahooDailyReader(_DailyBaseReader)
try:
j = json.loads(re.search(ptrn, resp.text, re.DOTALL).group(1))
data = j["context"]["dispatcher"]["stores"]["HistoricalPriceStore"]
- except KeyError:
+ except KeyError as exc:
msg = "No data fetched for symbol {} using {}"
- raise RemoteDataError(msg.format(symbol, self.__class__.__name__))
+ raise RemoteDataError(msg.format(symbol, self.__class__.__name__)) from exc
# price data
prices = DataFrame(data["prices"])
@@ -175,7 +175,6 @@ class YahooDailyReader(_DailyBaseReader)
# dividends & splits data
if self.get_actions and data["eventsData"]:
-
actions = DataFrame(data["eventsData"])
actions.columns = [col.capitalize() for col in actions.columns]
actions["Date"] = to_datetime(
Index: pandas-datareader-0.10.0/pandas_datareader/yahoo/options.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/yahoo/options.py
+++ pandas-datareader-0.10.0/pandas_datareader/yahoo/options.py
@@ -137,14 +137,15 @@ class Options(_OptionBaseReader):
).sort_index()
def _option_from_url(self, url):
-
jd = self._parse_url(url)
result = jd["optionChain"]["result"]
try:
calls = result["options"]["calls"]
puts = result["options"]["puts"]
- except IndexError:
- raise RemoteDataError("Option json not available " "for url: %s" % url)
+ except IndexError as exc:
+ raise RemoteDataError(
+ "Option json not available " "for url: %s" % url
+ ) from exc
self.underlying_price = (
result["quote"]["regularMarketPrice"]
@@ -562,7 +563,7 @@ class Options(_OptionBaseReader):
on Yahoo and may change.
"""
- warnings.warn("get_forward_data() is deprecated", FutureWarning)
+ warnings.warn("get_forward_data() is deprecated", FutureWarning, stacklevel=2)
end_date = dt.date.today() + MonthEnd(months)
dates = [date for date in self.expiry_dates if date <= end_date.date()]
data = self._get_data_in_date_range(dates, call=call, put=put)
@@ -620,7 +621,6 @@ class Options(_OptionBaseReader):
return self._load_data()
def _get_data_in_date_range(self, dates, call=True, put=True):
-
to_ret = Series({"call": call, "put": put})
to_ret = to_ret[to_ret].index
Index: pandas-datareader-0.10.0/pyproject.toml
===================================================================
--- /dev/null
+++ pandas-datareader-0.10.0/pyproject.toml
@@ -0,0 +1,96 @@
+[build-system]
+requires = ["setuptools>=64", "setuptools_scm>=8,<9", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "pandas-datareader"
+dynamic = ["version", "dependencies", "readme"]
+requires-python = ">=3.8"
+license = {file = "LICENSE.md"}
+description = "Pandas-compatible data readers. Formerly a component of pandas."
+authors = [
+ {name = "The PyData Development Team", email = "pydata@googlegroups.com"},
+]
+classifiers =[
+ "Development Status :: 5 - Production/Stable",
+ "Environment :: Console",
+ "Intended Audience :: Science/Research",
+ "License :: OSI Approved :: BSD License",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3 :: Only",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ "Topic :: Scientific/Engineering"
+]
+
+[project.urls]
+Homepage = "https://pandas.pydata.org"
+Documentation = "https://pandas-datareader.readthedocs.io/en/latest/"
+Repository = "https://github.com/pydata/pandas-datareader.git"
+"Bug Tracker" = "https://github.com/pydata/pandas-datareader/issues"
+
+
+[tool.setuptools]
+package-dir = {"" = "."}
+
+[tool.setuptools.dynamic]
+dependencies = {file = ["requirements.txt"]}
+readme = {file = ["README.md"], content-type = "text/markdown"}
+
+[tool.setuptools_scm]
+version_file = "pandas_datareader/_version.py"
+
+[tool.isort]
+profile="black"
+known_compat="pandas_datareader.compat.*"
+sections=["FUTURE","COMPAT","STDLIB","THIRDPARTY","FIRSTPARTY","LOCALFOLDER"]
+known_first_party="pandas_datareader"
+known_third_party=["numpy","pandas","pytest","requests"]
+combine_as_imports = true
+force_sort_within_sections = true
+
+[tool.pytest.ini_options]
+minversion = "6.0"
+addopts = "-ra -q"
+testpaths = ["pandas_datareader"]
+markers = [
+ "stable: mark a test as applying to a stable reader",
+ "requires_api_key: mark a test as requiring an API key",
+ "alpha_vantage: mark a test of the AlphaVantage reader",
+ "quandl: mark a test of the Quandl reader"
+ ]
+filterwarnings =[
+ "ignore:`np.bool` is a deprecated alias:DeprecationWarning:pandas.core.indexes",
+ "ignore:`np.object` is a deprecated alias:DeprecationWarning:pandas.core.indexes",
+ "ignore:`np.float` is a deprecated alias:DeprecationWarning:pandas.core.indexes",
+ "ignore:`np.complex` is a deprecated alias:DeprecationWarning:pandas.core.indexes",
+ "ignore:`np.bool` is a deprecated alias:DeprecationWarning:pandas.core.internals.blocks",
+ "ignore:`np.object` is a deprecated alias:DeprecationWarning:pandas.core.internals.blocks",
+ "ignore:`np.object` is a deprecated alias:DeprecationWarning:pandas.core.internals.construction",
+ "ignore:`np.object` is a deprecated alias:DeprecationWarning:pandas.io.parsers",
+ "ignore:`np.object` is a deprecated alias:DeprecationWarning:pandas.core.dtypes.cast",
+ "ignore:`np.float` is a deprecated alias:DeprecationWarning:pandas.core.internals.blocks",
+ "ignore:`np.complex` is a deprecated alias:DeprecationWarning:pandas.core.internals.blocks",
+ "ignore:Converting `np.inexact` or `np.floating` to a dtype:DeprecationWarning:pandas.core.indexes",
+]
+
+
+[tool.flake8]
+ignore = ["E203", "E266", "E501", "W503"]
+max-line-length = 88
+max-complexity = 18
+select = ["B","C","E","F","W","T4","B9"]
+
+[tool.black]
+target-version = ["py38", "py39", "py310","py311","py312"]
+required-version = "23.10.1"
+exclude = """
+(
+ pandas_datareader/_version.py
+)
+"""
Index: pandas-datareader-0.10.0/requirements-dev.txt
===================================================================
--- pandas-datareader-0.10.0.orig/requirements-dev.txt
+++ pandas-datareader-0.10.0/requirements-dev.txt
@@ -1,5 +1,6 @@
-black==21.5b1; python_version > '3.5'
-flake8-bugbear; python_version > '3.5'
+black==23.10.1
+isort>=5.12.0
+flake8-bugbear
coverage
codecov
coveralls
@@ -7,3 +8,4 @@ flake8
pytest
pytest-cov
wrapt
+flake8-pyproject
\ No newline at end of file
Index: pandas-datareader-0.10.0/requirements.txt
===================================================================
--- pandas-datareader-0.10.0.orig/requirements.txt
+++ pandas-datareader-0.10.0/requirements.txt
@@ -1,3 +1,3 @@
lxml
-pandas>=0.23
+pandas>=1.5.3
requests>=2.19.0
Index: pandas-datareader-0.10.0/versioneer.py
===================================================================
--- pandas-datareader-0.10.0.orig/versioneer.py
+++ /dev/null
@@ -1,1886 +0,0 @@
-# Version: 0.18
-
-"""The Versioneer - like a rocketeer, but for versions.
-
-The Versioneer
-==============
-
-* like a rocketeer, but for versions!
-* https://github.com/warner/python-versioneer
-* Brian Warner
-* License: Public Domain
-* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy
-* [![Latest Version]
-(https://pypip.in/version/versioneer/badge.svg?style=flat)
-](https://pypi.python.org/pypi/versioneer/)
-* [![Build Status]
-(https://travis-ci.org/warner/python-versioneer.png?branch=master)
-](https://travis-ci.org/warner/python-versioneer)
-
-This is a tool for managing a recorded version number in distutils-based
-python projects. The goal is to remove the tedious and error-prone "update
-the embedded version string" step from your release process. Making a new
-release should be as easy as recording a new tag in your version-control
-system, and maybe making new tarballs.
-
-
-## Quick Install
-
-* `pip install versioneer` to somewhere to your $PATH
-* add a `[versioneer]` section to your setup.cfg (see below)
-* run `versioneer install` in your source tree, commit the results
-
-## Version Identifiers
-
-Source trees come from a variety of places:
-
-* a version-control system checkout (mostly used by developers)
-* a nightly tarball, produced by build automation
-* a snapshot tarball, produced by a web-based VCS browser, like github's
- "tarball from tag" feature
-* a release tarball, produced by "setup.py sdist", distributed through PyPI
-
-Within each source tree, the version identifier (either a string or a number,
-this tool is format-agnostic) can come from a variety of places:
-
-* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows
- about recent "tags" and an absolute revision-id
-* the name of the directory into which the tarball was unpacked
-* an expanded VCS keyword ($Id$, etc)
-* a `_version.py` created by some earlier build step
-
-For released software, the version identifier is closely related to a VCS
-tag. Some projects use tag names that include more than just the version
-string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool
-needs to strip the tag prefix to extract the version identifier. For
-unreleased software (between tags), the version identifier should provide
-enough information to help developers recreate the same tree, while also
-giving them an idea of roughly how old the tree is (after version 1.2, before
-version 1.3). Many VCS systems can report a description that captures this,
-for example `git describe --tags --dirty --always` reports things like
-"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the
-0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has
-uncommitted changes.
-
-The version identifier is used for multiple purposes:
-
-* to allow the module to self-identify its version: `myproject.__version__`
-* to choose a name and prefix for a 'setup.py sdist' tarball
-
-## Theory of Operation
-
-Versioneer works by adding a special `_version.py` file into your source
-tree, where your `__init__.py` can import it. This `_version.py` knows how to
-dynamically ask the VCS tool for version information at import time.
-
-`_version.py` also contains `$Revision$` markers, and the installation
-process marks `_version.py` to have this marker rewritten with a tag name
-during the `git archive` command. As a result, generated tarballs will
-contain enough information to get the proper version.
-
-To allow `setup.py` to compute a version too, a `versioneer.py` is added to
-the top level of your source tree, next to `setup.py` and the `setup.cfg`
-that configures it. This overrides several distutils/setuptools commands to
-compute the version when invoked, and changes `setup.py build` and `setup.py
-sdist` to replace `_version.py` with a small static file that contains just
-the generated version data.
-
-## Installation
-
-See [INSTALL.md](./INSTALL.md) for detailed installation instructions.
-
-## Version-String Flavors
-
-Code which uses Versioneer can learn about its version string at runtime by
-importing `_version` from your main `__init__.py` file and running the
-`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can
-import the top-level `versioneer.py` and run `get_versions()`.
-
-Both functions return a dictionary with different flavors of version
-information:
-
-* `['version']`: A condensed version string, rendered using the selected
- style. This is the most commonly used value for the project's version
- string. The default "pep440" style yields strings like `0.11`,
- `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section
- below for alternative styles.
-
-* `['full-revisionid']`: detailed revision identifier. For Git, this is the
- full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac".
-
-* `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the
- commit date in ISO 8601 format. This will be None if the date is not
- available.
-
-* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that
- this is only accurate if run in a VCS checkout, otherwise it is likely to
- be False or None
-
-* `['error']`: if the version string could not be computed, this will be set
- to a string describing the problem, otherwise it will be None. It may be
- useful to throw an exception in setup.py if this is set, to avoid e.g.
- creating tarballs with a version string of "unknown".
-
-Some variants are more useful than others. Including `full-revisionid` in a
-bug report should allow developers to reconstruct the exact code being tested
-(or indicate the presence of local changes that should be shared with the
-developers). `version` is suitable for display in an "about" box or a CLI
-`--version` output: it can be easily compared against release notes and lists
-of bugs fixed in various releases.
-
-The installer adds the following text to your `__init__.py` to place a basic
-version in `YOURPROJECT.__version__`:
-
- from ._version import get_versions
- __version__ = get_versions()['version']
- del get_versions
-
-## Styles
-
-The setup.cfg `style=` configuration controls how the VCS information is
-rendered into a version string.
-
-The default style, "pep440", produces a PEP440-compliant string, equal to the
-un-prefixed tag name for actual releases, and containing an additional "local
-version" section with more detail for in-between builds. For Git, this is
-TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags
---dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the
-tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and
-that this commit is two revisions ("+2") beyond the "0.11" tag. For released
-software (exactly equal to a known tag), the identifier will only contain the
-stripped tag, e.g. "0.11".
-
-Other styles are available. See [details.md](details.md) in the Versioneer
-source tree for descriptions.
-
-## Debugging
-
-Versioneer tries to avoid fatal errors: if something goes wrong, it will tend
-to return a version of "0+unknown". To investigate the problem, run `setup.py
-version`, which will run the version-lookup code in a verbose mode, and will
-display the full contents of `get_versions()` (including the `error` string,
-which may help identify what went wrong).
-
-## Known Limitations
-
-Some situations are known to cause problems for Versioneer. This details the
-most significant ones. More can be found on Github
-[issues page](https://github.com/warner/python-versioneer/issues).
-
-### Subprojects
-
-Versioneer has limited support for source trees in which `setup.py` is not in
-the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are
-two common reasons why `setup.py` might not be in the root:
-
-* Source trees which contain multiple subprojects, such as
- [Buildbot](https://github.com/buildbot/buildbot), which contains both
- "master" and "slave" subprojects, each with their own `setup.py`,
- `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI
- distributions (and upload multiple independently-installable tarballs).
-* Source trees whose main purpose is to contain a C library, but which also
- provide bindings to Python (and perhaps other langauges) in subdirectories.
-
-Versioneer will look for `.git` in parent directories, and most operations
-should get the right version string. However `pip` and `setuptools` have bugs
-and implementation details which frequently cause `pip install .` from a
-subproject directory to fail to find a correct version string (so it usually
-defaults to `0+unknown`).
-
-`pip install --editable .` should work correctly. `setup.py install` might
-work too.
-
-Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in
-some later version.
-
-[Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking
-this issue. The discussion in
-[PR #61](https://github.com/warner/python-versioneer/pull/61) describes the
-issue from the Versioneer side in more detail.
-[pip PR#3176](https://github.com/pypa/pip/pull/3176) and
-[pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve
-pip to let Versioneer work correctly.
-
-Versioneer-0.16 and earlier only looked for a `.git` directory next to the
-`setup.cfg`, so subprojects were completely unsupported with those releases.
-
-### Editable installs with setuptools <= 18.5
-
-`setup.py develop` and `pip install --editable .` allow you to install a
-project into a virtualenv once, then continue editing the source code (and
-test) without re-installing after every change.
-
-"Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a
-convenient way to specify executable scripts that should be installed along
-with the python package.
-
-These both work as expected when using modern setuptools. When using
-setuptools-18.5 or earlier, however, certain operations will cause
-`pkg_resources.DistributionNotFound` errors when running the entrypoint
-script, which must be resolved by re-installing the package. This happens
-when the install happens with one version, then the egg_info data is
-regenerated while a different version is checked out. Many setup.py commands
-cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into
-a different virtualenv), so this can be surprising.
-
-[Bug #83](https://github.com/warner/python-versioneer/issues/83) describes
-this one, but upgrading to a newer version of setuptools should probably
-resolve it.
-
-### Unicode version strings
-
-While Versioneer works (and is continually tested) with both Python 2 and
-Python 3, it is not entirely consistent with bytes-vs-unicode distinctions.
-Newer releases probably generate unicode version strings on py2. It's not
-clear that this is wrong, but it may be surprising for applications when then
-write these strings to a network connection or include them in bytes-oriented
-APIs like cryptographic checksums.
-
-[Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates
-this question.
-
-
-## Updating Versioneer
-
-To upgrade your project to a new release of Versioneer, do the following:
-
-* install the new Versioneer (`pip install -U versioneer` or equivalent)
-* edit `setup.cfg`, if necessary, to include any new configuration settings
- indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details.
-* re-run `versioneer install` in your source tree, to replace
- `SRC/_version.py`
-* commit any changed files
-
-## Future Directions
-
-This tool is designed to make it easily extended to other version-control
-systems: all VCS-specific components are in separate directories like
-src/git/ . The top-level `versioneer.py` script is assembled from these
-components by running make-versioneer.py . In the future, make-versioneer.py
-will take a VCS name as an argument, and will construct a version of
-`versioneer.py` that is specific to the given VCS. It might also take the
-configuration arguments that are currently provided manually during
-installation by editing setup.py . Alternatively, it might go the other
-direction and include code from all supported VCS systems, reducing the
-number of intermediate scripts.
-
-
-## License
-
-To make Versioneer easier to embed, all its code is dedicated to the public
-domain. The `_version.py` that it creates is also in the public domain.
-Specifically, both are released under the Creative Commons "Public Domain
-Dedication" license (CC0-1.0), as described in
-https://creativecommons.org/publicdomain/zero/1.0/ .
-
-"""
-
-from __future__ import print_function
-
-import errno
-import json
-import os
-import re
-import subprocess
-import sys
-
-try:
- import configparser
-except ImportError:
- import ConfigParser as configparser
-
-
-class VersioneerConfig:
- """Container for Versioneer configuration parameters."""
-
-
-def get_root():
- """Get the project root directory.
-
- We require that all commands are run from the project root, i.e. the
- directory that contains setup.py, setup.cfg, and versioneer.py .
- """
- root = os.path.realpath(os.path.abspath(os.getcwd()))
- setup_py = os.path.join(root, "setup.py")
- versioneer_py = os.path.join(root, "versioneer.py")
- if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)):
- # allow 'python path/to/setup.py COMMAND'
- root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0])))
- setup_py = os.path.join(root, "setup.py")
- versioneer_py = os.path.join(root, "versioneer.py")
- if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)):
- err = (
- "Versioneer was unable to run the project root directory. "
- "Versioneer requires setup.py to be executed from "
- "its immediate directory (like 'python setup.py COMMAND'), "
- "or in a way that lets it use sys.argv[0] to find the root "
- "(like 'python path/to/setup.py COMMAND')."
- )
- raise VersioneerBadRootError(err)
- try:
- # Certain runtime workflows (setup.py install/develop in a setuptools
- # tree) execute all dependencies in a single python process, so
- # "versioneer" may be imported multiple times, and python's shared
- # module-import table will cache the first one. So we can't use
- # os.path.dirname(__file__), as that will find whichever
- # versioneer.py was first imported, even in later projects.
- me = os.path.realpath(os.path.abspath(__file__))
- me_dir = os.path.normcase(os.path.splitext(me)[0])
- vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0])
- if me_dir != vsr_dir:
- print(
- "Warning: build in %s is using versioneer.py from %s"
- % (os.path.dirname(me), versioneer_py)
- )
- except NameError:
- pass
- return root
-
-
-def get_config_from_root(root):
- """Read the project setup.cfg file to determine Versioneer config."""
- # This might raise EnvironmentError (if setup.cfg is missing), or
- # configparser.NoSectionError (if it lacks a [versioneer] section), or
- # configparser.NoOptionError (if it lacks "VCS="). See the docstring at
- # the top of versioneer.py for instructions on writing your setup.cfg .
- setup_cfg = os.path.join(root, "setup.cfg")
- parser = configparser.SafeConfigParser()
- with open(setup_cfg, "r") as f:
- parser.readfp(f)
- VCS = parser.get("versioneer", "VCS") # mandatory
-
- def get(parser, name):
- if parser.has_option("versioneer", name):
- return parser.get("versioneer", name)
- return None
-
- cfg = VersioneerConfig()
- cfg.VCS = VCS
- cfg.style = get(parser, "style") or ""
- cfg.versionfile_source = get(parser, "versionfile_source")
- cfg.versionfile_build = get(parser, "versionfile_build")
- cfg.tag_prefix = get(parser, "tag_prefix")
- if cfg.tag_prefix in ("''", '""'):
- cfg.tag_prefix = ""
- cfg.parentdir_prefix = get(parser, "parentdir_prefix")
- cfg.verbose = get(parser, "verbose")
- return cfg
-
-
-class NotThisMethod(Exception):
- """Exception raised if a method is not valid for the current scenario."""
-
-
-# these dictionaries contain VCS-specific tools
-LONG_VERSION_PY = {}
-HANDLERS = {}
-
-
-def register_vcs_handler(vcs, method): # decorator
- """Decorator to mark a method as the handler for a particular VCS."""
-
- def decorate(f):
- """Store f in HANDLERS[vcs][method]."""
- if vcs not in HANDLERS:
- HANDLERS[vcs] = {}
- HANDLERS[vcs][method] = f
- return f
-
- return decorate
-
-
-def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None):
- """Call the given command(s)."""
- assert isinstance(commands, list)
- p = None
- for c in commands:
- try:
- dispcmd = str([c] + args)
- # remember shell=False, so use git.cmd on windows, not just git
- p = subprocess.Popen(
- [c] + args,
- cwd=cwd,
- env=env,
- stdout=subprocess.PIPE,
- stderr=(subprocess.PIPE if hide_stderr else None),
- )
- break
- except EnvironmentError:
- e = sys.exc_info()[1]
- if e.errno == errno.ENOENT:
- continue
- if verbose:
- print("unable to run %s" % dispcmd)
- print(e)
- return None, None
- else:
- if verbose:
- print("unable to find command, tried %s" % (commands,))
- return None, None
- stdout = p.communicate()[0].strip()
- if sys.version_info[0] >= 3:
- stdout = stdout.decode()
- if p.returncode != 0:
- if verbose:
- print("unable to run %s (error)" % dispcmd)
- print("stdout was %s" % stdout)
- return None, p.returncode
- return stdout, p.returncode
-
-
-LONG_VERSION_PY[
- "git"
-] = r'''
-# This file helps to compute a version number in source trees obtained from
-# git-archive tarball (such as those provided by githubs download-from-tag
-# feature). Distribution tarballs (built by setup.py sdist) and build
-# directories (produced by setup.py build) will contain a much shorter file
-# that just contains the computed version number.
-
-# This file is released into the public domain. Generated by
-# versioneer-0.18 (https://github.com/warner/python-versioneer)
-
-"""Git implementation of _version.py."""
-
-import errno
-import os
-import re
-import subprocess
-import sys
-
-
-def get_keywords():
- """Get the keywords needed to look up the version information."""
- # these strings will be replaced by git during git-archive.
- # setup.py/versioneer.py will grep for the variable names, so they must
- # each be defined on a line of their own. _version.py will just call
- # get_keywords().
- git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s"
- git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s"
- git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s"
- keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
- return keywords
-
-
-class VersioneerConfig:
- """Container for Versioneer configuration parameters."""
-
-
-def get_config():
- """Create, populate and return the VersioneerConfig() object."""
- # these strings are filled in when 'setup.py versioneer' creates
- # _version.py
- cfg = VersioneerConfig()
- cfg.VCS = "git"
- cfg.style = "%(STYLE)s"
- cfg.tag_prefix = "%(TAG_PREFIX)s"
- cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s"
- cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s"
- cfg.verbose = False
- return cfg
-
-
-class NotThisMethod(Exception):
- """Exception raised if a method is not valid for the current scenario."""
-
-
-LONG_VERSION_PY = {}
-HANDLERS = {}
-
-
-def register_vcs_handler(vcs, method): # decorator
- """Decorator to mark a method as the handler for a particular VCS."""
- def decorate(f):
- """Store f in HANDLERS[vcs][method]."""
- if vcs not in HANDLERS:
- HANDLERS[vcs] = {}
- HANDLERS[vcs][method] = f
- return f
- return decorate
-
-
-def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
- env=None):
- """Call the given command(s)."""
- assert isinstance(commands, list)
- p = None
- for c in commands:
- try:
- dispcmd = str([c] + args)
- # remember shell=False, so use git.cmd on windows, not just git
- p = subprocess.Popen([c] + args, cwd=cwd, env=env,
- stdout=subprocess.PIPE,
- stderr=(subprocess.PIPE if hide_stderr
- else None))
- break
- except EnvironmentError:
- e = sys.exc_info()[1]
- if e.errno == errno.ENOENT:
- continue
- if verbose:
- print("unable to run %%s" %% dispcmd)
- print(e)
- return None, None
- else:
- if verbose:
- print("unable to find command, tried %%s" %% (commands,))
- return None, None
- stdout = p.communicate()[0].strip()
- if sys.version_info[0] >= 3:
- stdout = stdout.decode()
- if p.returncode != 0:
- if verbose:
- print("unable to run %%s (error)" %% dispcmd)
- print("stdout was %%s" %% stdout)
- return None, p.returncode
- return stdout, p.returncode
-
-
-def versions_from_parentdir(parentdir_prefix, root, verbose):
- """Try to determine the version from the parent directory name.
-
- Source tarballs conventionally unpack into a directory that includes both
- the project name and a version string. We will also support searching up
- two directory levels for an appropriately named parent directory
- """
- rootdirs = []
-
- for i in range(3):
- dirname = os.path.basename(root)
- if dirname.startswith(parentdir_prefix):
- return {"version": dirname[len(parentdir_prefix):],
- "full-revisionid": None,
- "dirty": False, "error": None, "date": None}
- else:
- rootdirs.append(root)
- root = os.path.dirname(root) # up a level
-
- if verbose:
- print("Tried directories %%s but none started with prefix %%s" %%
- (str(rootdirs), parentdir_prefix))
- raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
-
-
-@register_vcs_handler("git", "get_keywords")
-def git_get_keywords(versionfile_abs):
- """Extract version information from the given file."""
- # the code embedded in _version.py can just fetch the value of these
- # keywords. When used from setup.py, we don't want to import _version.py,
- # so we do it with a regexp instead. This function is not used from
- # _version.py.
- keywords = {}
- try:
- f = open(versionfile_abs, "r")
- for line in f.readlines():
- if line.strip().startswith("git_refnames ="):
- mo = re.search(r'=\s*"(.*)"', line)
- if mo:
- keywords["refnames"] = mo.group(1)
- if line.strip().startswith("git_full ="):
- mo = re.search(r'=\s*"(.*)"', line)
- if mo:
- keywords["full"] = mo.group(1)
- if line.strip().startswith("git_date ="):
- mo = re.search(r'=\s*"(.*)"', line)
- if mo:
- keywords["date"] = mo.group(1)
- f.close()
- except EnvironmentError:
- pass
- return keywords
-
-
-@register_vcs_handler("git", "keywords")
-def git_versions_from_keywords(keywords, tag_prefix, verbose):
- """Get version information from git keywords."""
- if not keywords:
- raise NotThisMethod("no keywords at all, weird")
- date = keywords.get("date")
- if date is not None:
- # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant
- # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601
- # -like" string, which we must then edit to make compliant), because
- # it's been around since git-1.5.3, and it's too difficult to
- # discover which version we're using, or to work around using an
- # older one.
- date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
- refnames = keywords["refnames"].strip()
- if refnames.startswith("$Format"):
- if verbose:
- print("keywords are unexpanded, not using")
- raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
- refs = set([r.strip() for r in refnames.strip("()").split(",")])
- # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
- # just "foo-1.0". If we see a "tag: " prefix, prefer those.
- TAG = "tag: "
- tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
- if not tags:
- # Either we're using git < 1.8.3, or there really are no tags. We use
- # a heuristic: assume all version tags have a digit. The old git %%d
- # expansion behaves like git log --decorate=short and strips out the
- # refs/heads/ and refs/tags/ prefixes that would let us distinguish
- # between branches and tags. By ignoring refnames without digits, we
- # filter out many common branch names like "release" and
- # "stabilization", as well as "HEAD" and "master".
- tags = set([r for r in refs if re.search(r'\d', r)])
- if verbose:
- print("discarding '%%s', no digits" %% ",".join(refs - tags))
- if verbose:
- print("likely tags: %%s" %% ",".join(sorted(tags)))
- for ref in sorted(tags):
- # sorting will prefer e.g. "2.0" over "2.0rc1"
- if ref.startswith(tag_prefix):
- r = ref[len(tag_prefix):]
- if verbose:
- print("picking %%s" %% r)
- return {"version": r,
- "full-revisionid": keywords["full"].strip(),
- "dirty": False, "error": None,
- "date": date}
- # no suitable tags, so version is "0+unknown", but full hex is still there
- if verbose:
- print("no suitable tags, using unknown + full revision id")
- return {"version": "0+unknown",
- "full-revisionid": keywords["full"].strip(),
- "dirty": False, "error": "no suitable tags", "date": None}
-
-
-@register_vcs_handler("git", "pieces_from_vcs")
-def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
- """Get version from 'git describe' in the root of the source tree.
-
- This only gets called if the git-archive 'subst' keywords were *not*
- expanded, and _version.py hasn't already been rewritten with a short
- version string, meaning we're inside a checked out source tree.
- """
- GITS = ["git"]
- if sys.platform == "win32":
- GITS = ["git.cmd", "git.exe"]
-
- out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root,
- hide_stderr=True)
- if rc != 0:
- if verbose:
- print("Directory %%s not under git control" %% root)
- raise NotThisMethod("'git rev-parse --git-dir' returned error")
-
- # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
- # if there isn't one, this yields HEX[-dirty] (no NUM)
- describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty",
- "--always", "--long",
- "--match", "%%s*" %% tag_prefix],
- cwd=root)
- # --long was added in git-1.5.5
- if describe_out is None:
- raise NotThisMethod("'git describe' failed")
- describe_out = describe_out.strip()
- full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
- if full_out is None:
- raise NotThisMethod("'git rev-parse' failed")
- full_out = full_out.strip()
-
- pieces = {}
- pieces["long"] = full_out
- pieces["short"] = full_out[:7] # maybe improved later
- pieces["error"] = None
-
- # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
- # TAG might have hyphens.
- git_describe = describe_out
-
- # look for -dirty suffix
- dirty = git_describe.endswith("-dirty")
- pieces["dirty"] = dirty
- if dirty:
- git_describe = git_describe[:git_describe.rindex("-dirty")]
-
- # now we have TAG-NUM-gHEX or HEX
-
- if "-" in git_describe:
- # TAG-NUM-gHEX
- mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
- if not mo:
- # unparseable. Maybe git-describe is misbehaving?
- pieces["error"] = ("unable to parse git-describe output: '%%s'"
- %% describe_out)
- return pieces
-
- # tag
- full_tag = mo.group(1)
- if not full_tag.startswith(tag_prefix):
- if verbose:
- fmt = "tag '%%s' doesn't start with prefix '%%s'"
- print(fmt %% (full_tag, tag_prefix))
- pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'"
- %% (full_tag, tag_prefix))
- return pieces
- pieces["closest-tag"] = full_tag[len(tag_prefix):]
-
- # distance: number of commits since tag
- pieces["distance"] = int(mo.group(2))
-
- # commit: short hex revision ID
- pieces["short"] = mo.group(3)
-
- else:
- # HEX: no tags
- pieces["closest-tag"] = None
- count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"],
- cwd=root)
- pieces["distance"] = int(count_out) # total number of commits
-
- # commit date: see ISO-8601 comment in git_versions_from_keywords()
- date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"],
- cwd=root)[0].strip()
- pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
-
- return pieces
-
-
-def plus_or_dot(pieces):
- """Return a + if we don't already have one, else return a ."""
- if "+" in pieces.get("closest-tag", ""):
- return "."
- return "+"
-
-
-def render_pep440(pieces):
- """Build up version string, with post-release "local version identifier".
-
- Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
- get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
-
- Exceptions:
- 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- if pieces["distance"] or pieces["dirty"]:
- rendered += plus_or_dot(pieces)
- rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"])
- if pieces["dirty"]:
- rendered += ".dirty"
- else:
- # exception #1
- rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"],
- pieces["short"])
- if pieces["dirty"]:
- rendered += ".dirty"
- return rendered
-
-
-def render_pep440_pre(pieces):
- """TAG[.post.devDISTANCE] -- No -dirty.
-
- Exceptions:
- 1: no tags. 0.post.devDISTANCE
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- if pieces["distance"]:
- rendered += ".post.dev%%d" %% pieces["distance"]
- else:
- # exception #1
- rendered = "0.post.dev%%d" %% pieces["distance"]
- return rendered
-
-
-def render_pep440_post(pieces):
- """TAG[.postDISTANCE[.dev0]+gHEX] .
-
- The ".dev0" means dirty. Note that .dev0 sorts backwards
- (a dirty tree will appear "older" than the corresponding clean one),
- but you shouldn't be releasing software with -dirty anyways.
-
- Exceptions:
- 1: no tags. 0.postDISTANCE[.dev0]
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- if pieces["distance"] or pieces["dirty"]:
- rendered += ".post%%d" %% pieces["distance"]
- if pieces["dirty"]:
- rendered += ".dev0"
- rendered += plus_or_dot(pieces)
- rendered += "g%%s" %% pieces["short"]
- else:
- # exception #1
- rendered = "0.post%%d" %% pieces["distance"]
- if pieces["dirty"]:
- rendered += ".dev0"
- rendered += "+g%%s" %% pieces["short"]
- return rendered
-
-
-def render_pep440_old(pieces):
- """TAG[.postDISTANCE[.dev0]] .
-
- The ".dev0" means dirty.
-
- Eexceptions:
- 1: no tags. 0.postDISTANCE[.dev0]
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- if pieces["distance"] or pieces["dirty"]:
- rendered += ".post%%d" %% pieces["distance"]
- if pieces["dirty"]:
- rendered += ".dev0"
- else:
- # exception #1
- rendered = "0.post%%d" %% pieces["distance"]
- if pieces["dirty"]:
- rendered += ".dev0"
- return rendered
-
-
-def render_git_describe(pieces):
- """TAG[-DISTANCE-gHEX][-dirty].
-
- Like 'git describe --tags --dirty --always'.
-
- Exceptions:
- 1: no tags. HEX[-dirty] (note: no 'g' prefix)
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- if pieces["distance"]:
- rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"])
- else:
- # exception #1
- rendered = pieces["short"]
- if pieces["dirty"]:
- rendered += "-dirty"
- return rendered
-
-
-def render_git_describe_long(pieces):
- """TAG-DISTANCE-gHEX[-dirty].
-
- Like 'git describe --tags --dirty --always -long'.
- The distance/hash is unconditional.
-
- Exceptions:
- 1: no tags. HEX[-dirty] (note: no 'g' prefix)
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"])
- else:
- # exception #1
- rendered = pieces["short"]
- if pieces["dirty"]:
- rendered += "-dirty"
- return rendered
-
-
-def render(pieces, style):
- """Render the given version pieces into the requested style."""
- if pieces["error"]:
- return {"version": "unknown",
- "full-revisionid": pieces.get("long"),
- "dirty": None,
- "error": pieces["error"],
- "date": None}
-
- if not style or style == "default":
- style = "pep440" # the default
-
- if style == "pep440":
- rendered = render_pep440(pieces)
- elif style == "pep440-pre":
- rendered = render_pep440_pre(pieces)
- elif style == "pep440-post":
- rendered = render_pep440_post(pieces)
- elif style == "pep440-old":
- rendered = render_pep440_old(pieces)
- elif style == "git-describe":
- rendered = render_git_describe(pieces)
- elif style == "git-describe-long":
- rendered = render_git_describe_long(pieces)
- else:
- raise ValueError("unknown style '%%s'" %% style)
-
- return {"version": rendered, "full-revisionid": pieces["long"],
- "dirty": pieces["dirty"], "error": None,
- "date": pieces.get("date")}
-
-
-def get_versions():
- """Get version information or return default if unable to do so."""
- # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
- # __file__, we can work backwards from there to the root. Some
- # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
- # case we can only use expanded keywords.
-
- cfg = get_config()
- verbose = cfg.verbose
-
- try:
- return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
- verbose)
- except NotThisMethod:
- pass
-
- try:
- root = os.path.realpath(__file__)
- # versionfile_source is the relative path from the top of the source
- # tree (where the .git directory might live) to this file. Invert
- # this to find the root from __file__.
- for i in cfg.versionfile_source.split('/'):
- root = os.path.dirname(root)
- except NameError:
- return {"version": "0+unknown", "full-revisionid": None,
- "dirty": None,
- "error": "unable to find root of source tree",
- "date": None}
-
- try:
- pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
- return render(pieces, cfg.style)
- except NotThisMethod:
- pass
-
- try:
- if cfg.parentdir_prefix:
- return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
- except NotThisMethod:
- pass
-
- return {"version": "0+unknown", "full-revisionid": None,
- "dirty": None,
- "error": "unable to compute version", "date": None}
-'''
-
-
-@register_vcs_handler("git", "get_keywords")
-def git_get_keywords(versionfile_abs):
- """Extract version information from the given file."""
- # the code embedded in _version.py can just fetch the value of these
- # keywords. When used from setup.py, we don't want to import _version.py,
- # so we do it with a regexp instead. This function is not used from
- # _version.py.
- keywords = {}
- try:
- f = open(versionfile_abs, "r")
- for line in f.readlines():
- if line.strip().startswith("git_refnames ="):
- mo = re.search(r'=\s*"(.*)"', line)
- if mo:
- keywords["refnames"] = mo.group(1)
- if line.strip().startswith("git_full ="):
- mo = re.search(r'=\s*"(.*)"', line)
- if mo:
- keywords["full"] = mo.group(1)
- if line.strip().startswith("git_date ="):
- mo = re.search(r'=\s*"(.*)"', line)
- if mo:
- keywords["date"] = mo.group(1)
- f.close()
- except EnvironmentError:
- pass
- return keywords
-
-
-@register_vcs_handler("git", "keywords")
-def git_versions_from_keywords(keywords, tag_prefix, verbose):
- """Get version information from git keywords."""
- if not keywords:
- raise NotThisMethod("no keywords at all, weird")
- date = keywords.get("date")
- if date is not None:
- # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
- # datestamp. However we prefer "%ci" (which expands to an "ISO-8601
- # -like" string, which we must then edit to make compliant), because
- # it's been around since git-1.5.3, and it's too difficult to
- # discover which version we're using, or to work around using an
- # older one.
- date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
- refnames = keywords["refnames"].strip()
- if refnames.startswith("$Format"):
- if verbose:
- print("keywords are unexpanded, not using")
- raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
- refs = set([r.strip() for r in refnames.strip("()").split(",")])
- # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
- # just "foo-1.0". If we see a "tag: " prefix, prefer those.
- TAG = "tag: "
- tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)])
- if not tags:
- # Either we're using git < 1.8.3, or there really are no tags. We use
- # a heuristic: assume all version tags have a digit. The old git %d
- # expansion behaves like git log --decorate=short and strips out the
- # refs/heads/ and refs/tags/ prefixes that would let us distinguish
- # between branches and tags. By ignoring refnames without digits, we
- # filter out many common branch names like "release" and
- # "stabilization", as well as "HEAD" and "master".
- tags = set([r for r in refs if re.search(r"\d", r)])
- if verbose:
- print("discarding '%s', no digits" % ",".join(refs - tags))
- if verbose:
- print("likely tags: %s" % ",".join(sorted(tags)))
- for ref in sorted(tags):
- # sorting will prefer e.g. "2.0" over "2.0rc1"
- if ref.startswith(tag_prefix):
- r = ref[len(tag_prefix) :]
- if verbose:
- print("picking %s" % r)
- return {
- "version": r,
- "full-revisionid": keywords["full"].strip(),
- "dirty": False,
- "error": None,
- "date": date,
- }
- # no suitable tags, so version is "0+unknown", but full hex is still there
- if verbose:
- print("no suitable tags, using unknown + full revision id")
- return {
- "version": "0+unknown",
- "full-revisionid": keywords["full"].strip(),
- "dirty": False,
- "error": "no suitable tags",
- "date": None,
- }
-
-
-@register_vcs_handler("git", "pieces_from_vcs")
-def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
- """Get version from 'git describe' in the root of the source tree.
-
- This only gets called if the git-archive 'subst' keywords were *not*
- expanded, and _version.py hasn't already been rewritten with a short
- version string, meaning we're inside a checked out source tree.
- """
- GITS = ["git"]
- if sys.platform == "win32":
- GITS = ["git.cmd", "git.exe"]
-
- out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True)
- if rc != 0:
- if verbose:
- print("Directory %s not under git control" % root)
- raise NotThisMethod("'git rev-parse --git-dir' returned error")
-
- # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
- # if there isn't one, this yields HEX[-dirty] (no NUM)
- describe_out, rc = run_command(
- GITS,
- [
- "describe",
- "--tags",
- "--dirty",
- "--always",
- "--long",
- "--match",
- "%s*" % tag_prefix,
- ],
- cwd=root,
- )
- # --long was added in git-1.5.5
- if describe_out is None:
- raise NotThisMethod("'git describe' failed")
- describe_out = describe_out.strip()
- full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
- if full_out is None:
- raise NotThisMethod("'git rev-parse' failed")
- full_out = full_out.strip()
-
- pieces = {}
- pieces["long"] = full_out
- pieces["short"] = full_out[:7] # maybe improved later
- pieces["error"] = None
-
- # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
- # TAG might have hyphens.
- git_describe = describe_out
-
- # look for -dirty suffix
- dirty = git_describe.endswith("-dirty")
- pieces["dirty"] = dirty
- if dirty:
- git_describe = git_describe[: git_describe.rindex("-dirty")]
-
- # now we have TAG-NUM-gHEX or HEX
-
- if "-" in git_describe:
- # TAG-NUM-gHEX
- mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe)
- if not mo:
- # unparseable. Maybe git-describe is misbehaving?
- pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out
- return pieces
-
- # tag
- full_tag = mo.group(1)
- if not full_tag.startswith(tag_prefix):
- if verbose:
- fmt = "tag '%s' doesn't start with prefix '%s'"
- print(fmt % (full_tag, tag_prefix))
- pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % (
- full_tag,
- tag_prefix,
- )
- return pieces
- pieces["closest-tag"] = full_tag[len(tag_prefix) :]
-
- # distance: number of commits since tag
- pieces["distance"] = int(mo.group(2))
-
- # commit: short hex revision ID
- pieces["short"] = mo.group(3)
-
- else:
- # HEX: no tags
- pieces["closest-tag"] = None
- count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root)
- pieces["distance"] = int(count_out) # total number of commits
-
- # commit date: see ISO-8601 comment in git_versions_from_keywords()
- date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[
- 0
- ].strip()
- pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
-
- return pieces
-
-
-def do_vcs_install(manifest_in, versionfile_source, ipy):
- """Git-specific installation logic for Versioneer.
-
- For Git, this means creating/changing .gitattributes to mark _version.py
- for export-subst keyword substitution.
- """
- GITS = ["git"]
- if sys.platform == "win32":
- GITS = ["git.cmd", "git.exe"]
- files = [manifest_in, versionfile_source]
- if ipy:
- files.append(ipy)
- try:
- me = __file__
- if me.endswith(".pyc") or me.endswith(".pyo"):
- me = os.path.splitext(me)[0] + ".py"
- versioneer_file = os.path.relpath(me)
- except NameError:
- versioneer_file = "versioneer.py"
- files.append(versioneer_file)
- present = False
- try:
- f = open(".gitattributes", "r")
- for line in f.readlines():
- if line.strip().startswith(versionfile_source):
- if "export-subst" in line.strip().split()[1:]:
- present = True
- f.close()
- except EnvironmentError:
- pass
- if not present:
- f = open(".gitattributes", "a+")
- f.write("%s export-subst\n" % versionfile_source)
- f.close()
- files.append(".gitattributes")
- run_command(GITS, ["add", "--"] + files)
-
-
-def versions_from_parentdir(parentdir_prefix, root, verbose):
- """Try to determine the version from the parent directory name.
-
- Source tarballs conventionally unpack into a directory that includes both
- the project name and a version string. We will also support searching up
- two directory levels for an appropriately named parent directory
- """
- rootdirs = []
-
- for i in range(3):
- dirname = os.path.basename(root)
- if dirname.startswith(parentdir_prefix):
- return {
- "version": dirname[len(parentdir_prefix) :],
- "full-revisionid": None,
- "dirty": False,
- "error": None,
- "date": None,
- }
- else:
- rootdirs.append(root)
- root = os.path.dirname(root) # up a level
-
- if verbose:
- print(
- "Tried directories %s but none started with prefix %s"
- % (str(rootdirs), parentdir_prefix)
- )
- raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
-
-
-SHORT_VERSION_PY = """
-# This file was generated by 'versioneer.py' (0.18) from
-# revision-control system data, or from the parent directory name of an
-# unpacked source archive. Distribution tarballs contain a pre-generated copy
-# of this file.
-
-import json
-
-version_json = '''
-%s
-''' # END VERSION_JSON
-
-
-def get_versions():
- return json.loads(version_json)
-"""
-
-
-def versions_from_file(filename):
- """Try to determine the version from _version.py if present."""
- try:
- with open(filename) as f:
- contents = f.read()
- except EnvironmentError:
- raise NotThisMethod("unable to read _version.py")
- mo = re.search(
- r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S
- )
- if not mo:
- mo = re.search(
- r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S
- )
- if not mo:
- raise NotThisMethod("no version_json in _version.py")
- return json.loads(mo.group(1))
-
-
-def write_to_version_file(filename, versions):
- """Write the given version number to the given _version.py file."""
- os.unlink(filename)
- contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": "))
- with open(filename, "w") as f:
- f.write(SHORT_VERSION_PY % contents)
-
- print("set %s to '%s'" % (filename, versions["version"]))
-
-
-def plus_or_dot(pieces):
- """Return a + if we don't already have one, else return a ."""
- if "+" in pieces.get("closest-tag", ""):
- return "."
- return "+"
-
-
-def render_pep440(pieces):
- """Build up version string, with post-release "local version identifier".
-
- Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
- get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
-
- Exceptions:
- 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- if pieces["distance"] or pieces["dirty"]:
- rendered += plus_or_dot(pieces)
- rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
- if pieces["dirty"]:
- rendered += ".dirty"
- else:
- # exception #1
- rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"])
- if pieces["dirty"]:
- rendered += ".dirty"
- return rendered
-
-
-def render_pep440_pre(pieces):
- """TAG[.post.devDISTANCE] -- No -dirty.
-
- Exceptions:
- 1: no tags. 0.post.devDISTANCE
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- if pieces["distance"]:
- rendered += ".post.dev%d" % pieces["distance"]
- else:
- # exception #1
- rendered = "0.post.dev%d" % pieces["distance"]
- return rendered
-
-
-def render_pep440_post(pieces):
- """TAG[.postDISTANCE[.dev0]+gHEX] .
-
- The ".dev0" means dirty. Note that .dev0 sorts backwards
- (a dirty tree will appear "older" than the corresponding clean one),
- but you shouldn't be releasing software with -dirty anyways.
-
- Exceptions:
- 1: no tags. 0.postDISTANCE[.dev0]
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- if pieces["distance"] or pieces["dirty"]:
- rendered += ".post%d" % pieces["distance"]
- if pieces["dirty"]:
- rendered += ".dev0"
- rendered += plus_or_dot(pieces)
- rendered += "g%s" % pieces["short"]
- else:
- # exception #1
- rendered = "0.post%d" % pieces["distance"]
- if pieces["dirty"]:
- rendered += ".dev0"
- rendered += "+g%s" % pieces["short"]
- return rendered
-
-
-def render_pep440_old(pieces):
- """TAG[.postDISTANCE[.dev0]] .
-
- The ".dev0" means dirty.
-
- Eexceptions:
- 1: no tags. 0.postDISTANCE[.dev0]
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- if pieces["distance"] or pieces["dirty"]:
- rendered += ".post%d" % pieces["distance"]
- if pieces["dirty"]:
- rendered += ".dev0"
- else:
- # exception #1
- rendered = "0.post%d" % pieces["distance"]
- if pieces["dirty"]:
- rendered += ".dev0"
- return rendered
-
-
-def render_git_describe(pieces):
- """TAG[-DISTANCE-gHEX][-dirty].
-
- Like 'git describe --tags --dirty --always'.
-
- Exceptions:
- 1: no tags. HEX[-dirty] (note: no 'g' prefix)
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- if pieces["distance"]:
- rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
- else:
- # exception #1
- rendered = pieces["short"]
- if pieces["dirty"]:
- rendered += "-dirty"
- return rendered
-
-
-def render_git_describe_long(pieces):
- """TAG-DISTANCE-gHEX[-dirty].
-
- Like 'git describe --tags --dirty --always -long'.
- The distance/hash is unconditional.
-
- Exceptions:
- 1: no tags. HEX[-dirty] (note: no 'g' prefix)
- """
- if pieces["closest-tag"]:
- rendered = pieces["closest-tag"]
- rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
- else:
- # exception #1
- rendered = pieces["short"]
- if pieces["dirty"]:
- rendered += "-dirty"
- return rendered
-
-
-def render(pieces, style):
- """Render the given version pieces into the requested style."""
- if pieces["error"]:
- return {
- "version": "unknown",
- "full-revisionid": pieces.get("long"),
- "dirty": None,
- "error": pieces["error"],
- "date": None,
- }
-
- if not style or style == "default":
- style = "pep440" # the default
-
- if style == "pep440":
- rendered = render_pep440(pieces)
- elif style == "pep440-pre":
- rendered = render_pep440_pre(pieces)
- elif style == "pep440-post":
- rendered = render_pep440_post(pieces)
- elif style == "pep440-old":
- rendered = render_pep440_old(pieces)
- elif style == "git-describe":
- rendered = render_git_describe(pieces)
- elif style == "git-describe-long":
- rendered = render_git_describe_long(pieces)
- else:
- raise ValueError("unknown style '%s'" % style)
-
- return {
- "version": rendered,
- "full-revisionid": pieces["long"],
- "dirty": pieces["dirty"],
- "error": None,
- "date": pieces.get("date"),
- }
-
-
-class VersioneerBadRootError(Exception):
- """The project root directory is unknown or missing key files."""
-
-
-def get_versions(verbose=False):
- """Get the project version from whatever source is available.
-
- Returns dict with two keys: 'version' and 'full'.
- """
- if "versioneer" in sys.modules:
- # see the discussion in cmdclass.py:get_cmdclass()
- del sys.modules["versioneer"]
-
- root = get_root()
- cfg = get_config_from_root(root)
-
- assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg"
- handlers = HANDLERS.get(cfg.VCS)
- assert handlers, "unrecognized VCS '%s'" % cfg.VCS
- verbose = verbose or cfg.verbose
- assert (
- cfg.versionfile_source is not None
- ), "please set versioneer.versionfile_source"
- assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix"
-
- versionfile_abs = os.path.join(root, cfg.versionfile_source)
-
- # extract version from first of: _version.py, VCS command (e.g. 'git
- # describe'), parentdir. This is meant to work for developers using a
- # source checkout, for users of a tarball created by 'setup.py sdist',
- # and for users of a tarball/zipball created by 'git archive' or github's
- # download-from-tag feature or the equivalent in other VCSes.
-
- get_keywords_f = handlers.get("get_keywords")
- from_keywords_f = handlers.get("keywords")
- if get_keywords_f and from_keywords_f:
- try:
- keywords = get_keywords_f(versionfile_abs)
- ver = from_keywords_f(keywords, cfg.tag_prefix, verbose)
- if verbose:
- print("got version from expanded keyword %s" % ver)
- return ver
- except NotThisMethod:
- pass
-
- try:
- ver = versions_from_file(versionfile_abs)
- if verbose:
- print("got version from file %s %s" % (versionfile_abs, ver))
- return ver
- except NotThisMethod:
- pass
-
- from_vcs_f = handlers.get("pieces_from_vcs")
- if from_vcs_f:
- try:
- pieces = from_vcs_f(cfg.tag_prefix, root, verbose)
- ver = render(pieces, cfg.style)
- if verbose:
- print("got version from VCS %s" % ver)
- return ver
- except NotThisMethod:
- pass
-
- try:
- if cfg.parentdir_prefix:
- ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
- if verbose:
- print("got version from parentdir %s" % ver)
- return ver
- except NotThisMethod:
- pass
-
- if verbose:
- print("unable to compute version")
-
- return {
- "version": "0+unknown",
- "full-revisionid": None,
- "dirty": None,
- "error": "unable to compute version",
- "date": None,
- }
-
-
-def get_version():
- """Get the short version string for this project."""
- return get_versions()["version"]
-
-
-def get_cmdclass():
- """Get the custom setuptools/distutils subclasses used by Versioneer."""
- if "versioneer" in sys.modules:
- del sys.modules["versioneer"]
- # this fixes the "python setup.py develop" case (also 'install' and
- # 'easy_install .'), in which subdependencies of the main project are
- # built (using setup.py bdist_egg) in the same python process. Assume
- # a main project A and a dependency B, which use different versions
- # of Versioneer. A's setup.py imports A's Versioneer, leaving it in
- # sys.modules by the time B's setup.py is executed, causing B to run
- # with the wrong versioneer. Setuptools wraps the sub-dep builds in a
- # sandbox that restores sys.modules to it's pre-build state, so the
- # parent is protected against the child's "import versioneer". By
- # removing ourselves from sys.modules here, before the child build
- # happens, we protect the child from the parent's versioneer too.
- # Also see https://github.com/warner/python-versioneer/issues/52
-
- cmds = {}
-
- # we add "version" to both distutils and setuptools
- from distutils.core import Command
-
- class cmd_version(Command):
- description = "report generated version string"
- user_options = []
- boolean_options = []
-
- def initialize_options(self):
- pass
-
- def finalize_options(self):
- pass
-
- def run(self):
- vers = get_versions(verbose=True)
- print("Version: %s" % vers["version"])
- print(" full-revisionid: %s" % vers.get("full-revisionid"))
- print(" dirty: %s" % vers.get("dirty"))
- print(" date: %s" % vers.get("date"))
- if vers["error"]:
- print(" error: %s" % vers["error"])
-
- cmds["version"] = cmd_version
-
- # we override "build_py" in both distutils and setuptools
- #
- # most invocation pathways end up running build_py:
- # distutils/build -> build_py
- # distutils/install -> distutils/build ->..
- # setuptools/bdist_wheel -> distutils/install ->..
- # setuptools/bdist_egg -> distutils/install_lib -> build_py
- # setuptools/install -> bdist_egg ->..
- # setuptools/develop -> ?
- # pip install:
- # copies source tree to a tempdir before running egg_info/etc
- # if .git isn't copied too, 'git describe' will fail
- # then does setup.py bdist_wheel, or sometimes setup.py install
- # setup.py egg_info -> ?
-
- # we override different "build_py" commands for both environments
- if "setuptools" in sys.modules:
- from setuptools.command.build_py import build_py as _build_py
- else:
- from distutils.command.build_py import build_py as _build_py
-
- class cmd_build_py(_build_py):
- def run(self):
- root = get_root()
- cfg = get_config_from_root(root)
- versions = get_versions()
- _build_py.run(self)
- # now locate _version.py in the new build/ directory and replace
- # it with an updated value
- if cfg.versionfile_build:
- target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build)
- print("UPDATING %s" % target_versionfile)
- write_to_version_file(target_versionfile, versions)
-
- cmds["build_py"] = cmd_build_py
-
- if "cx_Freeze" in sys.modules: # cx_freeze enabled?
- from cx_Freeze.dist import build_exe as _build_exe
-
- # nczeczulin reports that py2exe won't like the pep440-style string
- # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g.
- # setup(console=[{
- # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION
- # "product_version": versioneer.get_version(),
- # ...
-
- class cmd_build_exe(_build_exe):
- def run(self):
- root = get_root()
- cfg = get_config_from_root(root)
- versions = get_versions()
- target_versionfile = cfg.versionfile_source
- print("UPDATING %s" % target_versionfile)
- write_to_version_file(target_versionfile, versions)
-
- _build_exe.run(self)
- os.unlink(target_versionfile)
- with open(cfg.versionfile_source, "w") as f:
- LONG = LONG_VERSION_PY[cfg.VCS]
- f.write(
- LONG
- % {
- "DOLLAR": "$",
- "STYLE": cfg.style,
- "TAG_PREFIX": cfg.tag_prefix,
- "PARENTDIR_PREFIX": cfg.parentdir_prefix,
- "VERSIONFILE_SOURCE": cfg.versionfile_source,
- }
- )
-
- cmds["build_exe"] = cmd_build_exe
- del cmds["build_py"]
-
- if "py2exe" in sys.modules: # py2exe enabled?
- try:
- from py2exe.distutils_buildexe import py2exe as _py2exe # py3
- except ImportError:
- from py2exe.build_exe import py2exe as _py2exe # py2
-
- class cmd_py2exe(_py2exe):
- def run(self):
- root = get_root()
- cfg = get_config_from_root(root)
- versions = get_versions()
- target_versionfile = cfg.versionfile_source
- print("UPDATING %s" % target_versionfile)
- write_to_version_file(target_versionfile, versions)
-
- _py2exe.run(self)
- os.unlink(target_versionfile)
- with open(cfg.versionfile_source, "w") as f:
- LONG = LONG_VERSION_PY[cfg.VCS]
- f.write(
- LONG
- % {
- "DOLLAR": "$",
- "STYLE": cfg.style,
- "TAG_PREFIX": cfg.tag_prefix,
- "PARENTDIR_PREFIX": cfg.parentdir_prefix,
- "VERSIONFILE_SOURCE": cfg.versionfile_source,
- }
- )
-
- cmds["py2exe"] = cmd_py2exe
-
- # we override different "sdist" commands for both environments
- if "setuptools" in sys.modules:
- from setuptools.command.sdist import sdist as _sdist
- else:
- from distutils.command.sdist import sdist as _sdist
-
- class cmd_sdist(_sdist):
- def run(self):
- versions = get_versions()
- self._versioneer_generated_versions = versions
- # unless we update this, the command will keep using the old
- # version
- self.distribution.metadata.version = versions["version"]
- return _sdist.run(self)
-
- def make_release_tree(self, base_dir, files):
- root = get_root()
- cfg = get_config_from_root(root)
- _sdist.make_release_tree(self, base_dir, files)
- # now locate _version.py in the new base_dir directory
- # (remembering that it may be a hardlink) and replace it with an
- # updated value
- target_versionfile = os.path.join(base_dir, cfg.versionfile_source)
- print("UPDATING %s" % target_versionfile)
- write_to_version_file(
- target_versionfile, self._versioneer_generated_versions
- )
-
- cmds["sdist"] = cmd_sdist
-
- return cmds
-
-
-CONFIG_ERROR = """
-setup.cfg is missing the necessary Versioneer configuration. You need
-a section like:
-
- [versioneer]
- VCS = git
- style = pep440
- versionfile_source = src/myproject/_version.py
- versionfile_build = myproject/_version.py
- tag_prefix =
- parentdir_prefix = myproject-
-
-You will also need to edit your setup.py to use the results:
-
- import versioneer
- setup(version=versioneer.get_version(),
- cmdclass=versioneer.get_cmdclass(), ...)
-
-Please read the docstring in ./versioneer.py for configuration instructions,
-edit setup.cfg, and re-run the installer or 'python versioneer.py setup'.
-"""
-
-SAMPLE_CONFIG = """
-# See the docstring in versioneer.py for instructions. Note that you must
-# re-run 'versioneer.py setup' after changing this section, and commit the
-# resulting files.
-
-[versioneer]
-#VCS = git
-#style = pep440
-#versionfile_source =
-#versionfile_build =
-#tag_prefix =
-#parentdir_prefix =
-
-"""
-
-INIT_PY_SNIPPET = """
-from ._version import get_versions
-__version__ = get_versions()['version']
-del get_versions
-"""
-
-
-def do_setup():
- """Main VCS-independent setup function for installing Versioneer."""
- root = get_root()
- try:
- cfg = get_config_from_root(root)
- except (
- EnvironmentError,
- configparser.NoSectionError,
- configparser.NoOptionError,
- ) as e:
- if isinstance(e, (EnvironmentError, configparser.NoSectionError)):
- print("Adding sample versioneer config to setup.cfg", file=sys.stderr)
- with open(os.path.join(root, "setup.cfg"), "a") as f:
- f.write(SAMPLE_CONFIG)
- print(CONFIG_ERROR, file=sys.stderr)
- return 1
-
- print(" creating %s" % cfg.versionfile_source)
- with open(cfg.versionfile_source, "w") as f:
- LONG = LONG_VERSION_PY[cfg.VCS]
- f.write(
- LONG
- % {
- "DOLLAR": "$",
- "STYLE": cfg.style,
- "TAG_PREFIX": cfg.tag_prefix,
- "PARENTDIR_PREFIX": cfg.parentdir_prefix,
- "VERSIONFILE_SOURCE": cfg.versionfile_source,
- }
- )
-
- ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py")
- if os.path.exists(ipy):
- try:
- with open(ipy, "r") as f:
- old = f.read()
- except EnvironmentError:
- old = ""
- if INIT_PY_SNIPPET not in old:
- print(" appending to %s" % ipy)
- with open(ipy, "a") as f:
- f.write(INIT_PY_SNIPPET)
- else:
- print(" %s unmodified" % ipy)
- else:
- print(" %s doesn't exist, ok" % ipy)
- ipy = None
-
- # Make sure both the top-level "versioneer.py" and versionfile_source
- # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so
- # they'll be copied into source distributions. Pip won't be able to
- # install the package without this.
- manifest_in = os.path.join(root, "MANIFEST.in")
- simple_includes = set()
- try:
- with open(manifest_in, "r") as f:
- for line in f:
- if line.startswith("include "):
- for include in line.split()[1:]:
- simple_includes.add(include)
- except EnvironmentError:
- pass
- # That doesn't cover everything MANIFEST.in can do
- # (http://docs.python.org/2/distutils/sourcedist.html#commands), so
- # it might give some false negatives. Appending redundant 'include'
- # lines is safe, though.
- if "versioneer.py" not in simple_includes:
- print(" appending 'versioneer.py' to MANIFEST.in")
- with open(manifest_in, "a") as f:
- f.write("include versioneer.py\n")
- else:
- print(" 'versioneer.py' already in MANIFEST.in")
- if cfg.versionfile_source not in simple_includes:
- print(
- " appending versionfile_source ('%s') to MANIFEST.in"
- % cfg.versionfile_source
- )
- with open(manifest_in, "a") as f:
- f.write("include %s\n" % cfg.versionfile_source)
- else:
- print(" versionfile_source already in MANIFEST.in")
-
- # Make VCS-specific changes. For git, this means creating/changing
- # .gitattributes to mark _version.py for export-subst keyword
- # substitution.
- do_vcs_install(manifest_in, cfg.versionfile_source, ipy)
- return 0
-
-
-def scan_setup_py():
- """Validate the contents of setup.py against Versioneer's expectations."""
- found = set()
- setters = False
- errors = 0
- with open("setup.py", "r") as f:
- for line in f.readlines():
- if "import versioneer" in line:
- found.add("import")
- if "versioneer.get_cmdclass()" in line:
- found.add("cmdclass")
- if "versioneer.get_version()" in line:
- found.add("get_version")
- if "versioneer.VCS" in line:
- setters = True
- if "versioneer.versionfile_source" in line:
- setters = True
- if len(found) != 3:
- print("")
- print("Your setup.py appears to be missing some important items")
- print("(but I might be wrong). Please make sure it has something")
- print("roughly like the following:")
- print("")
- print(" import versioneer")
- print(" setup( version=versioneer.get_version(),")
- print(" cmdclass=versioneer.get_cmdclass(), ...)")
- print("")
- errors += 1
- if setters:
- print("You should remove lines like 'versioneer.VCS = ' and")
- print("'versioneer.versionfile_source = ' . This configuration")
- print("now lives in setup.cfg, and should be removed from setup.py")
- print("")
- errors += 1
- return errors
-
-
-if __name__ == "__main__":
- cmd = sys.argv[1]
- if cmd == "setup":
- errors = do_setup()
- errors += scan_setup_py()
- if errors:
- sys.exit(1)
Index: pandas-datareader-0.10.0/pandas_datareader/av/__init__.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/av/__init__.py
+++ pandas-datareader-0.10.0/pandas_datareader/av/__init__.py
@@ -70,18 +70,18 @@ class AlphaVantage(_BaseReader):
def _read_lines(self, out):
try:
df = pd.DataFrame.from_dict(out[self.data_key], orient="index")
- except KeyError:
+ except KeyError as exc:
if "Error Message" in out:
raise ValueError(
"The requested symbol {} could not be "
"retrieved. Check valid ticker"
".".format(self.symbols)
- )
+ ) from exc
else:
raise RemoteDataError(
" Their was an issue from the data vendor "
"side, here is their response: {}".format(out)
- )
+ ) from exc
df = df[sorted(df.columns)]
df.columns = [id[3:] for id in df.columns]
return df
Index: pandas-datareader-0.10.0/pandas_datareader/iex/__init__.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/iex/__init__.py
+++ pandas-datareader-0.10.0/pandas_datareader/iex/__init__.py
@@ -71,8 +71,8 @@ class IEX(_BaseReader):
"""
try:
content = json.loads(out.text)
- except Exception:
- raise TypeError("Failed to interpret response as JSON.")
+ except Exception as exc:
+ raise TypeError("Failed to interpret response as JSON.") from exc
for key, string in content.items():
e = "IEX Output error encountered: {}".format(string)
Index: pandas-datareader-0.10.0/pandas_datareader/iex/stats.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/iex/stats.py
+++ pandas-datareader-0.10.0/pandas_datareader/iex/stats.py
@@ -23,8 +23,9 @@ class DailySummaryReader(IEX):
import warnings
warnings.warn(
- "Daily statistics is not working due to issues with the " "IEX API",
+ "Daily statistics is not working due to issues with the IEX API",
UnstableAPIWarning,
+ stacklevel=2,
)
self.curr_date = start
super(DailySummaryReader, self).__init__(
Index: pandas-datareader-0.10.0/pandas_datareader/io/jsdmx.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/io/jsdmx.py
+++ pandas-datareader-0.10.0/pandas_datareader/io/jsdmx.py
@@ -31,9 +31,9 @@ def read_jsdmx(path_or_buf):
try:
import simplejson as json
- except ImportError:
+ except ImportError as exc:
if sys.version_info[:2] < (2, 7):
- raise ImportError("simplejson is required in python 2.6")
+ raise ImportError("simplejson is required in python 2.6") from exc
import json
if isinstance(jdata, dict):
Index: pandas-datareader-0.10.0/pandas_datareader/nasdaq_trader.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/nasdaq_trader.py
+++ pandas-datareader-0.10.0/pandas_datareader/nasdaq_trader.py
@@ -41,7 +41,9 @@ def _download_nasdaq_symbols(timeout):
ftp_session = FTP(_NASDAQ_FTP_SERVER, timeout=timeout)
ftp_session.login()
except all_errors as err:
- raise RemoteDataError("Error connecting to %r: %s" % (_NASDAQ_FTP_SERVER, err))
+ raise RemoteDataError(
+ "Error connecting to %r: %s" % (_NASDAQ_FTP_SERVER, err)
+ ) from err
lines = []
try:
@@ -49,7 +51,7 @@ def _download_nasdaq_symbols(timeout):
except all_errors as err:
raise RemoteDataError(
"Error downloading from %r: %s" % (_NASDAQ_FTP_SERVER, err)
- )
+ ) from err
finally:
ftp_session.close()
Index: pandas-datareader-0.10.0/pandas_datareader/tests/test_bankofcanada.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/test_bankofcanada.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/test_bankofcanada.py
@@ -42,7 +42,9 @@ class TestBankOfCanada(object):
date.today(),
)
- pairs = zip((1 / df)[symbol].tolist(), df_i[symbol_inverted].tolist())
+ pairs = zip(
+ (1 / df)[symbol].tolist(), df_i[symbol_inverted].tolist(), strict=True
+ )
assert all(a - b < 0.01 for a, b in pairs)
def test_bankofcanada_usd_count(self):
Index: pandas-datareader-0.10.0/pandas_datareader/tests/test_base.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/test_base.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/test_base.py
@@ -23,9 +23,9 @@ class TestBaseReader(object):
base._BaseReader([]).url
def test_invalid_format(self):
+ b = base._BaseReader([])
+ b._format = "IM_NOT_AN_IMPLEMENTED_TYPE"
with pytest.raises(NotImplementedError):
- b = base._BaseReader([])
- b._format = "IM_NOT_AN_IMPLEMENTED_TYPE"
b._read_one_data("a", None)
def test_default_start_date(self):
@@ -35,6 +35,6 @@ class TestBaseReader(object):
class TestDailyBaseReader(object):
def test_get_params(self):
+ b = base._DailyBaseReader()
with pytest.raises(NotImplementedError):
- b = base._DailyBaseReader()
b._get_params()
Index: pandas-datareader-0.10.0/pandas_datareader/tests/test_iex.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/test_iex.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/test_iex.py
@@ -31,15 +31,13 @@ class TestIEX(object):
df = get_last_iex("INVALID TICKER")
assert df.shape[0] == 0
- @pytest.mark.xfail(
- reason="IEX daily history API is returning 500 as of " "Jan 2018"
- )
+ @pytest.mark.xfail(reason="IEX daily history API is returning 500 as of Jan 2018")
def test_daily(self):
- with pytest.warns(UnstableAPIWarning):
+ with pytest.warns(UnstableAPIWarning, match="Daily statistics"):
df = get_dailysummary_iex(
start=datetime(2017, 5, 5), end=datetime(2017, 5, 6)
)
- assert df["routedVolume"].iloc[0] == 39974788
+ assert df["routedVolume"].iloc[0] == 39974788
def test_symbols(self):
df = get_iex_symbols()
Index: pandas-datareader-0.10.0/pandas_datareader/tests/test_iex_daily.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/test_iex_daily.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/test_iex_daily.py
@@ -25,17 +25,17 @@ class TestIEXDaily(object):
return datetime(2017, 5, 24)
def test_iex_bad_symbol(self):
- with pytest.raises(Exception):
+ with pytest.raises(Exception): # noqa: B017
web.DataReader("BADTICKER", "iex,", self.start, self.end)
def test_iex_bad_symbol_list(self):
- with pytest.raises(Exception):
+ with pytest.raises(Exception): # noqa: B017
web.DataReader(["AAPL", "BADTICKER"], "iex", self.start, self.end)
def test_daily_invalid_date(self):
start = datetime(2000, 1, 5)
end = datetime(2017, 5, 24)
- with pytest.raises(Exception):
+ with pytest.raises(Exception): # noqa: B017
web.DataReader(["AAPL", "TSLA"], "iex", start, end)
def test_single_symbol(self):
Index: pandas-datareader-0.10.0/pandas_datareader/tests/yahoo/test_yahoo.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/yahoo/test_yahoo.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/yahoo/test_yahoo.py
@@ -34,7 +34,7 @@ class TestYahoo(object):
start = datetime(2010, 1, 1)
end = datetime(2013, 1, 27)
- with pytest.raises(Exception):
+ with pytest.raises(Exception): # noqa: B017
web.DataReader("NON EXISTENT TICKER", "yahoo", start, end)
def test_get_quote_series(self):
Index: pandas-datareader-0.10.0/pandas_datareader/yahoo/fx.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/yahoo/fx.py
+++ pandas-datareader-0.10.0/pandas_datareader/yahoo/fx.py
@@ -5,7 +5,6 @@ import warnings
from pandas import DataFrame, Series, concat, to_datetime
from pandas_datareader._utils import RemoteDataError, SymbolWarning
-from pandas_datareader.compat import string_types
from pandas_datareader.yahoo.daily import YahooDailyReader
@@ -58,7 +57,7 @@ class YahooFXReader(YahooDailyReader):
"""Read data"""
try:
# If a single symbol, (e.g., 'GOOG')
- if isinstance(self.symbols, (string_types, int)):
+ if isinstance(self.symbols, (str, int)):
df = self._read_one_data(self.symbols)
# Or multiple symbols, (e.g., ['GOOG', 'AAPL', 'MSFT'])
@@ -103,7 +102,7 @@ class YahooFXReader(YahooDailyReader):
passed.append(sym)
except IOError:
msg = "Failed to read symbol: {0!r}, replacing with NaN."
- warnings.warn(msg.format(sym), SymbolWarning)
+ warnings.warn(msg.format(sym), SymbolWarning, stacklevel=2)
failed.append(sym)
if len(passed) == 0:
Index: pandas-datareader-0.10.0/pandas_datareader/bankofcanada.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/bankofcanada.py
+++ pandas-datareader-0.10.0/pandas_datareader/bankofcanada.py
@@ -1,7 +1,6 @@
from __future__ import unicode_literals
from pandas_datareader.base import _BaseReader
-from pandas_datareader.compat import string_types
class BankOfCanadaReader(_BaseReader):
@@ -16,7 +15,7 @@ class BankOfCanadaReader(_BaseReader):
@property
def url(self):
"""API URL"""
- if not isinstance(self.symbols, string_types):
+ if not isinstance(self.symbols, str):
raise ValueError("data name must be string")
return "{0}/{1}/csv".format(self._URL, self.symbols)
Index: pandas-datareader-0.10.0/pandas_datareader/enigma.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/enigma.py
+++ pandas-datareader-0.10.0/pandas_datareader/enigma.py
@@ -3,7 +3,7 @@ import time
import pandas as pd
-from pandas_datareader.base import _BaseReader, string_types
+from pandas_datareader.base import _BaseReader
from pandas_datareader.compat import StringIO
from pandas_datareader.exceptions import DEP_ERROR_MSG, ImmediateDeprecationError
@@ -71,7 +71,7 @@ class EnigmaReader(_BaseReader):
self._api_key = api_key
self._dataset_id = dataset_id
- if not isinstance(self._dataset_id, string_types):
+ if not isinstance(self._dataset_id, str):
raise ValueError(
"The Enigma dataset_id must be a string (ex: "
"'bedaf052-5fcd-4758-8d27-048ce8746c6a')"
Index: pandas-datareader-0.10.0/pandas_datareader/eurostat.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/eurostat.py
+++ pandas-datareader-0.10.0/pandas_datareader/eurostat.py
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
import pandas as pd
from pandas_datareader.base import _BaseReader
-from pandas_datareader.compat import string_types
from pandas_datareader.io.sdmx import _read_sdmx_dsd, read_sdmx
@@ -15,7 +14,7 @@ class EurostatReader(_BaseReader):
@property
def url(self):
"""API URL"""
- if not isinstance(self.symbols, string_types):
+ if not isinstance(self.symbols, str):
raise ValueError("data name must be string")
q = "{0}/data/{1}/?startperiod={2}&endperiod={3}"
@@ -24,7 +23,7 @@ class EurostatReader(_BaseReader):
@property
def dsd_url(self):
"""API DSD URL"""
- if not isinstance(self.symbols, string_types):
+ if not isinstance(self.symbols, str):
raise ValueError("data name must be string")
return "{0}/datastructure/ESTAT/DSD_{1}".format(self._URL, self.symbols)
Index: pandas-datareader-0.10.0/pandas_datareader/io/util.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/io/util.py
+++ pandas-datareader-0.10.0/pandas_datareader/io/util.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
import os
-from pandas_datareader.compat import get_filepath_or_buffer, string_types
+from pandas_datareader.compat import get_filepath_or_buffer
def _read_content(path_or_buf):
@@ -12,7 +12,7 @@ def _read_content(path_or_buf):
filepath_or_buffer = get_filepath_or_buffer(path_or_buf)[0]
- if isinstance(filepath_or_buffer, string_types):
+ if isinstance(filepath_or_buffer, str):
try:
exists = os.path.exists(filepath_or_buffer)
except (TypeError, ValueError):
Index: pandas-datareader-0.10.0/pandas_datareader/moex.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/moex.py
+++ pandas-datareader-0.10.0/pandas_datareader/moex.py
@@ -1,9 +1,10 @@
import datetime as dt
+from io import StringIO
import pandas as pd
from pandas_datareader.base import _DailyBaseReader
-from pandas_datareader.compat import StringIO, binary_type, concat, is_list_like
+from pandas_datareader.compat import is_list_like
class MoexReader(_DailyBaseReader):
@@ -108,7 +109,7 @@ class MoexReader(_DailyBaseReader):
"{} request returned no data; check URL for invalid "
"inputs: {}".format(service, self.__url_metadata)
)
- if isinstance(text, binary_type):
+ if isinstance(text, bytes):
text = text.decode("windows-1251")
header_str = "secid;boardid;"
@@ -200,7 +201,7 @@ class MoexReader(_DailyBaseReader):
"check URL or correct a date".format(self.__class__.__name__)
)
elif len(dfs) > 1:
- b = concat(dfs, axis=0, join="outer", sort=True)
+ b = pd.concat(dfs, axis=0, join="outer", sort=True)
else:
b = dfs[0]
return b
@@ -227,7 +228,7 @@ class MoexReader(_DailyBaseReader):
"{} request returned no data; check URL for invalid "
"inputs: {}".format(service, self.url)
)
- if isinstance(text, binary_type):
+ if isinstance(text, bytes):
text = text.decode("windows-1251")
return text
Index: pandas-datareader-0.10.0/pandas_datareader/naver.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/naver.py
+++ pandas-datareader-0.10.0/pandas_datareader/naver.py
@@ -3,7 +3,6 @@ from xml.etree import ElementTree
import numpy as np
from pandas import DataFrame, to_datetime
-from six import string_types
from pandas_datareader.base import _DailyBaseReader
@@ -32,7 +31,7 @@ class NaverDailyReader(_DailyBaseReader)
get_actions=False,
adjust_dividends=True,
):
- if not isinstance(symbols, string_types):
+ if not isinstance(symbols, str):
raise NotImplementedError("Bulk-fetching is not implemented")
super().__init__(
Index: pandas-datareader-0.10.0/pandas_datareader/oecd.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/oecd.py
+++ pandas-datareader-0.10.0/pandas_datareader/oecd.py
@@ -1,7 +1,6 @@
import pandas as pd
from pandas_datareader.base import _BaseReader
-from pandas_datareader.compat import string_types
from pandas_datareader.io import read_jsdmx
@@ -15,7 +14,7 @@ class OECDReader(_BaseReader):
"""API URL"""
url = "http://stats.oecd.org/SDMX-JSON/data"
- if not isinstance(self.symbols, string_types):
+ if not isinstance(self.symbols, str):
raise ValueError("data name must be string")
# API: https://data.oecd.org/api/sdmx-json-documentation/
Index: pandas-datareader-0.10.0/pandas_datareader/tests/test_stooq.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/test_stooq.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/test_stooq.py
@@ -26,6 +26,7 @@ def test_stooq_sp500():
assert f.shape[0] > 0
+@pytest.mark.xfail(reason="No longer works as of Otober 2023")
def test_stooq_clx19f():
f = get_data_stooq("CLX26.F", start="20200101", end="20200115")
assert f.shape[0] > 0
Index: pandas-datareader-0.10.0/pandas_datareader/tests/test_tsp.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/test_tsp.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/test_tsp.py
@@ -4,7 +4,7 @@ import pytest
from pandas_datareader import tsp as tsp
-pytestmark = pytest.mark.stable
+pytestmark = pytest.mark.skip(reason="TSP API has changed")
class TestTSPFunds(object):
Index: pandas-datareader-0.10.0/pandas_datareader/yahoo/actions.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/yahoo/actions.py
+++ pandas-datareader-0.10.0/pandas_datareader/yahoo/actions.py
@@ -1,6 +1,6 @@
+import pandas as pd
from pandas import DataFrame, MultiIndex
-from pandas_datareader.compat import concat
from pandas_datareader.yahoo.daily import YahooDailyReader
@@ -35,7 +35,7 @@ def _get_one_action(data):
dividends = DataFrame(data["Dividends"]).dropna()
dividends["action"] = "DIVIDEND"
dividends = dividends.rename(columns={"Dividends": "value"})
- actions = concat([actions, dividends], sort=True)
+ actions = pd.concat([actions, dividends], sort=True, axis=1)
actions = actions.sort_index(ascending=False)
if "Splits" in data.columns:
@@ -43,7 +43,7 @@ def _get_one_action(data):
splits = DataFrame(data["Splits"]).dropna()
splits["action"] = "SPLIT"
splits = splits.rename(columns={"Splits": "value"})
- actions = concat([actions, splits], sort=True)
+ actions = pd.concat([actions, splits], sort=True, axis=1)
actions = actions.sort_index(ascending=False)
return actions
Index: pandas-datareader-0.10.0/pandas_datareader/yahoo/quotes.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/yahoo/quotes.py
+++ pandas-datareader-0.10.0/pandas_datareader/yahoo/quotes.py
@@ -4,7 +4,6 @@ import json
from pandas import DataFrame
from pandas_datareader.base import _BaseReader
-from pandas_datareader.compat import string_types
from pandas_datareader.yahoo.headers import DEFAULT_HEADERS
_DEFAULT_PARAMS = {
@@ -45,7 +44,7 @@ class YahooQuotesReader(_BaseReader):
return "https://query1.finance.yahoo.com/v7/finance/quote"
def read(self):
- if isinstance(self.symbols, string_types):
+ if isinstance(self.symbols, str):
return self._read_one_data(self.url, self.params(self.symbols))
else:
data = OrderedDict()
Index: pandas-datareader-0.10.0/pandas_datareader/tests/test_econdb.py
===================================================================
--- pandas-datareader-0.10.0.orig/pandas_datareader/tests/test_econdb.py
+++ pandas-datareader-0.10.0/pandas_datareader/tests/test_econdb.py
@@ -11,14 +11,18 @@ pytestmark = pytest.mark.stable
class TestEcondb(object):
def test_infer_start_end_from_symbols(self):
df = web.DataReader(
- (
- "dataset=NAMQ_10_GDP&v=Geopolitical entity (reporting)"
- "&h=TIME&from=2010-02-01&to=2018-10-01&GEO=[AL,AT,BE,BA,"
- "BG,HR,CY,CZ,DK,EE,EA19,FI,FR,DE,EL,HU,IS,IE,IT,XK,LV,LT,"
- "LU,MT,ME,NL,MK,NO,PL,PT,RO,RS,SK,SI,ES,SE,CH,TR,UK]"
- "&NA_ITEM=[B1GQ]&S_ADJ=[SCA]&UNIT=[CLV10_MNAC]"
+ "&".join(
+ [
+ "dataset=RBI_BULLETIN",
+ "v=TIME",
+ "h=Indicator",
+ "from=2022-01-01",
+ "to=2022-07-01",
+ ]
),
"econdb",
+ start="2020-01-01",
+ end="2022-01-01",
)
assert df.index[0].year == 2010
assert df.index[-1].year == 2018
Index: pandas-datareader-0.10.0/setup.cfg
===================================================================
--- pandas-datareader-0.10.0.orig/setup.cfg
+++ /dev/null
@@ -1,48 +0,0 @@
-[versioneer]
-vcs = git
-style = pep440
-versionfile_source = pandas_datareader/_version.py
-versionfile_build = pandas_datareader/_version.py
-tag_prefix = v
-
-[isort]
-known_compat = pandas_datareader.compat.*
-sections = FUTURE,COMPAT,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
-known_first_party = pandas_datareader
-known_third_party = numpy,pandas,pytest,requests
-combine_as_imports = True
-force_sort_within_sections = True
-profile = black
-
-[tool:pytest]
-minversion = 5.0.1
-testpaths = pandas_datareader
-markers =
- stable: mark a test as applying to a stable reader
- requires_api_key: mark a test as requiring an API key
- alpha_vantage: mark a test of the AlphaVantage reader
- quandl: mark a test of the Quandl reader
-filterwarnings =
- ignore:`np.bool` is a deprecated alias:DeprecationWarning:pandas.core.indexes
- ignore:`np.object` is a deprecated alias:DeprecationWarning:pandas.core.indexes
- ignore:`np.float` is a deprecated alias:DeprecationWarning:pandas.core.indexes
- ignore:`np.complex` is a deprecated alias:DeprecationWarning:pandas.core.indexes
- ignore:`np.bool` is a deprecated alias:DeprecationWarning:pandas.core.internals.blocks
- ignore:`np.object` is a deprecated alias:DeprecationWarning:pandas.core.internals.blocks
- ignore:`np.object` is a deprecated alias:DeprecationWarning:pandas.core.internals.construction
- ignore:`np.object` is a deprecated alias:DeprecationWarning:pandas.io.parsers
- ignore:`np.object` is a deprecated alias:DeprecationWarning:pandas.core.dtypes.cast
- ignore:`np.float` is a deprecated alias:DeprecationWarning:pandas.core.internals.blocks
- ignore:`np.complex` is a deprecated alias:DeprecationWarning:pandas.core.internals.blocks
- ignore:Converting `np.inexact` or `np.floating` to a dtype:DeprecationWarning:pandas.core.indexes
-
-[flake8]
-ignore = E203, E266, E501, W503
-max-line-length = 80
-max-complexity = 18
-select = B,C,E,F,W,T4,B9
-
-[egg_info]
-tag_build =
-tag_date = 0
-
Index: pandas-datareader-0.10.0/setup.py
===================================================================
--- pandas-datareader-0.10.0.orig/setup.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-from setuptools import find_packages, setup
-
-import versioneer
-
-NAME = "pandas-datareader"
-
-
-def readme():
- with open("README.md") as f:
- return f.read()
-
-
-install_requires = []
-with open("./requirements.txt") as f:
- install_requires = f.read().splitlines()
-with open("./requirements-dev.txt") as f:
- tests_require = f.read().splitlines()
-
-setup(
- name=NAME,
- version=versioneer.get_version(),
- cmdclass=versioneer.get_cmdclass(),
- description="Data readers extracted from the pandas codebase,"
- "should be compatible with recent pandas versions",
- long_description=readme(),
- license="BSD License",
- author="The PyData Development Team",
- author_email="pydata@googlegroups.com",
- url="https://github.com/pydata/pandas-datareader",
- classifiers=[
- "Development Status :: 4 - Beta",
- "Environment :: Console",
- "Intended Audience :: Science/Research",
- "Operating System :: OS Independent",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.6",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Topic :: Scientific/Engineering",
- ],
- keywords="data",
- install_requires=install_requires,
- packages=find_packages(exclude=["contrib", "docs", "tests*"]),
- test_suite="tests",
- tests_require=tests_require,
- zip_safe=False,
- python_requires=">=3.6",
-)