Skip to content

Commit a7877ae

Browse files
refactor: Decorator to take docs rather than inheritance
1 parent ca9fb13 commit a7877ae

File tree

16 files changed

+94
-217
lines changed

16 files changed

+94
-217
lines changed

bigframes/_tools/docs.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
def inherit_docs(source_class):
17+
"""
18+
A class decorator that copies docstrings from source_class to the
19+
decorated class for any methods or attributes that match names.
20+
"""
21+
22+
def decorator(target_class):
23+
# 1. Steal the main class docstring if the target doesn't have one
24+
if not target_class.__doc__ and source_class.__doc__:
25+
target_class.__doc__ = source_class.__doc__
26+
27+
# 2. Iterate over all attributes in the source class
28+
for name, source_item in vars(source_class).items():
29+
# Check if the target class has the same attribute
30+
if name in vars(target_class):
31+
target_item = getattr(target_class, name)
32+
33+
# Only copy if the target doesn't have a docstring
34+
# and the source does
35+
if hasattr(target_item, "__doc__") and not target_item.__doc__:
36+
if hasattr(source_item, "__doc__") and source_item.__doc__:
37+
try:
38+
# Use functools.update_wrapper or manual assignment
39+
# for methods, properties, and static methods
40+
target_item.__doc__ = source_item.__doc__
41+
except AttributeError:
42+
# Read-only attributes or certain built-ins
43+
# might skip docstring assignment
44+
pass
45+
46+
return target_class
47+
48+
return decorator

bigframes/core/groupby/dataframe_group_by.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import pandas as pd
2525

2626
from bigframes import session
27+
from bigframes._tools import docs
2728
from bigframes.core import agg_expressions
2829
from bigframes.core import expression as ex
2930
import bigframes.core.block_transforms as block_ops
@@ -44,9 +45,8 @@
4445

4546

4647
@log_adapter.class_logger
47-
class DataFrameGroupBy(vendored_pandas_groupby.DataFrameGroupBy):
48-
__doc__ = vendored_pandas_groupby.GroupBy.__doc__
49-
48+
@docs.inherit_docs(vendored_pandas_groupby.DataFrameGroupBy)
49+
class DataFrameGroupBy:
5050
def __init__(
5151
self,
5252
block: blocks.Block,

bigframes/core/groupby/series_group_by.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import pandas
2525

2626
from bigframes import session
27+
from bigframes._tools import docs
2728
from bigframes.core import expression as ex
2829
import bigframes.core.block_transforms as block_ops
2930
import bigframes.core.blocks as blocks
@@ -43,9 +44,8 @@
4344

4445

4546
@log_adapter.class_logger
47+
@docs.inherit_docs(vendored_pandas_groupby.SeriesGroupBy)
4648
class SeriesGroupBy(vendored_pandas_groupby.SeriesGroupBy):
47-
__doc__ = vendored_pandas_groupby.GroupBy.__doc__
48-
4949
def __init__(
5050
self,
5151
block: blocks.Block,

bigframes/core/indexes/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import pandas
2828

2929
from bigframes import dtypes
30+
from bigframes._tools import docs
3031
import bigframes.core.agg_expressions as ex_types
3132
import bigframes.core.block_transforms as block_ops
3233
import bigframes.core.blocks as blocks
@@ -47,8 +48,8 @@
4748
import bigframes.series
4849

4950

50-
class Index(vendored_pandas_index.Index):
51-
__doc__ = vendored_pandas_index.Index.__doc__
51+
@docs.inherit_docs(vendored_pandas_index.Index)
52+
class Index:
5253
_query_job = None
5354
_block: blocks.Block
5455
_linked_frame: Union[

bigframes/core/indexes/datetimes.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@
2020
datetimes as vendored_pandas_datetime_index,
2121
)
2222

23+
from bigframes._tools import docs
2324
from bigframes.core import expression as ex
2425
from bigframes.core.indexes.base import Index
2526
from bigframes.operations import date_ops
2627

2728

28-
class DatetimeIndex(Index, vendored_pandas_datetime_index.DatetimeIndex):
29-
__doc__ = vendored_pandas_datetime_index.DatetimeIndex.__doc__
29+
@docs.inherit_docs(vendored_pandas_datetime_index.DatetimeIndex)
30+
class DatetimeIndex(Index):
3031

3132
# Must be above 5000 for pandas to delegate to bigframes for binops
3233
__pandas_priority__ = 12000

bigframes/core/indexes/multi.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import bigframes_vendored.pandas.core.indexes.multi as vendored_pandas_multindex
2020
import pandas
2121

22+
from bigframes._tools import docs
2223
from bigframes.core import blocks
2324
from bigframes.core import expression as ex
2425
from bigframes.core.indexes.base import Index
@@ -27,9 +28,8 @@
2728
import bigframes.session
2829

2930

30-
class MultiIndex(Index, vendored_pandas_multindex.MultiIndex):
31-
__doc__ = vendored_pandas_multindex.MultiIndex.__doc__
32-
31+
@docs.inherit_docs(vendored_pandas_multindex.MultiIndex)
32+
class MultiIndex(Index):
3333
@classmethod
3434
def from_tuples(
3535
cls,

bigframes/core/window/rolling.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import pandas
2323

2424
from bigframes import dtypes
25+
from bigframes._tools import docs
2526
from bigframes.core import agg_expressions
2627
from bigframes.core import expression as ex
2728
from bigframes.core import ordering, utils, window_spec
@@ -36,9 +37,8 @@
3637

3738

3839
@log_adapter.class_logger
39-
class Window(vendored_pandas_rolling.Window):
40-
__doc__ = vendored_pandas_rolling.Window.__doc__
41-
40+
@docs.inherit_docs(vendored_pandas_rolling.Window)
41+
class Window:
4242
def __init__(
4343
self,
4444
block: blocks.Block,

0 commit comments

Comments
 (0)