From b9ba7085983bd287ef08963bffbb5acf964db041 Mon Sep 17 00:00:00 2001 From: Marc Garcia Date: Mon, 12 Nov 2018 15:33:47 +0000 Subject: [PATCH 01/25] DOC: Adding validation of the section order in docstrings (#23607) * Adding validation of the section order in docstrings * Updating allowed sections --- scripts/tests/test_validate_docstrings.py | 34 ++++++++++++++++++++ scripts/validate_docstrings.py | 38 +++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/scripts/tests/test_validate_docstrings.py b/scripts/tests/test_validate_docstrings.py index ccd5f56141a6a..c1bdab73c2671 100644 --- a/scripts/tests/test_validate_docstrings.py +++ b/scripts/tests/test_validate_docstrings.py @@ -350,6 +350,35 @@ def private_classes(self): This mentions NDFrame, which is not correct. """ + def unknown_section(self): + """ + This section has an unknown section title. + + Unknown Section + --------------- + This should raise an error in the validation. + """ + + def sections_in_wrong_order(self): + """ + This docstring has the sections in the wrong order. + + Parameters + ---------- + name : str + This section is in the right position. + + Examples + -------- + >>> print('So far Examples is good, as it goes before Parameters') + So far Examples is good, as it goes before Parameters + + See Also + -------- + function : This should generate an error, as See Also needs to go + before Examples. + """ + class BadSummaries(object): @@ -706,6 +735,11 @@ def test_bad_generic_functions(self, func): ('BadGenericDocStrings', 'private_classes', ("Private classes (NDFrame) should not be mentioned in public " 'docstrings',)), + ('BadGenericDocStrings', 'unknown_section', + ('Found unknown section "Unknown Section".',)), + ('BadGenericDocStrings', 'sections_in_wrong_order', + ('Wrong order of sections. "See Also" should be located before ' + '"Notes"',)), ('BadSeeAlso', 'desc_no_period', ('Missing period at end of description for See Also "Series.iloc"',)), ('BadSeeAlso', 'desc_first_letter_lowercase', diff --git a/scripts/validate_docstrings.py b/scripts/validate_docstrings.py index ed84e58049cae..7da77a1f60ad5 100755 --- a/scripts/validate_docstrings.py +++ b/scripts/validate_docstrings.py @@ -56,6 +56,9 @@ PRIVATE_CLASSES = ['NDFrame', 'IndexOpsMixin'] DIRECTIVES = ['versionadded', 'versionchanged', 'deprecated'] +ALLOWED_SECTIONS = ['Parameters', 'Attributes', 'Methods', 'Returns', 'Yields', + 'Other Parameters', 'Raises', 'Warns', 'See Also', 'Notes', + 'References', 'Examples'] ERROR_MSGS = { 'GL01': 'Docstring text (summary) should start in the line immediately ' 'after the opening quotes (not in the same line, or leaving a ' @@ -69,6 +72,10 @@ 'mentioned in public docstrings', 'GL05': 'Tabs found at the start of line "{line_with_tabs}", please use ' 'whitespace only', + 'GL06': 'Found unknown section "{section}". Allowed sections are: ' + '{allowed_sections}', + 'GL07': 'Wrong order of sections. "{wrong_section}" should be located ' + 'before "{goes_before}", the right order is: {sorted_sections}', 'SS01': 'No summary found (a short summary in a single line should be ' 'present at the beginning of the docstring)', 'SS02': 'Summary does not start with a capital letter', @@ -353,6 +360,18 @@ def double_blank_lines(self): prev = row.strip() return False + @property + def section_titles(self): + sections = [] + self.doc._doc.reset() + while not self.doc._doc.eof(): + content = self.doc._read_to_next_section() + if (len(content) > 1 + and len(content[0]) == len(content[1]) + and set(content[1]) == {'-'}): + sections.append(content[0]) + return sections + @property def summary(self): return ' '.join(self.doc['Summary']) @@ -580,6 +599,25 @@ def validate_one(func_name): if re.match("^ *\t", line): errs.append(error('GL05', line_with_tabs=line.lstrip())) + unseen_sections = list(ALLOWED_SECTIONS) + for section in doc.section_titles: + if section not in ALLOWED_SECTIONS: + errs.append(error('GL06', + section=section, + allowed_sections=', '.join(ALLOWED_SECTIONS))) + else: + if section in unseen_sections: + section_idx = unseen_sections.index(section) + unseen_sections = unseen_sections[section_idx + 1:] + else: + section_idx = ALLOWED_SECTIONS.index(section) + goes_before = ALLOWED_SECTIONS[section_idx + 1] + errs.append(error('GL07', + sorted_sections=' > '.join(ALLOWED_SECTIONS), + wrong_section=section, + goes_before=goes_before)) + break + if not doc.summary: errs.append(error('SS01')) else: From c7385239340050b7643c614f52fb513f19ac0ed4 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Mon, 12 Nov 2018 08:58:52 -0800 Subject: [PATCH 02/25] CLN: remove incorrect usages of com.AbstractMethodError (#23625) --- pandas/core/generic.py | 8 +++++--- pandas/core/groupby/generic.py | 5 +++-- pandas/core/groupby/groupby.py | 5 +++-- pandas/core/groupby/ops.py | 3 ++- pandas/core/indexes/datetimelike.py | 5 +++-- pandas/io/common.py | 7 +++---- pandas/io/html.py | 19 +++++++++---------- pandas/io/json/json.py | 8 ++++---- pandas/io/parquet.py | 6 +++--- pandas/io/parsers.py | 6 +++--- pandas/plotting/_core.py | 3 ++- pandas/tests/io/parser/test_parsers.py | 4 ++-- pandas/tests/test_resample.py | 5 ++--- pandas/tseries/offsets.py | 8 ++++---- 14 files changed, 48 insertions(+), 44 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 34f25c5634d5b..2c7f6ae8e3533 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -11,6 +11,8 @@ import pandas as pd from pandas._libs import properties, Timestamp, iNaT +from pandas.errors import AbstractMethodError + from pandas.core.dtypes.common import ( ensure_int64, ensure_object, @@ -200,7 +202,7 @@ def _constructor(self): """Used when a manipulation result has the same dimensions as the original. """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def __unicode__(self): # unicode representation based upon iterating over self @@ -221,7 +223,7 @@ def _constructor_sliced(self): """Used when a manipulation result has one lower dimension(s) as the original, such as DataFrame single columns slicing. """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) @property def _constructor_expanddim(self): @@ -2884,7 +2886,7 @@ def _iget_item_cache(self, item): return lower def _box_item_values(self, key, values): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _maybe_cache_changed(self, item, value): """The object has called back to us saying maybe it has changed. diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index 451f1199ac8e6..b0477c7d3a8ad 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -18,6 +18,7 @@ import pandas.compat as compat from pandas.compat import lzip, map from pandas.compat.numpy import _np_version_under1p13 +from pandas.errors import AbstractMethodError from pandas.util._decorators import Appender, Substitution from pandas.core.dtypes.cast import maybe_downcast_to_dtype @@ -240,7 +241,7 @@ def _aggregate_generic(self, func, *args, **kwargs): return self._wrap_generic_output(result, obj) def _wrap_aggregated_output(self, output, names=None): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _aggregate_item_by_item(self, func, *args, **kwargs): # only for axis==0 @@ -1659,4 +1660,4 @@ def _aggregate_item_by_item(self, func, *args, **kwargs): raise ValueError("axis value must be greater than 0") def _wrap_aggregated_output(self, output, names=None): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index ea7507799fa9a..12327e1cf148e 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -20,6 +20,7 @@ class providing the base-class of operations. import pandas.compat as compat from pandas.compat import callable, range, set_function_name, zip from pandas.compat.numpy import function as nv +from pandas.errors import AbstractMethodError from pandas.util._decorators import Appender, Substitution, cache_readonly from pandas.util._validators import validate_kwargs @@ -706,7 +707,7 @@ def _iterate_slices(self): yield self._selection_name, self._selected_obj def transform(self, func, *args, **kwargs): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _cumcount_array(self, ascending=True): """ @@ -861,7 +862,7 @@ def _python_agg_general(self, func, *args, **kwargs): return self._wrap_aggregated_output(output) def _wrap_applied_output(self, *args, **kwargs): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _concat_objects(self, keys, values, not_indexed_same=False): from pandas.core.reshape.concat import concat diff --git a/pandas/core/groupby/ops.py b/pandas/core/groupby/ops.py index 390334a89cbfe..125bd9a5e855d 100644 --- a/pandas/core/groupby/ops.py +++ b/pandas/core/groupby/ops.py @@ -13,6 +13,7 @@ from pandas._libs import NaT, groupby as libgroupby, iNaT, lib, reduction from pandas.compat import lzip, range, zip +from pandas.errors import AbstractMethodError from pandas.util._decorators import cache_readonly from pandas.core.dtypes.common import ( @@ -841,7 +842,7 @@ def _chop(self, sdata, slice_obj): return sdata.iloc[slice_obj] def apply(self, f): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) class SeriesSplitter(DataSplitter): diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 1d9d3b1d3bd16..4547f47314bad 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -10,6 +10,7 @@ from pandas._libs.tslibs.timestamps import RoundTo, round_nsint64 import pandas.compat as compat from pandas.compat.numpy import function as nv +from pandas.errors import AbstractMethodError from pandas.util._decorators import Appender, cache_readonly from pandas.core.dtypes.common import ( @@ -21,7 +22,7 @@ from pandas.core.dtypes.generic import ABCIndex, ABCIndexClass, ABCSeries from pandas.core.dtypes.missing import isna -from pandas.core import algorithms, common as com, ops +from pandas.core import algorithms, ops from pandas.core.arrays import PeriodArray from pandas.core.arrays.datetimelike import DatetimeLikeArrayMixin import pandas.core.indexes.base as ibase @@ -531,7 +532,7 @@ def argmax(self, axis=None, *args, **kwargs): @property def _formatter_func(self): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _format_attrs(self): """ diff --git a/pandas/io/common.py b/pandas/io/common.py index 155cf566b4c40..3a67238a66450 100644 --- a/pandas/io/common.py +++ b/pandas/io/common.py @@ -10,12 +10,11 @@ import pandas.compat as compat from pandas.compat import BytesIO, StringIO, string_types, text_type from pandas.errors import ( # noqa - DtypeWarning, EmptyDataError, ParserError, ParserWarning) + AbstractMethodError, DtypeWarning, EmptyDataError, ParserError, + ParserWarning) from pandas.core.dtypes.common import is_file_like, is_number -import pandas.core.common as com - from pandas.io.formats.printing import pprint_thing # gh-12665: Alias for now and remove later. @@ -67,7 +66,7 @@ def __iter__(self): return self def __next__(self): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) if not compat.PY3: diff --git a/pandas/io/html.py b/pandas/io/html.py index bcbb07c6dddfb..c967bdd29df1f 100644 --- a/pandas/io/html.py +++ b/pandas/io/html.py @@ -12,12 +12,11 @@ from pandas.compat import ( binary_type, iteritems, lmap, lrange, raise_with_traceback, string_types, u) -from pandas.errors import EmptyDataError +from pandas.errors import AbstractMethodError, EmptyDataError from pandas.core.dtypes.common import is_list_like from pandas import Series -import pandas.core.common as com from pandas.io.common import _is_url, _validate_header_arg, urlopen from pandas.io.formats.printing import pprint_thing @@ -256,7 +255,7 @@ def _text_getter(self, obj): text : str or unicode The text from an individual DOM node. """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _parse_td(self, obj): """Return the td elements from a row element. @@ -271,7 +270,7 @@ def _parse_td(self, obj): list of node-like These are the elements of each row, i.e., the columns. """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _parse_thead_tr(self, table): """ @@ -286,7 +285,7 @@ def _parse_thead_tr(self, table): list of node-like These are the row elements of a table. """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _parse_tbody_tr(self, table): """ @@ -305,7 +304,7 @@ def _parse_tbody_tr(self, table): list of node-like These are the row elements of a table. """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _parse_tfoot_tr(self, table): """ @@ -320,7 +319,7 @@ def _parse_tfoot_tr(self, table): list of node-like These are the row elements of a table. """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _parse_tables(self, doc, match, attrs): """ @@ -346,7 +345,7 @@ def _parse_tables(self, doc, match, attrs): list of node-like HTML elements to be parsed into raw data. """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _equals_tag(self, obj, tag): """ @@ -365,7 +364,7 @@ def _equals_tag(self, obj, tag): boolean Whether `obj`'s tag name is `tag` """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _build_doc(self): """ @@ -376,7 +375,7 @@ def _build_doc(self): node-like The DOM from which to parse the table element. """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _parse_thead_tbody_tfoot(self, table_html): """ diff --git a/pandas/io/json/json.py b/pandas/io/json/json.py index af7b390de213d..4453416a97f89 100644 --- a/pandas/io/json/json.py +++ b/pandas/io/json/json.py @@ -7,11 +7,11 @@ import pandas._libs.json as json from pandas._libs.tslibs import iNaT from pandas.compat import StringIO, long, to_str, u +from pandas.errors import AbstractMethodError from pandas.core.dtypes.common import is_period_dtype from pandas import DataFrame, MultiIndex, Series, compat, isna, to_datetime -import pandas.core.common as com from pandas.core.reshape.concat import concat from pandas.io.common import ( @@ -97,7 +97,7 @@ def __init__(self, obj, orient, date_format, double_precision, self._format_axes() def _format_axes(self): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def write(self): return self._write(self.obj, self.orient, self.double_precision, @@ -658,7 +658,7 @@ def _convert_axes(self): setattr(self.obj, axis, new_axis) def _try_convert_types(self): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _try_convert_data(self, name, data, use_dtypes=True, convert_dates=True): @@ -771,7 +771,7 @@ def _try_convert_to_date(self, data): return data, False def _try_convert_dates(self): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) class SeriesParser(Parser): diff --git a/pandas/io/parquet.py b/pandas/io/parquet.py index 3d72b1ec3a47f..aad59f9805a3b 100644 --- a/pandas/io/parquet.py +++ b/pandas/io/parquet.py @@ -4,9 +4,9 @@ from warnings import catch_warnings from pandas.compat import string_types +from pandas.errors import AbstractMethodError from pandas import DataFrame, get_option -import pandas.core.common as com from pandas.io.common import get_filepath_or_buffer, is_s3_url @@ -67,10 +67,10 @@ def validate_dataframe(df): raise ValueError("Index level names must be strings") def write(self, df, path, compression, **kwargs): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def read(self, path, columns=None, **kwargs): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) class PyArrowImpl(BaseImpl): diff --git a/pandas/io/parsers.py b/pandas/io/parsers.py index 12914c10e0655..9fd35effe1b07 100755 --- a/pandas/io/parsers.py +++ b/pandas/io/parsers.py @@ -20,7 +20,8 @@ import pandas.compat as compat from pandas.compat import ( PY3, StringIO, lrange, lzip, map, range, string_types, u, zip) -from pandas.errors import EmptyDataError, ParserError, ParserWarning +from pandas.errors import ( + AbstractMethodError, EmptyDataError, ParserError, ParserWarning) from pandas.util._decorators import Appender from pandas.core.dtypes.cast import astype_nansafe @@ -33,7 +34,6 @@ from pandas.core import algorithms from pandas.core.arrays import Categorical -import pandas.core.common as com from pandas.core.frame import DataFrame from pandas.core.index import ( Index, MultiIndex, RangeIndex, ensure_index_from_sequences) @@ -1050,7 +1050,7 @@ def _make_engine(self, engine='c'): self._engine = klass(self.f, **self.options) def _failover_to_python(self): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def read(self, nrows=None): nrows = _validate_integer('nrows', nrows) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 405c534e8528b..1c70ece434abb 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -12,6 +12,7 @@ from pandas.util._decorators import cache_readonly, Appender from pandas.compat import range, lrange, map, zip, string_types import pandas.compat as compat +from pandas.errors import AbstractMethodError import pandas.core.common as com from pandas.core.base import PandasObject @@ -373,7 +374,7 @@ def _compute_plot_data(self): self.data = numeric_data def _make_plot(self): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _add_table(self): if self.table is False: diff --git a/pandas/tests/io/parser/test_parsers.py b/pandas/tests/io/parser/test_parsers.py index 50d927176a7b4..21286e9b82323 100644 --- a/pandas/tests/io/parser/test_parsers.py +++ b/pandas/tests/io/parser/test_parsers.py @@ -6,9 +6,9 @@ from pandas._libs.tslib import Timestamp from pandas.compat import StringIO +from pandas.errors import AbstractMethodError from pandas import DataFrame, read_csv, read_table -import pandas.core.common as com import pandas.util.testing as tm from .c_parser_only import CParserTests @@ -46,7 +46,7 @@ def read_table(self, *args, **kwargs): raise NotImplementedError def float_precision_choices(self): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) @pytest.fixture(autouse=True) def setup_method(self, datapath): diff --git a/pandas/tests/test_resample.py b/pandas/tests/test_resample.py index 756385f0cfb56..7e0342e8b987a 100644 --- a/pandas/tests/test_resample.py +++ b/pandas/tests/test_resample.py @@ -24,12 +24,11 @@ notna, Timestamp, Timedelta) from pandas.compat import range, lrange, zip, OrderedDict -from pandas.errors import UnsupportedFunctionCall +from pandas.errors import AbstractMethodError, UnsupportedFunctionCall import pandas.tseries.offsets as offsets from pandas.tseries.offsets import Minute, BDay from pandas.core.groupby.groupby import DataError -import pandas.core.common as com from pandas.core.indexes.datetimes import date_range from pandas.core.indexes.period import period_range, PeriodIndex, Period @@ -599,7 +598,7 @@ def index(self, _index_start, _index_end, _index_freq): @pytest.fixture def _series_name(self): - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) @pytest.fixture def _static_values(self, index): diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 25c419e485db1..067a7d4622ca2 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -9,7 +9,6 @@ from pandas.core.dtypes.generic import ABCPeriod from pandas.core.tools.datetimes import to_datetime -import pandas.core.common as com # import after tools, dateutil check from dateutil.easter import easter @@ -29,6 +28,7 @@ roll_yearday, shift_month, BaseOffset) +from pandas.errors import AbstractMethodError __all__ = ['Day', 'BusinessDay', 'BDay', 'CustomBusinessDay', 'CDay', @@ -1097,7 +1097,7 @@ def apply(self, other): def _apply(self, n, other): """Handle specific apply logic for child classes""" - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) @apply_index_wraps def apply_index(self, i): @@ -1137,11 +1137,11 @@ def _get_roll(self, i, before_day_of_month, after_day_of_month): The roll array is based on the fact that i gets rolled back to the first day of the month. """ - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) def _apply_index_days(self, i, roll): """Apply the correct day for each date in i""" - raise com.AbstractMethodError(self) + raise AbstractMethodError(self) class SemiMonthEnd(SemiMonthOffset): From 2d4dd508fa7419a39201ad7befb287d0d72378ef Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 12 Nov 2018 11:02:51 -0600 Subject: [PATCH 03/25] DOC: avoid SparseArray.take error (#23637) Closes https://github.com/pandas-dev/pandas/issues/22215 SparseArray.take not accepting scalars is already in 0.24.0.txt --- doc/source/whatsnew/v0.18.1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.18.1.txt b/doc/source/whatsnew/v0.18.1.txt index 34921505a46bf..2445daebb580a 100644 --- a/doc/source/whatsnew/v0.18.1.txt +++ b/doc/source/whatsnew/v0.18.1.txt @@ -266,7 +266,7 @@ These changes conform sparse handling to return the correct types and work to ma ``SparseArray.take`` now returns a scalar for scalar input, ``SparseArray`` for others. Furthermore, it handles a negative indexer with the same rule as ``Index`` (:issue:`10560`, :issue:`12796`) -.. ipython:: python +.. code-block:: python s = pd.SparseArray([np.nan, np.nan, 1, 2, 3, np.nan, 4, 5, np.nan, 6]) s.take(0) From a08bf3de02bb1e53fb95df24ae060b63c2a44c96 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Mon, 12 Nov 2018 21:54:49 +0100 Subject: [PATCH 04/25] DOC: clean-up recent doc errors/warnings (#23636) --- doc/source/advanced.rst | 2 +- doc/source/ecosystem.rst | 2 +- doc/source/timeseries.rst | 4 +- doc/source/whatsnew/v0.24.0.txt | 114 +++++++++++++++------------- pandas/_libs/tslibs/timedeltas.pyx | 14 ++-- pandas/core/frame.py | 3 + pandas/core/generic.py | 14 ++-- pandas/core/indexes/datetimelike.py | 3 +- pandas/core/tools/timedeltas.py | 14 ++-- 9 files changed, 91 insertions(+), 79 deletions(-) diff --git a/doc/source/advanced.rst b/doc/source/advanced.rst index 24c117a534209..563c869eff54d 100644 --- a/doc/source/advanced.rst +++ b/doc/source/advanced.rst @@ -702,7 +702,7 @@ Index Types We have discussed ``MultiIndex`` in the previous sections pretty extensively. Documentation about ``DatetimeIndex`` and ``PeriodIndex`` are shown :ref:`here `, -and documentation about ``TimedeltaIndex`` is found :ref:`here `. +and documentation about ``TimedeltaIndex`` is found :ref:`here `. In the following sub-sections we will highlight some other index types. diff --git a/doc/source/ecosystem.rst b/doc/source/ecosystem.rst index edbd6629a617d..ad389bbe35b71 100644 --- a/doc/source/ecosystem.rst +++ b/doc/source/ecosystem.rst @@ -140,7 +140,7 @@ which are utilized by Jupyter Notebook for displaying (Note: HTML tables may or may not be compatible with non-HTML Jupyter output formats.) -See :ref:`Options and Settings ` and :ref:`options.available ` +See :ref:`Options and Settings ` and :ref:`options.available` for pandas ``display.`` settings. `quantopian/qgrid `__ diff --git a/doc/source/timeseries.rst b/doc/source/timeseries.rst index 42fd356bbe65a..cc377f45c4b8d 100644 --- a/doc/source/timeseries.rst +++ b/doc/source/timeseries.rst @@ -2372,7 +2372,8 @@ can be controlled by the ``nonexistent`` argument. The following options are ava * ``shift``: Shifts nonexistent times forward to the closest real time .. ipython:: python - dti = date_range(start='2015-03-29 01:30:00', periods=3, freq='H') + + dti = pd.date_range(start='2015-03-29 01:30:00', periods=3, freq='H') # 2:30 is a nonexistent time Localization of nonexistent times will raise an error by default. @@ -2385,6 +2386,7 @@ Localization of nonexistent times will raise an error by default. Transform nonexistent times to ``NaT`` or the closest real time forward in time. .. ipython:: python + dti dti.tz_localize('Europe/Warsaw', nonexistent='shift') dti.tz_localize('Europe/Warsaw', nonexistent='NaT') diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 20496c9fb3f31..3938fba4648b1 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -14,11 +14,10 @@ New features ~~~~~~~~~~~~ - :func:`merge` now directly allows merge between objects of type ``DataFrame`` and named ``Series``, without the need to convert the ``Series`` object into a ``DataFrame`` beforehand (:issue:`21220`) - ``ExcelWriter`` now accepts ``mode`` as a keyword argument, enabling append to existing workbooks when using the ``openpyxl`` engine (:issue:`3441`) -- ``FrozenList`` has gained the ``.union()`` and ``.difference()`` methods. This functionality greatly simplifies groupby's that rely on explicitly excluding certain columns. See :ref:`Splitting an object into groups -` for more information (:issue:`15475`, :issue:`15506`) +- ``FrozenList`` has gained the ``.union()`` and ``.difference()`` methods. This functionality greatly simplifies groupby's that rely on explicitly excluding certain columns. See :ref:`Splitting an object into groups ` for more information (:issue:`15475`, :issue:`15506`). - :func:`DataFrame.to_parquet` now accepts ``index`` as an argument, allowing -the user to override the engine's default behavior to include or omit the -dataframe's indexes from the resulting Parquet file. (:issue:`20768`) + the user to override the engine's default behavior to include or omit the + dataframe's indexes from the resulting Parquet file. (:issue:`20768`) - :meth:`DataFrame.corr` and :meth:`Series.corr` now accept a callable for generic calculation methods of correlation, e.g. histogram intersection (:issue:`22684`) @@ -227,7 +226,7 @@ Other Enhancements - :class:`Series` and :class:`DataFrame` now support :class:`Iterable` in constructor (:issue:`2193`) - :class:`DatetimeIndex` gained :attr:`DatetimeIndex.timetz` attribute. Returns local time with timezone information. (:issue:`21358`) - :meth:`round`, :meth:`ceil`, and meth:`floor` for :class:`DatetimeIndex` and :class:`Timestamp` now support an ``ambiguous`` argument for handling datetimes that are rounded to ambiguous times (:issue:`18946`) -- :meth:`round`, :meth:`ceil`, and meth:`floor` for :class:`DatetimeIndex` and :class:`Timestamp` now support a ``nonexistent`` argument for handling datetimes that are rounded to nonexistent times. See :ref:`timeseries.timezone_nonexsistent` (:issue:`22647`) +- :meth:`round`, :meth:`ceil`, and meth:`floor` for :class:`DatetimeIndex` and :class:`Timestamp` now support a ``nonexistent`` argument for handling datetimes that are rounded to nonexistent times. See :ref:`timeseries.timezone_nonexistent` (:issue:`22647`) - :class:`Resampler` now is iterable like :class:`GroupBy` (:issue:`15314`). - :meth:`Series.resample` and :meth:`DataFrame.resample` have gained the :meth:`Resampler.quantile` (:issue:`15023`). - :meth:`pandas.core.dtypes.is_list_like` has gained a keyword ``allow_sets`` which is ``True`` by default; if ``False``, @@ -237,7 +236,7 @@ Other Enhancements - Compatibility with Matplotlib 3.0 (:issue:`22790`). - Added :meth:`Interval.overlaps`, :meth:`IntervalArray.overlaps`, and :meth:`IntervalIndex.overlaps` for determining overlaps between interval-like objects (:issue:`21998`) - :func:`~DataFrame.to_parquet` now supports writing a ``DataFrame`` as a directory of parquet files partitioned by a subset of the columns when ``engine = 'pyarrow'`` (:issue:`23283`) -- :meth:`Timestamp.tz_localize`, :meth:`DatetimeIndex.tz_localize`, and :meth:`Series.tz_localize` have gained the ``nonexistent`` argument for alternative handling of nonexistent times. See :ref:`timeseries.timezone_nonexsistent` (:issue:`8917`) +- :meth:`Timestamp.tz_localize`, :meth:`DatetimeIndex.tz_localize`, and :meth:`Series.tz_localize` have gained the ``nonexistent`` argument for alternative handling of nonexistent times. See :ref:`timeseries.timezone_nonexistent` (:issue:`8917`) - :meth:`read_excel()` now accepts ``usecols`` as a list of column names or callable (:issue:`18273`) .. _whatsnew_0240.api_breaking: @@ -283,10 +282,10 @@ and replaced it with references to `pyarrow` (:issue:`21639` and :issue:`23053`) .. _whatsnew_0240.api_breaking.csv_line_terminator: `os.linesep` is used for ``line_terminator`` of ``DataFrame.to_csv`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :func:`DataFrame.to_csv` now uses :func:`os.linesep` rather than ``'\n'`` - for the default line terminator (:issue:`20353`). +for the default line terminator (:issue:`20353`). This change only affects when running on Windows, where ``'\r\n'`` was used for line terminator even when ``'\n'`` was passed in ``line_terminator``. @@ -294,26 +293,26 @@ Previous Behavior on Windows: .. code-block:: ipython -In [1]: data = pd.DataFrame({ - ...: "string_with_lf": ["a\nbc"], - ...: "string_with_crlf": ["a\r\nbc"] - ...: }) + In [1]: data = pd.DataFrame({ + ...: "string_with_lf": ["a\nbc"], + ...: "string_with_crlf": ["a\r\nbc"] + ...: }) -In [2]: # When passing file PATH to to_csv, line_terminator does not work, and csv is saved with '\r\n'. - ...: # Also, this converts all '\n's in the data to '\r\n'. - ...: data.to_csv("test.csv", index=False, line_terminator='\n') + In [2]: # When passing file PATH to to_csv, line_terminator does not work, and csv is saved with '\r\n'. + ...: # Also, this converts all '\n's in the data to '\r\n'. + ...: data.to_csv("test.csv", index=False, line_terminator='\n') -In [3]: with open("test.csv", mode='rb') as f: - ...: print(f.read()) -b'string_with_lf,string_with_crlf\r\n"a\r\nbc","a\r\r\nbc"\r\n' + In [3]: with open("test.csv", mode='rb') as f: + ...: print(f.read()) + b'string_with_lf,string_with_crlf\r\n"a\r\nbc","a\r\r\nbc"\r\n' -In [4]: # When passing file OBJECT with newline option to to_csv, line_terminator works. - ...: with open("test2.csv", mode='w', newline='\n') as f: - ...: data.to_csv(f, index=False, line_terminator='\n') + In [4]: # When passing file OBJECT with newline option to to_csv, line_terminator works. + ...: with open("test2.csv", mode='w', newline='\n') as f: + ...: data.to_csv(f, index=False, line_terminator='\n') -In [5]: with open("test2.csv", mode='rb') as f: - ...: print(f.read()) -b'string_with_lf,string_with_crlf\n"a\nbc","a\r\nbc"\n' + In [5]: with open("test2.csv", mode='rb') as f: + ...: print(f.read()) + b'string_with_lf,string_with_crlf\n"a\nbc","a\r\nbc"\n' New Behavior on Windows: @@ -322,54 +321,54 @@ New Behavior on Windows: - The value of ``line_terminator`` only affects the line terminator of CSV, so it does not change the value inside the data. -.. code-block:: ipython + .. code-block:: ipython -In [1]: data = pd.DataFrame({ - ...: "string_with_lf": ["a\nbc"], - ...: "string_with_crlf": ["a\r\nbc"] - ...: }) + In [1]: data = pd.DataFrame({ + ...: "string_with_lf": ["a\nbc"], + ...: "string_with_crlf": ["a\r\nbc"] + ...: }) -In [2]: data.to_csv("test.csv", index=False, line_terminator='\n') + In [2]: data.to_csv("test.csv", index=False, line_terminator='\n') -In [3]: with open("test.csv", mode='rb') as f: - ...: print(f.read()) -b'string_with_lf,string_with_crlf\n"a\nbc","a\r\nbc"\n' + In [3]: with open("test.csv", mode='rb') as f: + ...: print(f.read()) + b'string_with_lf,string_with_crlf\n"a\nbc","a\r\nbc"\n' - On Windows, the value of ``os.linesep`` is ``'\r\n'``, so if ``line_terminator`` is not set, ``'\r\n'`` is used for line terminator. - Again, it does not affect the value inside the data. -.. code-block:: ipython + .. code-block:: ipython -In [1]: data = pd.DataFrame({ - ...: "string_with_lf": ["a\nbc"], - ...: "string_with_crlf": ["a\r\nbc"] - ...: }) + In [1]: data = pd.DataFrame({ + ...: "string_with_lf": ["a\nbc"], + ...: "string_with_crlf": ["a\r\nbc"] + ...: }) -In [2]: data.to_csv("test.csv", index=False) + In [2]: data.to_csv("test.csv", index=False) -In [3]: with open("test.csv", mode='rb') as f: - ...: print(f.read()) -b'string_with_lf,string_with_crlf\r\n"a\nbc","a\r\nbc"\r\n' + In [3]: with open("test.csv", mode='rb') as f: + ...: print(f.read()) + b'string_with_lf,string_with_crlf\r\n"a\nbc","a\r\nbc"\r\n' - For files objects, specifying ``newline`` is not sufficient to set the line terminator. You must pass in the ``line_terminator`` explicitly, even in this case. -.. code-block:: ipython + .. code-block:: ipython -In [1]: data = pd.DataFrame({ - ...: "string_with_lf": ["a\nbc"], - ...: "string_with_crlf": ["a\r\nbc"] - ...: }) + In [1]: data = pd.DataFrame({ + ...: "string_with_lf": ["a\nbc"], + ...: "string_with_crlf": ["a\r\nbc"] + ...: }) -In [2]: with open("test2.csv", mode='w', newline='\n') as f: - ...: data.to_csv(f, index=False) + In [2]: with open("test2.csv", mode='w', newline='\n') as f: + ...: data.to_csv(f, index=False) -In [3]: with open("test2.csv", mode='rb') as f: - ...: print(f.read()) -b'string_with_lf,string_with_crlf\r\n"a\nbc","a\r\nbc"\r\n' + In [3]: with open("test2.csv", mode='rb') as f: + ...: print(f.read()) + b'string_with_lf,string_with_crlf\r\n"a\nbc","a\r\nbc"\r\n' .. _whatsnew_0240.api_breaking.interval_values: @@ -777,17 +776,20 @@ Previous Behavior: df = pd.DataFrame(arr) .. ipython:: python + # Comparison operations and arithmetic operations both broadcast. df == arr[[0], :] df + arr[[0], :] .. ipython:: python + # Comparison operations and arithmetic operations both broadcast. df == (1, 2) df + (1, 2) .. ipython:: python :okexcept: + # Comparison operations and arithmetic opeartions both raise ValueError. df == (1, 2, 3) df + (1, 2, 3) @@ -797,8 +799,9 @@ Previous Behavior: DataFrame Arithmetic Operations Broadcasting Changes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + :class:`DataFrame` arithmetic operations when operating with 2-dimensional -``np.ndarray`` objects now broadcast in the same way as ``np.ndarray``s +``np.ndarray`` objects now broadcast in the same way as ``np.ndarray`` broadcast. (:issue:`23000`) Previous Behavior: @@ -817,11 +820,13 @@ Previous Behavior: *Current Behavior*: .. ipython:: python + arr = np.arange(6).reshape(3, 2) df = pd.DataFrame(arr) df .. ipython:: python + df + arr[[0], :] # 1 row, 2 columns df + arr[:, [1]] # 1 column, 3 rows @@ -888,7 +893,7 @@ Current Behavior: ... OverflowError: Trying to coerce negative values to unsigned integers -.. _whatsnew_0240.api.crosstab_dtypes +.. _whatsnew_0240.api.crosstab_dtypes: Crosstab Preserves Dtypes ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1008,6 +1013,7 @@ Current Behavior: .. ipython:: python :okwarning: + per = pd.Period('2016Q1') per + 3 diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx index c09a8e5b395ee..ca8491726a5f7 100644 --- a/pandas/_libs/tslibs/timedeltas.pyx +++ b/pandas/_libs/tslibs/timedeltas.pyx @@ -1111,14 +1111,14 @@ class Timedelta(_Timedelta): Parameters ---------- value : Timedelta, timedelta, np.timedelta64, string, or integer - unit : string, {'Y', 'M', 'W', 'D', 'days', 'day', - 'hours', hour', 'hr', 'h', 'm', 'minute', 'min', 'minutes', - 'T', 'S', 'seconds', 'sec', 'second', 'ms', - 'milliseconds', 'millisecond', 'milli', 'millis', 'L', - 'us', 'microseconds', 'microsecond', 'micro', 'micros', - 'U', 'ns', 'nanoseconds', 'nano', 'nanos', 'nanosecond' - 'N'}, optional + unit : str, optional Denote the unit of the input, if input is an integer. Default 'ns'. + Possible values: + {'Y', 'M', 'W', 'D', 'days', 'day', 'hours', hour', 'hr', 'h', + 'm', 'minute', 'min', 'minutes', 'T', 'S', 'seconds', 'sec', 'second', + 'ms', 'milliseconds', 'millisecond', 'milli', 'millis', 'L', + 'us', 'microseconds', 'microsecond', 'micro', 'micros', 'U', + 'ns', 'nanoseconds', 'nano', 'nanos', 'nanosecond', 'N'} days, seconds, microseconds, milliseconds, minutes, hours, weeks : numeric, optional Values for construction in compat with datetime.timedelta. diff --git a/pandas/core/frame.py b/pandas/core/frame.py index f8d153327f135..f6f91ff5081f1 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -3409,6 +3409,7 @@ def assign(self, **kwargs): Berkeley 25.0 Where the value is a callable, evaluated on `df`: + >>> df.assign(temp_f=lambda x: x.temp_c * 9 / 5 + 32) temp_c temp_f Portland 17.0 62.6 @@ -3416,6 +3417,7 @@ def assign(self, **kwargs): Alternatively, the same behavior can be achieved by directly referencing an existing Series or sequence: + >>> df.assign(temp_f=df['temp_c'] * 9 / 5 + 32) temp_c temp_f Portland 17.0 62.6 @@ -3424,6 +3426,7 @@ def assign(self, **kwargs): In Python 3.6+, you can create multiple columns within the same assign where one of the columns depends on another one defined within the same assign: + >>> df.assign(temp_f=lambda x: x['temp_c'] * 9 / 5 + 32, ... temp_k=lambda x: (x['temp_f'] + 459.67) * 5 / 9) temp_c temp_f temp_k diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 2c7f6ae8e3533..2cb3df421325e 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -6508,16 +6508,16 @@ def interpolate(self, method='linear', axis=0, limit=None, inplace=False, def asof(self, where, subset=None): """ - Return the last row(s) without any `NaN`s before `where`. + Return the last row(s) without any NaNs before `where`. The last row (for each element in `where`, if list) without any - `NaN` is taken. - In case of a :class:`~pandas.DataFrame`, the last row without `NaN` + NaN is taken. + In case of a :class:`~pandas.DataFrame`, the last row without NaN considering only the subset of columns (if not `None`) .. versionadded:: 0.19.0 For DataFrame - If there is no good value, `NaN` is returned for a Series or + If there is no good value, NaN is returned for a Series or a Series of NaN values for a DataFrame Parameters @@ -6526,7 +6526,7 @@ def asof(self, where, subset=None): Date(s) before which the last row(s) are returned. subset : str or array-like of str, default `None` For DataFrame, if not `None`, only use these columns to - check for `NaN`s. + check for NaNs. Notes ----- @@ -6562,7 +6562,7 @@ def asof(self, where, subset=None): 2.0 For a sequence `where`, a Series is returned. The first value is - ``NaN``, because the first element of `where` is before the first + NaN, because the first element of `where` is before the first index value. >>> s.asof([5, 20]) @@ -6571,7 +6571,7 @@ def asof(self, where, subset=None): dtype: float64 Missing values are not considered. The following is ``2.0``, not - ``NaN``, even though ``NaN`` is at the index location for ``30``. + NaN, even though NaN is at the index location for ``30``. >>> s.asof(30) 2.0 diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 4547f47314bad..2ce6a0ec2a7a4 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -91,6 +91,8 @@ class TimelikeOps(object): :ref:`frequency aliases ` for a list of possible `freq` values. ambiguous : 'infer', bool-ndarray, 'NaT', default 'raise' + Only relevant for DatetimeIndex: + - 'infer' will attempt to infer fall dst-transition hours based on order - bool-ndarray where True signifies a DST time, False designates @@ -99,7 +101,6 @@ class TimelikeOps(object): - 'NaT' will return NaT where there are ambiguous times - 'raise' will raise an AmbiguousTimeError if there are ambiguous times - Only relevant for DatetimeIndex .. versionadded:: 0.24.0 nonexistent : 'shift', 'NaT', default 'raise' diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index fad136b3b5a45..58673c80c0c55 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -21,14 +21,14 @@ def to_timedelta(arg, unit='ns', box=True, errors='raise'): Parameters ---------- arg : string, timedelta, list, tuple, 1-d array, or Series - unit : string, {'Y', 'M', 'W', 'D', 'days', 'day', - 'hours', hour', 'hr', 'h', 'm', 'minute', 'min', 'minutes', - 'T', 'S', 'seconds', 'sec', 'second', 'ms', - 'milliseconds', 'millisecond', 'milli', 'millis', 'L', - 'us', 'microseconds', 'microsecond', 'micro', 'micros', - 'U', 'ns', 'nanoseconds', 'nano', 'nanos', 'nanosecond' - 'N'}, optional + unit : str, optional Denote the unit of the input, if input is an integer. Default 'ns'. + Possible values: + {'Y', 'M', 'W', 'D', 'days', 'day', 'hours', hour', 'hr', 'h', + 'm', 'minute', 'min', 'minutes', 'T', 'S', 'seconds', 'sec', 'second', + 'ms', 'milliseconds', 'millisecond', 'milli', 'millis', 'L', + 'us', 'microseconds', 'microsecond', 'micro', 'micros', 'U', + 'ns', 'nanoseconds', 'nano', 'nanos', 'nanosecond', 'N'} box : boolean, default True - If True returns a Timedelta/TimedeltaIndex of the results - if False returns a np.timedelta64 or ndarray of values of dtype From e75b2399afa606c858413c620e1b60f9a0a7972c Mon Sep 17 00:00:00 2001 From: Ksenia Gueletina Date: Mon, 12 Nov 2018 19:45:50 -0500 Subject: [PATCH 05/25] DOC: Fix name of the See Also section titles in docstrings (#23653) --- pandas/_libs/tslibs/period.pyx | 2 +- pandas/core/accessor.py | 2 +- pandas/core/arrays/categorical.py | 24 ++++++++++++------------ pandas/core/arrays/datetimes.py | 2 +- pandas/core/arrays/period.py | 2 +- pandas/core/base.py | 4 ++-- pandas/core/frame.py | 18 +++++++++--------- pandas/core/generic.py | 8 ++++---- pandas/core/groupby/generic.py | 4 ++-- pandas/core/groupby/groupby.py | 10 +++++----- pandas/core/indexes/base.py | 14 +++++++------- pandas/core/indexes/datetimelike.py | 8 ++++---- pandas/core/indexes/multi.py | 8 ++++---- pandas/core/indexes/numeric.py | 2 +- pandas/core/indexes/range.py | 2 +- pandas/core/ops.py | 8 ++++---- pandas/core/resample.py | 6 +++--- pandas/core/reshape/merge.py | 4 ++-- pandas/core/reshape/util.py | 2 +- pandas/core/series.py | 18 +++++++++--------- pandas/core/tools/datetimes.py | 2 +- pandas/core/tools/numeric.py | 2 +- pandas/core/tools/timedeltas.py | 2 +- pandas/core/window.py | 10 +++++----- pandas/io/json/table_schema.py | 2 +- pandas/io/sql.py | 10 +++++----- 26 files changed, 88 insertions(+), 88 deletions(-) diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index a284d8fb544e7..d651e75674239 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -1739,7 +1739,7 @@ cdef class _Period(object): ------- Timestamp - See also + See Also -------- Period.end_time : Return the end Timestamp. Period.dayofyear : Return the day of year. diff --git a/pandas/core/accessor.py b/pandas/core/accessor.py index 6694737737562..d178c66da2cc1 100644 --- a/pandas/core/accessor.py +++ b/pandas/core/accessor.py @@ -247,7 +247,7 @@ def plot(self): >>> ds.geo.plot() # plots data on a map -See also +See Also -------- %(others)s """ diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 4363f3ccb14e2..55f0040344bdc 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -313,7 +313,7 @@ class Categorical(ExtensionArray, PandasObject): See the `user guide `_ for more. - See also + See Also -------- pandas.api.types.CategoricalDtype : Type for categorical data CategoricalIndex : An Index with an underlying ``Categorical`` @@ -457,7 +457,7 @@ def categories(self): If the new categories do not validate as categories or if the number of new categories is unequal the number of old categories - See also + See Also -------- rename_categories reorder_categories @@ -823,7 +823,7 @@ def set_categories(self, new_categories, ordered=None, rename=False, ------- cat : Categorical with reordered categories or None if inplace. - See also + See Also -------- rename_categories reorder_categories @@ -894,7 +894,7 @@ def rename_categories(self, new_categories, inplace=False): With ``inplace=False``, the new categorical is returned. With ``inplace=True``, there is no return value. - See also + See Also -------- reorder_categories add_categories @@ -971,7 +971,7 @@ def reorder_categories(self, new_categories, ordered=None, inplace=False): ------- cat : Categorical with reordered categories or None if inplace. - See also + See Also -------- rename_categories add_categories @@ -1010,7 +1010,7 @@ def add_categories(self, new_categories, inplace=False): ------- cat : Categorical with new categories added or None if inplace. - See also + See Also -------- rename_categories reorder_categories @@ -1058,7 +1058,7 @@ def remove_categories(self, removals, inplace=False): ------- cat : Categorical with removed categories or None if inplace. - See also + See Also -------- rename_categories reorder_categories @@ -1100,7 +1100,7 @@ def remove_unused_categories(self, inplace=False): ------- cat : Categorical with unused categories dropped or None if inplace. - See also + See Also -------- rename_categories reorder_categories @@ -1364,7 +1364,7 @@ def isna(self): ------- a boolean array of whether my values are null - See also + See Also -------- isna : top-level isna isnull : alias of isna @@ -1387,7 +1387,7 @@ def notna(self): ------- a boolean array of whether my values are not null - See also + See Also -------- notna : top-level notna notnull : alias of notna @@ -1503,7 +1503,7 @@ def argsort(self, *args, **kwargs): ------- argsorted : numpy array - See also + See Also -------- numpy.ndarray.argsort @@ -2322,7 +2322,7 @@ def repeat(self, repeats, *args, **kwargs): """ Repeat elements of a Categorical. - See also + See Also -------- numpy.ndarray.repeat diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index a6f688fb0cf7a..926228f267049 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -874,7 +874,7 @@ def to_period(self, freq=None): PeriodIndex(['2017-01-01', '2017-01-02'], dtype='period[D]', freq='D') - See also + See Also -------- pandas.PeriodIndex: Immutable ndarray holding ordinal values pandas.DatetimeIndex.to_pydatetime: Return DatetimeIndex as object diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index b343d42ef3b7c..faba404faeb23 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -636,7 +636,7 @@ def repeat(self, repeats, *args, **kwargs): """ Repeat elements of a PeriodArray. - See also + See Also -------- numpy.ndarray.repeat """ diff --git a/pandas/core/base.py b/pandas/core/base.py index de368f52b6f00..5533054fcaf8a 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -820,7 +820,7 @@ def argmax(self, axis=None): """ return a ndarray of the maximum argument indexer - See also + See Also -------- numpy.ndarray.argmax """ @@ -863,7 +863,7 @@ def argmin(self, axis=None): """ return a ndarray of the minimum argument indexer - See also + See Also -------- numpy.ndarray.argmin """ diff --git a/pandas/core/frame.py b/pandas/core/frame.py index f6f91ff5081f1..cef811d710a39 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -346,7 +346,7 @@ class DataFrame(NDFrame): 1 4 5 6 2 7 8 9 - See also + See Also -------- DataFrame.from_records : constructor from tuples, also record arrays DataFrame.from_dict : from dicts of Series, arrays, or dicts @@ -1694,7 +1694,7 @@ def from_csv(cls, path, header=0, sep=',', index_col=0, parse_dates=True, datetime format based on the first datetime string. If the format can be inferred, there often will be a large parsing speed-up. - See also + See Also -------- pandas.read_csv @@ -5592,7 +5592,7 @@ def pivot(self, index=None, columns=None, values=None): ------- table : DataFrame - See also + See Also -------- DataFrame.pivot : pivot without aggregation that can handle non-numeric data @@ -5797,7 +5797,7 @@ def unstack(self, level=-1, fill_value=None): .. versionadded:: 0.18.0 - See also + See Also -------- DataFrame.pivot : Pivot a table based on column values. DataFrame.stack : Pivot a level of the column labels (inverse operation @@ -5867,7 +5867,7 @@ def unstack(self, level=-1, fill_value=None): col_level : int or string, optional If columns are a MultiIndex then use this level to melt. - See also + See Also -------- %(other)s pivot_table @@ -6108,7 +6108,7 @@ def _gotitem(self, 3 NaN dtype: float64 - See also + See Also -------- DataFrame.apply : Perform any type of operations. DataFrame.transform : Perform transformation type operations. @@ -6242,7 +6242,7 @@ def apply(self, func, axis=0, broadcast=None, raw=False, reduce=None, side-effects, as they will take effect twice for the first column/row. - See also + See Also -------- DataFrame.applymap: For elementwise operations DataFrame.aggregate: only perform aggregating type operations @@ -6351,7 +6351,7 @@ def applymap(self, func): DataFrame Transformed DataFrame. - See also + See Also -------- DataFrame.apply : Apply a function along input axis of DataFrame @@ -6434,7 +6434,7 @@ def append(self, other, ignore_index=False, those rows to a list and then concatenate the list with the original DataFrame all at once. - See also + See Also -------- pandas.concat : General function to concatenate DataFrame, Series or Panel objects diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 2cb3df421325e..80ea084ccd2be 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1850,7 +1850,7 @@ def empty(self): >>> df.dropna().empty True - See also + See Also -------- pandas.Series.dropna pandas.DataFrame.dropna @@ -5309,7 +5309,7 @@ def astype(self, dtype, copy=True, errors='raise', **kwargs): 1 2 dtype: int64 - See also + See Also -------- pandas.to_datetime : Convert argument to datetime. pandas.to_timedelta : Convert argument to timedelta. @@ -10090,7 +10090,7 @@ def _doc_parms(cls): """ _all_see_also = """\ -See also +See Also -------- pandas.Series.all : Return True if all elements are True pandas.DataFrame.any : Return True if one (or more) elements are True @@ -10117,7 +10117,7 @@ def _doc_parms(cls): ------- %(outname)s : %(name1)s or %(name2)s\n %(examples)s -See also +See Also -------- pandas.core.window.Expanding.%(accum_func_name)s : Similar functionality but ignores ``NaN`` values. diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index b0477c7d3a8ad..ee84f8cda07d0 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -734,7 +734,7 @@ def _selection_name(self): 1 1 2 2 3 4 - See also + See Also -------- pandas.Series.groupby.apply pandas.Series.groupby.transform @@ -1289,7 +1289,7 @@ class DataFrameGroupBy(NDFrameGroupBy): 1 1 2 0.590716 2 3 4 0.704907 - See also + See Also -------- pandas.DataFrame.groupby.apply pandas.DataFrame.groupby.transform diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index 12327e1cf148e..5041449b4d724 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -43,7 +43,7 @@ class providing the base-class of operations. _doc_template = """ - See also + See Also -------- pandas.Series.%(name)s pandas.DataFrame.%(name)s @@ -91,7 +91,7 @@ class providing the base-class of operations. -------- {examples} - See also + See Also -------- pipe : Apply function to the full GroupBy object instead of to each group. @@ -253,7 +253,7 @@ class providing the base-class of operations. ------- %(klass)s -See also +See Also -------- aggregate, transform @@ -1624,7 +1624,7 @@ def ngroup(self, ascending=True): 5 0 dtype: int64 - See also + See Also -------- .cumcount : Number the rows in each group. """ @@ -1680,7 +1680,7 @@ def cumcount(self, ascending=True): 5 0 dtype: int64 - See also + See Also -------- .ngroup : Number the groups themselves. """ diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 263de57d32f31..2b916f35a1173 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -876,7 +876,7 @@ def ravel(self, order='C'): """ return an ndarray of the flattened values of the underlying data - See also + See Also -------- numpy.ndarray.ravel """ @@ -2160,7 +2160,7 @@ def _concat_same_dtype(self, to_concat, name): If allow_fill=True and fill_value is not None, indices specified by -1 is regarded as NA. If Index doesn't hold NA, raise ValueError - See also + See Also -------- numpy.ndarray.take """ @@ -2305,7 +2305,7 @@ def notna(self): numpy.ndarray Boolean array to indicate which entries are not NA. - See also + See Also -------- Index.notnull : alias of notna Index.isna: inverse of notna @@ -2338,7 +2338,7 @@ def putmask(self, mask, value): """ return a new Index of the values set with the mask - See also + See Also -------- numpy.ndarray.putmask """ @@ -2695,7 +2695,7 @@ def argsort(self, *args, **kwargs): Integer indices that would sort the index if used as an indexer. - See also + See Also -------- numpy.argsort : Similar method for NumPy arrays. Index.sort_values : Return sorted copy of Index. @@ -3202,7 +3202,7 @@ def _get_level_values(self, level): values : Index Calling object, as there is only one level in the Index. - See also + See Also -------- MultiIndex.get_level_values : get values for a level of a MultiIndex @@ -3607,7 +3607,7 @@ def isin(self, values, level=None): is_contained : ndarray NumPy array of boolean values. - See also + See Also -------- Series.isin : Same for Series. DataFrame.isin : Same method for DataFrames. diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 2ce6a0ec2a7a4..3f9a60f6d5c51 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -436,7 +436,7 @@ def min(self, axis=None, *args, **kwargs): Return the minimum value of the Index or minimum along an axis. - See also + See Also -------- numpy.ndarray.min """ @@ -465,7 +465,7 @@ def argmin(self, axis=None, *args, **kwargs): See `numpy.ndarray.argmin` for more information on the `axis` parameter. - See also + See Also -------- numpy.ndarray.argmin """ @@ -486,7 +486,7 @@ def max(self, axis=None, *args, **kwargs): Return the maximum value of the Index or maximum along an axis. - See also + See Also -------- numpy.ndarray.max """ @@ -515,7 +515,7 @@ def argmax(self, axis=None, *args, **kwargs): See `numpy.ndarray.argmax` for more information on the `axis` parameter. - See also + See Also -------- numpy.ndarray.argmax """ diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 01304cce507f0..7a188dd7ba299 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -1176,7 +1176,7 @@ def to_frame(self, index=True, name=None): ------- DataFrame : a DataFrame containing the original MultiIndex data. - See also + See Also -------- DataFrame """ @@ -2204,7 +2204,7 @@ def get_loc(self, key, method=None): or a sequence of such. If you want to use those, use :meth:`MultiIndex.get_locs` instead. - See also + See Also -------- Index.get_loc : get_loc method for (single-level) index. MultiIndex.slice_locs : Get slice location given start label(s) and @@ -2530,7 +2530,7 @@ def get_locs(self, seq): >>> mi.get_locs([[True, False, True], slice('e', 'f')]) array([2], dtype=int64) - See also + See Also -------- MultiIndex.get_loc : Get location for a label or a tuple of labels. MultiIndex.slice_locs : Get slice location given start label(s) and @@ -2657,7 +2657,7 @@ def equals(self, other): Determines if two MultiIndex objects have the same labeling information (the levels themselves do not necessarily have to be the same) - See also + See Also -------- equal_levels """ diff --git a/pandas/core/indexes/numeric.py b/pandas/core/indexes/numeric.py index 795ffeefa1794..bdd0bf40507f4 100644 --- a/pandas/core/indexes/numeric.py +++ b/pandas/core/indexes/numeric.py @@ -155,7 +155,7 @@ def insert(self, loc, item): ----- An Index instance can **only** contain hashable objects. - See also + See Also -------- Index : The base pandas Index type """ diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index e4c177a08462e..e689eb4a7d84a 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -305,7 +305,7 @@ def argsort(self, *args, **kwargs): ------- argsorted : numpy array - See also + See Also -------- numpy.ndarray.argsort """ diff --git a/pandas/core/ops.py b/pandas/core/ops.py index fbfdfb9c01237..1f422a6098fa0 100644 --- a/pandas/core/ops.py +++ b/pandas/core/ops.py @@ -88,7 +88,7 @@ def _maybe_match_name(a, b): ------- name : str or None - See also + See Also -------- pandas.core.common.consensus_name_attr """ @@ -609,7 +609,7 @@ def _get_op_name(op, special): e NaN dtype: float64 -See also +See Also -------- Series.{reverse} """ @@ -673,7 +673,7 @@ def _get_op_name(op, special): -------- {df_examples} -See also +See Also -------- DataFrame.{reverse} """ @@ -692,7 +692,7 @@ def _get_op_name(op, special): ------- Panel -See also +See Also -------- Panel.{reverse} """ diff --git a/pandas/core/resample.py b/pandas/core/resample.py index 36476a8ecb657..0a275c7a3575b 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -239,7 +239,7 @@ def pipe(self, func, *args, **kwargs): 2013-01-01 00:00:02 7 4.949747 2013-01-01 00:00:04 5 NaN - See also + See Also -------- pandas.DataFrame.groupby.aggregate pandas.DataFrame.resample.transform @@ -983,7 +983,7 @@ def _upsample(self, method, limit=None, fill_value=None): fill_value : scalar, default None Value to use for missing values - See also + See Also -------- .fillna @@ -1113,7 +1113,7 @@ def _upsample(self, method, limit=None, fill_value=None): fill_value : scalar, default None Value to use for missing values - See also + See Also -------- .fillna diff --git a/pandas/core/reshape/merge.py b/pandas/core/reshape/merge.py index e09cf0a527ff9..3d6f55c907269 100644 --- a/pandas/core/reshape/merge.py +++ b/pandas/core/reshape/merge.py @@ -199,7 +199,7 @@ def merge_ordered(left, right, on=None, The output type will the be same as 'left', if it is a subclass of DataFrame. - See also + See Also -------- merge merge_asof @@ -447,7 +447,7 @@ def merge_asof(left, right, on=None, 3 2016-05-25 13:30:00.048 GOOG 720.92 100 NaN NaN 4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN - See also + See Also -------- merge merge_ordered diff --git a/pandas/core/reshape/util.py b/pandas/core/reshape/util.py index 07f7272398777..7f43a0e9719b8 100644 --- a/pandas/core/reshape/util.py +++ b/pandas/core/reshape/util.py @@ -26,7 +26,7 @@ def cartesian_product(X): [array(['A', 'A', 'B', 'B', 'C', 'C'], dtype='|S1'), array([1, 2, 1, 2, 1, 2])] - See also + See Also -------- itertools.product : Cartesian product of input iterables. Equivalent to nested for-loops. diff --git a/pandas/core/series.py b/pandas/core/series.py index 20e4720a3bde7..6617bf8500a1c 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -475,7 +475,7 @@ def ravel(self, order='C'): """ Return the flattened underlying data as an ndarray - See also + See Also -------- numpy.ndarray.ravel """ @@ -487,7 +487,7 @@ def compress(self, condition, *args, **kwargs): .. deprecated:: 0.24.0 - See also + See Also -------- numpy.ndarray.compress """ @@ -538,7 +538,7 @@ def put(self, *args, **kwargs): Applies the `put` method to its `values` attribute if it has one. - See also + See Also -------- numpy.ndarray.put """ @@ -992,7 +992,7 @@ def repeat(self, repeats, *args, **kwargs): Repeat elements of an Series. Refer to `numpy.ndarray.repeat` for more information about the `repeats` argument. - See also + See Also -------- numpy.ndarray.repeat """ @@ -2181,7 +2181,7 @@ def append(self, to_append, ignore_index=False, verify_integrity=False): list and then concatenate the list with the original Series all at once. - See also + See Also -------- pandas.concat : General function to concatenate DataFrame, Series or Panel objects @@ -2784,7 +2784,7 @@ def argsort(self, axis=0, kind='quicksort', order=None): ------- argsorted : Series, with -1 indicated where nan values are present - See also + See Also -------- numpy.ndarray.argsort """ @@ -3198,7 +3198,7 @@ def _gotitem(self, key, ndim, subset=None): max 4 dtype: int64 - See also + See Also -------- pandas.Series.apply : Invoke function on a Series. pandas.Series.transform : Transform function producing @@ -3263,7 +3263,7 @@ def apply(self, func, convert_dtype=True, args=(), **kwds): ------- y : Series or DataFrame if func returns a Series - See also + See Also -------- Series.map: For element-wise operations Series.agg: only perform aggregating type operations @@ -3891,7 +3891,7 @@ def from_csv(cls, path, sep=',', parse_dates=True, header=None, datetime format based on the first datetime string. If the format can be inferred, there often will be a large parsing speed-up. - See also + See Also -------- pandas.read_csv diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index dcba51d26980f..0eb2ffeab28f1 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -543,7 +543,7 @@ def to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, 1 1960-01-03 2 1960-01-04 - See also + See Also -------- pandas.DataFrame.astype : Cast argument to a specified dtype. pandas.to_timedelta : Convert argument to timedelta. diff --git a/pandas/core/tools/numeric.py b/pandas/core/tools/numeric.py index 4bb5c223d1bcc..12699927141cb 100644 --- a/pandas/core/tools/numeric.py +++ b/pandas/core/tools/numeric.py @@ -88,7 +88,7 @@ def to_numeric(arg, errors='raise', downcast=None): 3 -3.0 dtype: float64 - See also + See Also -------- pandas.DataFrame.astype : Cast argument to a specified dtype. pandas.to_datetime : Convert argument to datetime. diff --git a/pandas/core/tools/timedeltas.py b/pandas/core/tools/timedeltas.py index 58673c80c0c55..db93820c6942f 100644 --- a/pandas/core/tools/timedeltas.py +++ b/pandas/core/tools/timedeltas.py @@ -68,7 +68,7 @@ def to_timedelta(arg, unit='ns', box=True, errors='raise'): TimedeltaIndex(['0 days', '1 days', '2 days', '3 days', '4 days'], dtype='timedelta64[ns]', freq=None) - See also + See Also -------- pandas.DataFrame.astype : Cast argument to a specified dtype. pandas.to_datetime : Convert argument to datetime. diff --git a/pandas/core/window.py b/pandas/core/window.py index be28a3bcccec6..b250851a18f4d 100644 --- a/pandas/core/window.py +++ b/pandas/core/window.py @@ -50,7 +50,7 @@ ------- same type as input -See also +See Also -------- pandas.Series.%(name)s pandas.DataFrame.%(name)s @@ -733,7 +733,7 @@ def f(arg, *args, **kwargs): 8 -0.096361 0.818139 0.472290 9 0.070889 0.134399 -0.031308 - See also + See Also -------- pandas.DataFrame.rolling.aggregate pandas.DataFrame.aggregate @@ -1640,7 +1640,7 @@ def _validate_freq(self): 8 -0.289082 -1.647453 9 0.212668 -1.647453 - See also + See Also -------- pandas.Series.rolling pandas.DataFrame.rolling @@ -1916,7 +1916,7 @@ def _get_window(self, other=None): 8 0.067236 0.948257 0.163353 9 -0.286980 0.618493 -0.694496 - See also + See Also -------- pandas.DataFrame.expanding.aggregate pandas.DataFrame.rolling.aggregate @@ -2219,7 +2219,7 @@ def _constructor(self): 8 0.067236 0.948257 0.163353 9 -0.286980 0.618493 -0.694496 - See also + See Also -------- pandas.DataFrame.rolling.aggregate diff --git a/pandas/io/json/table_schema.py b/pandas/io/json/table_schema.py index 3b4ebb638412e..5cbecaf143295 100644 --- a/pandas/io/json/table_schema.py +++ b/pandas/io/json/table_schema.py @@ -290,7 +290,7 @@ def parse_table_schema(json, precise_float): :class:`Index` name of 'index' and :class:`MultiIndex` names starting with 'level_' are not supported. - See also + See Also -------- build_table_schema : inverse function pandas.read_json diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 2f411a956dfb8..db405390431c9 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -222,7 +222,7 @@ def read_sql_table(table_name, con, schema=None, index_col=None, ----- Any datetime values with time zone information will be converted to UTC. - See also + See Also -------- read_sql_query : Read SQL query into a DataFrame. read_sql @@ -302,7 +302,7 @@ def read_sql_query(sql, con, index_col=None, coerce_float=True, params=None, Any datetime values with time zone information parsed via the `parse_dates` parameter will be converted to UTC. - See also + See Also -------- read_sql_table : Read SQL database table into a DataFrame. read_sql @@ -366,7 +366,7 @@ def read_sql(sql, con, index_col=None, coerce_float=True, params=None, ------- DataFrame - See also + See Also -------- read_sql_table : Read SQL database table into a DataFrame. read_sql_query : Read SQL query into a DataFrame. @@ -1002,7 +1002,7 @@ def read_table(self, table_name, index_col=None, coerce_float=True, ------- DataFrame - See also + See Also -------- pandas.read_sql_table SQLDatabase.read_query @@ -1063,7 +1063,7 @@ def read_query(self, sql, index_col=None, coerce_float=True, ------- DataFrame - See also + See Also -------- read_sql_table : Read SQL database table into a DataFrame read_sql From 20bdb3e4019afe2037b26524a447ac8913d6e325 Mon Sep 17 00:00:00 2001 From: Benoit Paquet Date: Mon, 12 Nov 2018 21:11:20 -0500 Subject: [PATCH 06/25] CI: Allow to compile docs with ipython 7.11 #22990 (#23655) --- ci/deps/travis-36-doc.yaml | 2 +- doc/source/conf.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/deps/travis-36-doc.yaml b/ci/deps/travis-36-doc.yaml index ce095b887f189..6bf8cb38e0b7c 100644 --- a/ci/deps/travis-36-doc.yaml +++ b/ci/deps/travis-36-doc.yaml @@ -11,7 +11,7 @@ dependencies: - html5lib - hypothesis>=3.58.0 - ipykernel - - ipython==6.5.0 + - ipython - ipywidgets - lxml - matplotlib diff --git a/doc/source/conf.py b/doc/source/conf.py index b0501eaf54dc2..3b0b51dd0d648 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -388,6 +388,7 @@ category=FutureWarning) +ipython_warning_is_error = False ipython_exec_lines = [ 'import numpy as np', 'import pandas as pd', From 2e1ce1a069537b1cef47ef698d1b029bc5f50cc0 Mon Sep 17 00:00:00 2001 From: Jeremy Schendel Date: Tue, 13 Nov 2018 06:48:57 -0700 Subject: [PATCH 07/25] TST: IntervalTree.get_loc_interval should return platform int (#23660) --- pandas/_libs/intervaltree.pxi.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/intervaltree.pxi.in b/pandas/_libs/intervaltree.pxi.in index aa53f5086b894..7be3bdbc1048a 100644 --- a/pandas/_libs/intervaltree.pxi.in +++ b/pandas/_libs/intervaltree.pxi.in @@ -116,7 +116,7 @@ cdef class IntervalTree(IntervalMixin): enclosing = self.get_loc(0.5 * (key_left + key_right)) combined = np.concatenate([left_overlap, right_overlap, enclosing]) uniques = pd.unique(combined) - return uniques + return uniques.astype('intp') def get_indexer(self, scalar_t[:] target): """Return the positions corresponding to unique intervals that overlap From 71cd230f3ce3e29760b31dfcfa391cd2c4371842 Mon Sep 17 00:00:00 2001 From: gfyoung Date: Tue, 13 Nov 2018 05:50:45 -0800 Subject: [PATCH 08/25] CLN: Move to_excel to generic.py (#23656) --- pandas/core/frame.py | 18 ------------------ pandas/core/generic.py | 34 +++++++++++++++++++++++++++------- pandas/core/series.py | 13 ------------- 3 files changed, 27 insertions(+), 38 deletions(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index cef811d710a39..3a8ad3f98f8e0 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1829,24 +1829,6 @@ def to_panel(self): return self._constructor_expanddim(new_mgr) - @Appender(_shared_docs['to_excel'] % _shared_doc_kwargs) - def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='', - float_format=None, columns=None, header=True, index=True, - index_label=None, startrow=0, startcol=0, engine=None, - merge_cells=True, encoding=None, inf_rep='inf', verbose=True, - freeze_panes=None): - - from pandas.io.formats.excel import ExcelFormatter - formatter = ExcelFormatter(self, na_rep=na_rep, cols=columns, - header=header, - float_format=float_format, index=index, - index_label=index_label, - merge_cells=merge_cells, - inf_rep=inf_rep) - formatter.write(excel_writer, sheet_name=sheet_name, startrow=startrow, - startcol=startcol, freeze_panes=freeze_panes, - engine=engine) - @deprecate_kwarg(old_arg_name='encoding', new_arg_name=None) def to_stata(self, fname, convert_dates=None, write_index=True, encoding="latin-1", byteorder=None, time_stamp=None, diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 80ea084ccd2be..d5cc56d9f881d 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1977,16 +1977,17 @@ def _repr_latex_(self): # I/O Methods _shared_docs['to_excel'] = """ - Write %(klass)s to an excel sheet. + Write %(klass)s to an Excel sheet. - To write a single %(klass)s to an excel .xlsx file it is only necessary to + To write a single %(klass)s to an Excel .xlsx file it is only necessary to specify a target file name. To write to multiple sheets it is necessary to create an `ExcelWriter` object with a target file name, and specify a sheet - in the file to write to. Multiple sheets may be written to by - specifying unique `sheet_name`. With all data written to the file it is - necessary to save the changes. Note that creating an ExcelWriter object - with a file name that already exists will result in the contents of the - existing file being erased. + in the file to write to. + + Multiple sheets may be written to by specifying unique `sheet_name`. + With all data written to the file it is necessary to save the changes. + Note that creating an `ExcelWriter` object with a file name that already + exists will result in the contents of the existing file being erased. Parameters ---------- @@ -9951,6 +9952,25 @@ def to_csv(self, path_or_buf=None, sep=",", na_rep='', float_format=None, if path_or_buf is None: return formatter.path_or_buf.getvalue() + @Appender(_shared_docs["to_excel"] % dict(klass="object")) + def to_excel(self, excel_writer, sheet_name="Sheet1", na_rep="", + float_format=None, columns=None, header=True, index=True, + index_label=None, startrow=0, startcol=0, engine=None, + merge_cells=True, encoding=None, inf_rep="inf", verbose=True, + freeze_panes=None): + df = self if isinstance(self, ABCDataFrame) else self.to_frame() + + from pandas.io.formats.excel import ExcelFormatter + formatter = ExcelFormatter(df, na_rep=na_rep, cols=columns, + header=header, + float_format=float_format, index=index, + index_label=index_label, + merge_cells=merge_cells, + inf_rep=inf_rep) + formatter.write(excel_writer, sheet_name=sheet_name, startrow=startrow, + startcol=startcol, freeze_panes=freeze_panes, + engine=engine) + def _doc_parms(cls): """Return a tuple of the doc parms.""" diff --git a/pandas/core/series.py b/pandas/core/series.py index 6617bf8500a1c..9a3873a41a2da 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -3970,19 +3970,6 @@ def to_csv(self, *args, **kwargs): kwargs["header"] = False # Backwards compatibility. return self.to_frame().to_csv(**kwargs) - @Appender(generic._shared_docs['to_excel'] % _shared_doc_kwargs) - def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='', - float_format=None, columns=None, header=True, index=True, - index_label=None, startrow=0, startcol=0, engine=None, - merge_cells=True, encoding=None, inf_rep='inf', verbose=True): - df = self.to_frame() - df.to_excel(excel_writer=excel_writer, sheet_name=sheet_name, - na_rep=na_rep, float_format=float_format, columns=columns, - header=header, index=index, index_label=index_label, - startrow=startrow, startcol=startcol, engine=engine, - merge_cells=merge_cells, encoding=encoding, - inf_rep=inf_rep, verbose=verbose) - @Appender(generic._shared_docs['isna'] % _shared_doc_kwargs) def isna(self): return super(Series, self).isna() From 454ecfc61891be610fbb586a7d946eb61b87f32d Mon Sep 17 00:00:00 2001 From: William Ayd Date: Tue, 13 Nov 2018 08:57:18 -0800 Subject: [PATCH 09/25] Add to_flat_index method to MultiIndex (#22866) --- doc/source/api.rst | 1 + doc/source/whatsnew/v0.24.0.txt | 1 + pandas/core/indexes/base.py | 20 +++++++++++++ pandas/core/indexes/multi.py | 29 +++++++++++++++++++ pandas/tests/indexes/multi/test_conversion.py | 8 +++++ pandas/tests/indexes/test_base.py | 8 +++++ 6 files changed, 67 insertions(+) diff --git a/doc/source/api.rst b/doc/source/api.rst index 665649aead33c..81bb420c47a99 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1724,6 +1724,7 @@ MultiIndex Components MultiIndex.set_levels MultiIndex.set_labels MultiIndex.to_hierarchical + MultiIndex.to_flat_index MultiIndex.to_frame MultiIndex.is_lexsorted MultiIndex.sortlevel diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 3938fba4648b1..46abc16f1b96a 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -238,6 +238,7 @@ Other Enhancements - :func:`~DataFrame.to_parquet` now supports writing a ``DataFrame`` as a directory of parquet files partitioned by a subset of the columns when ``engine = 'pyarrow'`` (:issue:`23283`) - :meth:`Timestamp.tz_localize`, :meth:`DatetimeIndex.tz_localize`, and :meth:`Series.tz_localize` have gained the ``nonexistent`` argument for alternative handling of nonexistent times. See :ref:`timeseries.timezone_nonexistent` (:issue:`8917`) - :meth:`read_excel()` now accepts ``usecols`` as a list of column names or callable (:issue:`18273`) +- :meth:`MultiIndex.to_flat_index` has been added to flatten multiple levels into a single-level :class:`Index` object. .. _whatsnew_0240.api_breaking: diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 2b916f35a1173..ff2562a4480bc 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1113,6 +1113,26 @@ def _format_attrs(self): """ return format_object_attrs(self) + def to_flat_index(self): + """ + Identity method. + + .. versionadded:: 0.24.0 + + This is implemented for compatability with subclass implementations + when chaining. + + Returns + ------- + pd.Index + Caller. + + See Also + -------- + MultiIndex.to_flat_index : Subclass implementation. + """ + return self + def to_series(self, index=None, name=None): """ Create a Series with both index and values equal to the index keys diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 7a188dd7ba299..310e7c2bd95d7 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -193,6 +193,7 @@ class MultiIndex(Index): set_levels set_labels to_frame + to_flat_index is_lexsorted sortlevel droplevel @@ -1246,6 +1247,34 @@ def to_hierarchical(self, n_repeat, n_shuffle=1): FutureWarning, stacklevel=2) return MultiIndex(levels=levels, labels=labels, names=names) + def to_flat_index(self): + """ + Convert a MultiIndex to an Index of Tuples containing the level values. + + .. versionadded:: 0.24.0 + + Returns + ------- + pd.Index + Index with the MultiIndex data represented in Tuples. + + Notes + ----- + This method will simply return the caller if called by anything other + than a MultiIndex. + + Examples + -------- + >>> index = pd.MultiIndex.from_product( + ... [['foo', 'bar'], ['baz', 'qux']], + ... names=['a', 'b']) + >>> index.to_flat_index() + Index([('foo', 'baz'), ('foo', 'qux'), + ('bar', 'baz'), ('bar', 'qux')], + dtype='object') + """ + return Index(self.values, tupleize_cols=False) + @property def is_all_dates(self): return False diff --git a/pandas/tests/indexes/multi/test_conversion.py b/pandas/tests/indexes/multi/test_conversion.py index 79494a7c77cbd..fb734b016518e 100644 --- a/pandas/tests/indexes/multi/test_conversion.py +++ b/pandas/tests/indexes/multi/test_conversion.py @@ -170,3 +170,11 @@ def test_to_series_with_arguments(idx): assert s.values is not idx.values assert s.index is not idx assert s.name != idx.name + + +def test_to_flat_index(idx): + expected = pd.Index((('foo', 'one'), ('foo', 'two'), ('bar', 'one'), + ('baz', 'two'), ('qux', 'one'), ('qux', 'two')), + tupleize_cols=False) + result = idx.to_flat_index() + tm.assert_index_equal(result, expected) diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 4a3efe22926f7..619f60a42e0be 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -2266,6 +2266,14 @@ def test_tab_complete_warning(self, ip): with provisionalcompleter('ignore'): list(ip.Completer.completions('idx.', 4)) + def test_to_flat_index(self, indices): + # 22866 + if isinstance(indices, MultiIndex): + pytest.skip("Separate expectation for MultiIndex") + + result = indices.to_flat_index() + tm.assert_index_equal(result, indices) + class TestMixedIntIndex(Base): # Mostly the tests from common.py for which the results differ From fe52d9f29416dd7d19c04ba7d47434b68c411bbd Mon Sep 17 00:00:00 2001 From: gfyoung Date: Tue, 13 Nov 2018 09:32:51 -0800 Subject: [PATCH 10/25] BUG: Fix read_excel w/parse_cols & empty dataset (#23661) Closes gh-9208. --- doc/source/whatsnew/v0.24.0.txt | 6 +++--- pandas/io/excel.py | 19 +++++++++++-------- pandas/tests/io/data/test1.xls | Bin 30720 -> 28160 bytes pandas/tests/io/data/test1.xlsm | Bin 45056 -> 13072 bytes pandas/tests/io/data/test1.xlsx | Bin 44929 -> 12982 bytes pandas/tests/io/test_excel.py | 10 ++++++++++ 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 46abc16f1b96a..d836ef3441e89 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -1264,9 +1264,6 @@ MultiIndex I/O ^^^ -- Bug in :meth:`to_sql` when writing timezone aware data (``datetime64[ns, tz]`` dtype) would raise a ``TypeError`` (:issue:`9086`) -- Bug in :meth:`to_sql` where a naive DatetimeIndex would be written as ``TIMESTAMP WITH TIMEZONE`` type in supported databases, e.g. PostgreSQL (:issue:`23510`) - .. _whatsnew_0240.bug_fixes.nan_with_str_dtype: Proper handling of `np.NaN` in a string data-typed column with the Python engine @@ -1302,6 +1299,9 @@ Current Behavior: Notice how we now instead output ``np.nan`` itself instead of a stringified form of it. +- Bug in :meth:`to_sql` when writing timezone aware data (``datetime64[ns, tz]`` dtype) would raise a ``TypeError`` (:issue:`9086`) +- Bug in :meth:`to_sql` where a naive DatetimeIndex would be written as ``TIMESTAMP WITH TIMEZONE`` type in supported databases, e.g. PostgreSQL (:issue:`23510`) +- Bug in :meth:`read_excel()` when ``parse_cols`` is specified with an empty dataset (:issue:`9208`) - :func:`read_html()` no longer ignores all-whitespace ```` within ```` when considering the ``skiprows`` and ``header`` arguments. Previously, users had to decrease their ``header`` and ``skiprows`` values on such tables to work around the issue. (:issue:`21641`) - :func:`read_excel()` will correctly show the deprecation warning for previously deprecated ``sheetname`` (:issue:`17994`) - :func:`read_csv()` and func:`read_table()` will throw ``UnicodeError`` and not coredump on badly encoded strings (:issue:`22748`) diff --git a/pandas/io/excel.py b/pandas/io/excel.py index c25a7670cce44..a7e0e48de0a75 100644 --- a/pandas/io/excel.py +++ b/pandas/io/excel.py @@ -634,14 +634,17 @@ def _parse_cell(cell_contents, cell_typ): else: offset = 1 + max(header) - for col in index_col: - last = data[offset][col] - - for row in range(offset + 1, len(data)): - if data[row][col] == '' or data[row][col] is None: - data[row][col] = last - else: - last = data[row][col] + # Check if we have an empty dataset + # before trying to collect data. + if offset < len(data): + for col in index_col: + last = data[offset][col] + + for row in range(offset + 1, len(data)): + if data[row][col] == '' or data[row][col] is None: + data[row][col] = last + else: + last = data[row][col] has_index_names = is_list_like(header) and len(header) > 1 diff --git a/pandas/tests/io/data/test1.xls b/pandas/tests/io/data/test1.xls index db0f9dec7d5e42c87dc0b0d297b66305f7af4225..a5940b2cfa6c2481955bca02e074fdb910c96c67 100644 GIT binary patch literal 28160 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 IGM4cF4^v|zm;e9( literal 30720 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 E|39OKD*ylh diff --git a/pandas/tests/io/data/test1.xlsm b/pandas/tests/io/data/test1.xlsm index 4c873e55a5300797bd9055d29c7820e1c0526da2..981c303b7bd30c736f0e67ee7f1302f2bd738fa6 100644 GIT binary patch literal 13072 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 literal 45056 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ĽE;I9emg+?-n2oq?eqyvUKn{Kk^PM6%|a zj%fvJ_!3lBN;V}l7=;G@#f4EMJl2gf^Jj`Oz2Fi3i+sAk&yKMEXZ}@M_pqvAfmcC;*xkQsFsKWL&hGz|k2x4r5`W%L`>u6y_fh5s{#n_J@ z>g)oVt1Q00+Na+LBt31IOBCajQS0F)#@j&Kh$dKrbydv_Fd$#*c7RP#AxeFwXyRQp zaiZ@`5LhY&pL0|4)Z_3&s0v5H7ZlmYWez-V(MPeKuwu zLV?%+Jq2?7NrCzh3dHd>w0aEQa^Jr`d4~X{epOhfQW90yd{Au)HiGlkTB0^9dAJlb zg<(f4la^rvd;4r>cpvH+zF#>wjk>h_!cg5iUjTJ1sG94Rf_rKD_^Evr-DI_7H&=_6 zSU0)y(U#$HdGm5rN~zALaJFxnQ~+mY-f-^RjR36P#OZZ|g*V~it&cSe=qj4$VG9!Ze{DS6zaOJK+{`9sa;e?491k`i|j2RQ3 z+Wg|c41w0~{t3hkU6TUliXHfxzc_FZ-`f$wfhhvK&OaE!nr(S6+COyL1SsvInTZtg zyBMtA4_c;(8ux!;9I@VC9bXf>T{D}W9!nY)P)~P0!W4dY4|1{>q8)S7yv<-7=eHpv zIfKEY{i&T2C8J;DG1IgolxU+TF&~uv~VJ~NIr7>uyI=27arml2uo}GGJqG~`m z^`T11KY8CzzZ*h|>*Y@1q3y;Zm3Ss-r1|iEfugv4JIdrJe&CzL4%nd_}3E zV8y`D66BAhFU)X+D0k0{(p*7jU%8JK=Nmy2wa0PH5-tT8Z*Vok5claNCQvGEBE2Zw zKvnoAbNMV`Z*`ivdx*naJ>9i8F+a3!<+qI3|K`C~rsYC*8%F_vlp_|S0wuzfpgFUx z2s8^^4hJpf)GoAxBVaN>O6NFPI$+GvqWCS3vfDh%7HL9}CEbP;d3=5>65ge(=SnM_!zszqDqA-#zWI$B`|Rqw_U zlBE!gL!)z&dt##Ag2gKo-@odmPmpE6of1gQ{U3klnV@guw*kRzvszd&) zAqLe3!iAp@BQG2wq$X1&e?n}QE}{PWBFU`)dfI1YcX z&%6fFOTlHTyn02^){Wa7&E1(Gpi~Mj=e7iK zN|whRL{Tp;?k&7p&dxZe9T8{@j9gS8J6ySG=_S{mPhm!bsV9c{I&eZye^i})!fie? zjDUPlVrzkj)xcW2%*}FWtH0F3t8W_5oeZnoCZth$emvB2sBTRRzae$q4fwdH;?2lV3zEwjW)$cMyslL{!{h8db;wMBYmJwq2BCX$iv--XSDGILwg^Sioqcn9pg!78(~+O zXS22dCQ&gER#RnNIKfL37+juc>rAOU<)(GKdan`roWSj6IrTxGxo29vK!vdoY2j{V zNeVcogn4!4rI!-ogUsLUxvSU(%dp12F_hOgo0F@}kekrRSt&h_kCm0E*we9UW0<&{ zAa)duCSoN!GA7ISe!wV-6=Tdn-Xl**clN6h2CDY;hMw&_(!b*|A-bpneZ$>qXQi?C zF}~KE|C#>z8??<(UQYTj_KgJ&?34ou3%vF#bod;}Is*CXH*CoYi3@Cc=4*7xk9k%f z<@O!+A}r~!_)fEjbC{xeO0EFzXJ@xu_@`|0&T3 zHkuCX#%KFl-)U${s|2Rg&NMZD?Vx@`^3j_;O48c}Y=H?J?-g=2t?Qre5eE5{cwR29 zYn&d{Zk2Jj%n2=9$9X?nau@-6O%OEgqPW#9{N(ak^J2CUm!)e`35nlvuGK@B)8GOH zcCphi0?UeTmf;_90{Zk3EDDsrT%^^BCiyGfK&BjjjV(6xw>AfmCo9kYn1TFi7P(jg zK|t1DufNV2``U8$#5@>n_&fgO7a3YrH2vI^2#HKIp!J^52{^ne&C@KVhfbm@b*_xD zrh(9sQ`t$-t>?-$&td?rx$S+R2yVC&d_HQ;l03=l1Xy251aGoc)a?<%!x@_}dhuHc z=`Yn9%I$h67=vP@6HIn+?zgRSj8L)27MSJ&RAol;W)7hH`^)lmu7sF)^31VKB0IQn zmFvZ>Ak;PX#3WBe4iBD9%3fqU$rcPGAApZ)-Dj;5X4c$fbEq#4$hJqQVVu;3725E7 z*x&Wx>r-NHL~Aq0DVAy5G+ZG+<`Jf7E*-cz*T(d6aFKg2BzIO!ClV7!qOAllwebeq z*YNPA0}<>+@Y)4}kMy{y!K+I78iA%K^7Wj zH|vRCE!kde_jwY@X?@q8JH#J>e)$w2Tza zh8R2BsfS;NNq<*5+vVB`(r8)TUs@nm=mu3oiAT-$@3-KWpU7`kB)t; zFFq1dV9M(&A>(Mmij5ClMel)R1*O(Mb+u@ODBSxgOV^uJ0t-yLUhPUr$dZjbhq}@D z=!Y%ddeY<@8KsI(kF$Jw+!D%LLCJG%@S@Y|Fd@ZU2KP4bYcNKyWf~)yPh>M;_E9JL ztF*mC@Ay}TLai8I^D3z(IYrLWKK#5o;ajs4ieA9LRt09}@+a`+Eyw`V-V`n!eYr3r zTMAGZP7>gW#@+L5@HY-$>B+H86VVv9dvnBa){Ol8ZkzF}MbGcl)l(-TOIFDnH04>~ zOngKEwAG9vY@|^*Vm5|}@cKE93TMv2git9EIFvo&?oinQhDRzF%4S$la6t3*UVitX zl1Zx{YfG=I#ga5FFp*>fB&CL2)||qf=7m<7AZ}9IOLgl}#AlyqJA6i%mf}`59&7F} z+nZS4vSQ-OIHOnHSUeMDnNP=8oWKx_ZlN9=mdBM!?X4C*?|a7b65>?_F-t6c(z*1p)EN<8eMD@$ILGrYsSLJcBJG0Z zN?Q|cu6ivnnog&+b0uLW#&($zVjPQJKJP1qT?342g6K#w8r$iN)JWRJe4>h*oMN;v zeC`kC*yP6esmEP;M^za$s?+ z;^JyXrQym@D4c|t_c)l%GA;q|w$yHH4P>^(=i!ARFeq{3H}HycHMJv*^>uizWnTF} zhYMbF&!9-_A|(r2LW?!pRawH}^n}^B2u+?qo-gT!xar6CvI*7%k7H^ROHd!lnIsos zC`b;G-?_BaL9?iJWg%}NJ@bYhZIwR=unff3@p#r3MrD3#7~^}t`u*dU@gxzvXsx&@ zHJ$AX2Fws!aczzXcjRiX%5$y6QX@0UV#@O2vU!*)B`w3b4xoN8OuR^8nzc$iR4_lO z|Do>((O|7hy2t6hUfNSnclXxDCA7iGPn8LlY7u@wMy>PumoIn-R53@ZpoV@p)tQV~ zw#`Sd!7~;hKd=5 z_Tsd^QZ(mkUX`0WfSU>nR!62`lbA?P?0GU=(K55#dhb-Y9C9^B{C?~_N#Qj?$7Q9M znc!kdg6m6*+F4C(xypT4c{lhq?e8yB+(-FJ2KO^PvU6CBI9xrd29f0gkIiAw+Z>Ql zyNm7(;L@U*8EDPs9wGYbuhsG0xyPGw$de36g?#pBb#!*|v;{is73tt4ihz zbE0zfh+q^ls(fU9r&@*M?Xa(Drqf!*vJ5pQ^effyhCusO>ZoNDw|3KE$^d1B2>01p zIk8leergbl%LvX#wMA)bQ7+xdY4Ajqqo_*E_@#w}O8L)#&+)yh0n*l_ON)#(rA1rB zEDg(-S_Fe8p3Ulu<57TOeT)fc*UsUP!j~H~t>+7ZvG`IvO;z{-axUt}L4pO%+!W<%|y=C z32a=WWA;HTNgCoa*5P=yHx|@r_9BAUV}?#gIYfvXV)6s1V5Y!wZF4oWf*o?Z~MdhlT|TLx^*Ll@J6rD~VRd!Pd$dOj0oX;nI| zyA&-5wp>8edi6bKpQ86Rj=2|mD>!W>i$cWvi!bKr-KFC<@9R7=kBN7qt=Ib;7bmX} z=c+ATvA2&yyzjmwY{ZchBqmXju`(ygJ8)fC?~hL-D?p#4%fwV-Z=UtX-v4c2N6ya2 zY(N4U3Gx)@AAxOY>;yDZb#bz?v-mTY6<$c+O3j5@Je6KMiS`P9;b({%1H!23IHj{a@CyMSA%?5`MN_feJ^^K*l_xE8 zTQ4x*<6|XnFmg-WPWp|v#SH%~vtMU77N^|L23Y0-GR|i-A$=D#X)tj@?!83sGV){J zH5l_5LhlRrqw7sE!;BT_zNEP5@ti?Z8j9S13}CJ}Glcx)zh*l>h(oRu@xJUX}SqIbkh{y^7BvcMdo(V%2&Hzagdk=VvMI)+EQT@ z6=lQwW3+HlDns8;-xGBE^(<6IBNfF6eP56X_hcKqjwBv0Ew%=o7$VfLD%Kt`ZTe~k z^9ibGKkP^Qk_p)5w2w-kjD^VX#uy1@OY;s$9-IW2i0-*xWZ3wk!RCX8hfXh${>}r~ zJxthL{}T`V>c0Kc1CZ$rhQv|mUGTg&HGi0L1dX9A#T@NDK+<3-`$E>Tp62>?XFfzM zy4!SxP2XP||2#6(loF-PPJ|+qQzDhgCtawnB2!D?nV(DuUirXy^N8GKcw~~!I?|f$cKeBfkhKF0Fj*2CJ6koy1vrn5JTWs7 zjU2P+9!f3h4Z{R_f(XH>_%*%s&x=W9EevQdqEDhz8|$qTe!HS9yu-7IAa0bQj$yT=`Gb&Y>Y&kJCZj)jaj=JGp^ zQK48Rr2=~`j%O>>Zq0P3@h4 ze@Gk1GSz=Z(~w~GiG3s2&4v@Y3il{J=$)27!!EYe8Q;1i@|ok9nc7|Vvy2?p!OfAv zk~TjMS)B7>k~8|C#tU`0Pe!GsuF=vsIRMUz(CILe*7!7saOk~cywYN>%|e(+jox$h zKH@JnFiQD$9j}nMe^P_!?VVg)%CiV`{a|}-H=i#?-Y(L8zndU&=)U6T2Pm$41meD; zO*U;n0FOvWSmb`guDWKM0br1b!y(sHCriLSdORlpK9Uf`r>M%zarqTEf92Kv`R3!- z7mP1Vm+Ic6p|Sh;1sT@AAL}m8n)cNsQT~9W*a-FAT6N!tSNDOu7R=K9GK;m+WESMR z>WyTwjB8`mH2TxN6DI7A3RmJA_5}N5eU;qN;m|XN*yI>CgOI^0dBmusGq>Z}c5n98 z7bL9H*XNJnL*wEyI(_u56r40K*LgAtoD3f#*8g_QJ^P|hDjpJquOT#y@vlK>?BMX9 z7=#4hKdz5)O7=@^sJ%xp7tc|biFpT=Q3Fe}rTNc38$-p`St#V2W>uNJE&Z@R^}g=S z+`^|JJDk<-Zl&B@JH@CmKIt73x*n$wk*GmYc_{s20;FwvzIcSONO{NXA{3(m>r(!A znQruTF#}NMB$%HuxZX5>zydvs>Vz8#Okl|G!yub_(+62pJ->g&nRMUA$z`@N z_B3Zvcf)w7vx$RLbnp`F1(-qyS?GzC@h!R-(dVNsE0HeAnhB$dy;prZN^Jqnu3=A% zE`Fe!oBPSstCJ`|S%&-FNY+R1?b_Six!}M^Ia4yWpwABB9uAvO?V9{?JFGo>yvH4E zC(*BNGwgY{)1(os&h4$J(^stta8B=~YN8Zux>7=mZg#s+gzCaPED%=`9TwDX7pdty z?Wbb%!Cv34U#y1N+F(a3w|PF`+`KsDd_ZY!G1%PuXxLp^uz8C<-VXUs{w!cn(996w z{P&yW|NQ6vdHd3#0|C`OFr#MeHR(>NTK~&T~zQkYlSDvCg9s2%8NyYqIlwTtBDazAf$#0ZG zyuU^HH9C2U^0Y1f8wHl|7s}Hn`BQ+WorB*1l;pnve)kccnm#?7{WiU&{L}R5N$n}Z z(}T=!1Ptn@KKR>X%~Qaq=YrpWSTz3!z~85Yr+`mY_HRI3+FyWAH1^+W?*BPx7(~fK z!tnnB`b$MDux1ux7|yD8NP~%cYeee>D{Egv%-$J>@J@ zP$GcxuznUBD3SEvZaD+m8-q91b316`}#UuGLw6%=D+@O z)g^|t-KtW`dXfB*7?6IE+4w3+_fpD;vIzgYmSThOCmY4647OMw=TqYCJ-T&bz9$HY z4ljb?>%k;nBArd$wo(+5IOKLO+=I zCUc)wZ#4CBiK`0#F3AWIx#^JL$%a}q?~n_)MNgIu^8C<8$Y8lSc*jhcKJG91rvW08=xLc57z}2>`d>UX;{AnuZpc%oAV=haJQW$>?i;A0yj%Z25B_onAFg$3glN$;-AdHl!J8U8c$_?`li@g*&$-@&FkTLepC95{8QU<%<2fX zyIaouas=cb|L#44;PT7gkg80W0YD7c%Y^Y&`O|?y(E&cLXtdAnPWN|bVuH3i$kYDs zF3orQy&+?YTZt#cehycf+<6lB=Jh@O3coEt-`P>N?nuoftTn<&-Rvl!~o?ZM<%Q+n~pp_w&RQo)5MM6R3&Q)6{WI6KX*h9%X%X^aV zkxirBd5+1yy>w9B9sbxnv#0k=;N4gE&*ZiEpU=8Umzq^)epY?%Rk=`?Uj&z{R>BA^ zv<{v7VJ1^+g;|?medyE;7tWDaMt0Y4n^eCMIQphDqlq92<|1#5@0sd++&AQ_AYwnuwJ#jq#=8$U9-x<<>ER~ z=Yhq9H*!l|Yy15}wM=40l@X%hmHzWRy{UVpD;`wDX$ynf^=>bF-e^BlnDFlAqID<{ zREVv8?0(7v4oE)WsN+n}Yk$FnER8ERO@k8l)@8MKM$UMBc(S~&^uFK8&?;`T{YnOA z@f~U%Jv82g3ZHh+x!O74n+IQ~vrk9xS%!a02RP>qo(>jH{N1#PD&?)~shVXt>vGOwnGH`*P=Bv&lC0Wz~N%QT~t? zdri#bcF@}IK6RFtF?_l4xZu?=1AFwHU#{3kAv2ew^q7#8e&Z-N%lmUX-!*bhwi4JF z8@XU4fyF|^Pt;UHlsC^1Rnw7#>JD?e>ZbFwS)s#Z^KIh^_S7(GPFmpoJ6~@vXGUG? zJ@VNj@n}*u2S?WYoon;yx7DRvE9MUOYHc27Rhw9tP!YW*MRs1SFODB)6cHe(} zP|LA1cUV%wF)Tr*U-#+(>lN+Gm=@|UEoiy_J(B442YlOr48n&603eImHHg5Vo4)RW zyAkBxJ&O#;91>RUZ^0CaT9$)#6NYWmw>Jha7F#@b<`!`+N8Hvc8blJ06F*80IbU7M zxv9H)LN@Ye&0%{|bB*ki#HoA%7f#2swsLE|r@}D>UCdfC_M=I08y&-QYpbQ74Jx}P zjrK|*Ple$UJ%%`O_yepJbogc#XE^i6x?Sg`7eQeR{VI*4#7O5}1ci z)>m}h%yHiQAXVaWP9J9Ay8xm^={uLPvz^%Q@t)wuHH?e|-6+d?>>j5t0hLw@3J zdY*&|E+G}4J8J1U=&Ska&f9}GXAe{AYwonP8(;dxa5J-4qU9~^l_N!7G}k6s6mE^# z&2_kUe%tG&CYfUUDzK?0(N81TXrf z?xRTV>F{*J-z#M$Y3wfr(@cInc$TqHnO^a1ymX8#qPy7m*5VZJjku1}**W9izeP&Y zsoQhO`(k@azG>>^+6;7RO~v64AQ$M0OG@39h8Ith| zDN(lJ%2Pe)fx`^(;IC)% zFNDTT-V332f}Y9d$SbH)AHV{)N5!~f59dXWXO~#QGG;c9d7wte{b3dFg>TyB^(^_a ze0Q~4oA4BRE~2R9F?mq;x(ly&OI~6qrt!Q>^MhLI@BGE=l1&{9Tf6Ryp%#J_@%`I` zX!Ewh<5oOd?mE2upMBTPdn)fgvpP5EjXmD9sJ@k|Aa?!*tqgN)r3&Xew6)b zLiu!YY2i+PGp%5Cr#*y9Z9o>nz$uNJuV>Mo5S*Xhul1{BWJQamc{`F4KJczNY5S0#56} zZ>{TpE`rwe^NU?ZT2jnsn$zDu%4~f4`pqB<^$tm9{dnpc+d~a81KWr48+t$P zRgF0;zyIvPb50F4FKZJmtPM{|KQOaTOx&UkTjaAaLMr7(Ld_$A9h zY11>0d!28x+*2^nx0Y$>%6q%FhAOrH#vMM;mW3uJsr4qiVg7FB#ub6W(dzx>=6pz5 zR-0Q2tkkCas=RT!d*2JRS<4zfa*L>om*zQDoD#k0$7$^HC8$I-=Gt4951owjvHpC> z+94geI0ln1*sueLR(xALYooz^h$pN*R0@+GlkM!SS3~(Nc5ZYU9sysHvwR z)eGe@9Q4C+-QHRG*!Yl9PK6-B4!f& z?DH!}uVLd?jw7=ey$wsXrs`Z#IVyLp$&n+5XRh3CxN-V)u^rh4Zt-|;%1C8fUe46I zrLO-&fzzi0y;`bUH@~+Kx7BbP3$?Qko){cH^36=`sdEKO(vd^3p=)3E{oH8E*4%SM z$THypHBLQN{!V*sc_{I9iq=I#*O=4rJ9!PFhG&cOjvYG@=c1^xdhZCuzsu;BkZua~ zo%M|Lpm_EDPiNgDWO~#&tYh4)!#&jt4xNc8Kk@n9{ZJ8I*|Q7Lx0CbjEDmzSN=RPN z(6@BY;|NN+tQK`Mf%eoY{bH0z7N@g%Y|3vgySj>snf`N0Wvo>)uPc7{eLWFPYJZkv zdyBoh=#zi>4foPPG;pqeR{N1*gfrX#EKZ)lk*_APk<7-dRjNM!6S{7!w-;fsrK?k3vDd$iM+chfm<>&pLu>Njw z>n^VV)x=Sz%v4}B8FIgX*OIW*Nnh;a+OtcyA`ZOtrU_a0ru}+f@Tc^E!+vzFC zi#vI9?Z;Qrrd_r)hFNa5YNoFe@q4F__aoY>HS9O2hH%cJB5<1@tq_q5?E0+ziec2> znaF&-o7C>!*2vY*%)|p2>x50zxg(7h>4Wf$b}fTjKBq*JR?XI=&q;6`jP}o1NKZL9 zvn=lczmnSUbxLqh7u&X&$(~-`VtQ`>`g^Qeio}fa+>7q`?5Mo33W3fYvlAOu%ChcX z;5~_i*OMo2=uhSp4Qi|w1vQ{ex{e2CkPJ!3&64!DBoICL!}B~e%;lJRe7wtjVO3Or`FeFYZ|%v|n=J-BPDl2$cu3A}$DLAl?iGx8!@q;4 zU(TU8UNVA9huiXJ-H<4g8glD6xv($!9y~{94^4@6M>Zky8~3(yUXQZP(Xg4}n_Pj; z#y=^sA#t-KiOV04D7X4w!EZ_JRyAn{Zzoyp3B*)bmks%=W#ZxP$DQM||x;fvD z$6?)9&6W+Btu6B6F0PIHYJy5_d)03`O?vF#s(VE8oAhU!e3|q+Wv-{pqh;@=itk4q z%-tparzyW>7W@(;C!fSJu!+tW`hlPQiIz48yN32gE}Tu^IQZq#Rq0q3dziJ*`r(HigcdO`8MmA=N%MOF9CJo$ zOP|WAFE{NsYA%n>@lBpOV%LQAN*r6e9{J_yh{*Gv@8|NYYD$C@b;c*|pOXhSWHT?; zo;M$`()dQynl7HPR}n0Vm7TAUR@`$E@84Lj`n%mr>^3A- za-9EO8+@e0z}4XEzUSgZPAxI@l+>bKz8K$^ z%E~%>?}kFrMEi-V`m$gud6dI%Y79zGE@kP#|@5?5~N8n$+m8yZLQn^u_SKm70AY z(%rI*PcCL{g~(Q(N+0u!o^$zZL*!?e#H`h~`rc zWi@WJ$z>8&AP>e5B_%j9EfVG>ZYy0k;Hr$qHn?gsxB{Ls>NPxrA55Suv@z8`S@4B^1_Z4lgop^Sw;#~PSbAah3O8{z z4758F`)a!I-eUj!weBI5&&k+}x{rY01;3fn9$Kc8T$HZ_bYM6X6j! zF>yL&W;OO3?-@JfkQ4U_Q!UeNA7EQj$1Bt9dDV!A4y@mSa0y8MjiBU?!J~-82W<~{oxY*ZV=2I%7Up`ophv6a+x_|H zB#Od2u8l?UmX2G=F30#(TjE{R@5*dni~B)2iNNhY_gSC{Y5Gg4>Wt6vM_%zWxhsP+ zoE{h@Z~H!d%(^d0zvKNrr6xX2VQ)AqB|_2X%a#{AX7XD3SYty#$)#VOM;$vb2>0pC zfvS7sv1A|Sb+&tDvtzbd$63Gj%SmEM`$f{7^@edSA7AD8+k`CcUJLwt8o=1fz&wD` z0Q~=d8t}(9ddqGyeNvMzLS+!gx8|R$b*I2Z=Mpl8&2-RcSa!f6$C>Mu;hBQXy9JDC zgSXR{svNu6e3Nyxb92-l=8QLG|KiilDN*v(;6)jBv|V^Tb>P#iE^TpOGgEz^L-xhV zrK`u(c##(31V`Fd-_p1yaiZn8GGOrOLuX6ix_bH~7X9u;ny;V2(vq*O2Ty&!+n3R_ zw{=qn-wt`iy=i!#qOc@d(m!zh^Hjx~{)z9sLl-LKQ11@~zHFTm4i5J?wu*mptor-p ztNgEZFV0Y{4{~l!+(|f-V};PQt9vWSL)nf`QA7lWYT2*3-_fe8)e(+X{>k04ak*EU zZP>L=X(pOCeDJ}PZgb(Vg;-DOWnsKZ{7rwA3g&D*tR{P=PIde_7Ya+8?u%-Z)#Kr{ zCcF$Ct8>hem!9Uq~Zy-1)Ukn!YreCpv#mHCg0(aZ!&6_l@V0z0z0r%asisp{nY| zm4|WkR{Yez{k1mYMg8ZpS2jm^kDg+#_#UcEP6Xo-7LLTm;6dxJe#++NH^CS%qmkA_PdQg18#%SkXCFYUq9Wol)%jV;+){7Ma@ zNkpagFsUHx3rE_nKk2fLSx-(i7RU`ynhBF@KYA-qO-P3Cn337=8X~}YYV9o~$8Ik0 zD1a}~DCL5J!ng9XFSTbM+}5|@KE>Mj<9`04n(`TKF4@;sMj7IzS2H><8?%+{TaO7J zF$&wa_A9gPqB~*rc{U-M8u3e%DI?9HHp3+lPhE0%oeg{vbeAF z{Q0w}AFA5NCH6Uu$nCKBqrSovD$oA7T@m_xB`spLZ1aKtl{TCL%;fo z4J6Zizr5n{wSC+dvbt}p$?r<0(2t+tFK~(O<1S9ZtJbPY)_Ze|Rbo&tX<^JY-@7Ax zoi ztg|-^rd;g^=T;Dr9Pn|am?ST{b53~N2VTDRu>sYFrZof3_e(e(x7qrS0aTTLie^yg z`lB2IVB!yiA0`68?w>H!b`9-j9e}+YV6&x{#>@2s(zF~G#c z1eih}fI((&Ff%YfTH9C|o1HU)IskzEsmt~2zI&tqz|TJ@z{W&h>e6KgDfV&bS7uS@ z*DW!C%f&75`Wb8MbG!5J;_g2GwQP+3c}YL4^q>3x75l$@|Aa67fpfve0K(bj zmB-D?F8r-M%-_}03WA}rdkTEe=DT!uao)HE8bG=P z4ny#?m%G{S8bkar1J~RQjUZSNf+f9zP5(xp`D|c_?QZ)Ybi%w0EFl=8!yMr4a@HDx z#UMB-0By577sNAjfxEBC?pzRk=AP?8)_>!H`G>!+Ba15#o)dC?MEomp6z$%b-hukqHDtbXb15`(NDE z8w9h8Tyrtp)vYoF!vQ-c7r-4r1Flf*2KWOzfD~W@m;n0F^Ewa!^>_d%z!z$9hkD(i z78DaV-~+Y&XFTgaaQ+Ns5Dd+{%ZDAHe_Jg0=wD-`VgisT zw}A`_#LYjXME|27qVt!;5YOm;)&LL)Y2feDDgCpada=zSfAvUxVrjTCyssAvSp9eU zW&O(fgY^?skF$RH$9UFB)-TX!95@55fbSn1`9WNv{#c2?zwng)MTT|=GYD{jY7&Hp zhIsuur~k5|9{#t*{?W6m3HLNS_7nT%{Fwb!wQyw{}NBpmK^ZiHvzsQ0DE@An-JB1_LIMH$|A{foW<h9b0ASCG^RRaGsiGtgG%E@kHLrmQIC;_EB*M^~U!fP0{OK#2P_Wngz7+#Lr1 zt2Te^Z%hXU{?Qg>0RVbGp_n!Jk2Z&30C*7yZOiKaXgdnUL?Ju?G-$d72Za1d588P9 z0U*#r?ZhA7nfB>Jv1yvYScT#h`&|Ioxx-*=7cdw*g%JHO0MO>kAOS%}7?cM9SXk^v zedwJr7A7$O`qkqP&frYqf5FB~N1*_|+r9??5>Wul-*9$g^={dXuS|bE_dMS7cMK-r zG4tPH;NdPRV-hgfJw5y%m0cqLM+9~UGui< zhnCmvn!AUm7s@*@C^#e(b2BV9EIGezk^Xx7+1P`Bx-n(D_&XZT|9MWnw6d~7ukDLdN zsFP%j$4OE4kM}xOP{k;(Lg1mdDqJ`DW$&ZOsko=z+eiNoy^a8p@;h9~~z_d*gxwKaI}G00a$EoP>!gzee`8X58Il=XWDl7 z7(o0fN+CUYAQnN%A4dF^EMlhbpXaYS7H3#S$3U!uF+SqCcRmY67GHwO3Ux>*#DzYYS9Q32XT&h?VeulmfGe3 z3-yY2=`_*LQ5=tX`*}YBz~!26s|ala(EFkp%f?obiRBBmL$CFhI!RiKpvU?eA(%N%#>(D zP5r$xuX|Cvm;P-fqIf}DJSXDELr{$Ya4bXBogcuzVMw+yvQ9 zN^h5#aYhl%ZWOCR%Clmko$xb1E6Kc5tQ$Uc^j;f0Z>Ze`*9ynQ9S8_6P^q}dXR|$a0Zf0b_DTkIFeoo?w1~L z6V{7JK=Q0vB{WtP7J||pTkbT6m1wE-U%f^z>t36pnv#yBX8?wC?Rd}%g{NhlX8(6Arr+(` zs@~50U^`W=cMQi*IE>YxB&K53sEe~&om{YSF&*kdym_Rb%hC6u4$jwP0Y zuPedWu1K-rwUt!%u3W7o#Wk*FEt_<19W#1IZNmv5G6S;u{|N)VG=0#D@~*QDezLWS z!W&nv;@b=(`!tz9kKnRQAx|t!8nxt3lR0bvs>Qyica0A7y;*os#K#So&8Wl?_o17) zW||g>0LFOX*J?-P!N#V>hQXkD&)2UTJ}!OFzgZj}@XK7i;+L7Uz=x&xU3V>jVEn%= z2YVNRXXhTxhm7aMgmz`&M9bAvEkaFRe)6j+1#h6A);;20ZnTofM7E|XIZ!5#C8f33 zMfKI=?&VAXx{-(&`f)0vmncH-x20X8R>rNj?!%s-RCZ6ICA{dO!!#Wf8O8%9c1`pq z_>l*LdD*cSGrG5~jY5j7HMck`aZ%l)DgDdukWGi+F552vbT5u@AqtK6kyiF&>NnD; zD;bX|p($8BGPjlqRX1N{)bH>};U_=eA?Otu92x%F#V>dxye~B{AZWb!K)tYP*I;vp zR~y0rSJmvp01P7ULq>6j0enx0;$5l~V*rE1VjSrR?)Q_&%-hF$TGzDZk)Roj?&Ss0 z-%%@fxVP--0wxR~R}4V>8wKfXBWiq?O*uVTc`c*^yvG!YUF|_4ex!7ROUoDx#}; z_(Cg^14HO`{^sa-?~CJ3*4FYlg~9sVkLGi((g&j??I~Ov_dg=M7yuvEn=;nP0E8Ao zwldm?NudmYw^@H$2D~Aei6RG8H+@paV8ds`pJI`b`7$8-Ii|4FS&Nd8M$TAMS>_eM zu=gCe^SQk45&C8r(;EK2VK}=K)Nvg0XlWR#&EP_1F4#sCp2u5Jgv#%YZHk7hu3W1d zoeeLmH#@ZIiGnH5g|tzAeaP{ovbiwjE^ zCyZRH#$00lIq<)>M&^AW?|Ep?c~aSY5PPnU=!)crC1%MvIqC{+OMUuKz4KV zpWS%@Mko`HUK6z!A(LEep4c)kigRm!&z= zhuc@ZAw{S+VD0GpslvC?o64OqZoOjPHu56KLK$}ML-DooPuWK!<*21STvIaT!5J~v zy&8Qd(v#}L9)piaJEr50N7ptk!#mN%CK^5Sb|>E%FT6Y0s$(i8*|+m*R%J_22}dcb zWdPs&0NAAD3CLYfj6s`T9+GYcx#xeuxM|Y0GNIEBWA&umukR-EVRb;iz}YEJIzIzo zJ2Q(&4pWX-Ne;dt^YDbjJSyB%G)w2^y2Od;jo-8u?T)z%L**+K%X6O;rC$SGLpUEq zyu&&J=(ad!Os(vcFtG(C+@3GsMHHpLoZ^T|(&+ui=Fc4$b6b;VGA+~1^`uQ32Q?;@ zOzhG;hs!m%#V-thZ!}-zdX9;bpC{JIwWm2=0OJcj)6Bq=Ta_Jt`@lSM#QlM8=!Ae8 z0+~Bs6{&=lgRg3jg`cc((lXbwd%0L|f7b+-SgBn8LSwds_{GR~Mgo@108m!U7?m@F zy0+wUT$>myfp(GPWZ&y7I;IkNXr4IU$N*y2^p07LY2buVTGsPb#Xn=+ioLgtzE0dT zD$faykQK={e`MJs9>rr|xl;>gUD(9$Q{Pb|C$>LdWB_R@H-$U$j>46}n-$HWH%b?6 zF&-Pk22m4=FdUU&vaOFVhP883VW5jVs}J$Pb1h3UTBGHLr%Hz`8|^O1fW%M0I6 zVNX${3C${nAZ|HJG*k^@?aRy}4&*$!vXeh_xk5!lYiJ#})ak=It5~!75P@(Yh#2JoFNg8(AfV0IQ-9lRuOdTUB1Nc;fwi zd}-ZWzJ|-El8;b~Qfv&aPb^nnUudfk4!SEhBZ@jbhKoW5F{z#P!i%sR%^dcmW<7YZM3KYB?ajxc z4)x29lflNjHz|`pHa9|tql}(l-3RHXK*x518hE}8bnD6IAE7xu zLpg+|>I%(1QoB%Z;o50PHNIbV`9*)Rsrr4J3V=d6iu`3v%B!rb0u+i>KdkH2NDt0t#$1$0TBn!ECxPj3bu2dy7$BEn`SOoj-O^^sm#`8#Q)ECE zt;u_2q3FP+qSBeInJ*h*Of6rFCZ+bN2s|>_X4@D$|A4u66z2nrkCYtMjd<*nuL&Yc zd=Q*#$6x}qv#%OKd?7nUIqexdM>6{cImf1ZxhA~){CW%Twwh^EzMju{r$EEIeU|xp zZWiH>_nk!e;i9u0vOCMg#>mJH#}+s8%pHOlO0!jPt?7|fkF!a#JH=^eUK^`@E!)*m zMWj8Dq-QMt!%uct*TN_Ki8qJev&&8s9ZX|yscsfv-b{a}Ek&j`R@bxO2SGKp!(p^? zh5;ny3MVhAw+exQU0Y6duSrdlEwWsBUK%Zu48SkpRjHY3)39=1`_27&bq0_;tu$OT6e;-w zeypj!X;4KY?_>}I5C;dk;gW;C>*AB;S{BvKF&)3&F#lLdAl78Wz>k9__SDUeejJGb zq|-!6i+xjwF1XAfTpDFBhD=#L~WMDNq9&Ea-^&>YOUv7A9 zXk}?d4j>6`kU&=1J2T4>a0RR+y%S7)M)aCy8-(v zp%d13&YGWbDfG72Y!jtMPUEWM=-k7RhdQa5Ggt!Kr}Z6^j;+uXH?W_p>W`RhhIP%Jd279zoOcLK2zHX|8p|H^605+MU5N^@!`FmHV#L z3O`Mks+G|!THsSjCUSTo`PU+>oChDjL@zyZzPWU@s(*GUdwFV1GFedC-N<2P_pp3+-4==4j zp1u&NI@D}NS?!wme*dW%sYy?(Lwkn^*^U6_@M71r;80DPV3(TrbySugA3FhS27WBT zN>CoHq|+6&;%H1W%kVkNswS#%GA+=pbbb-{0(qtcB^IPO;bReAwlH!3Qyso|K1=n> zf>_#mmu8*a@WA0GzzjhI8w`d%q3KZUGM<{xo{uQOc$&OwI)LMhJm#GhL!N$j^xL*( zaWSa8YSEe)hFAXC^Yi;?aM$hr!+c%L-&@(igiX3wXE#wCei$4!rVb>Ot3UGTfDR68 zdB`YSO)x%<&I^h=WEkc;ahXQ19m8`f7m|07#uoOy`6>-VJgwxT%RznuJ#&^6dZJGW z!24X+mO4!O{<@HmS^9R?uBBx}-E_Hot^=Ra=>95rbZy=$5BChC{GsEsZ(3bT|NFB8 zbsBEc1uxmFa2@C;xB(Rb97$*vLASPsa&`_vJOj{eHiPmR`&$g)_ZcXqmfaGj{i4dz z`JJJQg>S4tWLV@RqB?tbyMJ`{-3n>tmLg3FO-4rH58~V_li$uFAR7BMN?(EYR0iM- znpa@*dh(ep4s`SgfvKbn@FKsXm$rXXb?4TLT=KNHLwwGlRNY9FZeee0HLM4jjF+Gv z1{pw)_CUfl3an=_BObSxE(PK`;gaC&O}&97DrJDo)=JenfA$JJ*zdY2NZvb=mW$GhA{Suw^*xYj(L$(8cu{vTKl-Dar8Ld4<`el6l;GBQ#iH!4T))qs*6~Z> z+b5U40Y3=hSkav#ER3XQ`F*&{nQf4+PCL4Dmo6UpuC>}eWd#nyUZUbUBV-wX#qip) z6*;@x!l#`9jBDF9`A;7oT|)yX4pQIq;gg8HYm?(&n}&iDVy^OvQ&yHFs3$tC*d3iQ z!yS#0Ib=By%4=(!c3Pte+L-Jfg48Ghi2Uq)e5blRQW}HkcBo4$D(}sppQPziSCW_M z^8FR_+RlljywpA?blU{(bI_s+mm!l?8}VgjFEY^{#?kCo0C`2=bDHT+PV*_sF%q(^ zMa>RGP~Q!=IiCP8Q`AUf%ao<5&Tz=dD8@u?VlR33Q6O=Fl2Z5EE#e`)lQFbG4si`{vf8IPC(T4XK0p7zS|l zQFt3&e(W()1mn|#<80O;SxrR14|ox@KnrTfsv{Mdiu2|LXb32L1i{j6Q7=C`LTk&T z&Vdyw6P2PoT25~z`^h;EznDhzPJzb9rmi!q&DzrhXS)%iSQBdC**vmG4yiI8&lkLs z(t4m-M=7y`H>H01)JK9U?flN&X1(pBS_!p>)a|xp3n{UkTal@uv+C6`-(mcV`imBn zYtX`u=1Ti)JzyV)RWpF-W+Teofo|=wt{uC93t$?xa^nG2xECgN86((+uSie=5SXNWSf%~5B-wJ>*t7R+FA?o4` zJ_#;?LD~~2b1AJPS-vEr5Ij8!6KF$>yWMseI%eBd&pYvl&kREq+y z{KHLyicxUOK?X3B+1PWRjAkvL>qYYUXe)}z=0_d|yXi36wQ6cfG5OdcdgAOHnYFk+ zCe)dxNsWUmP?5{>O1Rp`#VG$+--*<+610A!zU3p^kdmD2z14xkBDP1NAVaD3B zh=T9~%|ua?c48v(AnlYVrG9oL0joBfF+MkgZV!jWP2i$y{K74URj}qHJvZ`~ms4M` z7e{=R+#9PXnvdZy48q|hp(eH0CdvboN$2RKGTSvl;iuG#C_HQc#UB+uaHV(5nJcw} zSabhFES0?*#|NG9j)8;u2dQ(3#7mMA6q)Rf*%`DTO$~IUI?j~jk3bH0UnXZ9xAd*(1BV|z`4)C1W0l^=_*$%Q5x<;f)bI%dQ zYs2^BM<0D_kI;Y)(+y_h2Tt?Wt!Idzp0Iq{xOap+=4eT9I^g8imaqGI$n{fNO`&Dx zh5D+G%V@dbyOfTx!3ihFFMYl;rg8~(m-jROS~1zVM^|2i?tOibanovGJgMaXabu(v z{DhfiObGXE(wVZ!a&4_#*dv1;6qPjHn-Q>E&1M3N(~=ET%a&qH-7g6_eaeSo zH|U1ZSj>ueS4VBa&P)8l}Q!m7=*^3aFiT9n>|W*_P?a%B=Na27qG zjoe2w8VTm+YR8MF-yxTu8^?r_(n?Zi{M>q~@cfv{ZRfY@<#I+qA2_>xzzKU9Pl9#e z_xWTYxmrDNF~ogX9A%}w(~y$bo906{bij2X#uv%FZ4!=WTPcLnY7)E@|^5=@131fE^f3ma}H z^0s-%V9C#KjmV63s?O_nNbJR> z5G28>i75sU8~i*R4;=$oE3p#732u~&)cuVbSbQ59bAF3k^hx>ZTmE} zBv~@PpywkdH7LyTVOn)NLG@0k(nE!iw~}#h7H?nw@%|Rv-F5E~=2_%~){I>lRm~Yn z7P^QDM1Cw53MDW|)(+w=I6oA@B;?2m)s*AGutWztC>fa&8}7_iNocKUJ~%A{4N9)f zYpUc&aXkOx2o`XwT*@oG=$^tO4lq6b0k;jTFb4P)ct#Bg?$-Jk6qRH(o53Q5NR(N7eOw+9MA)QOA1B z@qAw}{tH9oVRA{LPW`U+4aLP?>^Z%OD|$QsFL zYDTw%WVO$B=p>eD2d^tQn~_M+q2B+VJ@eTrtrdkApxMeFa^AHaI0oUGnT5%QHkekkmjdd`9NqlGi zQEF%`{n!M`VD>#xfUW_WIPS#P;N#R#M3JCJo}JkYU=M+HequA)eMDm~Tnq+Gez78j zbDP-JeR6NS%G28s0-fp!(ink-;a(UM;Rx356XKf6=h8L=TP=PZnxva9K^aShD?|>% z4qydIN^WF$+6&A_S^!qM=?oZ7A_4{|@>}frr)@#F)M;%64Q@lTqAyX{of+b|=SD&G zNUP^>SMV}5f6QS>8P2_c;0cEAn}ji;opkPGG|ZGf46BCje#p3SxeZl{RkE%em3cNh4LWtQQdQz2 z)iL(%FoCrexo*M8A&1hXIpJ8seysf`UHcc9vGzKGbS)T4_43XROH3K=(wa!PQ|=Rn z?s~3wg6_AMINv6M<3xB8C&k-wu;z$aq_9`3@EkR*G8%y@gG>Yd^j8dgG`CqM%O%3PdApM@>iFY%UNUe}wkHW-H9gXh(Cr!2Nj z^ryd`u{wa2qsS#8yz!#o^BH7^invc$NG%zefY=+X0ysE~gCSdb(p_}5p&AhlD+y>0 zYDEqyl~>UFx|f4}%F>IZ;qPWaO?>rNWNHnCfqB`b3|C)n`>!8>UiVIFNk#TIT?yZwsePp>Mg9`AM#R;pZ z)_pV-)zfkW&bNpZZoZJO1iDb{$tqE;D0A*(reJO9d`2bcM&3+q)_8)cpIPZdbA2(H zMe=}ETxs7 z=5`=^rcwyHetBea8rWD#!Lu>|U%k_jlaaiXiI?W!%2onQs(+0Gzx`)x-C$uwKCkcW%NtK@_Pq%~_rRo}rZXAi10M zs6$*ZPH)8i=HtrAWUGk^Xal;988*xy(TmBvdoW0&PtE7aBIS|dK*XtS7)^4gg0LU4 z93HrB=c6r`szN_ZLxMW9XijioH(A3vm02xsUjB zl*;I}9r!z6jr zHHyN*<_!HgWscmNt}8@pQQ5EoE2*3-J$Ny44OL>Z1Ih1z>D#vNotA7G8tWJ%937^e zFT!e{xTH6l&vbtqO_SSs3fHKN>WQWlk_oNPK?CU8ZY6%2WfY5;tz^X*6Wd#BBZx_n ztOFFsjg}@01Ud4KB7#@FU!}8ke}#IBUAU8Z4?(25X{5${An`m*EYIgQj|$mpX>mK^ z%R(!~hC8sg{~6Z24qVwjtP(@#M6{vPB#%?lD@(EGs;MhIeYgbZzc$ztY9l;J-5DK= zNKTAZw=;JOh_5(9{v@fIgAUf&!S!&zSeTX=Y|~5Zo@NCzW?LufHyo+W_-giEUXJ<5 zJ)nD`4;>B;7lGMrNXi|s@6rf#kFeTtC-Q@&%n%uzb%T7A*()?swu$Q5<>bLF-Yrkg z5bK;d2IDo8D9J1X`_2Ks=Q@yk2nbNR4Swu31=q$qq0&hZ!qYj`wl!$}pgE=YG<6^z zD@?ZHrX8TbpHOla$sg{|ssKNrq+Pjm#yo?)y%1yD<8XF-!C9TE`GgwY6Us5$k87{f z&M$N!bDY*g&d9alCPLd=>+P3eRQq0SSSks;Om0!zc&g?-L9cuazqKJLPaWvwT8W}! za9v?m>FbqzG`r!%Xk9t7PMS)mq#77HS(|19u$c9f$EiFHE#P z!F?8oP8UN*k224|CVfby%dAvpv!O$&=Y}GcXv{+db($pABn{3&JNa=P#zk|aws!P$ z>Yc-EcTPaJvsfdl<2eetOG%9`(3ioD>DCqYE5`77H?k-Eq#>X)L3m#LaP3uI6zERj zBKfyaR@)s$%L*24y|pV7YErl7U8uy2CD*$P-#^HEV3wA2t^C}*Z!Mi|_d)OD&&WD@ z=d?8wRWq8b!V9KutX1#imw>3*mAy1Y95c@7K&J7n? zdxfmM-}iZ+=QnNLmXR3yMPA>0!5z`{HxJCZMV~qR=w=56-|vE>Ac#*3HMP++cR_UL z-t=Mmt0|AQPx@&}0g>KbvoKL;L8ucWUOm6dx*S3O`Aw2H&i;6!(Ic>}#V}v1KgWSD z)o}j#3+QYDbrxT6cN2Pbrm?-cps$eGQg9XL6COwaT3>)a-J5V&w^q!FAX>2h9xK1a zfZq)OsgGfn#tTc(mb%Ficb$cEsBV21?Ab0hh_Rzz6Y24PKr`fP0AOu{s;QYHk4IVg zeoUK_k$DSYS&V2|^J(WJNOcPtu#HiijIfmmca{o&?z(D}OjL-tJDw3|%HZkm`&NKn z`dnTvHKLHNhO|ZVQZwu*Trs;1u}#?bF<^)U*<3_?T6G)ISU9l5!|WLnJDgJ?jdZXb zE+1&w_+DHe*umgiLg9Vwe7*UKmpXg46ktwCuFHNCt$uIIm(b1F67ed`5%%*Jp}qHm zAlh(^o4=8=F3j;6@~+@q1?y6)d)UgPv60>VDj_YJJT|l1LBh~@lQOY2Ut9J7$_B7i zZhAk_X4DbK`05n&nUY1ODX3|HYK#?RG+yR~!?m=K6S@to13`5KO|y8VY191^p=gcs z0e|~VnOLMPtP|vjO*lW%(ieDbq>Keu zv4iV?l0-z$(?%J-aE>7T9O#RZIS-&+B2g0@{cEFXK^X(*(2EqPTahOjns3>EQVBvE z@YK_YCfIR}x9$bSQ+rQ%_&yep*Tr4~uje{Rn4@jP+&JQLS4IdaJLTl$6eQ2~~uWLZu+jxc_g84bI zREsw(Psw)dINB_ur5<68cLZDpRMDJ3=qU@~*!nA-!)d&eFFSOF#V3QFSAQ@+xNz$a zqaFu4?Stwq;`3B1767>6GC>C^hhmA=B4=b1h4-L!1EO_+D{`YO*51V~!2}7%&P8Y? zx2Gv8a)tIV=SV>tUO~5uTDXdikxUDS=I=%JO$enjy6gl18vNySbVF~a-|S{^Vkax; zsSYdZ(Rf59&udGFcs<5)R3@ZlDQ1~K(S(pXrK>Pz39D_o%Oke|?vfDog?{kAVBM!! zwDV1{GXj=G{(Ep&wkv+c^tP$sbuaSuZpn$`lK_WwZ(*84zJr)K3;)aCc!@ACy&m=nzGYMjebX5p7PkEBr}X`@{A zRUz{3nFn-+vZc8WCR6P(nv$3;S_F^=X_C{Pr*KhfDMUefbA>w}M1{F#FZv{IP<1kB z>7qq&s5phP5^eJB(>b2NT+u=$5&vOgV=W-y=VF=T-HPy;i*hkR)r^k1r&DZLfFGbq zMq>qw!%!k`gQLK0$4U(8zJ<=7eg)M$YJNYJH97uT)g*aI*`&=SD5Me^G0 z-PJ!2#lElWUCR2{V#f08qFR?CCZBUfOW%x70|+7^Tp1!reavDUc={Nc zluXm<9gPMl&e8XyT8PE;RRz0HADE`ZcOWUs`W(PU()L~@uRTAfKV4?{_9 z!Qu?(mZl%ymqPRUFnA=}#m zMJsC2Sj4?`$Ha!mXsqH6IbO39azm%xM@7Ubx=n21(RKk`qg0qbL7YX`5z{}X!_2vo zv5pxXp>b#~Y&HJQeD4@jodj2aO2-@9qiGl8=2c6l`S#UyfDE~hhAVrGUtcDpt-&Fr`{^n9izb4K}QF9?25Y?@Cb%iP%nfR6#Ojb;)`<1d>0)=$2!D>Z#aN zuo2?q92__!57p<8_M?vOS)9{(q9Ku`>&&llVV;#uxXe`L|0V(~h zaJatOLm(9{8xzP|*)J((NM0I+@IGM7^77%Re1Zh;5J_;XgukB(AnUVWHY->)L?F2fd~Lvl{ap_3mLUP~GjuSq-B1^5syXupTqo}4qpFr*sb26 z=!NxZt5~zUD`-n`_P9lfl-1e?B3H2_IW2W2}*O4_Dj5jyB2qJV;Lkh7Kd- z0KjD@lLRs1+{OuRMJV7#i@JTdEp)u#)PQs8)6`lE2+-oxS;-&98~^PMD)^Jy3Lg4gf2b zlt%rR26)i_m5+#vbYoOop$U8@0CsL@=Wv5Zy1D`BOX~tf=S6W$kp;Rjfz%3g(2HZ~ zdXWy_pUwl;2(e>xsJCPxuGOBPi0h(eip+;a>mUox$`4XJK?bE&Z;94;K0a~K$H9PU1ZOqIJyxmC4j#s48$Rem8YKwxI$$3Q% zTA=xn+xKHj6egSO!#nZ`N#gU4ciBC*yiVp=Rww5%J`Fl7GYQ-`;7IunRsn(|TZ$L@ zUyM@{Q+$~QBa-eAs@>G-sgU&t5Ts>1lt*65J(3b6p?X8kNFojXDi<bOiSl@ye!l1fPkreVcCRlmxa-@2E=Q z-XV2(0Xn?aP0aBzwz8N6n7`wfw| z-w*z9I5=nufOCFe`8o}d&&itT%UFJ`4V>CHBdvnmqSfeb1)vZDZ1HWseWK&gUK*TI z{JfcX`;^$&$;3jycI7BW6PkeXz~Lz zpJs;r0Kek{VM^Gv6u$)mfMkdeso_PJz3zFyIxqD>&WUcx3y*}J?pgmh#GZ5HQU8VP z3IF-O1Lo#%6jq<`qKv7h`|~Pw7Sz_oj9~}!fiJl8L_Buh#IKcJ4U$rl!EB74-pJyU2e_ae#zb44E0VK|y$dl90T!(PXL74;9!cj!_GvawQ!HR&7cXt0CiUUo zGR8gSo)O{UQvkhvg&iBLjv-l(z0b#HcjTO@h*TcKJJ^Y4QCt1-KX9_e zhB|xfFiKEJtsJ@;9c7u2f2erRv$l>3jwt37vFzj|*b+D%(r zTb0t1@01$!PS1DSrst)lKlLYctnesyTK?BFS3NkdO=SkHFHj#sXtU-radI#(5!(!l zr0RQv9QnauYz=B(&iZE{5cLQ2AqP*{7%_GbOmNgdxXNKI%8iGWM<3s|-yAH=3I!XQ z_IQ|dp?1@Kqvw8_E9}3Ewm;L}uEEa8cxls0FAjZ}Ag>ZRBD9(6n)l+`krc?T2HOTd zsZ|sR(*KG0cmk-*ym;wCrrh7?0D9`)?o*0?>z&tDe~h>t(3mijXh&ShiKHdd4akQz zekfh(K2v}0-t!IU$%$=4Tk1HY;T?@}UA>mjk7(Hg)JN8vCR+X6H0P%nl^N@yX5WZt z-D7CK?qyz^$n@nr-D2thY4T;Xo6L0Nh_;Nf9CK~b@^u@c_)8%7GcvptWP%hG!y`&T z+dJ(Y_G+FXN|%dUc|<4@<;h4!kvhx%YA8aw9J8167Eg<8hM=SJr(4JlMQ$U)ZSw9M z+dlGPtC=4ib_4KasTJ(G3pVA;`8gb%Tf%yk{A@liYmRNoTA+>|@z|}Z7PF2_w&x`h128xAk*wF8 z-7mGLSVquI27pFGpfmMB@{Xa^B_G6#RQ1G6Dt=Bd`-!xCifYD7sk;xw$_r`jS@+jJ zl2sEra}w^;(aXJoO-)Svlqr)&$pJ8(C= zKPdgso}|A|DA(S+xr?|ATA?k$@S5l-$`;f|K{sYyhlm1}sZ^1dG|S$^3YX)vu{B7g zd^vrEkOnV|cRES7eQ5kEf@YKrnKk~(wnh>%r+)rm+nZ8fc5X0y$hCQ~{(EMchpKBo z#U5R6Zy^^;a(sNUBpx0BS>kp?$NeA@J_^~8THo`o(5P+ph@IV?d*f?|uSdB*Se)Hg z{da5JfA9rD_nOzNN%j3<^6^q^J2RbXrL)Fcu{L@A@=@`*(>_kt(B^#U%w9S~foH}N=xe<(a!gI(hLuwunrqN(ef zP5wUL6B@=i9ief@gbh3m^WY{p@+0IjaJuo#h8!CQoiu9upEje559-bE8HiMigPef5 z?L4rZ{SCDD{|le6A@=Lw@R^>6Q~YHi>PN$_QiHIm+YZ~|%h^Rlv;x31|6z5>IqCC! z?k~_$IId#{OuBYq4frSK4;f?OZG&h=6>B)uqIGQVIO{_9QDk3kzGi&tF460Q$Vi*z zOxcPK9PWqwt64|e>9zB!OiqM=h+1?us=5-kx3aC!Xc<4Fv7&=$8;m;opa; z8Hybbr75|cw52RMDCo%)M|5B};xp^}09#kk;h^^zZb+R2zhN6IN~P>ZZKneV!Q5`} zNoq0;qqG2#t^J=ydr57)QE3a&xL&o4AvVL#RAXM+67hM#5^xR^#z^g|tVUjYJbjcY zL#M}8%mO*e>F)Jcu+(QRCFyjsX3l6;>T^H>Fb zw5T7S5nS`EvWex{M#tCL$0%|W~h%BFpVVTiOX`LYL3+{9iZL~`rTZfiZv6wA%eOICZe>uBXw+20qTvBw@6eqx( z0CeY-3Y5QhAhwq)S~5aDT#2n4W*Y{*3B`7g%v-o*l%oNi2-|R?FSKq`->_1 zFmdLb`>Yk>ClQ-KzU7fb!Z$FreL7xX$_i9+Iyj~*lDtryP2LE1N|e+rk#W@U#PUb5 zdn(%z0CC>|c_I^ws{+zmtC0+BnX@jZ`eX=tTGbKUJY1*uH*^eU&MdnRG0~AyEOZ3( z&}{|GS3AcH3xeqx6j$uWS~R5G?+UChp;)00kQKvn$c8CnP;(g?SMdE?bdHTLh2Bo> z{&w=&8Ol!H-ht8)0p@opZZ)E)h{sx!@HR=;4$37L7)n4kK;@P!!tdz>_7Al*^?{$-9xJ z5Y)?gQo@C2fsh>Vqaz|y2Hhe?px0fEf-{A^0e&l-aClkIv3VW2@TU>I7>!f=K7&a! zOwe$lCvAH^OA<((A_BTy;{}m`RF8l}bpdbyp~`^ZRd`$`Hb$rAodQ`jsXcfSz+|k3 z7T=AJkfOY@3G^zMr^AT-WTru1|EDG=+$YYcq?Kp{B+ncrVAB&Fyc*GKR0%JGZSx2f z-(^)Qd$V<0qKfp;>x$3=-Cc2)7ji2V#3goo)Q=npHipNvXuC)_>=ycqPIuzJBXc3g zAI1Nu_gVBzz$)0=7n^e?v>raly%*^bR{UVvl+7SLwfcpTR#}2 z*6<@ON8$*zjou7P61nDn_AaAI>Wq$G+s5uKazo^6SIuqQ zzXk0&Yrv|+2ch_V001;Pf<9ZHtn8t8ZdM91*=|FC=x*|-E6?XCo}hjV1q?H%}=xGfmOc{shV8d}2yXNq-p#oi^%Fjgb@wZz9T$vG6Pr9*TvXQZai)GlBjTO?FC)LxFouF1Y5(GYtBWZ&ls> z6@tJ&=CzI8zPY|Iwkon=7ttM{mHwLLQG6>5Ujn%d3(qLtFchR2sXW1Dq;-MW-aED( zXmY_}MZuVT!dRvM4raRh2z8ko-SGVmy50FfayVkqex|)>9sHycG3xw*>|ZlJG5uuB zyG_pyqiB;Zh|H#m_)_#*0)VC`)@ttwboQ);E`Rh5!dFOhbl+luK&S8pcK~)MgX7x8 za3;1BA@HzRIgQI%9%FB}XC#KR?E8Edo;<-pt!iJ8bZ`_+Z+_5!FU65s8T>J-(tjjP z2-qeo9Z+tf35ea^n{Cn+ly9&I{(dmYNkb5JhI@O0r|e)V&_V?hlWVXgPCUq61}2IL z)KJxaH7xZ?F@R~m;KmkQe#<|2XM@q3F#~C?Vd_2OPo$-FXZ8<3PdHXlf6nmFa2Xz? zl(olBKizWAXQ{8=E0cD8*&81j9 zS{1fA(vU$}yBpYXpFEcjX!GE_BS=>^w)a64XW2|~^B>6Bg&My6PF21A<^%AHjPk?; z3%FZ(@Ky;#h68RoCF-`(pH~3zt@g&}{ouTuJ?huU+EScTF)(lEx5SxQ_1|;O27@ce zM>_+)U+V_iDR^8iZKHAd^%J!SV>i&1npaL>-e?!%F)0@n!bjV!>6Y`+@k$yuCLItI zR68_@WJZfq(9$OCng=QnX|iy`gyDe7HQ~}B?qPnwQ?6f7EDryYW(h^~&lj$#dnzo%UPzW(H=z&k_1f#1KFv;4wRn|Iw95_I>M`00QJbP7H8JkMYzo#jHb0UmUR^Ub_!R4=&R!fh0y}c zd&n&ssA>W+7ikVCJSyF{p$v-YNQ^`-9u1fM{tNKpNNWWtF|X$4f2(nQbE(t1m&9|4 z^{jTluNZ^EP=SDK-RF1ry?Nr#PpFTnSGG5Lz0~q>I8r;=ETgvVhF9$AM>S(v(Ew7bkHk}`s6hk%o;P((!DMCNDam-Q4 zOtgYy%Xk@KPDkT)7SZ9p8bX`ckdZfXDa1cP-u)w<^iup|;e{5K?O)7H>+ZW#m&J>n z*{)*%<<_UH7S$u+I-Aexdr07Hyqsi>GCM>Y(IG`o{5~`T(N|D&gn^{a-j!(nM+E^} z2Q%`5rQAA|@zf#7YFx2Q`f7WZ7+;1mlz3Atww{v?L_@h5@ELhUOG13G_IIK0McErW zd3Y;P4-94|uKoZVNUPGhyrKhOKEDg}0a3h_J02-`rs&NUkCPs~T(V?%M>r4r<+GGTBDfOL&c)d-@bm01MGl+3Ay4xoUkrg@{p z2ToboW~4;HodM?UZUSWu$Lu6a;lKG9O25nEc#Dv*R2X9&^&bpJ3@cr(CnzK9oE=^a z@4{E=3|U4eQ15d!Q=)Cd^Tc!q3fimrewwq294BCf$cyS_K(`&upqj>j-w?S#N`l<( zqc=PA%gTABD6K_j`$YPHRT(lE8@k7yelkBkra5HUR(y>ML=X3>Z{Hr_up`sv?(L0d zvvv(Tugl%(cs4F`4!4EH4}Kt9tLSncs1U z^-l+6<#wwf)fscYQr>#G#e(%&{cSyHbhBitSp!9H4sn&MDo3sZo5aAyfJq3CMsM#`O?0+L$^Vaw}=$u@G@B31$xScT?)(tm)&&FG&|i0vVt5uvvt zo@b8j90c4PQ4t7Q%_2vXs(eG4ZUb-8h^Y3Hk7PjJ3Zg9phN%wX5|nomp1ejr1w7Z31%+6u9R;fv_p#U+3Zb7 z>|Mlp?iyloY*4fol`5Vz6~Dh4o?EZ72SE>884H4}>QAGwH-WaolEn)GCvgh2Wx{z7 z3aN}3w(YnJ$gLNg$MhuX*(;QtQ*3=i+=aJ88H&yl_@@)BOI-_BhQ)FdD*kjse@z9& zv7!En5OH{>=pLVLrUwnrv+@E5nPow-euW{&i#`SjaT>Z}?#^B83`#?&a%*uZwCj(T zqD>GPINoyr9sL8`Gc^?uOv@#^1AFq3rhzfmx>RO$)x2+cU1Z6PH6HuU`uy+!hf3tc znNft$>S5F|&auS2fxU7bHrwFwplrq`wE`OG{*W6OlWK$WWoP25f~V|RU~n89%pVB{(3%2%bcZCP>Z zv?gsyEHgFC5ZH1!cx=;CQD2?CAu*M>oNQDMve#~R^s zWQCU(7K>|#uU$lF9qM3OtLmC)6}m=2OxG<1jIS6p1MZ!8Qxpv4xfE;sG8R{%&Op9L zuTbnp{ghX*i*f;;Bysj@XD=W6gvWQ4v+7=tx(IRPu68NBAHd2L+zYN?ya_|IEGlv- z+osqiO(-9}4Y-TLm^&=(>`mn_VH13r@I2W@(VIH(o?{_e^&IB3>739|Wm8D~C9z|Wy^JLWx5P|jh3$BB zd*BE>lE}*pQLvljn|mm;)su)*djeZ3@8x1N#J#ijgXo)~`4B1|4R0&5=)+N7zl6># zzG|Ii18!vYs;<%xe+B`jqH)LgcY(ir$6H>VU1_?~%qJN4uaCM2#fKxGWuIpc!;@_e zj=&hrv(^nrjUZnz(-*BlLd6}unV`yqr7Bd$uUYN^L!hS%0J1GRn3jg^FR~e`xiCA2 zxe?R&M~2VV4v`PIjbCw@73`u^qHbSsYx(jKZN`|;ZPOy~S z0c%qZ?Re=LtuGT~&BUk--80y$(Y#K!-6#Se!}M4$yB_4o$@lqzYGxaM=?Brq_@FJH z-jl;01dX43h2Cg;_ZpC*>BN6FNjW2P;P9-_x+HpffE3cZ_+IL`v{heoc8Xmvl(ZJ-6qoFwVX;z>*T3d{5MC=q!k_3*Np2;TeMpW%Z&f43Qjac}jL2$_U zXb!!C!nGx$Z`ggndp7$MM5>(9t!_w`kIZCMfPpfVn+Xg|x>X1vjlBjsPz$^%(KSMM zxp6(vPFfR3Y086npfru!Zsv^obr96EaIJa*?oefsZIras3F{_p?SHiuA~%)~P(nA! zdB#zVdF>qiu*gUa3EJ|qo}Lz53bJqNd%0@L;*b=$K@#$Y*|u~iZX#Ke=bm3#?#5d@ghmqFo z<#1eEe0=D6l6{nV>-(_H$nfJmPd`~_GhRWnaojISCPeVtUpbD z?%ho#-eO8xTUb~z6%2sX0SHjL+Hdn8qvbHN5X2wCH zMe@QeaMr#>2y)&vVBIo;_Gur+_=U!GJP|EHD21RKwZ-Dmb%?{rF|?-=OcliRQ|Qr$ zQdY8e9b$Bij1Pa9nBc1kWIqQlmHC33Nzj0UXpmz4MmHqd0JJaEP;@(}{P#~9eWcXc{A|4313H@%)@!!Yqz`fPk zvj5`OQxiE6w53nxQkYYW#UX1F?FFz<{(c6R9S98D`3yeQx%1|e2bEr`~u%K6o zBbqpip)JF%L`zgDq1r&PrMiKIifqW{6cd1tbaU|;x-q5?$IYBdsEPFWG~vk&9-z3f zIERqVKk^#w#b8i0i5!dNwUb69A?ED1t=4)wE%QDC6q$P0Sn+d=R|V0$-jIg1oJROi2f z=1^Y}3YuV-vc;<%q?%Yj`|vw}0#Ol|EHsceAf3$s>=CR8g*6HVydij+T)b=uphvG+sU^!}|BVAk5Qdi*Q! z44uk#e}{R(!x{IX{mJTrm)NqqtSp(ADw9IQwhwWlt7%IAhM8hH9uP)ISP3i+0aafm zE3CPjX> zuN59;Q=wqnnq(l3%i$Q*33!Kk6q`-r6~_S-KWlXb)&vPr-orbXZ!s(Ghg#f%g|c_X zO~YnYe1!!G?L?a?0A-E3caTOI-tg^8K=aqJHXo~h3iD?zfPKTNp_Q5HUDHYQuaqz(We={7|W^yT4+ zF&u;U`NTw>CCJP3LyyYlu3a&bG*$K*N3k~#$HZ4N72F)R%4LyQy51$0NNH1~3(1~(1Vsce@~^mZsg zeN2R21K9Q$JM{syUVEFY4=azooPWj5smCu)xT$`I0t<_I#KQX83fhB6;Ly%b<#rIW zGUSs;ScBDlqZbnv+6-|t)fzHG{S)qC?zP(A1=u>xkJwINzd5B@hrSq>7jlzkp!3uS zK@!Dd7}Sv>CeVNtA?}hMPZ_sOkQPkJjG-;Vwj%o;L;gUVNdw6T?a_X1euz`2gF(T5 z+>~gAu2b4@HeUszdbITnQrcK}JIxYssR|%f$#4Lja`hCwE?WdrA(TYBh^y2#5)m>R zAsc9RMR1m1pcqXr&?N!_r|li`1A7x1{ji&qLRq#xuPm~GvOY!MPJK#yLwtdnLM2kq z_QZ9G7SYXsl5|w8X2MPx!lSh^PCCG}SD|OXxfnYFhTTxq>h1)}JvyxW4)s>@({&r^ z?;D4c719)k9n4gs*%mi}Stx5f(AI}r(*H_78%%7;ngfupHdki_k@~;lj9KEPy3LV% z8_oqH7wj#k4riJ=8tnl+lw1nrN+2D^;al`NaQu=KMj04YvmgCyx^+z4+N^)PuTHQC zI{+UPD|>Uo@JLQYPMwzpNU=DhG{Luz>>^%Zzu+$wZF(<#f}iz99D#i5u}>z&0KJM& zqqv}S88h2ho1lje>!fTOP=b zQKeEAKOXtCS!H$-6?BdjUdL%8;7KfNjG(<%C)R$Glt{G{p91qsUDwRNNPL%v`k7`Y zdSh%2Aw_2hj{Hz@j%a1jUX2f{`vmw(Bt+qqE{@)|R^*}^MDSeU8hE_x>Z&+N$L*_} z4lVuAaJ`s2=ANqBf*Dox{Gzwu26w61sFUDpbVx%Lpz71gDx)TB`c(7Id!`R$h7^pC z7i>89wDIYGet+)TzunidC@8~K@81$wbp%#rfY)b-ImRM$s$xLV?*au3eQzwG&xD z#@ag=Ri2>l(;ylkA4ZfdbkkFCXhnPTdL|GqeQaOB+OF`)a+?MIn#zviSKXi}8nJF0 z$9S!d2z&(Wa#!7Fy_KjC*wfxOI8d~ODi_EK?p4FXU8&e%xLdL#N3(;$dF<1LH-;Qh zX90A~gOn|FubOJ)%#!3@@rThH3vn4Lh{Q~YHK-Gtx`5b;>KTi~t6IUV^Ig_}oS!6& zzlb=3Qq~4GjfplD+OF|o_fzeCl7x;*(h}6Ki$nOSZXD0`xXdjNrCm8I9UYliiFPUM zy(QLyxCBZuLuO)LU2i;JJ}{5N-zJkZXR)BBLCR7SzYe+{^X$-nQM>zSeCsxro%~iW zXl4W^Se*7L#?(+=e^{Tl{Pwk0CoqOxQq!)H1OiXag?MWWsw{ap*6)~ zpujs@|96-)`v|DaZQ~L@HFK1tnYXeWJ4Lg2W?sQd=Qx~2kAvxLr^Xh&sTh%n$BjC5 z-vV`8(3vXqcUCZf7LT^`YsC^8F6a$(xUmi?=exJR@zJn{Lm4OF?=QpF*si%n*69d)Xwk4@4~h0#>-h;{{j#%n@;ZeYH8!5UBje?Y_>l?r7}~0NRJ0d}`}q?(FVL z)=f1BxqYV;^5m;8Jw^?_7A&JIkR5EHkal=S)}VZe$QUh5P&OZ80gLl`xNMkP9&vRf zZ60s@;ifos{;6<}-gDhc&J%G5HH~OVjW8zL0pu{0i6iDv>_A?IdtzNqTo~M&Lb2C% z=*)qx!(DScs!>;X{}tNZ?w~(NS2Oaem4MRp(e!2Z5u2Vg1h8NY4jb!Q0lZBAYz1MYHyEl!8dJX~iCl!~|!BDwmF5t*r#Qb}3i19O2Ept-@@zcXgIn91=J>TMVm96auqpKBzGA zM2~J*#{zgKx%<< zJc8oPTBK16U=WRC0WxcaR8xwTu7_^LHpXaZ6H?oDs}J;RN3ss4B`_(N)=UJ01%528F8jb zvjrS!__QjJ&ww(Hy%dHcv@WUz+a5X&dUA#hIrhODe;MESc`=Ko$bE1jLssq7=71AD zsvDZO3_VN^f%HCBq*5>7Z5c&QXmn`^XqxbAZc5l|L8wP{NZZ6Fpd2hXJ`C=)$`bO? zJ|PEb+@SLXvdIh`aq9M%p+HW&CdJ2uZtoH~jEKxXG#vG%Jg}NCq~g$KA< z62$JC@X}U%;$XAq9?BEgzx@umi)h5Wzi5^d0Ic zdHS-Rnss{OpWY4+YC7g$dLoo{`X7l;e+!w{N`w#bvp=gjrb7Dt2;vfQq`()}$g$7V z+Hfx0I?RFt042(stI5N3J~EyF0A@8 zItu_O(rgGo-8t=aV|2YnvfvH|;M_2Zs1BAUvsZN#LmO&gRR?}4%2Z!Yl5~hxA|vU- zc$Y`WO*t*SUTlr_wh`?xI~mQEb*WPXGQ7y{<*oNV1O}z<)f@+H zBVWQ2ZX~eu`ooAH$ap6KX(+Z6%A9?yhc?WY&ZC3Xhz+D0&n)-qlj06 zGJOkxYhX)@SEW2pLbROX;K^3^$AFOc!M%_$G~DM|^8Nv5z>O4^?{&`Ja(jm}kY5jy zdaD2UW`oJ>{F~=F$9gVqew%J2(b=FMmCID)E7`sIlUcfT=y}cx)}+FxtryRD%;#Rj zet61BBjT$m>%O`xu10sYWQDHL5m*}E=wFC>Z$1Fu(1q0Dyj2Zm2S%wXsPDSw;#ey_{Aqs%z{E7!~4ot?=3 zO0s565kGmNV%-AV`vtfC7|2s6-RHbi0i;JWEumsPU)`<7qGAxREzbIaQwac(_|a{b z%@|iQ9ZjG4N`mWZD-&+eJq9#K55nh5)V{e?4nr+nLQ`K69oNoyuKhRgo$QdI!RJ=` zlBi%&jzB7G@KAB<)kr{Am2WY+GU{qv27muZjJ}}tYLQt;GB^rOqx|;Z)6(v>c}u`V z6p>p#7x1IW1B%@%|MiuwV=pSUjD5QNi1E0)6#d3G_Rp%*5nJvJmvW4^PxX!N=`kt2 zntXCy-4A^&=1Y#~WtC!9@a<&xjLE*R&`mVk&{tB{Q{YxGY{+WQyLz5?O0M;YKK+Kg zdbLPnm{ArvcCPf&_kFt~BW-&oZFRX<&fZzGV*kvp zogkZS+j~Bo6nT}F9^35hpWLx+JScJ@wj$-zxXDh_WW~lyr_NNMr-%E;|1bOX(ioMS2dbj>efFnq_HXu} zUF(@BAgJ(p6`@4qE9!0UA`f;4eRHyVW9Qjlb`cJuvFA!!?Q5=APc`~ixgV8!Gs+^_ zO9rZoMNJmYL!ScFVdhC2R2Ob5h3Bug_Z#AjBn4{{;vVEMkJ}bvCJfF4 z&NqE!Mmxqz&=Jv;Xknxu6)YI7;^iQGD6(NPI#-|o?p20Im zcgvNA*JUgkSN^m?v##9(WY`+$Ix`h7m-#9O*niy&{(>v{vl{<=*Q(wuGTtypUL6+d z89MB2SPZiKipuQEcqvsDM}|nT+I23mp}Ril2=zBUAN{S0>8$PUzT_#vkFC9Bwg#ud zr!s%DV%o8u-MY5C3flTt3+$~gzhUf{WV+ivLf>{kUX*w0Li83lKaJg<3rp%A_X(Fp zM)|*K3=VzN&;Ua}-vsX2%MEACFGQE*PFz~M|2}TZC`4@-*y8-DaC^J$a6#$ljK<+s zMWk-|qk%2hGtmHX)Kx=Y(h(m07DTp``uulKfeWs18>x4fm5Ye*{&Qc{%djaz+#jr@ z{pUwyO)oK{OQy|kbr-#(cRaJyncna^&0zhQv~t~Gz`OmYlU6Fv?Z19(kqlnEEP?qz zkRDq$IJ>2Ez}an01-dnANB-Hzd$%-3SEDe0Y_{&hx}+s%AElkGzp^G{?3=#gLreK^ zl`HRY$O%rwL_$*cQQM(Ht{OmClJM$fcS!qc8R4L+#f?_aU%cWvl6)*}t%z{c?~RQOUA)CVh{D4sp}nDtFdzwm*7!D6GG`&6-&`k+W05s19IIm+kh_4zw;mvZ!-sh39u--Fx^aK!^+^+6gnj)k zxy3cF_gu4<_($&TP^L#ew(-Y-C>f0(%l&(xoSzMM=VG3U9Hzouf+u2!;M>I);}K0K zDDC)UTPo%lAho8fCE^&3w~OVflp?EvVb1apv{TvI=wH+Hu&gaOB=YK?p$AtcQg^%c zcq=>0M_vjHVIXrR7ZoKx} zZR;ZR$EgbW0&Dxn5o#L4!r*-|F2ssts@ElK1Ar2;xF2M_y(fWj1^0jU z^0#C^z@bczL-vzA<2g{Jswus13mHs4SSiYyl235>WDO@3NBo~&ZM06wLxG)3Zr7+e z1oN(|XP3p@h!udB&a3adJ@a#?)II!;wEIoNyAE8e_<#Bh|Ns7V9TjHC+7Clh7^z z_Zot%C$8A;Njtdg&$|vPupEwm!D*K`Z2f{0k=?o<1ECnxD zsRLc@aSlKzeX^-4o(bq+{lIqp-*wSS-8YEW$M?1hq5=A3>jI^`+}A=<;AnF0I~NUk zpX$-2XHP13=(XK!#a+JkKiYfpcqrHJ-)UsBHIgk8W2=-hNJ>P=c4diD_QGTxV;M%m zP_~q8MJ3tyE!l1eF-Ry|wid?HawRiS4aWFA-0%I~^y|Ohz4!Cm#>Xu0%sKD#p7*TJ z^PF?WFHUw>oD|`p5kd$lO2;DaZ66l3Jam*WI({IqIJ)EEsr%Yf2yq}+lsyf=Kayxg ze`^Cl@^U^1=e=eEcEil1|y#yQF{zlsAR&HxPw}3IT0V9`jkeg!Rilzw02CC z%0YovQZV=H4>kgHxrr`RYx(qH_eU2d;xcd55pg)h=pyHvK82_TT*bNfp!l4_$#{@ik#rIL7I>BWr`h zZ0R}y+O@Y9?s9cz?uzb2n8?Eh!CLHx)Onu!D^OzxiKzrS_mqGnWp!yJgR^=Cnz#Xx z{%haETIowBeOc5;BRkXWKKdY$v4uo;y|&1ToLwT0XW3L6??4~_Zd$j{cIM_(NBDfP z)+U!b)#O3eFXQ#f?m~#$?Ypue<>rx`J2kA~s1s!@PK#$nU%#B(0$Q>%=kks?!R>#% z?+d0!=>}A@=`q#haSX5D>Bb=83-#Mu@~0cPcT!_6WxtrW8^NRoj)PseT9oDUk4uXh zF65ye*)^L~&1KHH&$!!*M4_i{%aVS8QJ;+4%QoUYcB=Nx zv3&<^sRQNdMib9@7`~veMc9Rl_61ysU+#_S_o@o3<8$B8OU-GL{yxQFDQR^yOgJb4 zRA){lQbZEcRP(bKvUFmui(>T%XI0Jh6i^Iy*t&7H#5u3m@|AjSR(DeLYc@TY)W^`9 z_OVFd$A_vlsm)9KfpVfOcYwnwu@*~{LP_t;$~_q#r0fGzGoLSEmFf{0#PkesHVHGJn;WlrUTArcFJzezH1X6Ifbu zOIeGo0m|^iUY+JQVzF(a{6mB}iRiCY+Vk42Q!K!9`G-fmofM-YP4QFNPuwdaL}i$8 zEVHml^i)iGNYYr7P{AE;n}xTO0jl@YL7LjK8r^8d67yUb}n;B1SMID0&LQTSl8jM2LYB21MT;!od0S<)P*KQFi)r zlJR9hyosd%@)KBb@{ghvNd-yekC~JdU0doIO>4h%c-V25FJ5I-NxK^CWzd?(%_22fTGu+_EgT* z4A(cR)Z*t?f_AzvxqERw);3R{z5Q*v?T+W)5z`S9nR zeUhvmW9V#<;;hViGn3@nM$@0zS(5l|k+qj!KX0jCM} zb*{?R6ViKoS`w3Y1T0PRtx8rbaNOD^FpS-mNamhZ!4dY&w2Vyx#X3 z8cDxoK;xHe+x6)y-s)iD=bavJgAX_SQ{&vM-=@kFKH5w)MRNPqXjG5zd`uz}d&TAs zEX%9hw9}p%eS|8gDZG9(ZFBWML0veStcnaj0=G(F@}LEkVs!dP-R?;?5O7tdRf8sE z`Mc+CP#a_YyFs*q(A*i8@gzWVVk0K&!}CfNy`a3>A_^`q{eHpzuoI1f8&zE^XS*Ou(40WwXHCIj|W zG{wq{wi2*mj;HVIrR1hQKhx$}Z1!{z#@hQtzY03@<%orjVCt#|q5LT9~#^9CRf4 zW4#J+r)EP*)Efh&h4M7`|J(zcjmTf$C<@eb%~h6iD5LqcMdj#@X4fP~sWJ4>h#Lp5 zV&z+=uJE=-b0j&C6!s{1fsU70+Ph^$0I-yyIbd5uR|^P9hbbAl| z#h-zon7vUFK@T3U84VMX%lz%UR!q}klWseR>I;kz5w0j)kP!x`-7SED|d2{=Ku>21^Nn;}?%_G`%KfRh7?Uk5yQ z_h()u*GRw2@(k-QGFKUjM7%AHQh_fCwJga7@PK;l1_G@?JE(l`!e#@+med&7K~-r6 zYcInxpDsCl2N?zG>Ni1a#9uTwfUyko7M2Jp1RCPAP>wL5eBymz0!a!Hk8um z!1j25;hp$k=AmwdG9SwHiF_Nd)$!(woKzfZSDQ!k=4f#ps9gG?@lG^pMQ;*kFpMi8(A0auy2H8WfA6JCIb=K@LqGEfr_WtGHq7v>fdw(Au*BSZIje| zS`Txn@*?5j;uiV#0y;L9Z*actl=!~$I-NxsJH$4bc|6l#JqsHoHK~td7P-HaGEj67 z-Y0<=>hC%Niy7Z{k&H}pjbb7OB+Pog9B@XNQ6HXpQIyO1ajOM!PgqQZ!tEQN z8MqCN{k_GW(vZsAd?2Pb17)9O`1;M8;CX>KD^|2DXTgw~{N=c#LZj4JzpKp9Bd(y^ zBNHrpPfbB*14Q3Zkj;!akWOQEWiWLiT=OV8I@Z}a19Z#p*&!+TRr=)>NWA#na;OT}rW368-s z$b;H0Gd#78kB)@cr%N1MEDu^?;;L8fYR_HQk~ifTOlIXYnY@vYr+k^BxgfL^jM*i& zR(Tu?dDKwnA?{L;m=&h(Q(tK|9&8G_tm;;JkI8Q=#(pU7+^883JCWPtp8U4eP;Be1 zCmhaSUSBeoYS=fF(zv-U;bY38vf~ToCF{G5%R&TK>V4L@Hnalrz~#4etIiO;R1+W8 z%(jQD5}$4bAz>h+4{Htw(BiI@jS#f50*BUkfID- z%lU3QSbUYEL5_WTm1Ja5+{eL~syOoS=8e7*3nKSaO&`<@R~rndYX}60y)CzL7{f`W zjPi|Rmpr~`I_S10<*AhKQDV5@O~&nU$1xRvjGLpt{U5p=yfGA^XDCc4aXfSZ&Z z#iNqb-Nj9M@nVncxsK*ZqFO1&hL8G2 ztfyPfj*a&YA+Cw;wGww1J`k){SgAL^jn*jp`TC*cdwA6;<+#ngk^8mKRgbwz!nN!; z1!iMYzP}e!*mhj;)wW9$IhY6+(`1$%w$DzeA^RmTN(Ta;6etEErh4W|yBlH$X$QOK zrp=lA-btr+-cV8VTSokhlV?83+&c~U)O7;{ZTX&)?eSjN|7Ybt#Wx_{+V!%mVAw2T z2^oLUpaPwcmKfNbY$({-Q&t;Whig{&CBAE6Rsc7>7gc-wS$nfmgk)i9!Mv(E%Dj*_ z45lt3Wy6vGb+`ZSfuL(D_P2S8iukhf;FryYznp49J$2Q^Qet$V%80LNZjFy^!?+q9UjQ}=p zdyEIhWH-@b1}~L#rXpFf<3(9BLW3W8iBI_%QrACWBy{XwR;eqa?0#j41$CiQBMRzI zE}LyPPTXYpkoCN43hwnGrBU7NG=1u^_d0uTmpy!WahLilpW&TU?{*~TFSAvbSyp@x zeKwwqL{J_&&7YYpa&!EKY!Sk4Vbe_AyDTM>5gUI?CJ`SPeDzyk|AdxL6irR;bNj1Z z2ekxE<#VqNhx)NPXnyLLjSB>t^LM=p+prIqls^oON@c8*C*a59K<{q-lluR9XQ_#I zCt%$PwkI!mV7;wZ`O{c`J%Yf_llQm)g4ckdIo2U40H?I|!n%25WLBSl1l&rWxxWAa zbimJq)&ag}T{C#U!xHgcu6B65>*~3Gibtz`LG=JrQW>8L#tF#v3l9fAbcftmtL0Ce@d-cDF7!5i3a z@FM>+^2s72UAF*D@kaPZ`U~=`VIeqSaahdSv)s=RtSrX(-2%f%{ZGTN*!I(5e1`>q ztUbgaH0qYX-3SO;{TEnwF;XHB^lx)ZaPq;~xu0`(lX3CDI{rwJADxyz@hoKjPRt)& zm>)5$xAT9(Lm+$hyJ7sx>i-D6UblV^-JAa%^dFkmSbrm6Gzj7Ze;j~$&K9kH`VTX7 B7yJMK diff --git a/pandas/tests/io/test_excel.py b/pandas/tests/io/test_excel.py index 9b147d53c06c4..c79affaff3c1f 100644 --- a/pandas/tests/io/test_excel.py +++ b/pandas/tests/io/test_excel.py @@ -235,6 +235,16 @@ def test_index_col_label_error(self, ext): self.get_exceldf("test1", ext, "Sheet1", index_col=["A"], usecols=["A", "C"]) + def test_index_col_empty(self, ext): + # see gh-9208 + result = self.get_exceldf("test1", ext, "Sheet3", + index_col=["A", "B", "C"]) + expected = DataFrame(columns=["D", "E", "F"], + index=MultiIndex(levels=[[]] * 3, + labels=[[]] * 3, + names=["A", "B", "C"])) + tm.assert_frame_equal(result, expected) + def test_usecols_pass_non_existent_column(self, ext): msg = ("Usecols do not match columns, " "columns expected but not found: " + r"\['E'\]") From a197837c4067469478b13e491a21b58cb78ed165 Mon Sep 17 00:00:00 2001 From: Stephen Childs Date: Tue, 13 Nov 2018 12:52:41 -0500 Subject: [PATCH 11/25] DOC: Update is_sparse docstring (#19983) * BUG: Identify SparseDataFrame as sparse The is_sparse function checks to see if an array-like is spare by checking to see if it is an instance of ABCSparseArray or ABCSparseSeries. This commit adds ABCSparseDataFrame to that list -- so it can detect that a DataFrame (which is an array-like object) is sparse. Added a test for this. * Revert "BUG: Identify SparseDataFrame as sparse" This reverts commit 10dffd1452b50af101f26b331cbfabd3ea217434. The previous commit's change was not necessary. Will add a docstring to clarify the behaviour of the method. * DOC: Revise is_sparce docstring Clean up the docstring for is_sparse so it confirms to the documentation style guide. Add additional examples and clarify that is_sparse expect a 1-dimensional array-like. * DOC: Adjust is_sparse docstring. Responding to pull request comments. --- pandas/core/dtypes/common.py | 47 ++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/pandas/core/dtypes/common.py b/pandas/core/dtypes/common.py index 94e9b72b001b1..a01266870b8fc 100644 --- a/pandas/core/dtypes/common.py +++ b/pandas/core/dtypes/common.py @@ -150,32 +150,59 @@ def is_object_dtype(arr_or_dtype): def is_sparse(arr): """ - Check whether an array-like is a pandas sparse array. + Check whether an array-like is a 1-D pandas sparse array. + + Check that the one-dimensional array-like is a pandas sparse array. + Returns True if it is a pandas sparse array, not another type of + sparse array. Parameters ---------- arr : array-like - The array-like to check. + Array-like to check. Returns ------- - boolean : Whether or not the array-like is a pandas sparse array. + bool + Whether or not the array-like is a pandas sparse array. + + See Also + -------- + DataFrame.to_sparse : Convert DataFrame to a SparseDataFrame. + Series.to_sparse : Convert Series to SparseSeries. + Series.to_dense : Return dense representation of a Series. Examples -------- - >>> is_sparse(np.array([1, 2, 3])) - False - >>> is_sparse(pd.SparseArray([1, 2, 3])) + Returns `True` if the parameter is a 1-D pandas sparse array. + + >>> is_sparse(pd.SparseArray([0, 0, 1, 0])) True - >>> is_sparse(pd.SparseSeries([1, 2, 3])) + >>> is_sparse(pd.SparseSeries([0, 0, 1, 0])) True - This function checks only for pandas sparse array instances, so - sparse arrays from other libraries will return False. + Returns `False` if the parameter is not sparse. + + >>> is_sparse(np.array([0, 0, 1, 0])) + False + >>> is_sparse(pd.Series([0, 1, 0, 0])) + False + + Returns `False` if the parameter is not a pandas sparse array. >>> from scipy.sparse import bsr_matrix - >>> is_sparse(bsr_matrix([1, 2, 3])) + >>> is_sparse(bsr_matrix([0, 1, 0, 0])) False + + Returns `False` if the parameter has more than one dimension. + + >>> df = pd.SparseDataFrame([389., 24., 80.5, np.nan], + columns=['max_speed'], + index=['falcon', 'parrot', 'lion', 'monkey']) + >>> is_sparse(df) + False + >>> is_sparse(df.max_speed) + True """ from pandas.core.arrays.sparse import SparseDtype From 2d2b214a4305c3e2029d1f36568ea3f2084b7de5 Mon Sep 17 00:00:00 2001 From: gfyoung Date: Wed, 14 Nov 2018 04:59:24 -0800 Subject: [PATCH 12/25] DOC: Surface / doc mangle_dupe_cols in read_excel (#23678) xref gh-10523. --- pandas/io/excel.py | 14 +++++++++-- pandas/tests/io/test_excel.py | 46 ++++++++++++++++++++--------------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/pandas/io/excel.py b/pandas/io/excel.py index a7e0e48de0a75..3ce8953a6edb2 100644 --- a/pandas/io/excel.py +++ b/pandas/io/excel.py @@ -175,12 +175,16 @@ convert integral floats to int (i.e., 1.0 --> 1). If False, all numeric data will be read in as floats: Excel stores all numbers as floats internally +mangle_dupe_cols : boolean, default True + Duplicate columns will be specified as 'X', 'X.1', ...'X.N', rather than + 'X'...'X'. Passing in False will cause data to be overwritten if there + are duplicate names in the columns. Returns ------- parsed : DataFrame or Dict of DataFrames - DataFrame from the passed in Excel file. See notes in sheet_name - argument for more information on when a Dict of Dataframes is returned. + DataFrame from the passed in Excel file. See notes in sheet_name + argument for more information on when a dict of DataFrames is returned. Examples -------- @@ -314,6 +318,7 @@ def read_excel(io, comment=None, skipfooter=0, convert_float=True, + mangle_dupe_cols=True, **kwds): # Can't use _deprecate_kwarg since sheetname=None has a special meaning @@ -349,6 +354,7 @@ def read_excel(io, comment=comment, skipfooter=skipfooter, convert_float=convert_float, + mangle_dupe_cols=mangle_dupe_cols, **kwds) @@ -441,6 +447,7 @@ def parse(self, comment=None, skipfooter=0, convert_float=True, + mangle_dupe_cols=True, **kwds): """ Parse specified sheet(s) into a DataFrame @@ -476,6 +483,7 @@ def parse(self, comment=comment, skipfooter=skipfooter, convert_float=convert_float, + mangle_dupe_cols=mangle_dupe_cols, **kwds) def _parse_excel(self, @@ -498,6 +506,7 @@ def _parse_excel(self, comment=None, skipfooter=0, convert_float=True, + mangle_dupe_cols=True, **kwds): _validate_header_arg(header) @@ -667,6 +676,7 @@ def _parse_cell(cell_contents, cell_typ): comment=comment, skipfooter=skipfooter, usecols=usecols, + mangle_dupe_cols=mangle_dupe_cols, **kwds) output[asheetname] = parser.read(nrows=nrows) diff --git a/pandas/tests/io/test_excel.py b/pandas/tests/io/test_excel.py index c79affaff3c1f..a097e0adbeb7a 100644 --- a/pandas/tests/io/test_excel.py +++ b/pandas/tests/io/test_excel.py @@ -1846,33 +1846,41 @@ def roundtrip(data, header=True, parser_hdr=0, index=True): def test_duplicated_columns(self, *_): # see gh-5235 - write_frame = DataFrame([[1, 2, 3], [1, 2, 3], [1, 2, 3]]) - col_names = ["A", "B", "B"] - - write_frame.columns = col_names - write_frame.to_excel(self.path, "test1") + df = DataFrame([[1, 2, 3], [1, 2, 3], [1, 2, 3]], + columns=["A", "B", "B"]) + df.to_excel(self.path, "test1") + expected = DataFrame([[1, 2, 3], [1, 2, 3], [1, 2, 3]], + columns=["A", "B", "B.1"]) - read_frame = read_excel(self.path, "test1", index_col=0) - read_frame.columns = col_names + # By default, we mangle. + result = read_excel(self.path, "test1", index_col=0) + tm.assert_frame_equal(result, expected) - tm.assert_frame_equal(write_frame, read_frame) + # Explicitly, we pass in the parameter. + result = read_excel(self.path, "test1", index_col=0, + mangle_dupe_cols=True) + tm.assert_frame_equal(result, expected) # see gh-11007, gh-10970 - write_frame = DataFrame([[1, 2, 3, 4], [5, 6, 7, 8]], - columns=["A", "B", "A", "B"]) - write_frame.to_excel(self.path, "test1") - - read_frame = read_excel(self.path, "test1", index_col=0) - read_frame.columns = ["A", "B", "A", "B"] + df = DataFrame([[1, 2, 3, 4], [5, 6, 7, 8]], + columns=["A", "B", "A", "B"]) + df.to_excel(self.path, "test1") - tm.assert_frame_equal(write_frame, read_frame) + result = read_excel(self.path, "test1", index_col=0) + expected = DataFrame([[1, 2, 3, 4], [5, 6, 7, 8]], + columns=["A", "B", "A.1", "B.1"]) + tm.assert_frame_equal(result, expected) # see gh-10982 - write_frame.to_excel(self.path, "test1", index=False, header=False) - read_frame = read_excel(self.path, "test1", header=None) + df.to_excel(self.path, "test1", index=False, header=False) + result = read_excel(self.path, "test1", header=None) - write_frame.columns = [0, 1, 2, 3] - tm.assert_frame_equal(write_frame, read_frame) + expected = DataFrame([[1, 2, 3, 4], [5, 6, 7, 8]]) + tm.assert_frame_equal(result, expected) + + msg = "Setting mangle_dupe_cols=False is not supported yet" + with pytest.raises(ValueError, match=msg): + read_excel(self.path, "test1", header=None, mangle_dupe_cols=False) def test_swapped_columns(self, merge_cells, engine, ext): # Test for issue #5427. From 886b040136c47ec232aca44df180823b47141218 Mon Sep 17 00:00:00 2001 From: justinchan23 <45015017+justinchan23@users.noreply.github.com> Date: Wed, 14 Nov 2018 08:04:32 -0500 Subject: [PATCH 13/25] Fix errorbar visualization (#23674) --- doc/source/visualization.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/visualization.rst b/doc/source/visualization.rst index 569a6fb7b7a0d..dd8ccfcfd28ac 100644 --- a/doc/source/visualization.rst +++ b/doc/source/visualization.rst @@ -1405,7 +1405,7 @@ Here is an example of one way to easily plot group means with standard deviation # Plot fig, ax = plt.subplots() @savefig errorbar_example.png - means.plot.bar(yerr=errors, ax=ax) + means.plot.bar(yerr=errors, ax=ax, capsize=4) .. ipython:: python :suppress: From 6f8c6e1ed5f3bb4c11ddbf70e4587f62c1200ead Mon Sep 17 00:00:00 2001 From: Myles Braithwaite Date: Wed, 14 Nov 2018 08:58:15 -0500 Subject: [PATCH 14/25] DOC: Accessing files from a S3 bucket. (#23639) --- doc/source/io.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/source/io.rst b/doc/source/io.rst index 34dc185c200e6..92fc28af0281a 100644 --- a/doc/source/io.rst +++ b/doc/source/io.rst @@ -1580,12 +1580,19 @@ You can pass in a URL to a CSV file: df = pd.read_csv('https://download.bls.gov/pub/time.series/cu/cu.item', sep='\t') -S3 URLs are handled as well: +S3 URLs are handled as well but require installing the `S3Fs +`_ library: .. code-block:: python df = pd.read_csv('s3://pandas-test/tips.csv') +If your S3 bucket requires cedentials you will need to set them as environment +variables or in the ``~/.aws/credentials`` config file, refer to the `S3Fs +documentation on credentials +`_. + + Writing out Data '''''''''''''''' From 118ba81e97200a7c0d06a1ffc457830617ee4466 Mon Sep 17 00:00:00 2001 From: gfyoung Date: Wed, 14 Nov 2018 06:24:48 -0800 Subject: [PATCH 15/25] REF: Move Excel names parameter handling to CSV (#23690) --- pandas/io/excel.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pandas/io/excel.py b/pandas/io/excel.py index 3ce8953a6edb2..141d2c79a1927 100644 --- a/pandas/io/excel.py +++ b/pandas/io/excel.py @@ -660,6 +660,7 @@ def _parse_cell(cell_contents, cell_typ): # GH 12292 : error when read one empty column from excel file try: parser = TextParser(data, + names=names, header=header, index_col=index_col, has_index_names=has_index_names, @@ -681,9 +682,6 @@ def _parse_cell(cell_contents, cell_typ): output[asheetname] = parser.read(nrows=nrows) - if names is not None: - output[asheetname].columns = names - if not squeeze or isinstance(output[asheetname], DataFrame): output[asheetname].columns = output[ asheetname].columns.set_names(header_names) From 44769627ad5695aeb52f703613310dd2fcc2fce8 Mon Sep 17 00:00:00 2001 From: Jeremy Schendel Date: Wed, 14 Nov 2018 07:26:24 -0700 Subject: [PATCH 16/25] BUG: Fix Series/DataFrame.rank(pct=True) with more than 2**24 rows (#23688) --- doc/source/whatsnew/v0.24.0.txt | 1 + pandas/_libs/algos_rank_helper.pxi.in | 4 ++-- pandas/tests/frame/test_rank.py | 7 +++++++ pandas/tests/series/test_rank.py | 7 +++++++ pandas/tests/test_algos.py | 9 +++++++++ 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index d836ef3441e89..9f92d7cbd9657 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -1205,6 +1205,7 @@ Numeric - Bug in :class:`DataFrame` with ``timedelta64[ns]`` dtype arithmetic operations with ``ndarray`` with integer dtype incorrectly treating the narray as ``timedelta64[ns]`` dtype (:issue:`23114`) - Bug in :meth:`Series.rpow` with object dtype ``NaN`` for ``1 ** NA`` instead of ``1`` (:issue:`22922`). - :meth:`Series.agg` can now handle numpy NaN-aware methods like :func:`numpy.nansum` (:issue:`19629`) +- Bug in :meth:`Series.rank` and :meth:`DataFrame.rank` when ``pct=True`` and more than 2:sup:`24` rows are present resulted in percentages greater than 1.0 (:issue:`18271`) Strings ^^^^^^^ diff --git a/pandas/_libs/algos_rank_helper.pxi.in b/pandas/_libs/algos_rank_helper.pxi.in index 4d144dcf2808a..329c368e13d6d 100644 --- a/pandas/_libs/algos_rank_helper.pxi.in +++ b/pandas/_libs/algos_rank_helper.pxi.in @@ -53,7 +53,7 @@ def rank_1d_{{dtype}}(object in_arr, ties_method='average', int tiebreak = 0 bint keep_na = 0 bint isnan - float count = 0.0 + float64_t count = 0.0 tiebreak = tiebreakers[ties_method] {{if dtype == 'float64'}} @@ -228,7 +228,7 @@ def rank_2d_{{dtype}}(object in_arr, axis=0, ties_method='average', float64_t sum_ranks = 0 int tiebreak = 0 bint keep_na = 0 - float count = 0.0 + float64_t count = 0.0 tiebreak = tiebreakers[ties_method] diff --git a/pandas/tests/frame/test_rank.py b/pandas/tests/frame/test_rank.py index 078c48539de16..eaba5f7ec7790 100644 --- a/pandas/tests/frame/test_rank.py +++ b/pandas/tests/frame/test_rank.py @@ -309,3 +309,10 @@ def test_rank_pct_true(self, method, exp): expected = DataFrame(exp) tm.assert_frame_equal(result, expected) + + def test_pct_max_many_rows(self): + # GH 18271 + df = DataFrame({'A': np.arange(2**24 + 1), + 'B': np.arange(2**24 + 1, 0, -1)}) + result = df.rank(pct=True).max() + assert (result == 1).all() diff --git a/pandas/tests/series/test_rank.py b/pandas/tests/series/test_rank.py index 9772ceecfc7b1..5b0ea37a0bfcf 100644 --- a/pandas/tests/series/test_rank.py +++ b/pandas/tests/series/test_rank.py @@ -495,3 +495,10 @@ def test_rank_first_pct(dtype, ser, exp): result = s.rank(method='first', pct=True) expected = Series(exp).astype(result.dtype) assert_series_equal(result, expected) + + +def test_pct_max_many_rows(): + # GH 18271 + s = Series(np.arange(2**24 + 1)) + result = s.rank(pct=True).max() + assert result == 1 diff --git a/pandas/tests/test_algos.py b/pandas/tests/test_algos.py index 3642c4ee98a9e..ff505f2986b1a 100644 --- a/pandas/tests/test_algos.py +++ b/pandas/tests/test_algos.py @@ -1462,6 +1462,15 @@ def test_too_many_ndims(self): with pytest.raises(TypeError, match=msg): algos.rank(arr) + @pytest.mark.parametrize('values', [ + np.arange(2**24 + 1), + np.arange(2**25 + 2).reshape(2**24 + 1, 2)], + ids=['1d', '2d']) + def test_pct_max_many_rows(self, values): + # GH 18271 + result = algos.rank(values, pct=True).max() + assert result == 1 + def test_pad_backfill_object_segfault(): From 302e4ca1dda7da23822d7c1f40b9d3959aa7fcc9 Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Wed, 14 Nov 2018 09:50:31 -0500 Subject: [PATCH 17/25] CI: raise clone depth limit on CI --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9fac09e1fa788..6d31adcbf8a43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ env: git: # for cloning - depth: 1000 + depth: 1500 matrix: fast_finish: true From fb4405d5ebc132f50103b500592109988ad6a0c5 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 14 Nov 2018 07:23:02 -0800 Subject: [PATCH 18/25] Implement _most_ of the EA interface for DTA/TDA (#23643) --- pandas/core/arrays/datetimelike.py | 63 ++++++++++- pandas/core/arrays/datetimes.py | 28 ++++- pandas/core/arrays/period.py | 56 +++------ pandas/core/arrays/timedeltas.py | 14 ++- pandas/core/dtypes/concat.py | 8 +- pandas/core/indexes/datetimelike.py | 23 ++-- pandas/core/indexes/datetimes.py | 17 ++- pandas/tests/arrays/test_datetimelike.py | 138 ++++++++++++++++++++++- 8 files changed, 270 insertions(+), 77 deletions(-) diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index daf2dcccd284b..094c9c3df0bed 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -39,7 +39,7 @@ from pandas.core.dtypes.missing import isna import pandas.core.common as com -from pandas.core.algorithms import checked_add_with_arr +from pandas.core.algorithms import checked_add_with_arr, take, unique1d from .base import ExtensionOpsMixin from pandas.util._decorators import deprecate_kwarg @@ -196,6 +196,67 @@ def astype(self, dtype, copy=True): return self._box_values(self.asi8) return super(DatetimeLikeArrayMixin, self).astype(dtype, copy) + # ------------------------------------------------------------------ + # ExtensionArray Interface + # TODO: + # * _from_sequence + # * argsort / _values_for_argsort + # * _reduce + + def unique(self): + result = unique1d(self.asi8) + return type(self)(result, dtype=self.dtype) + + def _validate_fill_value(self, fill_value): + """ + If a fill_value is passed to `take` convert it to an i8 representation, + raising ValueError if this is not possible. + + Parameters + ---------- + fill_value : object + + Returns + ------- + fill_value : np.int64 + + Raises + ------ + ValueError + """ + raise AbstractMethodError(self) + + def take(self, indices, allow_fill=False, fill_value=None): + if allow_fill: + fill_value = self._validate_fill_value(fill_value) + + new_values = take(self.asi8, + indices, + allow_fill=allow_fill, + fill_value=fill_value) + + return type(self)(new_values, dtype=self.dtype) + + @classmethod + def _concat_same_type(cls, to_concat): + dtypes = {x.dtype for x in to_concat} + assert len(dtypes) == 1 + dtype = list(dtypes)[0] + + values = np.concatenate([x.asi8 for x in to_concat]) + return cls(values, dtype=dtype) + + def copy(self, deep=False): + values = self.asi8.copy() + return type(self)(values, dtype=self.dtype, freq=self.freq) + + def _values_for_factorize(self): + return self.asi8, iNaT + + @classmethod + def _from_factorized(cls, values, original): + return cls(values, dtype=original.dtype) + # ------------------------------------------------------------------ # Null Handling diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 926228f267049..7b4e362ac9fa0 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -12,7 +12,7 @@ conversion, fields, timezones, resolution as libresolution) -from pandas.util._decorators import cache_readonly +from pandas.util._decorators import cache_readonly, Appender from pandas.errors import PerformanceWarning from pandas import compat @@ -21,8 +21,7 @@ is_object_dtype, is_int64_dtype, is_datetime64tz_dtype, - is_datetime64_dtype, - ensure_int64) + is_datetime64_dtype) from pandas.core.dtypes.dtypes import DatetimeTZDtype from pandas.core.dtypes.missing import isna from pandas.core.dtypes.generic import ABCIndexClass, ABCSeries @@ -294,7 +293,7 @@ def _generate_range(cls, start, end, periods, freq, tz=None, if tz is not None and index.tz is None: arr = conversion.tz_localize_to_utc( - ensure_int64(index.values), + index.asi8, tz, ambiguous=ambiguous) index = cls(arr) @@ -317,7 +316,7 @@ def _generate_range(cls, start, end, periods, freq, tz=None, if not right_closed and len(index) and index[-1] == end: index = index[:-1] - return cls._simple_new(index.values, freq=freq, tz=tz) + return cls._simple_new(index.asi8, freq=freq, tz=tz) # ----------------------------------------------------------------- # Descriptive Properties @@ -419,6 +418,25 @@ def __iter__(self): for v in converted: yield v + # ---------------------------------------------------------------- + # ExtensionArray Interface + + @property + def _ndarray_values(self): + return self._data + + @Appender(dtl.DatetimeLikeArrayMixin._validate_fill_value.__doc__) + def _validate_fill_value(self, fill_value): + if isna(fill_value): + fill_value = iNaT + elif isinstance(fill_value, (datetime, np.datetime64)): + self._assert_tzawareness_compat(fill_value) + fill_value = Timestamp(fill_value).value + else: + raise ValueError("'fill_value' should be a Timestamp. " + "Got '{got}'.".format(got=fill_value)) + return fill_value + # ----------------------------------------------------------------- # Comparison Methods diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index faba404faeb23..e46b00da6161e 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -216,14 +216,6 @@ def _from_sequence(cls, scalars, dtype=None, copy=False): ordinals = libperiod.extract_ordinals(periods, freq) return cls(ordinals, freq=freq) - def _values_for_factorize(self): - return self.asi8, iNaT - - @classmethod - def _from_factorized(cls, values, original): - # type: (Sequence[Optional[Period]], PeriodArray) -> PeriodArray - return cls(values, freq=original.freq) - @classmethod def _from_datetime64(cls, data, freq, tz=None): """Construct a PeriodArray from a datetime64 array @@ -262,14 +254,6 @@ def _generate_range(cls, start, end, periods, freq, fields): return subarr, freq - @classmethod - def _concat_same_type(cls, to_concat): - freq = {x.freq for x in to_concat} - assert len(freq) == 1 - freq = list(freq)[0] - values = np.concatenate([x._data for x in to_concat]) - return cls(values, freq=freq) - # -------------------------------------------------------------------- # Data / Attributes @@ -415,29 +399,20 @@ def __setitem__( raise TypeError(msg) self._data[key] = value - def take(self, indices, allow_fill=False, fill_value=None): - if allow_fill: - if isna(fill_value): - fill_value = iNaT - elif isinstance(fill_value, Period): - if self.freq != fill_value.freq: - msg = DIFFERENT_FREQ_INDEX.format( - self.freq.freqstr, - fill_value.freqstr - ) - raise IncompatibleFrequency(msg) - - fill_value = fill_value.ordinal - else: - msg = "'fill_value' should be a Period. Got '{}'." - raise ValueError(msg.format(fill_value)) - - new_values = algos.take(self._data, - indices, - allow_fill=allow_fill, - fill_value=fill_value) - - return type(self)(new_values, self.freq) + @Appender(dtl.DatetimeLikeArrayMixin._validate_fill_value.__doc__) + def _validate_fill_value(self, fill_value): + if isna(fill_value): + fill_value = iNaT + elif isinstance(fill_value, Period): + if fill_value.freq != self.freq: + msg = DIFFERENT_FREQ_INDEX.format(self.freq.freqstr, + fill_value.freqstr) + raise IncompatibleFrequency(msg) + fill_value = fill_value.ordinal + else: + raise ValueError("'fill_value' should be a Period. " + "Got '{got}'.".format(got=fill_value)) + return fill_value def fillna(self, value=None, method=None, limit=None): # TODO(#20300) @@ -474,9 +449,6 @@ def fillna(self, value=None, method=None, limit=None): new_values = self.copy() return new_values - def copy(self, deep=False): - return type(self)(self._data.copy(), freq=self.freq) - def value_counts(self, dropna=False): from pandas import Series, PeriodIndex diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 9dbdd6ff8b562..ad564ca34930f 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -9,6 +9,7 @@ from pandas._libs.tslibs.fields import get_timedelta_field from pandas._libs.tslibs.timedeltas import ( array_to_timedelta64, parse_timedelta_unit) +from pandas.util._decorators import Appender from pandas import compat @@ -139,7 +140,7 @@ def _simple_new(cls, values, freq=None, dtype=_TD_DTYPE): result._freq = freq return result - def __new__(cls, values, freq=None): + def __new__(cls, values, freq=None, dtype=_TD_DTYPE): freq, freq_infer = dtl.maybe_infer_freq(freq) @@ -193,6 +194,17 @@ def _generate_range(cls, start, end, periods, freq, closed=None): # ---------------------------------------------------------------- # Array-Like / EA-Interface Methods + @Appender(dtl.DatetimeLikeArrayMixin._validate_fill_value.__doc__) + def _validate_fill_value(self, fill_value): + if isna(fill_value): + fill_value = iNaT + elif isinstance(fill_value, (timedelta, np.timedelta64, Tick)): + fill_value = Timedelta(fill_value).value + else: + raise ValueError("'fill_value' should be a Timedelta. " + "Got '{got}'.".format(got=fill_value)) + return fill_value + # ---------------------------------------------------------------- # Arithmetic Methods diff --git a/pandas/core/dtypes/concat.py b/pandas/core/dtypes/concat.py index bb4ab823069ee..ebfb41825ae0a 100644 --- a/pandas/core/dtypes/concat.py +++ b/pandas/core/dtypes/concat.py @@ -476,13 +476,7 @@ def _concat_datetimetz(to_concat, name=None): all inputs must be DatetimeIndex it is used in DatetimeIndex.append also """ - # do not pass tz to set because tzlocal cannot be hashed - if len({str(x.dtype) for x in to_concat}) != 1: - raise ValueError('to_concat must have the same tz') - tz = to_concat[0].tz - # no need to localize because internal repr will not be changed - new_values = np.concatenate([x.asi8 for x in to_concat]) - return to_concat[0]._simple_new(new_values, tz=tz, name=name) + return to_concat[0]._concat_same_dtype(to_concat, name=name) def _concat_index_same_dtype(indexes, klass=None): diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 3f9a60f6d5c51..39bc7f4b85de2 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -18,7 +18,6 @@ is_datetime_or_timedelta_dtype, is_dtype_equal, is_float, is_float_dtype, is_integer, is_integer_dtype, is_list_like, is_object_dtype, is_period_dtype, is_scalar, is_string_dtype) -import pandas.core.dtypes.concat as _concat from pandas.core.dtypes.generic import ABCIndex, ABCIndexClass, ABCSeries from pandas.core.dtypes.missing import isna @@ -215,6 +214,11 @@ def ceil(self, freq, ambiguous='raise', nonexistent='raise'): class DatetimeIndexOpsMixin(DatetimeLikeArrayMixin): """ common ops mixin to support a unified interface datetimelike Index """ + # override DatetimeLikeArrayMixin method + copy = Index.copy + unique = Index.unique + take = Index.take + # DatetimeLikeArrayMixin assumes subclasses are mutable, so these are # properties there. They can be made into cache_readonly for Index # subclasses bc they are immutable @@ -685,17 +689,21 @@ def _concat_same_dtype(self, to_concat, name): """ attribs = self._get_attributes_dict() attribs['name'] = name + # do not pass tz to set because tzlocal cannot be hashed + if len({str(x.dtype) for x in to_concat}) != 1: + raise ValueError('to_concat must have the same tz') if not is_period_dtype(self): # reset freq attribs['freq'] = None - - if getattr(self, 'tz', None) is not None: - return _concat._concat_datetimetz(to_concat, name) + # TODO(DatetimeArray) + # - remove the .asi8 here + # - remove the _maybe_box_as_values + # - combine with the `else` block + new_data = self._concat_same_type(to_concat).asi8 else: - new_data = np.concatenate([c.asi8 for c in to_concat]) + new_data = type(self._values)._concat_same_type(to_concat) - new_data = self._maybe_box_as_values(new_data, **attribs) return self._simple_new(new_data, **attribs) def _maybe_box_as_values(self, values, **attribs): @@ -704,7 +712,6 @@ def _maybe_box_as_values(self, values, **attribs): # but others are not. When everyone is an ExtensionArray, this can # be removed. Currently used in # - sort_values - # - _concat_same_dtype return values def astype(self, dtype, copy=True): @@ -761,7 +768,7 @@ def _ensure_datetimelike_to_i8(other, to_utc=False): try: return np.array(other, copy=False).view('i8') except TypeError: - # period array cannot be coerces to int + # period array cannot be coerced to int other = Index(other) return other.asi8 diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index b754b2705d034..23446a57e7789 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -551,16 +551,13 @@ def snap(self, freq='S'): # TODO: what about self.name? if so, use shallow_copy? def unique(self, level=None): - # Override here since IndexOpsMixin.unique uses self._values.unique - # For DatetimeIndex with TZ, that's a DatetimeIndex -> recursion error - # So we extract the tz-naive DatetimeIndex, unique that, and wrap the - # result with out TZ. - if self.tz is not None: - naive = type(self)(self._ndarray_values, copy=False) - else: - naive = self - result = super(DatetimeIndex, naive).unique(level=level) - return self._shallow_copy(result.values) + if level is not None: + self._validate_index_level(level) + + # TODO(DatetimeArray): change dispatch once inheritance is removed + # call DatetimeArray method + result = DatetimeArray.unique(self) + return self._shallow_copy(result._data) def union(self, other): """ diff --git a/pandas/tests/arrays/test_datetimelike.py b/pandas/tests/arrays/test_datetimelike.py index bb4022c9cac9a..a1242e2481fed 100644 --- a/pandas/tests/arrays/test_datetimelike.py +++ b/pandas/tests/arrays/test_datetimelike.py @@ -56,7 +56,68 @@ def timedelta_index(request): return pd.TimedeltaIndex(['1 Day', '3 Hours', 'NaT']) -class TestDatetimeArray(object): +class SharedTests(object): + index_cls = None + + def test_take(self): + data = np.arange(100, dtype='i8') + np.random.shuffle(data) + + idx = self.index_cls._simple_new(data, freq='D') + arr = self.array_cls(idx) + + takers = [1, 4, 94] + result = arr.take(takers) + expected = idx.take(takers) + + tm.assert_index_equal(self.index_cls(result), expected) + + takers = np.array([1, 4, 94]) + result = arr.take(takers) + expected = idx.take(takers) + + tm.assert_index_equal(self.index_cls(result), expected) + + def test_take_fill(self): + data = np.arange(10, dtype='i8') + + idx = self.index_cls._simple_new(data, freq='D') + arr = self.array_cls(idx) + + result = arr.take([-1, 1], allow_fill=True, fill_value=None) + assert result[0] is pd.NaT + + result = arr.take([-1, 1], allow_fill=True, fill_value=np.nan) + assert result[0] is pd.NaT + + result = arr.take([-1, 1], allow_fill=True, fill_value=pd.NaT) + assert result[0] is pd.NaT + + with pytest.raises(ValueError): + arr.take([0, 1], allow_fill=True, fill_value=2) + + with pytest.raises(ValueError): + arr.take([0, 1], allow_fill=True, fill_value=2.0) + + with pytest.raises(ValueError): + arr.take([0, 1], allow_fill=True, + fill_value=pd.Timestamp.now().time) + + def test_concat_same_type(self): + data = np.arange(10, dtype='i8') + + idx = self.index_cls._simple_new(data, freq='D').insert(0, pd.NaT) + arr = self.array_cls(idx) + + result = arr._concat_same_type([arr[:-1], arr[1:], arr]) + expected = idx._concat_same_dtype([idx[:-1], idx[1:], idx], None) + + tm.assert_index_equal(self.index_cls(result), expected) + + +class TestDatetimeArray(SharedTests): + index_cls = pd.DatetimeIndex + array_cls = DatetimeArray def test_array_object_dtype(self, tz_naive_fixture): # GH#23524 @@ -175,8 +236,60 @@ def test_int_properties(self, datetime_index, propname): tm.assert_numpy_array_equal(result, expected) + def test_take_fill_valid(self, datetime_index, tz_naive_fixture): + dti = datetime_index.tz_localize(tz_naive_fixture) + arr = DatetimeArray(dti) + + now = pd.Timestamp.now().tz_localize(dti.tz) + result = arr.take([-1, 1], allow_fill=True, fill_value=now) + assert result[0] == now + + with pytest.raises(ValueError): + # fill_value Timedelta invalid + arr.take([-1, 1], allow_fill=True, fill_value=now - now) + + with pytest.raises(ValueError): + # fill_value Period invalid + arr.take([-1, 1], allow_fill=True, fill_value=pd.Period('2014Q1')) + + tz = None if dti.tz is not None else 'US/Eastern' + now = pd.Timestamp.now().tz_localize(tz) + with pytest.raises(TypeError): + # Timestamp with mismatched tz-awareness + arr.take([-1, 1], allow_fill=True, fill_value=now) + + def test_concat_same_type_invalid(self, datetime_index): + # different timezones + dti = datetime_index + arr = DatetimeArray(dti) + + if arr.tz is None: + other = arr.tz_localize('UTC') + else: + other = arr.tz_localize(None) + + with pytest.raises(AssertionError): + arr._concat_same_type([arr, other]) + + def test_concat_same_type_different_freq(self): + # we *can* concatentate DTI with different freqs. + a = DatetimeArray(pd.date_range('2000', periods=2, freq='D', + tz='US/Central')) + b = DatetimeArray(pd.date_range('2000', periods=2, freq='H', + tz='US/Central')) + result = DatetimeArray._concat_same_type([a, b]) + expected = DatetimeArray(pd.to_datetime([ + '2000-01-01 00:00:00', '2000-01-02 00:00:00', + '2000-01-01 00:00:00', '2000-01-01 01:00:00', + ]).tz_localize("US/Central")) + + tm.assert_datetime_array_equal(result, expected) + + +class TestTimedeltaArray(SharedTests): + index_cls = pd.TimedeltaIndex + array_cls = TimedeltaArray -class TestTimedeltaArray(object): def test_from_tdi(self): tdi = pd.TimedeltaIndex(['1 Day', '3 Hours']) arr = TimedeltaArray(tdi) @@ -223,8 +336,27 @@ def test_int_properties(self, timedelta_index, propname): tm.assert_numpy_array_equal(result, expected) + def test_take_fill_valid(self, timedelta_index): + tdi = timedelta_index + arr = TimedeltaArray(tdi) + + td1 = pd.Timedelta(days=1) + result = arr.take([-1, 1], allow_fill=True, fill_value=td1) + assert result[0] == td1 + + now = pd.Timestamp.now() + with pytest.raises(ValueError): + # fill_value Timestamp invalid + arr.take([0, 1], allow_fill=True, fill_value=now) + + with pytest.raises(ValueError): + # fill_value Period invalid + arr.take([0, 1], allow_fill=True, fill_value=now.to_period('D')) + -class TestPeriodArray(object): +class TestPeriodArray(SharedTests): + index_cls = pd.PeriodIndex + array_cls = PeriodArray def test_from_pi(self, period_index): pi = period_index From a6c71bff40cc0e289727cc085b9589924c4e49c4 Mon Sep 17 00:00:00 2001 From: Fabian Haase Date: Wed, 14 Nov 2018 18:04:08 +0100 Subject: [PATCH 19/25] Pin flake8-rst version (#23699) --- ci/deps/travis-36.yaml | 2 +- environment.yml | 2 +- requirements-dev.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/deps/travis-36.yaml b/ci/deps/travis-36.yaml index 8aa551f6194d9..1880fa2501581 100644 --- a/ci/deps/travis-36.yaml +++ b/ci/deps/travis-36.yaml @@ -9,7 +9,7 @@ dependencies: - fastparquet - flake8>=3.5 - flake8-comprehensions - - flake8-rst + - flake8-rst=0.4.2 - gcsfs - geopandas - html5lib diff --git a/environment.yml b/environment.yml index f66625e6a60c7..742b974566577 100644 --- a/environment.yml +++ b/environment.yml @@ -13,7 +13,7 @@ dependencies: - Cython>=0.28.2 - flake8 - flake8-comprehensions - - flake8-rst + - flake8-rst=0.4.2 - hypothesis>=3.58.0 - isort - moto diff --git a/requirements-dev.txt b/requirements-dev.txt index 93145d948c218..9acfe243d22fb 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,7 +4,7 @@ pytz Cython>=0.28.2 flake8 flake8-comprehensions -flake8-rst +flake8-rst==0.4.2 hypothesis>=3.58.0 isort moto From 3edc18dbc8893734e7c3b8d802b3fa1afe9ddaa8 Mon Sep 17 00:00:00 2001 From: Sumin Byeon Date: Thu, 15 Nov 2018 02:05:36 +0900 Subject: [PATCH 20/25] CLN: Remove unnecessary code (#23696) --- pandas/core/accessor.py | 2 +- pandas/core/generic.py | 2 +- pandas/core/groupby/groupby.py | 2 +- pandas/tests/dtypes/test_inference.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas/core/accessor.py b/pandas/core/accessor.py index d178c66da2cc1..f2ae7f6b56551 100644 --- a/pandas/core/accessor.py +++ b/pandas/core/accessor.py @@ -11,7 +11,7 @@ class DirNamesMixin(object): - _accessors = frozenset([]) + _accessors = frozenset() _deprecations = frozenset( ['asobject', 'base', 'data', 'flags', 'itemsize', 'strides']) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index d5cc56d9f881d..1c81105b9d417 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -117,7 +117,7 @@ class NDFrame(PandasObject, SelectionMixin): '_default_fill_value', '_metadata', '__array_struct__', '__array_interface__'] _internal_names_set = set(_internal_names) - _accessors = frozenset([]) + _accessors = frozenset() _deprecations = frozenset(['as_blocks', 'blocks', 'convert_objects', 'is_copy']) _metadata = [] diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index 5041449b4d724..c5f375bd60253 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -324,7 +324,7 @@ def _group_selection_context(groupby): class _GroupBy(PandasObject, SelectionMixin): _group_selection = None - _apply_whitelist = frozenset([]) + _apply_whitelist = frozenset() def __init__(self, obj, keys=None, axis=0, level=None, grouper=None, exclusions=None, selection=None, as_index=True, diff --git a/pandas/tests/dtypes/test_inference.py b/pandas/tests/dtypes/test_inference.py index 1ff3005722341..f2552cffc6651 100644 --- a/pandas/tests/dtypes/test_inference.py +++ b/pandas/tests/dtypes/test_inference.py @@ -59,7 +59,7 @@ def coerce(request): ({'a', 1}, 'set', 'set'), # noqa: E241 (set(), 'set', 'set-empty'), # noqa: E241 (frozenset({'a', 1}), 'set', 'frozenset'), # noqa: E241 - (frozenset([]), 'set', 'frozenset-empty'), # noqa: E241 + (frozenset(), 'set', 'frozenset-empty'), # noqa: E241 (iter([1, 2]), True, 'iterator'), # noqa: E241 (iter([]), True, 'iterator-empty'), # noqa: E241 ((x for x in [1, 2]), True, 'generator'), # noqa: E241 From fcb840349caa1a922b1d15e7a8e1ab05bfeed94e Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 14 Nov 2018 17:06:45 +0000 Subject: [PATCH 21/25] ENH: Allow export of mixed columns to Stata strl (#23692) Enable export of large columns to Stata strls when the column contains None as a null value closes #23633 --- doc/source/whatsnew/v0.24.0.txt | 1 + pandas/io/stata.py | 2 ++ pandas/tests/io/test_stata.py | 17 +++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 9f92d7cbd9657..3057e3f700eab 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -239,6 +239,7 @@ Other Enhancements - :meth:`Timestamp.tz_localize`, :meth:`DatetimeIndex.tz_localize`, and :meth:`Series.tz_localize` have gained the ``nonexistent`` argument for alternative handling of nonexistent times. See :ref:`timeseries.timezone_nonexistent` (:issue:`8917`) - :meth:`read_excel()` now accepts ``usecols`` as a list of column names or callable (:issue:`18273`) - :meth:`MultiIndex.to_flat_index` has been added to flatten multiple levels into a single-level :class:`Index` object. +- :meth:`DataFrame.to_stata` and :class:` pandas.io.stata.StataWriter117` can write mixed sting columns to Stata strl format (:issue:`23633`) .. _whatsnew_0240.api_breaking: diff --git a/pandas/io/stata.py b/pandas/io/stata.py index 66e996075f1ed..215391bbf217a 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -2558,6 +2558,8 @@ def generate_table(self): for o, (idx, row) in enumerate(selected.iterrows()): for j, (col, v) in enumerate(col_index): val = row[col] + # Allow columns with mixed str and None (GH 23633) + val = '' if val is None else val key = gso_table.get(val, None) if key is None: # Stata prefers human numbers diff --git a/pandas/tests/io/test_stata.py b/pandas/tests/io/test_stata.py index c6b6f6cab9ddd..47293e8765d26 100644 --- a/pandas/tests/io/test_stata.py +++ b/pandas/tests/io/test_stata.py @@ -1505,3 +1505,20 @@ def test_unicode_dta_118(self): expected = pd.DataFrame(values, columns=columns) tm.assert_frame_equal(unicode_df, expected) + + def test_mixed_string_strl(self): + # GH 23633 + output = [ + {'mixed': 'string' * 500, + 'number': 0}, + {'mixed': None, + 'number': 1} + ] + + output = pd.DataFrame(output) + with tm.ensure_clean() as path: + output.to_stata(path, write_index=False, version=117) + reread = read_stata(path) + expected = output.fillna('') + expected.number = expected.number.astype('int32') + tm.assert_frame_equal(reread, expected) From 5a04e6ec929dc46f938197484142ca72f2aa1ba2 Mon Sep 17 00:00:00 2001 From: Pablo Ambrosio Date: Wed, 14 Nov 2018 17:55:14 -0300 Subject: [PATCH 22/25] DOC: update pandas.core.groupby.DataFrameGroupBy.resample docstring. (#20374) --- pandas/core/groupby/groupby.py | 107 +++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index c5f375bd60253..bf1e5ebb18786 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -1307,12 +1307,111 @@ def describe(self, **kwargs): return result.T return result.unstack() - @Substitution(name='groupby') - @Appender(_doc_template) def resample(self, rule, *args, **kwargs): """ - Provide resampling when using a TimeGrouper - Return a new grouper with our resampler appended + Provide resampling when using a TimeGrouper. + + Given a grouper, the function resamples it according to a string + "string" -> "frequency". + + See the :ref:`frequency aliases ` + documentation for more details. + + Parameters + ---------- + rule : str or DateOffset + The offset string or object representing target grouper conversion. + *args, **kwargs + Possible arguments are `how`, `fill_method`, `limit`, `kind` and + `on`, and other arguments of `TimeGrouper`. + + Returns + ------- + Grouper + Return a new grouper with our resampler appended. + + See Also + -------- + pandas.Grouper : Specify a frequency to resample with when + grouping by a key. + DatetimeIndex.resample : Frequency conversion and resampling of + time series. + + Examples + -------- + >>> idx = pd.date_range('1/1/2000', periods=4, freq='T') + >>> df = pd.DataFrame(data=4 * [range(2)], + ... index=idx, + ... columns=['a', 'b']) + >>> df.iloc[2, 0] = 5 + >>> df + a b + 2000-01-01 00:00:00 0 1 + 2000-01-01 00:01:00 0 1 + 2000-01-01 00:02:00 5 1 + 2000-01-01 00:03:00 0 1 + + Downsample the DataFrame into 3 minute bins and sum the values of + the timestamps falling into a bin. + + >>> df.groupby('a').resample('3T').sum() + a b + a + 0 2000-01-01 00:00:00 0 2 + 2000-01-01 00:03:00 0 1 + 5 2000-01-01 00:00:00 5 1 + + Upsample the series into 30 second bins. + + >>> df.groupby('a').resample('30S').sum() + a b + a + 0 2000-01-01 00:00:00 0 1 + 2000-01-01 00:00:30 0 0 + 2000-01-01 00:01:00 0 1 + 2000-01-01 00:01:30 0 0 + 2000-01-01 00:02:00 0 0 + 2000-01-01 00:02:30 0 0 + 2000-01-01 00:03:00 0 1 + 5 2000-01-01 00:02:00 5 1 + + Resample by month. Values are assigned to the month of the period. + + >>> df.groupby('a').resample('M').sum() + a b + a + 0 2000-01-31 0 3 + 5 2000-01-31 5 1 + + Downsample the series into 3 minute bins as above, but close the right + side of the bin interval. + + >>> df.groupby('a').resample('3T', closed='right').sum() + a b + a + 0 1999-12-31 23:57:00 0 1 + 2000-01-01 00:00:00 0 2 + 5 2000-01-01 00:00:00 5 1 + + Downsample the series into 3 minute bins and close the right side of + the bin interval, but label each bin using the right edge instead of + the left. + + >>> df.groupby('a').resample('3T', closed='right', label='right').sum() + a b + a + 0 2000-01-01 00:00:00 0 1 + 2000-01-01 00:03:00 0 2 + 5 2000-01-01 00:03:00 5 1 + + Add an offset of twenty seconds. + + >>> df.groupby('a').resample('3T', loffset='20s').sum() + a b + a + 0 2000-01-01 00:00:20 0 2 + 2000-01-01 00:03:20 0 1 + 5 2000-01-01 00:00:20 5 1 """ from pandas.core.resample import get_resampler_for_grouping return get_resampler_for_grouping(self, rule, *args, **kwargs) From 6d031f2b739ac1197cbb81b36cdea5f954d4e065 Mon Sep 17 00:00:00 2001 From: syutbai Date: Wed, 14 Nov 2018 15:56:57 -0500 Subject: [PATCH 23/25] DOC: Fix format of the See Also descriptions (#23654) * pandas refs 23630, partial. --- pandas/core/arrays/categorical.py | 18 +++--- pandas/core/arrays/datetimes.py | 6 +- pandas/core/arrays/interval.py | 36 ++++++------ pandas/core/arrays/period.py | 4 +- pandas/core/base.py | 4 +- pandas/core/dtypes/inference.py | 2 +- pandas/core/dtypes/missing.py | 4 +- pandas/core/frame.py | 75 ++++++++++++------------ pandas/core/generic.py | 90 ++++++++++++++--------------- pandas/core/groupby/groupby.py | 4 +- pandas/core/indexes/base.py | 42 +++++++------- pandas/core/indexes/datetimelike.py | 2 +- pandas/core/indexes/datetimes.py | 8 +-- pandas/core/indexes/frozen.py | 2 +- pandas/core/indexes/interval.py | 2 +- pandas/core/indexes/multi.py | 24 ++++---- pandas/core/indexes/numeric.py | 2 +- pandas/core/indexes/period.py | 8 +-- pandas/core/indexes/range.py | 4 +- pandas/core/indexes/timedeltas.py | 6 +- pandas/core/indexing.py | 18 +++--- pandas/core/series.py | 42 +++++++------- pandas/core/strings.py | 22 +++---- pandas/core/window.py | 82 +++++++++++++------------- pandas/io/json/table_schema.py | 2 +- pandas/io/pytables.py | 4 +- pandas/io/sql.py | 2 +- pandas/io/stata.py | 4 +- pandas/plotting/_core.py | 4 +- pandas/plotting/_misc.py | 2 +- pandas/util/_validators.py | 4 +- 31 files changed, 265 insertions(+), 264 deletions(-) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 55f0040344bdc..333f4e5ea21b4 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -315,8 +315,8 @@ class Categorical(ExtensionArray, PandasObject): See Also -------- - pandas.api.types.CategoricalDtype : Type for categorical data - CategoricalIndex : An Index with an underlying ``Categorical`` + pandas.api.types.CategoricalDtype : Type for categorical data. + CategoricalIndex : An Index with an underlying ``Categorical``. """ # For comparisons, so that numpy uses our implementation if the compare @@ -1366,9 +1366,9 @@ def isna(self): See Also -------- - isna : top-level isna - isnull : alias of isna - Categorical.notna : boolean inverse of Categorical.isna + isna : Top-level isna. + isnull : Alias of isna. + Categorical.notna : Boolean inverse of Categorical.isna. """ @@ -1389,9 +1389,9 @@ def notna(self): See Also -------- - notna : top-level notna - notnull : alias of notna - Categorical.isna : boolean inverse of Categorical.notna + notna : Top-level notna. + notnull : Alias of notna. + Categorical.isna : Boolean inverse of Categorical.notna. """ return ~self.isna() @@ -2371,7 +2371,7 @@ def isin(self, values): See Also -------- - pandas.Series.isin : equivalent method on Series + pandas.Series.isin : Equivalent method on Series. Examples -------- diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 7b4e362ac9fa0..04d6b5f161956 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -584,7 +584,7 @@ def tz_convert(self, tz): See Also -------- - DatetimeIndex.tz : A timezone that has a variable offset from UTC + DatetimeIndex.tz : A timezone that has a variable offset from UTC. DatetimeIndex.tz_localize : Localize tz-naive DatetimeIndex to a given time zone, or remove timezone from a tz-aware DatetimeIndex. @@ -894,8 +894,8 @@ def to_period(self, freq=None): See Also -------- - pandas.PeriodIndex: Immutable ndarray holding ordinal values - pandas.DatetimeIndex.to_pydatetime: Return DatetimeIndex as object + pandas.PeriodIndex: Immutable ndarray holding ordinal values. + pandas.DatetimeIndex.to_pydatetime: Return DatetimeIndex as object. """ from pandas.core.arrays import PeriodArray diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 94be29893d2b9..90118cd300a22 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -94,11 +94,11 @@ See Also -------- -Index : The base pandas Index type -Interval : A bounded slice-like interval; the elements of an %(klass)s -interval_range : Function to create a fixed frequency IntervalIndex -cut : Bin values into discrete Intervals -qcut : Bin values into equal-sized Intervals based on rank or sample quantiles +Index : The base pandas Index type. +Interval : A bounded slice-like interval; the elements of an %(klass)s. +interval_range : Function to create a fixed frequency IntervalIndex. +cut : Bin values into discrete Intervals. +qcut : Bin values into equal-sized Intervals based on rank or sample quantiles. """ @@ -244,9 +244,9 @@ def _from_factorized(cls, values, original): See Also -------- - interval_range : Function to create a fixed frequency IntervalIndex - %(klass)s.from_arrays : Construct from a left and right array - %(klass)s.from_tuples : Construct from a sequence of tuples + interval_range : Function to create a fixed frequency IntervalIndex. + %(klass)s.from_arrays : Construct from a left and right array. + %(klass)s.from_tuples : Construct from a sequence of tuples. """ @classmethod @@ -354,13 +354,13 @@ def from_arrays(cls, left, right, closed='right', copy=False, dtype=None): See Also -------- - interval_range : Function to create a fixed frequency IntervalIndex + interval_range : Function to create a fixed frequency IntervalIndex. %(klass)s.from_arrays : Construct an %(klass)s from a left and - right array + right array. %(klass)s.from_breaks : Construct an %(klass)s from an array of - splits + splits. %(klass)s.from_tuples : Construct an %(klass)s from an - array-like of tuples + array-like of tuples. """ _interval_shared_docs['from_tuples'] = """ @@ -389,11 +389,11 @@ def from_arrays(cls, left, right, closed='right', copy=False, dtype=None): See Also -------- - interval_range : Function to create a fixed frequency IntervalIndex + interval_range : Function to create a fixed frequency IntervalIndex. %(klass)s.from_arrays : Construct an %(klass)s from a left and - right array + right array. %(klass)s.from_breaks : Construct an %(klass)s from an array of - splits + splits. """ @classmethod @@ -1027,9 +1027,9 @@ def repeat(self, repeats, **kwargs): See Also -------- - Index.repeat : Equivalent function for Index - Series.repeat : Equivalent function for Series - numpy.repeat : Underlying implementation + Index.repeat : Equivalent function for Index. + Series.repeat : Equivalent function for Series. + numpy.repeat : Underlying implementation. """ left_repeat = self.left.repeat(repeats, **kwargs) right_repeat = self.right.repeat(repeats, **kwargs) diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index e46b00da6161e..d9989b1ac36c0 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -146,8 +146,8 @@ class PeriodArray(dtl.DatetimeLikeArrayMixin, ExtensionArray): See Also -------- - period_array : Create a new PeriodArray - pandas.PeriodIndex : Immutable Index for period data + period_array : Create a new PeriodArray. + pandas.PeriodIndex : Immutable Index for period data. """ # array priority higher than numpy scalars __array_priority__ = 1000 diff --git a/pandas/core/base.py b/pandas/core/base.py index 5533054fcaf8a..17108c16c07dc 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -1014,8 +1014,8 @@ def value_counts(self, normalize=False, sort=True, ascending=False, See Also -------- - Series.count: number of non-NA elements in a Series - DataFrame.count: number of non-NA elements in a DataFrame + Series.count: Number of non-NA elements in a Series. + DataFrame.count: Number of non-NA elements in a DataFrame. Examples -------- diff --git a/pandas/core/dtypes/inference.py b/pandas/core/dtypes/inference.py index 5f35a040d7d47..241a1b471f677 100644 --- a/pandas/core/dtypes/inference.py +++ b/pandas/core/dtypes/inference.py @@ -44,7 +44,7 @@ def is_number(obj): See Also -------- - pandas.api.types.is_integer: checks a subgroup of numbers + pandas.api.types.is_integer: Checks a subgroup of numbers. Examples -------- diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index a12985bb7d42c..fa60c326a19ea 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -43,7 +43,7 @@ def isna(obj): See Also -------- - notna : boolean inverse of pandas.isna. + notna : Boolean inverse of pandas.isna. Series.isna : Detect missing values in a Series. DataFrame.isna : Detect missing values in a DataFrame. Index.isna : Detect missing values in an Index. @@ -274,7 +274,7 @@ def notna(obj): See Also -------- - isna : boolean inverse of pandas.notna. + isna : Boolean inverse of pandas.notna. Series.notna : Detect valid values in a Series. DataFrame.notna : Detect valid values in a DataFrame. Index.notna : Detect valid values in an Index. diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 3a8ad3f98f8e0..511604517a84e 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -221,9 +221,9 @@ See Also -------- -merge_ordered : merge with optional filling/interpolation. -merge_asof : merge on nearest keys. -DataFrame.join : similar method using indices. +merge_ordered : Merge with optional filling/interpolation. +merge_asof : Merge on nearest keys. +DataFrame.join : Similar method using indices. Examples -------- @@ -348,10 +348,10 @@ class DataFrame(NDFrame): See Also -------- - DataFrame.from_records : constructor from tuples, also record arrays - DataFrame.from_dict : from dicts of Series, arrays, or dicts - DataFrame.from_items : from sequence of (key, value) pairs - pandas.read_csv, pandas.read_table, pandas.read_clipboard + DataFrame.from_records : Constructor from tuples, also record arrays. + DataFrame.from_dict : From dicts of Series, arrays, or dicts. + DataFrame.from_items : From sequence of (key, value) pairs + pandas.read_csv, pandas.read_table, pandas.read_clipboard. """ @property @@ -1066,8 +1066,8 @@ def from_dict(cls, data, orient='columns', dtype=None, columns=None): See Also -------- DataFrame.from_records : DataFrame from ndarray (structured - dtype), list of tuples, dict, or DataFrame - DataFrame : DataFrame object creation using constructor + dtype), list of tuples, dict, or DataFrame. + DataFrame : DataFrame object creation using constructor. Examples -------- @@ -1484,9 +1484,9 @@ def to_records(self, index=True, convert_datetime64=None): See Also -------- - DataFrame.from_records: convert structured or record ndarray + DataFrame.from_records: Convert structured or record ndarray to DataFrame. - numpy.recarray: ndarray that allows field access using + numpy.recarray: An ndarray that allows field access using attributes, analogous to typed columns in a spreadsheet. @@ -1900,9 +1900,10 @@ def to_stata(self, fname, convert_dates=None, write_index=True, See Also -------- - pandas.read_stata : Import Stata data files - pandas.io.stata.StataWriter : low-level writer for Stata data files - pandas.io.stata.StataWriter117 : low-level writer for version 117 files + pandas.read_stata : Import Stata data files. + pandas.io.stata.StataWriter : Low-level writer for Stata data files. + pandas.io.stata.StataWriter117 : Low-level writer for version 117 + files. Examples -------- @@ -3729,9 +3730,9 @@ def drop(self, labels=None, axis=0, index=None, columns=None, -------- DataFrame.loc : Label-location based indexer for selection by label. DataFrame.dropna : Return DataFrame with labels on given axis omitted - where (all or any) data are missing + where (all or any) data are missing. DataFrame.drop_duplicates : Return DataFrame with duplicate rows - removed, optionally only considering certain columns + removed, optionally only considering certain columns. Series.drop : Return Series with specified index labels removed. Raises @@ -4683,7 +4684,7 @@ def nlargest(self, n, columns, keep='first'): -------- DataFrame.nsmallest : Return the first `n` rows ordered by `columns` in ascending order. - DataFrame.sort_values : Sort DataFrame by the values + DataFrame.sort_values : Sort DataFrame by the values. DataFrame.head : Return the first `n` rows without re-ordering. Notes @@ -5070,7 +5071,7 @@ def combine(self, other, func, fill_value=None, overwrite=True): See Also -------- DataFrame.combine_first : Combine two DataFrame objects and default to - non-null values in frame calling the method + non-null values in frame calling the method. """ other_idxlen = len(other.index) # save for compare @@ -5176,7 +5177,7 @@ def combine_first(self, other): See Also -------- DataFrame.combine : Perform series-wise operation on two DataFrames - using a given function + using a given function. """ import pandas.core.computation.expressions as expressions @@ -5388,9 +5389,9 @@ def update(self, other, join='left', overwrite=True, filter_func=None, See Also -------- - DataFrame.pivot_table : generalization of pivot that can handle + DataFrame.pivot_table : Generalization of pivot that can handle duplicate values for one index/column pair. - DataFrame.unstack : pivot based on the index values instead of a + DataFrame.unstack : Pivot based on the index values instead of a column. Notes @@ -5576,8 +5577,8 @@ def pivot(self, index=None, columns=None, values=None): See Also -------- - DataFrame.pivot : pivot without aggregation that can handle - non-numeric data + DataFrame.pivot : Pivot without aggregation that can handle + non-numeric data. """ @Substitution('') @@ -6226,9 +6227,9 @@ def apply(self, func, axis=0, broadcast=None, raw=False, reduce=None, See Also -------- - DataFrame.applymap: For elementwise operations - DataFrame.aggregate: only perform aggregating type operations - DataFrame.transform: only perform transforming type operations + DataFrame.applymap: For elementwise operations. + DataFrame.aggregate: Only perform aggregating type operations. + DataFrame.transform: Only perform transforming type operations. Examples -------- @@ -6335,7 +6336,7 @@ def applymap(self, func): See Also -------- - DataFrame.apply : Apply a function along input axis of DataFrame + DataFrame.apply : Apply a function along input axis of DataFrame. Examples -------- @@ -6419,7 +6420,7 @@ def append(self, other, ignore_index=False, See Also -------- pandas.concat : General function to concatenate DataFrame, Series - or Panel objects + or Panel objects. Examples -------- @@ -6886,10 +6887,10 @@ def cov(self, min_periods=None): See Also -------- - pandas.Series.cov : compute covariance with another Series - pandas.core.window.EWM.cov: exponential weighted sample covariance - pandas.core.window.Expanding.cov : expanding sample covariance - pandas.core.window.Rolling.cov : rolling sample covariance + pandas.Series.cov : Compute covariance with another Series. + pandas.core.window.EWM.cov: Exponential weighted sample covariance. + pandas.core.window.Expanding.cov : Expanding sample covariance. + pandas.core.window.Rolling.cov : Rolling sample covariance. Notes ----- @@ -7046,11 +7047,11 @@ def count(self, axis=0, level=None, numeric_only=False): See Also -------- - Series.count: number of non-NA elements in a Series - DataFrame.shape: number of DataFrame rows and columns (including NA - elements) - DataFrame.isna: boolean same-sized DataFrame showing places of NA - elements + Series.count: Number of non-NA elements in a Series. + DataFrame.shape: Number of DataFrame rows and columns (including NA + elements). + DataFrame.isna: Boolean same-sized DataFrame showing places of NA + elements. Examples -------- diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 1c81105b9d417..9f56433c6868e 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -854,8 +854,8 @@ def squeeze(self, axis=None): See Also -------- - Series.iloc : Integer-location based indexing for selecting scalars - DataFrame.iloc : Integer-location based indexing for selecting Series + Series.iloc : Integer-location based indexing for selecting scalars. + DataFrame.iloc : Integer-location based indexing for selecting Series. Series.to_frame : Inverse of DataFrame.squeeze for a single-column DataFrame. @@ -1166,9 +1166,9 @@ def rename_axis(self, mapper=None, **kwargs): See Also -------- - pandas.Series.rename : Alter Series index labels or name - pandas.DataFrame.rename : Alter DataFrame index labels or name - pandas.Index.rename : Set new names on index + pandas.Series.rename : Alter Series index labels or name. + pandas.DataFrame.rename : Alter DataFrame index labels or name. + pandas.Index.rename : Set new names on index. Examples -------- @@ -2398,7 +2398,7 @@ def to_sql(self, name, con, schema=None, if_exists='fail', index=True, See Also -------- - pandas.read_sql : read a DataFrame from a table + pandas.read_sql : Read a DataFrame from a table. Notes ----- @@ -4980,8 +4980,8 @@ def values(self): See Also -------- - pandas.DataFrame.index : Retrieve the index labels - pandas.DataFrame.columns : Retrieving the column names + pandas.DataFrame.index : Retrieve the index labels. + pandas.DataFrame.columns : Retrieving the column names. """ self._consolidate_inplace() return self._data.as_array(transpose=self._AXIS_REVERSED) @@ -5133,7 +5133,7 @@ def dtypes(self): See Also -------- - pandas.DataFrame.ftypes : dtype and sparsity information. + pandas.DataFrame.ftypes : Dtype and sparsity information. Examples -------- @@ -5894,8 +5894,8 @@ def bfill(self, axis=None, inplace=False, limit=None, downcast=None): See Also -------- - %(klass)s.fillna : Fill NA values - %(klass)s.where : Replace values based on boolean condition + %(klass)s.fillna : Fill NA values. + %(klass)s.where : Replace values based on boolean condition. Series.str.replace : Simple string replacement. Returns @@ -6694,10 +6694,10 @@ def asof(self, where, subset=None): See Also -------- - %(klass)s.isnull : alias of isna - %(klass)s.notna : boolean inverse of isna - %(klass)s.dropna : omit axes labels with missing values - isna : top-level isna + %(klass)s.isnull : Alias of isna. + %(klass)s.notna : Boolean inverse of isna. + %(klass)s.dropna : Omit axes labels with missing values. + isna : Top-level isna. Examples -------- @@ -6762,10 +6762,10 @@ def isnull(self): See Also -------- - %(klass)s.notnull : alias of notna - %(klass)s.isna : boolean inverse of notna - %(klass)s.dropna : omit axes labels with missing values - notna : top-level notna + %(klass)s.notnull : Alias of notna. + %(klass)s.isna : Boolean inverse of notna. + %(klass)s.dropna : Omit axes labels with missing values. + notna : Top-level notna. Examples -------- @@ -7015,12 +7015,12 @@ def clip_upper(self, threshold, axis=None, inplace=False): See Also -------- DataFrame.clip : General purpose method to trim DataFrame values to - given threshold(s) + given threshold(s). DataFrame.clip_lower : Trim DataFrame values below given - threshold(s) + threshold(s). Series.clip : General purpose method to trim Series values to given - threshold(s) - Series.clip_lower : Trim Series values below given threshold(s) + threshold(s). + Series.clip_lower : Trim Series values below given threshold(s). Examples -------- @@ -7093,12 +7093,12 @@ def clip_lower(self, threshold, axis=None, inplace=False): See Also -------- DataFrame.clip : General purpose method to trim DataFrame values to - given threshold(s) + given threshold(s). DataFrame.clip_upper : Trim DataFrame values above given - threshold(s) + threshold(s). Series.clip : General purpose method to trim Series values to given - threshold(s) - Series.clip_upper : Trim Series values above given threshold(s) + threshold(s). + Series.clip_upper : Trim Series values above given threshold(s). Examples -------- @@ -7423,11 +7423,11 @@ def at_time(self, time, asof=False): See Also -------- - between_time : Select values between particular times of the day - first : Select initial periods of time series based on a date offset - last : Select final periods of time series based on a date offset + between_time : Select values between particular times of the day. + first : Select initial periods of time series based on a date offset. + last : Select final periods of time series based on a date offset. DatetimeIndex.indexer_at_time : Get just the index locations for - values at particular time of the day + values at particular time of the day. """ try: indexer = self.index.indexer_at_time(time, asof=asof) @@ -7485,11 +7485,11 @@ def between_time(self, start_time, end_time, include_start=True, See Also -------- - at_time : Select values at a particular time of the day - first : Select initial periods of time series based on a date offset - last : Select final periods of time series based on a date offset + at_time : Select values at a particular time of the day. + first : Select initial periods of time series based on a date offset. + last : Select final periods of time series based on a date offset. DatetimeIndex.indexer_between_time : Get just the index locations for - values between particular times of the day + values between particular times of the day. """ try: indexer = self.index.indexer_between_time( @@ -7840,9 +7840,9 @@ def first(self, offset): See Also -------- - last : Select final periods of time series based on a date offset - at_time : Select values at a particular time of the day - between_time : Select values between particular times of the day + last : Select final periods of time series based on a date offset. + at_time : Select values at a particular time of the day. + between_time : Select values between particular times of the day. """ if not isinstance(self.index, DatetimeIndex): raise TypeError("'first' only supports a DatetimeIndex index") @@ -7903,9 +7903,9 @@ def last(self, offset): See Also -------- - first : Select initial periods of time series based on a date offset - at_time : Select values at a particular time of the day - between_time : Select values between particular times of the day + first : Select initial periods of time series based on a date offset. + at_time : Select values at a particular time of the day. + between_time : Select values between particular times of the day. """ if not isinstance(self.index, DatetimeIndex): raise TypeError("'last' only supports a DatetimeIndex index") @@ -8389,7 +8389,7 @@ def _where(self, cond, other=np.nan, inplace=False, axis=None, level=None, See Also -------- :func:`DataFrame.%(name_other)s` : Return an object of same shape as - self + self. Examples -------- @@ -9061,7 +9061,7 @@ def abs(self): See Also -------- - numpy.absolute : calculate the absolute value element-wise. + numpy.absolute : Calculate the absolute value element-wise. """ return np.abs(self) @@ -10112,8 +10112,8 @@ def _doc_parms(cls): _all_see_also = """\ See Also -------- -pandas.Series.all : Return True if all elements are True -pandas.DataFrame.any : Return True if one (or more) elements are True +pandas.Series.all : Return True if all elements are True. +pandas.DataFrame.any : Return True if one (or more) elements are True. """ _cnum_doc = """ diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index bf1e5ebb18786..96aff09126772 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -216,8 +216,8 @@ class providing the base-class of operations. See Also -------- -pandas.Series.pipe : Apply a function with arguments to a series -pandas.DataFrame.pipe: Apply a function with arguments to a dataframe +pandas.Series.pipe : Apply a function with arguments to a series. +pandas.DataFrame.pipe: Apply a function with arguments to a dataframe. apply : Apply function to each group instead of to the full %(klass)s object. """ diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index ff2562a4480bc..2f449b4b33d8d 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -212,10 +212,10 @@ class Index(IndexOpsMixin, PandasObject): See Also --------- - RangeIndex : Index implementing a monotonic integer range + RangeIndex : Index implementing a monotonic integer range. CategoricalIndex : Index of :class:`Categorical` s. - MultiIndex : A multi-level, or hierarchical, Index - IntervalIndex : an Index of :class:`Interval` s. + MultiIndex : A multi-level, or hierarchical, Index. + IntervalIndex : An Index of :class:`Interval` s. DatetimeIndex, TimedeltaIndex, PeriodIndex Int64Index, UInt64Index, Float64Index """ @@ -820,8 +820,8 @@ def repeat(self, repeats, *args, **kwargs): See Also -------- - Series.repeat : Equivalent function for Series - numpy.repeat : Underlying implementation + Series.repeat : Equivalent function for Series. + numpy.repeat : Underlying implementation. Examples -------- @@ -2269,10 +2269,10 @@ def isna(self): See Also -------- - pandas.Index.notna : boolean inverse of isna. - pandas.Index.dropna : omit entries with missing values. - pandas.isna : top-level isna. - Series.isna : detect missing values in Series object. + pandas.Index.notna : Boolean inverse of isna. + pandas.Index.dropna : Omit entries with missing values. + pandas.isna : Top-level isna. + Series.isna : Detect missing values in Series object. Examples -------- @@ -2327,9 +2327,9 @@ def notna(self): See Also -------- - Index.notnull : alias of notna - Index.isna: inverse of notna - pandas.notna : top-level notna + Index.notnull : Alias of notna. + Index.isna: Inverse of notna. + pandas.notna : Top-level notna. Examples -------- @@ -2506,7 +2506,7 @@ def asof(self, label): passed index. merge_asof : Perform an asof merge (similar to left join but it matches on nearest key rather than equal key). - Index.get_loc : `asof` is a thin wrapper around `get_loc` + Index.get_loc : An `asof` is a thin wrapper around `get_loc` with method='pad'. Examples @@ -3224,7 +3224,7 @@ def _get_level_values(self, level): See Also -------- - MultiIndex.get_level_values : get values for a level of a MultiIndex + MultiIndex.get_level_values : Get values for a level of a MultiIndex. Notes ----- @@ -4429,7 +4429,7 @@ def slice_locs(self, start=None, end=None, step=None, kind=None): See Also -------- - Index.get_loc : Get location for a single label + Index.get_loc : Get location for a single label. """ inc = (step is None or step >= 0) @@ -4581,9 +4581,9 @@ def drop_duplicates(self, keep='first'): See Also -------- - Series.drop_duplicates : equivalent method on Series - DataFrame.drop_duplicates : equivalent method on DataFrame - Index.duplicated : related method on Index, indicating duplicate + Series.drop_duplicates : Equivalent method on Series. + DataFrame.drop_duplicates : Equivalent method on DataFrame. + Index.duplicated : Related method on Index, indicating duplicate Index values. Examples @@ -4662,9 +4662,9 @@ def duplicated(self, keep='first'): See Also -------- - pandas.Series.duplicated : Equivalent method on pandas.Series - pandas.DataFrame.duplicated : Equivalent method on pandas.DataFrame - pandas.Index.drop_duplicates : Remove duplicate values from Index + pandas.Series.duplicated : Equivalent method on pandas.Series. + pandas.DataFrame.duplicated : Equivalent method on pandas.DataFrame. + pandas.Index.drop_duplicates : Remove duplicate values from Index. """ return super(Index, self).duplicated(keep=keep) diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 39bc7f4b85de2..7616bc4ea10ef 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -58,7 +58,7 @@ def strftime(self, date_format): See Also -------- - pandas.to_datetime : Convert the given argument to datetime + pandas.to_datetime : Convert the given argument to datetime. DatetimeIndex.normalize : Return DatetimeIndex with times to midnight. DatetimeIndex.round : Round the DatetimeIndex to the specified freq. DatetimeIndex.floor : Floor the DatetimeIndex to the specified freq. diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index 23446a57e7789..a1fed8b93fcbb 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -164,10 +164,10 @@ class DatetimeIndex(DatetimeArray, DatelikeOps, TimelikeOps, See Also --------- - Index : The base pandas Index type - TimedeltaIndex : Index of timedelta64 data - PeriodIndex : Index of Period data - pandas.to_datetime : Convert argument to datetime + Index : The base pandas Index type. + TimedeltaIndex : Index of timedelta64 data. + PeriodIndex : Index of Period data. + pandas.to_datetime : Convert argument to datetime. """ _typ = 'datetimeindex' diff --git a/pandas/core/indexes/frozen.py b/pandas/core/indexes/frozen.py index 3ac4a2bf31a7e..cb145dd9eed4d 100644 --- a/pandas/core/indexes/frozen.py +++ b/pandas/core/indexes/frozen.py @@ -164,7 +164,7 @@ def searchsorted(self, value, side="left", sorter=None): See Also -------- - numpy.searchsorted : equivalent function + numpy.searchsorted : Equivalent function. """ # We are much more performant if the searched diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index eb4284203d865..2b157bf91c5a2 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -1185,7 +1185,7 @@ def interval_range(start=None, end=None, periods=None, freq=None, See Also -------- - IntervalIndex : an Index of intervals that are all closed on the same side. + IntervalIndex : An Index of intervals that are all closed on the same side. """ start = com.maybe_box_datetimelike(start) end = com.maybe_box_datetimelike(end) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 310e7c2bd95d7..dbb1b8e196bf7 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -171,11 +171,11 @@ class MultiIndex(Index): See Also -------- - MultiIndex.from_arrays : Convert list of arrays to MultiIndex + MultiIndex.from_arrays : Convert list of arrays to MultiIndex. MultiIndex.from_product : Create a MultiIndex from the cartesian product - of iterables - MultiIndex.from_tuples : Convert list of tuples to a MultiIndex - Index : The base pandas Index type + of iterables. + MultiIndex.from_tuples : Convert list of tuples to a MultiIndex. + Index : The base pandas Index type. Attributes ---------- @@ -1325,9 +1325,9 @@ def from_arrays(cls, arrays, sortorder=None, names=None): See Also -------- - MultiIndex.from_tuples : Convert list of tuples to MultiIndex + MultiIndex.from_tuples : Convert list of tuples to MultiIndex. MultiIndex.from_product : Make a MultiIndex from cartesian product - of iterables + of iterables. """ if not is_list_like(arrays): raise TypeError("Input must be a list / sequence of array-likes.") @@ -1431,8 +1431,8 @@ def from_product(cls, iterables, sortorder=None, names=None): See Also -------- - MultiIndex.from_arrays : Convert list of arrays to MultiIndex - MultiIndex.from_tuples : Convert list of tuples to MultiIndex + MultiIndex.from_arrays : Convert list of arrays to MultiIndex. + MultiIndex.from_tuples : Convert list of tuples to MultiIndex. """ from pandas.core.arrays.categorical import _factorize_from_iterables from pandas.core.reshape.util import cartesian_product @@ -1833,9 +1833,9 @@ def swaplevel(self, i=-2, j=-1): See Also -------- - Series.swaplevel : Swap levels i and j in a MultiIndex + Series.swaplevel : Swap levels i and j in a MultiIndex. Dataframe.swaplevel : Swap levels i and j in a MultiIndex on a - particular axis + particular axis. Examples -------- @@ -2235,7 +2235,7 @@ def get_loc(self, key, method=None): See Also -------- - Index.get_loc : get_loc method for (single-level) index. + Index.get_loc : The get_loc method for (single-level) index. MultiIndex.slice_locs : Get slice location given start label(s) and end label(s). MultiIndex.get_locs : Get location for a label/slice/list/mask or a @@ -2339,7 +2339,7 @@ def get_loc_level(self, key, level=0, drop_level=True): --------- MultiIndex.get_loc : Get location for a label or a tuple of labels. MultiIndex.get_locs : Get location for a label/slice/list/mask or a - sequence of such + sequence of such. """ def maybe_droplevels(indexer, levels, drop_level): diff --git a/pandas/core/indexes/numeric.py b/pandas/core/indexes/numeric.py index bdd0bf40507f4..23b2dde2e6494 100644 --- a/pandas/core/indexes/numeric.py +++ b/pandas/core/indexes/numeric.py @@ -157,7 +157,7 @@ def insert(self, loc, item): See Also -------- - Index : The base pandas Index type + Index : The base pandas Index type. """ _int64_descr_args = dict( diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index 7890f03a1eba7..f35e775fc0a28 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -165,10 +165,10 @@ class PeriodIndex(DatelikeOps, DatetimeIndexOpsMixin, See Also --------- - Index : The base pandas Index type - Period : Represents a period of time - DatetimeIndex : Index with datetime64 data - TimedeltaIndex : Index of timedelta64 data + Index : The base pandas Index type. + Period : Represents a period of time. + DatetimeIndex : Index with datetime64 data. + TimedeltaIndex : Index of timedelta64 data. """ _typ = 'periodindex' _attributes = ['name', 'freq'] diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index e689eb4a7d84a..0d4e7aaebeca5 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -49,8 +49,8 @@ class RangeIndex(Int64Index): See Also -------- - Index : The base pandas Index type - Int64Index : Index of int64 data + Index : The base pandas Index type. + Int64Index : Index of int64 data. Attributes ---------- diff --git a/pandas/core/indexes/timedeltas.py b/pandas/core/indexes/timedeltas.py index d9625d38b85de..9f9d8b1b67171 100644 --- a/pandas/core/indexes/timedeltas.py +++ b/pandas/core/indexes/timedeltas.py @@ -72,10 +72,10 @@ class TimedeltaIndex(TimedeltaArray, DatetimeIndexOpsMixin, See Also --------- - Index : The base pandas Index type + Index : The base pandas Index type. Timedelta : Represents a duration between two dates or times. - DatetimeIndex : Index of datetime64 data - PeriodIndex : Index of Period data + DatetimeIndex : Index of datetime64 data. + PeriodIndex : Index of Period data. Attributes ---------- diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 0c6aaf4b46d6a..d376c95a7e1b3 100755 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1569,11 +1569,11 @@ class _LocIndexer(_LocationIndexer): See Also -------- - DataFrame.at : Access a single value for a row/column label pair - DataFrame.iloc : Access group of rows and columns by integer position(s) + DataFrame.at : Access a single value for a row/column label pair. + DataFrame.iloc : Access group of rows and columns by integer position(s). DataFrame.xs : Returns a cross-section (row(s) or column(s)) from the Series/DataFrame. - Series.loc : Access group of values using labels + Series.loc : Access group of values using labels. Examples -------- @@ -2302,9 +2302,9 @@ class _AtIndexer(_ScalarAccessIndexer): See Also -------- DataFrame.iat : Access a single value for a row/column pair by integer - position - DataFrame.loc : Access a group of rows and columns by label(s) - Series.at : Access a single value using a label + position. + DataFrame.loc : Access a group of rows and columns by label(s). + Series.at : Access a single value using a label. Examples -------- @@ -2372,9 +2372,9 @@ class _iAtIndexer(_ScalarAccessIndexer): See Also -------- - DataFrame.at : Access a single value for a row/column label pair - DataFrame.loc : Access a group of rows and columns by label(s) - DataFrame.iloc : Access a group of rows and columns by integer position(s) + DataFrame.at : Access a single value for a row/column label pair. + DataFrame.loc : Access a group of rows and columns by label(s). + DataFrame.iloc : Access a group of rows and columns by integer position(s). Examples -------- diff --git a/pandas/core/series.py b/pandas/core/series.py index 9a3873a41a2da..7f832009ca273 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1456,8 +1456,8 @@ def unique(self): See Also -------- - pandas.unique : top-level unique method for any 1-d array-like object. - Index.unique : return Index with unique values from an Index object. + pandas.unique : Top-level unique method for any 1-d array-like object. + Index.unique : Return Index with unique values from an Index object. Examples -------- @@ -1516,9 +1516,9 @@ def drop_duplicates(self, keep='first', inplace=False): See Also -------- - Index.drop_duplicates : equivalent method on Index - DataFrame.drop_duplicates : equivalent method on DataFrame - Series.duplicated : related method on Series, indicating duplicate + Index.drop_duplicates : Equivalent method on Index. + DataFrame.drop_duplicates : Equivalent method on DataFrame. + Series.duplicated : Related method on Series, indicating duplicate Series values. Examples @@ -1638,9 +1638,9 @@ def duplicated(self, keep='first'): See Also -------- - pandas.Index.duplicated : Equivalent method on pandas.Index - pandas.DataFrame.duplicated : Equivalent method on pandas.DataFrame - pandas.Series.drop_duplicates : Remove duplicate values from Series + pandas.Index.duplicated : Equivalent method on pandas.Index. + pandas.DataFrame.duplicated : Equivalent method on pandas.DataFrame. + pandas.Series.drop_duplicates : Remove duplicate values from Series. """ return super(Series, self).duplicated(keep=keep) @@ -1976,7 +1976,7 @@ def diff(self, periods=1): Series.pct_change: Percent change over given number of periods. Series.shift: Shift index by desired number of periods with an optional time freq. - DataFrame.diff: First discrete difference of object + DataFrame.diff: First discrete difference of object. Examples -------- @@ -2184,7 +2184,7 @@ def append(self, to_append, ignore_index=False, verify_integrity=False): See Also -------- pandas.concat : General function to concatenate DataFrame, Series - or Panel objects + or Panel objects. Returns ------- @@ -2316,7 +2316,7 @@ def combine(self, other, func, fill_value=None): See Also -------- Series.combine_first : Combine Series values, choosing the calling - Series's values first + Series's values first. """ if fill_value is None: fill_value = na_value_for_dtype(self.dtype, compat=False) @@ -2381,7 +2381,7 @@ def combine_first(self, other): See Also -------- Series.combine : Perform elementwise operation on two Series - using a given function + using a given function. """ new_index = self.index.union(other.index) this = self.reindex(new_index, copy=False) @@ -2649,9 +2649,9 @@ def sort_index(self, axis=0, level=None, ascending=True, inplace=False, See Also -------- - DataFrame.sort_index: Sort DataFrame by the index - DataFrame.sort_values: Sort DataFrame by the value - Series.sort_values : Sort Series by the value + DataFrame.sort_index: Sort DataFrame by the index. + DataFrame.sort_values: Sort DataFrame by the value. + Series.sort_values : Sort Series by the value. Examples -------- @@ -3265,9 +3265,9 @@ def apply(self, func, convert_dtype=True, args=(), **kwds): See Also -------- - Series.map: For element-wise operations - Series.agg: only perform aggregating type operations - Series.transform: only perform transforming type operations + Series.map: For element-wise operations. + Series.agg: Only perform aggregating type operations. + Series.transform: Only perform transforming type operations. Examples -------- @@ -3742,7 +3742,7 @@ def isin(self, values): See Also -------- - pandas.DataFrame.isin : equivalent method on DataFrame + pandas.DataFrame.isin : Equivalent method on DataFrame. Examples -------- @@ -3800,8 +3800,8 @@ def between(self, left, right, inclusive=True): See Also -------- - pandas.Series.gt : Greater than of series and other - pandas.Series.lt : Less than of series and other + pandas.Series.gt : Greater than of series and other. + pandas.Series.lt : Less than of series and other. Examples -------- diff --git a/pandas/core/strings.py b/pandas/core/strings.py index a12605aaed554..99aab607b2bf0 100644 --- a/pandas/core/strings.py +++ b/pandas/core/strings.py @@ -205,7 +205,7 @@ def str_contains(arr, pat, case=True, flags=0, na=np.nan, regex=True): See Also -------- - match : analogous, but stricter, relying on re.match instead of re.search + match : Analogous, but stricter, relying on re.match instead of re.search. Series.str.startswith : Test if the start of each string element matches a pattern. Series.str.endswith : Same as startswith, but tests the end of string. @@ -667,9 +667,9 @@ def str_match(arr, pat, case=True, flags=0, na=np.nan): See Also -------- - contains : analogous, but less strict, relying on re.search instead of - re.match - extract : extract matched groups + contains : Analogous, but less strict, relying on re.search instead of + re.match. + extract : Extract matched groups. """ if not case: @@ -803,7 +803,7 @@ def str_extract(arr, pat, flags=0, expand=True): See Also -------- - extractall : returns all matches (not just the first match) + extractall : Returns all matches (not just the first match). Examples -------- @@ -890,7 +890,7 @@ def str_extractall(arr, pat, flags=0): See Also -------- - extract : returns first match only (not all matches) + extract : Returns first match only (not all matches). Examples -------- @@ -2104,8 +2104,8 @@ def cat(self, others=None, sep=None, na_rep=None, join=None): See Also -------- - split : Split each string in the Series/Index - join : Join lists contained as elements in the Series/Index + split : Split each string in the Series/Index. + join : Join lists contained as elements in the Series/Index. Examples -------- @@ -2676,9 +2676,9 @@ def encode(self, encoding, errors="strict"): See Also -------- - Series.str.strip : Remove leading and trailing characters in Series/Index - Series.str.lstrip : Remove leading characters in Series/Index - Series.str.rstrip : Remove trailing characters in Series/Index + Series.str.strip : Remove leading and trailing characters in Series/Index. + Series.str.lstrip : Remove leading characters in Series/Index. + Series.str.rstrip : Remove trailing characters in Series/Index. Examples -------- diff --git a/pandas/core/window.py b/pandas/core/window.py index b250851a18f4d..edd7191bcc458 100644 --- a/pandas/core/window.py +++ b/pandas/core/window.py @@ -416,10 +416,10 @@ def aggregate(self, arg, *args, **kwargs): See Also -------- - Series.%(name)s : Calling object with Series data - DataFrame.%(name)s : Calling object with DataFrames - Series.mean : Equivalent method for Series - DataFrame.mean : Equivalent method for DataFrame + Series.%(name)s : Calling object with Series data. + DataFrame.%(name)s : Calling object with DataFrames. + Series.mean : Equivalent method for Series. + DataFrame.mean : Equivalent method for DataFrame. Examples -------- @@ -592,7 +592,7 @@ class Window(_Window): See Also -------- expanding : Provides expanding transformations. - ewm : Provides exponential weighted functions + ewm : Provides exponential weighted functions. """ def validate(self): @@ -903,9 +903,9 @@ class _Rolling_and_Expanding(_Rolling): See Also -------- - pandas.Series.%(name)s : Calling object with Series data - pandas.DataFrame.%(name)s : Calling object with DataFrames - pandas.DataFrame.count : Count of the full DataFrame + pandas.Series.%(name)s : Calling object with Series data. + pandas.DataFrame.%(name)s : Calling object with DataFrames. + pandas.DataFrame.count : Count of the full DataFrame. Examples -------- @@ -1031,10 +1031,10 @@ def max(self, *args, **kwargs): See Also -------- - Series.%(name)s : Calling object with a Series - DataFrame.%(name)s : Calling object with a DataFrame - Series.min : Similar method for Series - DataFrame.min : Similar method for DataFrame + Series.%(name)s : Calling object with a Series. + DataFrame.%(name)s : Calling object with a DataFrame. + Series.min : Similar method for Series. + DataFrame.min : Similar method for DataFrame. Examples -------- @@ -1074,10 +1074,10 @@ def mean(self, *args, **kwargs): See Also -------- - Series.%(name)s : Calling object with Series data - DataFrame.%(name)s : Calling object with DataFrames - Series.median : Equivalent method for Series - DataFrame.median : Equivalent method for DataFrame + Series.%(name)s : Calling object with Series data. + DataFrame.%(name)s : Calling object with DataFrames. + Series.median : Equivalent method for Series. + DataFrame.median : Equivalent method for DataFrame. Examples -------- @@ -1117,11 +1117,11 @@ def median(self, **kwargs): See Also -------- - Series.%(name)s : Calling object with Series data - DataFrame.%(name)s : Calling object with DataFrames - Series.std : Equivalent method for Series - DataFrame.std : Equivalent method for DataFrame - numpy.std : Equivalent method for Numpy array + Series.%(name)s : Calling object with Series data. + DataFrame.%(name)s : Calling object with DataFrames. + Series.std : Equivalent method for Series. + DataFrame.std : Equivalent method for DataFrame. + numpy.std : Equivalent method for Numpy array. Notes ----- @@ -1188,11 +1188,11 @@ def f(arg, *args, **kwargs): See Also -------- - Series.%(name)s : Calling object with Series data - DataFrame.%(name)s : Calling object with DataFrames - Series.var : Equivalent method for Series - DataFrame.var : Equivalent method for DataFrame - numpy.var : Equivalent method for Numpy array + Series.%(name)s : Calling object with Series data. + DataFrame.%(name)s : Calling object with DataFrames. + Series.var : Equivalent method for Series. + DataFrame.var : Equivalent method for DataFrame. + numpy.var : Equivalent method for Numpy array. Notes ----- @@ -1255,12 +1255,12 @@ def skew(self, **kwargs): See Also -------- - Series.%(name)s : Calling object with Series data - DataFrame.%(name)s : Calling object with DataFrames - Series.kurt : Equivalent method for Series - DataFrame.kurt : Equivalent method for DataFrame - scipy.stats.skew : Third moment of a probability density - scipy.stats.kurtosis : Reference SciPy method + Series.%(name)s : Calling object with Series data. + DataFrame.%(name)s : Calling object with DataFrames. + Series.kurt : Equivalent method for Series. + DataFrame.kurt : Equivalent method for DataFrame. + scipy.stats.skew : Third moment of a probability density. + scipy.stats.kurtosis : Reference SciPy method. Notes ----- @@ -1414,12 +1414,12 @@ def _get_cov(X, Y): See Also -------- - Series.%(name)s : Calling object with Series data - DataFrame.%(name)s : Calling object with DataFrames - Series.corr : Equivalent method for Series - DataFrame.corr : Equivalent method for DataFrame - %(name)s.cov : Similar method to calculate covariance - numpy.corrcoef : NumPy Pearson's correlation calculation + Series.%(name)s : Calling object with Series data. + DataFrame.%(name)s : Calling object with DataFrames. + Series.corr : Equivalent method for Series. + DataFrame.corr : Equivalent method for DataFrame. + %(name)s.cov : Similar method to calculate covariance. + numpy.corrcoef : NumPy Pearson's correlation calculation. Notes ----- @@ -1849,8 +1849,8 @@ class Expanding(_Rolling_and_Expanding): See Also -------- - rolling : Provides rolling window calculations - ewm : Provides exponential weighted functions + rolling : Provides rolling window calculations. + ewm : Provides exponential weighted functions. """ _attributes = ['min_periods', 'center', 'axis'] @@ -2168,7 +2168,7 @@ class EWM(_Rolling): See Also -------- - rolling : Provides rolling window calculations + rolling : Provides rolling window calculations. expanding : Provides expanding transformations. """ _attributes = ['com', 'min_periods', 'adjust', 'ignore_na', 'axis'] diff --git a/pandas/io/json/table_schema.py b/pandas/io/json/table_schema.py index 5cbecaf143295..2c2ecf75bbe7b 100644 --- a/pandas/io/json/table_schema.py +++ b/pandas/io/json/table_schema.py @@ -292,7 +292,7 @@ def parse_table_schema(json, precise_float): See Also -------- - build_table_schema : inverse function + build_table_schema : Inverse function. pandas.read_json """ table = loads(json, precise_float=precise_float) diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py index 4c28e0f88b1ae..8c574bcb70363 100644 --- a/pandas/io/pytables.py +++ b/pandas/io/pytables.py @@ -326,8 +326,8 @@ def read_hdf(path_or_buf, key=None, mode='r', **kwargs): See Also -------- - pandas.DataFrame.to_hdf : write a HDF file from a DataFrame - pandas.HDFStore : low-level access to HDF files + pandas.DataFrame.to_hdf : Write a HDF file from a DataFrame. + pandas.HDFStore : Low-level access to HDF files. Examples -------- diff --git a/pandas/io/sql.py b/pandas/io/sql.py index db405390431c9..a81bc11130153 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -1065,7 +1065,7 @@ def read_query(self, sql, index_col=None, coerce_float=True, See Also -------- - read_sql_table : Read SQL database table into a DataFrame + read_sql_table : Read SQL database table into a DataFrame. read_sql """ diff --git a/pandas/io/stata.py b/pandas/io/stata.py index 215391bbf217a..7e8ab002f7978 100644 --- a/pandas/io/stata.py +++ b/pandas/io/stata.py @@ -98,8 +98,8 @@ See Also -------- -pandas.io.stata.StataReader : low-level reader for Stata data files -pandas.DataFrame.to_stata: export Stata data files +pandas.io.stata.StataReader : Low-level reader for Stata data files. +pandas.DataFrame.to_stata: Export Stata data files. Examples -------- diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 1c70ece434abb..83ab3b6098956 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -3492,7 +3492,7 @@ def scatter(self, x, y, s=None, c=None, **kwds): See Also -------- - matplotlib.pyplot.scatter : scatter plot using multiple input data + matplotlib.pyplot.scatter : Scatter plot using multiple input data formats. Examples @@ -3568,7 +3568,7 @@ def hexbin(self, x, y, C=None, reduce_C_function=None, gridsize=None, See Also -------- DataFrame.plot : Make plots of a DataFrame. - matplotlib.pyplot.hexbin : hexagonal binning plot using matplotlib, + matplotlib.pyplot.hexbin : Hexagonal binning plot using matplotlib, the matplotlib function that is used under the hood. Examples diff --git a/pandas/plotting/_misc.py b/pandas/plotting/_misc.py index f889e08b5d348..39765b27cf19c 100644 --- a/pandas/plotting/_misc.py +++ b/pandas/plotting/_misc.py @@ -185,7 +185,7 @@ def radviz(frame, class_column, ax=None, color=None, colormap=None, **kwds): See Also -------- - pandas.plotting.andrews_curves : Plot clustering visualization + pandas.plotting.andrews_curves : Plot clustering visualization. Examples -------- diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index e51e0c88e5b95..1171478de2eb4 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -196,8 +196,8 @@ def validate_args_and_kwargs(fname, args, kwargs, See Also -------- - validate_args : purely args validation - validate_kwargs : purely kwargs validation + validate_args : Purely args validation. + validate_kwargs : Purely kwargs validation. """ # Check that the total number of arguments passed in (i.e. From e413c491e090274aad78489cc17a2e29cbd8e269 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Wed, 14 Nov 2018 15:09:46 -0600 Subject: [PATCH 24/25] DOC: Change release and whatsnew (#21599) * DOC: Change release and whatsnew Changes: * We will include the correct (latest on master or maintenance branch) whatsnew directly in the index.rst toctree * Contributors are included in the whatsnew for each version (automatically) * Removed release.rst * Added new releases.rst which has toctrees for each release Incidental changes * Updated style.ipynb. Writing the jinja template was confusing sphinx. We included it in the git source now. * Fixing some inconsitent header levels (will do more) * Refactored announce.py to support auto-generated contributors --- .gitignore | 1 - ci/build_docs.sh | 8 +- ci/deps/travis-36-doc.yaml | 1 + doc/make.py | 7 +- doc/source/conf.py | 42 ++- doc/source/contributing.rst | 2 +- doc/source/index.rst.template | 4 +- doc/source/releases.rst | 203 ++++++++++++ doc/source/style.ipynb | 105 ++---- doc/source/templates/myhtml.tpl | 5 + doc/source/whatsnew.rst | 109 ------ .../whatsnew/{v0.10.0.txt => v0.10.0.rst} | 15 +- .../whatsnew/{v0.10.1.txt => v0.10.1.rst} | 10 + .../whatsnew/{v0.11.0.txt => v0.11.0.rst} | 10 + .../whatsnew/{v0.12.0.txt => v0.12.0.rst} | 10 + .../whatsnew/{v0.13.0.txt => v0.13.0.rst} | 309 +++++++++++++++++- .../whatsnew/{v0.13.1.txt => v0.13.1.rst} | 89 ++++- .../whatsnew/{v0.14.0.txt => v0.14.0.rst} | 14 +- .../whatsnew/{v0.14.1.txt => v0.14.1.rst} | 10 + .../whatsnew/{v0.15.0.txt => v0.15.0.rst} | 10 + .../whatsnew/{v0.15.1.txt => v0.15.1.rst} | 10 + .../whatsnew/{v0.15.2.txt => v0.15.2.rst} | 10 + .../whatsnew/{v0.16.0.txt => v0.16.0.rst} | 12 +- .../whatsnew/{v0.16.1.txt => v0.16.1.rst} | 10 + .../whatsnew/{v0.16.2.txt => v0.16.2.rst} | 10 + .../whatsnew/{v0.17.0.txt => v0.17.0.rst} | 20 +- .../whatsnew/{v0.17.1.txt => v0.17.1.rst} | 10 + .../whatsnew/{v0.18.0.txt => v0.18.0.rst} | 10 + .../whatsnew/{v0.18.1.txt => v0.18.1.rst} | 10 + .../whatsnew/{v0.19.0.txt => v0.19.0.rst} | 10 + .../whatsnew/{v0.19.1.txt => v0.19.1.rst} | 10 + .../whatsnew/{v0.19.2.txt => v0.19.2.rst} | 10 + .../whatsnew/{v0.20.0.txt => v0.20.0.rst} | 12 +- .../whatsnew/{v0.20.2.txt => v0.20.2.rst} | 10 + .../whatsnew/{v0.20.3.txt => v0.20.3.rst} | 10 + .../whatsnew/{v0.21.0.txt => v0.21.0.rst} | 10 + .../whatsnew/{v0.21.1.txt => v0.21.1.rst} | 10 + .../whatsnew/{v0.22.0.txt => v0.22.0.rst} | 10 + .../whatsnew/{v0.23.0.txt => v0.23.0.rst} | 17 +- .../whatsnew/{v0.23.1.txt => v0.23.1.rst} | 13 +- .../whatsnew/{v0.23.2.txt => v0.23.2.rst} | 20 +- doc/source/whatsnew/v0.23.3.rst | 16 + doc/source/whatsnew/v0.23.3.txt | 7 - .../whatsnew/{v0.23.4.txt => v0.23.4.rst} | 13 +- .../whatsnew/{v0.24.0.txt => v0.24.0.rst} | 25 +- .../whatsnew/{v0.4.x.txt => v0.4.x.rst} | 6 + .../whatsnew/{v0.5.0.txt => v0.5.0.rst} | 10 + .../whatsnew/{v0.6.0.txt => v0.6.0.rst} | 10 + .../whatsnew/{v0.6.1.txt => v0.6.1.rst} | 8 + .../whatsnew/{v0.7.0.txt => v0.7.0.rst} | 10 + .../whatsnew/{v0.7.1.txt => v0.7.1.rst} | 10 + .../whatsnew/{v0.7.2.txt => v0.7.2.rst} | 10 + .../whatsnew/{v0.7.3.txt => v0.7.3.rst} | 16 +- .../whatsnew/{v0.8.0.txt => v0.8.0.rst} | 10 + .../whatsnew/{v0.8.1.txt => v0.8.1.rst} | 10 + .../whatsnew/{v0.9.0.txt => v0.9.0.rst} | 13 +- .../whatsnew/{v0.9.1.txt => v0.9.1.rst} | 15 +- {scripts => doc/sphinxext}/announce.py | 52 ++- doc/sphinxext/contributors.py | 40 +++ environment.yml | 1 + requirements-dev.txt | 1 + setup.cfg | 18 +- 62 files changed, 1223 insertions(+), 286 deletions(-) create mode 100644 doc/source/releases.rst create mode 100644 doc/source/templates/myhtml.tpl delete mode 100644 doc/source/whatsnew.rst rename doc/source/whatsnew/{v0.10.0.txt => v0.10.0.rst} (99%) rename doc/source/whatsnew/{v0.10.1.txt => v0.10.1.rst} (98%) rename doc/source/whatsnew/{v0.11.0.txt => v0.11.0.rst} (98%) rename doc/source/whatsnew/{v0.12.0.txt => v0.12.0.rst} (99%) rename doc/source/whatsnew/{v0.13.0.txt => v0.13.0.rst} (66%) rename doc/source/whatsnew/{v0.13.1.txt => v0.13.1.rst} (64%) rename doc/source/whatsnew/{v0.14.0.txt => v0.14.0.rst} (99%) rename doc/source/whatsnew/{v0.14.1.txt => v0.14.1.rst} (99%) rename doc/source/whatsnew/{v0.15.0.txt => v0.15.0.rst} (99%) rename doc/source/whatsnew/{v0.15.1.txt => v0.15.1.rst} (98%) rename doc/source/whatsnew/{v0.15.2.txt => v0.15.2.rst} (99%) rename doc/source/whatsnew/{v0.16.0.txt => v0.16.0.rst} (99%) rename doc/source/whatsnew/{v0.16.1.txt => v0.16.1.rst} (99%) rename doc/source/whatsnew/{v0.16.2.txt => v0.16.2.rst} (98%) rename doc/source/whatsnew/{v0.17.0.txt => v0.17.0.rst} (99%) rename doc/source/whatsnew/{v0.17.1.txt => v0.17.1.rst} (98%) rename doc/source/whatsnew/{v0.18.0.txt => v0.18.0.rst} (99%) rename doc/source/whatsnew/{v0.18.1.txt => v0.18.1.rst} (99%) rename doc/source/whatsnew/{v0.19.0.txt => v0.19.0.rst} (99%) rename doc/source/whatsnew/{v0.19.1.txt => v0.19.1.rst} (97%) rename doc/source/whatsnew/{v0.19.2.txt => v0.19.2.rst} (97%) rename doc/source/whatsnew/{v0.20.0.txt => v0.20.0.rst} (99%) rename doc/source/whatsnew/{v0.20.2.txt => v0.20.2.rst} (97%) rename doc/source/whatsnew/{v0.20.3.txt => v0.20.3.rst} (95%) rename doc/source/whatsnew/{v0.21.0.txt => v0.21.0.rst} (99%) rename doc/source/whatsnew/{v0.21.1.txt => v0.21.1.rst} (98%) rename doc/source/whatsnew/{v0.22.0.txt => v0.22.0.rst} (98%) rename doc/source/whatsnew/{v0.23.0.txt => v0.23.0.rst} (99%) rename doc/source/whatsnew/{v0.23.1.txt => v0.23.1.rst} (97%) rename doc/source/whatsnew/{v0.23.2.txt => v0.23.2.rst} (81%) create mode 100644 doc/source/whatsnew/v0.23.3.rst delete mode 100644 doc/source/whatsnew/v0.23.3.txt rename doc/source/whatsnew/{v0.23.4.txt => v0.23.4.rst} (84%) rename doc/source/whatsnew/{v0.24.0.txt => v0.24.0.rst} (99%) rename doc/source/whatsnew/{v0.4.x.txt => v0.4.x.rst} (97%) rename doc/source/whatsnew/{v0.5.0.txt => v0.5.0.rst} (96%) rename doc/source/whatsnew/{v0.6.0.txt => v0.6.0.rst} (97%) rename doc/source/whatsnew/{v0.6.1.txt => v0.6.1.rst} (96%) rename doc/source/whatsnew/{v0.7.0.txt => v0.7.0.rst} (98%) rename doc/source/whatsnew/{v0.7.1.txt => v0.7.1.rst} (90%) rename doc/source/whatsnew/{v0.7.2.txt => v0.7.2.rst} (89%) rename doc/source/whatsnew/{v0.7.3.txt => v0.7.3.rst} (92%) rename doc/source/whatsnew/{v0.8.0.txt => v0.8.0.rst} (99%) rename doc/source/whatsnew/{v0.8.1.txt => v0.8.1.rst} (93%) rename doc/source/whatsnew/{v0.9.0.txt => v0.9.0.rst} (96%) rename doc/source/whatsnew/{v0.9.1.txt => v0.9.1.rst} (97%) rename {scripts => doc/sphinxext}/announce.py (75%) create mode 100644 doc/sphinxext/contributors.py diff --git a/.gitignore b/.gitignore index a59f2843c365a..f912fedb199c0 100644 --- a/.gitignore +++ b/.gitignore @@ -109,6 +109,5 @@ doc/build/html/index.html # Windows specific leftover: doc/tmp.sv doc/source/styled.xlsx -doc/source/templates/ env/ doc/source/savefig/ diff --git a/ci/build_docs.sh b/ci/build_docs.sh index f445447e3565c..33340a1c038dc 100755 --- a/ci/build_docs.sh +++ b/ci/build_docs.sh @@ -5,7 +5,7 @@ if [ "${TRAVIS_OS_NAME}" != "linux" ]; then exit 0 fi -cd "$TRAVIS_BUILD_DIR" +cd "$TRAVIS_BUILD_DIR"/doc echo "inside $0" if [ "$DOC" ]; then @@ -14,10 +14,6 @@ if [ "$DOC" ]; then source activate pandas - mv "$TRAVIS_BUILD_DIR"/doc /tmp - mv "$TRAVIS_BUILD_DIR/LICENSE" /tmp # included in the docs. - cd /tmp/doc - echo ############################### echo # Log file for the doc build # echo ############################### @@ -29,7 +25,7 @@ if [ "$DOC" ]; then echo # Create and send docs # echo ######################## - cd /tmp/doc/build/html + cd build/html git config --global user.email "pandas-docs-bot@localhost.foo" git config --global user.name "pandas-docs-bot" diff --git a/ci/deps/travis-36-doc.yaml b/ci/deps/travis-36-doc.yaml index 6bf8cb38e0b7c..f79fcb11c179f 100644 --- a/ci/deps/travis-36-doc.yaml +++ b/ci/deps/travis-36-doc.yaml @@ -8,6 +8,7 @@ dependencies: - bottleneck - cython>=0.28.2 - fastparquet + - gitpython - html5lib - hypothesis>=3.58.0 - ipykernel diff --git a/doc/make.py b/doc/make.py index cab5fa0ed4c52..0a3a7483fcc91 100755 --- a/doc/make.py +++ b/doc/make.py @@ -126,7 +126,12 @@ def _process_single_doc(self, single_doc): self.single_doc = 'api' elif os.path.exists(os.path.join(SOURCE_PATH, single_doc)): self.single_doc_type = 'rst' - self.single_doc = os.path.splitext(os.path.basename(single_doc))[0] + + if 'whatsnew' in single_doc: + basename = single_doc + else: + basename = os.path.basename(single_doc) + self.single_doc = os.path.splitext(basename)[0] elif os.path.exists( os.path.join(SOURCE_PATH, '{}.rst'.format(single_doc))): self.single_doc_type = 'rst' diff --git a/doc/source/conf.py b/doc/source/conf.py index 3b0b51dd0d648..47adc80204fcc 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -40,7 +40,6 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.append(os.path.abspath('.')) sys.path.insert(0, os.path.abspath('../sphinxext')) - sys.path.extend([ # numpy standard doc extensions @@ -75,6 +74,7 @@ 'sphinx.ext.ifconfig', 'sphinx.ext.linkcode', 'nbsphinx', + 'contributors', # custom pandas extension ] try: @@ -120,7 +120,9 @@ templates_path = ['../_templates'] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = [ + '.rst', +] # The encoding of source files. source_encoding = 'utf-8' @@ -298,8 +300,26 @@ for page in moved_api_pages } + +common_imports = """\ +.. currentmodule:: pandas + +.. ipython:: python + :suppress: + + import numpy as np + from pandas import * + import pandas as pd + randn = np.random.randn + np.set_printoptions(precision=4, suppress=True) + options.display.max_rows = 15 + from pandas.compat import StringIO +""" + + html_context = { - 'redirects': {old: new for old, new in moved_api_pages} + 'redirects': {old: new for old, new in moved_api_pages}, + 'common_imports': common_imports, } # If false, no module index is generated. @@ -654,7 +674,23 @@ def process_class_docstrings(app, what, name, obj, options, lines): ] +def rstjinja(app, docname, source): + """ + Render our pages as a jinja template for fancy templating goodness. + """ + # http://ericholscher.com/blog/2016/jul/25/integrating-jinja-rst-sphinx/ + # Make sure we're outputting HTML + if app.builder.format != 'html': + return + src = source[0] + rendered = app.builder.templates.render_string( + src, app.config.html_context + ) + source[0] = rendered + + def setup(app): + app.connect("source-read", rstjinja) app.connect("autodoc-process-docstring", remove_flags_docstring) app.connect("autodoc-process-docstring", process_class_docstrings) app.add_autodocumenter(AccessorDocumenter) diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst index 514a58456bcd9..7eb9a6cf815ba 100644 --- a/doc/source/contributing.rst +++ b/doc/source/contributing.rst @@ -1103,7 +1103,7 @@ Information on how to write a benchmark and how to use asv can be found in the Documenting your code --------------------- -Changes should be reflected in the release notes located in ``doc/source/whatsnew/vx.y.z.txt``. +Changes should be reflected in the release notes located in ``doc/source/whatsnew/vx.y.z.rst``. This file contains an ongoing change log for each release. Add an entry to this file to document your fix, enhancement or (unavoidable) breaking change. Make sure to include the GitHub issue number when adding your entry (using ``:issue:`1234``` where ``1234`` is the diff --git a/doc/source/index.rst.template b/doc/source/index.rst.template index d2b88e794e51e..38f73f8617ced 100644 --- a/doc/source/index.rst.template +++ b/doc/source/index.rst.template @@ -118,7 +118,7 @@ See the package overview for more detail about what's in the library. {{ single_doc }} {% endif -%} {% if not single_doc -%} - whatsnew + What's New install contributing overview @@ -159,5 +159,5 @@ See the package overview for more detail about what's in the library. developer internals extending - release + releases {% endif -%} diff --git a/doc/source/releases.rst b/doc/source/releases.rst new file mode 100644 index 0000000000000..0167903cce8bc --- /dev/null +++ b/doc/source/releases.rst @@ -0,0 +1,203 @@ +.. _release: + +************* +Release Notes +************* + +This is the list of changes to pandas between each release. For full details, +see the commit logs at http://github.com/pandas-dev/pandas. For install and +upgrade instructions, see :ref:`install`. + +Version 0.24 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.24.0 + +Version 0.23 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.23.4 + whatsnew/v0.23.3 + whatsnew/v0.23.2 + whatsnew/v0.23.1 + whatsnew/v0.23.0 + +Version 0.22 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.22.0 + +Version 0.21 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.21.0 + whatsnew/v0.21.1 + +Version 0.20 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.20.0 + whatsnew/v0.20.2 + whatsnew/v0.20.3 + +Version 0.19 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.19.0 + whatsnew/v0.19.1 + whatsnew/v0.19.2 + +Version 0.18 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.18.0 + whatsnew/v0.18.1 + +Version 0.17 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.17.0 + whatsnew/v0.17.1 + +Version 0.16 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.16.0 + whatsnew/v0.16.1 + whatsnew/v0.16.2 + +Version 0.15 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.15.0 + whatsnew/v0.15.1 + whatsnew/v0.15.2 + +Version 0.14 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.14.0 + whatsnew/v0.14.1 + +Version 0.13 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.13.0 + whatsnew/v0.13.1 + +Version 0.12 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.12.0 + +Version 0.11 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.11.0 + +Version 0.10 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.10.0 + whatsnew/v0.10.1 + +Version 0.9 +----------- + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.9.0 + whatsnew/v0.9.1 + +Version 0.8 +------------ + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.8.0 + whatsnew/v0.8.1 + +Version 0.7 +----------- + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.7.0 + whatsnew/v0.7.1 + whatsnew/v0.7.2 + whatsnew/v0.7.3 + +Version 0.6 +----------- + +.. toctree:: + :maxdepth: 2 + + + whatsnew/v0.6.0 + whatsnew/v0.6.1 + +Version 0.5 +----------- + +.. toctree:: + :maxdepth: 2 + + + whatsnew/v0.5.0 + +Version 0.4 +----------- + +.. toctree:: + :maxdepth: 2 + + whatsnew/v0.4.x diff --git a/doc/source/style.ipynb b/doc/source/style.ipynb index 6f66c1a9bf7f9..792fe5120f6e8 100644 --- a/doc/source/style.ipynb +++ b/doc/source/style.ipynb @@ -2,9 +2,7 @@ "cells": [ { "cell_type": "markdown", - "metadata": { - "collapsed": true - }, + "metadata": {}, "source": [ "# Styling\n", "\n", @@ -51,7 +49,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": true, "nbsphinx": "hidden" }, "outputs": [], @@ -64,9 +61,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", @@ -132,9 +127,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "def color_negative_red(val):\n", @@ -188,9 +181,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "def highlight_max(s):\n", @@ -253,9 +244,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "def highlight_max(data, color='yellow'):\n", @@ -908,9 +897,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "from IPython.html import widgets\n", @@ -925,9 +912,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "def magnify():\n", @@ -946,9 +931,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "np.random.seed(25)\n", @@ -985,18 +968,16 @@ "- `vertical-align`\n", "- `white-space: nowrap`\n", "\n", - "Only CSS2 named colors and hex colors of the form `#rgb` or `#rrggbb` are currently supported.\n", "\n", - "The following pseudo CSS properties are also available to set excel specific style properties:\n", - "- `number-format`\n" + "- Only CSS2 named colors and hex colors of the form `#rgb` or `#rrggbb` are currently supported.\n", + "- The following pseudo CSS properties are also available to set excel specific style properties:\n", + " - `number-format`\n" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "df.style.\\\n", @@ -1037,9 +1018,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "from jinja2 import Environment, ChoiceLoader, FileSystemLoader\n", @@ -1047,39 +1026,21 @@ "from pandas.io.formats.style import Styler" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "%mkdir templates" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "This next cell writes the custom template.\n", - "We extend the template `html.tpl`, which comes with pandas." + "We'll use the following template:" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ - "%%file templates/myhtml.tpl\n", - "{% extends \"html.tpl\" %}\n", - "{% block table %}\n", - "

{{ table_title|default(\"My Table\") }}

\n", - "{{ super() }}\n", - "{% endblock table %}" + "with open(\"templates/myhtml.tpl\") as f:\n", + " print(f.read())" ] }, { @@ -1093,9 +1054,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "class MyStyler(Styler):\n", @@ -1122,9 +1081,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "MyStyler(df)" @@ -1140,9 +1097,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "HTML(MyStyler(df).render(table_title=\"Extending Example\"))" @@ -1158,9 +1113,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "EasyStyler = Styler.from_custom_template(\"templates\", \"myhtml.tpl\")\n", @@ -1177,9 +1130,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ "with open(\"template_structure.html\") as f:\n", @@ -1199,7 +1150,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": true, "nbsphinx": "hidden" }, "outputs": [], @@ -1216,7 +1166,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python [default]", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -1230,14 +1180,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.3" - }, - "widgets": { - "application/vnd.jupyter.widget-state+json": { - "state": {}, - "version_major": 1, - "version_minor": 0 - } + "version": "3.7.0" } }, "nbformat": 4, diff --git a/doc/source/templates/myhtml.tpl b/doc/source/templates/myhtml.tpl new file mode 100644 index 0000000000000..1170fd3def653 --- /dev/null +++ b/doc/source/templates/myhtml.tpl @@ -0,0 +1,5 @@ +{% extends "html.tpl" %} +{% block table %} +

{{ table_title|default("My Table") }}

+{{ super() }} +{% endblock table %} diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst deleted file mode 100644 index 8672685b3ebb4..0000000000000 --- a/doc/source/whatsnew.rst +++ /dev/null @@ -1,109 +0,0 @@ -.. _whatsnew: - -.. currentmodule:: pandas - -.. ipython:: python - :suppress: - - import numpy as np - from pandas import * - import pandas as pd - randn = np.random.randn - np.set_printoptions(precision=4, suppress=True) - options.display.max_rows = 15 - -********** -What's New -********** - -These are new features and improvements of note in each release. - -.. include:: whatsnew/v0.24.0.txt - -.. include:: whatsnew/v0.23.4.txt - -.. include:: whatsnew/v0.23.3.txt - -.. include:: whatsnew/v0.23.2.txt - -.. include:: whatsnew/v0.23.1.txt - -.. include:: whatsnew/v0.23.0.txt - -.. include:: whatsnew/v0.22.0.txt - -.. include:: whatsnew/v0.21.1.txt - -.. include:: whatsnew/v0.21.0.txt - -.. include:: whatsnew/v0.20.3.txt - -.. include:: whatsnew/v0.20.2.txt - -.. include:: whatsnew/v0.20.0.txt - -.. include:: whatsnew/v0.19.2.txt - -.. include:: whatsnew/v0.19.1.txt - -.. include:: whatsnew/v0.19.0.txt - -.. include:: whatsnew/v0.18.1.txt - -.. include:: whatsnew/v0.18.0.txt - -.. include:: whatsnew/v0.17.1.txt - -.. include:: whatsnew/v0.17.0.txt - -.. include:: whatsnew/v0.16.2.txt - -.. include:: whatsnew/v0.16.1.txt - -.. include:: whatsnew/v0.16.0.txt - -.. include:: whatsnew/v0.15.2.txt - -.. include:: whatsnew/v0.15.1.txt - -.. include:: whatsnew/v0.15.0.txt - -.. include:: whatsnew/v0.14.1.txt - -.. include:: whatsnew/v0.14.0.txt - -.. include:: whatsnew/v0.13.1.txt - -.. include:: whatsnew/v0.13.0.txt - -.. include:: whatsnew/v0.12.0.txt - -.. include:: whatsnew/v0.11.0.txt - -.. include:: whatsnew/v0.10.1.txt - -.. include:: whatsnew/v0.10.0.txt - -.. include:: whatsnew/v0.9.1.txt - -.. include:: whatsnew/v0.9.0.txt - -.. include:: whatsnew/v0.8.1.txt - -.. include:: whatsnew/v0.8.0.txt - -.. include:: whatsnew/v0.7.3.txt - -.. include:: whatsnew/v0.7.2.txt - -.. include:: whatsnew/v0.7.1.txt - -.. include:: whatsnew/v0.7.0.txt - -.. include:: whatsnew/v0.6.1.txt - -.. include:: whatsnew/v0.6.0.txt - -.. include:: whatsnew/v0.5.0.txt - -.. include:: whatsnew/v0.4.x.txt diff --git a/doc/source/whatsnew/v0.10.0.txt b/doc/source/whatsnew/v0.10.0.rst similarity index 99% rename from doc/source/whatsnew/v0.10.0.txt rename to doc/source/whatsnew/v0.10.0.rst index 298088a4f96b3..27f20111dbf96 100644 --- a/doc/source/whatsnew/v0.10.0.txt +++ b/doc/source/whatsnew/v0.10.0.rst @@ -1,13 +1,10 @@ .. _whatsnew_0100: -.. ipython:: python - :suppress: - - from pandas.compat import StringIO - v0.10.0 (December 17, 2012) --------------------------- +{{ common_imports }} + This is a major release from 0.9.1 and includes many new features and enhancements along with a large number of bug fixes. There are also a number of important API changes that long-time pandas users should pay close attention @@ -431,3 +428,11 @@ Here is a taste of what to expect. See the :ref:`full release notes ` or issue tracker on GitHub for a complete list. + + +.. _whatsnew_0.10.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.9.0..v0.10.0 diff --git a/doc/source/whatsnew/v0.10.1.txt b/doc/source/whatsnew/v0.10.1.rst similarity index 98% rename from doc/source/whatsnew/v0.10.1.txt rename to doc/source/whatsnew/v0.10.1.rst index f1a32440c6950..5679babf07b73 100644 --- a/doc/source/whatsnew/v0.10.1.txt +++ b/doc/source/whatsnew/v0.10.1.rst @@ -3,6 +3,8 @@ v0.10.1 (January 22, 2013) --------------------------- +{{ common_imports }} + This is a minor release from 0.10.0 and includes new features, enhancements, and bug fixes. In particular, there is substantial new HDFStore functionality contributed by Jeff Reback. @@ -208,3 +210,11 @@ combined result, by using ``where`` on a selector table. See the :ref:`full release notes ` or issue tracker on GitHub for a complete list. + + +.. _whatsnew_0.10.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.10.0..v0.10.1 diff --git a/doc/source/whatsnew/v0.11.0.txt b/doc/source/whatsnew/v0.11.0.rst similarity index 98% rename from doc/source/whatsnew/v0.11.0.txt rename to doc/source/whatsnew/v0.11.0.rst index f39e6c9ff459b..051d735e539aa 100644 --- a/doc/source/whatsnew/v0.11.0.txt +++ b/doc/source/whatsnew/v0.11.0.rst @@ -3,6 +3,8 @@ v0.11.0 (April 22, 2013) ------------------------ +{{ common_imports }} + This is a major release from 0.10.1 and includes many new features and enhancements along with a large number of bug fixes. The methods of Selecting Data have had quite a number of additions, and Dtype support is now full-fledged. @@ -330,3 +332,11 @@ Enhancements See the :ref:`full release notes ` or issue tracker on GitHub for a complete list. + + +.. _whatsnew_0.11.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.10.1..v0.11.0 diff --git a/doc/source/whatsnew/v0.12.0.txt b/doc/source/whatsnew/v0.12.0.rst similarity index 99% rename from doc/source/whatsnew/v0.12.0.txt rename to doc/source/whatsnew/v0.12.0.rst index f66f6c0f72d5d..a462359b6e3c0 100644 --- a/doc/source/whatsnew/v0.12.0.txt +++ b/doc/source/whatsnew/v0.12.0.rst @@ -3,6 +3,8 @@ v0.12.0 (July 24, 2013) ------------------------ +{{ common_imports }} + This is a major release from 0.11.0 and includes several new features and enhancements along with a large number of bug fixes. @@ -504,3 +506,11 @@ Bug Fixes See the :ref:`full release notes ` or issue tracker on GitHub for a complete list. + + +.. _whatsnew_0.12.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.11.0..v0.12.0 diff --git a/doc/source/whatsnew/v0.13.0.txt b/doc/source/whatsnew/v0.13.0.rst similarity index 66% rename from doc/source/whatsnew/v0.13.0.txt rename to doc/source/whatsnew/v0.13.0.rst index 94cd451196ead..037347afb1d59 100644 --- a/doc/source/whatsnew/v0.13.0.txt +++ b/doc/source/whatsnew/v0.13.0.rst @@ -3,6 +3,8 @@ v0.13.0 (January 3, 2014) --------------------------- +{{ common_imports }} + This is a major release from 0.12.0 and includes a number of API changes, several new features and enhancements along with a large number of bug fixes. @@ -425,7 +427,7 @@ than switching to the short info view (:issue:`4886`, :issue:`5550`). This makes the representation more consistent as small DataFrames get larger. -.. image:: _static/df_repr_truncated.png +.. image:: ../_static/df_repr_truncated.png :alt: Truncated HTML representation of a DataFrame To get the info view, call :meth:`DataFrame.info`. If you prefer the @@ -976,11 +978,308 @@ to unify methods and behaviors. Series formerly subclassed directly from s.a = 5 s +.. _release.bug_fixes-0.13.0: + Bug Fixes ~~~~~~~~~ -See :ref:`V0.13.0 Bug Fixes` for an extensive list of bugs that have been fixed in 0.13.0. +- ``HDFStore`` + + - raising an invalid ``TypeError`` rather than ``ValueError`` when + appending with a different block ordering (:issue:`4096`) + - ``read_hdf`` was not respecting as passed ``mode`` (:issue:`4504`) + - appending a 0-len table will work correctly (:issue:`4273`) + - ``to_hdf`` was raising when passing both arguments ``append`` and + ``table`` (:issue:`4584`) + - reading from a store with duplicate columns across dtypes would raise + (:issue:`4767`) + - Fixed a bug where ``ValueError`` wasn't correctly raised when column + names weren't strings (:issue:`4956`) + - A zero length series written in Fixed format not deserializing properly. + (:issue:`4708`) + - Fixed decoding perf issue on pyt3 (:issue:`5441`) + - Validate levels in a MultiIndex before storing (:issue:`5527`) + - Correctly handle ``data_columns`` with a Panel (:issue:`5717`) +- Fixed bug in tslib.tz_convert(vals, tz1, tz2): it could raise IndexError + exception while trying to access trans[pos + 1] (:issue:`4496`) +- The ``by`` argument now works correctly with the ``layout`` argument + (:issue:`4102`, :issue:`4014`) in ``*.hist`` plotting methods +- Fixed bug in ``PeriodIndex.map`` where using ``str`` would return the str + representation of the index (:issue:`4136`) +- Fixed test failure ``test_time_series_plot_color_with_empty_kwargs`` when + using custom matplotlib default colors (:issue:`4345`) +- Fix running of stata IO tests. Now uses temporary files to write + (:issue:`4353`) +- Fixed an issue where ``DataFrame.sum`` was slower than ``DataFrame.mean`` + for integer valued frames (:issue:`4365`) +- ``read_html`` tests now work with Python 2.6 (:issue:`4351`) +- Fixed bug where ``network`` testing was throwing ``NameError`` because a + local variable was undefined (:issue:`4381`) +- In ``to_json``, raise if a passed ``orient`` would cause loss of data + because of a duplicate index (:issue:`4359`) +- In ``to_json``, fix date handling so milliseconds are the default timestamp + as the docstring says (:issue:`4362`). +- ``as_index`` is no longer ignored when doing groupby apply (:issue:`4648`, + :issue:`3417`) +- JSON NaT handling fixed, NaTs are now serialized to `null` (:issue:`4498`) +- Fixed JSON handling of escapable characters in JSON object keys + (:issue:`4593`) +- Fixed passing ``keep_default_na=False`` when ``na_values=None`` + (:issue:`4318`) +- Fixed bug with ``values`` raising an error on a DataFrame with duplicate + columns and mixed dtypes, surfaced in (:issue:`4377`) +- Fixed bug with duplicate columns and type conversion in ``read_json`` when + ``orient='split'`` (:issue:`4377`) +- Fixed JSON bug where locales with decimal separators other than '.' threw + exceptions when encoding / decoding certain values. (:issue:`4918`) +- Fix ``.iat`` indexing with a ``PeriodIndex`` (:issue:`4390`) +- Fixed an issue where ``PeriodIndex`` joining with self was returning a new + instance rather than the same instance (:issue:`4379`); also adds a test + for this for the other index types +- Fixed a bug with all the dtypes being converted to object when using the + CSV cparser with the usecols parameter (:issue:`3192`) +- Fix an issue in merging blocks where the resulting DataFrame had partially + set _ref_locs (:issue:`4403`) +- Fixed an issue where hist subplots were being overwritten when they were + called using the top level matplotlib API (:issue:`4408`) +- Fixed a bug where calling ``Series.astype(str)`` would truncate the string + (:issue:`4405`, :issue:`4437`) +- Fixed a py3 compat issue where bytes were being repr'd as tuples + (:issue:`4455`) +- Fixed Panel attribute naming conflict if item is named 'a' + (:issue:`3440`) +- Fixed an issue where duplicate indexes were raising when plotting + (:issue:`4486`) +- Fixed an issue where cumsum and cumprod didn't work with bool dtypes + (:issue:`4170`, :issue:`4440`) +- Fixed Panel slicing issued in ``xs`` that was returning an incorrect dimmed + object (:issue:`4016`) +- Fix resampling bug where custom reduce function not used if only one group + (:issue:`3849`, :issue:`4494`) +- Fixed Panel assignment with a transposed frame (:issue:`3830`) +- Raise on set indexing with a Panel and a Panel as a value which needs + alignment (:issue:`3777`) +- frozenset objects now raise in the ``Series`` constructor (:issue:`4482`, + :issue:`4480`) +- Fixed issue with sorting a duplicate MultiIndex that has multiple dtypes + (:issue:`4516`) +- Fixed bug in ``DataFrame.set_values`` which was causing name attributes to + be lost when expanding the index. (:issue:`3742`, :issue:`4039`) +- Fixed issue where individual ``names``, ``levels`` and ``labels`` could be + set on ``MultiIndex`` without validation (:issue:`3714`, :issue:`4039`) +- Fixed (:issue:`3334`) in pivot_table. Margins did not compute if values is + the index. +- Fix bug in having a rhs of ``np.timedelta64`` or ``np.offsets.DateOffset`` + when operating with datetimes (:issue:`4532`) +- Fix arithmetic with series/datetimeindex and ``np.timedelta64`` not working + the same (:issue:`4134`) and buggy timedelta in NumPy 1.6 (:issue:`4135`) +- Fix bug in ``pd.read_clipboard`` on windows with PY3 (:issue:`4561`); not + decoding properly +- ``tslib.get_period_field()`` and ``tslib.get_period_field_arr()`` now raise + if code argument out of range (:issue:`4519`, :issue:`4520`) +- Fix boolean indexing on an empty series loses index names (:issue:`4235`), + infer_dtype works with empty arrays. +- Fix reindexing with multiple axes; if an axes match was not replacing the + current axes, leading to a possible lazy frequency inference issue + (:issue:`3317`) +- Fixed issue where ``DataFrame.apply`` was reraising exceptions incorrectly + (causing the original stack trace to be truncated). +- Fix selection with ``ix/loc`` and non_unique selectors (:issue:`4619`) +- Fix assignment with iloc/loc involving a dtype change in an existing column + (:issue:`4312`, :issue:`5702`) have internal setitem_with_indexer in core/indexing + to use Block.setitem +- Fixed bug where thousands operator was not handled correctly for floating + point numbers in csv_import (:issue:`4322`) +- Fix an issue with CacheableOffset not properly being used by many + DateOffset; this prevented the DateOffset from being cached (:issue:`4609`) +- Fix boolean comparison with a DataFrame on the lhs, and a list/tuple on the + rhs (:issue:`4576`) +- Fix error/dtype conversion with setitem of ``None`` on ``Series/DataFrame`` + (:issue:`4667`) +- Fix decoding based on a passed in non-default encoding in ``pd.read_stata`` + (:issue:`4626`) +- Fix ``DataFrame.from_records`` with a plain-vanilla ``ndarray``. + (:issue:`4727`) +- Fix some inconsistencies with ``Index.rename`` and ``MultiIndex.rename``, + etc. (:issue:`4718`, :issue:`4628`) +- Bug in using ``iloc/loc`` with a cross-sectional and duplicate indices + (:issue:`4726`) +- Bug with using ``QUOTE_NONE`` with ``to_csv`` causing ``Exception``. + (:issue:`4328`) +- Bug with Series indexing not raising an error when the right-hand-side has + an incorrect length (:issue:`2702`) +- Bug in MultiIndexing with a partial string selection as one part of a + MultIndex (:issue:`4758`) +- Bug with reindexing on the index with a non-unique index will now raise + ``ValueError`` (:issue:`4746`) +- Bug in setting with ``loc/ix`` a single indexer with a MultiIndex axis and + a NumPy array, related to (:issue:`3777`) +- Bug in concatenation with duplicate columns across dtypes not merging with + axis=0 (:issue:`4771`, :issue:`4975`) +- Bug in ``iloc`` with a slice index failing (:issue:`4771`) +- Incorrect error message with no colspecs or width in ``read_fwf``. + (:issue:`4774`) +- Fix bugs in indexing in a Series with a duplicate index (:issue:`4548`, + :issue:`4550`) +- Fixed bug with reading compressed files with ``read_fwf`` in Python 3. + (:issue:`3963`) +- Fixed an issue with a duplicate index and assignment with a dtype change + (:issue:`4686`) +- Fixed bug with reading compressed files in as ``bytes`` rather than ``str`` + in Python 3. Simplifies bytes-producing file-handling in Python 3 + (:issue:`3963`, :issue:`4785`). +- Fixed an issue related to ticklocs/ticklabels with log scale bar plots + across different versions of matplotlib (:issue:`4789`) +- Suppressed DeprecationWarning associated with internal calls issued by + repr() (:issue:`4391`) +- Fixed an issue with a duplicate index and duplicate selector with ``.loc`` + (:issue:`4825`) +- Fixed an issue with ``DataFrame.sort_index`` where, when sorting by a + single column and passing a list for ``ascending``, the argument for + ``ascending`` was being interpreted as ``True`` (:issue:`4839`, + :issue:`4846`) +- Fixed ``Panel.tshift`` not working. Added `freq` support to ``Panel.shift`` + (:issue:`4853`) +- Fix an issue in TextFileReader w/ Python engine (i.e. PythonParser) + with thousands != "," (:issue:`4596`) +- Bug in getitem with a duplicate index when using where (:issue:`4879`) +- Fix Type inference code coerces float column into datetime (:issue:`4601`) +- Fixed ``_ensure_numeric`` does not check for complex numbers + (:issue:`4902`) +- Fixed a bug in ``Series.hist`` where two figures were being created when + the ``by`` argument was passed (:issue:`4112`, :issue:`4113`). +- Fixed a bug in ``convert_objects`` for > 2 ndims (:issue:`4937`) +- Fixed a bug in DataFrame/Panel cache insertion and subsequent indexing + (:issue:`4939`, :issue:`5424`) +- Fixed string methods for ``FrozenNDArray`` and ``FrozenList`` + (:issue:`4929`) +- Fixed a bug with setting invalid or out-of-range values in indexing + enlargement scenarios (:issue:`4940`) +- Tests for fillna on empty Series (:issue:`4346`), thanks @immerrr +- Fixed ``copy()`` to shallow copy axes/indices as well and thereby keep + separate metadata. (:issue:`4202`, :issue:`4830`) +- Fixed skiprows option in Python parser for read_csv (:issue:`4382`) +- Fixed bug preventing ``cut`` from working with ``np.inf`` levels without + explicitly passing labels (:issue:`3415`) +- Fixed wrong check for overlapping in ``DatetimeIndex.union`` + (:issue:`4564`) +- Fixed conflict between thousands separator and date parser in csv_parser + (:issue:`4678`) +- Fix appending when dtypes are not the same (error showing mixing + float/np.datetime64) (:issue:`4993`) +- Fix repr for DateOffset. No longer show duplicate entries in kwds. + Removed unused offset fields. (:issue:`4638`) +- Fixed wrong index name during read_csv if using usecols. Applies to c + parser only. (:issue:`4201`) +- ``Timestamp`` objects can now appear in the left hand side of a comparison + operation with a ``Series`` or ``DataFrame`` object (:issue:`4982`). +- Fix a bug when indexing with ``np.nan`` via ``iloc/loc`` (:issue:`5016`) +- Fixed a bug where low memory c parser could create different types in + different chunks of the same file. Now coerces to numerical type or raises + warning. (:issue:`3866`) +- Fix a bug where reshaping a ``Series`` to its own shape raised + ``TypeError`` (:issue:`4554`) and other reshaping issues. +- Bug in setting with ``ix/loc`` and a mixed int/string index (:issue:`4544`) +- Make sure series-series boolean comparisons are label based (:issue:`4947`) +- Bug in multi-level indexing with a Timestamp partial indexer + (:issue:`4294`) +- Tests/fix for MultiIndex construction of an all-nan frame (:issue:`4078`) +- Fixed a bug where :func:`~pandas.read_html` wasn't correctly inferring + values of tables with commas (:issue:`5029`) +- Fixed a bug where :func:`~pandas.read_html` wasn't providing a stable + ordering of returned tables (:issue:`4770`, :issue:`5029`). +- Fixed a bug where :func:`~pandas.read_html` was incorrectly parsing when + passed ``index_col=0`` (:issue:`5066`). +- Fixed a bug where :func:`~pandas.read_html` was incorrectly inferring the + type of headers (:issue:`5048`). +- Fixed a bug where ``DatetimeIndex`` joins with ``PeriodIndex`` caused a + stack overflow (:issue:`3899`). +- Fixed a bug where ``groupby`` objects didn't allow plots (:issue:`5102`). +- Fixed a bug where ``groupby`` objects weren't tab-completing column names + (:issue:`5102`). +- Fixed a bug where ``groupby.plot()`` and friends were duplicating figures + multiple times (:issue:`5102`). +- Provide automatic conversion of ``object`` dtypes on fillna, related + (:issue:`5103`) +- Fixed a bug where default options were being overwritten in the option + parser cleaning (:issue:`5121`). +- Treat a list/ndarray identically for ``iloc`` indexing with list-like + (:issue:`5006`) +- Fix ``MultiIndex.get_level_values()`` with missing values (:issue:`5074`) +- Fix bound checking for Timestamp() with datetime64 input (:issue:`4065`) +- Fix a bug where ``TestReadHtml`` wasn't calling the correct ``read_html()`` + function (:issue:`5150`). +- Fix a bug with ``NDFrame.replace()`` which made replacement appear as + though it was (incorrectly) using regular expressions (:issue:`5143`). +- Fix better error message for to_datetime (:issue:`4928`) +- Made sure different locales are tested on travis-ci (:issue:`4918`). Also + adds a couple of utilities for getting locales and setting locales with a + context manager. +- Fixed segfault on ``isnull(MultiIndex)`` (now raises an error instead) + (:issue:`5123`, :issue:`5125`) +- Allow duplicate indices when performing operations that align + (:issue:`5185`, :issue:`5639`) +- Compound dtypes in a constructor raise ``NotImplementedError`` + (:issue:`5191`) +- Bug in comparing duplicate frames (:issue:`4421`) related +- Bug in describe on duplicate frames +- Bug in ``to_datetime`` with a format and ``coerce=True`` not raising + (:issue:`5195`) +- Bug in ``loc`` setting with multiple indexers and a rhs of a Series that + needs broadcasting (:issue:`5206`) +- Fixed bug where inplace setting of levels or labels on ``MultiIndex`` would + not clear cached ``values`` property and therefore return wrong ``values``. + (:issue:`5215`) +- Fixed bug where filtering a grouped DataFrame or Series did not maintain + the original ordering (:issue:`4621`). +- Fixed ``Period`` with a business date freq to always roll-forward if on a + non-business date. (:issue:`5203`) +- Fixed bug in Excel writers where frames with duplicate column names weren't + written correctly. (:issue:`5235`) +- Fixed issue with ``drop`` and a non-unique index on Series (:issue:`5248`) +- Fixed segfault in C parser caused by passing more names than columns in + the file. (:issue:`5156`) +- Fix ``Series.isin`` with date/time-like dtypes (:issue:`5021`) +- C and Python Parser can now handle the more common MultiIndex column + format which doesn't have a row for index names (:issue:`4702`) +- Bug when trying to use an out-of-bounds date as an object dtype + (:issue:`5312`) +- Bug when trying to display an embedded PandasObject (:issue:`5324`) +- Allows operating of Timestamps to return a datetime if the result is out-of-bounds + related (:issue:`5312`) +- Fix return value/type signature of ``initObjToJSON()`` to be compatible + with numpy's ``import_array()`` (:issue:`5334`, :issue:`5326`) +- Bug when renaming then set_index on a DataFrame (:issue:`5344`) +- Test suite no longer leaves around temporary files when testing graphics. (:issue:`5347`) + (thanks for catching this @yarikoptic!) +- Fixed html tests on win32. (:issue:`4580`) +- Make sure that ``head/tail`` are ``iloc`` based, (:issue:`5370`) +- Fixed bug for ``PeriodIndex`` string representation if there are 1 or 2 + elements. (:issue:`5372`) +- The GroupBy methods ``transform`` and ``filter`` can be used on Series + and DataFrames that have repeated (non-unique) indices. (:issue:`4620`) +- Fix empty series not printing name in repr (:issue:`4651`) +- Make tests create temp files in temp directory by default. (:issue:`5419`) +- ``pd.to_timedelta`` of a scalar returns a scalar (:issue:`5410`) +- ``pd.to_timedelta`` accepts ``NaN`` and ``NaT``, returning ``NaT`` instead of raising (:issue:`5437`) +- performance improvements in ``isnull`` on larger size pandas objects +- Fixed various setitem with 1d ndarray that does not have a matching + length to the indexer (:issue:`5508`) +- Bug in getitem with a MultiIndex and ``iloc`` (:issue:`5528`) +- Bug in delitem on a Series (:issue:`5542`) +- Bug fix in apply when using custom function and objects are not mutated (:issue:`5545`) +- Bug in selecting from a non-unique index with ``loc`` (:issue:`5553`) +- Bug in groupby returning non-consistent types when user function returns a ``None``, (:issue:`5592`) +- Work around regression in numpy 1.7.0 which erroneously raises IndexError from ``ndarray.item`` (:issue:`5666`) +- Bug in repeated indexing of object with resultant non-unique index (:issue:`5678`) +- Bug in fillna with Series and a passed series/dict (:issue:`5703`) +- Bug in groupby transform with a datetime-like grouper (:issue:`5712`) +- Bug in MultiIndex selection in PY3 when using certain keys (:issue:`5725`) +- Row-wise concat of differing dtypes failing in certain cases (:issue:`5754`) + +.. _whatsnew_0.13.0.contributors: + +Contributors +~~~~~~~~~~~~ -See the :ref:`full release notes -` or issue tracker -on GitHub for a complete list of all API changes, Enhancements and Bug Fixes. +.. contributors:: v0.12.0..v0.13.0 diff --git a/doc/source/whatsnew/v0.13.1.txt b/doc/source/whatsnew/v0.13.1.rst similarity index 64% rename from doc/source/whatsnew/v0.13.1.txt rename to doc/source/whatsnew/v0.13.1.rst index a4807a6d61b76..6a1b578cc08fb 100644 --- a/doc/source/whatsnew/v0.13.1.txt +++ b/doc/source/whatsnew/v0.13.1.rst @@ -3,6 +3,8 @@ v0.13.1 (February 3, 2014) -------------------------- +{{ common_imports }} + This is a minor release from 0.13.0 and includes a small number of API changes, several new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -126,10 +128,6 @@ API changes df.equals(df2) df.equals(df2.sort_index()) - import pandas.core.common as com - com.array_equivalent(np.array([0, np.nan]), np.array([0, np.nan])) - np.array_equal(np.array([0, np.nan]), np.array([0, np.nan])) - - ``DataFrame.apply`` will use the ``reduce`` argument to determine whether a ``Series`` or a ``DataFrame`` should be returned when the ``DataFrame`` is empty (:issue:`6007`). @@ -296,11 +294,86 @@ Experimental There are no experimental changes in 0.13.1 +.. _release.bug_fixes-0.13.1: + Bug Fixes ~~~~~~~~~ -See :ref:`V0.13.1 Bug Fixes` for an extensive list of bugs that have been fixed in 0.13.1. +- Bug in ``io.wb.get_countries`` not including all countries (:issue:`6008`) +- Bug in Series replace with timestamp dict (:issue:`5797`) +- read_csv/read_table now respects the `prefix` kwarg (:issue:`5732`). +- Bug in selection with missing values via ``.ix`` from a duplicate indexed DataFrame failing (:issue:`5835`) +- Fix issue of boolean comparison on empty DataFrames (:issue:`5808`) +- Bug in isnull handling ``NaT`` in an object array (:issue:`5443`) +- Bug in ``to_datetime`` when passed a ``np.nan`` or integer datelike and a format string (:issue:`5863`) +- Bug in groupby dtype conversion with datetimelike (:issue:`5869`) +- Regression in handling of empty Series as indexers to Series (:issue:`5877`) +- Bug in internal caching, related to (:issue:`5727`) +- Testing bug in reading JSON/msgpack from a non-filepath on windows under py3 (:issue:`5874`) +- Bug when assigning to .ix[tuple(...)] (:issue:`5896`) +- Bug in fully reindexing a Panel (:issue:`5905`) +- Bug in idxmin/max with object dtypes (:issue:`5914`) +- Bug in ``BusinessDay`` when adding n days to a date not on offset when n>5 and n%5==0 (:issue:`5890`) +- Bug in assigning to chained series with a series via ix (:issue:`5928`) +- Bug in creating an empty DataFrame, copying, then assigning (:issue:`5932`) +- Bug in DataFrame.tail with empty frame (:issue:`5846`) +- Bug in propagating metadata on ``resample`` (:issue:`5862`) +- Fixed string-representation of ``NaT`` to be "NaT" (:issue:`5708`) +- Fixed string-representation for Timestamp to show nanoseconds if present (:issue:`5912`) +- ``pd.match`` not returning passed sentinel +- ``Panel.to_frame()`` no longer fails when ``major_axis`` is a + ``MultiIndex`` (:issue:`5402`). +- Bug in ``pd.read_msgpack`` with inferring a ``DateTimeIndex`` frequency + incorrectly (:issue:`5947`) +- Fixed ``to_datetime`` for array with both Tz-aware datetimes and ``NaT``'s (:issue:`5961`) +- Bug in rolling skew/kurtosis when passed a Series with bad data (:issue:`5749`) +- Bug in scipy ``interpolate`` methods with a datetime index (:issue:`5975`) +- Bug in NaT comparison if a mixed datetime/np.datetime64 with NaT were passed (:issue:`5968`) +- Fixed bug with ``pd.concat`` losing dtype information if all inputs are empty (:issue:`5742`) +- Recent changes in IPython cause warnings to be emitted when using previous versions + of pandas in QTConsole, now fixed. If you're using an older version and + need to suppress the warnings, see (:issue:`5922`). +- Bug in merging ``timedelta`` dtypes (:issue:`5695`) +- Bug in plotting.scatter_matrix function. Wrong alignment among diagonal + and off-diagonal plots, see (:issue:`5497`). +- Regression in Series with a MultiIndex via ix (:issue:`6018`) +- Bug in Series.xs with a MultiIndex (:issue:`6018`) +- Bug in Series construction of mixed type with datelike and an integer (which should result in + object type and not automatic conversion) (:issue:`6028`) +- Possible segfault when chained indexing with an object array under NumPy 1.7.1 (:issue:`6026`, :issue:`6056`) +- Bug in setting using fancy indexing a single element with a non-scalar (e.g. a list), + (:issue:`6043`) +- ``to_sql`` did not respect ``if_exists`` (:issue:`4110` :issue:`4304`) +- Regression in ``.get(None)`` indexing from 0.12 (:issue:`5652`) +- Subtle ``iloc`` indexing bug, surfaced in (:issue:`6059`) +- Bug with insert of strings into DatetimeIndex (:issue:`5818`) +- Fixed unicode bug in to_html/HTML repr (:issue:`6098`) +- Fixed missing arg validation in get_options_data (:issue:`6105`) +- Bug in assignment with duplicate columns in a frame where the locations + are a slice (e.g. next to each other) (:issue:`6120`) +- Bug in propagating _ref_locs during construction of a DataFrame with dups + index/columns (:issue:`6121`) +- Bug in ``DataFrame.apply`` when using mixed datelike reductions (:issue:`6125`) +- Bug in ``DataFrame.append`` when appending a row with different columns (:issue:`6129`) +- Bug in DataFrame construction with recarray and non-ns datetime dtype (:issue:`6140`) +- Bug in ``.loc`` setitem indexing with a dataframe on rhs, multiple item setting, and + a datetimelike (:issue:`6152`) +- Fixed a bug in ``query``/``eval`` during lexicographic string comparisons (:issue:`6155`). +- Fixed a bug in ``query`` where the index of a single-element ``Series`` was + being thrown away (:issue:`6148`). +- Bug in ``HDFStore`` on appending a dataframe with MultiIndexed columns to + an existing table (:issue:`6167`) +- Consistency with dtypes in setting an empty DataFrame (:issue:`6171`) +- Bug in selecting on a MultiIndex ``HDFStore`` even in the presence of under + specified column spec (:issue:`6169`) +- Bug in ``nanops.var`` with ``ddof=1`` and 1 elements would sometimes return ``inf`` + rather than ``nan`` on some platforms (:issue:`6136`) +- Bug in Series and DataFrame bar plots ignoring the ``use_index`` keyword (:issue:`6209`) +- Bug in groupby with mixed str/int under python3 fixed; ``argsort`` was failing (:issue:`6212`) + +.. _whatsnew_0.13.1.contributors: + +Contributors +~~~~~~~~~~~~ -See the :ref:`full release notes -` or issue tracker -on GitHub for a complete list of all API changes, Enhancements and Bug Fixes. +.. contributors:: v0.13.0..v0.13.1 diff --git a/doc/source/whatsnew/v0.14.0.txt b/doc/source/whatsnew/v0.14.0.rst similarity index 99% rename from doc/source/whatsnew/v0.14.0.txt rename to doc/source/whatsnew/v0.14.0.rst index d4b7b09c054d6..9606bbac2a1b3 100644 --- a/doc/source/whatsnew/v0.14.0.txt +++ b/doc/source/whatsnew/v0.14.0.rst @@ -3,6 +3,8 @@ v0.14.0 (May 31 , 2014) ----------------------- +{{ common_imports }} + This is a major release from 0.13.1 and includes a small number of API changes, several new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -249,13 +251,13 @@ Display Changes constraints were reached and an ellipse (...) signaled that part of the data was cut off. - .. image:: _static/trunc_before.png + .. image:: ../_static/trunc_before.png :alt: The previous look of truncate. In the current version, large DataFrames are centrally truncated, showing a preview of head and tail in both dimensions. - .. image:: _static/trunc_after.png + .. image:: ../_static/trunc_after.png :alt: The new look. - allow option ``'truncate'`` for ``display.show_dimensions`` to only show the dimensions if the @@ -1047,3 +1049,11 @@ Bug Fixes - Bug in expressions evaluation with reversed ops, showing in series-dataframe ops (:issue:`7198`, :issue:`7192`) - Bug in multi-axis indexing with > 2 ndim and a MultiIndex (:issue:`7199`) - Fix a bug where invalid eval/query operations would blow the stack (:issue:`5198`) + + +.. _whatsnew_0.14.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.13.1..v0.14.0 diff --git a/doc/source/whatsnew/v0.14.1.txt b/doc/source/whatsnew/v0.14.1.rst similarity index 99% rename from doc/source/whatsnew/v0.14.1.txt rename to doc/source/whatsnew/v0.14.1.rst index d019cf54086c6..3b0ff5650d90d 100644 --- a/doc/source/whatsnew/v0.14.1.txt +++ b/doc/source/whatsnew/v0.14.1.rst @@ -3,6 +3,8 @@ v0.14.1 (July 11, 2014) ----------------------- +{{ common_imports }} + This is a minor release from 0.14.0 and includes a small number of API changes, several new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -269,3 +271,11 @@ Bug Fixes - Bug in grouped `hist` doesn't handle `rot` kw and `sharex` kw properly (:issue:`7234`) - Bug in ``.loc`` performing fallback integer indexing with ``object`` dtype indices (:issue:`7496`) - Bug (regression) in ``PeriodIndex`` constructor when passed ``Series`` objects (:issue:`7701`). + + +.. _whatsnew_0.14.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.14.0..v0.14.1 diff --git a/doc/source/whatsnew/v0.15.0.txt b/doc/source/whatsnew/v0.15.0.rst similarity index 99% rename from doc/source/whatsnew/v0.15.0.txt rename to doc/source/whatsnew/v0.15.0.rst index 4be6975958af5..00eda927a9c73 100644 --- a/doc/source/whatsnew/v0.15.0.txt +++ b/doc/source/whatsnew/v0.15.0.rst @@ -3,6 +3,8 @@ v0.15.0 (October 18, 2014) -------------------------- +{{ common_imports }} + This is a major release from 0.14.1 and includes a small number of API changes, several new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -1216,3 +1218,11 @@ Bug Fixes - Suppress FutureWarning generated by NumPy when comparing object arrays containing NaN for equality (:issue:`7065`) - Bug in ``DataFrame.eval()`` where the dtype of the ``not`` operator (``~``) was not correctly inferred as ``bool``. + + +.. _whatsnew_0.15.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.14.1..v0.15.0 diff --git a/doc/source/whatsnew/v0.15.1.txt b/doc/source/whatsnew/v0.15.1.rst similarity index 98% rename from doc/source/whatsnew/v0.15.1.txt rename to doc/source/whatsnew/v0.15.1.rst index 8cbf239ea20d0..88127d4e1b8d8 100644 --- a/doc/source/whatsnew/v0.15.1.txt +++ b/doc/source/whatsnew/v0.15.1.rst @@ -3,6 +3,8 @@ v0.15.1 (November 9, 2014) -------------------------- +{{ common_imports }} + This is a minor bug-fix release from 0.15.0 and includes a small number of API changes, several new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -304,3 +306,11 @@ Bug Fixes - Bug in Setting by indexer to a scalar value with a mixed-dtype `Panel4d` was failing (:issue:`8702`) - Bug where ``DataReader``'s would fail if one of the symbols passed was invalid. Now returns data for valid symbols and np.nan for invalid (:issue:`8494`) - Bug in ``get_quote_yahoo`` that wouldn't allow non-float return values (:issue:`5229`). + + +.. _whatsnew_0.15.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.15.0..v0.15.1 diff --git a/doc/source/whatsnew/v0.15.2.txt b/doc/source/whatsnew/v0.15.2.rst similarity index 99% rename from doc/source/whatsnew/v0.15.2.txt rename to doc/source/whatsnew/v0.15.2.rst index ee72fab7d23f2..dd988cde88145 100644 --- a/doc/source/whatsnew/v0.15.2.txt +++ b/doc/source/whatsnew/v0.15.2.rst @@ -3,6 +3,8 @@ v0.15.2 (December 12, 2014) --------------------------- +{{ common_imports }} + This is a minor release from 0.15.1 and includes a large number of bug fixes along with several new features, enhancements, and performance improvements. A small number of API changes were necessary to fix existing bugs. @@ -238,3 +240,11 @@ Bug Fixes - Bug in plotting if sharex was enabled and index was a timeseries, would show labels on multiple axes (:issue:`3964`). - Bug where passing a unit to the TimedeltaIndex constructor applied the to nano-second conversion twice. (:issue:`9011`). - Bug in plotting of a period-like array (:issue:`9012`) + + +.. _whatsnew_0.15.2.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.15.1..v0.15.2 diff --git a/doc/source/whatsnew/v0.16.0.txt b/doc/source/whatsnew/v0.16.0.rst similarity index 99% rename from doc/source/whatsnew/v0.16.0.txt rename to doc/source/whatsnew/v0.16.0.rst index ce525bbb4c1d6..d394b43a7ec88 100644 --- a/doc/source/whatsnew/v0.16.0.txt +++ b/doc/source/whatsnew/v0.16.0.rst @@ -3,6 +3,8 @@ v0.16.0 (March 22, 2015) ------------------------ +{{ common_imports }} + This is a major release from 0.15.2 and includes a small number of API changes, several new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -74,7 +76,7 @@ calculate the ratio, and plot PetalRatio = lambda x: x.PetalWidth / x.PetalLength) .plot(kind='scatter', x='SepalRatio', y='PetalRatio')) -.. image:: _static/whatsnew_assign.png +.. image:: ../_static/whatsnew_assign.png :scale: 50 % See the :ref:`documentation ` for more. (:issue:`9229`) @@ -675,3 +677,11 @@ Bug Fixes df1 = DataFrame({'x': Series(['a','b','c']), 'y': Series(['d','e','f'])}) df2 = df1[['x']] df2['y'] = ['g', 'h', 'i'] + + +.. _whatsnew_0.16.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.15.2..v0.16.0 diff --git a/doc/source/whatsnew/v0.16.1.txt b/doc/source/whatsnew/v0.16.1.rst similarity index 99% rename from doc/source/whatsnew/v0.16.1.txt rename to doc/source/whatsnew/v0.16.1.rst index d3a8064a0e786..aae96a5d63c14 100644 --- a/doc/source/whatsnew/v0.16.1.txt +++ b/doc/source/whatsnew/v0.16.1.rst @@ -3,6 +3,8 @@ v0.16.1 (May 11, 2015) ---------------------- +{{ common_imports }} + This is a minor bug-fix release from 0.16.0 and includes a a large number of bug fixes along several new features, enhancements, and performance improvements. We recommend that all users upgrade to this version. @@ -465,3 +467,11 @@ Bug Fixes - Bug in subclassed ``DataFrame``. It may not return the correct class, when slicing or subsetting it. (:issue:`9632`) - Bug in ``.median()`` where non-float null values are not handled correctly (:issue:`10040`) - Bug in Series.fillna() where it raises if a numerically convertible string is given (:issue:`10092`) + + +.. _whatsnew_0.16.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.16.0..v0.16.1 diff --git a/doc/source/whatsnew/v0.16.2.txt b/doc/source/whatsnew/v0.16.2.rst similarity index 98% rename from doc/source/whatsnew/v0.16.2.txt rename to doc/source/whatsnew/v0.16.2.rst index 047da4c94093b..acae3a55d5f78 100644 --- a/doc/source/whatsnew/v0.16.2.txt +++ b/doc/source/whatsnew/v0.16.2.rst @@ -3,6 +3,8 @@ v0.16.2 (June 12, 2015) ----------------------- +{{ common_imports }} + This is a minor bug-fix release from 0.16.1 and includes a a large number of bug fixes along some new features (:meth:`~DataFrame.pipe` method), enhancements, and performance improvements. @@ -165,3 +167,11 @@ Bug Fixes - Bug in ``read_hdf`` where open stores could not be used (:issue:`10330`). - Bug in adding empty ``DataFrames``, now results in a ``DataFrame`` that ``.equals`` an empty ``DataFrame`` (:issue:`10181`). - Bug in ``to_hdf`` and ``HDFStore`` which did not check that complib choices were valid (:issue:`4582`, :issue:`8874`). + + +.. _whatsnew_0.16.2.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.16.1..v0.16.2 diff --git a/doc/source/whatsnew/v0.17.0.txt b/doc/source/whatsnew/v0.17.0.rst similarity index 99% rename from doc/source/whatsnew/v0.17.0.txt rename to doc/source/whatsnew/v0.17.0.rst index 404f2bf06e861..abde8d953f4df 100644 --- a/doc/source/whatsnew/v0.17.0.txt +++ b/doc/source/whatsnew/v0.17.0.rst @@ -3,6 +3,8 @@ v0.17.0 (October 9, 2015) ------------------------- +{{ common_imports }} + This is a major release from 0.16.2 and includes a small number of API changes, several new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -160,7 +162,7 @@ To alleviate this issue, we have added a new, optional plotting interface, which In [14]: df.plot.bar() -.. image:: _static/whatsnew_plot_submethods.png +.. image:: ../_static/whatsnew_plot_submethods.png As a result of this change, these methods are now all discoverable via tab-completion: @@ -313,11 +315,11 @@ has been changed to make this keyword unnecessary - the change is shown below. **Old** -.. image:: _static/old-excel-index.png +.. image:: ../_static/old-excel-index.png **New** -.. image:: _static/new-excel-index.png +.. image:: ../_static/new-excel-index.png .. warning:: @@ -354,14 +356,14 @@ Some East Asian countries use Unicode characters its width is corresponding to 2 df = pd.DataFrame({u'国籍': ['UK', u'日本'], u'名前': ['Alice', u'しのぶ']}) df; -.. image:: _static/option_unicode01.png +.. image:: ../_static/option_unicode01.png .. ipython:: python pd.set_option('display.unicode.east_asian_width', True) df; -.. image:: _static/option_unicode02.png +.. image:: ../_static/option_unicode02.png For further details, see :ref:`here ` @@ -1167,3 +1169,11 @@ Bug Fixes - Bug in ``.groupby`` when number of keys to group by is same as length of index (:issue:`11185`) - Bug in ``convert_objects`` where converted values might not be returned if all null and ``coerce`` (:issue:`9589`) - Bug in ``convert_objects`` where ``copy`` keyword was not respected (:issue:`9589`) + + +.. _whatsnew_0.17.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.16.2..v0.17.0 diff --git a/doc/source/whatsnew/v0.17.1.txt b/doc/source/whatsnew/v0.17.1.rst similarity index 98% rename from doc/source/whatsnew/v0.17.1.txt rename to doc/source/whatsnew/v0.17.1.rst index 328a8193c8b13..44554a88fba04 100644 --- a/doc/source/whatsnew/v0.17.1.txt +++ b/doc/source/whatsnew/v0.17.1.rst @@ -3,6 +3,8 @@ v0.17.1 (November 21, 2015) --------------------------- +{{ common_imports }} + .. note:: We are proud to announce that *pandas* has become a sponsored project of the (`NumFOCUS organization`_). This will help ensure the success of development of *pandas* as a world-class open-source project. @@ -202,3 +204,11 @@ Bug Fixes - Bug in ``DataFrame.to_sparse()`` loses column names for MultiIndexes (:issue:`11600`) - Bug in ``DataFrame.round()`` with non-unique column index producing a Fatal Python error (:issue:`11611`) - Bug in ``DataFrame.round()`` with ``decimals`` being a non-unique indexed Series producing extra columns (:issue:`11618`) + + +.. _whatsnew_0.17.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.17.0..v0.17.1 diff --git a/doc/source/whatsnew/v0.18.0.txt b/doc/source/whatsnew/v0.18.0.rst similarity index 99% rename from doc/source/whatsnew/v0.18.0.txt rename to doc/source/whatsnew/v0.18.0.rst index e38ba54d4b058..5cd4163b1a7a5 100644 --- a/doc/source/whatsnew/v0.18.0.txt +++ b/doc/source/whatsnew/v0.18.0.rst @@ -3,6 +3,8 @@ v0.18.0 (March 13, 2016) ------------------------ +{{ common_imports }} + This is a major release from 0.17.1 and includes a small number of API changes, several new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -1290,3 +1292,11 @@ Bug Fixes - Bug when specifying a UTC ``DatetimeIndex`` by setting ``utc=True`` in ``.to_datetime`` (:issue:`11934`) - Bug when increasing the buffer size of CSV reader in ``read_csv`` (:issue:`12494`) - Bug when setting columns of a ``DataFrame`` with duplicate column names (:issue:`12344`) + + +.. _whatsnew_0.18.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.17.1..v0.18.0 diff --git a/doc/source/whatsnew/v0.18.1.txt b/doc/source/whatsnew/v0.18.1.rst similarity index 99% rename from doc/source/whatsnew/v0.18.1.txt rename to doc/source/whatsnew/v0.18.1.rst index 2445daebb580a..1dc01d7f1f745 100644 --- a/doc/source/whatsnew/v0.18.1.txt +++ b/doc/source/whatsnew/v0.18.1.rst @@ -3,6 +3,8 @@ v0.18.1 (May 3, 2016) --------------------- +{{ common_imports }} + This is a minor bug-fix release from 0.18.0 and includes a large number of bug fixes along with several new features, enhancements, and performance improvements. We recommend that all users upgrade to this version. @@ -692,3 +694,11 @@ Bug Fixes - Bug in ``pd.to_numeric()`` with ``Index`` returns ``np.ndarray``, rather than ``Index`` (:issue:`12777`) - Bug in ``pd.to_numeric()`` with datetime-like may raise ``TypeError`` (:issue:`12777`) - Bug in ``pd.to_numeric()`` with scalar raises ``ValueError`` (:issue:`12777`) + + +.. _whatsnew_0.18.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.18.0..v0.18.1 diff --git a/doc/source/whatsnew/v0.19.0.txt b/doc/source/whatsnew/v0.19.0.rst similarity index 99% rename from doc/source/whatsnew/v0.19.0.txt rename to doc/source/whatsnew/v0.19.0.rst index 73fb124afef87..467319a4527d1 100644 --- a/doc/source/whatsnew/v0.19.0.txt +++ b/doc/source/whatsnew/v0.19.0.rst @@ -3,6 +3,8 @@ v0.19.0 (October 2, 2016) ------------------------- +{{ common_imports }} + This is a major release from 0.18.1 and includes number of API changes, several new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -1564,3 +1566,11 @@ Bug Fixes - ``PeriodIndex`` can now accept ``list`` and ``array`` which contains ``pd.NaT`` (:issue:`13430`) - Bug in ``df.groupby`` where ``.median()`` returns arbitrary values if grouped dataframe contains empty bins (:issue:`13629`) - Bug in ``Index.copy()`` where ``name`` parameter was ignored (:issue:`14302`) + + +.. _whatsnew_0.19.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.18.1..v0.19.0 diff --git a/doc/source/whatsnew/v0.19.1.txt b/doc/source/whatsnew/v0.19.1.rst similarity index 97% rename from doc/source/whatsnew/v0.19.1.txt rename to doc/source/whatsnew/v0.19.1.rst index 1c577dddf1cd4..0c909fa4195d7 100644 --- a/doc/source/whatsnew/v0.19.1.txt +++ b/doc/source/whatsnew/v0.19.1.rst @@ -3,6 +3,8 @@ v0.19.1 (November 3, 2016) -------------------------- +{{ common_imports }} + This is a minor bug-fix release from 0.19.0 and includes some small regression fixes, bug fixes and performance improvements. We recommend that all users upgrade to this version. @@ -59,3 +61,11 @@ Bug Fixes - Bug in ``df.groupby`` where ``TypeError`` raised when ``pd.Grouper(key=...)`` is passed in a list (:issue:`14334`) - Bug in ``pd.pivot_table`` may raise ``TypeError`` or ``ValueError`` when ``index`` or ``columns`` is not scalar and ``values`` is not specified (:issue:`14380`) + + +.. _whatsnew_0.19.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.19.0..v0.19.1 diff --git a/doc/source/whatsnew/v0.19.2.txt b/doc/source/whatsnew/v0.19.2.rst similarity index 97% rename from doc/source/whatsnew/v0.19.2.txt rename to doc/source/whatsnew/v0.19.2.rst index 171d97b76de75..1cded6d2c94e2 100644 --- a/doc/source/whatsnew/v0.19.2.txt +++ b/doc/source/whatsnew/v0.19.2.rst @@ -3,6 +3,8 @@ v0.19.2 (December 24, 2016) --------------------------- +{{ common_imports }} + This is a minor bug-fix release in the 0.19.x series and includes some small regression fixes, bug fixes and performance improvements. We recommend that all users upgrade to this version. @@ -80,3 +82,11 @@ Bug Fixes - Explicit check in ``to_stata`` and ``StataWriter`` for out-of-range values when writing doubles (:issue:`14618`) - Bug in ``.plot(kind='kde')`` which did not drop missing values to generate the KDE Plot, instead generating an empty plot. (:issue:`14821`) - Bug in ``unstack()`` if called with a list of column(s) as an argument, regardless of the dtypes of all columns, they get coerced to ``object`` (:issue:`11847`) + + +.. _whatsnew_0.19.2.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.19.1..v0.19.2 diff --git a/doc/source/whatsnew/v0.20.0.txt b/doc/source/whatsnew/v0.20.0.rst similarity index 99% rename from doc/source/whatsnew/v0.20.0.txt rename to doc/source/whatsnew/v0.20.0.rst index 9f5fbdc195f34..8456449ee4419 100644 --- a/doc/source/whatsnew/v0.20.0.txt +++ b/doc/source/whatsnew/v0.20.0.rst @@ -3,6 +3,8 @@ v0.20.1 (May 5, 2017) --------------------- +{{ common_imports }} + This is a major release from 0.19.2 and includes a number of API changes, deprecations, new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -381,7 +383,7 @@ For example, after running the following, ``styled.xlsx`` renders as below: highlight_max() styled.to_excel('styled.xlsx', engine='openpyxl') -.. image:: _static/style-excel.png +.. image:: ../_static/style-excel.png .. ipython:: python :suppress: @@ -1731,3 +1733,11 @@ Other - Compat for 32-bit platforms for ``.qcut/cut``; bins will now be ``int64`` dtype (:issue:`14866`) - Bug in interactions with ``Qt`` when a ``QtApplication`` already exists (:issue:`14372`) - Avoid use of ``np.finfo()`` during ``import pandas`` removed to mitigate deadlock on Python GIL misuse (:issue:`14641`) + + +.. _whatsnew_0.20.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.19.2..v0.20.0 diff --git a/doc/source/whatsnew/v0.20.2.txt b/doc/source/whatsnew/v0.20.2.rst similarity index 97% rename from doc/source/whatsnew/v0.20.2.txt rename to doc/source/whatsnew/v0.20.2.rst index 3de6fbc8afaf8..784cd09edff30 100644 --- a/doc/source/whatsnew/v0.20.2.txt +++ b/doc/source/whatsnew/v0.20.2.rst @@ -3,6 +3,8 @@ v0.20.2 (June 4, 2017) ---------------------- +{{ common_imports }} + This is a minor bug-fix release in the 0.20.x series and includes some small regression fixes, bug fixes and performance improvements. We recommend that all users upgrade to this version. @@ -125,3 +127,11 @@ Other ^^^^^ - Bug in ``DataFrame.drop()`` with an empty-list with non-unique indices (:issue:`16270`) + + +.. _whatsnew_0.20.2.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.20.0..v0.20.2 diff --git a/doc/source/whatsnew/v0.20.3.txt b/doc/source/whatsnew/v0.20.3.rst similarity index 95% rename from doc/source/whatsnew/v0.20.3.txt rename to doc/source/whatsnew/v0.20.3.rst index 582f975f81a7a..47bfcc761b088 100644 --- a/doc/source/whatsnew/v0.20.3.txt +++ b/doc/source/whatsnew/v0.20.3.rst @@ -3,6 +3,8 @@ v0.20.3 (July 7, 2017) ----------------------- +{{ common_imports }} + This is a minor bug-fix release in the 0.20.x series and includes some small regression fixes and bug fixes. We recommend that all users upgrade to this version. @@ -58,3 +60,11 @@ Categorical ^^^^^^^^^^^ - Bug in ``DataFrame.sort_values`` not respecting the ``kind`` parameter with categorical data (:issue:`16793`) + + +.. _whatsnew_0.20.3.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.20.2..v0.20.3 diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.rst similarity index 99% rename from doc/source/whatsnew/v0.21.0.txt rename to doc/source/whatsnew/v0.21.0.rst index 77ae5b92d0e70..c9a90f3ada7e5 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.rst @@ -3,6 +3,8 @@ v0.21.0 (October 27, 2017) -------------------------- +{{ common_imports }} + This is a major release from 0.20.3 and includes a number of API changes, deprecations, new features, enhancements, and performance improvements along with a large number of bug fixes. We recommend that all users upgrade to this version. @@ -1176,3 +1178,11 @@ Other - Bug where some inplace operators were not being wrapped and produced a copy when invoked (:issue:`12962`) - Bug in :func:`eval` where the ``inplace`` parameter was being incorrectly handled (:issue:`16732`) + + +.. _whatsnew_0.21.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.20.3..v0.21.0 diff --git a/doc/source/whatsnew/v0.21.1.txt b/doc/source/whatsnew/v0.21.1.rst similarity index 98% rename from doc/source/whatsnew/v0.21.1.txt rename to doc/source/whatsnew/v0.21.1.rst index 49e59c9ddf5a7..bf13d5d67ed63 100644 --- a/doc/source/whatsnew/v0.21.1.txt +++ b/doc/source/whatsnew/v0.21.1.rst @@ -3,6 +3,8 @@ v0.21.1 (December 12, 2017) --------------------------- +{{ common_imports }} + This is a minor bug-fix release in the 0.21.x series and includes some small regression fixes, bug fixes and performance improvements. We recommend that all users upgrade to this version. @@ -169,3 +171,11 @@ String ^^^^^^ - :meth:`Series.str.split()` will now propagate ``NaN`` values across all expanded columns instead of ``None`` (:issue:`18450`) + + +.. _whatsnew_0.21.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.21.0..v0.21.1 diff --git a/doc/source/whatsnew/v0.22.0.txt b/doc/source/whatsnew/v0.22.0.rst similarity index 98% rename from doc/source/whatsnew/v0.22.0.txt rename to doc/source/whatsnew/v0.22.0.rst index d165339cb0de9..f05b84a9d8902 100644 --- a/doc/source/whatsnew/v0.22.0.txt +++ b/doc/source/whatsnew/v0.22.0.rst @@ -3,6 +3,8 @@ v0.22.0 (December 29, 2017) --------------------------- +{{ common_imports }} + This is a major release from 0.21.1 and includes a single, API-breaking change. We recommend that all users upgrade to this version after carefully reading the release note (singular!). @@ -241,3 +243,11 @@ With conda, use Note that the inconsistency in the return value for all-*NA* series is still there for pandas 0.20.3 and earlier. Avoiding pandas 0.21 will only help with the empty case. + + +.. _whatsnew_0.22.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.21.1..v0.22.0 diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.rst similarity index 99% rename from doc/source/whatsnew/v0.23.0.txt rename to doc/source/whatsnew/v0.23.0.rst index 473a4bb72e6d9..f84517a3e3b9c 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.rst @@ -1,7 +1,9 @@ .. _whatsnew_0230: -v0.23.0 (May 15, 2018) ----------------------- +What's new in 0.23.0 (May 15, 2018) +----------------------------------- + +{{ common_imports }} This is a major release from 0.22.0 and includes a number of API changes, deprecations, new features, enhancements, and performance improvements along @@ -908,7 +910,7 @@ frames would not fit within the terminal width, and pandas would introduce line breaks to display these 20 columns. This resulted in an output that was relatively difficult to read: -.. image:: _static/print_df_old.png +.. image:: ../_static/print_df_old.png If Python runs in a terminal, the maximum number of columns is now determined automatically so that the printed data frame fits within the current terminal @@ -918,7 +920,7 @@ well as in many IDEs), this value cannot be inferred automatically and is thus set to `20` as in previous versions. In a terminal, this results in a much nicer output: -.. image:: _static/print_df_new.png +.. image:: ../_static/print_df_new.png Note that if you don't like the new default, you can always set this option yourself. To revert to the old setting, you can run this line: @@ -1412,3 +1414,10 @@ Other - Improved error message when attempting to use a Python keyword as an identifier in a ``numexpr`` backed query (:issue:`18221`) - Bug in accessing a :func:`pandas.get_option`, which raised ``KeyError`` rather than ``OptionError`` when looking up a non-existent option key in some cases (:issue:`19789`) - Bug in :func:`testing.assert_series_equal` and :func:`testing.assert_frame_equal` for Series or DataFrames with differing unicode data (:issue:`20503`) + +.. _whatsnew_0.23.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.22.0..v0.23.0 diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.rst similarity index 97% rename from doc/source/whatsnew/v0.23.1.txt rename to doc/source/whatsnew/v0.23.1.rst index 1a514ba627fcb..e8e0060c48337 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.rst @@ -1,7 +1,9 @@ .. _whatsnew_0231: -v0.23.1 (June 12, 2018) ------------------------ +What's New in 0.23.1 (June 12, 2018) +------------------------------------ + +{{ common_imports }} This is a minor bug-fix release in the 0.23.x series and includes some small regression fixes and bug fixes. We recommend that all users upgrade to this version. @@ -138,3 +140,10 @@ Bug Fixes - Tab completion on :class:`Index` in IPython no longer outputs deprecation warnings (:issue:`21125`) - Bug preventing pandas being used on Windows without C++ redistributable installed (:issue:`21106`) + +.. _whatsnew_0.23.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.23.0..v0.23.1 diff --git a/doc/source/whatsnew/v0.23.2.txt b/doc/source/whatsnew/v0.23.2.rst similarity index 81% rename from doc/source/whatsnew/v0.23.2.txt rename to doc/source/whatsnew/v0.23.2.rst index 7ec6e2632e717..573a30f17846b 100644 --- a/doc/source/whatsnew/v0.23.2.txt +++ b/doc/source/whatsnew/v0.23.2.rst @@ -1,7 +1,9 @@ .. _whatsnew_0232: -v0.23.2 (July 5, 2018) ----------------------- +What's New in 0.23.2 (July 5, 2018) +----------------------------------- + +{{ common_imports }} This is a minor bug-fix release in the 0.23.x series and includes some small regression fixes and bug fixes. We recommend that all users upgrade to this version. @@ -101,8 +103,20 @@ Bug Fixes **Timezones** - Bug in :class:`Timestamp` and :class:`DatetimeIndex` where passing a :class:`Timestamp` localized after a DST transition would return a datetime before the DST transition (:issue:`20854`) -- Bug in comparing :class:`DataFrame`s with tz-aware :class:`DatetimeIndex` columns with a DST transition that raised a ``KeyError`` (:issue:`19970`) +- Bug in comparing :class:`DataFrame` with tz-aware :class:`DatetimeIndex` columns with a DST transition that raised a ``KeyError`` (:issue:`19970`) +- Bug in :meth:`DatetimeIndex.shift` where an ``AssertionError`` would raise when shifting across DST (:issue:`8616`) +- Bug in :class:`Timestamp` constructor where passing an invalid timezone offset designator (``Z``) would not raise a ``ValueError`` (:issue:`8910`) +- Bug in :meth:`Timestamp.replace` where replacing at a DST boundary would retain an incorrect offset (:issue:`7825`) +- Bug in :meth:`DatetimeIndex.reindex` when reindexing a tz-naive and tz-aware :class:`DatetimeIndex` (:issue:`8306`) +- Bug in :meth:`DatetimeIndex.resample` when downsampling across a DST boundary (:issue:`8531`) **Timedelta** - Bug in :class:`Timedelta` where non-zero timedeltas shorter than 1 microsecond were considered False (:issue:`21484`) + +.. _whatsnew_0.23.2.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.23.1..v0.23.2 diff --git a/doc/source/whatsnew/v0.23.3.rst b/doc/source/whatsnew/v0.23.3.rst new file mode 100644 index 0000000000000..29758e54b437b --- /dev/null +++ b/doc/source/whatsnew/v0.23.3.rst @@ -0,0 +1,16 @@ +.. _whatsnew_0233: + +What's New in 0.23.3 (July 7, 2018) +----------------------------------- + +{{ common_imports }} + +This release fixes a build issue with the sdist for Python 3.7 (:issue:`21785`) +There are no other changes. + +.. _whatsnew_0.23.3.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.23.2..v0.23.3 diff --git a/doc/source/whatsnew/v0.23.3.txt b/doc/source/whatsnew/v0.23.3.txt deleted file mode 100644 index b8adce27d2523..0000000000000 --- a/doc/source/whatsnew/v0.23.3.txt +++ /dev/null @@ -1,7 +0,0 @@ -.. _whatsnew_0233: - -v0.23.3 (July 7, 2018) ----------------------- - -This release fixes a build issue with the sdist for Python 3.7 (:issue:`21785`) -There are no other changes. diff --git a/doc/source/whatsnew/v0.23.4.txt b/doc/source/whatsnew/v0.23.4.rst similarity index 84% rename from doc/source/whatsnew/v0.23.4.txt rename to doc/source/whatsnew/v0.23.4.rst index 9a3ad3f61ee49..c8f08d0bb7091 100644 --- a/doc/source/whatsnew/v0.23.4.txt +++ b/doc/source/whatsnew/v0.23.4.rst @@ -1,7 +1,9 @@ .. _whatsnew_0234: -v0.23.4 (August 3, 2018) ------------------------- +What's New in 0.23.4 (August 3, 2018) +------------------------------------- + +{{ common_imports }} This is a minor bug-fix release in the 0.23.x series and includes some small regression fixes and bug fixes. We recommend that all users upgrade to this version. @@ -35,3 +37,10 @@ Bug Fixes **Missing** - Bug in :func:`Series.clip` and :func:`DataFrame.clip` cannot accept list-like threshold containing ``NaN`` (:issue:`19992`) + +.. _whatsnew_0.23.4.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.23.3..v0.23.4 diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.rst similarity index 99% rename from doc/source/whatsnew/v0.24.0.txt rename to doc/source/whatsnew/v0.24.0.rst index 3057e3f700eab..44c467795d1ed 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.rst @@ -1,13 +1,18 @@ .. _whatsnew_0240: -v0.24.0 (Month XX, 2018) ------------------------- +What's New in 0.24.0 (Month XX, 2018) +------------------------------------- .. warning:: Starting January 1, 2019, pandas feature releases will support Python 3 only. See :ref:`install.dropping-27` for more. +{{ common_imports }} + +These are the changes in pandas 0.24.0. See :ref:`release` for a full changelog +including other versions of pandas. + .. _whatsnew_0240.enhancements: New features @@ -205,6 +210,7 @@ See the :ref:`advanced docs on renaming` for more details. Other Enhancements ^^^^^^^^^^^^^^^^^^ + - :func:`to_datetime` now supports the ``%Z`` and ``%z`` directive when passed into ``format`` (:issue:`13486`) - :func:`Series.mode` and :func:`DataFrame.mode` now support the ``dropna`` parameter which can be used to specify whether ``NaN``/``NaT`` values should be considered (:issue:`17534`) - :func:`to_csv` now supports ``compression`` keyword when a file handle is passed. (:issue:`21227`) @@ -1175,7 +1181,7 @@ Timezones - Bug in :class:`DatetimeIndex` comparisons failing to raise ``TypeError`` when comparing timezone-aware ``DatetimeIndex`` against ``np.datetime64`` (:issue:`22074`) - Bug in ``DataFrame`` assignment with a timezone-aware scalar (:issue:`19843`) - Bug in :func:`DataFrame.asof` that raised a ``TypeError`` when attempting to compare tz-naive and tz-aware timestamps (:issue:`21194`) -- Bug when constructing a :class:`DatetimeIndex` with :class:`Timestamp`s constructed with the ``replace`` method across DST (:issue:`18785`) +- Bug when constructing a :class:`DatetimeIndex` with :class:`Timestamp` constructed with the ``replace`` method across DST (:issue:`18785`) - Bug when setting a new value with :meth:`DataFrame.loc` with a :class:`DatetimeIndex` with a DST transition (:issue:`18308`, :issue:`20724`) - Bug in :meth:`DatetimeIndex.unique` that did not re-localize tz-aware dates correctly (:issue:`21737`) - Bug when indexing a :class:`Series` with a DST transition (:issue:`21846`) @@ -1260,7 +1266,7 @@ MultiIndex ^^^^^^^^^^ - Removed compatibility for :class:`MultiIndex` pickles prior to version 0.8.0; compatibility with :class:`MultiIndex` pickles from version 0.13 forward is maintained (:issue:`21654`) -- :meth:`MultiIndex.get_loc_level` (and as a consequence, ``.loc`` on a :class:`MultiIndex`ed object) will now raise a ``KeyError``, rather than returning an empty ``slice``, if asked a label which is present in the ``levels`` but is unused (:issue:`22221`) +- :meth:`MultiIndex.get_loc_level` (and as a consequence, ``.loc`` on a ``Series`` or ``DataFrame`` with a :class:`MultiIndex` index) will now raise a ``KeyError``, rather than returning an empty ``slice``, if asked a label which is present in the ``levels`` but is unused (:issue:`22221`) - Fix ``TypeError`` in Python 3 when creating :class:`MultiIndex` in which some levels have mixed types, e.g. when some labels are tuples (:issue:`15457`) I/O @@ -1363,9 +1369,9 @@ Reshaping - Bug in :func:`pandas.wide_to_long` when a string is passed to the stubnames argument and a column name is a substring of that stubname (:issue:`22468`) - Bug in :func:`merge` when merging ``datetime64[ns, tz]`` data that contained a DST transition (:issue:`18885`) - Bug in :func:`merge_asof` when merging on float values within defined tolerance (:issue:`22981`) -- Bug in :func:`pandas.concat` when concatenating a multicolumn DataFrame with tz-aware data against a DataFrame with a different number of columns (:issue`22796`) +- Bug in :func:`pandas.concat` when concatenating a multicolumn DataFrame with tz-aware data against a DataFrame with a different number of columns (:issue:`22796`) - Bug in :func:`merge_asof` where confusing error message raised when attempting to merge with missing values (:issue:`23189`) -- Bug in :meth:`DataFrame.nsmallest` and :meth:`DataFrame.nlargest` for dataframes that have :class:`MultiIndex`ed columns (:issue:`23033`). +- Bug in :meth:`DataFrame.nsmallest` and :meth:`DataFrame.nlargest` for dataframes that have a :class:`MultiIndex` for columns (:issue:`23033`). .. _whatsnew_0240.bug_fixes.sparse: @@ -1398,3 +1404,10 @@ Other - :meth:`~pandas.io.formats.style.Styler.bar` now also supports tablewise application (in addition to rowwise and columnwise) with ``axis=None`` and setting clipping range with ``vmin`` and ``vmax`` (:issue:`21548` and :issue:`21526`). ``NaN`` values are also handled properly. - Logical operations ``&, |, ^`` between :class:`Series` and :class:`Index` will no longer raise ``ValueError`` (:issue:`22092`) - Bug in :meth:`DataFrame.combine_first` in which column types were unexpectedly converted to float (:issue:`20699`) + +.. _whatsnew_0.24.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.23.4..HEAD diff --git a/doc/source/whatsnew/v0.4.x.txt b/doc/source/whatsnew/v0.4.x.rst similarity index 97% rename from doc/source/whatsnew/v0.4.x.txt rename to doc/source/whatsnew/v0.4.x.rst index ed9352059a6dc..e54614849c93b 100644 --- a/doc/source/whatsnew/v0.4.x.txt +++ b/doc/source/whatsnew/v0.4.x.rst @@ -3,6 +3,8 @@ v.0.4.3 through v0.4.1 (September 25 - October 9, 2011) ------------------------------------------------------- +{{ common_imports }} + New Features ~~~~~~~~~~~~ @@ -61,3 +63,7 @@ Performance Enhancements .. _ENHed: https://github.com/pandas-dev/pandas/commit/edd9f1945fc010a57fa0ae3b3444d1fffe592591 .. _ENH56: https://github.com/pandas-dev/pandas/commit/56e0c9ffafac79ce262b55a6a13e1b10a88fbe93 +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.4.1..v0.4.3 diff --git a/doc/source/whatsnew/v0.5.0.txt b/doc/source/whatsnew/v0.5.0.rst similarity index 96% rename from doc/source/whatsnew/v0.5.0.txt rename to doc/source/whatsnew/v0.5.0.rst index 6fe6a02b08f70..c6d17cb1e1290 100644 --- a/doc/source/whatsnew/v0.5.0.txt +++ b/doc/source/whatsnew/v0.5.0.rst @@ -4,6 +4,8 @@ v.0.5.0 (October 24, 2011) -------------------------- +{{ common_imports }} + New Features ~~~~~~~~~~~~ @@ -41,3 +43,11 @@ Performance Enhancements .. _ENH61: https://github.com/pandas-dev/pandas/commit/6141961 .. _ENH5c: https://github.com/pandas-dev/pandas/commit/5ca6ff5d822ee4ddef1ec0d87b6d83d8b4bbd3eb + + +.. _whatsnew_0.5.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.4.0..v0.5.0 diff --git a/doc/source/whatsnew/v0.6.0.txt b/doc/source/whatsnew/v0.6.0.rst similarity index 97% rename from doc/source/whatsnew/v0.6.0.txt rename to doc/source/whatsnew/v0.6.0.rst index bd01dd0a90a59..de45b3b383129 100644 --- a/doc/source/whatsnew/v0.6.0.txt +++ b/doc/source/whatsnew/v0.6.0.rst @@ -3,6 +3,8 @@ v.0.6.0 (November 25, 2011) --------------------------- +{{ common_imports }} + New Features ~~~~~~~~~~~~ - :ref:`Added ` ``melt`` function to ``pandas.core.reshape`` @@ -54,3 +56,11 @@ Performance Enhancements - VBENCH Significantly improved performance of ``Series.order``, which also makes np.unique called on a Series faster (:issue:`327`) - VBENCH Vastly improved performance of GroupBy on axes with a MultiIndex (:issue:`299`) + + +.. _whatsnew_0.6.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.5.0..v0.6.0 diff --git a/doc/source/whatsnew/v0.6.1.txt b/doc/source/whatsnew/v0.6.1.rst similarity index 96% rename from doc/source/whatsnew/v0.6.1.txt rename to doc/source/whatsnew/v0.6.1.rst index acd5b0774f2bb..d01757775d694 100644 --- a/doc/source/whatsnew/v0.6.1.txt +++ b/doc/source/whatsnew/v0.6.1.rst @@ -48,3 +48,11 @@ Performance improvements - Column deletion in DataFrame copies no data (computes views on blocks) (GH #158) + + +.. _whatsnew_0.6.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.6.0..v0.6.1 diff --git a/doc/source/whatsnew/v0.7.0.txt b/doc/source/whatsnew/v0.7.0.rst similarity index 98% rename from doc/source/whatsnew/v0.7.0.txt rename to doc/source/whatsnew/v0.7.0.rst index 21d91950e7b78..e278bc0738108 100644 --- a/doc/source/whatsnew/v0.7.0.txt +++ b/doc/source/whatsnew/v0.7.0.rst @@ -3,6 +3,8 @@ v.0.7.0 (February 9, 2012) -------------------------- +{{ common_imports }} + New features ~~~~~~~~~~~~ @@ -298,3 +300,11 @@ Performance improvements ``level`` parameter passed (:issue:`545`) - Ported skiplist data structure to C to speed up ``rolling_median`` by about 5-10x in most typical use cases (:issue:`374`) + + +.. _whatsnew_0.7.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.6.1..v0.7.0 diff --git a/doc/source/whatsnew/v0.7.1.txt b/doc/source/whatsnew/v0.7.1.rst similarity index 90% rename from doc/source/whatsnew/v0.7.1.txt rename to doc/source/whatsnew/v0.7.1.rst index bc12cb8d200cd..f1a133797fd59 100644 --- a/doc/source/whatsnew/v0.7.1.txt +++ b/doc/source/whatsnew/v0.7.1.rst @@ -3,6 +3,8 @@ v.0.7.1 (February 29, 2012) --------------------------- +{{ common_imports }} + This release includes a few new features and addresses over a dozen bugs in 0.7.0. @@ -28,3 +30,11 @@ Performance improvements - Improve performance and memory usage of fillna on DataFrame - Can concatenate a list of Series along axis=1 to obtain a DataFrame (:issue:`787`) + + +.. _whatsnew_0.7.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.7.0..v0.7.1 diff --git a/doc/source/whatsnew/v0.7.2.txt b/doc/source/whatsnew/v0.7.2.rst similarity index 89% rename from doc/source/whatsnew/v0.7.2.txt rename to doc/source/whatsnew/v0.7.2.rst index c711639354139..b870db956f4f1 100644 --- a/doc/source/whatsnew/v0.7.2.txt +++ b/doc/source/whatsnew/v0.7.2.rst @@ -3,6 +3,8 @@ v.0.7.2 (March 16, 2012) --------------------------- +{{ common_imports }} + This release targets bugs in 0.7.1, and adds a few minor features. New features @@ -25,3 +27,11 @@ Performance improvements - Use khash for Series.value_counts, add raw function to algorithms.py (:issue:`861`) - Intercept __builtin__.sum in groupby (:issue:`885`) + + +.. _whatsnew_0.7.2.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.7.1..v0.7.2 diff --git a/doc/source/whatsnew/v0.7.3.txt b/doc/source/whatsnew/v0.7.3.rst similarity index 92% rename from doc/source/whatsnew/v0.7.3.txt rename to doc/source/whatsnew/v0.7.3.rst index 77cc72d8707cf..30e22f105656c 100644 --- a/doc/source/whatsnew/v0.7.3.txt +++ b/doc/source/whatsnew/v0.7.3.rst @@ -3,6 +3,8 @@ v.0.7.3 (April 12, 2012) ------------------------ +{{ common_imports }} + This is a minor release from 0.7.2 and fixes many minor bugs and adds a number of nice new features. There are also a couple of API changes to note; these should not affect very many users, and we are inclined to call them "bug fixes" @@ -22,7 +24,7 @@ New features from pandas.tools.plotting import scatter_matrix scatter_matrix(df, alpha=0.2) -.. image:: savefig/scatter_matrix_kde.png +.. image:: ../savefig/scatter_matrix_kde.png :width: 5in - Add ``stacked`` argument to Series and DataFrame's ``plot`` method for @@ -32,14 +34,14 @@ New features df.plot(kind='bar', stacked=True) -.. image:: savefig/bar_plot_stacked_ex.png +.. image:: ../savefig/bar_plot_stacked_ex.png :width: 4in .. code-block:: python df.plot(kind='barh', stacked=True) -.. image:: savefig/barh_plot_stacked_ex.png +.. image:: ../savefig/barh_plot_stacked_ex.png :width: 4in - Add log x and y :ref:`scaling options ` to @@ -94,3 +96,11 @@ Series, to be more consistent with the ``groupby`` behavior with DataFrame: grouped = df.groupby('A')['C'] grouped.describe() grouped.apply(lambda x: x.sort_values()[-2:]) # top 2 values + + +.. _whatsnew_0.7.3.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.7.2..v0.7.3 diff --git a/doc/source/whatsnew/v0.8.0.txt b/doc/source/whatsnew/v0.8.0.rst similarity index 99% rename from doc/source/whatsnew/v0.8.0.txt rename to doc/source/whatsnew/v0.8.0.rst index 28c043e772605..eedaaa3dfa8bd 100644 --- a/doc/source/whatsnew/v0.8.0.txt +++ b/doc/source/whatsnew/v0.8.0.rst @@ -3,6 +3,8 @@ v0.8.0 (June 29, 2012) ------------------------ +{{ common_imports }} + This is a major release from 0.7.3 and includes extensive work on the time series handling and processing infrastructure as well as a great deal of new functionality throughout the library. It includes over 700 commits from more @@ -269,3 +271,11 @@ unique. In many cases it will no longer fail (some method like ``append`` still check for uniqueness unless disabled). However, all is not lost: you can inspect ``index.is_unique`` and raise an exception explicitly if it is ``False`` or go to a different code branch. + + +.. _whatsnew_0.8.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.7.3..v0.8.0 diff --git a/doc/source/whatsnew/v0.8.1.txt b/doc/source/whatsnew/v0.8.1.rst similarity index 93% rename from doc/source/whatsnew/v0.8.1.txt rename to doc/source/whatsnew/v0.8.1.rst index add96bec9d1dd..468b99341163c 100644 --- a/doc/source/whatsnew/v0.8.1.txt +++ b/doc/source/whatsnew/v0.8.1.rst @@ -3,6 +3,8 @@ v0.8.1 (July 22, 2012) ---------------------- +{{ common_imports }} + This release includes a few new features, performance enhancements, and over 30 bug fixes from 0.8.0. New features include notably NA friendly string processing functionality and a series of new plot types and options. @@ -34,3 +36,11 @@ Performance improvements Categorical types - Significant datetime parsing performance improvements + + +.. _whatsnew_0.8.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.8.0..v0.8.1 diff --git a/doc/source/whatsnew/v0.9.0.txt b/doc/source/whatsnew/v0.9.0.rst similarity index 96% rename from doc/source/whatsnew/v0.9.0.txt rename to doc/source/whatsnew/v0.9.0.rst index b60fb9cc64f4a..ee4e8c338c984 100644 --- a/doc/source/whatsnew/v0.9.0.txt +++ b/doc/source/whatsnew/v0.9.0.rst @@ -1,9 +1,6 @@ .. _whatsnew_0900: -.. ipython:: python - :suppress: - - from pandas.compat import StringIO +{{ common_imports }} v0.9.0 (October 7, 2012) ------------------------ @@ -95,3 +92,11 @@ See the :ref:`full release notes ` or issue tracker on GitHub for a complete list. + + +.. _whatsnew_0.9.0.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.8.1..v0.9.0 diff --git a/doc/source/whatsnew/v0.9.1.txt b/doc/source/whatsnew/v0.9.1.rst similarity index 97% rename from doc/source/whatsnew/v0.9.1.txt rename to doc/source/whatsnew/v0.9.1.rst index 1f58170b30244..fe3de9be95a74 100644 --- a/doc/source/whatsnew/v0.9.1.txt +++ b/doc/source/whatsnew/v0.9.1.rst @@ -1,13 +1,10 @@ .. _whatsnew_0901: -.. ipython:: python - :suppress: - - from pandas.compat import StringIO - v0.9.1 (November 14, 2012) -------------------------- +{{ common_imports }} + This is a bug fix release from 0.9.0 and includes several new features and enhancements along with a large number of bug fixes. The new features include by-column sort order for DataFrame and Series, improved NA handling for the rank @@ -158,3 +155,11 @@ API changes See the :ref:`full release notes ` or issue tracker on GitHub for a complete list. + + +.. _whatsnew_0.9.1.contributors: + +Contributors +~~~~~~~~~~~~ + +.. contributors:: v0.9.0..v0.9.1 diff --git a/scripts/announce.py b/doc/sphinxext/announce.py similarity index 75% rename from scripts/announce.py rename to doc/sphinxext/announce.py index 7b7933eba54dd..6bc53d3e96d01 100755 --- a/scripts/announce.py +++ b/doc/sphinxext/announce.py @@ -33,19 +33,21 @@ $ ./scripts/announce.py $GITHUB v1.11.0..v1.11.1 > announce.rst """ -from __future__ import print_function, division +from __future__ import division, print_function +import codecs import os import re -import codecs +import textwrap + from git import Repo UTF8Writer = codecs.getwriter('utf8') -this_repo = Repo(os.path.join(os.path.dirname(__file__), "..")) +this_repo = Repo(os.path.join(os.path.dirname(__file__), "..", "..")) author_msg = """\ -A total of %d people contributed to this release. People with a "+" by their -names contributed a patch for the first time. +A total of %d people contributed patches to this release. People with a +"+" by their names contributed a patch for the first time. """ pull_request_msg = """\ @@ -98,19 +100,35 @@ def get_pull_requests(repo, revision_range): return prs -def main(revision_range, repo): +def build_components(revision_range, heading="Contributors"): lst_release, cur_release = [r.strip() for r in revision_range.split('..')] - - # document authors authors = get_authors(revision_range) - heading = u"Contributors" - print() - print(heading) - print(u"=" * len(heading)) - print(author_msg % len(authors)) - for s in authors: - print(u'* ' + s) + return { + 'heading': heading, + 'author_message': author_msg % len(authors), + 'authors': authors, + } + + +def build_string(revision_range, heading="Contributors"): + components = build_components(revision_range, heading=heading) + components['uline'] = '=' * len(components['heading']) + components['authors'] = "* " + "\n* ".join(components['authors']) + + tpl = textwrap.dedent("""\ + {heading} + {uline} + + {author_message} + {authors}""").format(**components) + return tpl + + +def main(revision_range): + # document authors + text = build_string(revision_range) + print(text) if __name__ == "__main__": @@ -118,7 +136,5 @@ def main(revision_range, repo): parser = ArgumentParser(description="Generate author lists for release") parser.add_argument('revision_range', help='..') - parser.add_argument('--repo', help="Github org/repository", - default="pandas-dev/pandas") args = parser.parse_args() - main(args.revision_range, args.repo) + main(args.revision_range) diff --git a/doc/sphinxext/contributors.py b/doc/sphinxext/contributors.py new file mode 100644 index 0000000000000..0f04d47435699 --- /dev/null +++ b/doc/sphinxext/contributors.py @@ -0,0 +1,40 @@ +"""Sphinx extension for listing code contributors to a release. + +Usage:: + + .. contributors:: v0.23.0..v0.23.1 + +This will be replaced with a message indicating the number of +code contributors and commits, and then list each contributor +individually. +""" +from docutils import nodes +from docutils.parsers.rst import Directive + +from announce import build_components + + +class ContributorsDirective(Directive): + required_arguments = 1 + name = 'contributors' + + def run(self): + components = build_components(self.arguments[0]) + + message = nodes.paragraph() + message += nodes.Text(components['author_message']) + + listnode = nodes.bullet_list() + + for author in components['authors']: + para = nodes.paragraph() + para += nodes.Text(author) + listnode += nodes.list_item('', para) + + return [message, listnode] + + +def setup(app): + app.add_directive('contributors', ContributorsDirective) + + return {'version': '0.1'} diff --git a/environment.yml b/environment.yml index 742b974566577..fc35f1290f1b1 100644 --- a/environment.yml +++ b/environment.yml @@ -14,6 +14,7 @@ dependencies: - flake8 - flake8-comprehensions - flake8-rst=0.4.2 + - gitpython - hypothesis>=3.58.0 - isort - moto diff --git a/requirements-dev.txt b/requirements-dev.txt index 9acfe243d22fb..6678d205aca6c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,6 +5,7 @@ Cython>=0.28.2 flake8 flake8-comprehensions flake8-rst==0.4.2 +gitpython hypothesis>=3.58.0 isort moto diff --git a/setup.cfg b/setup.cfg index 9f5384170a245..7212833435997 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,7 +34,22 @@ exclude = ignore = F821, # undefined name W391, # blank line at end of file [Seems to be a bug (v0.4.1)] - +exclude = + doc/source/whatsnew/v0.7.0.rst + doc/source/whatsnew/v0.10.1.rst + doc/source/whatsnew/v0.12.0.rst + doc/source/whatsnew/v0.13.0.rst + doc/source/whatsnew/v0.13.1.rst + doc/source/whatsnew/v0.14.0.rst + doc/source/whatsnew/v0.15.0.rst + doc/source/whatsnew/v0.16.0.rst + doc/source/whatsnew/v0.16.2.rst + doc/source/whatsnew/v0.17.0.rst + doc/source/whatsnew/v0.18.0.rst + doc/source/whatsnew/v0.18.1.rst + doc/source/whatsnew/v0.20.0.rst + doc/source/whatsnew/v0.21.0.rst + doc/source/whatsnew/v0.23.0.rst [yapf] based_on_style = pep8 @@ -405,3 +420,4 @@ skip= pandas/types/common.py, pandas/plotting/_compat.py, pandas/tests/extension/arrow/test_bool.py + doc/source/conf.py From b4b945adad587851d570e950d05a1da75c5dc76c Mon Sep 17 00:00:00 2001 From: Doug Latornell Date: Wed, 14 Nov 2018 18:27:25 -0500 Subject: [PATCH 25/25] DOC: Delete trailing blank lines in docstrings. (#23651) xref gh-23632 --- pandas/core/series.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 7f832009ca273..8fba3030be9d4 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -314,7 +314,6 @@ def from_array(cls, arr, index=None, name=None, dtype=None, copy=False, .. deprecated :: 0.23.0 Use pd.Series(..) constructor instead. - """ warnings.warn("'from_array' is deprecated and will be removed in a " "future version. Please use the pd.Series(..) " @@ -437,7 +436,6 @@ def values(self): array(['2013-01-01T05:00:00.000000000', '2013-01-02T05:00:00.000000000', '2013-01-03T05:00:00.000000000'], dtype='datetime64[ns]') - """ return self._data.external_values() @@ -1824,7 +1822,6 @@ def round(self, decimals=0, *args, **kwargs): -------- numpy.around DataFrame.round - """ nv.validate_round(args, kwargs) result = com.values_from_object(self).round(decimals) @@ -1906,7 +1903,6 @@ def corr(self, other, method='pearson', min_periods=None): min_periods : int, optional Minimum number of observations needed to have a valid result - Returns ------- correlation : float @@ -2230,8 +2226,6 @@ def append(self, to_append, ignore_index=False, verify_integrity=False): Traceback (most recent call last): ... ValueError: Indexes have overlapping values: [0, 1, 2] - - """ from pandas.core.reshape.concat import concat @@ -2436,7 +2430,6 @@ def update(self, other): 1 2 2 6 dtype: int64 - """ other = other.reindex_like(self) mask = notna(other) @@ -3011,7 +3004,6 @@ def swaplevel(self, i=-2, j=-1, copy=True): The indexes ``i`` and ``j`` are now optional, and default to the two innermost levels of the index. - """ new_index = self.index.swaplevel(i, j) return self._constructor(self._values, index=new_index, @@ -3336,8 +3328,6 @@ def apply(self, func, convert_dtype=True, args=(), **kwds): New York 3.044522 Helsinki 2.484907 dtype: float64 - - """ if len(self) == 0: return self._constructor(dtype=self.dtype,