tdrpa.tdworker 1.1.9.3__py38-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tdrpa/_tdxlwings/__init__.py +193 -0
- tdrpa/_tdxlwings/__pycache__/__init__.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/__init__.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/apps.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/apps.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/base_classes.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/base_classes.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/com_server.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/com_server.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/constants.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/constants.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/expansion.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/expansion.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/main.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/main.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/udfs.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/udfs.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/utils.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/utils.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/_win32patch.py +90 -0
- tdrpa/_tdxlwings/_xlmac.py +2240 -0
- tdrpa/_tdxlwings/_xlwindows.py +2518 -0
- tdrpa/_tdxlwings/addin/Dictionary.cls +474 -0
- tdrpa/_tdxlwings/addin/IWebAuthenticator.cls +71 -0
- tdrpa/_tdxlwings/addin/WebClient.cls +772 -0
- tdrpa/_tdxlwings/addin/WebHelpers.bas +3203 -0
- tdrpa/_tdxlwings/addin/WebRequest.cls +875 -0
- tdrpa/_tdxlwings/addin/WebResponse.cls +453 -0
- tdrpa/_tdxlwings/addin/xlwings.xlam +0 -0
- tdrpa/_tdxlwings/apps.py +35 -0
- tdrpa/_tdxlwings/base_classes.py +1092 -0
- tdrpa/_tdxlwings/cli.py +1306 -0
- tdrpa/_tdxlwings/com_server.py +385 -0
- tdrpa/_tdxlwings/constants.py +3080 -0
- tdrpa/_tdxlwings/conversion/__init__.py +103 -0
- tdrpa/_tdxlwings/conversion/framework.py +147 -0
- tdrpa/_tdxlwings/conversion/numpy_conv.py +34 -0
- tdrpa/_tdxlwings/conversion/pandas_conv.py +184 -0
- tdrpa/_tdxlwings/conversion/standard.py +321 -0
- tdrpa/_tdxlwings/expansion.py +83 -0
- tdrpa/_tdxlwings/ext/__init__.py +3 -0
- tdrpa/_tdxlwings/ext/sql.py +73 -0
- tdrpa/_tdxlwings/html/xlwings-alert.html +71 -0
- tdrpa/_tdxlwings/js/xlwings.js +577 -0
- tdrpa/_tdxlwings/js/xlwings.ts +729 -0
- tdrpa/_tdxlwings/mac_dict.py +6399 -0
- tdrpa/_tdxlwings/main.py +5205 -0
- tdrpa/_tdxlwings/mistune/__init__.py +63 -0
- tdrpa/_tdxlwings/mistune/block_parser.py +366 -0
- tdrpa/_tdxlwings/mistune/inline_parser.py +216 -0
- tdrpa/_tdxlwings/mistune/markdown.py +84 -0
- tdrpa/_tdxlwings/mistune/renderers.py +220 -0
- tdrpa/_tdxlwings/mistune/scanner.py +121 -0
- tdrpa/_tdxlwings/mistune/util.py +41 -0
- tdrpa/_tdxlwings/pro/__init__.py +40 -0
- tdrpa/_tdxlwings/pro/_xlcalamine.py +536 -0
- tdrpa/_tdxlwings/pro/_xlofficejs.py +146 -0
- tdrpa/_tdxlwings/pro/_xlremote.py +1293 -0
- tdrpa/_tdxlwings/pro/custom_functions_code.js +150 -0
- tdrpa/_tdxlwings/pro/embedded_code.py +60 -0
- tdrpa/_tdxlwings/pro/udfs_officejs.py +549 -0
- tdrpa/_tdxlwings/pro/utils.py +199 -0
- tdrpa/_tdxlwings/quickstart.xlsm +0 -0
- tdrpa/_tdxlwings/quickstart_addin.xlam +0 -0
- tdrpa/_tdxlwings/quickstart_addin_ribbon.xlam +0 -0
- tdrpa/_tdxlwings/quickstart_fastapi/main.py +47 -0
- tdrpa/_tdxlwings/quickstart_fastapi/requirements.txt +3 -0
- tdrpa/_tdxlwings/quickstart_standalone.xlsm +0 -0
- tdrpa/_tdxlwings/reports.py +12 -0
- tdrpa/_tdxlwings/rest/__init__.py +1 -0
- tdrpa/_tdxlwings/rest/api.py +368 -0
- tdrpa/_tdxlwings/rest/serializers.py +103 -0
- tdrpa/_tdxlwings/server.py +14 -0
- tdrpa/_tdxlwings/udfs.py +775 -0
- tdrpa/_tdxlwings/utils.py +777 -0
- tdrpa/_tdxlwings/xlwings-0.31.6.applescript +30 -0
- tdrpa/_tdxlwings/xlwings.bas +2061 -0
- tdrpa/_tdxlwings/xlwings_custom_addin.bas +2042 -0
- tdrpa/_tdxlwings/xlwingslib.cp38-win_amd64.pyd +0 -0
- tdrpa/tdworker/__init__.pyi +8 -0
- tdrpa/tdworker/_excel.pyi +703 -0
- tdrpa/tdworker/_img.pyi +173 -0
- tdrpa/tdworker/_os.pyi +46 -0
- tdrpa/tdworker/_w.pyi +129 -0
- tdrpa/tdworker/_web.pyi +248 -0
- tdrpa/tdworker/_winE.pyi +246 -0
- tdrpa/tdworker/_winK.pyi +74 -0
- tdrpa/tdworker/_winM.pyi +117 -0
- tdrpa/tdworker.cp38-win_amd64.pyd +0 -0
- tdrpa.tdworker-1.1.9.3.dist-info/METADATA +25 -0
- tdrpa.tdworker-1.1.9.3.dist-info/RECORD +97 -0
- tdrpa.tdworker-1.1.9.3.dist-info/WHEEL +5 -0
- tdrpa.tdworker-1.1.9.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
try:
|
2
|
+
import pandas as pd
|
3
|
+
except ImportError:
|
4
|
+
pd = None
|
5
|
+
try:
|
6
|
+
import numpy as np
|
7
|
+
except ImportError:
|
8
|
+
np = None
|
9
|
+
|
10
|
+
from .framework import (
|
11
|
+
Accessor,
|
12
|
+
ConversionContext,
|
13
|
+
Converter,
|
14
|
+
Options,
|
15
|
+
Pipeline,
|
16
|
+
accessors,
|
17
|
+
)
|
18
|
+
from .standard import (
|
19
|
+
AdjustDimensionsStage,
|
20
|
+
CleanDataForWriteStage,
|
21
|
+
CleanDataFromReadStage,
|
22
|
+
DictConverter,
|
23
|
+
Ensure2DStage,
|
24
|
+
ExpandRangeStage,
|
25
|
+
RangeAccessor,
|
26
|
+
RawValueAccessor,
|
27
|
+
ReadValueFromRangeStage,
|
28
|
+
TransposeStage,
|
29
|
+
ValueAccessor,
|
30
|
+
WriteValueToRangeStage,
|
31
|
+
)
|
32
|
+
|
33
|
+
if np:
|
34
|
+
from .numpy_conv import NumpyArrayConverter
|
35
|
+
if pd:
|
36
|
+
from .pandas_conv import PandasDataFrameConverter, PandasSeriesConverter
|
37
|
+
|
38
|
+
from .. import LicenseError
|
39
|
+
|
40
|
+
try:
|
41
|
+
from ..pro.reports.markdown import Markdown, MarkdownConverter
|
42
|
+
|
43
|
+
MarkdownConverter.register(Markdown)
|
44
|
+
except (ImportError, LicenseError, AttributeError):
|
45
|
+
pass
|
46
|
+
|
47
|
+
|
48
|
+
__all__ = (
|
49
|
+
"Accessor",
|
50
|
+
"ConversionContext",
|
51
|
+
"Converter",
|
52
|
+
"Options",
|
53
|
+
"Pipeline",
|
54
|
+
"accessors",
|
55
|
+
"AdjustDimensionsStage",
|
56
|
+
"CleanDataForWriteStage",
|
57
|
+
"CleanDataFromReadStage",
|
58
|
+
"DictConverter",
|
59
|
+
"Ensure2DStage",
|
60
|
+
"ExpandRangeStage",
|
61
|
+
"RangeAccessor",
|
62
|
+
"RawValueAccessor",
|
63
|
+
"ReadValueFromRangeStage",
|
64
|
+
"TransposeStage",
|
65
|
+
"ValueAccessor",
|
66
|
+
"WriteValueToRangeStage",
|
67
|
+
"NumpyArrayConverter",
|
68
|
+
"PandasDataFrameConverter",
|
69
|
+
"PandasSeriesConverter",
|
70
|
+
)
|
71
|
+
|
72
|
+
|
73
|
+
def read(rng, value, options, engine_name=None):
|
74
|
+
convert = options.get("convert", None)
|
75
|
+
pipeline = accessors.get(convert, convert).reader(options)
|
76
|
+
ctx = ConversionContext(rng=rng, value=value, engine_name=engine_name)
|
77
|
+
pipeline(ctx)
|
78
|
+
return ctx.value
|
79
|
+
|
80
|
+
|
81
|
+
def write(value, rng, options, engine_name=None):
|
82
|
+
# Don't allow to write lists and tuples as jagged arrays as appscript and pywin32
|
83
|
+
# don't handle that properly. This should really be handled in Ensure2DStage, but
|
84
|
+
# we'd have to set the original format in the conversion ctx meta as the check
|
85
|
+
# should only run for list and tuples.
|
86
|
+
if (
|
87
|
+
isinstance(value, (list, tuple))
|
88
|
+
and len(value) > 0
|
89
|
+
and isinstance(value[0], (list, tuple))
|
90
|
+
):
|
91
|
+
first_row = value[0]
|
92
|
+
for row in value:
|
93
|
+
if len(first_row) != len(row):
|
94
|
+
raise Exception(
|
95
|
+
"All elements of a 2d list or tuple must be of the same length"
|
96
|
+
)
|
97
|
+
convert = options.get("convert", None)
|
98
|
+
pipeline = (
|
99
|
+
accessors.get(convert, convert).router(value, rng, options).writer(options)
|
100
|
+
)
|
101
|
+
ctx = ConversionContext(rng=rng, value=value, engine_name=engine_name)
|
102
|
+
pipeline(ctx)
|
103
|
+
return ctx.value
|
@@ -0,0 +1,147 @@
|
|
1
|
+
import tdrpa._tdxlwings as xlwings
|
2
|
+
|
3
|
+
class ConversionContext:
|
4
|
+
__slots__ = ["range", "value", "source_value", "meta", "engine"]
|
5
|
+
|
6
|
+
def __init__(self, rng=None, value=None, engine_name=None):
|
7
|
+
self.range = rng
|
8
|
+
if engine_name:
|
9
|
+
self.engine = xlwings.engines[engine_name]
|
10
|
+
else:
|
11
|
+
# rng can only be None if used via COM server UDFs
|
12
|
+
self.engine = rng.sheet.book.app.engine if rng else xlwings.engines["excel"]
|
13
|
+
self.value = value
|
14
|
+
# used for markdown (could be replaced by handing the parsed ast from
|
15
|
+
# the converter stage to the formatting stage
|
16
|
+
self.source_value = value
|
17
|
+
self.meta = {}
|
18
|
+
|
19
|
+
|
20
|
+
class Options(dict):
|
21
|
+
def __init__(self, original):
|
22
|
+
super(Options, self).__init__(original)
|
23
|
+
|
24
|
+
def override(self, **overrides):
|
25
|
+
self.update(overrides)
|
26
|
+
return self
|
27
|
+
|
28
|
+
def erase(self, keys):
|
29
|
+
for key in keys:
|
30
|
+
self.pop(key, None)
|
31
|
+
return self
|
32
|
+
|
33
|
+
def defaults(self, **defaults):
|
34
|
+
for k, v in defaults.items():
|
35
|
+
self.setdefault(k, v)
|
36
|
+
return self
|
37
|
+
|
38
|
+
|
39
|
+
class Pipeline(list):
|
40
|
+
def prepend_stage(self, stage, only_if=True):
|
41
|
+
if only_if:
|
42
|
+
self.insert(0, stage)
|
43
|
+
return self
|
44
|
+
|
45
|
+
def append_stage(self, stage, only_if=True):
|
46
|
+
if only_if:
|
47
|
+
self.append(stage)
|
48
|
+
return self
|
49
|
+
|
50
|
+
def insert_stage(
|
51
|
+
self, stage, index=None, after=None, before=None, replace=None, only_if=True
|
52
|
+
):
|
53
|
+
if only_if:
|
54
|
+
if sum(x is not None for x in (index, after, before, replace)) != 1:
|
55
|
+
raise ValueError(
|
56
|
+
"Must specify exactly one of arguments: "
|
57
|
+
"index, after, before, replace"
|
58
|
+
)
|
59
|
+
if index is not None:
|
60
|
+
indices = (index,)
|
61
|
+
elif after is not None:
|
62
|
+
indices = tuple(
|
63
|
+
i + 1 for i, x in enumerate(self) if isinstance(x, after)
|
64
|
+
)
|
65
|
+
elif before is not None:
|
66
|
+
indices = tuple(i for i, x in enumerate(self) if isinstance(x, before))
|
67
|
+
elif replace is not None:
|
68
|
+
for i, x in enumerate(self):
|
69
|
+
if isinstance(x, replace):
|
70
|
+
self[i] = stage
|
71
|
+
return self
|
72
|
+
for i in reversed(indices):
|
73
|
+
self.insert(i, stage)
|
74
|
+
return self
|
75
|
+
|
76
|
+
def __call__(self, *args, **kwargs):
|
77
|
+
for stage in self:
|
78
|
+
stage(*args, **kwargs)
|
79
|
+
|
80
|
+
|
81
|
+
accessors = {}
|
82
|
+
|
83
|
+
|
84
|
+
class Accessor:
|
85
|
+
@classmethod
|
86
|
+
def reader(cls, options):
|
87
|
+
return Pipeline()
|
88
|
+
|
89
|
+
@classmethod
|
90
|
+
def writer(cls, options):
|
91
|
+
return Pipeline()
|
92
|
+
|
93
|
+
@classmethod
|
94
|
+
def register(cls, *types):
|
95
|
+
for type in types:
|
96
|
+
accessors[type] = cls
|
97
|
+
|
98
|
+
@classmethod
|
99
|
+
def router(cls, value, rng, options):
|
100
|
+
return cls
|
101
|
+
|
102
|
+
|
103
|
+
class Converter(Accessor):
|
104
|
+
class ToValueStage:
|
105
|
+
def __init__(self, write_value, options):
|
106
|
+
self.write_value = write_value
|
107
|
+
self.options = options
|
108
|
+
|
109
|
+
def __call__(self, c):
|
110
|
+
c.value = self.write_value(c.value, self.options)
|
111
|
+
|
112
|
+
class FromValueStage:
|
113
|
+
def __init__(self, read_value, options):
|
114
|
+
self.read_value = read_value
|
115
|
+
self.options = options
|
116
|
+
|
117
|
+
def __call__(self, c):
|
118
|
+
c.value = self.read_value(c.value, self.options)
|
119
|
+
|
120
|
+
base_type = None
|
121
|
+
base = None
|
122
|
+
|
123
|
+
@classmethod
|
124
|
+
def base_reader(cls, options, base_type=None):
|
125
|
+
if cls.base is not None:
|
126
|
+
return cls.base.reader(options)
|
127
|
+
else:
|
128
|
+
return accessors[base_type or cls.base_type].reader(options)
|
129
|
+
|
130
|
+
@classmethod
|
131
|
+
def base_writer(cls, options, base_type=None):
|
132
|
+
if cls.base is not None:
|
133
|
+
return cls.base.writer(options)
|
134
|
+
else:
|
135
|
+
return accessors[base_type or cls.base_type].writer(options)
|
136
|
+
|
137
|
+
@classmethod
|
138
|
+
def reader(cls, options):
|
139
|
+
return cls.base_reader(options).append_stage(
|
140
|
+
cls.FromValueStage(cls.read_value, options)
|
141
|
+
)
|
142
|
+
|
143
|
+
@classmethod
|
144
|
+
def writer(cls, options):
|
145
|
+
return cls.base_writer(options).prepend_stage(
|
146
|
+
cls.ToValueStage(cls.write_value, options)
|
147
|
+
)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
try:
|
2
|
+
import numpy as np
|
3
|
+
except ImportError:
|
4
|
+
np = None
|
5
|
+
|
6
|
+
|
7
|
+
if np:
|
8
|
+
try:
|
9
|
+
import pandas as pd
|
10
|
+
except ImportError:
|
11
|
+
pd = None
|
12
|
+
|
13
|
+
from . import Converter, Options
|
14
|
+
|
15
|
+
class NumpyArrayConverter(Converter):
|
16
|
+
@classmethod
|
17
|
+
def base_reader(cls, options):
|
18
|
+
return super(NumpyArrayConverter, cls).base_reader(
|
19
|
+
Options(options).defaults(empty=np.nan)
|
20
|
+
)
|
21
|
+
|
22
|
+
@classmethod
|
23
|
+
def read_value(cls, value, options):
|
24
|
+
dtype = options.get("dtype", None)
|
25
|
+
copy = options.get("copy", True)
|
26
|
+
order = options.get("order", None)
|
27
|
+
ndim = options.get("ndim", None) or 0
|
28
|
+
return np.array(value, dtype=dtype, copy=copy, order=order, ndmin=ndim)
|
29
|
+
|
30
|
+
@classmethod
|
31
|
+
def write_value(cls, value, options):
|
32
|
+
return value.tolist()
|
33
|
+
|
34
|
+
NumpyArrayConverter.register(np.array, np.ndarray)
|
@@ -0,0 +1,184 @@
|
|
1
|
+
from ..utils import xlserial_to_datetime
|
2
|
+
|
3
|
+
try:
|
4
|
+
import pandas as pd
|
5
|
+
except ImportError:
|
6
|
+
pd = None
|
7
|
+
|
8
|
+
|
9
|
+
if pd:
|
10
|
+
from . import Converter, Options
|
11
|
+
|
12
|
+
def _parse_dates(df, parse_dates):
|
13
|
+
# Office.js UDFs don't have the info whether the cell is in date format
|
14
|
+
if parse_dates is True:
|
15
|
+
parse_dates = [0]
|
16
|
+
elif not isinstance(parse_dates, list):
|
17
|
+
parse_dates = [parse_dates]
|
18
|
+
for col in parse_dates:
|
19
|
+
if isinstance(col, str):
|
20
|
+
df.loc[:, col] = df.loc[:, col].apply(xlserial_to_datetime)
|
21
|
+
else:
|
22
|
+
df.iloc[:, col] = df.iloc[:, col].apply(xlserial_to_datetime)
|
23
|
+
return df
|
24
|
+
|
25
|
+
def write_value(cls, value, options):
|
26
|
+
index = options.get("index", True)
|
27
|
+
header = options.get("header", True)
|
28
|
+
assign_empty_index_names = options.get("assign_empty_index_names", False)
|
29
|
+
|
30
|
+
index_names = value.index.names
|
31
|
+
if assign_empty_index_names:
|
32
|
+
# Useful when you want to have your DataFrame formatted as an Excel table
|
33
|
+
# which requires column header names. Since Excel tables only allow an empty
|
34
|
+
# space once, we'll generate multiple empty spaces for each column.
|
35
|
+
index_names = [
|
36
|
+
" " * (i + 1) if name is None else name
|
37
|
+
for i, name in enumerate(index_names)
|
38
|
+
]
|
39
|
+
else:
|
40
|
+
index_names = ["" if name is None else name for name in index_names]
|
41
|
+
index_levels = len(index_names)
|
42
|
+
|
43
|
+
if index:
|
44
|
+
if value.index.name in value.columns:
|
45
|
+
# Prevents column name collision when resetting the index
|
46
|
+
value.index = value.index.rename(None)
|
47
|
+
value = value.reset_index()
|
48
|
+
|
49
|
+
# Convert pandas-specific types without corresponding Excel type to strings
|
50
|
+
for ix, col in enumerate(value.columns):
|
51
|
+
if (
|
52
|
+
isinstance(value.iloc[:, ix].dtype, pd.PeriodDtype)
|
53
|
+
or value.iloc[:, ix].dtype == "timedelta64[ns]"
|
54
|
+
):
|
55
|
+
value.iloc[:, ix] = value.iloc[:, ix].astype(str)
|
56
|
+
|
57
|
+
if header:
|
58
|
+
if isinstance(value.columns, pd.MultiIndex):
|
59
|
+
columns = list(zip(*value.columns.tolist()))
|
60
|
+
columns = [list(i) for i in columns]
|
61
|
+
# Move index names right above the index
|
62
|
+
if index:
|
63
|
+
for c in columns[:-1]:
|
64
|
+
c[:index_levels] = [""] * index_levels
|
65
|
+
columns[-1][:index_levels] = index_names
|
66
|
+
else:
|
67
|
+
columns = [value.columns.tolist()]
|
68
|
+
if index:
|
69
|
+
columns[0][:index_levels] = index_names
|
70
|
+
value = columns + value.values.tolist()
|
71
|
+
else:
|
72
|
+
value = value.values.tolist()
|
73
|
+
|
74
|
+
return value
|
75
|
+
|
76
|
+
class PandasDataFrameConverter(Converter):
|
77
|
+
@classmethod
|
78
|
+
def base_reader(cls, options):
|
79
|
+
return super(PandasDataFrameConverter, cls).base_reader(
|
80
|
+
Options(options).override(ndim=2)
|
81
|
+
)
|
82
|
+
|
83
|
+
@classmethod
|
84
|
+
def read_value(cls, value, options):
|
85
|
+
index = options.get("index", 1)
|
86
|
+
header = options.get("header", 1)
|
87
|
+
dtype = options.get("dtype", None)
|
88
|
+
copy = options.get("copy", False)
|
89
|
+
parse_dates = options.get("parse_dates", None)
|
90
|
+
|
91
|
+
# build dataframe with only columns (no index) but correct header
|
92
|
+
if header == 1:
|
93
|
+
columns = pd.Index(value[0])
|
94
|
+
elif header > 1:
|
95
|
+
columns = pd.MultiIndex.from_arrays(value[:header])
|
96
|
+
else:
|
97
|
+
columns = None
|
98
|
+
|
99
|
+
df = pd.DataFrame(value[header:], columns=columns, dtype=dtype, copy=copy)
|
100
|
+
|
101
|
+
if parse_dates:
|
102
|
+
df = _parse_dates(df, parse_dates)
|
103
|
+
|
104
|
+
# handle index by resetting the index to the index first columns
|
105
|
+
# and renaming the index according to the name in the last row
|
106
|
+
if index > 0:
|
107
|
+
# rename uniquely the index columns to some never used name for column
|
108
|
+
# we do not use the column name directly as it would cause issues if
|
109
|
+
# several columns have the same name
|
110
|
+
df.columns = pd.Index(range(len(df.columns)))
|
111
|
+
df = df.set_index(list(df.columns)[:index])
|
112
|
+
|
113
|
+
df.index.names = pd.Index(
|
114
|
+
value[header - 1][:index] if header else [None] * index
|
115
|
+
)
|
116
|
+
|
117
|
+
if header:
|
118
|
+
df.columns = columns[index:]
|
119
|
+
else:
|
120
|
+
df.columns = pd.Index(range(len(df.columns)))
|
121
|
+
|
122
|
+
return df
|
123
|
+
|
124
|
+
@classmethod
|
125
|
+
def write_value(cls, value, options):
|
126
|
+
return write_value(cls, value, options)
|
127
|
+
|
128
|
+
PandasDataFrameConverter.register(pd.DataFrame, "df")
|
129
|
+
|
130
|
+
class PandasSeriesConverter(Converter):
|
131
|
+
@classmethod
|
132
|
+
def read_value(cls, value, options):
|
133
|
+
index = options.get("index", 1)
|
134
|
+
header = options.get("header", True)
|
135
|
+
dtype = options.get("dtype", None)
|
136
|
+
copy = options.get("copy", False)
|
137
|
+
parse_dates = options.get("parse_dates", None)
|
138
|
+
|
139
|
+
if header:
|
140
|
+
columns = value[0]
|
141
|
+
if not isinstance(columns, list):
|
142
|
+
columns = [columns]
|
143
|
+
data = value[1:]
|
144
|
+
else:
|
145
|
+
columns = None
|
146
|
+
data = value
|
147
|
+
|
148
|
+
df = pd.DataFrame(data, columns=columns, dtype=dtype, copy=copy)
|
149
|
+
|
150
|
+
if parse_dates:
|
151
|
+
df = _parse_dates(df, parse_dates)
|
152
|
+
|
153
|
+
if index:
|
154
|
+
df.columns = pd.Index(range(len(df.columns)))
|
155
|
+
df = df.set_index(list(df.columns)[:index])
|
156
|
+
df.index.names = pd.Index(
|
157
|
+
value[header - 1][:index] if header else [None] * index
|
158
|
+
)
|
159
|
+
|
160
|
+
if header:
|
161
|
+
df.columns = columns[index:]
|
162
|
+
else:
|
163
|
+
df.columns = pd.Index(range(len(df.columns)))
|
164
|
+
|
165
|
+
series = df.squeeze()
|
166
|
+
|
167
|
+
if not header:
|
168
|
+
series.name = None
|
169
|
+
series.index.name = None
|
170
|
+
|
171
|
+
return series
|
172
|
+
|
173
|
+
@classmethod
|
174
|
+
def write_value(cls, value, options):
|
175
|
+
if all(v is None for v in value.index.names) and value.name is None:
|
176
|
+
default_header = False
|
177
|
+
else:
|
178
|
+
default_header = True
|
179
|
+
|
180
|
+
options["header"] = options.get("header", default_header)
|
181
|
+
values = write_value(cls, value.to_frame(), options)
|
182
|
+
return values
|
183
|
+
|
184
|
+
PandasSeriesConverter.register(pd.Series)
|