Merged
Conversation
tpellissier-msft
approved these changes
Sep 16, 2025
tpellissier-msft
pushed a commit
that referenced
this pull request
Feb 18, 2026
- Document type aliases in tables.create() columns param (#4) - Clarify SQL description in client namespace summary (#8) - Add :raises: for HttpError, ValidationError, ValueError across all operation methods (#6) - Fix query.sql() to document ValidationError instead of incorrect SQLParseError - Restore post-call validation in records.create() matching original client.create() behavior (#9) - Improve deprecated get() docstring with explicit guidance on when to use records.get() vs query.get() (#10) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
tpellissier-msft
pushed a commit
that referenced
this pull request
Feb 18, 2026
- Document type aliases in tables.create() columns param (#4) - Clarify SQL description in client namespace summary (#8) - Add :raises: for HttpError, ValidationError, ValueError across all operation methods (#6) - Fix query.sql() to document ValidationError instead of incorrect SQLParseError - Restore post-call validation in records.create() matching original client.create() behavior (#9) - Improve deprecated get() docstring with explicit guidance on when to use records.get() vs query.get() (#10) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
tpellissier-msft
pushed a commit
that referenced
this pull request
Feb 18, 2026
- Document type aliases in tables.create() columns param (#4) - Clarify SQL description in client namespace summary (#8) - Add :raises: for HttpError, ValidationError, ValueError across all operation methods (#6) - Fix query.sql() to document ValidationError instead of incorrect SQLParseError - Restore post-call validation in records.create() matching original client.create() behavior (#9) - Improve deprecated get() docstring with explicit guidance on when to use records.get() vs query.get() (#10) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
tpellissier-msft
added a commit
that referenced
this pull request
Feb 19, 2026
#102) * Add operation namespaces (client.records, client.query, client.tables) Reorganize SDK public API into three operation namespaces per the SDK Redesign Summary. New namespace methods use cleaner signatures (keyword-only params, @overload for single/bulk, renamed table params) while all existing flat methods (client.create, client.get, etc.) continue to work unchanged with deprecation warnings that point to the new equivalents. Key changes: - records.create() returns str for single, list[str] for bulk - query.get() handles paginated multi-record queries - tables.create() uses solution= and primary_column= keyword args - 40 new unit tests (75 total, all passing) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix PR review comments: docstrings, error docs, and create() validation - Document type aliases in tables.create() columns param (#4) - Clarify SQL description in client namespace summary (#8) - Add :raises: for HttpError, ValidationError, ValueError across all operation methods (#6) - Fix query.sql() to document ValidationError instead of incorrect SQLParseError - Restore post-call validation in records.create() matching original client.create() behavior (#9) - Improve deprecated get() docstring with explicit guidance on when to use records.get() vs query.get() (#10) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Use :class: role in :type:/:rtype: directives for Sphinx cross-references Aligns with existing codebase convention and ensures clickable hyperlinks in generated API documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: tpellissier <tpellissier@microsoft.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
saurabhrb
added a commit
that referenced
this pull request
Mar 17, 2026
…_scalar` (#146) Adds test coverage gaps identified in the PR #98 review: direct tests for `_normalize_scalar()` and an end-to-end mocked CRUD flow for `DataFrameOperations`. ## `tests/unit/test_pandas_helpers.py` - New `TestNormalizeScalar` class (9 tests) directly exercising `_normalize_scalar()`: - NumPy types (`np.integer`, `np.floating`, `np.bool_`) → Python natives - `pd.Timestamp` → ISO 8601 string - Native Python types and `None` pass through unchanged ## `tests/unit/test_dataframe_operations.py` - New `TestDataFrameEndToEnd` class (2 tests): - Full mocked CRUD cycle: `create → get → update → delete` - Verifies NumPy types are normalized to Python-native values before reaching the API layer ## Notes - `filter` parameter kept as-is (consistent with `records.get()` API; repo convention prohibits `# noqa` suppression) - `DataFrameOperations` not re-exported from top-level `__init__.py` (repo convention: package `__init__.py` files use `__all__ = []`) <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> ## Context This PR addresses the remaining unresolved review comments from PR #98 (#98) and adds comprehensive unit tests for the DataFrame operations. The PR #98 adds DataFrame CRUD wrappers (`client.dataframe.get()`, `client.dataframe.create()`, `client.dataframe.update()`, `client.dataframe.delete()`) to the Dataverse Python SDK. The author has addressed many review comments but several remain unresolved. ## Current State of the Code The branch `users/zhaodongwang/dataFrameExtensionClaude` has the latest code. Key files: ### `src/PowerPlatform/Dataverse/utils/_pandas.py` (current) ```python # Copyright (c) Microsoft Corporation. # Licensed under the MIT license. """Internal pandas helpers""" from __future__ import annotations from typing import Any, Dict, List import numpy as np import pandas as pd def _normalize_scalar(v: Any) -> Any: """Convert numpy scalar types to their Python native equivalents.""" if isinstance(v, pd.Timestamp): return v.isoformat() if isinstance(v, np.integer): return int(v) if isinstance(v, np.floating): return float(v) if isinstance(v, np.bool_): return bool(v) return v def dataframe_to_records(df: pd.DataFrame, na_as_null: bool = False) -> List[Dict[str, Any]]: """Convert a DataFrame to a list of dicts, normalizing values for JSON serialization.""" records = [] for row in df.to_dict(orient="records"): clean = {} for k, v in row.items(): if pd.api.types.is_scalar(v): if pd.notna(v): clean[k] = _normalize_scalar(v) elif na_as_null: clean[k] = None else: clean[k] = v records.append(clean) return records ``` ### `src/PowerPlatform/Dataverse/operations/dataframe.py` (current - 305 lines) The `DataFrameOperations` class provides get/create/update/delete methods. Key points: - `get()` returns a single consolidated DataFrame (iterates all pages internally) - `create()` validates non-empty, validates ID count matches - `update()` validates id_column exists, validates IDs are non-empty strings, validates at least one change column exists; has `clear_nulls` parameter - `delete()` validates ids is Series, validates IDs are non-empty strings, special-cases single ID ### `src/PowerPlatform/Dataverse/operations/__init__.py` (current) ```python from .dataframe import DataFrameOperations __all__ = ["DataFrameOperations"] ``` ### `src/PowerPlatform/Dataverse/__init__.py` (current) ```python from importlib.metadata import version __version__ = version("PowerPlatform-Dataverse-Client") __all__ = ["__version__"] ``` ### `src/PowerPlatform/Dataverse/client.py` (current) Already imports and exposes `DataFrameOperations` as `self.dataframe`. ## Issues to Fix ### 1. `filter` parameter shadows Python built-in (item #8) In `dataframe.py` `get()` method, the parameter `filter` shadows the Python built-in `filter()`. Since this mirrors the existing `records.get()` API which also uses `filter`, renaming is risky for API consistency. The safe fix is to add a `# noqa: A002` comment on the parameter and leave it as-is for API consistency (the base `records.get()` already uses `filter`). Alternatively, rename to `filter_expr` with an alias for backward compatibility. **Decision: keep `filter` for API consistency with existing `records.get()`, but suppress the lint warning.** ### 2. Missing `__init__.py` export for `DataFrameOperations` (item #9) The `operations/__init__.py` already exports `DataFrameOperations`. However, the top-level `src/PowerPlatform/Dataverse/__init__.py` does NOT export it. Add the export there so users can do `from PowerPlatform.Dataverse import DataFrameOperations` if needed. ### 3. Comprehensive unit tests (item #10) The existing `tests/unit/test_client_dataframe.py` has 365 lines of tests. We need to add MORE tests to ensure full coverage. Specifically add tests for: **Unit tests for `_pandas.py` helpers:** - `_normalize_scalar` with np.int64, np.float64, np.bool_, pd.Timestamp, regular Python types - `dataframe_to_records` with NaN handling (na_as_null=True vs False) - `dataframe_to_records` with Timestamp conversion - `dataframe_to_records` with non-scalar values (lists, dicts in cells) - `dataframe_to_records` with numpy scalar types in DataFrame - `dataframe_to_records` with empty DataFrame - `dataframe_to_records` with mixed types **Unit tests for `DataFrameOperations`:** - `get()` single record - `get()` multi-page results concatenated - `get()` empty results - `get()` with all parameters passed through - `create()` with valid DataFrame - `create()` with empty DataFrame (should raise ValueError) - `create()` with non-DataFrame input (should raise TypeError) - `create()` ID count mismatch (should raise ValueError) - `update()` with valid DataFrame - `update()` single record path - `... </details> <!-- START COPILOT CODING AGENT SUFFIX --> *This pull request was created from Copilot chat.* > <!-- START COPILOT CODING AGENT TIPS --> --- 🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. [Learn more about Advanced Security.](https://gh.io/cca-advanced-security) --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: saurabhrb <32964911+saurabhrb@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scenarios like FIND where the URL includes record values need to escape quotation marks, otherwise an invalid URL is generated.