From fdbed7bfbb45c5553b2d0c65dc691bf5454aa899 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Tue, 8 Sep 2020 18:04:47 +0700 Subject: [PATCH 1/5] REF: eliminate mediator method _write --- pandas/io/json/_json.py | 130 ++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 85 deletions(-) diff --git a/pandas/io/json/_json.py b/pandas/io/json/_json.py index a4d923fdbe45a..36a1ce8918092 100644 --- a/pandas/io/json/_json.py +++ b/pandas/io/json/_json.py @@ -145,74 +145,82 @@ def _format_axes(self): raise AbstractMethodError(self) def write(self): - return self._write( + iso_dates = self.date_format == "iso" + return dumps( self.obj, - self.orient, - self.double_precision, - self.ensure_ascii, - self.date_unit, - self.date_format == "iso", - self.default_handler, - self.indent, + orient=self.orient, + double_precision=self.double_precision, + ensure_ascii=self.ensure_ascii, + date_unit=self.date_unit, + iso_dates=iso_dates, + default_handler=self.default_handler, + indent=self.indent, ) - def _write( + +class SeriesWriter(Writer): + _default_orient = "index" + + def __init__( self, obj, orient: Optional[str], + date_format: str, double_precision: int, ensure_ascii: bool, date_unit: str, - iso_dates: bool, - default_handler: Optional[Callable[[Any], JSONSerializable]], - indent: int, + index: bool, + default_handler: Optional[Callable[[Any], JSONSerializable]] = None, + indent: int = 0, ): - return dumps( + super().__init__( obj, - orient=orient, - double_precision=double_precision, - ensure_ascii=ensure_ascii, - date_unit=date_unit, - iso_dates=iso_dates, + orient, + date_format, + double_precision, + ensure_ascii, + date_unit, + index, default_handler=default_handler, indent=indent, ) - - -class SeriesWriter(Writer): - _default_orient = "index" + if not index and orient == "split": + self.obj = {"name": obj.name, "data": obj.values} def _format_axes(self): if not self.obj.index.is_unique and self.orient == "index": raise ValueError(f"Series index must be unique for orient='{self.orient}'") - def _write( + +class FrameWriter(Writer): + _default_orient = "columns" + + def __init__( self, obj, orient: Optional[str], + date_format: str, double_precision: int, ensure_ascii: bool, date_unit: str, - iso_dates: bool, - default_handler: Optional[Callable[[Any], JSONSerializable]], - indent: int, + index: bool, + default_handler: Optional[Callable[[Any], JSONSerializable]] = None, + indent: int = 0, ): - if not self.index and orient == "split": - obj = {"name": obj.name, "data": obj.values} - return super()._write( + super().__init__( obj, orient, + date_format, double_precision, ensure_ascii, date_unit, - iso_dates, - default_handler, - indent, + index, + default_handler=default_handler, + indent=indent, ) - - -class FrameWriter(Writer): - _default_orient = "columns" + if not index and orient == "split": + self.obj = obj.to_dict(orient="split") + del self.obj["index"] def _format_axes(self): """ @@ -231,31 +239,6 @@ def _format_axes(self): f"DataFrame columns must be unique for orient='{self.orient}'." ) - def _write( - self, - obj, - orient: Optional[str], - double_precision: int, - ensure_ascii: bool, - date_unit: str, - iso_dates: bool, - default_handler: Optional[Callable[[Any], JSONSerializable]], - indent: int, - ): - if not self.index and orient == "split": - obj = obj.to_dict(orient="split") - del obj["index"] - return super()._write( - obj, - orient, - double_precision, - ensure_ascii, - date_unit, - iso_dates, - default_handler, - indent, - ) - class JSONTableWriter(FrameWriter): _default_orient = "records" @@ -330,30 +313,7 @@ def __init__( self.orient = "records" self.index = index - def _write( - self, - obj, - orient, - double_precision, - ensure_ascii, - date_unit, - iso_dates, - default_handler, - indent, - ): - table_obj = {"schema": self.schema, "data": obj} - serialized = super()._write( - table_obj, - orient, - double_precision, - ensure_ascii, - date_unit, - iso_dates, - default_handler, - indent, - ) - - return serialized + self.obj = {"schema": self.schema, "data": self.obj} @deprecate_kwarg(old_arg_name="numpy", new_arg_name=None) From 1b89abaddfc9bcf80a9533b2ab0dc3e7d85e9711 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Thu, 10 Sep 2020 12:32:05 +0700 Subject: [PATCH 2/5] REF: extract property obj_to_write --- pandas/io/json/_json.py | 79 +++++++++++++---------------------------- 1 file changed, 25 insertions(+), 54 deletions(-) diff --git a/pandas/io/json/_json.py b/pandas/io/json/_json.py index 36a1ce8918092..a573d5bfb8a54 100644 --- a/pandas/io/json/_json.py +++ b/pandas/io/json/_json.py @@ -1,3 +1,4 @@ +from abc import abstractmethod, ABC from collections import abc import functools from io import BytesIO, StringIO @@ -110,7 +111,7 @@ def to_json( path_or_buf.close() -class Writer: +class Writer(ABC): def __init__( self, obj, @@ -147,7 +148,7 @@ def _format_axes(self): def write(self): iso_dates = self.date_format == "iso" return dumps( - self.obj, + self.obj_to_write, orient=self.orient, double_precision=self.double_precision, ensure_ascii=self.ensure_ascii, @@ -157,35 +158,21 @@ def write(self): indent=self.indent, ) + @property + @abstractmethod + def obj_to_write(self): + """Object to write in JSON format.""" + class SeriesWriter(Writer): _default_orient = "index" - def __init__( - self, - obj, - orient: Optional[str], - date_format: str, - double_precision: int, - ensure_ascii: bool, - date_unit: str, - index: bool, - default_handler: Optional[Callable[[Any], JSONSerializable]] = None, - indent: int = 0, - ): - super().__init__( - obj, - orient, - date_format, - double_precision, - ensure_ascii, - date_unit, - index, - default_handler=default_handler, - indent=indent, - ) - if not index and orient == "split": - self.obj = {"name": obj.name, "data": obj.values} + @property + def obj_to_write(self): + if not self.index and self.orient == "split": + return {"name": self.obj.name, "data": self.obj.values} + else: + return self.obj def _format_axes(self): if not self.obj.index.is_unique and self.orient == "index": @@ -195,32 +182,14 @@ def _format_axes(self): class FrameWriter(Writer): _default_orient = "columns" - def __init__( - self, - obj, - orient: Optional[str], - date_format: str, - double_precision: int, - ensure_ascii: bool, - date_unit: str, - index: bool, - default_handler: Optional[Callable[[Any], JSONSerializable]] = None, - indent: int = 0, - ): - super().__init__( - obj, - orient, - date_format, - double_precision, - ensure_ascii, - date_unit, - index, - default_handler=default_handler, - indent=indent, - ) - if not index and orient == "split": - self.obj = obj.to_dict(orient="split") - del self.obj["index"] + @property + def obj_to_write(self): + if not self.index and self.orient == "split": + obj_to_write = self.obj.to_dict(orient="split") + del obj_to_write["index"] + else: + obj_to_write = self.obj + return obj_to_write def _format_axes(self): """ @@ -313,7 +282,9 @@ def __init__( self.orient = "records" self.index = index - self.obj = {"schema": self.schema, "data": self.obj} + @property + def obj_to_write(self): + return {"schema": self.schema, "data": self.obj} @deprecate_kwarg(old_arg_name="numpy", new_arg_name=None) From efd6134ad2ed2d5ea57630c1c2c54a3a95f73e14 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Thu, 10 Sep 2020 12:34:08 +0700 Subject: [PATCH 3/5] FIX: import order --- pandas/io/json/_json.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/io/json/_json.py b/pandas/io/json/_json.py index a573d5bfb8a54..1923fa3bb9ba5 100644 --- a/pandas/io/json/_json.py +++ b/pandas/io/json/_json.py @@ -1,4 +1,4 @@ -from abc import abstractmethod, ABC +from abc import ABC, abstractmethod from collections import abc import functools from io import BytesIO, StringIO From 20b9b5b9db607d2fd5e33ead37b1f4342a7d9508 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Fri, 11 Sep 2020 11:24:28 +0700 Subject: [PATCH 4/5] TYP: add annotation to obj_to_write --- pandas/io/json/_json.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pandas/io/json/_json.py b/pandas/io/json/_json.py index 1923fa3bb9ba5..14e4e732b940b 100644 --- a/pandas/io/json/_json.py +++ b/pandas/io/json/_json.py @@ -4,7 +4,7 @@ from io import BytesIO, StringIO from itertools import islice import os -from typing import IO, Any, Callable, List, Optional, Type +from typing import IO, Any, Callable, Dict, List, Optional, Type, Union import numpy as np @@ -18,6 +18,7 @@ from pandas import DataFrame, MultiIndex, Series, isna, to_datetime from pandas.core.construction import create_series_with_explicit_dtype +from pandas.core.generic import NDFrame from pandas.core.reshape.concat import concat from pandas.io.common import get_compression_method, get_filepath_or_buffer, get_handle @@ -34,7 +35,7 @@ # interface to/from def to_json( path_or_buf, - obj, + obj: NDFrame, orient: Optional[str] = None, date_format: str = "epoch", double_precision: int = 10, @@ -160,7 +161,7 @@ def write(self): @property @abstractmethod - def obj_to_write(self): + def obj_to_write(self) -> Union[NDFrame, Dict[str, Any]]: """Object to write in JSON format.""" @@ -168,7 +169,7 @@ class SeriesWriter(Writer): _default_orient = "index" @property - def obj_to_write(self): + def obj_to_write(self) -> Union[NDFrame, Dict[str, Any]]: if not self.index and self.orient == "split": return {"name": self.obj.name, "data": self.obj.values} else: @@ -183,7 +184,7 @@ class FrameWriter(Writer): _default_orient = "columns" @property - def obj_to_write(self): + def obj_to_write(self) -> Union[NDFrame, Dict[str, Any]]: if not self.index and self.orient == "split": obj_to_write = self.obj.to_dict(orient="split") del obj_to_write["index"] @@ -283,7 +284,7 @@ def __init__( self.index = index @property - def obj_to_write(self): + def obj_to_write(self) -> Union[NDFrame, Dict[str, Any]]: return {"schema": self.schema, "data": self.obj} From 795c4ac0ab7b392a845630069d90c2baa0604bd6 Mon Sep 17 00:00:00 2001 From: Maxim Ivanov Date: Thu, 8 Oct 2020 13:10:32 +0700 Subject: [PATCH 5/5] TYP: fix for obj_to_write --- pandas/io/json/_json.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/pandas/io/json/_json.py b/pandas/io/json/_json.py index f67d75b1160c1..a72901d56a9a8 100644 --- a/pandas/io/json/_json.py +++ b/pandas/io/json/_json.py @@ -4,13 +4,18 @@ from io import BytesIO, StringIO from itertools import islice import os -from typing import IO, Any, Callable, Dict, List, Optional, Type, Union +from typing import IO, Any, Callable, List, Mapping, Optional, Type, Union import numpy as np import pandas._libs.json as json from pandas._libs.tslibs import iNaT -from pandas._typing import CompressionOptions, JSONSerializable, StorageOptions +from pandas._typing import ( + CompressionOptions, + IndexLabel, + JSONSerializable, + StorageOptions, +) from pandas.errors import AbstractMethodError from pandas.util._decorators import deprecate_kwarg, deprecate_nonkeyword_arguments @@ -161,15 +166,16 @@ def write(self): @property @abstractmethod - def obj_to_write(self) -> Union[NDFrame, Dict[str, Any]]: + def obj_to_write(self) -> Union[NDFrame, Mapping[IndexLabel, Any]]: """Object to write in JSON format.""" + pass class SeriesWriter(Writer): _default_orient = "index" @property - def obj_to_write(self) -> Union[NDFrame, Dict[str, Any]]: + def obj_to_write(self) -> Union[NDFrame, Mapping[IndexLabel, Any]]: if not self.index and self.orient == "split": return {"name": self.obj.name, "data": self.obj.values} else: @@ -184,7 +190,7 @@ class FrameWriter(Writer): _default_orient = "columns" @property - def obj_to_write(self) -> Union[NDFrame, Dict[str, Any]]: + def obj_to_write(self) -> Union[NDFrame, Mapping[IndexLabel, Any]]: if not self.index and self.orient == "split": obj_to_write = self.obj.to_dict(orient="split") del obj_to_write["index"] @@ -284,7 +290,7 @@ def __init__( self.index = index @property - def obj_to_write(self) -> Union[NDFrame, Dict[str, Any]]: + def obj_to_write(self) -> Union[NDFrame, Mapping[IndexLabel, Any]]: return {"schema": self.schema, "data": self.obj}