-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
REF: eliminate method _write() in json writers #36218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fdbed7b
1b89aba
efd6134
20b9b5b
6b70c0c
9bb9be2
e1fa7df
23afd99
795c4ac
48bb36f
f2e3a3b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,29 @@ | ||
from abc import ABC, abstractmethod | ||
from collections import abc | ||
import functools | ||
from io import BytesIO, StringIO | ||
from itertools import islice | ||
import os | ||
from typing import IO, Any, Callable, List, Optional, Tuple, Type | ||
from typing import IO, Any, Callable, List, Mapping, Optional, Tuple, 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 | ||
|
||
from pandas.core.dtypes.common import ensure_str, is_period_dtype | ||
|
||
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 | ||
|
@@ -33,7 +40,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, | ||
|
@@ -110,7 +117,7 @@ def to_json( | |
path_or_buf.close() | ||
|
||
|
||
class Writer: | ||
class Writer(ABC): | ||
_default_orient: str | ||
|
||
def __init__( | ||
|
@@ -146,75 +153,52 @@ def _format_axes(self): | |
raise AbstractMethodError(self) | ||
|
||
def write(self): | ||
return self._write( | ||
self.obj, | ||
self.orient, | ||
self.double_precision, | ||
self.ensure_ascii, | ||
self.date_unit, | ||
self.date_format == "iso", | ||
self.default_handler, | ||
self.indent, | ||
) | ||
|
||
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, | ||
): | ||
iso_dates = self.date_format == "iso" | ||
return dumps( | ||
obj, | ||
orient=orient, | ||
double_precision=double_precision, | ||
ensure_ascii=ensure_ascii, | ||
date_unit=date_unit, | ||
self.obj_to_write, | ||
orient=self.orient, | ||
double_precision=self.double_precision, | ||
ensure_ascii=self.ensure_ascii, | ||
date_unit=self.date_unit, | ||
iso_dates=iso_dates, | ||
default_handler=default_handler, | ||
indent=indent, | ||
default_handler=self.default_handler, | ||
indent=self.indent, | ||
) | ||
|
||
@property | ||
@abstractmethod | ||
def obj_to_write(self) -> Union[NDFrame, Mapping[IndexLabel, Any]]: | ||
"""Object to write in JSON format.""" | ||
pass | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you explicitly are the keys in the Dict necessarily str, or can they be any Index entries? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh yes, actually the keys in the dictionary can be of |
||
|
||
class SeriesWriter(Writer): | ||
_default_orient = "index" | ||
|
||
@property | ||
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: | ||
return self.obj | ||
|
||
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( | ||
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 = {"name": obj.name, "data": obj.values} | ||
return super()._write( | ||
obj, | ||
orient, | ||
double_precision, | ||
ensure_ascii, | ||
date_unit, | ||
iso_dates, | ||
default_handler, | ||
indent, | ||
) | ||
|
||
|
||
class FrameWriter(Writer): | ||
_default_orient = "columns" | ||
|
||
@property | ||
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"] | ||
else: | ||
obj_to_write = self.obj | ||
return obj_to_write | ||
|
||
def _format_axes(self): | ||
""" | ||
Try to format axes if they are datelike. | ||
|
@@ -232,31 +216,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" | ||
|
@@ -331,30 +290,9 @@ 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 | ||
@property | ||
def obj_to_write(self) -> Union[NDFrame, Mapping[IndexLabel, Any]]: | ||
return {"schema": self.schema, "data": self.obj} | ||
|
||
|
||
@deprecate_kwarg(old_arg_name="numpy", new_arg_name=None) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be FrameOrSeries?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with
FrameOrSeries
is that it does not allow changing the type of return value.Inside the function
to_json
there is a statement, which changes object from series to frame, which is not allowed.mypy error:
I tried to use
FrameOrSeriesUnion
, which allows changing type from series to frame, but I get another mypy error.Apparently for
NDFrame
onlyFrameOrSeries
is a correct casting.So, I have no clue how to deal with typing here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@WillAyd i expected FrameOrSeriesUnion would work for this, am i missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ivanovmg can you merge master and update the error message here? I don't think that line number is reflective of the latest code base
I think the error message is stemming from a mixture of using a Union and a TypeVar (the latter being somewhere in generic). Ideally should be cleaned up but I don't think needs to hold up this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we go.
I merged master, then modified
pandas/core/generic.py
.line 2164:
And replaced
NDFrame
withFrameOrSeriesUnion
in_json.py
.The error would be:
However, if I do not touch
generic.py
, then the following error with be thrown.