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)
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()
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()
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
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'))
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()
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)