What's the best way to get a proper type hinting f...
# python
g
What's the best way to get a proper type hinting for Outputs? Is there any cast method or anything available? acm certificate has the output of type
CertificateDomainValidationOptionArgs
https://www.pulumi.com/docs/reference/pkg/aws/acm/certificate/#outputs I'd like to be able to use it as
cert_validation_option.domain_name
, etc...
e
I’m not sure I follow this. CertificateDomainValidationOptionArgs is not CertificateDomainValidationOption. Where are you trying to use the domain_name>
E.g.
Copy code
cert: acm.Certificate
  cert.domain_validation_options: Output[Sequence[CertificateDomainValidationOption]]
  cert.domain_validation_options.apply(lambda x: x[0]): Output[CertificateDomainValidationOption]

  domain_name = cert.domain_validation_options.apply(lambda x: x[0]).apply(lambda x: x.domain_name)
  domain_name: Output[str]
IF you have some place that accepts an
Input[str]
you can now pass
domain_name: Output[str]
into it as Input arguments accept Output.
You cannot unpack Output[str] to str.
g
I think this is the problem
lambda x: x[0]).apply(lambda x: x.domain_name)
that my IDEs are not able to suggest the attributes of
x
which is ultimately what I'm trying to achieve. It's the lost information that bothers me
e
Oh! Thanks for clarifying that!
I think I’ve been filing this before: https://github.com/pulumi/pulumi-aws/issues/1516
Let me move this to pulumi/pulumi and escalate it, I’d very much like to get this fixed.
g
Yeah there are a couple of them possibly caused by my discussions. I'm trying to find suitable workarounds in the meantime
e
It’s going to be tough to find a workaround to for IDE completion and type checking if properties are marked as typed Any. You can make the programs work but without the IDE/typechecker support.
There: https://github.com/pulumi/pulumi/issues/7679 lobby to squeeze this in soon.
g
Since I laid my hands CDK API, I tend to compare it with other tools because I think they nailed it. Looks to me like AWSX is going in the same direction but I wasn't able to test it yet since it's not available for python afaik
I love how pydantic simplified instantiating dictionaries into objects together with some data validation. So I'm looking for a way how to get this experience back from
pulumi.Output
because they can also return a dict but it is not a dict but
Output[dict]
e
I’ll need to ask around about AWSX, not sure there.
g
One possible workaround I found was using
Output.future()
and
await
inside an async function then scheduling the function with
loop.create_task
However due to my limited experience with python async I'm not able to tell if there are any potential side effects. It seems to be a similar case to
Output.apply()
- where documentation recommends to avoid creating resources inside
apply()
Copy code
import pulumi
from pydantic import BaseModel

class MyZone(BaseModel):
    zone_id: str
    force_destroy: bool





async def fun():
    ref_zone = pulumi.StackReference(stack_name)
    print('lol')
    result = await ref_zone.outputs.future()
    print(result)
    my_zone = MyZone.parse_obj(result['my_zone'])
    print(my_zone)
    ec2.SecurityGroup(
        f"mhh{my_zone.zone_id}"
    )

loop = asyncio.get_running_loop()
loop.create_task(fun())
e
Hm. Reducing Output to future and awaiting in future will definitely break some features Pulumi implements in the Output layer, like dependency tracking and unknown/secret propagation.
You can however get an
Output[MyZone]
in the code above I think?
Copy code
ref_zone.outputs.apply(lambda result: MyZone.parse_obj(result['my_zone'])): Output[MyZone]
You will not be able to coax Output[MyZone] into using it in the
name
parameter of SecurityGroup though, that’s true. I’ll need to ask what is the recommended practice around this.
From pure Python view, your workaround can be made to work, consider asyncio.run:
Copy code
async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')

# Python 3.7+
asyncio.run(main())
With create_task the program does not wait (though Pulumi might be making it to wait in the current version). With asyncio.run you’re explicitly asking to run an async function and wait till it’s done.
Losing dependency tracking: so since your workaround is unpacking Output to future, Pulumi engine is no longer aware that SecurityGroup resource depends on the StackReference resource, but since the program is explicitly blocking and waiting, that may be okay as it will allocate in the right order anyway.
Consider though if it’s worth it. I’m digging up the docs on SecurityGroup, so it seems there’s two names in play:
Copy code
# ec2
 class SecurityGroup(pulumi.CustomResource):

    @overload
    def __init__(__self__,
                 resource_name: str,
                 ...
                 name: Optional[pulumi.Input[str]] = None,
                 ...
                 __props__=None):
        """
        # BUILT BY genResourceInitDocstring()
        :param str resource_name: The name of the resource.  ### this is the name as Pulumi sees it
        ...
        :param pulumi.Input[str] name: Name of the security group. If omitted, this provider will assign a random, unique name.  ### this is actual name in AWS
        """
        ...
g
It's not specific to the SecurityGroup I picked it as an example resource that is quick to deploy. Also I think using
asyncio.run
gave me error about multiple loops but will have to revisit the test later on
🤔 1
thank you for now!
e
So you could do this:
Copy code
my_zone: Output[MyZone] = ref_zone.outputs.apply(lambda result: MyZone.parse_obj(result['my_zone']))
sg = SecurityGroup(
  "mhh", # pulumi name does not depend on my_zone
  resource_name=my_zone.apply(lambda z: f"mhh{z.zone_id}")  # but AWS name does
)
TLDR - if passing Output to Input is more idiomatic Pulumi than unpacking Output in async layer. Interesting, I see. Thanks for that, I believe we have something in the works for removing the multiple event loops issues. I’ll check that with your program to repro. Thanks!
g
Agree with about that! still my ultimate goal is to get IDE to tell me that
z.
has the attribute of
z.zone_id
I'll try the similar example in C# to see if the IDE experience is somewhat different there then I'll think if there is something like that of python typhinting
because if you do
List[str]
you get hinted methods from that
list_items[0].join()
if we could get the same experience for Output in python that would be amazing