diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index aa3d96569..39d55d24b 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -15,17 +15,18 @@ from sapl.materia.models import Proposicao def adornar_msg(msg): - return '\n{1}\n{0}\n{1}'.format(msg, '#' * len(msg)) + return "\n{1}\n{0}\n{1}".format(msg, "#" * len(msg)) def migrar(flush=False, apagar_do_legado=False): if TAG_MARCO in REPO.tags: - info('A migração já está feita.') + info("A migração já está feita.") return assert TAG_ZOPE in REPO.tags, adornar_msg( - 'Antes de migrar ' - 'é necessário fazer a exportação de documentos do zope') - management.call_command('migrate') + "Antes de migrar " + "é necessário fazer a exportação de documentos do zope" + ) + management.call_command("migrate") primeira_migracao = migrar_dados(flush, apagar_do_legado) migrar_usuarios(REPO.working_dir, primeira_migracao) migrar_documentos(REPO, primeira_migracao) @@ -36,25 +37,26 @@ def migrar(flush=False, apagar_do_legado=False): def compactar_media(): # tar de media/sapl - print('Criando tar de media... ', end='', flush=True) - arq_tar = DIR_REPO.child('{}.media.tar'.format(NOME_BANCO_LEGADO)) + print("Criando tar de media... ", end="", flush=True) + arq_tar = DIR_REPO.child("{}.media.tar".format(NOME_BANCO_LEGADO)) arq_tar.remove() - subprocess.check_output(['tar', 'cfh', arq_tar, '-C', DIR_REPO, 'sapl']) - print('SUCESSO') + subprocess.check_output(["tar", "cfh", arq_tar, "-C", DIR_REPO, "sapl"]) + print("SUCESSO") -PROPOSICAO_UPLOAD_TO = Proposicao._meta.get_field('texto_original').upload_to +PROPOSICAO_UPLOAD_TO = Proposicao._meta.get_field("texto_original").upload_to def salva_conteudo_do_sde(proposicao, conteudo): caminho_relativo = PROPOSICAO_UPLOAD_TO( - proposicao, 'proposicao_sde_{}.xml'.format(proposicao.pk)) + proposicao, "proposicao_sde_{}.xml".format(proposicao.pk) + ) caminho_absoluto = Path(REPO.working_dir, caminho_relativo) caminho_absoluto.parent.mkdir(parents=True) # ajusta caminhos para folhas de estilo conteudo = conteudo.replace(b'"XSLT/HTML', b'"/XSLT/HTML') conteudo = conteudo.replace(b"'XSLT/HTML", b"'/XSLT/HTML") - with open(caminho_absoluto, 'wb') as arq: + with open(caminho_absoluto, "wb") as arq: arq.write(conteudo) proposicao.texto_original = caminho_relativo proposicao.save() @@ -66,18 +68,25 @@ def scrap_sde(url, usuario, senha=None): # login session = requests.session() - res = session.post('{}?retry=1'.format(url), - {'__ac_name': usuario, '__ac_password': senha}) + res = session.post( + "{}?retry=1".format(url), + {"__ac_name": usuario, "__ac_password": senha}, + ) assert res.status_code == 200 - url_proposicao_tmpl = '{}/sapl_documentos/proposicao/{}/renderXML?xsl=__default__' # noqa + url_proposicao_tmpl = ( + "{}/sapl_documentos/proposicao/{}/renderXML?xsl=__default__" + ) total = Proposicao.objects.count() for num, proposicao in enumerate(Proposicao.objects.all()): pk = proposicao.pk url_proposicao = url_proposicao_tmpl.format(url, pk) res = session.get(url_proposicao) - print("pk: {} status: {} {} (progresso: {:.2%})".format( - pk, res.status_code, url_proposicao, num / total)) + print( + "pk: {} status: {} {} (progresso: {:.2%})".format( + pk, res.status_code, url_proposicao, num / total + ) + ) if res.status_code == 200: salva_conteudo_do_sde(proposicao, res.content) @@ -85,24 +94,32 @@ def scrap_sde(url, usuario, senha=None): def tenta_correcao(): from sapl.legacy.migracao_dados import ocorrencias - gravar_marco('producao', pula_se_ja_existe=True) + gravar_marco("producao", pula_se_ja_existe=True) migrar_dados() - assert 'fk' not in ocorrencias, "AINDA EXISTEM FKS ORFAS" + assert "fk" not in ocorrencias, "AINDA EXISTEM FKS ORFAS" gravar_marco() from IPython import get_ipython import git + sigla = NOME_BANCO_LEGADO[-3:] - print(f'cd ~/migracao_sapl/repos/sapl_cm_{sigla}') + print(f"cd ~/migracao_sapl/repos/sapl_cm_{sigla}") get_ipython().run_line_magic( - 'cd', f'~/migracao_sapl/repos/sapl_cm_{sigla}') - get_ipython().system("diff -rq producao dados | grep -v 'Only in dados' | grep -v 'Files producao/sequences.yaml and dados/sequences.yaml differ'") # noqa - get_ipython().system('vimdiff producao/sequences.yaml dados/sequences.yaml') # noqa + "cd", f"~/migracao_sapl/repos/sapl_cm_{sigla}" + ) + get_ipython().system( + "diff -rq producao dados | grep -v 'Only in dados' | grep -v 'Files producao/sequences.yaml and dados/sequences.yaml differ'" # noqa + ) + get_ipython().system( + "vimdiff producao/sequences.yaml dados/sequences.yaml" + ) ajustes = Path( - f'/home/mazza/work/consulta_sapls/ajustes_pre_migracao/{sigla}.sql').read_file() # noqa - assert ajustes.count('RESSUSCITADOS') == 1 - consulta_sapl = git.Repo(f'/home/mazza/work/consulta_sapls') + f"/home/mazza/work/consulta_sapls/ajustes_pre_migracao/{sigla}.sql" + ).read_file() + assert ajustes.count("RESSUSCITADOS") == 1 + consulta_sapl = git.Repo(f"/home/mazza/work/consulta_sapls") consulta_sapl.git.add( - f'/home/mazza/work/consulta_sapls/ajustes_pre_migracao/{sigla}.sql') - consulta_sapl.index.commit(f'Ajusta {sigla} (p migração corretiva)') + f"/home/mazza/work/consulta_sapls/ajustes_pre_migracao/{sigla}.sql" + ) + consulta_sapl.index.commit(f"Ajusta {sigla} (p migração corretiva)") diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 683180e9d..79262e24b 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -33,61 +33,93 @@ from sapl.base.models import Autor, TipoAutor, cria_models_tipo_autor from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao from sapl.legacy.models import NormaJuridica as OldNormaJuridica from sapl.legacy.models import Numeracao, TipoNumeracaoProtocolo -from sapl.legacy_migration_settings import (DIR_DADOS_MIGRACAO, DIR_REPO, - NOME_BANCO_LEGADO, PYTZ_TIMEZONE, - SIGLA_CASA) -from sapl.materia.models import (AcompanhamentoMateria, DocumentoAcessorio, - MateriaLegislativa, Proposicao, - StatusTramitacao, TipoDocumento, - TipoMateriaLegislativa, TipoProposicao, - Tramitacao) -from sapl.norma.models import (AssuntoNorma, NormaJuridica, NormaRelacionada, - TipoVinculoNormaJuridica) -from sapl.parlamentares.models import (Legislatura, Mandato, Parlamentar, - Partido, TipoAfastamento) -from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo, - StatusTramitacaoAdministrativo) -from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao, OrdemDia, - RegistroVotacao, TipoResultadoVotacao) +from sapl.legacy_migration_settings import ( + DIR_DADOS_MIGRACAO, + DIR_REPO, + NOME_BANCO_LEGADO, + PYTZ_TIMEZONE, + SIGLA_CASA, +) +from sapl.materia.models import ( + AcompanhamentoMateria, + DocumentoAcessorio, + MateriaLegislativa, + Proposicao, + StatusTramitacao, + TipoDocumento, + TipoMateriaLegislativa, + TipoProposicao, + Tramitacao, +) +from sapl.norma.models import ( + AssuntoNorma, + NormaJuridica, + NormaRelacionada, + TipoVinculoNormaJuridica, +) +from sapl.parlamentares.models import ( + Legislatura, + Mandato, + Parlamentar, + Partido, + TipoAfastamento, +) +from sapl.protocoloadm.models import ( + DocumentoAdministrativo, + Protocolo, + StatusTramitacaoAdministrativo, +) +from sapl.sessao.models import ( + ExpedienteMateria, + ExpedienteSessao, + OrdemDia, + RegistroVotacao, + TipoResultadoVotacao, +) from sapl.utils import normalize from .scripts.normaliza_dump_mysql import normaliza_dump_mysql # BASE ###################################################################### # apps to be migrated, in app dependency order (very important) -appconfs = [apps.get_app_config(n) for n in [ - 'parlamentares', - 'comissoes', - # base precisa vir depois dos apps parlamentares e comissoes - # pois Autor os referencia - 'base', - 'materia', - 'norma', - 'sessao', - 'lexml', - 'protocoloadm', ]] +appconfs = [ + apps.get_app_config(n) + for n in [ + "parlamentares", + "comissoes", + # base precisa vir depois dos apps parlamentares e comissoes + # pois Autor os referencia + "base", + "materia", + "norma", + "sessao", + "lexml", + "protocoloadm", + ] +] unique_constraints = [] one_to_one_constraints = [] primeira_vez = [] # apps quase não têm interseção -name_sets = [(ac.label, set(m.__name__ for m in ac.get_models())) - for ac in appconfs] +name_sets = [ + (ac.label, set(m.__name__ for m in ac.get_models())) for ac in appconfs +] for a1, s1 in name_sets: for a2, s2 in name_sets: if a1 is not a2: # existe uma interseção de nomes entre comissoes e materia - if {a1, a2} == {'comissoes', 'materia'}: - assert s1.intersection(s2) == {'DocumentoAcessorio'} + if {a1, a2} == {"comissoes", "materia"}: + assert s1.intersection(s2) == {"DocumentoAcessorio"} else: assert not s1.intersection(s2) # RENAMES ################################################################### -MODEL_RENAME_PATTERN = re.compile('(.+) \((.+)\)') -MODEL_RENAME_INCLUDE_PATTERN = re.compile('<(.+)>') +MODEL_RENAME_PATTERN = re.compile("(.+) \((.+)\)") +MODEL_RENAME_INCLUDE_PATTERN = re.compile("<(.+)>") def get_renames(): @@ -96,7 +128,8 @@ def get_renames(): includes = {} for app in appconfs: app_rename_data = yaml.load( - pkg_resources.resource_string(app.module.__name__, 'legacy.yaml')) + pkg_resources.resource_string(app.module.__name__, "legacy.yaml") + ) for model_name, renames in app_rename_data.items(): # armazena ou substitui includes if MODEL_RENAME_INCLUDE_PATTERN.match(model_name): @@ -119,51 +152,60 @@ def get_renames(): field_renames, model_renames = get_renames() -legacy_app = apps.get_app_config('legacy') +legacy_app = apps.get_app_config("legacy") models_novos_para_antigos = { model: legacy_app.get_model(model_renames.get(model, model.__name__)) - for model in field_renames} + for model in field_renames +} models_novos_para_antigos[Composicao] = models_novos_para_antigos[Participacao] campos_novos_para_antigos = { model._meta.get_field(nome_novo): nome_antigo for model, renames in field_renames.items() - for nome_novo, nome_antigo in renames.items()} + for nome_novo, nome_antigo in renames.items() +} # campos de Composicao (de Comissao) -for nome_novo, nome_antigo in (('comissao', 'cod_comissao'), - ('periodo', 'cod_periodo_comp')): +for nome_novo, nome_antigo in ( + ("comissao", "cod_comissao"), + ("periodo", "cod_periodo_comp"), +): campos_novos_para_antigos[ - Composicao._meta.get_field(nome_novo)] = nome_antigo + Composicao._meta.get_field(nome_novo) + ] = nome_antigo # campos virtuais de Proposicao para funcionar com get_fk_related -class CampoVirtual(namedtuple('CampoVirtual', 'model related_model')): +class CampoVirtual(namedtuple("CampoVirtual", "model related_model")): null = True CAMPOS_VIRTUAIS_PROPOSICAO = { TipoMateriaLegislativa: CampoVirtual(Proposicao, MateriaLegislativa), - TipoDocumento: CampoVirtual(Proposicao, DocumentoAcessorio) + TipoDocumento: CampoVirtual(Proposicao, DocumentoAcessorio), } for campo_virtual in CAMPOS_VIRTUAIS_PROPOSICAO.values(): - campos_novos_para_antigos[campo_virtual] = 'cod_mat_ou_doc' + campos_novos_para_antigos[campo_virtual] = "cod_mat_ou_doc" CAMPOS_VIRTUAIS_TIPO_PROPOSICAO = { - 'M': CampoVirtual(TipoProposicao, TipoMateriaLegislativa), - 'D': CampoVirtual(TipoProposicao, TipoDocumento) + "M": CampoVirtual(TipoProposicao, TipoMateriaLegislativa), + "D": CampoVirtual(TipoProposicao, TipoDocumento), } for campo_virtual in CAMPOS_VIRTUAIS_TIPO_PROPOSICAO.values(): - campos_novos_para_antigos[campo_virtual] = 'tip_mat_ou_doc' + campos_novos_para_antigos[campo_virtual] = "tip_mat_ou_doc" # campos virtuais de Autor para funcionar com get_fk_related -CAMPOS_VIRTUAIS_AUTOR = {related: CampoVirtual(Autor, related) - for related in (Parlamentar, Comissao, Partido)} -for related, campo_antigo in [(Parlamentar, 'cod_parlamentar'), - (Comissao, 'cod_comissao'), - (Partido, 'cod_partido')]: +CAMPOS_VIRTUAIS_AUTOR = { + related: CampoVirtual(Autor, related) + for related in (Parlamentar, Comissao, Partido) +} +for related, campo_antigo in [ + (Parlamentar, "cod_parlamentar"), + (Comissao, "cod_comissao"), + (Partido, "cod_partido"), +]: campo_virtual = CAMPOS_VIRTUAIS_AUTOR[related] campos_novos_para_antigos[campo_virtual] = campo_antigo @@ -172,7 +214,7 @@ for related, campo_antigo in [(Parlamentar, 'cod_parlamentar'), def info(msg): - print('INFO: ' + msg) + print("INFO: " + msg) ocorrencias = defaultdict(list) @@ -180,21 +222,22 @@ ocorrencias = defaultdict(list) def warn(tipo, msg, dados): ocorrencias[tipo].append(dados) - print('CUIDADO! ' + msg.format(**dados)) + print("CUIDADO! " + msg.format(**dados)) @lru_cache() def get_pk_legado(tabela): - if tabela == 'despacho_inicial': + if tabela == "despacho_inicial": # adaptação para deleção correta no mysql ao final de migrar_model # acompanha o agrupamento de despacho_inicial feito em iter_sql_records - return 'cod_materia', 'cod_comissao' - elif tabela == 'mesa_sessao_plenaria': + return "cod_materia", "cod_comissao" + elif tabela == "mesa_sessao_plenaria": # retiramos 'cod_sessao_leg' redundante que da problema # ao verificar se o registro já está migrado - return 'cod_cargo', 'cod_parlamentar', 'cod_sessao_plen' + return "cod_cargo", "cod_parlamentar", "cod_sessao_plen" res = exec_legado( - 'show index from {} WHERE Key_name = "PRIMARY"'.format(tabela)) + 'show index from {} WHERE Key_name = "PRIMARY"'.format(tabela) + ) return [r[4] for r in res] @@ -214,34 +257,44 @@ def com_aspas_se_necessario(valor): class ForeignKeyFaltando(ObjectDoesNotExist): - 'Uma FK aponta para um registro inexistente' + "Uma FK aponta para um registro inexistente" def __init__(self, field, valor, old): self.field = field self.valor = valor self.old = old - msg = 'FK não encontrada para [{campo} = {valor}] (em {tabela} / pk = {pk})' # noqa + msg = ( + "FK não encontrada para [{campo} = {valor}] (em {tabela} / pk = {pk})" + ) # noqa @property def dados(self): campo = campos_novos_para_antigos[self.field] _, tabela, campos_pk = get_estrutura_legado(self.field.model) pk = {c: getattr(self.old, c) for c in campos_pk} - sql = 'select * from {} where {};'.format( + sql = "select * from {} where {};".format( tabela, - ' and '.join([ - '{} = {}'.format(k, com_aspas_se_necessario(v)) - for k, v in pk.items()])) - return OrderedDict((('campo', campo), - ('valor', self.valor), - ('tabela', tabela), - ('pk', pk), - ('sql', sql))) + " and ".join( + [ + "{} = {}".format(k, com_aspas_se_necessario(v)) + for k, v in pk.items() + ] + ), + ) + return OrderedDict( + ( + ("campo", campo), + ("valor", self.valor), + ("tabela", tabela), + ("pk", pk), + ("sql", sql), + ) + ) def get_all_ids_from_model(model): - return set(model.objects.values_list('id', flat=True)) + return set(model.objects.values_list("id", flat=True)) @lru_cache() @@ -263,19 +316,19 @@ def get_fk_related(field, old): raise ForeignKeyFaltando(field=field, valor=valor, old=old) -def exec_sql(sql, db='default'): +def exec_sql(sql, db="default"): cursor = connections[db].cursor() cursor.execute(sql) return cursor -exec_legado = partial(exec_sql, db='legacy') +exec_legado = partial(exec_sql, db="legacy") def _formatar_lista_para_sql(iteravel): lista = list(iteravel) if lista: - return '({})'.format(str(lista)[1:-1]) # transforma "[...]" em "(...)" + return "({})".format(str(lista)[1:-1]) # transforma "[...]" em "(...)" else: return None @@ -297,12 +350,12 @@ def primeira_coluna(cursor): # UNIFORMIZAÇÃO DO BANCO ANTES DA MIGRAÇÃO ############################### -SQL_NAO_TEM_TABELA = ''' +SQL_NAO_TEM_TABELA = """ SELECT count(*) FROM information_schema.columns WHERE table_schema=database() AND TABLE_NAME="{}" -''' +""" def existe_tabela_no_legado(tabela): @@ -319,7 +372,7 @@ def existe_coluna_no_legado(tabela, coluna): def garante_coluna_no_legado(tabela, spec_coluna): coluna = spec_coluna.split()[0] if not existe_coluna_no_legado(tabela, coluna): - exec_legado('ALTER TABLE {} ADD COLUMN {}'.format(tabela, spec_coluna)) + exec_legado("ALTER TABLE {} ADD COLUMN {}".format(tabela, spec_coluna)) assert existe_coluna_no_legado(tabela, coluna) @@ -332,10 +385,11 @@ def garante_tabela_no_legado(create_table): TABELAS_REFERENCIANDO_AUTOR = [ # , - ('autoria', True), - ('documento_administrativo', True), - ('proposicao', True), - ('protocolo', False)] + ("autoria", True), + ("documento_administrativo", True), + ("proposicao", True), + ("protocolo", False), +] def reverte_exclusao_de_autores_referenciados_no_legado(): @@ -343,35 +397,44 @@ def reverte_exclusao_de_autores_referenciados_no_legado(): na base legada""" def get_autores_referenciados(tabela, tem_ind_excluido): - sql = '''select distinct cod_autor from {} + sql = """select distinct cod_autor from {} where cod_autor is not null - '''.format(tabela) + """.format( + tabela + ) if tem_ind_excluido: - sql += ' and ind_excluido != 1' + sql += " and ind_excluido != 1" return primeira_coluna(exec_legado(sql)) # reverte exclusões de autores referenciados por outras tabelas autores_referenciados = { cod for tabela, tem_ind_excluido in TABELAS_REFERENCIANDO_AUTOR - for cod in get_autores_referenciados(tabela, tem_ind_excluido)} + for cod in get_autores_referenciados(tabela, tem_ind_excluido) + } exec_legado_em_subconjunto( - 'update autor set ind_excluido = 0 where cod_autor in {}', - autores_referenciados) + "update autor set ind_excluido = 0 where cod_autor in {}", + autores_referenciados, + ) # propaga exclusões para autores não referenciados - for tabela, fk in [('parlamentar', 'cod_parlamentar'), - ('comissao', 'cod_comissao')]: - sql = ''' + for tabela, fk in [ + ("parlamentar", "cod_parlamentar"), + ("comissao", "cod_comissao"), + ]: + sql = """ update autor set ind_excluido = 1 where {cod_parlamentar} is not null and {cod_parlamentar} not in ( select {cod_parlamentar} from {parlamentar} where ind_excluido <> 1) - '''.format(parlamentar=tabela, cod_parlamentar=fk) + """.format( + parlamentar=tabela, cod_parlamentar=fk + ) if autores_referenciados: - sql += ' and cod_autor not in ({})'.format( - ', '.join(map(str, autores_referenciados))) + sql += " and cod_autor not in ({})".format( + ", ".join(map(str, autores_referenciados)) + ) exec_legado(sql) @@ -385,13 +448,14 @@ def get_reapontamento_de_autores_repetidos(autores): """ grupos_de_repetidos = [ [cod_autor for _, cod_autor in grupo] - for cod_zzz, grupo in groupby(autores, lambda r: r[0])] + for cod_zzz, grupo in groupby(autores, lambda r: r[0]) + ] # mantém apenas os grupos com mais de um autor por cod_zzz grupos_de_repetidos = [g for g in grupos_de_repetidos if len(g) > 1] # aponta cada autor de cada grupo de repetidos para o 1o do seu grupo - reapontamento = {autor: grupo[0] - for grupo in grupos_de_repetidos - for autor in grupo} + reapontamento = { + autor: grupo[0] for grupo in grupos_de_repetidos for autor in grupo + } # apagaremos todos menos o primeiro apagar = [k for k, v in reapontamento.items() if k != v] return reapontamento, apagar @@ -404,8 +468,10 @@ def get_autorias_sem_repeticoes(autoria, reapontamento): autoria = sorted((reapontamento[a], m, i) for a, m, i in autoria) # agrupa por [autor (1o do grupo de repetidos), materia], com # ind_primeiro_autor == 1 se isso acontece em qualquer autor do grupo - autoria = [(a, m, max(i for a, m, i in grupo)) - for (a, m), grupo in groupby(autoria, lambda x: x[:2])] + autoria = [ + (a, m, max(i for a, m, i in grupo)) + for (a, m), grupo in groupby(autoria, lambda x: x[:2]) + ] return autoria @@ -418,12 +484,15 @@ def unifica_autores_repetidos_no_legado(campo_agregador): # - não excluidas, # - em seguida as que têm col_username, # - em seguida as que têm des_cargo - autores = exec_legado(''' + autores = exec_legado( + """ select {cod_parlamentar}, cod_autor from autor where {cod_parlamentar} is not null order by {cod_parlamentar}, - ind_excluido, col_username desc, des_cargo desc'''.format( - cod_parlamentar=campo_agregador)) + ind_excluido, col_username desc, des_cargo desc""".format( + cod_parlamentar=campo_agregador + ) + ) reapontamento, apagar = get_reapontamento_de_autores_repetidos(autores) @@ -434,62 +503,80 @@ def unifica_autores_repetidos_no_legado(campo_agregador): # Reaponta AUTORIA (many-to-many) # simplificamos retirando inicialmente as autorias excluidas - exec_legado('delete from autoria where ind_excluido = 1') + exec_legado("delete from autoria where ind_excluido = 1") # selecionamos as autorias envolvidas em repetições de autores - from_autoria = ' from autoria where cod_autor in {}' + from_autoria = " from autoria where cod_autor in {}" autoria = exec_legado_em_subconjunto( - 'select cod_autor, cod_materia, ind_primeiro_autor' + from_autoria, - reapontamento) + "select cod_autor, cod_materia, ind_primeiro_autor" + from_autoria, + reapontamento, + ) # apagamos todas as autorias envolvidas - exec_legado_em_subconjunto('delete ' + from_autoria, reapontamento) + exec_legado_em_subconjunto("delete " + from_autoria, reapontamento) # e depois inserimos apenas as sem repetições c ind_primeiro_autor ajustado nova_autoria = get_autorias_sem_repeticoes(autoria, reapontamento) if nova_autoria: - exec_legado(''' + exec_legado( + """ insert into autoria (cod_autor, cod_materia, ind_primeiro_autor, ind_excluido) - values {}'''.format(', '.join([str((a, m, i, 0)) - for a, m, i in nova_autoria]))) + values {}""".format( + ", ".join([str((a, m, i, 0)) for a, m, i in nova_autoria]) + ) + ) # Reaponta outras tabelas que referenciam autor for tabela, _ in TABELAS_REFERENCIANDO_AUTOR: for antigo, novo in reapontamento.items(): if antigo != novo: - exec_legado(''' + exec_legado( + """ update {} set cod_autor = {} where cod_autor = {} - '''.format(tabela, novo, antigo)) + """.format( + tabela, novo, antigo + ) + ) # Finalmente excluimos os autores redundantes, # cujas referências foram todas substituídas a essa altura - exec_legado_em_subconjunto('delete from autor where cod_autor in {}', - apagar) + exec_legado_em_subconjunto( + "delete from autor where cod_autor in {}", apagar + ) def anula_tipos_origem_externa_invalidos(): """Anula tipos de origem externa inválidos para que não impeçam a migração da matéria""" - tipos_validos = primeira_coluna(exec_legado(''' + tipos_validos = primeira_coluna( + exec_legado( + """ select tip_materia from tipo_materia_legislativa - where ind_excluido <> 1;''')) + where ind_excluido <> 1;""" + ) + ) - exec_legado_em_subconjunto(''' + exec_legado_em_subconjunto( + """ update materia_legislativa set tip_origem_externa = NULL - where tip_origem_externa not in {};''', tipos_validos) + where tip_origem_externa not in {};""", + tipos_validos, + ) def get_ids_registros_votacao_para(tabela): - sql = ''' + sql = """ select r.cod_votacao from {} o inner join registro_votacao r on o.cod_ordem = r.cod_ordem and o.cod_materia = r.cod_materia where o.ind_excluido != 1 and r.ind_excluido != 1 order by o.cod_sessao_plen, num_ordem - '''.format(tabela) + """.format( + tabela + ) return set(primeira_coluna(exec_legado(sql))) @@ -502,7 +589,8 @@ def checa_registros_votacao_ambiguos_e_remove_nao_usados(): ordem, expediente = [ get_ids_registros_votacao_para(tabela) - for tabela in ('ordem_dia', 'expediente_materia')] + for tabela in ("ordem_dia", "expediente_materia") + ] # interrompe migração se houver registros ambíguos ambiguos = ordem.intersection(expediente) @@ -510,98 +598,99 @@ def checa_registros_votacao_ambiguos_e_remove_nao_usados(): ambiguos = ambiguos - set(como_resolver) if ambiguos: - warn('registro_votacao_ambiguos', - 'Existe(m) RegistroVotacao ambíguo(s): {cod_votacao}', - {'cod_votacao': ambiguos}) + warn( + "registro_votacao_ambiguos", + "Existe(m) RegistroVotacao ambíguo(s): {cod_votacao}", + {"cod_votacao": ambiguos}, + ) # exclui registros não usados (zumbis) - todos = set(primeira_coluna(exec_legado( - 'select cod_votacao from registro_votacao'))) + todos = set( + primeira_coluna( + exec_legado("select cod_votacao from registro_votacao") + ) + ) nao_usados = todos - ordem.union(expediente) - exec_legado_em_subconjunto(''' + exec_legado_em_subconjunto( + """ update registro_votacao set ind_excluido = 1 - where cod_votacao in {}''', nao_usados) + where cod_votacao in {}""", + nao_usados, + ) PROPAGACOES_DE_EXCLUSAO = [ # sessao_legislativa - ('sessao_legislativa', 'composicao_mesa', 'cod_sessao_leg'), - + ("sessao_legislativa", "composicao_mesa", "cod_sessao_leg"), # parlamentar - ('parlamentar', 'dependente', 'cod_parlamentar'), - ('parlamentar', 'filiacao', 'cod_parlamentar'), - ('parlamentar', 'mandato', 'cod_parlamentar'), - ('parlamentar', 'composicao_mesa', 'cod_parlamentar'), - ('parlamentar', 'composicao_comissao', 'cod_parlamentar'), + ("parlamentar", "dependente", "cod_parlamentar"), + ("parlamentar", "filiacao", "cod_parlamentar"), + ("parlamentar", "mandato", "cod_parlamentar"), + ("parlamentar", "composicao_mesa", "cod_parlamentar"), + ("parlamentar", "composicao_comissao", "cod_parlamentar"), # no 2.5 os parlamentares excluídos não são listados na presença da sessão - ('parlamentar', 'sessao_plenaria_presenca', 'cod_parlamentar'), + ("parlamentar", "sessao_plenaria_presenca", "cod_parlamentar"), # ... nem na presença da ordem do dia - ('parlamentar', 'ordem_dia_presenca', 'cod_parlamentar'), + ("parlamentar", "ordem_dia_presenca", "cod_parlamentar"), # ... nem na mesa da sessão - ('parlamentar', 'mesa_sessao_plenaria', 'cod_parlamentar'), - + ("parlamentar", "mesa_sessao_plenaria", "cod_parlamentar"), # coligacao - ('coligacao', 'composicao_coligacao', 'cod_coligacao'), - + ("coligacao", "composicao_coligacao", "cod_coligacao"), # comissao - ('comissao', 'composicao_comissao', 'cod_comissao'), - ('periodo_comp_comissao', 'composicao_comissao', 'cod_periodo_comp'), - + ("comissao", "composicao_comissao", "cod_comissao"), + ("periodo_comp_comissao", "composicao_comissao", "cod_periodo_comp"), # sessao - ('sessao_plenaria', 'ordem_dia', 'cod_sessao_plen'), - ('sessao_plenaria', 'expediente_materia', 'cod_sessao_plen'), - ('sessao_plenaria', 'expediente_sessao_plenaria', 'cod_sessao_plen'), - ('sessao_plenaria', 'sessao_plenaria_presenca', 'cod_sessao_plen'), - ('sessao_plenaria', 'ordem_dia_presenca', 'cod_sessao_plen'), - ('sessao_plenaria', 'mesa_sessao_plenaria', 'cod_sessao_plen'), - ('sessao_plenaria', 'oradores', 'cod_sessao_plen'), - ('sessao_plenaria', 'oradores_expediente', 'cod_sessao_plen'), - + ("sessao_plenaria", "ordem_dia", "cod_sessao_plen"), + ("sessao_plenaria", "expediente_materia", "cod_sessao_plen"), + ("sessao_plenaria", "expediente_sessao_plenaria", "cod_sessao_plen"), + ("sessao_plenaria", "sessao_plenaria_presenca", "cod_sessao_plen"), + ("sessao_plenaria", "ordem_dia_presenca", "cod_sessao_plen"), + ("sessao_plenaria", "mesa_sessao_plenaria", "cod_sessao_plen"), + ("sessao_plenaria", "oradores", "cod_sessao_plen"), + ("sessao_plenaria", "oradores_expediente", "cod_sessao_plen"), # as consultas no código do sapl 2.5 # votacao_ordem_dia_obter_zsql e votacao_expediente_materia_obter_zsql # indicam que os registros de votação de matérias excluídas não são # exibidos... - ('materia_legislativa', 'registro_votacao', 'cod_materia'), + ("materia_legislativa", "registro_votacao", "cod_materia"), # as exclusões de registro_votacao sem referência # nem a ordem_dia nem a expediente_materia são feitas num método à parte - # materia - ('materia_legislativa', 'tramitacao', 'cod_materia'), - ('materia_legislativa', 'autoria', 'cod_materia'), - ('materia_legislativa', 'anexada', 'cod_materia_principal'), - ('materia_legislativa', 'anexada', 'cod_materia_anexada'), - ('materia_legislativa', 'documento_acessorio', 'cod_materia'), - ('materia_legislativa', 'numeracao', 'cod_materia'), - ('materia_legislativa', 'expediente_materia', 'cod_materia'), - ('materia_legislativa', 'ordem_dia', 'cod_materia'), - ('materia_legislativa', 'acomp_materia', 'cod_materia'), - ('materia_legislativa', 'despacho_inicial', 'cod_materia'), - ('materia_legislativa', 'legislacao_citada', 'cod_materia'), - ('materia_legislativa', 'relatoria', 'cod_materia'), - ('materia_legislativa', 'materia_assunto', 'cod_materia'), - - + ("materia_legislativa", "tramitacao", "cod_materia"), + ("materia_legislativa", "autoria", "cod_materia"), + ("materia_legislativa", "anexada", "cod_materia_principal"), + ("materia_legislativa", "anexada", "cod_materia_anexada"), + ("materia_legislativa", "documento_acessorio", "cod_materia"), + ("materia_legislativa", "numeracao", "cod_materia"), + ("materia_legislativa", "expediente_materia", "cod_materia"), + ("materia_legislativa", "ordem_dia", "cod_materia"), + ("materia_legislativa", "acomp_materia", "cod_materia"), + ("materia_legislativa", "despacho_inicial", "cod_materia"), + ("materia_legislativa", "legislacao_citada", "cod_materia"), + ("materia_legislativa", "relatoria", "cod_materia"), + ("materia_legislativa", "materia_assunto", "cod_materia"), # norma - ('norma_juridica', 'vinculo_norma_juridica', 'cod_norma_referente'), - ('norma_juridica', 'vinculo_norma_juridica', 'cod_norma_referida'), - ('norma_juridica', 'legislacao_citada', 'cod_norma'), - + ("norma_juridica", "vinculo_norma_juridica", "cod_norma_referente"), + ("norma_juridica", "vinculo_norma_juridica", "cod_norma_referida"), + ("norma_juridica", "legislacao_citada", "cod_norma"), # documento administrativo - ('documento_administrativo', 'tramitacao_administrativo', 'cod_documento'), + ("documento_administrativo", "tramitacao_administrativo", "cod_documento"), ] PROPAGACOES_DE_EXCLUSAO_REGISTROS_VOTACAO = [ - ('registro_votacao', 'registro_votacao_parlamentar', 'cod_votacao'), + ("registro_votacao", "registro_votacao_parlamentar", "cod_votacao") ] def propaga_exclusoes(propagacoes): for tabela_pai, tabela_filha, fk in propagacoes: [pk_pai] = get_pk_legado(tabela_pai) - sql = ''' + sql = """ update {} set ind_excluido = 1 where {} not in ( select {} from {} where ind_excluido != 1) - '''.format(tabela_filha, fk, pk_pai, tabela_pai) + """.format( + tabela_filha, fk, pk_pai, tabela_pai + ) exec_legado(sql) @@ -609,12 +698,16 @@ def corrige_unidades_tramitacao_destino_vazia_como_anterior(): """Se uma unidade de tramitação estiver vazia no legado a configura como a anterior""" - for tabela_tramitacao in ['tramitacao', 'tramitacao_administrativo']: - exec_legado(''' + for tabela_tramitacao in ["tramitacao", "tramitacao_administrativo"]: + exec_legado( + """ update {} set cod_unid_tram_dest = cod_unid_tram_local where cod_unid_tram_dest is null; - '''.format(tabela_tramitacao)) + """.format( + tabela_tramitacao + ) + ) def apaga_ref_a_mats_e_docs_inexistentes_em_proposicoes(): @@ -623,28 +716,45 @@ def apaga_ref_a_mats_e_docs_inexistentes_em_proposicoes(): # não seria possível apagá-los, # pois é impossível para um usuário não autor acessar as proposicões # para apagar a referências antes - exec_legado(''' + exec_legado( + """ update proposicao set cod_materia = NULL where cod_materia not in ( select cod_materia from materia_legislativa where ind_excluido <> 1); - ''') - props_sem_mats = list(primeira_coluna(exec_legado(''' + """ + ) + props_sem_mats = list( + primeira_coluna( + exec_legado( + """ select cod_proposicao from proposicao p inner join tipo_proposicao t on p.tip_proposicao = t.tip_proposicao where t.ind_mat_ou_doc = 'M' and cod_mat_ou_doc not in ( select cod_materia from materia_legislativa where ind_excluido <> 1) - '''))) - props_sem_docs = list(primeira_coluna(exec_legado(''' + """ + ) + ) + ) + props_sem_docs = list( + primeira_coluna( + exec_legado( + """ select cod_proposicao from proposicao p inner join tipo_proposicao t on p.tip_proposicao = t.tip_proposicao where t.ind_mat_ou_doc = 'D' and cod_mat_ou_doc not in ( select cod_documento from documento_acessorio where ind_excluido <> 1); - '''))) - exec_legado_em_subconjunto(''' + """ + ) + ) + ) + exec_legado_em_subconjunto( + """ update proposicao set cod_mat_ou_doc = NULL - where cod_proposicao in {}''', props_sem_mats + props_sem_docs) + where cod_proposicao in {}""", + props_sem_mats + props_sem_docs, + ) def uniformiza_banco(): @@ -652,34 +762,41 @@ def uniformiza_banco(): checa_registros_votacao_ambiguos_e_remove_nao_usados() propaga_exclusoes(PROPAGACOES_DE_EXCLUSAO_REGISTROS_VOTACAO) - garante_coluna_no_legado('proposicao', - 'num_proposicao int(11) NULL') + garante_coluna_no_legado("proposicao", "num_proposicao int(11) NULL") - garante_coluna_no_legado('tipo_materia_legislativa', - 'ind_num_automatica BOOLEAN NULL DEFAULT FALSE') + garante_coluna_no_legado( + "tipo_materia_legislativa", + "ind_num_automatica BOOLEAN NULL DEFAULT FALSE", + ) - garante_coluna_no_legado('tipo_materia_legislativa', - 'quorum_minimo_votacao int(11) NULL') + garante_coluna_no_legado( + "tipo_materia_legislativa", "quorum_minimo_votacao int(11) NULL" + ) - garante_coluna_no_legado('materia_legislativa', - 'txt_resultado TEXT NULL') + garante_coluna_no_legado("materia_legislativa", "txt_resultado TEXT NULL") # Cria campos cod_presenca_sessao (sendo a nova PK da tabela) # e dat_sessao em sessao_plenaria_presenca - if not existe_coluna_no_legado('sessao_plenaria_presenca', - 'cod_presenca_sessao'): - exec_legado(''' + if not existe_coluna_no_legado( + "sessao_plenaria_presenca", "cod_presenca_sessao" + ): + exec_legado( + """ ALTER TABLE sessao_plenaria_presenca DROP PRIMARY KEY, ADD cod_presenca_sessao INT auto_increment PRIMARY KEY FIRST; - ''') - assert existe_coluna_no_legado('sessao_plenaria_presenca', - 'cod_presenca_sessao') + """ + ) + assert existe_coluna_no_legado( + "sessao_plenaria_presenca", "cod_presenca_sessao" + ) - garante_coluna_no_legado('sessao_plenaria_presenca', - 'dat_sessao DATE NULL') + garante_coluna_no_legado( + "sessao_plenaria_presenca", "dat_sessao DATE NULL" + ) - garante_tabela_no_legado(''' + garante_tabela_no_legado( + """ CREATE TABLE lexml_registro_publicador ( cod_publicador INT auto_increment NOT NULL, id_publicador INT, nom_publicador varchar(255), @@ -688,9 +805,11 @@ def uniformiza_banco(): nom_responsavel varchar(255), tipo varchar(50), id_responsavel INT, PRIMARY KEY (cod_publicador)); - ''') + """ + ) - garante_tabela_no_legado(''' + garante_tabela_no_legado( + """ CREATE TABLE lexml_registro_provedor ( cod_provedor INT auto_increment NOT NULL, id_provedor INT, nom_provedor varchar(255), @@ -700,16 +819,19 @@ def uniformiza_banco(): tipo varchar(50), id_responsavel INT, xml_provedor longtext, PRIMARY KEY (cod_provedor)); - ''') + """ + ) - garante_tabela_no_legado(''' + garante_tabela_no_legado( + """ CREATE TABLE tipo_situacao_militar ( tip_situacao_militar INT auto_increment NOT NULL, des_tipo_situacao varchar(50), ind_excluido INT, PRIMARY KEY (tip_situacao_militar)); - ''') + """ + ) - update_specs = ''' + update_specs = """ vinculo_norma_juridica | ind_excluido = '' | trim(ind_excluido) = '0' unidade_tramitacao | cod_parlamentar = NULL | cod_parlamentar = 0 parlamentar | cod_nivel_instrucao = NULL | cod_nivel_instrucao = 0 @@ -717,21 +839,21 @@ parlamentar | tip_situacao_militar = NULL | tip_situacao_militar = mandato | tip_afastamento = NULL | tip_afastamento = 0 relatoria | tip_fim_relatoria = NULL | tip_fim_relatoria = 0 sessao_plenaria_presenca | dat_sessao = NULL | dat_sessao = 0 - '''.strip().splitlines() + """.strip().splitlines() for spec in update_specs: - spec = spec.split('|') - exec_legado('UPDATE {} SET {} WHERE {}'.format(*spec)) + spec = spec.split("|") + exec_legado("UPDATE {} SET {} WHERE {}".format(*spec)) # retira apontamentos de materia para assunto inexistente - exec_legado('delete from materia_assunto where cod_assunto = 0') + exec_legado("delete from materia_assunto where cod_assunto = 0") # corrige string "None" em autor exec_legado('update autor set des_cargo = NULL where des_cargo = "None"') - unifica_autores_repetidos_no_legado('cod_parlamentar') - unifica_autores_repetidos_no_legado('cod_comissao') - unifica_autores_repetidos_no_legado('col_username') + unifica_autores_repetidos_no_legado("cod_parlamentar") + unifica_autores_repetidos_no_legado("cod_comissao") + unifica_autores_repetidos_no_legado("col_username") # é importante reverter a exclusão de autores somente depois, para que a # unificação possa dar prioridade às informações dos autores não excluídos @@ -741,10 +863,12 @@ sessao_plenaria_presenca | dat_sessao = NULL | dat_sessao = 0 corrige_unidades_tramitacao_destino_vazia_como_anterior() # matérias inexistentes não são mostradas em norma jurídica => apagamos - exec_legado('''update norma_juridica set cod_materia = NULL + exec_legado( + """update norma_juridica set cod_materia = NULL where cod_materia not in ( select cod_materia from materia_legislativa - where ind_excluido <> 1);''') + where ind_excluido <> 1);""" + ) apaga_ref_a_mats_e_docs_inexistentes_em_proposicoes() @@ -754,16 +878,16 @@ class Record: def iter_sql_records(tabela): - if tabela == 'despacho_inicial': - sql = ''' select cod_materia, cod_comissao from despacho_inicial + if tabela == "despacho_inicial": + sql = """ select cod_materia, cod_comissao from despacho_inicial where ind_excluido <> 1 group by cod_materia, cod_comissao order by cod_materia, min(num_ordem) - ''' + """ else: - sql = 'select * from ' + tabela - if existe_coluna_no_legado(tabela, 'ind_excluido'): - sql += ' where ind_excluido <> 1' + sql = "select * from " + tabela + if existe_coluna_no_legado(tabela, "ind_excluido"): + sql += " where ind_excluido <> 1" cursor = exec_legado(sql) fieldnames = [name[0] for name in cursor.description] for row in cursor.fetchall(): @@ -773,35 +897,51 @@ def iter_sql_records(tabela): def fill_vinculo_norma_juridica(): - lista = [('A', 'Altera o(a)', - 'Alterado(a) pelo(a)'), - ('R', 'Revoga integralmente o(a)', - 'Revogado(a) integralmente pelo(a)'), - ('P', 'Revoga parcialmente o(a)', - 'Revogado(a) parcialmente pelo(a)'), - ('T', 'Revoga integralmente por consolidação', - 'Revogado(a) integralmente por consolidação'), - ('C', 'Norma correlata', - 'Norma correlata'), - ('S', 'Ressalva o(a)', - 'Ressalvada pelo(a)'), - ('E', 'Reedita o(a)', - 'Reeditada pelo(a)'), - ('I', 'Reedita com alteração o(a)', - 'Reeditada com alteração pelo(a)'), - ('G', 'Regulamenta o(a)', - 'Regulamentada pelo(a)'), - ('K', 'Suspende parcialmente o(a)', - 'Suspenso(a) parcialmente pelo(a)'), - ('L', 'Suspende integralmente o(a)', - 'Suspenso(a) integralmente pelo(a)'), - ('N', 'Julga integralmente inconstitucional', - 'Julgada integralmente inconstitucional'), - ('O', 'Julga parcialmente inconstitucional', - 'Julgada parcialmente inconstitucional')] - lista_objs = [TipoVinculoNormaJuridica( - sigla=item[0], descricao_ativa=item[1], descricao_passiva=item[2]) - for item in lista] + lista = [ + ("A", "Altera o(a)", "Alterado(a) pelo(a)"), + ( + "R", + "Revoga integralmente o(a)", + "Revogado(a) integralmente pelo(a)", + ), + ("P", "Revoga parcialmente o(a)", "Revogado(a) parcialmente pelo(a)"), + ( + "T", + "Revoga integralmente por consolidação", + "Revogado(a) integralmente por consolidação", + ), + ("C", "Norma correlata", "Norma correlata"), + ("S", "Ressalva o(a)", "Ressalvada pelo(a)"), + ("E", "Reedita o(a)", "Reeditada pelo(a)"), + ("I", "Reedita com alteração o(a)", "Reeditada com alteração pelo(a)"), + ("G", "Regulamenta o(a)", "Regulamentada pelo(a)"), + ( + "K", + "Suspende parcialmente o(a)", + "Suspenso(a) parcialmente pelo(a)", + ), + ( + "L", + "Suspende integralmente o(a)", + "Suspenso(a) integralmente pelo(a)", + ), + ( + "N", + "Julga integralmente inconstitucional", + "Julgada integralmente inconstitucional", + ), + ( + "O", + "Julga parcialmente inconstitucional", + "Julgada parcialmente inconstitucional", + ), + ] + lista_objs = [ + TipoVinculoNormaJuridica( + sigla=item[0], descricao_ativa=item[1], descricao_passiva=item[2] + ) + for item in lista + ] TipoVinculoNormaJuridica.objects.bulk_create(lista_objs) @@ -810,39 +950,44 @@ def criar_configuracao_inicial(): # se estamos refazendo a migração não recriamos o appconf return False # Ajusta sequencia numérica de protocolo e cria base.AppConfig - if (TipoNumeracaoProtocolo._meta.db_table in TABELAS_LEGADO - and TipoNumeracaoProtocolo.objects.exists()): + if ( + TipoNumeracaoProtocolo._meta.db_table in TABELAS_LEGADO + and TipoNumeracaoProtocolo.objects.exists() + ): # se este banco legado tem a a configuração de numeração de protocolo - tipo = TipoNumeracaoProtocolo.objects.latest('dat_inicial_protocolo') + tipo = TipoNumeracaoProtocolo.objects.latest("dat_inicial_protocolo") descricao = tipo.des_numeracao_protocolo - if 'POR ANO' in descricao: - sequencia_numeracao = 'A' - elif 'POR LEGISLATURA' in descricao: - sequencia_numeracao = 'L' - elif 'CONSECUTIVO' in descricao: - sequencia_numeracao = 'U' + if "POR ANO" in descricao: + sequencia_numeracao = "A" + elif "POR LEGISLATURA" in descricao: + sequencia_numeracao = "L" + elif "CONSECUTIVO" in descricao: + sequencia_numeracao = "U" else: - sequencia_numeracao = 'A' + sequencia_numeracao = "A" appconf = AppConf(sequencia_numeracao=sequencia_numeracao) appconf.save() return True def get_sequence_name_and_last_value(model): - sequence_name = '%s_id_seq' % model._meta.db_table - [(last_value,)] = exec_sql(f'select last_value from {sequence_name}') + sequence_name = "%s_id_seq" % model._meta.db_table + [(last_value,)] = exec_sql(f"select last_value from {sequence_name}") return sequence_name, last_value def reinicia_sequence(model, ultima_pk_legado): ultimo_id = max( ultima_pk_legado, - model.objects.latest('id').id if model.objects.exists() else 0) + model.objects.latest("id").id if model.objects.exists() else 0, + ) sequence_name, last_value = get_sequence_name_and_last_value(model) if ultimo_id > last_value: - exec_sql(f''' + exec_sql( + f""" ALTER SEQUENCE {sequence_name} - RESTART WITH {ultimo_id + 1} MINVALUE -1;''') + RESTART WITH {ultimo_id + 1} MINVALUE -1;""" + ) REPO = git.Repo.init(DIR_REPO) @@ -856,31 +1001,31 @@ def populate_renamed_fields(new, old): if old_field_name: field_type = field.get_internal_type() - if field_type == 'ForeignKey': - fk_field_name = '{}_id'.format(field.name) + if field_type == "ForeignKey": + fk_field_name = "{}_id".format(field.name) value = get_fk_related(field, old) setattr(new, fk_field_name, value) else: value = getattr(old, old_field_name) - if field_type in ('CharField', 'TextField'): - if value in (None, 'None'): - value = '' + if field_type in ("CharField", "TextField"): + if value in (None, "None"): + value = "" elif isinstance(value, str): # retira caracters nulos que o postgres não aceita # quando usamos bulk_create - value = value.replace('\0', '') + value = value.replace("\0", "") # ajusta tempos segundo timezone # os campos TIMESTAMP do mysql são gravados em UTC # os DATETIME e TIME não têm timezone - if field_type == 'DateTimeField' and value: + if field_type == "DateTimeField" and value: # as datas armazenadas no legado na verdade são naive sem_tz = value.replace(tzinfo=None) value = PYTZ_TIMEZONE.localize(sem_tz).astimezone(pytz.utc) - if field_type == 'TimeField' and value: + if field_type == "TimeField" and value: value = value.replace(tzinfo=PYTZ_TIMEZONE) setattr(new, field.name, value) @@ -888,18 +1033,19 @@ def populate_renamed_fields(new, old): def roda_comando_shell(cmd): res = os.system(cmd) - assert res == 0, 'O comando falhou: {}'.format(cmd) + assert res == 0, "O comando falhou: {}".format(cmd) def get_arquivo_ajustes_pre_migracao(): return DIR_DADOS_MIGRACAO.child( - 'ajustes_pre_migracao', '{}.sql'.format(SIGLA_CASA)) + "ajustes_pre_migracao", "{}.sql".format(SIGLA_CASA) + ) def do_flush(): # excluindo database antigo. - info('Excluindo entradas antigas do banco destino.') - FlushCommand().handle(database='default', interactive=False, verbosity=0) + info("Excluindo entradas antigas do banco destino.") + FlushCommand().handle(database="default", interactive=False, verbosity=0) # apaga tipos de autor padrão (criados no flush acima) TipoAutor.objects.all().delete() @@ -916,12 +1062,15 @@ def migrar_dados(flush=False, apagar_do_legado=False): ocorrencias.default_factory = list # restaura dump - arq_dump = Path(DIR_DADOS_MIGRACAO.child( - 'dumps_mysql', '{}.sql'.format(NOME_BANCO_LEGADO))) - assert arq_dump.exists(), 'Dump do mysql faltando: {}'.format(arq_dump) - info('Restaurando dump mysql de [{}]'.format(arq_dump)) + arq_dump = Path( + DIR_DADOS_MIGRACAO.child( + "dumps_mysql", "{}.sql".format(NOME_BANCO_LEGADO) + ) + ) + assert arq_dump.exists(), "Dump do mysql faltando: {}".format(arq_dump) + info("Restaurando dump mysql de [{}]".format(arq_dump)) normaliza_dump_mysql(arq_dump) - roda_comando_shell('mysql -uroot < {}'.format(arq_dump)) + roda_comando_shell("mysql -uroot < {}".format(arq_dump)) # desliga checagens do mysql # e possibilita inserir valor zero em campos de autoincremento @@ -938,21 +1087,21 @@ def migrar_dados(flush=False, apagar_do_legado=False): do_flush() primeira_migracao = criar_configuracao_inicial() - info('Começando migração: ...') + info("Começando migração: ...") migrar_todos_os_models(apagar_do_legado) except Exception as e: - ocorrencias['traceback'] = str(traceback.format_exc()) + ocorrencias["traceback"] = str(traceback.format_exc()) raise e finally: # congela e grava ocorrências ocorrencias.default_factory = None - arq_ocorrencias = Path(REPO.working_dir, 'ocorrencias.yaml') - with open(arq_ocorrencias, 'w') as arq: + arq_ocorrencias = Path(REPO.working_dir, "ocorrencias.yaml") + with open(arq_ocorrencias, "w") as arq: pyaml.dump(ocorrencias, arq, vspacing=1, width=200) REPO.git.add([arq_ocorrencias.name]) - info('Ocorrências salvas em\n {}'.format(arq_ocorrencias)) + info("Ocorrências salvas em\n {}".format(arq_ocorrencias)) if not ocorrencias: - info('NÃO HOUVE OCORRÊNCIAS !!!') + info("NÃO HOUVE OCORRÊNCIAS !!!") # recria tipos de autor padrão que não foram criados pela migração cria_models_tipo_autor() @@ -967,13 +1116,17 @@ def move_para_depois_de(lista, movido, referencias): return lista -TABELAS_LEGADO = [t for (t,) in exec_legado('show tables')] -EXISTE_REUNIAO_NO_LEGADO = 'reuniao_comissao' in TABELAS_LEGADO +TABELAS_LEGADO = [t for (t,) in exec_legado("show tables")] +EXISTE_REUNIAO_NO_LEGADO = "reuniao_comissao" in TABELAS_LEGADO def get_models_a_migrar(): - models = [model for app in appconfs for model in app.models.values() - if model in field_renames] + models = [ + model + for app in appconfs + for model in app.models.values() + if model in field_renames + ] # retira reuniões quando não existe na base legada # (só existe no sapl 3.0) if not EXISTE_REUNIAO_NO_LEGADO: @@ -982,11 +1135,13 @@ def get_models_a_migrar(): # a migração de TipoProposicao precisa ser feita # após TipoMateriaLegislativa e TipoDocumento # (porém antes de Proposicao) - move_para_depois_de(models, TipoProposicao, - [TipoMateriaLegislativa, TipoDocumento]) + move_para_depois_de( + models, TipoProposicao, [TipoMateriaLegislativa, TipoDocumento] + ) assert models.index(TipoProposicao) < models.index(Proposicao) - move_para_depois_de(models, Proposicao, - [MateriaLegislativa, DocumentoAcessorio]) + move_para_depois_de( + models, Proposicao, [MateriaLegislativa, DocumentoAcessorio] + ) return models @@ -997,7 +1152,7 @@ def migrar_todos_os_models(apagar_do_legado): def migrar_model(model, apagar_do_legado): - print('Migrando %s...' % model.__name__) + print("Migrando %s..." % model.__name__) model_legado, tabela_legado, campos_pk_legado = get_estrutura_legado(model) @@ -1006,7 +1161,7 @@ def migrar_model(model, apagar_do_legado): # A PK NO LEGADO TEM UM ÚNICO CAMPO nome_pk = model_legado._meta.pk.name - if 'ind_excluido' in {f.name for f in model_legado._meta.fields}: + if "ind_excluido" in {f.name for f in model_legado._meta.fields}: # se o model legado tem o campo ind_excluido # enumera apenas os não excluídos old_records = model_legado.objects.filter(~Q(ind_excluido=1)) @@ -1020,15 +1175,16 @@ def migrar_model(model, apagar_do_legado): ids_ja_migrados = get_all_ids_from_model(model) apagados_pelo_usuario = [ - int(v.object_id) - for v in Version.objects.get_deleted(model)] + int(v.object_id) for v in Version.objects.get_deleted(model) + ] def ja_esta_migrado(old): id = get_id_do_legado(old) return id in ids_ja_migrados or id in apagados_pelo_usuario - ultima_pk_legado = model_legado.objects.all().aggregate( - Max('pk'))['pk__max'] or 0 + ultima_pk_legado = ( + model_legado.objects.all().aggregate(Max("pk"))["pk__max"] or 0 + ) else: # A PK NO LEGADO TEM MAIS DE UM CAMPO @@ -1037,33 +1193,43 @@ def migrar_model(model, apagar_do_legado): get_id_do_legado = None renames = field_renames[model] - campos_velhos_p_novos = {v: k - for k, v in renames.items()} + campos_velhos_p_novos = {v: k for k, v in renames.items()} if model_legado == Numeracao: # nao usamos cod_numeracao no 3.1 => apelamos p todos os campos - campos_chave = ['cod_materia', 'tip_materia', 'num_materia', - 'ano_materia', 'dat_materia'] + campos_chave = [ + "cod_materia", + "tip_materia", + "num_materia", + "ano_materia", + "dat_materia", + ] else: campos_chave = campos_pk_legado def sem_sufixo_id(k): - return k[:-3] if k.endswith('_id') else k + return k[:-3] if k.endswith("_id") else k apagados_pelo_usuario = Version.objects.get_deleted(model) apagados_pelo_usuario = [ {sem_sufixo_id(k): v for k, v in version.field_dict.items()} - for version in apagados_pelo_usuario] + for version in apagados_pelo_usuario + ] campos_chave_novos = {campos_velhos_p_novos[c] for c in campos_chave} apagados_pelo_usuario = [ {k: v for k, v in apagado.items() if k in campos_chave_novos} - for apagado in apagados_pelo_usuario] + for apagado in apagados_pelo_usuario + ] def ja_esta_migrado(old): - chave = {campos_velhos_p_novos[c]: getattr(old, c) - for c in campos_chave} - return (chave in apagados_pelo_usuario - or model.objects.filter(**chave).exists()) + chave = { + campos_velhos_p_novos[c]: getattr(old, c) for c in campos_chave + } + return ( + chave in apagados_pelo_usuario + or model.objects.filter(**chave).exists() + ) + ultima_pk_legado = model_legado.objects.count() ajuste_antes_salvar = AJUSTE_ANTES_SALVAR.get(model) @@ -1072,7 +1238,7 @@ def migrar_model(model, apagar_do_legado): # convert old records to new ones with transaction.atomic(): novos = [] - sql_delete_legado = '' + sql_delete_legado = "" for old in old_records: if ja_esta_migrado(old): # pulamos esse objeto, pois já foi migrado anteriormente @@ -1088,7 +1254,7 @@ def migrar_model(model, apagar_do_legado): # tentamos preencher uma FK e o ojeto relacionado # não existe # então este é um objeo órfão: simplesmente ignoramos - warn('fk', e.msg, e.dados) + warn("fk", e.msg, e.dados) continue else: new.clean() # valida model @@ -1096,17 +1262,18 @@ def migrar_model(model, apagar_do_legado): # acumula deleção do registro no legado if apagar_do_legado: - sql_delete_legado += 'delete from {} where {};\n'.format( + sql_delete_legado += "delete from {} where {};\n".format( tabela_legado, - ' and '.join( - '{} = "{}"'.format(campo, - getattr(old, campo)) - for campo in campos_pk_legado)) + " and ".join( + '{} = "{}"'.format(campo, getattr(old, campo)) + for campo in campos_pk_legado + ), + ) # salva novos registros with reversion.create_revision(): model.objects.bulk_create(novos) - reversion.set_comment('Objetos criados pela migração') + reversion.set_comment("Objetos criados pela migração") if ajuste_depois_salvar: ajuste_depois_salvar() @@ -1126,6 +1293,7 @@ def migrar_model(model, apagar_do_legado): # MIGRATION_ADJUSTMENTS ##################################################### + def adjust_acompanhamentomateria(new, old): new.confirmado = True @@ -1134,15 +1302,16 @@ def adjust_documentoadministrativo(new, old): if old.num_protocolo: numero, ano = old.num_protocolo, new.ano # False < True => o primeiro será o protocolo não anulado - protocolos = Protocolo.objects.filter( - numero=numero, ano=ano).order_by('anulado') + protocolos = Protocolo.objects.filter(numero=numero, ano=ano).order_by( + "anulado" + ) if protocolos: new.protocolo = protocolos[0] else: # Se não achamos o protocolo registramos no número externo new.numero_externo = numero - nota = ''' + nota = """ ## NOTA DE MIGRAÇÃO DE DADOS DO SAPL 2.5 ## O número de protocolo original deste documento era [{numero}], ano [{ano}]. @@ -1150,22 +1319,29 @@ Não existe no sistema nenhum protocolo com estes dados e portanto nenhum protocolo foi vinculado a este documento. Colocamos então o número de protocolo no campo "número externo". -''' +""" nota = nota.strip().format(numero=numero, ano=ano) - msg = 'Protocolo {numero} faltando (referenciado ' \ - 'no documento administrativo {cod_documento})' - warn('protocolo_faltando', msg, - {'numero': numero, - 'cod_documento': old.cod_documento, - 'nota': nota}) - new.observacao += ('\n\n' if new.observacao else '') + nota + msg = ( + "Protocolo {numero} faltando (referenciado " + "no documento administrativo {cod_documento})" + ) + warn( + "protocolo_faltando", + msg, + { + "numero": numero, + "cod_documento": old.cod_documento, + "nota": nota, + }, + ) + new.observacao += ("\n\n" if new.observacao else "") + nota def adjust_mandato(new, old): if old.dat_fim_mandato: new.data_fim_mandato = old.dat_fim_mandato if not new.data_fim_mandato: - legislatura = Legislatura.objects.latest('data_fim') + legislatura = Legislatura.objects.latest("data_fim") new.data_fim_mandato = legislatura.data_fim new.data_expedicao_diploma = legislatura.data_inicio if not new.data_inicio_mandato: @@ -1181,10 +1357,12 @@ def adjust_ordemdia_antes_salvar(new, old): if old.num_ordem is None: new.numero_ordem = 999999999 - warn('ordem_dia_num_ordem_nulo', - 'OrdemDia de PK {pk} tinha numero ordem nulo. ' - 'O valor %s foi colocado no lugar.' % new.numero_ordem, - {'pk': old.pk}) + warn( + "ordem_dia_num_ordem_nulo", + "OrdemDia de PK {pk} tinha numero ordem nulo. " + "O valor %s foi colocado no lugar." % new.numero_ordem, + {"pk": old.pk}, + ) def adjust_parlamentar(new, old): @@ -1194,16 +1372,24 @@ def adjust_parlamentar(new, old): # but data includes null values # => transform None to False if value is None: - warn('unidade_deliberativa_nulo_p_false', - 'nulo convertido para falso na unidade_deliberativa ' - 'do parlamentar {pk_parlamentar}', - {'pk_parlamentar': old.cod_parlamentar}) + warn( + "unidade_deliberativa_nulo_p_false", + "nulo convertido para falso na unidade_deliberativa " + "do parlamentar {pk_parlamentar}", + {"pk_parlamentar": old.cod_parlamentar}, + ) new.unidade_deliberativa = False # migra município de residência if old.cod_localidade_resid: - municipio_uf = list(exec_legado(''' + municipio_uf = list( + exec_legado( + """ select nom_localidade, sgl_uf from localidade - where cod_localidade = {}'''.format(old.cod_localidade_resid))) + where cod_localidade = {}""".format( + old.cod_localidade_resid + ) + ) + ) if municipio_uf: new.municipio_residencia, new.uf_residencia = municipio_uf[0] @@ -1211,32 +1397,38 @@ def adjust_parlamentar(new, old): def adjust_participacao(new, old): comissao_id, periodo_id = [ get_fk_related(Composicao._meta.get_field(name), old) - for name in ('comissao', 'periodo')] + for name in ("comissao", "periodo") + ] with reversion.create_revision(): composicao, _ = Composicao.objects.get_or_create( - comissao_id=comissao_id, periodo_id=periodo_id) - reversion.set_comment('Objeto criado pela migração') + comissao_id=comissao_id, periodo_id=periodo_id + ) + reversion.set_comment("Objeto criado pela migração") new.composicao = composicao def adjust_normarelacionada(new, old): new.tipo_vinculo = TipoVinculoNormaJuridica.objects.get( - sigla=old.tip_vinculo) + sigla=old.tip_vinculo + ) def adjust_protocolo_antes_salvar(new, old): if new.numero is None: new.numero = old.cod_protocolo - warn('num_protocolo_nulo', - 'Número do protocolo de PK {cod_protocolo} era nulo ' - 'e foi alterado para sua pk ({cod_protocolo})', - {'cod_protocolo': old.cod_protocolo}) + warn( + "num_protocolo_nulo", + "Número do protocolo de PK {cod_protocolo} era nulo " + "e foi alterado para sua pk ({cod_protocolo})", + {"cod_protocolo": old.cod_protocolo}, + ) def get_arquivo_resolve_registro_votacao(): return DIR_DADOS_MIGRACAO.child( - 'ajustes_pre_migracao', - '{}_resolve_registro_votacao_ambiguo.yaml'.format(SIGLA_CASA)) + "ajustes_pre_migracao", + "{}_resolve_registro_votacao_ambiguo.yaml".format(SIGLA_CASA), + ) def get_como_resolver_registro_votacao_ambiguo(): @@ -1249,9 +1441,11 @@ def get_como_resolver_registro_votacao_ambiguo(): def adjust_registrovotacao_antes_salvar(new, old): ordem_dia = OrdemDia.objects.filter( - pk=old.cod_ordem, materia=old.cod_materia) + pk=old.cod_ordem, materia=old.cod_materia + ) expediente_materia = ExpedienteMateria.objects.filter( - pk=old.cod_ordem, materia=old.cod_materia) + pk=old.cod_ordem, materia=old.cod_materia + ) if ordem_dia and not expediente_materia: new.ordem = ordem_dia[0] @@ -1261,29 +1455,33 @@ def adjust_registrovotacao_antes_salvar(new, old): if ordem_dia and expediente_materia: como_resolver = get_como_resolver_registro_votacao_ambiguo() campo = como_resolver[new.id] - if campo.startswith('ordem'): + if campo.startswith("ordem"): new.ordem = ordem_dia[0] - elif campo.startswith('expediente'): + elif campo.startswith("expediente"): new.expediente = expediente_materia[0] else: - raise Exception(''' + raise Exception( + """ Registro de Votação ambíguo: {} - Resolva criando o arquivo {}'''.format( - new.id, get_arquivo_resolve_registro_votacao())) + Resolva criando o arquivo {}""".format( + new.id, get_arquivo_resolve_registro_votacao() + ) + ) def adjust_tipoafastamento(new, old): assert xor(old.ind_afastamento, old.ind_fim_mandato) if old.ind_afastamento: - new.indicador = 'A' + new.indicador = "A" elif old.ind_fim_mandato: - new.indicador = 'F' + new.indicador = "F" def set_generic_fk(new, campo_virtual, old): model = campo_virtual.related_model new.content_type = ContentType.objects.get( - app_label=model._meta.app_label, model=model._meta.model_name) + app_label=model._meta.app_label, model=model._meta.model_name + ) new.object_id = get_fk_related(campo_virtual, old) @@ -1305,11 +1503,11 @@ def adjust_proposicao_antes_salvar(new, old): def adjust_statustramitacao(new, old): if old.ind_fim_tramitacao: - new.indicador = 'F' + new.indicador = "F" elif old.ind_retorno_tramitacao: - new.indicador = 'R' + new.indicador = "R" else: - new.indicador = '' + new.indicador = "" def adjust_statustramitacaoadm(new, old): @@ -1317,14 +1515,15 @@ def adjust_statustramitacaoadm(new, old): def adjust_tramitacao(new, old): - if old.sgl_turno == 'Ú': - new.turno = 'U' + if old.sgl_turno == "Ú": + new.turno = "U" def adjust_tipo_autor(new, old): - model_apontado = normalize(new.descricao.lower()).replace(' ', '') - content_types = ContentType.objects.filter( - model=model_apontado).exclude(app_label='legacy') + model_apontado = normalize(new.descricao.lower()).replace(" ", "") + content_types = ContentType.objects.filter(model=model_apontado).exclude( + app_label="legacy" + ) assert len(content_types) <= 1 new.content_type = content_types[0] if content_types else None @@ -1335,8 +1534,8 @@ def adjust_normajuridica_antes_salvar(new, old): # combobox era selecionada, o sistema pegava a primeira letra da seleção, # sendo F para Federal, E para Estadual, M para Municipal e o S para # Selecionar, que era a primeira opção quando nada era selecionado. - if old.tip_esfera_federacao == 'S': - new.esfera_federacao = '' + if old.tip_esfera_federacao == "S": + new.esfera_federacao = "" def adjust_normajuridica_depois_salvar(): @@ -1344,8 +1543,9 @@ def adjust_normajuridica_depois_salvar(): ligacao = NormaJuridica.assuntos.through assuntos_migrados, normas_migradas = [ - set(model.objects.values_list('id', flat=True)) - for model in [AssuntoNorma, NormaJuridica]] + set(model.objects.values_list("id", flat=True)) + for model in [AssuntoNorma, NormaJuridica] + ] def filtra_assuntos_migrados(cod_assunto): """cod_assunto é uma string com cods separados por vírgulas @@ -1353,13 +1553,15 @@ def adjust_normajuridica_depois_salvar(): """ if not cod_assunto: return [] - cods = {int(a) for a in cod_assunto.split(',') if a} + cods = {int(a) for a in cod_assunto.split(",") if a} return sorted(cods.intersection(assuntos_migrados)) old_normajurica_cod_assuntos = OldNormaJuridica.objects.filter( - pk__in=normas_migradas).values_list('pk', 'cod_assunto') - ja_migrados = set(ligacao.objects.values_list( - 'normajuridica_id', 'assuntonorma_id')) + pk__in=normas_migradas + ).values_list("pk", "cod_assunto") + ja_migrados = set( + ligacao.objects.values_list("normajuridica_id", "assuntonorma_id") + ) normas_assuntos = [ (norma, assunto) @@ -1372,15 +1574,18 @@ def adjust_normajuridica_depois_salvar(): ligacao.objects.bulk_create( ligacao(normajuridica_id=norma, assuntonorma_id=assunto) - for norma, assunto in normas_assuntos) + for norma, assunto in normas_assuntos + ) def adjust_autor(new, old): # vincula autor com o objeto relacionado, tentando os três campos antigos # o primeiro campo preenchido será usado, podendo lançar ForeignKeyFaltando - for model_relacionado, campo_nome in [(Parlamentar, 'nome_parlamentar'), - (Comissao, 'nome'), - (Partido, 'nome')]: + for model_relacionado, campo_nome in [ + (Parlamentar, "nome_parlamentar"), + (Comissao, "nome"), + (Partido, "nome"), + ]: field = CAMPOS_VIRTUAIS_AUTOR[model_relacionado] fk_encontrada = get_fk_related(field, old) if fk_encontrada: @@ -1390,15 +1595,18 @@ def adjust_autor(new, old): if old.col_username: user, created = get_user_model().objects.get_or_create( - username=old.col_username) + username=old.col_username + ) if created: # gera uma senha inutilizável, que precisará ser trocada user.set_password(None) with reversion.create_revision(): user.save() reversion.set_comment( - 'Usuário criado pela migração para o autor {}'.format( - old.cod_autor)) + "Usuário criado pela migração para o autor {}".format( + old.cod_autor + ) + ) grupo_autor = Group.objects.get(name="Autor") user.groups.add(grupo_autor) new.user = user @@ -1407,33 +1615,39 @@ def adjust_autor(new, old): def adjust_comissao(new, old): if not old.dat_extincao and not old.dat_fim_comissao: new.ativa = True - elif (old.dat_extincao and date.today() < new.data_extincao or - old.dat_fim_comissao and date.today() < new.data_fim_comissao): + elif ( + old.dat_extincao + and date.today() < new.data_extincao + or old.dat_fim_comissao + and date.today() < new.data_fim_comissao + ): new.ativa = True else: new.ativa = False def adjust_tiporesultadovotacao(new, old): - if 'aprova' in new.nome.lower(): + if "aprova" in new.nome.lower(): new.natureza = TipoResultadoVotacao.NATUREZA_CHOICES.aprovado - elif 'rejeita' in new.nome.lower(): + elif "rejeita" in new.nome.lower(): new.natureza = TipoResultadoVotacao.NATUREZA_CHOICES.rejeitado - elif 'retirado' in new.nome.lower(): + elif "retirado" in new.nome.lower(): new.natureza = TipoResultadoVotacao.NATUREZA_CHOICES.rejeitado else: - if new.nome != 'DESCONHECIDO': + if new.nome != "DESCONHECIDO": # ignoramos a natureza de item criado pela migração - warn('natureza_desconhecida_tipo_resultadovotacao', - 'Não foi possível identificar a natureza do ' - 'tipo de resultado de votação [{pk}: "{nome}"]', - {'pk': new.pk, 'nome': new.nome}) + warn( + "natureza_desconhecida_tipo_resultadovotacao", + "Não foi possível identificar a natureza do " + 'tipo de resultado de votação [{pk}: "{nome}"]', + {"pk": new.pk, "nome": new.nome}, + ) def str_to_time(fonte): if not fonte.strip(): return None - tempo = datetime.datetime.strptime(fonte, '%H:%M') + tempo = datetime.datetime.strptime(fonte, "%H:%M") return tempo.time() if tempo else None @@ -1442,13 +1656,13 @@ def adjust_reuniao_comissao(new, old): def remove_style(conteudo): - if 'style' not in conteudo: + if "style" not in conteudo: return conteudo # atalho que acelera muito os casos sem style - soup = BeautifulSoup(conteudo, 'html.parser') + soup = BeautifulSoup(conteudo, "html.parser") for tag in soup.recursiveChildGenerator(): - if hasattr(tag, 'attrs'): - tag.attrs = {k: v for k, v in tag.attrs.items() if k != 'style'} + if hasattr(tag, "attrs"): + tag.attrs = {k: v for k, v in tag.attrs.items() if k != "style"} return str(soup) @@ -1481,19 +1695,17 @@ AJUSTE_ANTES_SALVAR = { Reuniao: adjust_reuniao_comissao, } -AJUSTE_DEPOIS_SALVAR = { - NormaJuridica: adjust_normajuridica_depois_salvar, -} +AJUSTE_DEPOIS_SALVAR = {NormaJuridica: adjust_normajuridica_depois_salvar} # MARCO ###################################################################### -TIME_FORMAT = '%H:%M:%S' +TIME_FORMAT = "%H:%M:%S" # permite a gravação de tempos puros pelo pretty-yaml def time_representer(dumper, data): - return dumper.represent_scalar('!time', data.strftime(TIME_FORMAT)) + return dumper.represent_scalar("!time", data.strftime(TIME_FORMAT)) UnsafePrettyYAMLDumper.add_representer(datetime.time, time_representer) @@ -1505,12 +1717,12 @@ def time_constructor(loader, node): return datetime.datetime.strptime(value, TIME_FORMAT).time() -yaml.add_constructor(u'!time', time_constructor) +yaml.add_constructor("!time", time_constructor) -TAG_MARCO = 'marco' +TAG_MARCO = "marco" -def gravar_marco(nome_dir='dados', pula_se_ja_existe=False): +def gravar_marco(nome_dir="dados", pula_se_ja_existe=False): """Grava um dump de todos os dados como arquivos yaml no repo de marco """ # prepara ou localiza repositorio @@ -1524,36 +1736,41 @@ def gravar_marco(nome_dir='dados', pula_se_ja_existe=False): # exporta dados como arquivos yaml user_model = get_user_model() models = get_models_a_migrar() + [ - Composicao, user_model, Group, ContentType] + Composicao, + user_model, + Group, + ContentType, + ] sequences = [] for model in models: - info('Gravando marco de [{}]'.format(model.__name__)) + info("Gravando marco de [{}]".format(model.__name__)) dir_model = dir_dados.child(model._meta.app_label, model.__name__) dir_model.mkdir(parents=True) for data in model.objects.all().values(): - nome_arq = Path(dir_model, '{}.yaml'.format(data['id'])) - with open(nome_arq, 'w') as arq: + nome_arq = Path(dir_model, "{}.yaml".format(data["id"])) + with open(nome_arq, "w") as arq: pyaml.dump(data, arq) sequences.append(get_sequence_name_and_last_value(model)) # grava valores das seqeunces sequences = dict(sorted(sequences)) - Path(dir_dados, 'sequences.yaml').write_file(pyaml.dump(sequences)) + Path(dir_dados, "sequences.yaml").write_file(pyaml.dump(sequences)) # backup do banco - print('Gerando backup do banco... ', end='', flush=True) - arq_backup = DIR_REPO.child('{}.backup'.format(NOME_BANCO_LEGADO)) + print("Gerando backup do banco... ", end="", flush=True) + arq_backup = DIR_REPO.child("{}.backup".format(NOME_BANCO_LEGADO)) arq_backup.remove() - backup_cmd = ''' + backup_cmd = """ pg_dump --host localhost --port 5432 --username postgres --no-password - --format custom --blobs --verbose --file {} {}'''.format( - arq_backup, NOME_BANCO_LEGADO) + --format custom --blobs --verbose --file {} {}""".format( + arq_backup, NOME_BANCO_LEGADO + ) subprocess.check_output(backup_cmd.split(), stderr=subprocess.DEVNULL) - print('SUCESSO') + print("SUCESSO") # salva mudanças REPO.git.add([dir_dados.name]) REPO.git.add([arq_backup.name]) - if 'master' not in REPO.heads or REPO.index.diff('HEAD'): + if "master" not in REPO.heads or REPO.index.diff("HEAD"): # se de fato existe mudança - REPO.index.commit(f'Grava marco (em {nome_dir})') - REPO.git.execute('git tag -f'.split() + [TAG_MARCO]) + REPO.index.commit(f"Grava marco (em {nome_dir})") + REPO.git.execute("git tag -f".split() + [TAG_MARCO])