Coverage for pandalone\xlref\_xlref.py : 99%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
#!/usr/bin/env python # -*- coding: UTF-8 -*- # # Copyright 2014 European Commission (JRC); # Licensed under the EUPL (the 'Licence'); # You may not use this work except in compliance with the Licence. # You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl The user-facing implementation of *xlref*.
Prefer accessing the public members from the parent module. """
# TODO: Try different backends providing `colname` function. except ImportError: log.warning( 'One of `xlrd`, `...` libraries is needed, failures might occure later!')
"""When `True`, most coord-functions accept any 2-tuples."""
""" A pair of 1-based strings, denoting the "A1" coordinates of a cell.
The "num" coords (numeric, 0-based) are specified using numpy-arrays (:class:`Coords`). """
""" A pair of 0-based integers denoting the "num" coordinates of a cell.
The "A1" coords (1-based coordinates) are specified using :class:`Cell`. """ # return np.array([row, cell], dtype=np.int16)
"""Make *A1* :class:`Cell` from *resolved* coords, with rudimentary error-checking.
Examples::
>>> coords2Cell(row=0, col=0) Cell(row='1', col='A') >>> coords2Cell(row=0, col=26) Cell(row='1', col='AA')
>>> coords2Cell(row=10, col='.') Cell(row='11', col='.')
>>> coords2Cell(row=-3, col=-2) Traceback (most recent call last): AssertionError: negative row!
"""
""" An :term:`Edge` might be "cooked" or "uncooked" depending on its `land`:
- An *uncooked* edge contains *A1* :class:`Cell`. - An *cooked* edge contains a *resolved* :class:`Coords`.
Use None for missing moves. """
""" Make a new `Edge` from any non-values supplied, as is capitalized, or nothing.
:param str, None col: ie ``A`` :param str, None row: ie ``1`` :param str, None mov: ie ``RU1D?``
:return: a `Edge` if any non-None :rtype: Edge, None
Examples::
>>> tr = _uncooked_Edge('1', 'a', 'Rul') >>> tr Edge(land=Cell(row='1', col='A'), mov='RUL')
No error checking performed::
>>> _uncooked_Edge('Any', 'foo', 'BaR') Edge(land=Cell(row='Any', col='FOO'), mov='BAR')
>>> print(_uncooked_Edge(None, None, None)) None
except were coincidental::
>>> _uncooked_Edge(row=0, col=123, mov='BAR') Traceback (most recent call last): AttributeError: 'int' object has no attribute 'upper'
>>> _uncooked_Edge(row=0, col='A', mov=123) Traceback (most recent call last): AttributeError: 'int' object has no attribute 'upper' """
'L': Coords(0, -1), 'U': Coords(-1, 0), 'R': Coords(0, 1), 'D': Coords(1, 0) }
r""" ^\s*(?:(?P<sheet>[^!]+)?!)? # xl sheet name (?: # first cell (?P<st_col>[A-Z]+|_|\^) # first col (?P<st_row>[123456789]\d*|_|\^) # first row (?:\( (?P<st_mov>L|U|R|D|LD|LU|UL|UR|RU|RD|DL|DR) # moves from st cell \) )? ) (?:: # second cell [opt] (?P<nd_col>[A-Z]+|_|\^|\.) # second col (?P<nd_row>[123456789]\d*|_|\^|\.) # second row (?:\( (?P<nd_mov>L|U|R|D|LD|LU|UL|UR|RU|RD|DL|DR) # moves from nd cell \) )? (?:: (?P<rect_exp>[LURD?123456789]+) # rect expansion [opt] )? )? \s* (?::? (?P<json>\{.*\})? # any json object [opt] )\s*$""", re.IGNORECASE | re.X)
# TODO: Make rect_expansions `?` work different from numbers. r""" ^(?P<moves>[LURD]+) # primitive moves (?P<times>\?|\d+)? # repetition times $""", re.IGNORECASE | re.X)
""" Returns an iterator that repeats `moves` x `times`, or infinite if unspecified.
Used when parsing primitive :term:`directions`.
:param str moves: the moves to repeat :param str times: N of repetitions. If `None` it means infinite repetitions. :return: An iterator of the moves :rtype: iterator
Examples::
>>> list(_repeat_moves('LUR', '3')) ['LUR', 'LUR', 'LUR'] >>> list(_repeat_moves('ABC', '0')) [] >>> _repeat_moves('ABC') ## infinite repetitions repeat('ABC') """
""" Parse rect-expansion into a list of dir-letters iterables.
:param rect_exp: A string with a sequence of primitive moves: es. L1U1R1D1 :type xl_ref: str
:return: A list of primitive-dir chains. :rtype: list
Examples::
>>> res = _parse_rect_expansions('LURD?') >>> res [repeat('LUR'), repeat('D', 1)]
# infinite generator >>> [next(res[0]) for i in range(10)] ['LUR', 'LUR', 'LUR', 'LUR', 'LUR', 'LUR', 'LUR', 'LUR', 'LUR', 'LUR']
>>> list(res[1]) ['D']
>>> _parse_rect_expansions('1LURD') Traceback (most recent call last): ValueError: Invalid rect-expansion(1LURD) due to: 'NoneType' object has no attribute 'groupdict'
"""
for v in res if v != '']
""" Parses a :term:`xl-ref` and splits it in its "ingredients".
:param str xl_ref: a string with the following format: <sheet>!<st_col><st_row>(<st_mov>):<nd_col><nd_row>(<nd_mov>): <rect_exp>{<json>} i.e.::
sheet!A1(DR):Z20(UL):L1U2R1D1{"json":"..."}
:return: dictionary containing the following parameters::
- sheet: str - st_edge: (Edge, None) the 1st-ref, uncooked, with raw cell - nd_edge: (Edge, None) the 2nd-ref, uncooked, with raw cell - rect_exp: (str) as found on the xl-ref - json: parsed
:rtype: dict
Examples::
>>> res = parse_xl_ref('Sheet1!A1(DR):Z20(UL):L1U2R1D1:{"json":"..."}') >>> sorted(res.items()) [('json', {'json': '...'}), ('nd_edge', Edge(land=Cell(row='20', col='Z'), mov='UL')), ('rect_exp', [repeat('L', 1), repeat('U', 2), repeat('R', 1), repeat('D', 1)]), ('sheet', 'Sheet1'), ('st_edge', Edge(land=Cell(row='1', col='A'), mov='DR'))]
>>> parse_xl_ref('A1(DR)Z20(UL)') Traceback (most recent call last): ValueError: Invalid xl-ref(A1(DR)Z20(UL)) due to: not an `xl-ref` syntax. """
# Replace coords of 1st and 2nd cells # with "uncooked" edge. #
""" Parses a :term:`xl-url`.
:param str url: a string with the following format::
<url_file>#<sheet>!<1st_edge>:<2nd_edge>:<expand><json>
Exxample::
file:///path/to/file.xls#sheet_name!UP10:DN20:LDL1{"dim":2} :param XlUrl base_url: :param module backend: one of :mod:`_xlrd` or mod:`_xlwings`
:return: dictionary containing the following parameters::
- url_file - sheet - st_col - st_row - st_mov - nd_col - nd_row - nd_mov - json
:rtype: dict
Examples::
>>> url = 'file:///sample.xlsx#Sheet1!A1(UL):.^(DR):LU?:{"2": "ciao"}' >>> res = parse_xl_url(url) >>> sorted(res.items()) [('json', {'2': 'ciao'}), ('nd_edge', Edge(land=Cell(row='^', col='.'), mov='DR')), ('rect_exp', [repeat('L'), repeat('U', 1)]), ('sheet', 'Sheet1'), ('st_edge', Edge(land=Cell(row='1', col='A'), mov='UL')), ('url_file', 'file:///sample.xlsx')] """
""" Returns top-left/bottom-down margins of full cells from a :term:`state` matrix.
May be used by :meth:`_Spreadsheet.get_margin_coords()` if a backend does not report the sheet-margins internally.
:param np.ndarray states_matrix: A 2D-array with `False` wherever cell are blank or empty. Use :meth:`_Spreadsheet.get_states_matrix()` to derrive it. :return: the 2 coords of the top-left & bottom-right full cells :rtype: (Coords, Coords)
Examples::
>>> states_matrix = np.asarray([ ... [0, 0, 0], ... [0, 1, 0], ... [0, 1, 1], ... [0, 0, 1], ... ]) >>> margins = _margin_coords_from_states_matrix(states_matrix) >>> margins (Coords(row=1, col=1), Coords(row=3, col=2))
Note that the botom-left cell is not the same as `states_matrix` matrix size::
>>> states_matrix = np.asarray([ ... [0, 0, 0, 0], ... [0, 1, 0, 0], ... [0, 1, 1, 0], ... [0, 0, 1, 0], ... [0, 0, 0, 0], ... ]) >>> _margin_coords_from_states_matrix(states_matrix) == margins True
"""
# return indices.min(0), indices.max(0)
""" Resolves special coords or converts Excel 1-based rows to zero-based, reporting invalids.
:param str, int coord: excel-row coordinate or one of ``^_.`` :return: excel row number, >= 0 :rtype: int
Examples::
>>> row = _row2num('1') >>> row 0 >>> row == _row2num(1) True >>> _row2num('-1') -2
Fails ugly::
>>> _row2num('.') Traceback (most recent call last): ValueError: invalid literal for int() with base 10: '.' """
""" Resolves special coords or converts Excel A1 columns to a zero-based, reporting invalids.
:param str coord: excel-column coordinate or one of ``^_.`` :return: excel column number, >= 0 :rtype: int
Examples::
>>> col = _col2num('D') >>> col 3 >>> _col2num('d') == col True >>> _col2num('AaZ') 727
Fails ugly::
>>> _col2num('12') Traceback (most recent call last): ValueError: substring not found
>>> _col2num(1) Traceback (most recent call last): TypeError: 'int' object is not iterable """
""" Translates special coords or converts Excel string 1-based rows/cols to zero-based, reporting invalids.
:param str cname: the coord-name, one of 'row', 'column' :param function cfunc: the function to convert coord ``str --> int`` :param int, str coord: the "A1" coord to translate :param int up_coord: the resolved *top* or *left* margin coordinate :param int up_coord: the resolved *bottom* or *right* margin coordinate :param int, None base_coord: the resolved basis for dependent coord, if any
:return: the resolved coord or `None` if it were not a special coord.
Row examples::
>>> cname = 'row'
>>> r0 = _resolve_coord(cname, _row2num, '1', 1, 10) >>> r0 0 >>> r0 == _resolve_coord(cname, _row2num, 1, 1, 10) True >>> _resolve_coord(cname, _row2num, '^', 1, 10) 1 >>> _resolve_coord(cname, _row2num, '_', 1, 10) 10 >>> _resolve_coord(cname, _row2num, '.', 1, 10, 13) 13
But notice when base-cell missing::
>>> _resolve_coord(cname, _row2num, '.', 0, 10, base_coord=None) Traceback (most recent call last): ValueError: invalid row('.') due to: '.'
Other ROW error-checks::
>>> _resolve_coord(cname, _row2num, '0', 0, 10) Traceback (most recent call last): ValueError: invalid row('0') due to: resolved to negative(-1)!
>>> _resolve_coord(cname, _row2num, 'a', 0, 10) Traceback (most recent call last): ValueError: invalid row('a') due to: invalid literal for int() with base 10: 'a'
>>> _resolve_coord(cname, _row2num, None, 0, 10) Traceback (most recent call last): ValueError: invalid row(None) due to: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
Column examples::
>>> cname = 'column'
>>> _resolve_coord(cname, _col2num, 'A', 1, 10) 0 >>> _resolve_coord(cname, _col2num, 'DADA', 1, 10) 71084 >>> _resolve_coord(cname, _col2num, '.', 1, 10, 13) 13
And COLUMN error-checks::
>>> _resolve_coord(cname, _col2num, None, 0, 10) Traceback (most recent call last): ValueError: invalid column(None) due to: 'NoneType' object is not iterable
>>> _resolve_coord(cname, _col2num, '4', 0, 10) Traceback (most recent call last): ValueError: invalid column('4') due to: substring not found
>>> _resolve_coord(cname, _col2num, 4, 0, 10) Traceback (most recent call last): ValueError: invalid column(4) due to: 'int' object is not iterable
""" '^': up_coord, '_': dn_coord } else:
""" Translates any special coords to absolute ones.
To get the margin_coords, use one of:
* :meth:`_Spreadsheet.get_margin_coords()` * :func:`_margin_coords_from_states_matrix()`
:param Cell cell: The "A1" cell to translate its coords. :param Coords up_coords: the top-left resolved coords with full-cells :param Coords dn_coords: the bottom-right resolved coords with full-cells :param Coords base_cords: A resolved cell to base dependent coords (``.``). :return: the resolved cell-coords :rtype: Coords
Examples::
>>> up = Coords(1, 2) >>> dn = Coords(10, 6) >>> base = Coords(40, 50)
>>> _resolve_cell(Cell(col='B', row=5), up, dn) Coords(row=4, col=1)
>>> _resolve_cell(Cell('^', '^'), up, dn) Coords(row=1, col=2)
>>> _resolve_cell(Cell('_', '_'), up, dn) Coords(row=10, col=6)
>>> base == _resolve_cell(Cell('.', '.'), up, dn, base) True
>>> _resolve_cell(Cell('1', '5'), up, dn) Traceback (most recent call last): ValueError: invalid cell(Cell(row='1', col='5')) due to: invalid col('5') due to: substring not found
>>> _resolve_cell(Cell('A', 'B'), up, dn) Traceback (most recent call last): ValueError: invalid cell(Cell(row='A', col='B')) due to: invalid row('A') due to: invalid literal for int() with base 10: 'A'
But notice when base-cell missing::
>>> _resolve_cell(Cell('1', '.'), up, dn) Traceback (most recent call last): ValueError: invalid cell(Cell(row='1', col='.')) due to: invalid col('.') due to: '.'
""" else: up_coords[0], dn_coords[0], base_row) up_coords[1], dn_coords[1], base_col)
ex)
# VECTO_SLICE REVERSE COORD_INDEX 'L': (1, -1, lambda r, c: (r, slice(None, c + 1))), 'U': (0, -1, lambda r, c: (slice(None, r + 1), c)), 'R': (1, 1, lambda r, c: (r, slice(c, None))), 'D': (0, 1, lambda r, c: (slice(r, None), c)), }
mov_slices=_mov_slices):
primitive_dir_vectors=_primitive_dir_vectors): """ Scan row-by-row (or column-by-column) on specified `moves` and stop on the 1st full-cell.
:param np.ndarray states_matrix: A 2D-array with `False` wherever cell are blank or empty. Use :meth:`_Spreadsheet.get_states_matrix()` to derrive it. :param Coords dn_coords: the bottom-right for the top-left of full-cells :param Coords land: the landing-cell :param moves: which MUST not be empty :return: the identified target-cell's coordinates :rtype: Coords
Examples::
>>> states_matrix = np.array([ ... [0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0], ... [0, 0, 0, 1, 1, 1], ... [0, 0, 1, 0, 0, 1], ... [0, 0, 1, 1, 1, 1] ... ]) >>> args = (states_matrix, Coords(4, 5))
>>> _target_opposite(*(args + (Coords(0, 0), 'DR'))) Coords(row=3, col=2)
>>> _target_opposite(*(args + (Coords(0, 0), 'RD'))) Coords(row=2, col=3)
It fails if a non-empty target-cell cannot be found, or it ends-up beyond bounds::
>>> _target_opposite(*(args + (Coords(0, 0), 'D'))) Traceback (most recent call last): ValueError: No opposite-target for landing-Coords(row=0, col=0) with movement(D)!
>>> _target_opposite(*(args + (Coords(0, 0), 'UR'))) Traceback (most recent call last): ValueError: No opposite-target for landing-Coords(row=0, col=0) with movement(UR)!
But notice that the landing-cell maybe outside of bounds::
>>> _target_opposite(*(args + (Coords(3, 10), 'L'))) Coords(row=3, col=5)
"""
# if states_matrix[target].all(): # return Coords(*target)
# Limit negative coords, since they are valid indices. states_matrix, dn_coords, target, mov1) else:
""" :param np.ndarray states_matrix: A 2D-array with `False` wherever cell are blank or empty. Use :meth:`_Spreadsheet.get_states_matrix()` to derrive it. :param Coords dn_coords: the bottom-right for the top-left of full-cells :param Coords dn_coords: the bottom-right for the top-left of full-cells :param Coords land: The landing-cell, which MUST be full! """ states_matrix, dn_coords, land, mov) else:
""" Scan term:`exterior` row and column on specified `moves` and stop on the last full-cell.
:param Coords states_matrix: A 2D-array with `False` wherever cell are blank or empty. Use :meth:`_Spreadsheet.get_states_matrix()` to derrive it. :param Coords dn_coords: the bottom-right for the top-left of full-cells :param Coords land: the landing-cell which MUST be within bounds :param moves: which MUST not be empty :return: the identified target-cell's coordinates :rtype: Coords
Examples::
>>> states_matrix = np.array([ ... [0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0], ... [0, 0, 0, 1, 1, 1], ... [0, 0, 1, 0, 0, 1], ... [0, 0, 1, 1, 1, 1] ... ]) >>> args = (states_matrix, Coords(4, 5))
>>> _target_same(*(args + (Coords(4, 5), 'U'))) Coords(row=2, col=5)
>>> _target_same(*(args + (Coords(4, 5), 'L'))) Coords(row=4, col=2)
>>> _target_same(*(args + (Coords(4, 5), 'UL', ))) Coords(row=2, col=2)
It fails if landing is empty or beyond bounds::
>>> _target_same(*(args + (Coords(2, 2), 'DR'))) Traceback (most recent call last): ValueError: No same-target for landing-Coords(row=2, col=2) with movement(DR)!
>>> _target_same(*(args + (Coords(10, 3), 'U'))) Traceback (most recent call last): ValueError: No same-target for landing-Coords(row=10, col=3) with movement(U)!
"""
np.array(land), mov)
""" Applies the :term:`expansion-moves` based on the `states_matrix`.
:param state: :param xl_rect: :param Coords states_matrix: A 2D-array with `False` wherever cell are blank or empty. Use :meth:`_Spreadsheet.get_states_matrix()` to derrive it. :param exp_mov: :return:
Examples::
>>> states_matrix = np.array([ ... [0, 0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 1, 1, 1], ... [0, 0, 0, 1, 0, 0, 1], ... [0, 0, 0, 1, 1, 1, 1] ... ])
>>> rng = (Coords(6, 3), Coords(6, 3)) >>> exp_mov = [_repeat_moves('U')] >>> _expand_rect(states_matrix, True, rng, exp_mov) [Coords(row=6, col=3), Coords(row=6, col=3)]
>>> rng = (Coords(6, 3), Coords(7, 3)) >>> exp_mov = [_repeat_moves('R')] >>> _expand_rect(states_matrix, True, rng, exp_mov) [Coords(row=6, col=3), Coords(row=7, col=6)]
>>> rng = (Coords(6, 3), Coords(10, 3)) >>> exp_mov = [_repeat_moves('R')] >>> _expand_rect(states_matrix, True, rng, exp_mov) [Coords(row=6, col=3), Coords(row=10, col=6)]
>>> rng = (Coords(6, 5), Coords(6, 5)) >>> exp_mov = [_repeat_moves('LURD')] >>> _expand_rect(states_matrix, True, rng, exp_mov) [Coords(row=5, col=3), Coords(row=7, col=6)]
""" 'L': (0, 1), 'U': (0, 1), 'R': (1, 0), 'D': (1, 0), } else:
# return xl_rect
nd_edge=None, rect_exp=None): """ Performs :term:`targeting`, :term:`capturing` and :term:`expansions` based on the :term:`st_states-matrix`.
To get the margin_coords, use one of:
* :meth:`_Spreadsheet.get_margin_coords()` * :func:`_margin_coords_from_states_matrix()`
Its results can be fed into :func:`read_capture_values()`.
:param Coords states_matrix: A 2D-array with `False` wherever cell are blank or empty. Use :meth:`_Spreadsheet.get_states_matrix()` to derrive it. :param Coords up_coords: the top-left coords with full-cells :param Coords dn_coords: the bottom-right coords with full-cells :param Edge st_edge: "uncooked" as matched by regex :param Edge nd_edge: "uncooked" as matched by regex :param list or none rect_exp: the result of :func:`_parse_rect_expansions()`
:return: a ``(Coords, Coords)`` with the 1st and 2nd :term:`capture-cell` ordered from top-left --> bottom-right. :rtype: tuple
Examples::
>>> states_matrix = np.array([ ... [0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0], ... [0, 0, 0, 1, 1, 1], ... [0, 0, 1, 0, 0, 1], ... [0, 0, 1, 1, 1, 1] ... ], dtype=bool) >>> up, dn = _margin_coords_from_states_matrix(states_matrix)
>>> st_edge = Edge(Cell('1', 'A'), 'DR') >>> nd_edge = Edge(Cell('.', '.'), 'DR') >>> resolve_capture_rect(states_matrix, up, dn, st_edge, nd_edge) (Coords(row=3, col=2), Coords(row=4, col=2))
Walking backwards::
>>> st_edge = Edge(Cell('_', '_'), None) >>> nd_edge = Edge(Cell('.', '.'), 'UL') >>> rect = resolve_capture_rect(states_matrix, up, dn, st_edge, nd_edge) >>> rect (Coords(row=2, col=2), Coords(row=4, col=5))
>>> st_edge = Edge(Cell('^', '_'), None) >>> nd_edge = Edge(Cell('_', '^'), None) >>> rect == resolve_capture_rect(states_matrix, up, dn, st_edge, nd_edge) True
"""
else:
else:
else:
# Order rect-cells. # #capt_rect = c.min(0), c.max(0)
""" Extracts :term:`capture-rect` values from excel-sheet and apply :term:`filters`.
:param sheet: anything supporting the :func:`read_rect(states_matrix, xl_rect)` such as the the :class:`_Spreadsheet` which can hide away the backend-module . :param (Coords, Coords) xl_rect: the the top-left/bottom/right edges of capture-rect, inclusive :return: the rect values TODO: pre-processed
.. testsetup:: >>> import os, tempfile, xlrd, pandas as pd
>>> df = pd.DataFrame([ ... # Cols: 0 1 2 ... [None, None, None], ... [5.1, 6.1, 7.1] ... ]) >>> tmp = ''.join([tempfile.mkstemp()[1], '.xlsx']) >>> writer = pd.ExcelWriter(tmp) >>> df.to_excel(writer, 'Sheet1', startrow=5, startcol=3) >>> writer.save()
Examples:: >>> import xlrd >>> from pandalone import xlref
>>> xwb = xlrd.open_workbook(tmp).sheet_by_name('Sheet1') >>> sheet = xlref.wrap_sheet(xwb) >>> sheet.get_states_matrix() array([[False, False, False, False, False, False, False], [False, False, False, False, False, False, False], [False, False, False, False, False, False, False], [False, False, False, False, False, False, False], [False, False, False, False, False, False, False], [False, False, False, False, True, True, True], [False, False, False, True, False, False, False], [False, False, False, True, True, True, True]], dtype=bool)
# minimum matrix in the sheet >>> read_capture_rect(sheet, (Coords(5, 3), Coords(7, 6))) [[None, 0, 1, 2], [0, None, None, None], [1, 5.1, 6.1, 7.1]]
# single-value >>> read_capture_rect(sheet, (Coords(6, 3), Coords(6, 3))) [0]
# column >>> read_capture_rect(sheet, (Coords(0, 3), Coords(7, 3))) [None, None, None, None, None, None, 0, 1]
# row >>> read_capture_rect(sheet, (Coords(5, 0), Coords(5, 6))) [None, None, None, None, 0, 1, 2]
# row beyond sheet-limits >>> read_capture_rect(sheet, (Coords(5, 0), Coords(5, 10))) [None, None, None, None, 0, 1, 2, None, None, None, None]
.. testcleanup:: >>> os.remove(tmp) """
# column
# row
else:
""" Reshapes the output value of :func:`read_capture_rect()`.
:param value: matrix or vector or value :type value: list of lists, list, value
:param dim_min: minimum dimension or 'auto' :type dim_min: int, None
:param dim_max: maximum dimension :type dim_max: int, None
:return: reshaped value :rtype: list of lists, list, value
Examples::
>>> _redim_captured_values([1, 2], 2) [[1, 2]]
>>> _redim_captured_values([[1, 2]], 1) [[1, 2]]
>>> _redim_captured_values([[1, 2]], 1, 1) [1, 2]
>>> _redim_captured_values([], 2) [[]]
>>> _redim_captured_values([[1, 2]], 0, 0) Traceback (most recent call last): ValueError: Cannot reduce Captured-values dimension(2) to (0, 0)!
""" # TODO: Make redimming use np-arrays.
None: {'fun': lambda x: x}, # TODO: Actually _redim_captured_values(). 'df': {'fun': pd.DataFrame}, 'df_num': {'fun': _type_df_with_numeric_conversion}, 'nparray': {'fun': np.array}, 'dict': {'fun': dict}, 'sorted': {'fun': sorted} }
available_filters=_default_filters): """ Processes the output value of :func:`read_capture_rect()` function.
FIXME: Actually use _process_captured_values()!
:param value: matrix or vector or a scalar-value :type value: list of lists, list, value
:param str, None type: The 1st-filter to apply, if missing, applies the mapping found in the ``None --> <filter`` entry of the `available_filters` dict. :param dict, None kws: keyword arguments for the filter function :param sequence, None args: arguments for the type-function :param list filters: A list of 3-tuples ``(filter_callable, *args, **kws)`` to further process rect-values. :param dict available_filters: Entries of ``<fun_names> --> <callables>`` for pre-configured filters available to post-process rect-values. The callable for `None` key will be always called to the original values to ensure correct dimensionality :return: processed rect-values :rtype: given type, or list of lists, list, value
Examples::
>>> value = [[1, 2], [3, 4], [5, 6]] >>> res = _process_captured_values(value, func='dict') >>> sorted(res.items()) [(1, 2), (3, 4), (5, 6)]
>>> value = [[1, 9], [8, 10], [5, 11]] >>> _process_captured_values(value, ... filters=[{'func':'sorted', 'kws':{'reverse': True}}]) [[8, 10], [5, 11], [1, 9]] """
""" An abstract delegating to backends excel-worksheets wrapper that is utilized by this module.
Use :func:`pandalone.xlref.wrap_sheet()` to create it.
:param np.array _states_matrix: The :term:`st_states-matrix` cached, so recreate object to refresh it. :param dict _margin_coords: limits used by :func:`_resolve_cell`, cached, so recreate object to refresh it.
Resource management is outside of the scope of this class, and must happen in the backend workbook/sheet instance.
*xlrd* examples::
>>> import xlrd # doctest: +SKIP >>> with xlrd.open_workbook(self.tmp) as wb: # doctest: +SKIP ... sheet = xlref.xlrdSheet(wb.sheet_by_name('Sheet1')) ... ## Do whatever
*win32* examples::
>>> with dsgdsdsfsd as wb: # doctest: +SKIP ... sheet = xlref.win32Sheet(wb.sheet['Sheet1']) TODO """
def _read_states_matrix(self): pass
""" Read and cache the :term:`st_states-matrix` of the wrapped sheet.
:return: A 2D-array with `False` wherever cell are blank or empty. :rtype: ndarray """
def read_rect(self, up_coords, dn_coords): """ Fecth the actual values contained in the from the backend Excel-sheet.
:param up_coords: the top-left edges of capture-rect, inclusive :param dn_coords: the bottom-right edges of capture-rect, inclusive :return: a 2D-list with the values with at least 1 element, or an empty-list :rtype: list """ pass
""" Override if possible to read (any of the) limits directly from the sheet.
:return: the 2 coords of the top-left & bottom-right full cells; anyone coords can be None. By default returns ``(None, None)``. :rtype: (Coords, Coords)
""" return None, None # pragma: no cover
""" Extract (and cache) margins either internally or from :func:`_margin_coords_from_states_matrix()`.
:return: the resolved top-left and bottom-right :class:`Coords` :rtype: tuple
Examples::
>>> sheet = _Spreadsheet(sheet=None) >>> sheet._states_matrix = np.asarray([ ## Mock states_matrix. ... [0, 0, 0, 0], ... [1, 1, 0, 0], ... [0, 1, 1, 0], ... [0, 0, 1, 0], ... ]) >>> sheet.get_margin_coords() (Coords(row=1, col=0), Coords(row=3, col=2))
"""
|