Repository: wandb/wandb

Issue:
[CLI]: RecursionError when printing vars on run object
### Describe the bug

When accessing a run object through the API and calling the built-in `vars` function on it, and printing the result, it causes some infinite recursion logic.

Snippet comparabale to [docs](https://docs.wandb.ai/guides/track/log/logging-faqs#how-can-i-access-the-data-logged-to-my-runs-directly-and-programmatically):
```python 
import wandb

api = wandb.Api()
run = api.run("<some_run>")
print(vars(run))
```

<!--- A full traceback of the exception in the quotes below -->
```shell
Traceback (most recent call last):
  File "/Users/patrickhaller/Projects/GERPT/test.py", line 6, in <module>
    print(vars(run))
  File "/Users/patrickhaller/Projects/GERPT/venv/lib/python3.9/site-packages/wandb/apis/public.py", line 998, in __repr__
    return f"<User {self.email}>"
  File "/Users/patrickhaller/Projects/GERPT/venv/lib/python3.9/site-packages/wandb/apis/public.py", line 818, in __getattr__
    raise AttributeError(f"'{repr(self)}' object has no attribute '{name}'")
  File "/Users/patrickhaller/Projects/GERPT/venv/lib/python3.9/site-packages/wandb/apis/public.py", line 998, in __repr__
    return f"<User {self.email}>"
  File "/Users/patrickhaller/Projects/GERPT/venv/lib/python3.9/site-packages/wandb/apis/public.py", line 818, in __getattr__
    raise AttributeError(f"'{repr(self)}' object has no attribute '{name}'")
  File "/Users/patrickhaller/Projects/GERPT/venv/lib/python3.9/site-packages/wandb/apis/public.py", line 998, in __repr__
    return f"<User {self.email}>"
    ...
  File "/Users/patrickhaller/Projects/GERPT/venv/lib/python3.9/site-packages/wandb/apis/public.py", line 818, in __getattr__
    raise AttributeError(f"'{repr(self)}' object has no attribute '{name}'")
  File "/Users/patrickhaller/Projects/GERPT/venv/lib/python3.9/site-packages/wandb/apis/public.py", line 998, in __repr__
    return f"<User {self.email}>"
  File "/Users/patrickhaller/Projects/GERPT/venv/lib/python3.9/site-packages/wandb/apis/public.py", line 810, in __getattr__
    key = self.snake_to_camel(name)
  File "/Users/patrickhaller/Projects/GERPT/venv/lib/python3.9/site-packages/wandb/apis/public.py", line 790, in snake_to_camel
    camel = "".join([i.title() for i in string.split("_")])
  File "/Users/patrickhaller/Projects/GERPT/venv/lib/python3.9/site-packages/wandb/apis/public.py", line 790, in <listcomp>
    camel = "".join([i.title() for i in string.split("_")])
RecursionError: maximum recursion depth exceeded while calling a Python object
```


### Additional Files

_No response_

### Environment

WandB version: 0.12.16

OS: macOS Monetary

Python version: 3.9.10

Versions of relevant libraries:


### Additional Context

* Requires an existing run. 
* I removed part of the stack trace due to length constraints, which was repeating


Discussion:
Hi @HallerPatrick ,

I'll be glad to look into this for you. I am able to replicate the error on my end and will need time to review it. Are you attempting to print a specific attribute(s) of `run`? In the mean time you could also utilize `print(dir(run))`. 
Hey @MBakirWB,

I tried to look into the API through the python console to look at the dict of a `run` object. Out of habit am using `vars` instead of `dir`. This is probably not a urgent bug, I just wanted to let you know :)


Hi @HallerPatrick ,

We have identified the bug that causes this recursion. Thanks again for bringing it to our attention. I will be submitting a ticket to our engineering team to address and will update you when a fix is in place. 

Regards,

Mohammad

Resolving patch:
diff --git a/wandb/apis/public.py b/wandb/apis/public.py
--- a/wandb/apis/public.py
+++ b/wandb/apis/public.py
@@ -1149,7 +1149,16 @@ def generate_api_key(self, description=None):
             return None
 
     def __repr__(self):
-        return f"<User {self.email}>"
+        if "email" in self._attrs:
+            return f"<User {self._attrs['email']}>"
+        elif "username" in self._attrs:
+            return f"<User {self._attrs['username']}>"
+        elif "id" in self._attrs:
+            return f"<User {self._attrs['id']}>"
+        elif "name" in self._attrs:
+            return f"<User {self._attrs['name']!r}>"
+        else:
+            return "<User ???>"
 
 
 class Member(Attrs):


Test patch: