Skip to content

Instantly share code, notes, and snippets.

@jymchng
Last active December 16, 2024 07:05
Show Gist options
  • Save jymchng/f21b38a58879a8a2ee0ffb66fe31cb28 to your computer and use it in GitHub Desktop.
Save jymchng/f21b38a58879a8a2ee0ffb66fe31cb28 to your computer and use it in GitHub Desktop.

Revisions

  1. jymchng revised this gist Dec 16, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -2,4 +2,4 @@

    In the file, `env_variant.py`, the plan is to have `RollYourOwnNewTypeEnum` with variants that are only in this allowed set (`__VALID_MEMBERS__ = ["LOCAL", "DEV", "SIT", "UAT", "PREPROD", "PROD"]`).

    However, there seems to be no way to read `ENVVariant.my_replace(..)`?
    However, there seems to be no way to write `ENVVariant.my_replace(..)`?
  2. jymchng revised this gist Dec 16, 2024. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions requirements.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    pytest
  3. jymchng revised this gist Dec 16, 2024. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    # Challenge

    In the file, `env_variant.py`, the plan is to have `RollYourOwnNewTypeEnum` with variants that are only in this allowed set (`__VALID_MEMBERS__ = ["LOCAL", "DEV", "SIT", "UAT", "PREPROD", "PROD"]`).

    However, there seems to be no way to read `ENVVariant.my_replace(..)`?
  4. jymchng revised this gist Dec 16, 2024. 1 changed file with 68 additions and 0 deletions.
    68 changes: 68 additions & 0 deletions env_variant.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,68 @@
    import pytest
    from enum import Enum

    class ENVVariant(str):

    __VALID_MEMBERS__ = ["LOCAL", "DEV", "SIT", "UAT", "PREPROD", "PROD"]

    def __new__(cls, value: str):
    members = ENVVariant.__VALID_MEMBERS__
    if isinstance(value, RollYourOwnNewTypeEnum):
    value_as_str = str(value.value)
    else:
    value_as_str = str(value)
    if value_as_str not in members:
    raise ValueError(f"`value` = {value} must be one of `{members}`; `value_as_str` = {value_as_str}")
    return super().__new__(cls, value_as_str)

    # why not i write my own `.replace(..)`
    # yes, you can but how?
    def my_replace(self, old: "ENVVariant", new: "ENVVariant", count: int=-1):
    return ENVVariant(str(self).replace(str(old), str(new), count))

    class RollYourOwnNewTypeEnum(ENVVariant, Enum):

    LOCAL = "LOCAL"
    DEV = "DEV"
    SIT = "SIT"
    UAT = "UAT"
    PREPROD = "PREPROD"
    PROD = "PROD"

    def test_ryont_env_replace():

    env = RollYourOwnNewTypeEnum.LOCAL

    # expected outcomes
    assert env is RollYourOwnNewTypeEnum.LOCAL # pass
    assert env is not RollYourOwnNewTypeEnum.DEV # pass
    assert isinstance(env, RollYourOwnNewTypeEnum) # pass

    # now we try to replace
    env = env.replace(RollYourOwnNewTypeEnum.LOCAL, RollYourOwnNewTypeEnum.DEV)

    # we are hoping that it will continue to be a `RollYourOwnNewTypeEnum.DEV` but it is not
    assert env is not RollYourOwnNewTypeEnum.DEV # pass, no longer a `RollYourOwnNewTypeEnum`
    assert env is not RollYourOwnNewTypeEnum.LOCAL # pass, no longer a `RollYourOwnNewTypeEnum`
    assert not isinstance(env, RollYourOwnNewTypeEnum)
    assert isinstance(env, str) # 'downcast' (?) to `str`

    with pytest.raises(AssertionError):
    assert env is RollYourOwnNewTypeEnum.DEV

    with pytest.raises(AssertionError):
    assert env is RollYourOwnNewTypeEnum.DEV

    with pytest.raises(AssertionError):
    assert isinstance(env, RollYourOwnNewTypeEnum)

    env = env.replace("DEV", "NotAnEnv")
    assert env == "NotAnEnv" # this 'shouldn't' pass but it does

    env = RollYourOwnNewTypeEnum.LOCAL

    env = env.my_replace(RollYourOwnNewTypeEnum.LOCAL, RollYourOwnNewTypeEnum.PREPROD)

    assert isinstance(env, str)
    assert env is RollYourOwnNewTypeEnum.PREPROD
    assert isinstance(env, RollYourOwnNewTypeEnum)
  5. jymchng created this gist Dec 16, 2024.
    134 changes: 134 additions & 0 deletions newtype_enum.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,134 @@
    from newtype import NewType, newtype_exclude
    from enum import Enum
    import pytest

    class ENV(NewType(str), Enum):

    LOCAL = "LOCAL"
    DEV = "DEV"
    SIT = "SIT"
    UAT = "UAT"
    PREPROD = "PREPROD"
    PROD = "PROD"

    class RegularENV(str, Enum):

    LOCAL = "LOCAL"
    DEV = "DEV"
    SIT = "SIT"
    UAT = "UAT"
    PREPROD = "PREPROD"
    PROD = "PROD"

    class ENVVariant(str):

    __VALID_MEMBERS__ = ["LOCAL", "DEV", "SIT", "UAT", "PREPROD", "PROD"]

    def __new__(cls, value: str):
    members = ENVVariant.__VALID_MEMBERS__
    if isinstance(value, RollYourOwnNewTypeEnum):
    value_as_str = str(value.value)
    else:
    value_as_str = str(value)
    if value_as_str not in members:
    raise ValueError(f"`value` = {value} must be one of `{members}`; `value_as_str` = {value_as_str}")
    return super().__new__(cls, value_as_str)

    # why not i write my own `.replace(..)`
    # yes, you can but how?
    def my_replace(self, old: "ENVVariant", new: "ENVVariant", count: int=-1):
    return ENVVariant(str(self).replace(str(old), str(new), count))

    class RollYourOwnNewTypeEnum(ENVVariant, Enum):

    LOCAL = "LOCAL"
    DEV = "DEV"
    SIT = "SIT"
    UAT = "UAT"
    PREPROD = "PREPROD"
    PROD = "PROD"


    def test_nt_env_replace():

    env = ENV.LOCAL

    assert env is ENV.LOCAL
    assert env is not ENV.DEV
    assert isinstance(env, ENV)

    # let's say now we want to replace the environment
    # nevermind about the reason why we want to do so
    env = env.replace(ENV.LOCAL, ENV.DEV)

    # replacement is successful
    assert env is ENV.DEV
    assert env is not ENV.LOCAL

    # still an `ENV`
    assert isinstance(env, ENV)
    assert isinstance(env, str)

    with pytest.raises(ValueError):
    # cannot replace with something that is not a `ENV`
    env = env.replace(ENV.DEV, "NotAnEnv")

    with pytest.raises(ValueError):
    # cannot even make 'DEV' -> 'dev'
    env = env.lower()

    def test_reg_env_replace():

    env = RegularENV.LOCAL

    # expected outcomes
    assert env is RegularENV.LOCAL # pass
    assert env is not RegularENV.DEV # pass
    assert isinstance(env, RegularENV) # pass

    # now we try to replace
    env = env.replace(RegularENV.LOCAL, RegularENV.DEV)

    # we are hoping that it will continue to be a `RegularENV.DEV` but it is not
    assert env is not RegularENV.DEV # pass, no longer a `RegularENV`
    assert env is not RegularENV.LOCAL # pass, no longer a `RegularENV`
    assert not isinstance(env, RegularENV)
    assert isinstance(env, str) # 'downcast' (?) to `str`

    def test_ryont_env_replace():

    env = RollYourOwnNewTypeEnum.LOCAL

    # expected outcomes
    assert env is RollYourOwnNewTypeEnum.LOCAL # pass
    assert env is not RollYourOwnNewTypeEnum.DEV # pass
    assert isinstance(env, RollYourOwnNewTypeEnum) # pass

    # now we try to replace
    env = env.replace(RollYourOwnNewTypeEnum.LOCAL, RollYourOwnNewTypeEnum.DEV)

    # we are hoping that it will continue to be a `RollYourOwnNewTypeEnum.DEV` but it is not
    assert env is not RollYourOwnNewTypeEnum.DEV # pass, no longer a `RollYourOwnNewTypeEnum`
    assert env is not RollYourOwnNewTypeEnum.LOCAL # pass, no longer a `RollYourOwnNewTypeEnum`
    assert not isinstance(env, RollYourOwnNewTypeEnum)
    assert isinstance(env, str) # 'downcast' (?) to `str`

    with pytest.raises(AssertionError):
    assert env is RollYourOwnNewTypeEnum.DEV

    with pytest.raises(AssertionError):
    assert env is RollYourOwnNewTypeEnum.DEV

    with pytest.raises(AssertionError):
    assert isinstance(env, RollYourOwnNewTypeEnum)

    env = env.replace("DEV", "NotAnEnv")
    assert env == "NotAnEnv" # this 'shouldn't' pass but it does

    env = RollYourOwnNewTypeEnum.LOCAL

    env = env.my_replace(RollYourOwnNewTypeEnum.LOCAL, RollYourOwnNewTypeEnum.PREPROD)

    assert isinstance(env, str)
    assert env is RollYourOwnNewTypeEnum.PREPROD
    assert isinstance(env, RollYourOwnNewTypeEnum)