Repository: fabfuel/circuitbreaker

Issue:
Non obvious circuit breaker "name" property behavior
If you don't pass a "name" argument you can end up with a TypeError:

```python
cb = CircuitBreaker()
str(cb)  #TypeError: __str__ returned non-string (type NoneType)
```

Of course you have no problem if you first decorate something:

```python
cb = CircuitBreaker()

@cb
def some_func(): ...

str(cb)  # no error
```

But is it really obvious that it ends up with the name of a function?

```
print(cb.name)  # some_func
```

And if you use the same circuit breaker to decorate something else, it's name won't change:

```python
@cb
def another_func(): ...

print(cb)  # still "some_func"
```

I suggest that if there is no name we should generate one on instance initialization instead:

```python
cb = CircuitBreaker()
str(cb)  # unnamed_CircuitBreaker_1
```

Discussion:

Patch:
diff --git a/circuitbreaker.py b/circuitbreaker.py
index ff15b48..2d317fb 100644
--- a/circuitbreaker.py
+++ b/circuitbreaker.py
@@ -281,7 +281,7 @@ class CircuitBreaker(object):
         return self._fallback_function
 
     def __str__(self, *args, **kwargs):
-        return self._name
+        return self.name or 'unnamed_CircuitBreaker'
 
 
 class CircuitBreakerError(Exception):


Test patch:
diff --git a/tests/test_unit.py b/tests/test_unit.py
index 37a51e7..ac99871 100644
--- a/tests/test_unit.py
+++ b/tests/test_unit.py
@@ -34,6 +34,11 @@ def test_circuitbreaker__str__():
     assert str(cb) == 'Foobar'
 
 
+def test_circuitbreaker_unnamed__str__():
+    cb = CircuitBreaker()
+    assert str(cb) == 'unnamed_CircuitBreaker'
+
+
 def test_circuitbreaker_error__str__():
     cb = CircuitBreaker(name='Foobar')
     cb._last_failure = Exception()