Skip to content

Commit 1315f75

Browse files
authored
Merge pull request #53 from ncdcdev/feat/issue-47-expand-axis-range-option
feat: make expand_axis_range optional with default false (#47)
2 parents 305d421 + f630ded commit 1315f75

6 files changed

Lines changed: 251 additions & 25 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Two authentication methods are supported:
3737
- Read mode: get data from specific sheets/ranges with `sheet` and `cell_range` parameters
3838
- **Automatic header inclusion**: when `cell_range` is specified, frozen rows (headers) are automatically included by default
3939
- Set `include_frozen_rows=False` to get only the specified range
40+
- For sheets with `frozen_rows=0`, use `expand_axis_range=True` to include row 1 (for columns) or column A (for rows)
4041
- **Cell style information** (optional): set `include_cell_styles=True` to get background colors, column widths, and row heights
4142
- Default is `False` to minimize token usage
4243
- Useful for identifying highlighted cells, colored headers, or visually emphasized content

README_ja.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ stdioとHTTPの両方のトランスポートに対応しています。
3737
- 読み取りモード: `sheet``cell_range`パラメータで特定シート/範囲を取得
3838
- **ヘッダー自動追加**: `cell_range`指定時、デフォルトで固定行(ヘッダー)を自動的に含める
3939
- `include_frozen_rows=False`を指定すると、指定範囲のみを取得
40+
- `frozen_rows=0`のシートでは、`expand_axis_range=True`で1行目(列の場合)またはA列(行の場合)から自動取得
4041
- **セルスタイル情報**(オプション): `include_cell_styles=True`を指定すると、背景色・列幅・行高さを取得
4142
- デフォルトは`False`でトークン消費を最小化
4243
- 強調表示されたセル、色付きヘッダー、視覚的に強調されたコンテンツの識別に便利

src/server.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ def sharepoint_excel(
455455
cell_range: str | None = None,
456456
include_frozen_rows: bool = True,
457457
include_cell_styles: bool = False,
458+
expand_axis_range: bool = False,
458459
ctx: Context | None = None,
459460
) -> str:
460461
"""
@@ -467,15 +468,16 @@ def sharepoint_excel(
467468
cell_range: セル範囲(例: "A1:D10")
468469
- 推奨形式: "A1:D10"(開始セル:終了セル)
469470
- 列のみ: "A:D" も可(自動的に行範囲が追加されます)
470-
- ⚠️ 単一列/行の部分範囲は開始側のみ 1/A に自動拡張されます
471-
例: "J50:J100" → "J1:J100"(開始行が 1 行目に拡張されます)
472471
include_frozen_rows: cell_range指定時に固定行を自動追加(デフォルト: True)
473472
True: frozen_rowsで指定された行(通常はヘッダー)を自動的に取得
474473
False: 指定されたcell_rangeのみを取得
475474
include_cell_styles: セルの色・サイズ情報(default: false)
476475
色分けされたデータを抽出する場合のみTrueを指定
477476
背景色(fill)、列幅(width)、行高さ(height)を取得
478477
※トークン消費が約20%増加
478+
expand_axis_range: 単一列/行の部分範囲を開始側に自動拡張(default: false)
479+
True: 例 "J50:J100" → "J1:J100"(行1に拡張)
480+
frozen_rows=0でヘッダー文脈が不明な場合に使用
479481
ctx: FastMCP context (injected automatically)
480482
481483
Returns:
@@ -504,6 +506,7 @@ def sharepoint_excel(
504506
cell_range=cell_range,
505507
include_frozen_rows=include_frozen_rows,
506508
include_cell_styles=include_cell_styles,
509+
expand_axis_range=expand_axis_range,
507510
)
508511

509512
except Exception as e:
@@ -549,10 +552,14 @@ def register_tools():
549552
"Response includes cell data in 'rows' (value and coordinate) and structural information "
550553
"(sheet name, dimensions, frozen_rows, frozen_cols, freeze_panes when present, merged_ranges when merged cells exist). "
551554
"Cell styles (include_cell_styles, default: false): background colors and sizes. Use only for color-coded data extraction. "
552-
"Header detection: Cannot be auto-detected from frozen_rows. "
555+
"Header detection: For sheets with frozen_rows > 0, headers are automatically included with include_frozen_rows=True (default). "
556+
"For sheets with frozen_rows=0, headers are not automatically included and context may be unclear. "
553557
"ALWAYS read exactly 5 rows for header check: 'A1:Z5' (NOT 'A1:Z50' or more). "
554558
"Prefer 'query' search when possible to locate data first. "
555-
"Workflow: 1) Search OR read 'A1:Z5', 2) Read specific range only."
559+
"Workflow: 1) Search OR read 'A1:Z5' for header check, "
560+
"2) Read specific range (include_frozen_rows adds frozen headers automatically), "
561+
"3) If frozen_rows=0 and header context is unclear, retry with expand_axis_range=True "
562+
"to auto-include row 1 (for columns) or column A (for rows)."
556563
)
557564
)(sharepoint_excel)
558565
logging.info("Registered tool: sharepoint_excel")

src/sharepoint_excel.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ def parse_to_json(
108108
cell_range: str | None = None,
109109
include_frozen_rows: bool = True,
110110
include_cell_styles: bool = False,
111+
expand_axis_range: bool = False,
111112
) -> str:
112113
"""
113114
Excelファイルを解析してJSON形式で返す
@@ -121,6 +122,9 @@ def parse_to_json(
121122
False: 指定されたcell_rangeのみを取得
122123
include_cell_styles: セルの色・サイズ情報(default: false)
123124
色分けデータ抽出時のみ使用。トークン消費+約20%
125+
expand_axis_range: 単一列/行指定時に開始側を自動拡張(default: false)
126+
True: 例 "J50:J100" → "J1:J100"(行1に拡張)
127+
False: 指定範囲をそのまま使用
124128
125129
Returns:
126130
JSON文字列
@@ -212,6 +216,7 @@ def parse_to_json(
212216
cell_range,
213217
include_frozen_rows,
214218
include_cell_styles,
219+
expand_axis_range,
215220
)
216221
result["sheets"].append(sheet_data)
217222

@@ -399,6 +404,7 @@ def _parse_sheet(
399404
cell_range: str | None = None,
400405
include_frozen_rows: bool = True,
401406
include_cell_styles: bool = False,
407+
expand_axis_range: bool = False,
402408
) -> dict[str, Any]:
403409
"""
404410
シートを解析してdict形式で返す
@@ -408,6 +414,7 @@ def _parse_sheet(
408414
cell_range: セル範囲指定(例: "A1:D10")
409415
include_frozen_rows: cell_range指定時に固定行(ヘッダー)を自動追加
410416
include_cell_styles: セルのスタイル情報を含めるか
417+
expand_axis_range: 単一列/行指定時に開始側を自動拡張
411418
412419
Returns:
413420
シートデータのdict
@@ -446,22 +453,36 @@ def _parse_sheet(
446453
sheet_data["frozen_rows"] = frozen_rows
447454
sheet_data["frozen_cols"] = frozen_cols
448455

456+
# frozen_rows=0 かつ cell_range指定時、expand_axis_range=Falseの場合のみ警告
457+
# expand_axis_range=Trueの場合は1行目/A列が含まれるため警告不要
458+
if frozen_rows == 0 and cell_range and not expand_axis_range:
459+
sheet_data["header_detection"] = {
460+
"status": "no_frozen_rows",
461+
"frozen_rows": 0,
462+
"note": "This sheet has no frozen rows. Headers are not automatically included.",
463+
"suggestions": [
464+
"If headers are needed, read 'A1:Z5' to check header structure",
465+
"Or retry with expand_axis_range=True to include row 1 (for columns) or column A (for rows)",
466+
],
467+
}
468+
449469
# セル範囲の正規化・拡張(cell_rangeがある場合)
450470
# マージセル情報のキャッシュに使用するため、先に計算する
451471
effective_range_for_merge = None
452472
header_range = None # ヘッダー範囲(再利用のため事前に初期化)
453473
if cell_range:
454474
sheet_data["requested_range"] = cell_range
455475
effective_range = self._normalize_column_range(cell_range, sheet)
456-
expanded_range = self._expand_axis_range(effective_range)
457-
if expanded_range != effective_range:
458-
logger.info(
459-
"Expanded axis range '%s' -> '%s' (sheet=%s)",
460-
effective_range,
461-
expanded_range,
462-
sheet.title,
463-
)
464-
effective_range = expanded_range
476+
if expand_axis_range:
477+
expanded_range = self._expand_axis_range(effective_range)
478+
if expanded_range != effective_range:
479+
logger.info(
480+
"Expanded axis range '%s' -> '%s' (sheet=%s)",
481+
effective_range,
482+
expanded_range,
483+
sheet.title,
484+
)
485+
effective_range = expanded_range
465486

466487
if effective_range != cell_range:
467488
logger.info(

tests/test_server.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ def test_excel_read_default(
226226
cell_range=None,
227227
include_frozen_rows=True,
228228
include_cell_styles=False,
229+
expand_axis_range=False,
229230
)
230231

231232
@pytest.mark.unit
@@ -267,6 +268,7 @@ def test_excel_with_sheet_parameter(
267268
cell_range=None,
268269
include_frozen_rows=True,
269270
include_cell_styles=False,
271+
expand_axis_range=False,
270272
)
271273

272274
@pytest.mark.unit
@@ -290,6 +292,7 @@ def test_excel_with_cell_range_parameter(
290292
cell_range="A1:D10",
291293
include_frozen_rows=True,
292294
include_cell_styles=False,
295+
expand_axis_range=False,
293296
)
294297

295298
@pytest.mark.unit

0 commit comments

Comments
 (0)