Source code for pact_testgen.broker

import urllib
from typing import Dict, Optional, Tuple

import requests
from pydantic import BaseSettings
from pydantic.env_settings import SettingsSourceCallable, InitSettingsSource

from .models import Pact


[docs]class BrokerBaseSettings(BaseSettings): pass
[docs] class Config: env_prefix = "pact_broker_" # For broker settings, we want to allow passing values of None # and revert to loading from the environment. However, # we also want to prioritize username and password if they are passed # as init kwargs, but are not None. This pattern simplifies CLI option # handling, at the expense of additional complexity here.
[docs] @classmethod def customise_sources( cls, init_settings: SettingsSourceCallable, env_settings: SettingsSourceCallable, file_secret_settings: SettingsSourceCallable, ) -> Tuple[SettingsSourceCallable, ...]: return ( InitSettingsSource( _remove_items_with_value_none(init_settings.init_kwargs) ), env_settings, file_secret_settings, )
[docs]class BrokerBasicAuthConfig(BrokerBaseSettings): username: str password: str
[docs]class BrokerConfig(BrokerBaseSettings): # Same env vars as pact broker CLI client # https://github.com/pact-foundation/pact_broker-client#usage---cli base_url: str auth: Optional[BrokerBasicAuthConfig] @property def auth_tuple(self) -> Optional[Tuple[str, str]]: """ Returns auth value suitable for passing to requests. If username or password are present, will be Tuple[str,str], else None. """ if self.auth: return (self.auth.username, self.auth.password) return None
def _build_contract_url( base_url: str, provider_name: str, consumer_name: str, version=None ) -> str: if version is None or version == "latest": version = "latest" else: version = f"version/{version}" path = urllib.parse.quote( f"/pacts/provider/{provider_name}/consumer/{consumer_name}/{version}" ) return urllib.parse.urljoin(base_url, path) def _make_broker_request(url: str, auth: Optional[Tuple[str, str]] = None) -> Dict: resp = requests.get(url, auth=auth) resp.raise_for_status() return resp.json()
[docs]def get_pact_from_broker( broker_config: BrokerConfig, provider_name: str, consumer_name: str, version=None, ) -> Pact: """ Make an HTTP request to the Pact Broker to retrieve the desired contract. """ url = _build_contract_url( broker_config.base_url, provider_name, consumer_name, version=version ) data = _make_broker_request(url, auth=broker_config.auth_tuple) return Pact(**data)
def _remove_items_with_value_none(d: dict) -> Dict: return {k: v for k, v in d.items() if v is not None}