-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
955d088
commit a4a20ca
Showing
2 changed files
with
128 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from typing import Dict, Union | ||
|
||
|
||
class FeatureFlag: | ||
def __init__( | ||
self, | ||
name: Union[str, bytes], | ||
variant: Union[None, str, bytes] = None | ||
): | ||
self._name = name | ||
self._variant = self._coerce_variant(variant) | ||
|
||
@property | ||
def name(self) -> Union[str, bytes]: | ||
return self._name | ||
|
||
@property | ||
def variant(self) -> Union[None, str, bytes]: | ||
return self._variant | ||
|
||
# for JSON encoding the feature flag | ||
def to_dict(self) -> Dict[str, Union[str, bytes]]: | ||
if self._variant is None: | ||
return {'name': self._name} | ||
|
||
return {'name': self._name, 'variant': self._variant} | ||
|
||
# a FeatureFlag is valid if it has a non-empty string name and a variant | ||
# that's None or a string | ||
# FeatureFlags that are not valid will be ignored | ||
def is_valid(self) -> bool: | ||
return ( | ||
isinstance(self._name, (str, bytes)) and | ||
len(self._name) > 0 and | ||
(self._variant is None or isinstance(self._variant, (str, bytes))) | ||
) | ||
|
||
def _coerce_variant( | ||
self, | ||
variant: Union[None, str, bytes] | ||
) -> Union[None, str, bytes]: | ||
if variant is None or isinstance(variant, (str, bytes)): | ||
return variant | ||
|
||
try: | ||
return str(variant) | ||
except Exception: | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
from bugsnag.feature_flags import FeatureFlag | ||
|
||
|
||
class Unstringable: | ||
def __str__(self): | ||
raise Exception('no') | ||
|
||
def __repr__(self): | ||
raise Exception('nope') | ||
|
||
|
||
def test_feature_flag_has_name_and_variant(): | ||
flag = FeatureFlag('abc', 'xyz') | ||
|
||
assert flag.name == 'abc' | ||
assert flag.variant == 'xyz' | ||
|
||
|
||
def test_feature_flag_variant_is_optional(): | ||
assert FeatureFlag('a').variant is None | ||
assert FeatureFlag('a', None).variant is None | ||
|
||
|
||
def test_feature_flag_variant_is_coerced_to_string(): | ||
assert FeatureFlag('a', 123).variant == '123' | ||
assert FeatureFlag('a', [1, 2, 3]).variant == '[1, 2, 3]' | ||
|
||
|
||
def test_feature_flag_name_and_variant_can_be_bytes(): | ||
flag = FeatureFlag(b'abc', b'xyz') | ||
|
||
assert flag.name == b'abc' | ||
assert flag.variant == b'xyz' | ||
|
||
|
||
def test_feature_flag_variant_is_unset_if_not_coercable(): | ||
assert FeatureFlag('a', Unstringable()).variant is None | ||
|
||
|
||
def test_feature_flag_can_be_converted_to_dict(): | ||
flag = FeatureFlag('abc', 'xyz') | ||
|
||
assert flag.to_dict() == {'name': 'abc', 'variant': 'xyz'} | ||
|
||
|
||
def test_feature_flag_dict_does_not_have_variant_when_variant_is_not_given(): | ||
flag = FeatureFlag('xyz') | ||
|
||
assert flag.to_dict() == {'name': 'xyz'} | ||
|
||
|
||
def test_feature_flag_dict_does_not_have_variant_when_variant_is_none(): | ||
flag = FeatureFlag('abc', variant=None) | ||
|
||
assert flag.to_dict() == {'name': 'abc'} | ||
|
||
|
||
def test_a_feature_flag_with_name_and_variant_is_valid(): | ||
assert FeatureFlag('abc', 'xyz').is_valid() is True | ||
assert FeatureFlag('abc', b'xyz').is_valid() is True | ||
assert FeatureFlag(b'abc', b'xyz').is_valid() is True | ||
assert FeatureFlag(b'abc', 'xyz').is_valid() is True | ||
|
||
|
||
def test_a_feature_flag_with_only_name_is_valid(): | ||
flag = FeatureFlag('b') | ||
|
||
assert flag.is_valid() is True | ||
|
||
|
||
def test_a_feature_flag_with_empty_name_is_not_valid(): | ||
flag = FeatureFlag('') | ||
|
||
assert flag.is_valid() is False | ||
|
||
|
||
def test_a_feature_flag_with_none_name_is_not_valid(): | ||
flag = FeatureFlag(None) | ||
|
||
assert flag.is_valid() is False |