splor-mg / dpm

https://splor-mg.github.io/dpm/
0 stars 0 forks source link

Implementa dpm normalize #70

Closed fjuniorr closed 3 months ago

fjuniorr commented 10 months ago

Closes #67

codecov[bot] commented 10 months ago

Welcome to Codecov :tada:

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered :open_umbrella:

fjuniorr commented 10 months ago
    if resource_name:
        resource_names = resource_name
    else:
        resource_names = set.intersection(
            *[set(package._package.resource_names) for package in packages]
        )
        if not resource_names:
            print(
                "There are no resources with the same name in all packages to concatenate..."
            )
            typer.Exit(code=0)
labanca commented 7 months ago
  • even on windows path in datapackage must be linux based

Para o windows cmd, ambas as formas de escrever o path são aceitas:

Utilizando contrabarra \:

image

Utlizando barra /:

image

Já no git bash, a princípio somente funciona utilizado barra /:

image

Pelo que pesquisei o git bash converte os caracteres especiais do input de linha de comando antes de serem enviados como argumento para o programa. A contrabarra "desaparece" como visto na imagem acima (ao printar o valor de source logo no começo do normalize). Isso que dificulta manipulações da string pelo dpm vindas do git bash, nesse caso.

O problema pode ser "resolvido" inserindo o path dentro de aspas duplas (algo comumente feito no windows) ou \\:

image

Fiquei na dúvida da razão de não usar Path como tipo no Annotated também do argumento source, já que output_dir e data_path são do tipo Path.

@app.command("normalize")
def cli_normalize(
    source: Annotated[str, typer.Argument()],
    output_dir: Annotated[Path, typer.Option()] = ".",
    data_dir: Annotated[Path, typer.Option()] = "data",
    resource_name: Annotated[str, typer.Option()] = None,
    json_ext: Annotated[bool, typer.Option("--json")] = False,
    yaml_ext: Annotated[bool, typer.Option("--yaml")] = False,
):

Mudar para Path manteve tudo funcionando normalmente, mas por não ter certeza das razões, mantive como str (mesmo caso para resource_name) e adicionei uma conversão por precaução:

str(Path(source).as_posix())
str(Path(resource_name).as_posix())
labanca commented 7 months ago

@fjuniorr pronto pra revisão.

fjuniorr commented 5 months ago

No projeto https://github.com/splor-mg/dados-obz-2025 vamos usar uma etapa de make normalize executada com dpm normalize e uma etapa de make transform com implementação específica para o projeto em questão.

fjuniorr commented 5 months ago

@labanca acho que o erro relatado pelo @carloshob em https://github.com/splor-mg/dados-obz-2025/pull/5#issuecomment-2179348028 está relacionado aquele problema de encoding que você teve.

Imagino que o JSON que está sendo gerado não está como UTF-8 no windows. Não sei bem onde isso pode estar acontecendo. Talvez seja no redirecionamento que a gente faz via git bash?

Além disso adiciona por favor o as_posix nos caminhos.

labanca commented 5 months ago

@carloshob adicionei as_posix no calculo dos paths. Está no brach normalize. Veja se está ok e me avise se tiver algum erro.

Não tenho certeza que vai resolver o erro de enconding.

labanca commented 5 months ago

@carloshob outra coisa, tenta rodar o transform no cmd do windows (preferencialmente o git cmd) para verificar se o erro de encoding não acontece.

image

labanca commented 3 months ago

Nesse caso se executarmos

dpm normalize datapackages/monitoramento2020/datapackage.yaml > datapackages/monitoramento2020/datapackage.json --data-dir datapackages/monitoramento2020/data

O data package datapackages/monitoramento2020/datapackage.json vai ser inválido porque o path de cada recurso vai estar errado.

Precisamos voltar com as alterações de 6d37950 mas acho que o nome metadata-dir fica melhor pra comunicar o que está sendo feito.

No caso específico usado como exemplo, "datapackages/monitoramento2020/datapackage.yaml",

cli_normalize(
    source='datapackages/monitoramento2020/datapackage.yaml', 
    data_dir=Path("datapackages/monitoramento2020/data"),
    descriptor_path=Path("datapackages/monitoramento2020")
)

a resource está recebendo o caminho relativo durante o normalize:

{
   "name":"acoes_monitoramento",
   "type":"table",
   "profile":"tabular-data-resource",
   "path":"monitoramento2020/data/acoes_monitoramento.csv",
   "scheme":"file",
   "format":"csv",
   "mediatype":"text/csv",
   "encoding":"utf-8"
}

O descriptor usado no normalize para gerar os caminhos relativos é o seguinte:

    descriptor = {
        "profile": "tabular-data-resource",
        "name": resource.name,
        "path":  str((data_dir.relative_to(descriptor_path.parent) / f'{resource.name}.csv').as_posix()),
        "format": "csv",
        "encoding": "utf-8",
        "schema": {"fields": [
            {
                'name': field.custom['target'] if field.custom.get('target') else as_identifier(field.name),
                'type': field.type,
                'source': field.name,
            } for field in resource.schema.fields
        ]}
    }

Todavia ao tentar executar inferir as propriedades do recurso em:

    descriptor.update(resource.custom)
    resource = Resource.from_descriptor(descriptor)
    resource.infer(stats=True)

O frictionless acusa [scheme-error] The data source could not be successfully loaded: [Errno 2] No such file or directory: 'monitoramento2020/data/acoes_monitoramento.csv'

Para o frictionless o caminho relativo correto seria mesmo "path":"monitoramento2020/data/acoes_monitoramento.csv" @fjuniorr? Se sim, então a forma de executar o infer terá de ser alterada.

fjuniorr commented 3 months ago

Para o frictionless o caminho relativo correto seria mesmo "path":"monitoramento2020/data/acoes_monitoramento.csv" @fjuniorr? Se sim, então a forma de executar o infer terá de ser alterada.

Não, pra esse caso o caminho certo é data/acoes_monitoramento.csv (sem monitoramento2020). descriptor_path deveria conter o caminho completo para o arquivo, não? (ie. datapackages/monitoramento2020/datapackage.json)

labanca commented 3 months ago

Não, pra esse caso o caminho certo é data/acoes_monitoramento.csv (sem monitoramento2020).

Eu fiz testes e o path "data/acoes_monitoramento.csv" passa no validate do frictionless, mas o infer continua dando erro na execução, mesmo com o caminho relativo correto. Imagino que como o infer é executado levando em conta o working directory padrão, ele vai procurar o arquivo csv na pasta relativa e não vai encontrá-lo mesmo, já que ele está de fato dentro de "datapackages/monitoramento2020/data" e não em "/data/".

Alguma sugestão de como abordar essa questão?

descriptor_path deveria conter o caminho completo para o arquivo, não? (ie. datapackages/monitoramento2020/datapackage.json)

Está funcionando dessa forma. No caso seria melhor mudar o nome para metadata-dir como sugerido anteriormente. O descriptor-path é utilizado quando o descriptor é gerado no dpm normalize:

"path":  str((data_dir.relative_to(descriptor_path.parent) / f'{resource.name}.csv').as_posix()),

Eu tive de remover o .parent para ele pegar o caminho relativo certo "data/", no caso do exemplo.

fjuniorr commented 3 months ago

Na verdade minha sugestão é remover o infer (por outros motivos, mas vem a calhar se dá dando problema de implementação):

stats e updated_at

Pode ser que essas informações sejam úteis durante a etapa de normalização, mas especialmente a propriedade updated_at que altera em cada execução é incoveniente para os casos em que uma mudança nos metadados do data package é significativa.

Entre as opções de:

  • criar duas flags pra tornar a inserção das informações opcionais;
  • remover a funcionalidade.

Prefiro por enquanto remover e pensar que isso vai existir durante o dpm build.

-- https://github.com/splor-mg/dpm/pull/70#pullrequestreview-2063985910

labanca commented 3 months ago

Na verdade minha sugestão é remover o infer (por outros motivos, mas vem a calhar se dá dando problema de implementação):

Removi os resource.infer() e updated_at do normalize.

O dpm normalize funcionou tanto para

dpm normalize datapackages/monitoramento2020/datapackage.yaml --data-dir datapackages/monitoramento2020/data --metadata-dir datapackages/monitoramento2020

quanto para dpm normalize datapackage.yaml

image

fjuniorr commented 3 months ago

Conforme alinhado em reunião remover os testes deste PR e criar um issue dedicado para atacarmos essa questão em um momento posterior.

fjuniorr commented 3 months ago

Os dois formatos de comando estão funcionais:

dpm normalize datapackages/monitoramento2020/datapackage.yaml --data-dir datapackages/monitoramento2020/data --metadata-dir datapackages/monitoramento2020

ou

dpm normalize datapackages/monitoramento2020/datapackage.yaml --data-dir data