#Combine 2 functions

1 messages · Page 1 of 1 (latest)

hazy jolt
#

I'm stuck, trying to get 2 functions, to work together.
I'm also confused around what's the correct way to do this. Is it chaining or ?

So i'm publishing a container image in the function (build), and then i need the url in my return, to be pasted on to the function (update).
Both are of type str, so imho it should be a simple. But i can't get it to work.

Can anybody help or lead me in the right direction ?
Thanks.

My code

from typing import Annotated

import dagger
from dagger import Doc, dag, function, object_type


@object_type
class App:

    @function
    def build(
        self,
        src: Annotated[
            dagger.Directory,
            Doc("location of directory containing Dockerfile"),
        ],
    ) -> str:
        """Build and publish image from existing Dockerfile"""
        image_url = (
            dag.container()
            .with_directory("/src", src)
            .with_workdir("/src")
            .directory("/src")
            .docker_build()  # build from Dockerfile
            .publish("ttl.sh/my-shiny-app")
        )
        return image_url
    
    
    @function
    def update(self, repo: str, branch: str, deploy_filepath: str, image_url: str, git_user: str, git_email: str, git_password: dagger.Secret, force_with_lease: bool) -> None:
        """Update deployment file, with image name and version"""
        return (
            dag.image_updater()
            .update(repo, branch, deploy_filepath, image_url, git_user, git_email, git_password, force_with_lease)
        )
modest flicker
#

What error are you getting?

#

also can you show the code that actually does the combining?

#

I guess there's a 3d higher-level function that calls build() and passes the result in the image_url argument of update()?

hazy jolt
#

I have been trying several things, and gotten many errors. So i wanted to scratch everything, and ask what the right direction was.

Am i'm totalily off, if i try to create a 3 function, where i get the variable like this
var = self.build()
self.update(var)

If i'm not tatalily off, then i will write that function, and try again, and update this thread with the errors etc.

modest flicker
#

Not totally off. It should work the "regular" way in terms of passing values around, etc

#

whether it's a string, or a dagger type like dagger.Directory or dagger.File or dagger.Container should not make a difference

#

As long as you remember those types are immutable

#

If you find yourself stuck, I'm happy to look at a Trace so we can debug together. You'll need to connect your engine to Dagger Cloud with dagger login (there's a free account) then you will see Trace URLs appear that you can share

hazy jolt
#

Great. Thanks. I really appreciate it.
Now that i know i should work (both variables are str values) i will see if i can get it working, and update here.

hazy jolt
#

So i think i found the error, but i have no idea on how to solve it.
Any pointers etc. would be appreciated.
I'm guessing it's due to the update module running async ?

The Error :

 /src/educates/exercises/app/dagger/src/main/__init__.py:54: RuntimeWarning: coroutine 'App.update' was never awaited                                
┃   self.update(image_url, branch, deploy_filepath, git_user, git_email, git_password, force_with_lease, repo)                                        
┃ RuntimeWarning: Enable tracemalloc to get the object allocation traceback                                                                           
  ✔ 52f027c3a10d285f exec /runtime 2.7s
#

My code :

from typing import Annotated

import dagger
from dagger import Doc, dag, function, object_type


@object_type
class App:
    image_url: str = ""

    @function
    def build(
        self,
        src: Annotated[
            dagger.Directory,
            Doc("location of directory containing Dockerfile"),
        ],
    ) -> str:
        """Build and publish image from existing Dockerfile"""
        image_url = (
            dag.container()
            .with_directory("/src", src)
            .with_workdir("/src")
            .directory("/src")
            .docker_build()  # build from Dockerfile
            .publish("ttl.sh/my-shiny-app")
        )
        return image_url
    
    
    @function
    def update(self, repo: str, branch: str, deploy_filepath: str, image_url: str, git_user: str, git_email: str, git_password: dagger.Secret, force_with_lease: bool) -> None:
        """Update deployment file, with image name and version"""
        return (
            dag.image_updater()
            .update(repo, branch, deploy_filepath, image_url, git_user, git_email, git_password, force_with_lease)
        )

    @function
    async def deploy(self, src: Annotated[
            dagger.Directory,
            Doc("location of directory containing Dockerfile"),
            ],
            image_url: str,
            repo: str, 
            branch: str, 
            deploy_filepath: str, 
            git_user: str, 
            git_email: str, 
            git_password: dagger.Secret, 
            force_with_lease: bool) -> str:
        
        image_url = await(self.build(src))
        self.update(image_url, branch, deploy_filepath, git_user, git_email, git_password, force_with_lease, repo)

        return image_url
#

To test it, i'm simply running the following command

dagger call --debug deploy \
        --branch=main \
        --git-user=xxx \
        --repo=http://xxx \
        --git-email=xxx \
        --deploy_filepath=deployment.yaml \
        --force-with-lease=true \
        --image-url=xxx:xxx \
        --git_password=env:USER \
        --src=.

I don't think there is anything in this that make the code fail.

hazy jolt
#

Never mind. I got it working.

The solution was to add a await to the code, so the last function looked like this :

await self.update(repo, branch, deploy_filepath, image_url, git_user, git_email, git_password, force_with_lease)
#

I'm adding my full working code her, for reference for others.

from typing import Annotated

import dagger
from dagger import Doc, dag, function, object_type


@object_type
class App:
    image_url: str = ""

    @function
    def build(
        self,
        src: Annotated[
            dagger.Directory,
            Doc("location of directory containing Dockerfile"),
        ],
    ) -> str:
        """Build and publish image from existing Dockerfile"""
        image_url = (
            dag.container()
            .with_directory("/src", src)
            .with_workdir("/src")
            .directory("/src")
            .docker_build()  # build from Dockerfile
            .publish("ttl.sh/my-shiny-app")
        )
        return image_url
    
    
    @function
    def update(self, repo: str, branch: str, deploy_filepath: str, image_url: str, git_user: str, git_email: str, git_password: dagger.Secret, force_with_lease: bool) -> None:
        """Update deployment file, with image name and version"""
        return (
            dag.image_updater()
            .update(repo, branch, deploy_filepath, image_url, git_user, git_email, git_password, force_with_lease)
        )

    @function
    async def deploy(self, src: Annotated[
            dagger.Directory,
            Doc("location of directory containing Dockerfile"),
            ],
            repo: str, 
            branch: str,
            deploy_filepath: str, 
            image_url: str,
            git_user: str, 
            git_email: str, 
            git_password: dagger.Secret, 
            force_with_lease: bool) -> str:
        
        image_url = await(self.build(src))
        await self.update(repo, branch, deploy_filepath, image_url, git_user, git_email, git_password, force_with_lease)

        return image_url
tawny lark
# hazy jolt I'm adding my full working code her, for reference for others. ``` from typing ...

Hey, as you can see in Container.publish, it's an async function, returning a coroutine. Whenever you find one of these (including your own), you need to add an await to get the result, so your build function should have image_url = await (...). If a function has any await statements in its body then you need to add async to the function signature.

Since your update function doesn't have async you shouldn't add await before self.update, but if the dag.image_updater().update function is in fact async, then you should also add await and async to your update function.

See https://github.com/dagger/dagger/issues/4705 for basic rules.

GitHub

Summary Write a guide for Python users unfamiliar with asynchronous code. Motivation Asynchronous programming has become an increasingly important aspect of Python, yet it remains a topic that many...