Dazl call to Sandbox or Dal hub, depending on env variable

I want to write Dazl scripts so, that they do exactly the same against Sandbox and Daml Hub, depending on an env variable. This is the best I could come up with so far, basically duplicating the calling function.

The challenge is that dazl.connect(...) requires a different set of named arguments for the Sandbox and the Daml Hub case, and None is not accepted instead of a missing value.

Can I do this without duplicating the function?

The contents of my .env file:

HUB=true
HUB_LEDGER_ID=oq5rxvri2nvpo2nq
HUB_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImRhYmwtYmYxZmQzNzgtYTAzYy00MTk4LTkyYTgtNzNjMmMyOWU2OTNkIn0.eyJpc3MiOiJodWIuZGFtbC5jb20vbG9naW4iLCJzdWIiOiJhdXRoMHw2MTkyOWIzMjRlMmJmNTAwNmZlNTJmNjAiLCJleHAiOjE2NjE0NTI1ODQsImp0aSI6Ijk3ZjMwZDM3LTgwNWQtNDg0Yi1hNjAwLTFkMWM1MWRjOWI2ZCIsImh0dHBzOi8vZGFtbC5jb20vbGVkZ2VyLWFwaSI6eyJhY3RBcyI6WyJsZWRnZXItcGFydHktY2ZhMzI4NDYtYTA1Yy00N2ExLTgwNTQtZjNiNzllMTE0YmEyOjoxMjIwOGEyNTIyYWQzMzg1ZTRiODkyZGYyOTZiMjhiM2Q0OTEzMDMwOWQ5ZDk0ZWYxNDU2ZDY2Yzk4MjU0ZDA5OTU3YSJdLCJhZG1pbiI6ZmFsc2UsImFwcGxpY2F0aW9uSWQiOiJkYW1saHViIiwibGVkZ2VySWQiOiJvcTVyeHZyaTJudnBvMm5xIiwicGFydGljaXBhbnRJZCI6bnVsbCwicmVhZEFzIjpbImxlZGdlci1wYXJ0eS1jZmEzMjg0Ni1hMDVjLTQ3YTEtODA1NC1mM2I3OWUxMTRiYTI6OjEyMjA4YTI1MjJhZDMzODVlNGI4OTJkZjI5NmIyOGIzZDQ5MTMwMzA5ZDlkOTRlZjE0NTZkNjZjOTgyNTRkMDk5NTdhIl19LCJodWJDbGFpbXMiOnsibGVkZ2VySWQiOiJvcTVyeHZyaTJudnBvMm5xIiwib3duZXIiOiJ1c2VyLWdyYW50LTRiMjA5MWE4LTRmMDUtNDBkZS1hZWUyLTY5OTgzMzYyM2E4MyIsInBhcnR5IjoibGVkZ2VyLXBhcnR5LWNmYTMyODQ2LWEwNWMtNDdhMS04MDU0LWYzYjc5ZTExNGJhMjo6MTIyMDhhMjUyMmFkMzM4NWU0Yjg5MmRmMjk2YjI4YjNkNDkxMzAzMDlkOWQ5NGVmMTQ1NmQ2NmM5ODI1NGQwOTk1N2EiLCJwYXJ0eU5hbWUiOiJBbGljZSJ9LCJsZWRnZXJJZCI6Im9xNXJ4dnJpMm52cG8ybnEiLCJvd25lciI6InVzZXItZ3JhbnQtNGIyMDkxYTgtNGYwNS00MGRlLWFlZTItNjk5ODMzNjIzYTgzIiwicGFydHkiOiJsZWRnZXItcGFydHktY2ZhMzI4NDYtYTA1Yy00N2ExLTgwNTQtZjNiNzllMTE0YmEyOjoxMjIwOGEyNTIyYWQzMzg1ZTRiODkyZGYyOTZiMjhiM2Q0OTEzMDMwOWQ5ZDk0ZWYxNDU2ZDY2Yzk4MjU0ZDA5OTU3YSIsInBhcnR5TmFtZSI6IkFsaWNlIn0.mvWDZF3_POtqWsnVKkivxNAzTXMo8xfqKOZO05-eiNajSl7UE0SW7phH6GaXsPZNQAVkq8PBGRGXgK1v0c59kZgkQXmPWtkAHO3O9IdWc8PpYEMXDyphzgwPa7KXXSG6MKfR4y-3la_8EQAaS5oDCoSjD5ujn2hLwlnjE8X97A0
ALICE_SANDBOX='Alice::12207905d2300dd8cb73823e5cb0cc4a5992c9a2bc7989a9419678fe343a7640ab15'
ALICE_HUB='ledger-party-cfa32846-a05c-47a1-8054-f3b79e114ba2::12208a2522ad3385e4b892df296b28b3d49130309d9d94ef1456d66c98254d09957a'
PCKG_ID='5e91c7d2bfbf0b884babf456725c2132049b65506de0c4e1f3176f446c7f1ef7'
CERT_FILE='isrgrootx1.pem'

And the script:

#!/usr/bin/env python3

import os
import asyncio
import dazl
from dazl.damlast.lookup import parse_type_con_name
from dotenv import load_dotenv
load_dotenv()

url= 'https://' + os.environ["HUB_LEDGER_ID"] + '.daml.app:443' if os.environ["HUB"] == 'true' else 'localhost:6865'
token = os.environ["HUB_TOKEN"]
alice = os.environ["ALICE_HUB"] if os.environ["HUB"] == 'true' else os.environ["ALICE_SANDBOX"]
cert_file = os.environ["CERT_FILE"]

asset_tamplate_id = parse_type_con_name(os.environ["PCKG_ID"] + ':Main:Asset')

async def main_hub():
    print("Connecting to Daml Hub")
    async with dazl.connect(url=url,oauth_token=token, cert_file = cert_file) as conn:
        payload = {"owner": alice, "table": {}}
        event = await conn.create(asset_tamplate_id, payload)
        print(event.contract_id) 

async def main_sandbox():
    print("Connecting to Sandbox")
    async with dazl.connect(url=url, act_as = alice) as conn:
        payload = {"owner": alice, "table": {}}
        event = await conn.create(asset_tamplate_id, payload)
        print(event.contract_id)               

if os.environ["HUB"] == 'true':
    asyncio.run(main_hub())
else:
    asyncio.run(main_sandbox())

Definitely! In Python, you can use the ** operator to supply multiple named parameters to a function.


import os
import asyncio
import dazl
from dazl.damlast.lookup import parse_type_con_name
from dotenv import load_dotenv
load_dotenv()

def env():
    if os.environ["HUB"] == 'true':
        return {
            url: 'https://' + os.environ["HUB_LEDGER_ID"] + '.daml.app:443',
            token: os.environ["HUB_TOKEN"],
            cert_file: os.environ["CERT_FILE"]
        }
    else:
        return {
             url: 'localhost:6865',
             token: os.environ["HUB_TOKEN"]
        }

def alice_party():
    # you may want to consider moving this if statement "outside", and switch to
    # an environment variable that merely supplies a party literal
    return os.environ["ALICE_HUB"] if os.environ["HUB"] == 'true' else os.environ["ALICE_SANDBOX"]

asset_template_id = parse_type_con_name(os.environ["PCKG_ID"] + ':Main:Asset')

async def main():
    print("Connecting to Daml Hub")
    async with dazl.connect(**env()) as conn:
        payload = {"owner": alice_party(), "table": {}}
        event = await conn.create(asset_template_id, payload)
        print(event.contract_id) 

asyncio.run(main())

In general, though, it’ll be easier to manage this “if” outside:

#!/bin/sh
# this is sandbox.sh
export LEDGER_URL=localhost:6865
export LEDGER_PARTY=Alice
exec python3 thing.py
#!/bin/sh
# this is damlhub.sh
export LEDGER_URL="https://${HUB_LEDGER_ID}.daml.app:443"
# not sure where you're sourcing these from
# export LEDGER_PARTY=
# export CERT_FILE=
exec python3 thing.py

Then in your python code:

def env():
    connect_vars = {
        url: os.environ['LEDGER_URL']
        token: os.environ['LEDGER_PARTY'],
    }
    if cert_file := os.environ.get("CERT_FILE"):
         connect_vars['cert_file'] = cert_file
    return connect_vars

1 Like

Great, thank you!