Пример #1
0
    def build_declarant_incomes(self,
                                year,
                                max_income=5000000
                                ) -> TAllRegionStatsForOneYear:
        region_data = TAllRegionStatsForOneYear(
            year, file_name=self.options.get('output_json'))
        minOboronyId = 450
        query = """
            select o.region_id, i.size
            from declarations_section   s 
            join declarations_office o on s.office_id=o.id  
            join declarations_income i on i.section_id=s.id  
            where s.income_year = {} and  
                 i.size < {} and 
                 i.size > 0 and 
                 i.relative='{}' and
                 o.id != {} and
                 o.region_id is  not null and
                 o.region_id != {}
            order by o.region_id, i.size
        """.format(year, max_income, models.Relative.main_declarant_code,
                   minOboronyId, TRussianRegions.Russia_as_s_whole_region_id)
        regions = TRussianRegions()
        mrot = RUSSIA.get_mrot(year)
        assert mrot is not None
        with connection.cursor() as cursor:
            cursor.execute(query)
            for region_id, items in groupby(cursor, itemgetter(0)):
                incomes = list(income for _, income in items
                               if income / 12 > mrot)
                if region_id == TRussianRegions.Baikonur:
                    continue
                region = regions.get_region_by_id(region_id)
                if region.joined_to is not None:
                    region = regions.get_region_by_id(region.joined_to)
                stat_info = region_data.ross_stat.get_data(region.id, year)
                if stat_info is None:
                    raise Exception(
                        "cannot find stat_info for region.id={}, region.name={}"
                        .format(region.id, region.name))
                population = stat_info.population
                population_median_income = region_data.ross_stat.get_or_predict_median_salary(
                    region.id, year)
                if population_median_income is None:
                    raise Exception(
                        "cannot estimate population median_income for region.id={}, region.name={}"
                        .format(region.id, region.name))
                s = TRegionYearStats(
                    region.id, region.name, incomes, population_median_income,
                    population,
                    region_data.ross_stat.get_data(region.id,
                                                   2021).er_election_2021)
                region_data.add_snapshot(s)

        region_data.calc_aux_params()
        return region_data
Пример #2
0
class TDeclarationTitleParser:
    def __init__(self, title):
        self.title = normalize_whitespace(title)
        self.input_title = title
        self.type = None
        self.decl_objects = list()
        self.decl_time = None
        self.declarant_positions = list()
        self.fio = None
        self.regions = TRussianRegions()
        self.region_name = None
        self.org_name = None

    def find_starter(self):
        for p in ['сведения о доходах']:
            i = self.title.lower().find(p)
            if i != -1:
                self.title = self.title[i:]
                break
        type_regexp = "^((Уточненные Сведения)|(Сведения)|(Справка)|(Информация)|(С В Е Д Е Н И Я))"
        match = re.search(type_regexp, self.title, re.IGNORECASE)
        if match is not None:
            self.type = self.title[:match.end()]
            self.title = self.title[match.end():].strip()
            match = re.search("^(о|об)", self.title, re.IGNORECASE)
            if match is not None:
                self.title = self.title[match.end():].strip()
            return True
        return False

    def to_json(self):
        return {
            "input": self.input_title,
            "type": self.type,
            "objects": self.decl_objects,
            "time": self.decl_time,
            "positions": self.declarant_positions,
            "org_name": self.org_name,
            "fio": self.fio,
            "region": self.region_name
        }

    @staticmethod
    def from_json(j):
        r = TDeclarationTitleParser(j['input'])
        r.type = j['type']
        r.decl_objects = j['objects']
        r.decl_time = j['time']
        r.declarant_positions = j['positions']
        r.org_name = j['org_name']
        r.fio = j.get('fio')
        r.region_name = j.get('region')
        return r

    def find_decl_objects(self):
        match = re.search("^ *(о|об) ", self.title, re.IGNORECASE)
        if match is not None:
            self.title = self.title[match.end():].strip()
        objs = [
            'доходах', 'расходах', 'имуществе',
            'обязательствах ?имущественного ?характера',
            'сведения ?об ?источниках ?получения ?средств',
            'источниках ?получения ?средств'
        ]
        objects_regexps = "^({})".format('|'.join(
            map(lambda x: "({})".format(x), objs)))
        match = re.search(objects_regexps, self.title, re.IGNORECASE)
        objects_cnt = 0
        while match is not None:
            objects_cnt += 1
            self.decl_objects.append(self.title[:match.end()].strip().lower())
            self.title = self.title[match.end():].strip()
            match = re.search("^(и|,)( (о|об))? ", self.title, re.IGNORECASE)
            if match is not None:
                self.title = self.title[match.end():].strip()
            match = re.search(objects_regexps, self.title, re.IGNORECASE)
        return objects_cnt > 0

    #Сведения ведущий специалист комитета по ФК, спорту, туризму и молодёжной политике администрации Зеленчукского муниципального района Карачаево-Черкесской Республики, и членов его семьи за период с 1 января по 31 декабря 2011 года Беланова сергея Николаевича Декларированный годовой доход за 2011 г. (руб.) Перечень объектов недвижимого имущества и транспортных средств, принадлежащих на праве собственности Перечень объектов недвижимого имущества, находящихся в пользовании
    def find_declarant_position(self):
        self.find_declarant_position_const()
        r = '^(, )?представленные'
        match = re.search(r, self.title, re.IGNORECASE)
        if match is not None:
            self.title = self.title[match.end():].strip()
        words = self.title.split(" ")
        i = 0
        while i < len(words):
            w = words[i].strip(', ')
            if TRussianFio.can_start_fio(w):
                break
            if TRussianDictWrapper.is_morph_animative_noun(
                    w) and w != "заместителя":
                offset = self.title.find(words[i]) + len(words[i])
                self.declarant_positions.append(
                    self.title[:offset].strip(' ,'))
                self.title = self.title[offset:].strip()
                self.find_declarant_position_const()
                return True
            i += 1
            if i > 4:
                break
        return len(self.declarant_positions) > 0

    def find_fio_at_start(self):
        words = self.title.split(" ")
        if len(words) >= 3:
            if TRussianFio.is_fio_in_text(words[:3]):
                offset = self.title.find(words[2]) + len(words[2])
                self.fio = self.title[:offset].strip(' ,')
                self.title = self.title[offset:].strip()
                return True
        return False

    def find_fio_in_the_end(self):
        words = self.title.strip().split(" ")
        if len(words) >= 3:
            if TRussianFio.is_fio_in_text(words[-3:]):
                offset = self.title.find(words[-3])
                self.fio = self.title[offset:].strip(' ,')
                self.title = self.title[:offset].strip()
                return True
        return False

    def find_declarant_position_const(self):
        for s in [
                "лиц, замещающих муниципальные должности",
                "лиц, замещающих муниципальные и выборные должности",
                "лица, замещающего государственную должность",
                "лиц, замещающих должности",
                "лиц, замещающих должности государственной гражданской службы",
                "представленные лицами, замещающими государственные должности",
                "лицами, замещающими должности"
        ]:
            if self.title.startswith(s):
                self.declarant_positions.append(s)
                self.title = self.title[len(s):].strip(' ,')
                region_id, start, end = self.regions.get_region_all_forms_at_start(
                    self.title)
                if region_id is not None:
                    self.region_name = self.regions.get_region_by_id(
                        region_id).name
                    self.title = self.title[end:].strip(' ,')
                if self.title.startswith('и '):
                    self.title = self.title[2:].strip(' ,')
                    if not self.find_declarant_position_const():
                        self.title = "и " + self.title
                return True

    #'СВЕДЕНИЯ о доходах, об имуществе и обязательствах имущественного характера лица, замещающего государственную должность Российской Федерации, Короткова Алексея Владимировича и членов его семьи'
    def find_time(self, search_everywhere=True):
        if self.decl_time is not None:
            return True
        time_starter = "за (отчетный )?(финансовый )?((период)|(год))"
        time_regexps = [
            time_starter +
            " с [0-9]+ января [0-9]+ ?(года|г.) по [0-9]+ декабря [0-9]+ ?(года|г.)",
            time_starter +
            " с [0-9]+ января по [0-9]+ декабря [0-9]+ ?(года|г.)",
            time_starter + " с [0-9]+.[0-9]+.[0-9]+ по [0-9]+.[0-9]+.[0-9]+",
            "за [0-9]+ год"
        ]
        for r in time_regexps:
            if not search_everywhere:
                r = "^({})".format(r)
            match = re.search(r, self.title, re.IGNORECASE)
            if match is not None:
                self.decl_time = self.title[match.start():match.end()].strip()
                if search_everywhere:
                    self.title = self.title[:match.start()].strip()
                else:
                    self.title = self.title[match.end():].strip()
                return True
        return False

    def delete_unused(self):
        for p in ['а также', 'его супруг', 'ее супруг']:
            s = self.title.find(p)
            if s != -1:
                break
        for p in ['детей', 'ребенка']:
            e = self.title.rfind(p)
            if e != -1:
                e += len(p)
                break

        if s != -1 and e != -1:
            self.title = self.title[:s].strip() + " " + self.title[e:].strip()
            self.title = self.title.strip(' ,')
            return

        regexps = [
            r"и членов (ее|его|их) сем..",
            r"для размещения на официальном сайте и средствах массовой информации"
        ]
        for x in regexps:
            self.title = re.sub(x, "", self.title)

    def looks_like_orgname(self, orgname):
        starter = "^(структурно)|(территориал)"
        if re.search(starter, orgname, re.IGNORECASE) is None:
            return False
        ender = "((республики)|(области)|(края))$"
        if re.search(ender, orgname, re.IGNORECASE) is None:
            return False
        return True

    def parse(self, raise_exception=False):
        self.find_starter()
        if not self.find_decl_objects():
            if self.type is None:
                if raise_exception:
                    raise Exception("cannot parse decl objects {}".format(
                        self.title))
                else:
                    return False
        self.find_time(search_everywhere=False)
        if not self.find_declarant_position():
            if not self.find_fio_at_start():
                if self.looks_like_orgname(self.title):
                    self.org_name = self.title
                    return True
                if raise_exception:
                    raise Exception(
                        "cannot parse declarant position {}".format(
                            self.title))
                else:
                    return False
        else:
            self.find_fio_at_start()
        self.find_time()
        self.delete_unused()
        self.find_fio_in_the_end()
        self.org_name = self.title.strip(' ,')
        if self.org_name.startswith("в "):
            self.org_name = self.org_name[2:]
        return True
Пример #3
0
class TRossStatData:
    def __init__(self, regions=None):
        self.region_stat = dict()
        self.regions = regions
        if self.regions is None:
            self.regions = TRussianRegions()
        self.file_path = os.path.join(os.path.dirname(__file__),
                                      "data/ross_stat.json")

    def load_from_disk(self):
        with open(self.file_path) as inp:
            for key, years in json.load(inp).items():
                region = self.regions.get_region_by_id(int(key))
                assert region is not None
                region_id = region.id
                if region_id not in self.region_stat:
                    self.region_stat[region_id] = dict()
                for year, stat in years.items():
                    self.region_stat[int(region_id)][int(
                        year)] = TRegionYearInfo.from_json(stat)

    def save_to_disk(self, postfix=""):
        d = dict()
        with open(self.file_path + postfix, "w") as outp:
            for region_id, years in self.region_stat.items():
                d[region_id] = dict()
                for year, info in years.items():
                    d[region_id][year] = info.to_json()
            json.dump(d, outp, indent=3, ensure_ascii=False)

    def check(self, year: int):
        for r in self.regions.iterate_regions():
            if r.id not in self.region_stat:
                raise Exception("region {}, region_id={} is missing".format(
                    r.name, r.id))
            if year not in self.region_stat[r.id]:
                raise Exception(
                    "year {} region {}, region_id={} is missing".format(
                        year, r.name, r.id))

    def get_data(self, region_id, year: int) -> TRegionYearInfo:
        return self.region_stat.get(region_id, dict()).get(year)

    def get_or_create_data(self, region_id, year: int) -> TRegionYearInfo:
        return self.region_stat.get(region_id,
                                    dict()).get(year, TRegionYearInfo())

    def set_data(self, region_id, year: int, info: TRegionYearInfo):
        info.check()
        r = self.region_stat.get(region_id)
        assert r is not None
        r[year] = info

    def get_or_predict_median_salary(self, region_id: int, year: int) -> int:
        d = self.get_data(region_id, year)
        if d is not None and d.median_salary2 is not None:
            return d.median_salary2
        d1 = self.get_data(region_id, year - 1)
        d2 = self.get_data(region_id, year + 1)
        if d1 is not None and d1.median_salary2 is not None and d2 is not None and d2.median_salary2 is not None:
            return int((d1.median_salary2 + d2.median_salary2) / 2)
        return None