You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .claude/skills/dataverse-sdk-dev/SKILL.md
+30-3Lines changed: 30 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,17 +13,44 @@ This skill provides guidance for developers working on the PowerPlatform Dataver
13
13
14
14
### API Design
15
15
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`)
17
17
2.**Every public method needs README example** - Public API methods must have examples in README.md
18
18
3.**Reuse existing APIs** - Always check if an existing method can be used before making direct Web API calls
19
19
4.**Update documentation** when adding features - Keep README and SKILL files (both copies) in sync
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 |
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
21
48
22
49
### Code Style
23
50
24
51
6.**No emojis** - Do not use emoji in code, comments, or output
25
52
7.**Standardize output format** - Use `[INFO]`, `[WARN]`, `[ERR]`, `[OK]` prefixes for console output
26
53
8.**No noqa comments** - Do not add `# noqa: BLE001` or similar linter suppression comments
27
54
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