def __init__(self, xml_lattes, ano_incial, ano_final): self.ano_inicial = ano_incial self.ano_final = ano_final tree = ET.parse(xml_lattes) self.xml_root = tree.getroot() Alerta.addAlerta( "Aviso: para efeito de pontuação da produção bibliogáfica são contados os dois ultimo anos" " desprezando o ano corrente.") artigos_periodicos = self.__artigos() self.artigos_periodicos = artigos_periodicos[0] self.pontos = artigos_periodicos[1] trabalhos_eventos = self.__trabalho_eventos() self.lista_artigos_eventos = trabalhos_eventos[0] self.pontos += trabalhos_eventos[1] capitulos = self.__capitulo_livro() self.capitulos_livro = capitulos[0] self.pontos += capitulos[1] livros = self.__livro() self.lista_livros = livros[0] self.pontos += livros[1]
def __parse_iniciacoes_cientificas(self): # Extraindo do texto os dados sobre orientacoes # orientacoes = page_content.split('Título:') Resumo: orientacoes = re.findall(r'Título:(.*?)Resumo:', self.__page_content) lista_orientacoes = [] for orientacao in orientacoes: # if(orientacao == ""): # continue titulo = re.search(r'(.*?)Data de início:', orientacao).group(1) data_inicio_str = re.search( r'Data de início:(.*?)Data de término:', orientacao).group(1) if (data_inicio_str == ""): Alerta.addAlerta( "Iniciação Científica '" + titulo + "'não computada por não ter data de início definida.") continue data_inicio_ic = datetime.strptime(data_inicio_str, '%d/%m/%Y').date() if (self.fim_intersticio is not None): if (data_inicio_ic > self.fim_intersticio ): # IC começou depois do fim do intertício. continue data_termino_str = re.search(r'Data de término:(.*)', orientacao).group(1) if (data_termino_str != ""): data_termino = datetime.strptime(data_termino_str, '%d/%m/%Y').date() if (self.inicio_intersticio != None): # Errado! if (data_termino < self.inicio_intersticio ): # orientação terminou depois do intertício. continue else: data_termino = None tupletOrientacao = (titulo, data_inicio_ic, data_termino) lista_orientacoes.append(tupletOrientacao) return lista_orientacoes
def __init__(self, portal_docente:PortalDocente, ficha_funcional: FichaFuncional, producao_intelectual : ProducaoIntelectual): #Limpa os alertas preparando para o próximo parecer. Alerta.lista_alertas.clear() self.portal_docente = portal_docente self.ficha_funcional = ficha_funcional self.producao_intelectual_lattes = producao_intelectual self.lista_aquivos =list() self.status_parecer = StatusParecer.FAVORAVEL if (not ficha_funcional.is_valid()): Alerta.addAlerta("Importante: Ficha funcional vencida. Solicitar nova ao interessado") dt_permitida_processo = ficha_funcional.fim_intersticio - timedelta(days=60) if (date.today() < dt_permitida_processo): Alerta.addAlerta( "Verificar: Possível processo prematuro de progressão. Se verificado, devolver ao interessado (Art. 26, § 1).")
def __calcula_pontuacao(self): dic_pontuacao = dict() keys = self.dic_encargo_didatico.keys() if(self.nivel_ensino == NivelEnsino.POSGRADUACAO): for k in keys: dic_pontuacao[k] = (self.dic_encargo_didatico[k] / 15) * 5 return dic_pontuacao else: for k in keys: if (self.dic_encargo_didatico[ k] <= 120): # Até 8 horas semanais (2 disciplinas de 60 horas), fator de mult. é 5 dic_pontuacao[k] = (self.dic_encargo_didatico[k] / 15) * 5 else: dif = self.dic_encargo_didatico[k] - 120 dic_pontuacao[k] = (((120 / 15) * 5) + ((dif / 15) * 10)) if (dic_pontuacao[k] > 120): # limita a 16 horas somente para graduação? @todo duvida cpad dic_pontuacao[k] = 120 Alerta.addAlerta("Teto de encargo de ensino atingido em " + str(k)) return dic_pontuacao
def emitir_parecer_progressao(self, gravar_log= True): self.quadro_pontuacao[AnexoIII.ENSINO.value] = self.__verifica_retricoes_ensino(self.portal_docente) self.quadro_pontuacao[AnexoIII.ORIENTACAO.value] = self.portal_docente.orientacoes.pontos pontos_projeto_pesquisa = self.portal_docente.projetos_pesquisa.pontos pontos_acoes_extensao = self.portal_docente.acoes_extensao.pontos pontos_pesquisa_extensao = pontos_projeto_pesquisa+pontos_acoes_extensao self.quadro_pontuacao[AnexoIII.PESQUISA_EXTENSAO.value] = pontos_pesquisa_extensao pontos_ic = self.portal_docente.iniciacoes_cientificas.pontos self.quadro_pontuacao[AnexoIII.OUTRAS_ATIVIDADES.value] = pontos_ic # + ....incluir outros no futuro. self.quadro_pontuacao[AnexoIII.PRODUCAO_INTELECTUAL.value] = self.producao_intelectual_lattes.pontos if(self.__pontuacao_total() < 240): self.status_parecer = StatusParecer.INCONCLUSIVO Alerta.addAlerta("Importante: é necessário verificar outras produções do docente para atingir o mínimo de " "240 pontos.") self.__preencher_docx_anexo3() if (gravar_log): self.gravar_log()
def __verifica_retricoes_ensino(self, portal_docente:PortalDocente): #Verifica o mínimo de 120 horas por ano na graduação (Art 4 §2) encargo_anual = portal_docente.disciplinas_grad.encargo_docente_anual_grad() keys = encargo_anual.keys() for k in keys: if(encargo_anual[k] < 120): Alerta.addAlerta("Importante: em "+ str(k) + " não foi atingido o mínimo de 120 horas na graduacão (Art 4 §2)." "\n Verifique se o servidor ocupava cargo administrativo " ", se ficou afastado, ou se admissão foi atemporal. ") self.status_parecer = StatusParecer.INCONCLUSIVO #Verifica o mínimo de 40 pontos semestre (Art 35 §3) pontuacao_grad = portal_docente.disciplinas_grad.pontos_semestre pontuacao_posgrad = portal_docente.disciplinas_posgrad.pontos_semestre pontos_somados_periodos = {k: pontuacao_grad.get(k, 0) + pontuacao_posgrad.get(k, 0) for k in set(pontuacao_grad)} keys = portal_docente.disciplinas_grad.dic_encargo_didatico.keys() for k in keys: if ((pontos_somados_periodos[k] < 40) and (k[-1] != '3')): Alerta.addAlerta("Importante: não foi atingido o mínimo de 40 pontos de ensino (graduação + pós) no semestre "+ str(k) + "(Art 4 §2)." "\n Verificar se o servidor ocupava cargo administrativo ou encontrava-se afastado em " + str(k)) self.status_parecer = StatusParecer.INCONCLUSIVO total_pontos_ensino = portal_docente.disciplinas_grad.pontos + portal_docente.disciplinas_posgrad.pontos if(settings.aplicar_art52): fator_mult_media = 4 - settings.periodos_concluido_art52 # 4 periodos são previstos para chegar nos 160 pontos. total_pontos_ensino += (portal_docente.disciplinas_grad.media_pontos + portal_docente.disciplinas_posgrad.media_pontos) * fator_mult_media Alerta.addAlerta("Importante: Art. 52 aplicado. A pontuação da Área 1 é a média dos semestres concluídos indicados " "manualmente no filtro de configurações do sistema.") # Verifica a pontuação mínima de 160 pontos (Art. 37, § 1 if(total_pontos_ensino < 160): Alerta.addAlerta("Importante: não foi atingido o mínimo de 160 pontos no interstício para a área de ensino. (Art. 37, §1) " "\n Verifique se o servidor ocupava cargo administrativo ou encontrava-se ou estava " "afastado do período do insterstício") self.status_parecer = StatusParecer.INCONCLUSIVO return total_pontos_ensino
def __busca_disciplinas_grad(self, remove_duplicatas=True): # Extraindo do texto os dados sobre as disciplinas # disciplinas = re.findall(r'Disciplina:(.*?)Vagas ocupadas:', self.page_content) disciplinas = re.split(r'Disciplina:', self.page_content) lista_disciplinas = list() # somatório disciplinas de estágio sum_estagio_indireto = 0 sum_estagio_semidireto = 0 for disciplina in disciplinas: if (disciplina == ''): continue; codigo_disciplina = re.search(r'Código:(.*?)Período', disciplina).group(1) nome_disciplina = re.search(r'(.*?)Código', disciplina).group(1) nome_disciplina = nome_disciplina.upper() periodo = re.search(r'Período:(.*?)Curso', disciplina).group(1) # remove disciplinas canceladas de 2020/1 devido a pandemia COVID-19. @todo Testar como fica isso com # disciplina da matemática industrial. if (codigo_disciplina.endswith("I") and periodo == "2020/1"): continue vagas_ocupadas = float(re.search(r'Vagas ocupadas:(\d+)', disciplina).group(1)) if (vagas_ocupadas == 0): continue # não conta disciplinas que não tem nenhum aluno matriculado. if (nome_disciplina in self.filtro_disciplina): # remove as disciplinas de TCC (Art4,3) Alerta.addAlerta("Disciplina removida (Art 4, §3): " + nome_disciplina) continue # @todo dúvida para CPAD if (periodo in self.filtro_periodo): try: encargo_didatico = float(re.search(r'Encargo didático:(\d+.\d)', disciplina).group(1)) except: continue # encargo_didatico = 0 else: continue # Verificação dos estágios - somente graduação? @cpad dúvida. if any(nome_disciplina[0:8] in s for s in self.filtro_estagio_semidireta): Alerta.addAlerta("Pontuado com o estágio semi-direto (Art 35)." + nome_disciplina) if (float(encargo_didatico) > 60): if (sum_estagio_semidireto >= 60.0): encargo_didatico = 0 Alerta.addAlerta(" Encargo didático ZERADO (Art. 35, § 10): Máximo permitido atingido.") else: dif = abs(sum_estagio_semidireto - encargo_didatico) encargo_didatico = dif sum_estagio_semidireto += dif Alerta.addAlerta(" Encargo didático LIMITADO (Art. 35, § 10): Máximo permitido atingido.") elif any(nome_disciplina[0:8] in s for s in self.filtro_estagio_indireta): Alerta.addAlerta(nome_disciplina + "(" + periodo + "):" + "Pontuado com o estágio indireto (Art 35).") if (float(encargo_didatico) > 15.0): if (sum_estagio_indireto >= 15.0): encargo_didatico = 0 Alerta.addAlerta(" Encargo didático ZERADO (Art. 35, § 10): Máximo permitido atingido.") else: dif = abs(sum_estagio_indireto - encargo_didatico) encargo_didatico = dif sum_estagio_indireto += dif Alerta.addAlerta( nome_disciplina + "(" + periodo + "):" + " estágio indireto (LIMITADO) (Art. 35, § 10).") Alerta.addAlerta(" Maximo atingido! Encargo didático LIMITADO (Art. 35, § 10).") elif any(nome_disciplina[0:8] in s for s in self.filtro_estagio_direta): Alerta.addAlerta(nome_disciplina + "(" + periodo + "):" + "pontuado como estágio direto (Art 35).") elif (nome_disciplina.lower().find("estágio") != -1): Alerta.addAlerta( "INFORMAÇÃO NECESSÁRIA: " + nome_disciplina + "(" + periodo + "): possívelmente pontuada erroneamente como orientação direta.") retorno_busca = [(x, y, z) for x, y, z in lista_disciplinas if ((x == periodo) and (y == nome_disciplina))] if (len(retorno_busca) > 0): if (remove_duplicatas): Alerta.addAlerta( "Atenção: a disciplina " + nome_disciplina + " aparece duplicada no semestre " + periodo + "\n e NÃO FOI computada (Obs. 4 Anexo I). Solicitar a chefia a documentação comprobatória de que" "\n a disciplina foi ministrada em turmas com horários diferentes e, se comprovado, SOMAR " "n " + str(encargo_didatico) + " de encargo didático no semestre.") continue else: Alerta.addAlerta( "Atenção: a disciplina " + nome_disciplina + " aparece duplicada no semestre " + periodo + "\n e mas FOI computada (Obs. 4 Anexo I). Solicitar a chefia documentação que realmente comprove" "\n que a disciplina foi ministrada em turmas com horários diferentes e, se for o caso, REMOVER " "\n " + str(encargo_didatico) + " de encargo didático no semestre.") tupletDisciplina = (periodo, nome_disciplina, encargo_didatico) lista_disciplinas.append(tupletDisciplina) lista_disciplinas.sort(key=lambda tup: tup[0]) # sorts in place return lista_disciplinas
def __get_detalhamento(self): output = self.__str__() # resultado do parecer output += "== DETALHAMENTO DA PONTUAÇÃO == \n" output += "===== 1. Turmas de Graduação =====" "\n" output += formataPrint("", "Disciplinas da Graduação (Semestre, Código, Disciplina, Encargo didático)", self.portal_docente.disciplinas_grad.lista_disciplinas) + "\n" output += (formataPrint("", "Encargo didático Graduação (média: " + str(self.portal_docente.disciplinas_grad.media_encago_didatico) + ")", self.portal_docente.disciplinas_grad.dic_encargo_didatico.items())) + "\n" output += (formataPrint("", "Pontuação Graduação (média: " + str(self.portal_docente.disciplinas_grad.media_pontos) + ")", self.portal_docente.disciplinas_grad.pontos_semestre.items())) + "\n" output += "===== 2. Turmas de Pós-Graduação =====" "\n" output += (formataPrint("", "Disciplinas da Pós-graduação (Semestre, Código, Disciplina, Encargo didático)", self.portal_docente.disciplinas_posgrad.lista_disciplinas)) + "\n" output += (formataPrint("", "Encargo didático Pós-Graduação(média: " + str(self.portal_docente.disciplinas_posgrad.media_encago_didatico) + ")", self.portal_docente.disciplinas_posgrad.dic_encargo_didatico.items())) + "\n" output += (formataPrint("", "Pontuação Pós-graduação (média: " + str(self.portal_docente.disciplinas_posgrad.media_pontos) + ")", self.portal_docente.disciplinas_posgrad.pontos_semestre.items())) + "\n" output += "===== 3. Iniciações Científicas =====" "\n" output += formataPrint("", "Iniciações Científica (Título, Data Início, Data Término)", self.portal_docente.iniciacoes_cientificas.lista_iniciacoes_cientificas) + "\n" output += "===== 4. Ações de Extensão =====" "\n" output += (formataPrint("", "Ações de Extensão(Título, Data de Início, Data de Término, Papel do Docente (Lattes)", self.portal_docente.acoes_extensao.lista_projetos)) + "\n" output += "===== 5. Projetos de Pesquisa =====" "\n" output += (formataPrint("", "Projetos de Pesquisa (Título, Data de Início, Data de Término, Papel do Docente (Lattes))", self.portal_docente.projetos_pesquisa.lista_projetos)) + "\n" output += ("Pontuação de Projetos de Pesquisa:" + str(self.portal_docente.projetos_pesquisa.pontos)) + "\n" output += "===== 5. Orientações =====" "\n" output += (formataPrint("", "Orientações (Nível, Papel do Docente, Orientando, Data Início, Data Término", self.portal_docente.orientacoes.lista_orientacoes)) + "\n" output += ("Pontuação de orientações (somente) do portal docente:" + str(self.portal_docente.orientacoes.pontos)) + "\n" output += "===== 6. Produção Bibliográfica =====" "\n" output += (formataPrint("", "Livros ()", self.producao_intelectual_lattes.producao_bibliografica.lista_livros)) + "\n" output += (formataPrint("", "Capítulos de Livros ()", self.producao_intelectual_lattes.producao_bibliografica.capitulos_livro)) + "\n" output += (formataPrint("", "Artigos em Periódicos()", self.producao_intelectual_lattes.producao_bibliografica.artigos_periodicos)) + "\n" output += (formataPrint("", "Artigos em Eventos()", self.producao_intelectual_lattes.producao_bibliografica.lista_artigos_eventos)) + "\n" output += ("Alertas:" + str(Alerta.texto_formatado()) + "\n") output += "\n Observação: análise automatizada buscando informações da: \n a) ficha funcional de progressão, " + \ "\n b) relatório funcional para progressão (portal docente.ufes.br), \n c) Currículo Lattes na data corrente." return output
settings.path_xml_lattes, ficha_progressao) producao_intelectual_lattes = ProducaoIntelectual(settings.path_xml_lattes, ficha_progressao) parecer = Parecer(portal_docente, ficha_progressao, producao_intelectual_lattes) parecer.emitir_parecer_progressao() return parecer if __name__ == "__main__": ficha_progressao = FichaFuncional(settings.path_ficha_funcional) portal_docente = PortalDocente(settings.path_portal_docente, settings.path_xml_lattes, ficha_progressao) producao_intelectual_lattes = ProducaoIntelectual(settings.path_xml_lattes, ficha_progressao) parecer = Parecer(portal_docente, ficha_progressao, producao_intelectual_lattes) parecer.emitir_parecer_progressao() parecer.gravar_log() print(parecer) Alerta.print()
def __parse_projetos(self): dados_lattes = self.xml_root.find('DADOS-GERAIS') nome_servidor_lattes = (dados_lattes.attrib['NOME-COMPLETO']) # Extraindo do texto os dados sobre as projetos projetos = re.findall(r'Nome:(.*?)Descrição:', self.__page_content) lista_projetos = [] for projeto in projetos: nome_projeto = re.search(r'(.*?)Data de início:', projeto).group(1) data_inicial_str = re.search( r'Data de início:(.*?)Data de término', projeto).group(1) data_inicial_projeto = datetime.strptime(data_inicial_str, '%d/%m/%Y').date() # Só irá computar projetos que iniciaram depois do início do interício devido a uma falha no portal docente # que não indica o término dos projetos. if (self.inicio_intersticio > data_inicial_projeto): # todo verificar CPAD continue data_final_str = re.search(r'Data de término:(.*?)Carga horária', projeto).group(1) if (data_final_str != ""): data_final = datetime.strptime(data_final_str, '%d/%m/%Y').date() # if(active_from_date != None) and (active_from_date > data_final): # continue #todo verificar CPAD else: data_final = None # Verifica no XML do Lattes se é o coordenador. Caso não seja, é considerado integrante. str_papel_projeto = "" strProjeto = re.sub('[^a-z0-9]+', '', nome_projeto.lower()) for projeto in (self.xml_root.findall( './/PROJETO-DE-PESQUISA[@NATUREZA="PESQUISA"]')): nome_projeto_lattes = projeto.attrib['NOME-DO-PROJETO'] nome_projeto_lattes = re.sub('[^a-z0-9]+', '', nome_projeto_lattes.lower()) if (nome_projeto_lattes == strProjeto): membro_equipe = projeto.find( './/INTEGRANTES-DO-PROJETO[@FLAG-RESPONSAVEL="SIM"]') nome = membro_equipe.attrib['NOME-COMPLETO'] if (nome == nome_servidor_lattes): str_papel_projeto = "coordenador" else: str_papel_projeto = "integrante" break if (str_papel_projeto == ""): str_papel_projeto = "não determinado" Alerta.addAlerta( "Aviso: projeto de pesquisa '" + nome_projeto + "' não está registrado no Lattes. " "\n O docente será considerando um participante (não coordenador) para efeito de pontuação. " "\n Se necessário, solicite documentação comprobatória e pontue manualmente." ) tupletProjeto = (nome_projeto, data_inicial_projeto, data_final, str_papel_projeto) lista_projetos.append(tupletProjeto) if (len(lista_projetos) < len(projetos)): Alerta.addAlerta( "Aviso: Foram encontrados projetos iniciados antes do início do interstício que " " ainda estão em aberto no portal docente por falha do sistema da UFES. " "\n Se necessário, solicite documentação comprobatória e pontue manualmente." ) return lista_projetos