Skip to content

Commit ded5c1e

Browse files
committed
disambiguate explicit name none versus no name
1 parent 171f3ec commit ded5c1e

File tree

1 file changed

+28
-18
lines changed

1 file changed

+28
-18
lines changed

bigframes/operations/base.py

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414

1515
from __future__ import annotations
1616

17+
import enum
1718
import typing
18-
from typing import Any, List, Sequence, Union
19+
from typing import List, Sequence, Union
1920

2021
import bigframes_vendored.constants as constants
2122
import bigframes_vendored.pandas.pandas._typing as vendored_pandas_typing
@@ -34,7 +35,17 @@
3435
import bigframes.series as series
3536
import bigframes.session
3637

37-
_NO_NAME_SENTINEL = object()
38+
39+
class Default(enum.Enum):
40+
"""Sentinel that can disambiguate explicit None from missing.
41+
42+
See https://stackoverflow.com/a/76606310/101923
43+
"""
44+
45+
token = 0
46+
47+
48+
DEFAULT = Default.token
3849

3950

4051
class SeriesMethods:
@@ -45,7 +56,7 @@ def __init__(
4556
dtype: typing.Optional[
4657
bigframes.dtypes.DtypeString | bigframes.dtypes.Dtype
4758
] = None,
48-
name: str | None = None,
59+
name: str | None | Default = DEFAULT,
4960
copy: typing.Optional[bool] = None,
5061
*,
5162
session: typing.Optional[bigframes.session.Session] = None,
@@ -73,6 +84,16 @@ def __init__(
7384
f"Series constructor only supports copy=True. {constants.FEEDBACK_LINK}"
7485
)
7586

87+
if name is DEFAULT:
88+
if isinstance(data, blocks.Block):
89+
name = data.column_labels[0]
90+
elif hasattr(data, "name"):
91+
name = getattr(data, "name")
92+
elif hasattr(data, "_name"):
93+
name = getattr(data, "_name")
94+
else:
95+
name = None
96+
7697
if isinstance(data, blocks.Block):
7798
block = data
7899
elif isinstance(data, SeriesMethods):
@@ -109,6 +130,7 @@ def __init__(
109130
block = data_block
110131

111132
if block:
133+
# Data was a bigframes object.
112134
assert len(block.value_columns) == 1
113135
assert len(block.column_labels) == 1
114136
if index is not None: # reindexing operation
@@ -121,6 +143,7 @@ def __init__(
121143
bf_dtype = bigframes.dtypes.bigframes_type(dtype)
122144
block = block.multi_apply_unary_op(ops.AsTypeOp(to_type=bf_dtype))
123145
else:
146+
# Data was local.
124147
if isinstance(dtype, str) and dtype.lower() == "json":
125148
dtype = bigframes.dtypes.JSON_DTYPE
126149
pd_series = pd.Series(
@@ -129,25 +152,12 @@ def __init__(
129152
dtype=dtype, # type:ignore
130153
name=name,
131154
)
155+
name = pd_series.name # type: ignore
132156
block = read_pandas_func(pd_series)._get_block() # type:ignore
133157

134158
assert block is not None
135159

136-
# If we didn't get a block make sure the name is what the user
137-
# explicitly chose even if it is None. This is important for the
138-
# polars backend where the implicit column labels are integers.
139-
if name:
140-
default_name: Any = name
141-
elif hasattr(data, "name"):
142-
default_name = getattr(data, "name", None)
143-
elif hasattr(data, "_name"):
144-
default_name = getattr(data, "_name", None)
145-
else:
146-
default_name = _NO_NAME_SENTINEL
147-
148-
if default_name is not _NO_NAME_SENTINEL:
149-
block = block.with_column_labels([default_name])
150-
160+
block = block.with_column_labels([name])
151161
self._block: blocks.Block = block
152162

153163
@property

0 commit comments

Comments
 (0)