Slackbot
05/18/2023, 3:35 PMShaul Kremer
05/18/2023, 3:59 PMHttpFetchProvider
sets the event.config
attribute in its constructor if it's not already set. You can move your assignment to before calling the superclass constructor (which is actually what HttpFetchProvider
does too), e.g.
class KiplotHttpFetchProvider(HttpFetchProvider):
def __init__(self, event: KiplotHttpFetchEvent) -> None:
if event.config is None:
event.config = KiplotHttpFetcherConfig()
super().__init__(event)
Ben Wallis
05/18/2023, 4:04 PMdef __init__(self, event: KiplotHttpFetchEvent) -> None:
event.config = KiplotHttpFetcherConfig()
super().__init__(event)
Why does this work but not with the if
? Shouldn't event.config
be None
since KiplotHttpFetchProvider
is the most derived type?Shaul Kremer
05/18/2023, 4:20 PMevent
which might have a config
set with data. By using Pydantic's ORM mode (which doesn't actually touch any database, it just enables some functionality that's usually used with ORMs), you can upgrade it to KiplotHttpFetcherConfig
without losing existing data:
class KiplotHttpFetchEvent(HttpFetchEvent):
fetcher: str = "KiplotHttpFetchProvider"
config: KiplotHttpFetcherConfig = None
class Config:
orm_mode = True
def __init__(self, event: KiplotHttpFetchEvent) -> None:
event.config = KiplotHttpFetcherConfig.from_orm(event.config or HttpFetcherConfig())
super().__init__(event)
Ben Wallis
05/18/2023, 4:26 PMpydantic.errors.ConfigError: You must have the config attribute orm_mode=True to use from_orm
class KiplotHttpFetchEvent(HttpFetchEvent):
fetcher: str = "KiplotHttpFetchProvider"
config: KiplotHttpFetcherConfig = None
class Config:
orm_mode = True
class KiplotHttpFetchProvider(HttpFetchProvider):
def __init__(self, event: KiplotHttpFetchEvent) -> None:
event.config = KiplotHttpFetcherConfig.from_orm(event.config or HttpFetcherConfig())
super().__init__(event)
Shaul Kremer
05/18/2023, 5:06 PMorm_mode = True
in KiplotHttpFetcherConfig
, not KiplotHttpFetchEvent
Ben Wallis
05/18/2023, 5:29 PMresource_type
and resource_id
fields in KiplotHttpFetcherConfig
are being lost by the time it reaches `_process_`:
| opal_fetcher_kiplot_http.provider | INFO | KiplotHttpFetchProvider received incoming event, resource_type: None resource_id: None
This is the payload I'm sending to the API:
{
"entries": [
{
"config": {
"fetcher": "KiplotHttpFetchProvider",
"resource_id": "1234",
"resource_type": "outcome"
},
"dst_path": "/outcomes/1234",
"save_method": "PUT",
"topics": [
"test_topic"
],
"url": "<http://host.docker.internal:44444/test_data.json>"
}
]
}
Any ideas? Thanks for all the help so far btw, appreciate it 🙂Shaul Kremer
05/18/2023, 6:35 PMparse_event
function gets called by the base class and the implementation in HttpFetchProvider
overrides your config with the base class. Try overriding it too:
def parse_event(self, event: FetchEvent) -> HttpFetchEvent:
return KiplotHttpFetchEvent(**event.dict(exclude={"config"}), config=event.config)
Ben Wallis
05/18/2023, 7:27 PM_init_
override got it working - final minimal implementation of a custom HTTP fetcher looks like this:
from aiohttp import ClientResponse
from pydantic import Field
from typing import Optional
from opal_common.fetcher.providers.http_fetch_provider import HttpFetchProvider, HttpFetcherConfig, HttpFetchEvent
from opal_common.fetcher.logger import get_logger
from opal_common.fetcher.events import FetchEvent
logger = get_logger("kiplot_http_fetch_provider")
class KiplotHttpFetcherConfig(HttpFetcherConfig):
"""
Config for KiplotHttpFetchProvider-s
"""
fetcher: str = "KiplotHttpFetchProvider"
class KiplotHttpFetchEvent(HttpFetchEvent):
fetcher: str = "KiplotHttpFetchProvider"
config: KiplotHttpFetcherConfig = None
class KiplotHttpFetchProvider(HttpFetchProvider):
def parse_event(self, event: FetchEvent) -> KiplotHttpFetchEvent:
return KiplotHttpFetchEvent(**event.dict(exclude={"config"}), config=event.config)
async def _process_(self, res: ClientResponse):
self._event: KiplotHttpFetchEvent
# TODO: process data
return res
Would be handy to have something similar in the docs - I expect the use-case of needing a HTTP fetcher with custom processing is pretty common - in our case the plan is to use _process_
to restructure API responses into the correct shape for OPA, allowing the use of all our existing APIs to populate OPA with no application changesShaul Kremer
05/18/2023, 7:49 PMBen Wallis
05/18/2023, 8:01 PM