Skip to content

Profile wrapper object#65

Merged
Demonstrandum merged 5 commits into
masterfrom
cursor/profile-wrapper-object-e684
Mar 3, 2026
Merged

Profile wrapper object#65
Demonstrandum merged 5 commits into
masterfrom
cursor/profile-wrapper-object-e684

Conversation

@Demonstrandum

Copy link
Copy Markdown
Owner

Motivation for features / changes

The existing profile management (SerializedProfile, ProfileData) uses nested dictionaries with camelCase keys, making programmatic modification of profiles cumbersome and error-prone. This change introduces a high-level Profile wrapper object to provide a clean, Pythonic API for creating and modifying profiles.

Technical description of changes

  • New Profile class: Added tensorbored/plugins/core/profile_writer.py which provides a Pythonic interface for profile data.
    • Uses @property getters and setters for typed and validated access to profile fields.
    • Maps snake_case Python attributes (e.g., run_colors, y_axis_scale) to the underlying camelCase JSON fields.
    • Exposes run_colors and group_colors as plain dictionaries for easier manipulation.
    • Provides convenience methods like pin_scalar, add_superimposed_card, and select_runs.
    • Supports round-trip serialization/deserialization (Profile.from_serialized, Profile.load, profile.serialize, profile.write).
  • Backward Compatibility: create_profile, set_default_profile, and write_profile continue to function as before. write_profile now also accepts Profile instances directly.
  • ProfileData fix: Corrected ProfileData TypedDict to include symlogLinearThreshold and tagSymlogLinearThresholds.
  • Tests: Added comprehensive unit tests for the new Profile class.

Screenshots of UI changes (or N/A)

N/A

Detailed steps to verify changes work correctly (as executed by you)

  1. Run the unit tests: python -m pytest tensorbored/plugins/core/profile_writer_test.py
  2. Verify all 56 tests pass (30 new ProfileClassTest tests + 26 existing tests).
  3. Manually test the new API by creating a profile and writing it:
    from tensorbored.plugins.core import profile_writer
    
    p = profile_writer.Profile("Training Dashboard")
    p.pin_scalar("train/loss")
    p.pin_scalar("eval/loss")
    p.run_colors["train"] = "#2196F3"
    p.run_colors["eval"] = "#4CAF50"
    p.smoothing = 0.8
    p.y_axis_scale = "log10"
    p.tag_filter = "loss|accuracy"
    p.metric_descriptions["train/loss"] = "Training loss"
    p.expanded_tag_groups["train"] = True
    p.add_superimposed_card("Loss Comparison", ["train/loss", "eval/loss"])
    p.select_runs(["train", "eval"])
    p.write("./logs") # Verify a profile.json is created with the expected content

Alternate designs / implementations considered (or N/A)

N/A


Open in Web Open in Cursor 

Introduces a Profile class that provides snake_case property getters
and setters over the camelCase ProfileData/SerializedProfile dicts.
This makes programmatic profile construction much cleaner compared to
manually building nested TypedDicts.

Key features:
- Properties for all profile fields with validation on axis scales
- Convenience methods: pin_scalar, pin_histogram, pin_image,
  add_superimposed_card, select_runs
- serialize() to produce SerializedProfile dicts
- write(logdir) to serialize and write to disk in one call
- from_serialized() and load() classmethods for round-tripping
- run_colors/group_colors exposed as plain dicts instead of
  list[RunColorEntry]/list[GroupColorEntry]

Also:
- Adds missing symlogLinearThreshold and tagSymlogLinearThresholds
  fields to the ProfileData TypedDict (they were already being
  written but not declared)
- Updates write_profile to accept Profile instances directly
- 30 new tests covering construction, mutation, serialization,
  round-trips, and the builder workflow

Co-authored-by: Samuel <samuel@knutsen.co>
@cursor

cursor Bot commented Mar 3, 2026

Copy link
Copy Markdown

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

cursoragent and others added 3 commits March 3, 2026 14:01
create_profile and set_default_profile now delegate to
Profile(...).serialize() instead of duplicating the dict-building
logic. The two small type mismatches are bridged at the call site:
group_colors list[GroupColorEntry] -> dict[str,int], and
symlog_linear_threshold 1.0-means-default -> None-means-default.

Co-authored-by: Samuel <samuel@knutsen.co>
- create_profile now returns a Profile object (the primary API).
  write_profile and set_default_profile still accept it seamlessly.
- Profile.update(other) and a | b merge two profiles:
  dicts merged, lists extended, regex filters combined with
  alternation, optional scalars only overridden if non-None.
- Updated tests for the new return type (65 → 68 tests).
- Updated NEW.md, AGENTS_DEV.md, AGENTS_DOC.md, README.md to
  show create_profile / Profile as the primary workflow.

Co-authored-by: Samuel <samuel@knutsen.co>
Co-authored-by: Samuel <samuel@knutsen.co>
@github-actions

github-actions Bot commented Mar 3, 2026

Copy link
Copy Markdown

Preview Deployment

Status ✅ Running
Live Preview https://Demonstrandum-tensorbored-pr-65.hf.space
Space https://huggingface.co/spaces/Demonstrandum/tensorbored-pr-65
Details
  • Wheel: tensorbored_nightly-2.21.0a20260303-py3-none-any.whl
  • Commit: 5c9b244
  • Build status: success

@Demonstrandum Demonstrandum marked this pull request as ready for review March 3, 2026 14:33
Co-authored-by: Samuel <samuel@knutsen.co>
@Demonstrandum Demonstrandum merged commit 0c9f797 into master Mar 3, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants