Skip to content

Commit a22832e

Browse files
author
Abel Milash
committed
Move DataFrame methods to client.dataframe namespace
2 parents 1013bbe + c357eff commit a22832e

57 files changed

Lines changed: 8522 additions & 834 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.azdo/ci-pr.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ extends:
4747
displayName: 'Install dependencies'
4848
4949
- script: |
50-
black src tests --check
50+
black src tests examples --check
5151
displayName: 'Check format with black'
5252
5353
- script: |

.claude/skills/dataverse-sdk-dev/SKILL.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,44 @@ This skill provides guidance for developers working on the PowerPlatform Dataver
1313

1414
### API Design
1515

16-
1. **client.py** - client.py only contains public API methods and all public methods must be in client.py
16+
1. **Public methods in operation namespaces** - New public methods go in the appropriate namespace module under `src/PowerPlatform/Dataverse/operations/` (`records.py`, `query.py`, `tables.py`). The `client.py` file exposes these via namespace properties (`client.records`, `client.query`, `client.tables`). Public types and constants live in their own modules (e.g., `models/metadata.py`, `common/constants.py`)
1717
2. **Every public method needs README example** - Public API methods must have examples in README.md
1818
3. **Reuse existing APIs** - Always check if an existing method can be used before making direct Web API calls
1919
4. **Update documentation** when adding features - Keep README and SKILL files (both copies) in sync
2020
5. **Consider backwards compatibility** - Avoid breaking changes
21+
6. **Internal vs public naming** - Modules, files, and functions not meant to be part of the public API must use a `_` prefix (e.g., `_odata.py`, `_relationships.py`). Files without the prefix (e.g., `constants.py`, `metadata.py`) are public and importable by SDK consumers
22+
23+
### Dataverse Property Naming Rules
24+
25+
Dataverse uses two different naming conventions for properties. Getting this wrong causes 400 errors that are hard to debug.
26+
27+
| Property type | Name convention | Example | When used |
28+
|---|---|---|---|
29+
| **Structural** (columns) | LogicalName (always lowercase) | `new_name`, `new_priority` | `$select`, `$filter`, `$orderby`, record payload keys |
30+
| **Navigation** (relationships / lookups) | Navigation Property Name (usually SchemaName, PascalCase, case-sensitive) | `new_CustomerId`, `new_AgentId` | `$expand`, `@odata.bind` annotation keys |
31+
32+
Navigation property names are case-sensitive and must match the entity's `$metadata`. Using the logical name instead of the navigation property name results in 400 Bad Request errors.
33+
34+
**Critical rule:** The OData parser validates `@odata.bind` property names **case-sensitively** against declared navigation properties. Lowercasing `new_CustomerId@odata.bind` to `new_customerid@odata.bind` causes: `ODataException: An undeclared property 'new_customerid' which only has property annotations...`
35+
36+
**SDK implementation:**
37+
38+
- `_lowercase_keys()` lowercases all keys EXCEPT those containing `@odata.` (preserves navigation property casing in `@odata.bind` keys)
39+
- `_lowercase_list()` lowercases `$select` and `$orderby` params (structural properties)
40+
- `$expand` params are passed as-is (navigation properties, PascalCase)
41+
- `_convert_labels_to_ints()` skips `@odata.` keys entirely (they are annotations, not attributes)
42+
43+
**When adding new code that processes record dicts or builds query parameters:**
44+
45+
- Always use `_lowercase_keys()` for record payloads. Never manually call `.lower()` on all keys
46+
- Never lowercase `$expand` values or `@odata.bind` key prefixes
47+
- If iterating record keys, skip keys containing `@odata.` when doing attribute-level operations
2148

2249
### Code Style
2350

2451
6. **No emojis** - Do not use emoji in code, comments, or output
2552
7. **Standardize output format** - Use `[INFO]`, `[WARN]`, `[ERR]`, `[OK]` prefixes for console output
2653
8. **No noqa comments** - Do not add `# noqa: BLE001` or similar linter suppression comments
2754
9. **Document public APIs** - Add Sphinx-style docstrings with examples for public methods
28-
10. **Define __all__ in module files, not __init__.py** - Use `__all__` to control exports in the actual module file (e.g., errors.py), not in `__init__.py`.
29-
11. **Run black before committing** - Always run `python -m black <changed files>` before committing. CI will reject unformatted code. Config is in `pyproject.toml` under `[tool.black]`. And follow black formatting in general when coding.
55+
10. **Define __all__ in module files** - Each module declares its own exports via `__all__` (e.g., `errors.py` defines `__all__ = ["HttpError", ...]`). Package `__init__.py` files should not re-export or redefine another module's `__all__`; they use `__all__ = []` to indicate no star-import exports.
56+
11. **Run black before committing** - Always run `python -m black <changed files>` before committing. CI will reject unformatted code. Config is in `pyproject.toml` under `[tool.black]`.

0 commit comments

Comments
 (0)