Ejemplo n.º 1
0
def test_coerce() -> None:
    """Test value coercion."""
    @dataclass
    class _TestClass:
        ival: int = 0
        fval: float = 0.0

    # Float value present for int should never work.
    obj = _TestClass()
    # noinspection PyTypeHints
    obj.ival = 1.0  # type: ignore
    with pytest.raises(TypeError):
        dataclass_validate(obj, coerce_to_float=True)
    with pytest.raises(TypeError):
        dataclass_validate(obj, coerce_to_float=False)

    # Int value present for float should work only with coerce on.
    obj = _TestClass()
    obj.fval = 1
    dataclass_validate(obj, coerce_to_float=True)
    with pytest.raises(TypeError):
        dataclass_validate(obj, coerce_to_float=False)

    # Likewise, passing in an int for a float field should work only
    # with coerce on.
    dataclass_from_dict(_TestClass, {'fval': 1}, coerce_to_float=True)
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'fval': 1}, coerce_to_float=False)

    # Passing in floats for an int field should never work.
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'ival': 1.0}, coerce_to_float=True)
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'ival': 1.0}, coerce_to_float=False)
Ejemplo n.º 2
0
    def _hosting_state_response(self, result: Optional[Dict[str,
                                                            Any]]) -> None:

        # Its possible for this to come back to us after our UI is dead;
        # ignore in that case.
        if not self._container:
            return

        state: Optional[HostingState] = None
        if result is not None:
            self._debug_server_comm('got private party state response')
            try:
                state = dataclass_from_dict(HostingState, result)
            except Exception:
                pass
        else:
            self._debug_server_comm('private party state response errored')

        # Hmm I guess let's just ignore failed responses?...
        # Or should we show some sort of error state to the user?...
        if result is None or state is None:
            return

        self._waiting_for_initial_state = False
        self._waiting_for_start_stop_response = False
        self._hostingstate = state
        self._refresh_sub_tab()
Ejemplo n.º 3
0
    def _load_config(self) -> ServerConfig:
        user_config_path = 'config.yaml'

        if os.path.exists(user_config_path):
            import yaml
            with open(user_config_path) as infile:
                user_config_raw = yaml.safe_load(infile.read())

            # An empty config file will yield None, and that's ok.
            if user_config_raw is not None:
                return dataclass_from_dict(ServerConfig, user_config_raw)

        # Go with defaults if we weren't able to load anything.
        return ServerConfig()
Ejemplo n.º 4
0
    def _load_config_from_file(self, print_confirmation: bool) -> ServerConfig:

        out: Optional[ServerConfig] = None

        if not os.path.exists(self._config_path):

            # Special case:
            # If the user didn't specify a particular config file, allow
            # gracefully falling back to defaults if the default one is
            # missing.
            if not self._user_provided_config_path:
                if print_confirmation:
                    print(
                        f'{Clr.YLW}Default config file not found'
                        f' (\'{self._config_path}\'); using default'
                        f' settings.{Clr.RST}',
                        flush=True)
                self._config_mtime = None
                self._last_config_mtime_check_time = time.time()
                return ServerConfig()

            # Don't be so lenient if the user pointed us at one though.
            raise RuntimeError(
                f"Config file not found: '{self._config_path}'.")

        import yaml
        with open(self._config_path) as infile:
            user_config_raw = yaml.safe_load(infile.read())

        # An empty config file will yield None, and that's ok.
        if user_config_raw is not None:
            out = dataclass_from_dict(ServerConfig, user_config_raw)

        # Update our known mod-time since we know it exists.
        self._config_mtime = Path(self._config_path).stat().st_mtime
        self._last_config_mtime_check_time = time.time()

        # Go with defaults if we weren't able to load anything.
        if out is None:
            out = ServerConfig()

        if print_confirmation:
            print(f'{Clr.CYN}Valid server config file loaded.{Clr.RST}',
                  flush=True)
        return out
Ejemplo n.º 5
0
 def _connect_response(self, result: Optional[Dict[str, Any]]) -> None:
     try:
         self._connect_press_time = None
         if result is None:
             raise RuntimeError()
         cresult = dataclass_from_dict(ConnectResult, result)
         if cresult.error is not None:
             self._debug_server_comm('got error connect response')
             ba.screenmessage(
                 ba.Lstr(translate=('serverResponses', cresult.error)),
                 (1, 0, 0))
             ba.playsound(ba.getsound('error'))
             return
         self._debug_server_comm('got valid connect response')
         assert cresult.addr is not None and cresult.port is not None
         _ba.connect_to_party(cresult.addr, port=cresult.port)
     except Exception:
         self._debug_server_comm('got connect response error')
         ba.playsound(ba.getsound('error'))
Ejemplo n.º 6
0
    def _hosting_state_response(self, result: Optional[Dict[str,
                                                            Any]]) -> None:
        state: Optional[HostingState] = None
        if result is not None:
            self._debug_server_comm('got private party state response')
            try:
                state = dataclass_from_dict(HostingState, result)
            except Exception:
                pass
        else:
            self._debug_server_comm('private party state response errored')

        # Hmm I guess let's just ignore failed responses?...
        # Or should we show some sort of error state to the user?...
        if result is None or state is None:
            return

        self._initial_waiting_for_hosting_state = False
        self._waiting_for_hosting_state = False
        self._hostingstate = state
        self._refresh_sub_tab()
Ejemplo n.º 7
0
def test_assign() -> None:
    """Testing various assignments."""

    # pylint: disable=too-many-statements

    @dataclass
    class _TestClass:
        ival: int = 0
        sval: str = ''
        bval: bool = True
        fval: float = 1.0
        nval: _NestedClass = field(default_factory=_NestedClass)
        enval: _EnumTest = _EnumTest.TEST1
        oival: Optional[int] = None
        osval: Optional[str] = None
        obval: Optional[bool] = None
        ofval: Optional[float] = None
        oenval: Optional[_EnumTest] = _EnumTest.TEST1
        lsval: List[str] = field(default_factory=list)
        lival: List[int] = field(default_factory=list)
        lbval: List[bool] = field(default_factory=list)
        lfval: List[float] = field(default_factory=list)
        lenval: List[_EnumTest] = field(default_factory=list)
        ssval: Set[str] = field(default_factory=set)

    class _TestClass2:
        pass

    # Attempting to use with non-dataclass should fail.
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass2, {})

    # Attempting to pass non-dicts should fail.
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, [])  # type: ignore
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, None)  # type: ignore

    # Passing an attr not in the dataclass should fail.
    with pytest.raises(AttributeError):
        dataclass_from_dict(_TestClass, {'nonexistent': 'foo'})

    # A dict containing *ALL* values should match what we
    # get when creating a dataclass and then converting back
    # to a dict.
    dict1 = {
        'ival': 1,
        'sval': 'foo',
        'bval': True,
        'fval': 2.0,
        'nval': {
            'ival': 1,
            'sval': 'bar'
        },
        'enval': 'test1',
        'oival': 1,
        'osval': 'foo',
        'obval': True,
        'ofval': 1.0,
        'oenval': 'test2',
        'lsval': ['foo'],
        'lival': [10],
        'lbval': [False],
        'lfval': [1.0],
        'lenval': ['test1', 'test2'],
        'ssval': ['foo']
    }
    dc1 = dataclass_from_dict(_TestClass, dict1)
    assert dataclass_to_dict(dc1) == dict1

    # A few other assignment checks.
    assert isinstance(
        dataclass_from_dict(
            _TestClass, {
                'oival': None,
                'osval': None,
                'obval': None,
                'ofval': None,
                'lsval': [],
                'lival': [],
                'lbval': [],
                'lfval': [],
                'ssval': []
            }), _TestClass)
    assert isinstance(
        dataclass_from_dict(
            _TestClass, {
                'oival': 1,
                'osval': 'foo',
                'obval': True,
                'ofval': 2.0,
                'lsval': ['foo', 'bar', 'eep'],
                'lival': [10, 11, 12],
                'lbval': [False, True],
                'lfval': [1.0, 2.0, 3.0]
            }), _TestClass)

    # Attr assigns mismatched with their value types should fail.
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'ival': 'foo'})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'sval': 1})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'bval': 2})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'oival': 'foo'})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'osval': 1})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'obval': 2})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'ofval': 'blah'})
    with pytest.raises(ValueError):
        dataclass_from_dict(_TestClass, {'oenval': 'test3'})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'lsval': 'blah'})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'lsval': ['blah', None]})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'lsval': [1]})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'lsval': (1, )})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'lbval': [None]})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'lival': ['foo']})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'lfval': [True]})
    with pytest.raises(ValueError):
        dataclass_from_dict(_TestClass, {'lenval': ['test1', 'test3']})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'ssval': [True]})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'ssval': {}})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'ssval': set()})

    # More subtle attr/type mismatches that should fail
    # (we currently require EXACT type matches).
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'ival': True})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'fval': 2}, coerce_to_float=False)
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'bval': 1})
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'ofval': 1}, coerce_to_float=False)
    with pytest.raises(TypeError):
        dataclass_from_dict(_TestClass, {'lfval': [1]}, coerce_to_float=False)