AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 79565427
Accepted
CodyK
CodyK
Asked: 2025-04-10 06:30:14 +0800 CST2025-04-10 06:30:14 +0800 CST 2025-04-10 06:30:14 +0800 CST

Pydantic CLIApp/CLISubCommand com variáveis ​​de ambiente

  • 772

Atualmente, estou construindo uma CLI usando o Pydantic . Um dos subcomandos tem 2 parâmetros que eu gostaria de carregar por meio de uma variável de ambiente. Consegui carregar as variáveis ​​de ambiente por conta própria quando instanciei a classe diretamente, mas agora que ela é uma variável de ambiente CliSubCommand, estou com problemas para carregar os dois parâmetros por meio de variáveis ​​de ambiente. Também consegui fazer a CLI funcionar quando AWSStsGcpa classe estava herdando de BaseModel, fornecendo-a por meio da linha de comando. O Pydantic está apresentando um erro informando que as duas flags da AWS são necessárias. Elas estão localizadas no modelo aws_sts_gcp.py -> aws_access_keye aws_secret_key.

Também não quero que seja uma configuração global obrigatória, já que atualmente ela só é relevante para um comando.

root_tool.py


    from pydantic import BaseModel
    from pydantic_settings import CliSubCommand, CliApp
    from python_tools.gcp.models.aws_sts_gcp import AwsStsGcp
    
    class DummyCommand(BaseModel):
        project_id: str
    
        def cli_cmd(self) -> None:
            print(f'This is a dummy command.{self.project_id}"')
        
    class Tool(BaseModel):
        aws_sts: CliSubCommand[AwsStsGcp]
        dummy: CliSubCommand[DummyCommand]
    
        def cli_cmd(self) -> None:
            CliApp.run_subcommand(self)

aws_sts_gcp.py

    from pydantic import SecretStr
    from pydantic_settings import BaseSettings, SettingsConfigDict
    
    from python_tools.gcp.aws_gcs_transfer import create_aws_transfer_job 
    
    class AwsStsGcp(BaseSettings, cli_parse_args=True):
        model_config = SettingsConfigDict(env_file='.env', env_file_encoding='utf-8')
        destination_bucket: str
        src_bucket: str
        manifest_path: str | None = None
        aws_access_key: SecretStr
        aws_secret_key: SecretStr
        tranfer_name: str
        project_id: str
    
        def cli_cmd(self) -> None:
            create_aws_transfer_job(self)

cli_runner.py

from python_tools.gcp.models.root_tool import Tool
from pydantic_settings import CliApp

CliApp.run(Tool)

aws_gcs_transfer.py

from google.cloud.storage_transfer_v1 import (
    StorageTransferServiceClient,
    TransferJob,
    TransferSpec,
    TransferManifest,
    AwsS3Data,
    AwsAccessKey,
    GcsData,
    RunTransferJobRequest,
    CreateTransferJobRequest
)
#from python_tools.gcp.models.aws_sts_gcp import AwsStsGcp
from python_tools.consts import timestr
from python_tools.logging import logger

import time

def create_aws_transfer_job(transfer_details) -> None:
    s3_config = None

    transfer_manifest = None 

    client = StorageTransferServiceClient()
    s3_config = AwsS3Data(
        bucket_name=transfer_details.src_bucket,
        aws_access_key=AwsAccessKey(
            access_key_id=transfer_details.aws_access_key.get_secret_value(), secret_access_key=transfer_details.aws_secret_key.get_secret_value()
        )
    )

    gcs_dest = GcsData(bucket_name=transfer_details.destination_bucket)

    if transfer_details.manifest_path is not None:
        transfer_manifest = TransferManifest(location=transfer_details.manifest_path)
    
    sts_spec = TransferSpec(gcs_data_sink=gcs_dest, aws_s3_data_source=s3_config, transfer_manifest=transfer_manifest)
    timestamp = time.strftime(timestr)
    name = f"transferJobs/{transfer_details.tranfer_name}-{timestamp}"
    description = "Automated STS Job created from Python Tools."
    sts_job = TransferJob(
        project_id=transfer_details.project_id,
        name=name,
        description=description,
        transfer_spec=sts_spec,
        status=TransferJob.Status.ENABLED,
    )
    job_request = CreateTransferJobRequest(transfer_job=sts_job)

    logger.info(f"Starting Transfer Job for Job ID: {name}")
    transfer_request = RunTransferJobRequest(project_id=transfer_details.project_id, job_name=name)

    client.create_transfer_job(request=job_request)
    client.run_transfer_job(request=transfer_request)

.env

AWS_ACCESS_KEY = "test"
AWS_SECRET_KEY = "test"

Também tentei usar BaseSettings na raiz assim.

from pydantic import BaseModel
from pydantic_settings import CliSubCommand, CliApp, BaseSettings, SettingsConfigDict

from python_tools.gcp.models.aws_sts_gcp import AwsStsGcp

class DummyCommand(BaseModel):
    project_id: str

    def cli_cmd(self) -> None:
        print(f'This is a dummy command.{self.project_id}"')
    
class Tool(BaseSettings, cli_parse_args=True):
    model_config = SettingsConfigDict(env_file='.env', env_file_encoding='utf-8', extra='ignore')

    aws_sts: CliSubCommand[AwsStsGcp]
    dummy: CliSubCommand[DummyCommand]

    def cli_cmd(self) -> None:
        CliApp.run_subcommand(self)

from pydantic import SecretStr, BaseModel, Field  
from python_tools.gcp.aws_gcs_transfer import create_aws_transfer_job 

class AwsStsGcp(BaseModel):
    destination_bucket: str
    src_bucket: str
    manifest_path: str | None = None
    aws_access_key: SecretStr = Field(alias='AWS_ACCESS_KEY', env="AWS_ACCESS_KEY")
    aws_secret_key: SecretStr = Field(alias='AWS_SECRET_KEY',  env="AWS_SECRET_KEY")
    tranfer_name: str
    project_id: str

    def cli_cmd(self) -> None:
        create_aws_transfer_job(self)
python
  • 1 1 respostas
  • 127 Views

1 respostas

  • Voted
  1. Best Answer
    CodyK
    2025-04-11T11:44:02+08:002025-04-11T11:44:02+08:00

    Percebi que precisava usar o env_nested_delimiterpara definir variáveis ​​em modelos aninhados. E atualizar o nome da variável Env para

    AWS_STS__AWS_ACCESS_KEY = "test"
    AWS_STS__AWS_SECRET_KEY = "test"
    
    • 0

relate perguntas

  • Como divido o loop for em 3 quadros de dados individuais?

  • Como verificar se todas as colunas flutuantes em um Pandas DataFrame são aproximadamente iguais ou próximas

  • Como funciona o "load_dataset", já que não está detectando arquivos de exemplo?

  • Por que a comparação de string pandas.eval() retorna False

  • Python tkinter/ ttkboostrap dateentry não funciona quando no estado somente leitura

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve