Skip to content

feat: add safe repr implementations for watsonx and litellm backends#1359

Open
cptnm3 wants to merge 2 commits into
generative-computing:mainfrom
cptnm3:feat/add-repr-and-str
Open

feat: add safe repr implementations for watsonx and litellm backends#1359
cptnm3 wants to merge 2 commits into
generative-computing:mainfrom
cptnm3:feat/add-repr-and-str

Conversation

@cptnm3

@cptnm3 cptnm3 commented Jun 30, 2026

Copy link
Copy Markdown

Pull Request

Issue

Fixes #1317

Description

Added __repr__ and __str__ to show useful information with masked api_key

Testing

  • Tests added to the respective file if code was changed
  • New code has 100% coverage if code was added
  • Ensure existing tests and github automation passes (a maintainer will kick off the github automation when the rest of the PR is populated)

Attribution

  • AI coding assistants used

Adding a new component, requirement, sampling strategy, or tool?

If your PR adds or modifies one of the types below, check the matching box. A checklist of type-specific review items will be posted as a comment.

  • Component
  • Requirement
  • Sampling Strategy
  • Tool

NOTE: Please ensure you have an issue that has been acknowledged by a core contributor and routed you to open a pull request against this repository. Otherwise, please open an issue before continuing with this pull request.

Added __repr__ and __str__ to show useful information with masked api_key

Closes generative-computing#1317

Signed-off-by: Vishal V <VishalV@ibm.com>
@cptnm3 cptnm3 requested a review from a team as a code owner June 30, 2026 15:32
@github-actions github-actions Bot added the enhancement New feature or request label Jun 30, 2026
@psschwei

Copy link
Copy Markdown
Member

@cptnm3 thanks for the PR! If you don't mind, could you leave a comment on the issue so we can assign it to you?

@cptnm3

cptnm3 commented Jun 30, 2026

Copy link
Copy Markdown
Author

Done @psschwei . Sorry, in the contribution guidelines I did not see that I have to be assigned to an issue before working on it. Will keep in mind next time. Thanks!

@psschwei

Copy link
Copy Markdown
Member

no worries!

@AngeloDanducci AngeloDanducci left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution, @cptnm3! The implementation looks good overall and follows the existing OpenAIBackend pattern nicely.

I've left a few inline comments with some requested changes — mostly moving and mocking some of the tests, and a couple of small test improvements. Once those are addressed this should be good to go.

Comment on lines +144 to +150
def __repr__(self) -> str:
"""Return a useful string representation for debugging."""
return (
f"{self.__class__.__name__}("
f"model_id={self._model_id!r}, "
f"base_url={self._base_url!r})"
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def __repr__(self) -> str:
"""Return a useful string representation for debugging."""
return (
f"{self.__class__.__name__}("
f"model_id={self._model_id!r}, "
f"base_url={self._base_url!r})"
)
def __repr__(self) -> str:
"""Return a useful string representation for debugging."""
base_url_repr = self._base_url if self._explicit_base_url else None
return (
f"{self.__class__.__name__}("
f"model_id={self._model_id!r}, "
f"base_url={base_url_repr!r})"
)

self._base_url always holds the fallback value http://localhost:11434/v1 when base_url is not passed by the caller.

Recommend adding this to catch that case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you do the above also recommend adding another test case to verify

def test_repr_no_base_url_shows_none():
    backend = LiteLLMBackend(model_id="ollama_chat/test-model")
    r = repr(backend)
    assert "base_url=None" in r
    assert "http://localhost:11434" not in r

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Comment thread test/backends/test_litellm_ollama.py Outdated
session.reset()


def test_repr_shows_model_id_and_base_url():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend adding a test_str_* requivalent.

def test_str_shows_model_id_and_base_url():
    backend = LiteLLMBackend(
        model_id="ollama_chat/test-model", base_url="http://localhost:11434/v1"
    )
    assert "ollama_chat/test-model" in str(backend)
    assert "object at 0x" not in str(backend)

or similar.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Comment thread test/backends/test_watsonx.py Outdated
from mellea.stdlib.context import ChatContext, SimpleContext


def test_repr_masks_api_key():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend moving test_repr_masks_api_key, test_repr_no_key_shows_none, and test_str_masks_api_key to a separate file (e.g. test/backends/test_watsonx_repr.py) that uses pytest.importorskip only for the import itself at the top but carries no require_api_key or e2e marker — making them plain unit tests that run by default.

Same with the test_litellm_ollama.py addition.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to mellea/backends/test_litellm_repr.py and test/backends/test_watsonx_repr.py

Comment thread test/backends/test_watsonx.py Outdated
assert "test-project" not in r


def test_repr_no_key_shows_none(monkeypatch: pytest.MonkeyPatch):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inverted assertions here — the test passes api_key=None with WATSONX_API_KEY set in the environment. The constructor resolves None"env-key" before storing it (watsonx.py lines 132–133), so self._api_key is "env-key" and repr shows '***'. The assertions assert "***" not in r and assert "_api_key=None" in r are both inverted and will always fail.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected this. Please take a look

Comment thread test/backends/test_watsonx.py Outdated
assert "test-project" not in r


def test_str_masks_api_key():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When moving these tests over, recommend using a helper function

def clear_watsonx_env(monkeypatch: pytest.MonkeyPatch):
    monkeypatch.delenv("WATSONX_API_KEY", raising=False)
    monkeypatch.delenv("WATSONX_URL", raising=False)
    monkeypatch.delenv("WATSONX_PROJECT_ID", raising=False)

and then also using monkeypatch for some of the setup

def test_str_masks_api_key(clear_watsonx_env):
    with patch("mellea.backends.watsonx.APIClient"), patch(
        "mellea.backends.watsonx.ModelInference"
    ):

This avoids the issue of the init validating the url with fake credentials before the assertions.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Comment thread test/backends/test_watsonx.py Outdated
assert "***" in str(backend)
assert "test-project" not in str(backend)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend adding an additional test test_repr_env_key_is_masked or similar.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Watsonx repr tests moved to test_watsonx_repr.py — plain unit tests,
no e2e/require_api_key markers. Fix inverted assertions in
test_repr_no_key_shows_none; add test_repr_env_key_is_masked for
env-resolved key path. Use _make_backend helper + mock Credentials
to avoid real SDK init.

LiteLLM repr test moved to test_litellm_repr.py. Add
test_repr_omits_default_base_url and test_str_shows_model_id_and_base_url.
Fix LiteLLMBackend.__repr__ to show base_url=None when caller omitted it.

Signed-off-by: Vishal V <VishalV@ibm.com>
@cptnm3

cptnm3 commented Jul 2, 2026

Copy link
Copy Markdown
Author

Hi @AngeloDanducci. thanks for the review. I have made the suggested changes. Please take a look and let me know in case I have missed anything else

@cptnm3 cptnm3 requested a review from AngeloDanducci July 3, 2026 06:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add safe __repr__ to WatsonxBackend and LiteLLMBackend

3 participants