Skip to content

Commit

Permalink
add: example script to create or update a form (#83)
Browse files Browse the repository at this point in the history
- fix: template token copypasta in tests (token from MD template).
- chg: use create_ignore_duplicate_error in tests, because that
  would avoid ignoring issues like the above (invalid form).
  • Loading branch information
lindsay-stevens authored May 3, 2024
1 parent 3fd3985 commit d7a4f7f
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 12 deletions.
6 changes: 5 additions & 1 deletion docs/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ A script that uses mail merge to create personalized Word documents with data fr

## [October 2022 webinar materials](2022-10-pyodk-webinar.ipynb)

A Jupyter notebook companion to an October 2022 webinar by Hélène Martin introducing `pyodk`. Includes link to the session recording.
A Jupyter notebook companion to an October 2022 webinar by Hélène Martin introducing `pyodk`. Includes link to the session recording.

## [Create or Update Form script](create_or_update_form/create_or_update_form.py)

A script to create or update a form, optionally with attachments.
60 changes: 60 additions & 0 deletions docs/examples/create_or_update_form/create_or_update_form.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import sys
from os import PathLike
from pathlib import Path

from pyodk.client import Client
from pyodk.errors import PyODKError
from requests import Response

"""
A script to create or update a form, optionally with attachments.
Either use as a CLI script, or import create_or_update into another module.
If provided, all files in the [attachments_dir] path will be uploaded with the form.
"""


def create_ignore_duplicate_error(client: Client, definition: PathLike | str | bytes):
"""Create the form; ignore the error raised if it exists (409.3)."""
try:
client.forms.create(definition=definition)
except PyODKError as err:
if len(err.args) >= 2 and isinstance(err.args[1], Response):
err_detail = err.args[1].json()
err_code = err_detail.get("code")
if err_code is not None and str(err_code) == "409.3":
return
raise


def create_or_update(form_id: str, definition: str, attachments: str | None):
"""Create (and publish) the form, optionally with attachments."""
with Client() as client:
create_ignore_duplicate_error(client=client, definition=definition)
attach = None
if attachments is not None:
attach = Path(attachments).iterdir()
client.forms.update(
definition=definition,
form_id=form_id,
attachments=attach,
)


if __name__ == "__main__":
usage = """
Usage:
python create_or_update_form.py form_id definition.xlsx
python create_or_update_form.py form_id definition.xlsx attachments_dir
"""
if len(sys.argv) < 3:
print(usage)
sys.exit(1)
fid = sys.argv[1]
def_path = sys.argv[2]
attach_path = None
if len(sys.argv) == 4:
attach_path = sys.argv[3]
create_or_update(form_id=fid, definition=def_path, attachments=attach_path)
1 change: 1 addition & 0 deletions docs/examples/create_or_update_form/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pyodk==1.0.0
6 changes: 3 additions & 3 deletions tests/resources/forms_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def get_xml__range_draft(

def get_md__pull_data(version: str | None = None) -> str:
if version is None:
version = datetime.now().isoformat()
version = datetime.now(UTC).isoformat()
return f"""
| settings |
| | version |
Expand All @@ -106,7 +106,7 @@ def get_md__pull_data(version: str | None = None) -> str:
| survey | | | | |
| | type | name | label | calculation |
| | calculate | fruit | | pulldata('fruits', 'name', 'name_key', 'mango') |
| | note | note_fruit | The fruit ${{fruit}} pulled from csv | |
| | note | note_fruit | The fruit ${fruit} pulled from csv | |
"""
md__dingbat = """
| settings |
Expand All @@ -115,5 +115,5 @@ def get_md__pull_data(version: str | None = None) -> str:
| survey | | | | |
| | type | name | label | calculation |
| | calculate | fruit | | pulldata('fruits', 'name', 'name_key', 'mango') |
| | note | note_fruit | The fruit ${{fruit}} pulled from csv | |
| | note | note_fruit | The fruit ${fruit} pulled from csv | |
"""
30 changes: 22 additions & 8 deletions tests/utils/forms.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
from os import PathLike

from pyodk.client import Client
from pyodk.errors import PyODKError
from requests import Response

from tests.utils import utils
from tests.utils.md_table import md_table_to_temp_dir


def create_ignore_duplicate_error(
client: Client,
definition: PathLike | str | bytes,
form_id: str,
):
"""Create the form; ignore the error raised if it exists (409.3)."""
try:
client.forms.create(definition=definition, form_id=form_id)
except PyODKError as err:
if len(err.args) >= 2 and isinstance(err.args[1], Response):
err_detail = err.args[1].json()
err_code = err_detail.get("code")
if err_code is not None and str(err_code) == "409.3":
return
raise


def create_new_form__md(client: Client, form_id: str, form_def: str):
"""
Create a new form from a MarkDown string.
Expand All @@ -16,10 +36,7 @@ def create_new_form__md(client: Client, form_id: str, form_def: str):
with (
md_table_to_temp_dir(form_id=form_id, mdstr=form_def) as fp,
):
try:
client.forms.create(definition=fp, form_id=form_id)
except PyODKError:
pass
create_ignore_duplicate_error(client=client, definition=fp, form_id=form_id)


def create_new_form__xml(client: Client, form_id: str, form_def: str):
Expand All @@ -32,10 +49,7 @@ def create_new_form__xml(client: Client, form_id: str, form_def: str):
"""
with utils.get_temp_file(suffix=".xml") as fp:
fp.write_text(form_def)
try:
client.forms.create(definition=fp, form_id=form_id)
except PyODKError:
pass
create_ignore_duplicate_error(client=client, definition=fp, form_id=form_id)


def get_latest_form_version(client: Client, form_id: str) -> str:
Expand Down

0 comments on commit d7a4f7f

Please sign in to comment.