acoustic-evening-77298
08/08/2022, 3:40 PMsuper().__init__(
"<component-type-id>",
"<component-name>",
props: Optional[Inputs],
opts
)
In the examples I can find the props
are not handled. Digging through the code that seems to resolve to the Resource.__init__(... props )
To confirm, my best guess is that any pulumi.Input[]
to my custom component should be forwarded to the base class __init__
AND that part of the reason for this is to allow Pulumi to work out dependency ordering between my component and other resource outputs… BUT that it generally doesn’t matter in practice because these are forwarded to sub-resources of the component so the dependency ordering is handled that way.
---
So the question here:
(1) is the understanding above correct and
(2) are there any other important reasons for specifying the component properties?
In all of the Pulumi examples, they seem to pass None
or {}
(e.g. Azure Virtual Data Center)delightful-salesclerk-16161
08/08/2022, 3:41 PMquiet-wolf-18467
08/09/2022, 7:46 AMacoustic-evening-77298
08/16/2022, 2:16 PMargs
bit is somewhat overloaded under the hood and provides 2 functions:
1. It automatically sets resource inputs as outputs on the resource (see below)
2. In the context of DynamicProviders, you need to specify an empty/None/Null/Nil value in the Map to let the infrastructure to know to copy outputs back into the Resource. This seems to contradict what I found in the TypeScript example so I am not sure if this is a Python specific defect or a defect in the example (@quiet-wolf-18467) ? For a Component, you can just set the output in the component constructor since there is less pulumi magic in the backend.
----
(1)
Example pass through:
@dataclasses.dataclass
class MyArgs:
foo: Input[str]
bar: Input[str]
class MyComponent(ComponentResource):
# Auto populated by Pulumi. These fields here are handy for mypy / IDE typeahed
foo: Output[str]
bar: Output[str]
myout: Output[str] # declared here for consistency
def __init__(self, name: str, args: MyArgs, opts: Optional[ResourceOptions] = None)
super().__init__(
"what:ever:MyComponent",
name=name,
props=dataclasses.asdict(args), # This populates foo, bar as output properties on the Component resource
opts=opts
)
self.myout = <whatever>
---
(2)
In the context of Dynamic Resources:
# NOTE BaseModel does not play nice with deferred/Input/Output. Use dataclasses instead there
# At this level or the provider inputs are resolved to concrete types
class MyProviderIn(pydantic.BaseModel):
foo: str
bar: str
class MyProviderOut(MyProviderIn): # extend above with extra output
myout: str
class MyDynamicProvider(dynamic.ResourceProvider):
...
def create(self, props: Dict):
props_in = MyProviderIn(**props)
.. # do stuff
return CreateResult(id, MyProviderOut(myout=<result>, **props_in.dict())
@dataclasses.dataclass
class MyArgs:
foo: Input[str]
bar: Input[str]
class MyDynamicResource(dynamic.Resource):
foo: Output[str]
bar: Output[str]
myout: Output[str]
def __init__(self, name: str, props: MyDynamicResourceArgs, opts: Optional[ResourceOptions] = None):
props_dict_with_outputs_also = dataclasses.asdict(props)
# GOTCHA / POTENTIAL BUG: if you do not set this, you cannot access `myout` later in your __main__
# Even though it is set by your provider
props_dict_with_outputs_also["myout"] = None
super().__init__(MyDynamicProvider(), name, props_dict_with_outputs_also, opts):
Later this finally works
# __main__
my_component = MyComponent("whatever", MyArgs(foo="foo", bar="bar")
my_component_out: Output[str] = my_component.myout # This works as expected
my_dynamic_res = MyDynamicResouce("whatever", MyArgs(foo="foo", bar="bar")
my_dynamic_res_out: Output[str] = my_dynamic_res.myout # This will blow up without the gotcha fix above
``````