diff --git a/doc/members/proposals.rst b/doc/members/proposals.rst index 6df37bc60..ee8257fde 100644 --- a/doc/members/proposals.rst +++ b/doc/members/proposals.rst @@ -67,6 +67,29 @@ Some of these subcommands require additional arguments, such as the node ID or u These proposals and votes should be sent as the body of HTTP requests as described below. +Creating Proposals in Python +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``ccf.proposal_generator`` can also be imported and used in a Python application instead of as a command-line tool. + +.. literalinclude:: ../../python/tutorial.py + :language: py + :start-after: SNIPPET: import_proposal_generator + :lines: 1 + +The proposal generation functions return dictionaries that can be submitted to a ``CCFClient``. + +.. literalinclude:: ../../python/tutorial.py + :language: py + :start-after: SNIPPET_START: dict_proposal + :end-before: SNIPPET_END: dict_proposal + +You may wish to write these proposals to files so they can be examined or modified further. These proposal files can be submitted directly --- ``CCFClient`` will treat string request bodies beginning with an ``@`` as file paths in the same way that ``curl`` does, and use the content of the file when sending. + +.. literalinclude:: ../../python/tutorial.py + :language: py + :start-after: SNIPPET_START: json_proposal_with_file + :end-before: SNIPPET_END: json_proposal_with_file + Submitting a New Proposal ------------------------- diff --git a/python/tutorial.py b/python/tutorial.py index 54bf13cd2..47f91ad0e 100644 --- a/python/tutorial.py +++ b/python/tutorial.py @@ -27,8 +27,13 @@ common_dir = client_info["common_dir"] ca = os.path.join(common_dir, "networkcert.pem") cert = os.path.join(common_dir, "user0_cert.pem") key = os.path.join(common_dir, "user0_privk.pem") -# Client info loaded. Tutorial starts below. +# User client info loaded. +member_cert = os.path.join(common_dir, "member0_cert.pem") +member_key = os.path.join(common_dir, "member0_privk.pem") +# Member client info loaded. + +# Tutorial starts below. # SNIPPET: anonymous_client anonymous_client = ccf.clients.CCFClient(host, port, ca) @@ -86,3 +91,25 @@ for transaction in ledger: for key, value in public_tables[target_table].items(): target_table_changes += 1 # A key was changed # SNIPPET_END: iterate_over_ledger + +# SNIPPET: import_proposal_generator +import ccf.proposal_generator + +# SNIPPET_START: dict_proposal +proposal, vote = ccf.proposal_generator.open_network() +# >>> proposal +# {'script': {'text': 'return Calls:call("open_network")'}} + +member_client = ccf.clients.CCFClient(host, port, ca, member_cert, member_key) +response = member_client.post("/gov/proposals", body=proposal, signed=True,) +# SNIPPET_END: dict_proposal + +# SNIPPET_START: json_proposal_with_file +with open("my_open_network_proposal.json", "w") as f: + f.write(json.dumps(proposal, indent=2)) + +# The contents of `my_open_network_proposal.json` are submitted as the request body. +response = member_client.post( + "/gov/proposals", body="@my_open_network_proposal.json", signed=True, +) +# SNIPPET_END: json_proposal_with_file