def test_read_params(): # ---- Single default kwargs kwargs = lib.read_params({'a': 0}, {'a': 1, 'b': 2}) assert kwargs == {'a': 0, 'b': 2} assert kwargs.a == 0 assert kwargs.b == 2 kwargs.b = 3 assert kwargs.b == 3 assert kwargs == {'a': 0, 'b': 3} with pytest.raises(KeyError): lib.read_params({'a': 0, 'c': 8}, {'a': 1, 'b': 2}) kwargs = lib.read_params({'a': 0, 'c': 8}, {'a': 1, 'b': 2}, safe=False) assert kwargs == {'a': 0, 'b': 2} kwargs = lib.read_params( {'a': lib.DFT, 'b': None}, {'a': 1, 'b': 2} ) assert kwargs == {'a': 1, 'b': None} # ---- Multiple default kwargs kwargs = lib.read_params( {'a': 0, 'c': 8}, [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}], ) assert kwargs == [{'a': 0, 'b': 2}, {"c": 8, "d": 4}] with pytest.raises(KeyError): lib.read_params( {'a': 0, 'c': 8, 'e': 10}, [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}], ) kwargs = lib.read_params( {'a': 0, 'c': 8, 'e': 10}, [{'a': 1, 'b': 2}, {'c': 3, 'd': 4}], safe=False ) assert kwargs == [{'a': 0, 'b': 2}, {'c': 8, 'd': 4}] kwargs = lib.read_params( {'a': 0, 'c': 8, 'e': 10}, [{'a': 1, 'b': 2, 'e': 5, 'f': 6}, {'c': 3, 'd': 4, 'e': 5, 'f': 7}], safe=False ) assert kwargs == [ {'a': 0, 'b': 2, 'e': 10, 'f': 6}, {'c': 8, 'd': 4, 'e': 10, 'f': 7}, ]
def read_align_params(kwargs, dft_kwargs, safe=False): """Read alignments parameters Args: kwargs (dict) : parameters for alignment 'h_align': (str) -> horizontal alignment (within H_ALIGN) 'v_align': (str) -> vertical alignment (within V_ALIGN) 'align': (str) -> alignment ("{h_align}-{v_align}") overwrite other params dft_kwargs (dict) : default parameters for alignment 'h_align': (str) -> horizontal alignment (within H_ALIGN) 'v_align': (str) -> vertical alignment (within V_ALIGN) safe (bool) : raise Error if kwargs has unexpected params Return: (olutils.Param): dictionary with alignment params 'h_align': (str) -> horizontal alignment (within H_ALIGN) 'v_align': (str) -> vertical alignment (within V_ALIGN) """ assert sorted(dft_kwargs.keys()) == ['h_align', 'v_align'] if 'align' in kwargs: kwargs = _read_align_param(kwargs['align']) kwargs = read_params(kwargs, dft_kwargs, safe=safe) if kwargs.h_align not in H_ALIGN: raise ValueError( f"Unknown value for adjustment '{kwargs.h_align}'" f", must be within {H_ALIGN}" ) if kwargs.v_align not in V_ALIGN: raise ValueError( f"Unknown value for adjustment '{kwargs.v_align}'" f", must be within {V_ALIGN}" ) return kwargs
def plot_projection_base(T, c1, c2, **kwargs): """Plot projection of transformed data on given principal components""" plot_kwargs = read_params(kwargs, PLOT_KWARGS) plt.scatter( T[:, c1 - 1], T[:, c2 - 1], **plot_kwargs, )
def __init__(self, **kwargs): """Initiate a linear shape Args: **kwargs : aspect of shape @see self.__class__.dft_look """ super().__init__(**kwargs) look = read_params(kwargs, self.cls.dft_look, safe=False) apply_conversions(look, self.cls.par_conv) self._params = look
def __init__(self, window, card_size, **params): params = read_params(params, GRID_PARAMS) page_x, page_y = window.settings.size x_margin, y_margin = params.pop('xy_margin') assert page_x > 2 * x_margin, "x-margin must be twice smaller than page x-size" assert page_y > 2 * y_margin, "y-margin must be twice smaller than page y-size" params['xbounds'] = (x_margin, page_x - x_margin) params['ybounds'] = (y_margin, page_y - y_margin) super().__init__(*card_size, **params) self.window = window self.init(self.window.screen)
def __init__(self, **kwargs): """Initiate window settings Args: name (str): name of window size (2-int-tuple): size of window in pixels fps (int): number of frags per seconds background (color description): color of background @see oldisplay.collections.COLORS for available colors """ params = read_params(kwargs, self.__class__.dft_params) for param, value in params.items(): self.set(param, value)
def display_word_cards(window, words, card_size, **params): """Display one grid of words on window""" params = read_params(params, WORD_PARAMS) assert window.initiated, "Window must be initialized" window.components = [] # ---- Create Grid grid_params = params.pop('grid', {}) grid = build_display_grid(window, card_size, **grid_params) # ---- Read parameters txt_height = grid.dy // params.txt_height_r txt_xmargin = grid.dx // params.txt_xmargin_r txt_ymargin = grid.dy // params.txt_ymargin_r bot_txt_font = params.top_txt_font if params.bot_txt_font is None else params.bot_txt_font bot_txt_c = params.top_txt_c if params.bot_txt_c is None else params.bot_txt_c # ---- Write Words if len(words) > grid.cell_nb: logger.warning( f"Too many words ({len(words)}) regarding the number of cells" f" ({grid.cell_nb}): will only use first ({grid.cell_nb}) words") words = words[:grid.cell_nb] for (x, y), word in grid.xy_enum(words): ym = y + grid.dy // 2 window.components += [ Text(word.upper(), (x + txt_xmargin, ym - txt_ymargin), height=txt_height, align="bot-left", color=params.top_txt_c, font=params.top_txt_font), Rectangle( (x + txt_xmargin, ym + txt_ymargin // 2), (grid.dx - 3 * txt_xmargin // 2, txt_height + txt_ymargin), color=params.bot_txt_rect, ), Text(word.upper(), (x + grid.dx - txt_xmargin, ym + txt_ymargin), height=txt_height, align="top-right", rotate=180, color=bot_txt_c, font=bot_txt_font), ] logger.debug(f"{len(words)} word cards displayed on window")
def display_board_cards(window, card_size, **params): """Display validation cards on window""" params = read_params(params, BOARD_PARAMS) assert window.initiated, "Window must be initialized" window.components = [] # Main grid grid_params = params.pop('grid', {}) grid = build_display_grid(window, card_size, **grid_params) # Card grids cell_dx = grid.dx // params.board_size[0] cell_dy = grid.dy // params.board_size[1] cell_di, cell_dj = params.board_size colors = [params.t1_color, params.t2_color] * (grid.cell_nb // 2) for (x, y), color in grid.xy_enum(colors): # Inner grid window.components.append( Grid( cell_dx, cell_dy, xbounds=(x, x + grid.dx), ybounds=(y, y + grid.dy), color=color, only_inside=True, )) # Card colors positions = [(x + i * cell_dx, y + j * cell_dy) for i in range(cell_di) for j in range(cell_dj)] card_colors = ([params.t1_color] * params.guess_nb + [params.t2_color] * params.guess_nb + [color, params.death_color]) assert len(card_colors) < len(positions) card_colors += [params.neutral_color ] * (len(positions) - len(card_colors)) rd.shuffle(card_colors) radius = min(cell_dx, cell_dx) // (params.form_ratio * 2) for (x, y), color in zip(positions, card_colors): window.components.append( Disk((x + cell_dx // 2, y + cell_dy // 2), radius=radius, color=color)) logger.debug(f"{len(colors)} board cards displayed on window")
def display_validation_cards(window, card_size, **params): """Display validation cards on window""" params = read_params(params, VALIDATION_PARAMS) assert window.initiated, "Window must be initialized" window.components = [] # ---- Display grid grid_params = params.pop('grid', {}) grid = build_display_grid(window, card_size, **grid_params) # Display cards content colors = ([params.t1_color] * params.guess_nb + [params.t2_color] * params.guess_nb + [Color.mix(params.t1_color, params.t2_color)]) assert len(colors) <= (grid.i_max * grid.j_max), ( "Not enough space to display all validation cards") sx, sy = grid.dx // params.form_ratio, grid.dy // params.form_ratio for (x, y), color in grid.xy_enum(colors): x, y = x + grid.dx // 2, y + grid.dy // 2 window.components.append( Rectangle((x, y), (sx, sy), color=color, align='center')) logger.debug(f"{len(colors)} validation cards displayed on window")
def split_params(params, n, dft_value=DFT, extend_type=tuple, dft_params=None, safe=False): """Split an extended dict of params into n dicts of params Args: params (dict) : extended params to split for a given parameter, one can give 1-to-n values within an object of type extend_type. Value at position i will correspond to value of param for i_th dictionary. If a value is default, the value will be replaced by the one in previous dictionary n (int) : number of dict of params to build dft_value (object) : default object to use as default value if i_th value of a param equal to default, its value is replaced by the one of (i-1)_th extend_type (type|tuple[type]): type used to extend values of params must be iterable type dft_params (dict) : default parameters safe (bool) : raise error when params are not in dft_params Examples: >>> params = {'a': 1, 'b': (2, 20), 'c': (3, DFT, 30)} >>> split_params(params, 3) [ {'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 20, 'c': 3}, {'a': 1, 'b': 20, 'c': 30}, ] >>> params = {'a': 1, 'b': DFT, 'c': 3} >>> split_params(params, 3) [{'a': 1, 'b': DFT, 'c': 3}, None, None] >>> params = {'a': 10, 'b': DFT, '?': 1} >>> dft_params = {'a': 1, 'b': 2, 'c': 3} >>> split_params(params, 3, dft_params=dft_params) ({'a': 10, 'b': 2, 'c': 3}, None, None) >>> params = {'a': 10, 'b': (DFT, 30)} >>> dft_params = {'a': 1, 'b': 2} >>> split_params(params, 3, dft_params=dft_params) ({'a': 10, 'b': 2}, {'a': 10, 'b': 30}, None) >>> params = { ... 'a': (10,), ... 'b': (DFT, 20), ... 'c': (30, DFT, 40), # hovered c value will be same as normal ... 'd': (DFT, 40, DFT), # clicked d value will be same as hovered ... } >>> dft_params = {'a': 1, 'b': 2, 'c': 3, 'd': 4} >>> split_params(params, 3, dft_params=dft_params) ( {'a': 10, 'b': 2, 'c': 30, 'd': 4}, {'a': 10, 'b': 20, 'c': 30, 'd': 40}, {'a': 10, 'b': 20, 'c': 40, 'd': 40}, ) Return: (list[Param|NoneType]): n dict of params """ assert n > 0 # Read params param_dicts = [{} for i in range(n)] for key, extend_val in params.items(): if not isinstance(extend_val, extend_type): param_dicts[0][key] = extend_val continue prev_val = dft_value for i, val in enumerate(extend_val): try: param_dicts[i][key] = prev_val if val is dft_value else val except IndexError: raise ValueError( f"Parameter '{key}' has more than n={n} values") prev_val = val # Complete params prev_kwargs = dft_params if dft_params else param_dicts[0] result = [] for kwargs in param_dicts: if not kwargs: result.append(None) continue kwargs = read_params(kwargs, prev_kwargs, safe=safe, default=dft_value) result.append(kwargs) prev_kwargs = kwargs return result