Skip to content

Commit

Permalink
Исправил ошибку фильтрации строк по спецификам и проверку контроля с …
Browse files Browse the repository at this point in the history
…формулой вида "SUM{}|=|1|=|SUM{}"
  • Loading branch information
WoolenSweater committed Nov 3, 2021
1 parent 2c53542 commit ca7578c
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 43 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,12 @@
# CHANGELOG

### [1.2.4] - 2021-11-03

- Исправил ошибку при проверке контроля с формулой вида `SUM{}|=|1|=|SUM{}`.
- Исправил ошибку из-за которой при фильтрации строк по спецификам не возвращалась ни одна строка.
- Причина была в том, что не учитывалась возможность дефолтного значения специфик для строк отчёта где они явно не указаны.


### [1.2.3] - 2021-08-02

- Исправил разбор формулы контроля/условия. В них так же есть коды вида "01", тогда как в отчёте в коде нет нуля.
Expand Down
4 changes: 2 additions & 2 deletions rosstat/report.py
Expand Up @@ -46,13 +46,13 @@ def add_col(self, col_code, col_text):
self._blank = False

def get_spec(self, idx):
'''Возвращает специфику по её "индексу"'''
'''Возвращает специфику отчёта по её "индексу"'''
return getattr(self, f's{idx}')

def filter(self, specs):
'''Проверка, входит ли строка в список переданных специфик'''
for i in range(1, 4):
row_spec = self.get_spec(i)
row_spec = self.get_spec(i) or specs[i].default
if row_spec in self._ignore_report_specs:
return True
if specs[i] not in self._ignore_specs and row_spec not in specs[i]:
Expand Down
83 changes: 44 additions & 39 deletions rosstat/validators/control/parser/elements.py
Expand Up @@ -3,6 +3,7 @@
from itertools import chain
from functools import reduce
from .value import nullablefloat
from .specific import Specific
from ..exceptions import NoElemToCompareError
from ....helpers import str_int

Expand Down Expand Up @@ -51,8 +52,13 @@ def __neg__(self):
return self

def __repr__(self):
return ('<Elem {}{}{} value={} bool={}>').format(
self.section, self.rows, self.columns, self.val, self.bool)
return '<Elem {}{}{} value={} bool={}>'.format(
list(self.section),
list(self.rows),
list(self.columns),
self.val,
self.bool
)

def __modify(self, elem, op_func):
self.rows |= elem.rows
Expand Down Expand Up @@ -128,14 +134,19 @@ def __init__(self, section, rows, columns,
self.rows = set(str_int(v) for v in rows)
self.columns = set(str_int(v) for v in columns)

self.specs = {1: s1, 2: s2, 3: s3}
self.specs = {1: Specific(s1), 2: Specific(s2), 3: Specific(s3)}

self.funcs = []
self.elems = []

def __repr__(self):
return '<ElemList [{}]{}{} funcs={} elems={}>'.format(
self.section, self.rows, self.columns, self.funcs, self.elems)
return "<ElemList ['{}']{}{} funcs={} elems={}>".format(
self.section,
list(self.rows),
list(self.columns),
self.funcs,
self.elems
)

def __neg__(self):
self._apply_unary('neg')
Expand All @@ -151,38 +162,24 @@ def _prepare_specs(self, formats, catalogs):
'''Подготовка специфик. Если список специфик не "пуст" и не содержит
один только ключ "*", пытаемся "развернуть" его к простому списку.
Другими словами, все диапазоны специфик привести к явному набору в
соответствии со справочником. Затем конвертируем всё в множество
соответствии со справочником
'''
for spec_idx in range(1, 4):
if self.specs[spec_idx] in ([None], ['*']):
self.specs[spec_idx] = set(self.specs[spec_idx])
else:
spec_list = self.__get_spec_list(formats, catalogs, spec_idx)
self.specs[spec_idx] = set(self.__expand_specs(spec_list,
spec_idx))
if self.specs[spec_idx].need_expand():
spec_params = self.__get_spec_params(formats, spec_idx)
spec_list = self.__get_spec_list(catalogs, spec_params)

def __get_spec_list(self, formats, catalogs, spec_idx):
'''Определяем набор параметров для специфики указанной строки, раздела.
Выбираем список специфик по имени справочника из наборапараметров
'''
self.specs[spec_idx].params(spec_params)
self.specs[spec_idx].expand(spec_list)

def __get_spec_params(self, formats, spec_idx):
'''Определяем параметры для специфики указанной строки, раздела'''
row_code = next(iter(self.rows))
params = formats.get_spec_params(self.section, row_code, spec_idx)
return catalogs.get(params.get('dic'), {}).get('ids', [])

def __expand_specs(self, spec_list, spec_idx):
'''Перебираем специфики. Простые специфики сразу возвращаем. Если
имеем диапазон, определяем индекс начальной и конечной специфик
из списка-справочника, итерируемся по определенному диапазону,
возвращая соответствующие специфики из списка-справочника
'''
for spec in self.specs[spec_idx]:
if '-' in spec:
start, end = spec.split('-')
for i in range(spec_list.index(start.strip()),
spec_list.index(end.strip()) + 1):
yield spec_list[i]
else:
yield spec
return formats.get_spec_params(self.section, row_code, spec_idx)

def __get_spec_list(self, catalogs, spec_params):
'''Выбираем список специфик по имени справочника из параметров'''
return catalogs.get(spec_params.get('dic'), {}).get('ids', [])

def _read_data(self, report, dimension):
'''Чтение отчёта и конвертация его в массивы элементов'''
Expand Down Expand Up @@ -232,13 +229,15 @@ def _apply_funcs(self, report, params, ctx_elem):

def _apply_sum(self, ctx_elem):
'''Суммирование строк и/или графов'''
if self.columns == ctx_elem.columns: # строк в каждой графе
if isinstance(ctx_elem, ElemLogic): # для случаев SUM{}|=|1|=|SUM{}
self.elems = [[reduce(operator.add, chain(*self.elems))]]
elif self.columns == ctx_elem.columns: # строк в каждой графе
self.elems = [[reduce(operator.add, l)] for l in zip(*self.elems)]
elif self.rows == ctx_elem.rows: # граф в каждой строке
elif self.rows == ctx_elem.rows: # граф в каждой строке
self.elems = [[reduce(operator.add, l)] for l in self.elems]
elif not self.elems: # всех ячеек (секция пустая)
elif not self.elems: # всех ячеек (секция пустая)
self.elems = [[Elem(None, self.section, '*', '*')]]
else: # всех ячеек (секция не пустая)
else: # всех ячеек (секция не пустая)
self.elems = [[reduce(operator.add, chain(*self.elems))]]

def _apply_unary(self, func):
Expand Down Expand Up @@ -313,7 +312,10 @@ def __init__(self, l_elem, operator, r_elem):

def __repr__(self):
return '<ElemLogic left={} operator="{}" right={}>'.format(
self.l_elem, self.op_name, self.r_elem)
self.l_elem,
self.op_name,
self.r_elem
)

def check(self, report, params, ctx_elem=None):
'''Основной метод вызова проверки'''
Expand Down Expand Up @@ -391,7 +393,10 @@ def __init__(self, action, elems):

def __repr__(self):
return '<ElemSelector action={} funcs={} elems={}>'.format(
self.action, self.funcs, self.elems)
self.action,
self.funcs,
self.elems
)

def check(self, *args):
self._select(args)
Expand Down
44 changes: 44 additions & 0 deletions rosstat/validators/control/parser/specific.py
@@ -0,0 +1,44 @@
class Specific:
def __init__(self, specs):
self._specs = set(specs)
self._default = None

def __repr__(self):
return "<Specific {} default={}>".format(self._specs, self._default)

def __iter__(self):
return iter(self._specs)

def __contains__(self, spec):
return spec in self._specs

def __eq__(self, other):
return self._specs == other

@property
def default(self):
return self._default

def need_expand(self):
return self._specs not in ({None}, {'*'})

def params(self, params):
self._default = params.get('default')

def expand(self, dic):
self._specs = set(self._expand(dic))

def _expand(self, dic):
'''Перебираем специфики. Простые специфики сразу возвращаем. Если
имеем диапазон, определяем индекс начальной и конечной специфик
из списка-справочника, итерируемся по определенному диапазону,
возвращая соответствующие специфики из списка-справочника
'''
for spec in self._specs:
if '-' in spec:
start, end = spec.split('-')
for i in range(dic.index(start.strip()),
dic.index(end.strip()) + 1):
yield dic[i]
else:
yield spec
5 changes: 3 additions & 2 deletions setup.py
Expand Up @@ -2,7 +2,7 @@

setup(
name='rosstat-flc',
version='1.2.3',
version='1.2.4',
packages=find_packages(),
description='Tool for format-logistic control of reports sent to RosStat',
long_description=open('README.md', 'r').read(),
Expand All @@ -19,6 +19,7 @@
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9'
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
]
)

0 comments on commit ca7578c

Please sign in to comment.