From b9955df0889478bee8b146ad73ca9722bf7169bc Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Wed, 15 Nov 2023 21:03:35 -0800 Subject: [PATCH 01/77] bump version to 4.1.0.dev0 --- pyonepassword/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyonepassword/__about__.py b/pyonepassword/__about__.py index c866395a..6ca31d2d 100644 --- a/pyonepassword/__about__.py +++ b/pyonepassword/__about__.py @@ -1,5 +1,5 @@ __title__ = "pyonepassword" -__version__ = "4.0.1" +__version__ = "4.1.0.dev0" __summary__ = "A python API to query a 1Password account using the 'op' command-line tool" """ From e66c143ab54129c0d5793ac18c462898026370d3 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 19:24:20 -0800 Subject: [PATCH 02/77] reorder "document_..." methods in _OPCLIArgv --- pyonepassword/_op_cli_argv.py | 80 +++++++++++++++++------------------ 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/pyonepassword/_op_cli_argv.py b/pyonepassword/_op_cli_argv.py index 033ef934..47d4b53e 100644 --- a/pyonepassword/_op_cli_argv.py +++ b/pyonepassword/_op_cli_argv.py @@ -77,6 +77,32 @@ def svc_account_supported(self) -> OPSvcAcctSupportCode: supported = reg.command_supported(self) return supported + @classmethod + def document_get_argv(cls, op_exe, document_name_or_id, vault=None, include_archive=False): + + sub_cmd_args = [document_name_or_id] + if vault: + sub_cmd_args.extend(["--vault", vault]) + if include_archive: + sub_cmd_args.append("--include-archive") + argv = cls.document_generic_argv(op_exe, "get", sub_cmd_args) + return argv + + @classmethod + def document_delete_argv(cls, + op_exe: str, + document_name_or_id: str, + vault: Optional[str] = None, + archive: bool = False): + sub_cmd_args = [document_name_or_id] + if archive: + sub_cmd_args.append("--archive") + if vault: + sub_cmd_args.extend(["--vault", vault]) + delete_argv = cls.document_generic_argv(op_exe, "delete", sub_cmd_args) + + return delete_argv + @classmethod def item_generic_argv(cls, op_exe: str, @@ -119,33 +145,6 @@ def item_get_totp_argv(cls, op_exe, item_name_or_id, vault=None): op_exe, item_name_or_id, vault=vault, fields=field_arg) return argv - @classmethod - def document_generic_argv(cls, - op_exe: str, - subcommands: Optional[Union[str, List[str]]], - sub_cmd_args: Optional[List[str]]): - args = [] - global_args = ["--format", "json"] - if sub_cmd_args: - args.extend(sub_cmd_args) - argv = cls(op_exe, - "document", - args, - subcommands=subcommands, - global_args=global_args) - return argv - - @classmethod - def document_get_argv(cls, op_exe, document_name_or_id, vault=None, include_archive=False): - - sub_cmd_args = [document_name_or_id] - if vault: - sub_cmd_args.extend(["--vault", vault]) - if include_archive: - sub_cmd_args.append("--include-archive") - argv = cls.document_generic_argv(op_exe, "get", sub_cmd_args) - return argv - @classmethod def vault_generic_argv(cls, op_exe: str, @@ -493,16 +492,17 @@ def item_delete_argv(cls, return delete_argv @classmethod - def document_delete_argv(cls, - op_exe: str, - document_name_or_id: str, - vault: Optional[str] = None, - archive: bool = False): - sub_cmd_args = [document_name_or_id] - if archive: - sub_cmd_args.append("--archive") - if vault: - sub_cmd_args.extend(["--vault", vault]) - delete_argv = cls.document_generic_argv(op_exe, "delete", sub_cmd_args) - - return delete_argv + def document_generic_argv(cls, + op_exe: str, + subcommands: Optional[Union[str, List[str]]], + sub_cmd_args: Optional[List[str]]): + args = [] + global_args = ["--format", "json"] + if sub_cmd_args: + args.extend(sub_cmd_args) + argv = cls(op_exe, + "document", + args, + subcommands=subcommands, + global_args=global_args) + return argv From 884b8b5477244148605a804c8d78999135975163 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 19:25:35 -0800 Subject: [PATCH 03/77] rename _document_generic_argv() --- pyonepassword/_op_cli_argv.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pyonepassword/_op_cli_argv.py b/pyonepassword/_op_cli_argv.py index 47d4b53e..3964f2bf 100644 --- a/pyonepassword/_op_cli_argv.py +++ b/pyonepassword/_op_cli_argv.py @@ -85,7 +85,7 @@ def document_get_argv(cls, op_exe, document_name_or_id, vault=None, include_arch sub_cmd_args.extend(["--vault", vault]) if include_archive: sub_cmd_args.append("--include-archive") - argv = cls.document_generic_argv(op_exe, "get", sub_cmd_args) + argv = cls._document_generic_argv(op_exe, "get", sub_cmd_args) return argv @classmethod @@ -99,7 +99,8 @@ def document_delete_argv(cls, sub_cmd_args.append("--archive") if vault: sub_cmd_args.extend(["--vault", vault]) - delete_argv = cls.document_generic_argv(op_exe, "delete", sub_cmd_args) + delete_argv = cls._document_generic_argv( + op_exe, "delete", sub_cmd_args) return delete_argv @@ -492,10 +493,10 @@ def item_delete_argv(cls, return delete_argv @classmethod - def document_generic_argv(cls, - op_exe: str, - subcommands: Optional[Union[str, List[str]]], - sub_cmd_args: Optional[List[str]]): + def _document_generic_argv(cls, + op_exe: str, + subcommands: Optional[Union[str, List[str]]], + sub_cmd_args: Optional[List[str]]): args = [] global_args = ["--format", "json"] if sub_cmd_args: From 226a488b68ca333d8ebce62c71942824a3fad0aa Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 19:31:04 -0800 Subject: [PATCH 04/77] add _OPCLIArgv.document_edit_argv() --- pyonepassword/_op_cli_argv.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pyonepassword/_op_cli_argv.py b/pyonepassword/_op_cli_argv.py index 3964f2bf..82e677a4 100644 --- a/pyonepassword/_op_cli_argv.py +++ b/pyonepassword/_op_cli_argv.py @@ -88,6 +88,15 @@ def document_get_argv(cls, op_exe, document_name_or_id, vault=None, include_arch argv = cls._document_generic_argv(op_exe, "get", sub_cmd_args) return argv + @classmethod + def document_edit_argv(cls, op_exe, document_identifier, vault=None): + + sub_cmd_args = [document_identifier] + if vault: + sub_cmd_args.extend(["--vault", vault]) + argv = cls._document_generic_argv(op_exe, "edit", sub_cmd_args) + return argv + @classmethod def document_delete_argv(cls, op_exe: str, From 16f147498a2380d4baccb17c077f5a1fe1929f69 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 19:31:44 -0800 Subject: [PATCH 05/77] rename _py_op_cli.py to _op_cli.py --- pyonepassword/{_py_op_cli.py => _op_cli.py} | 0 pyonepassword/_py_op_commands.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename pyonepassword/{_py_op_cli.py => _op_cli.py} (100%) diff --git a/pyonepassword/_py_op_cli.py b/pyonepassword/_op_cli.py similarity index 100% rename from pyonepassword/_py_op_cli.py rename to pyonepassword/_op_cli.py diff --git a/pyonepassword/_py_op_commands.py b/pyonepassword/_py_op_commands.py index 587f4442..e7f2ca4f 100644 --- a/pyonepassword/_py_op_commands.py +++ b/pyonepassword/_py_op_commands.py @@ -11,9 +11,9 @@ if TYPE_CHECKING: # pragma: no coverage from pyonepassword._field_assignment import OPFieldTypeEnum +from ._op_cli import _OPCLIExecute from ._op_cli_argv import _OPArgv from ._op_cli_config import OPCLIConfig -from ._py_op_cli import _OPCLIExecute from ._svc_account import ( SVC_ACCT_CMD_NOT_SUPPORTED, SVC_ACCT_INCOMPAT_OPTIONS, From a767f3e61b99022c9314b10b38b261aef8369195 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 19:40:20 -0800 Subject: [PATCH 06/77] rename _py_op_commands to _op_commands --- ipython_snippets/basic.py | 2 +- ipython_snippets/pytest/misc.py | 2 +- ipython_snippets/signin.py | 2 +- pyonepassword/{_py_op_commands.py => _op_commands.py} | 0 pyonepassword/api/authentication.py | 2 +- pyonepassword/pyonepassword.py | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename pyonepassword/{_py_op_commands.py => _op_commands.py} (100%) diff --git a/ipython_snippets/basic.py b/ipython_snippets/basic.py index dcab77cd..dea43f7c 100644 --- a/ipython_snippets/basic.py +++ b/ipython_snippets/basic.py @@ -2,7 +2,7 @@ from pyonepassword import OP, logging from pyonepassword._op_cli_config import OPCLIAccountConfig, OPCLIConfig -from pyonepassword._py_op_commands import ( # noqa: F401 +from pyonepassword._op_commands import ( # noqa: F401 EXISTING_AUTH_AVAIL, EXISTING_AUTH_IGNORE, EXISTING_AUTH_REQD diff --git a/ipython_snippets/pytest/misc.py b/ipython_snippets/pytest/misc.py index 235015d4..a6ac891e 100644 --- a/ipython_snippets/pytest/misc.py +++ b/ipython_snippets/pytest/misc.py @@ -2,7 +2,7 @@ from pyonepassword import OP, logging from pyonepassword._op_cli_config import OPCLIConfig -from pyonepassword._py_op_commands import EXISTING_AUTH_REQD +from pyonepassword._op_commands import EXISTING_AUTH_REQD from tests.fixtures.op_fixtures import _setup_alt_env, _setup_normal_env from tests.fixtures.valid_op_cli_config import ( VALID_OP_CONFIG_NO_SHORTHAND_KEY, diff --git a/ipython_snippets/signin.py b/ipython_snippets/signin.py index 0b6f916c..c2429993 100644 --- a/ipython_snippets/signin.py +++ b/ipython_snippets/signin.py @@ -2,7 +2,7 @@ from pyonepassword import OP, logging from pyonepassword._op_cli_config import OPCLIAccountConfig, OPCLIConfig -from pyonepassword._py_op_commands import ( # noqa: F401 +from pyonepassword._op_commands import ( # noqa: F401 EXISTING_AUTH_AVAIL, EXISTING_AUTH_IGNORE, EXISTING_AUTH_REQD diff --git a/pyonepassword/_py_op_commands.py b/pyonepassword/_op_commands.py similarity index 100% rename from pyonepassword/_py_op_commands.py rename to pyonepassword/_op_commands.py diff --git a/pyonepassword/api/authentication.py b/pyonepassword/api/authentication.py index a44bdbdd..f3eefc90 100644 --- a/pyonepassword/api/authentication.py +++ b/pyonepassword/api/authentication.py @@ -1,4 +1,4 @@ -from .._py_op_commands import ( +from .._op_commands import ( EXISTING_AUTH_AVAIL, EXISTING_AUTH_IGNORE, EXISTING_AUTH_REQD, diff --git a/pyonepassword/pyonepassword.py b/pyonepassword/pyonepassword.py index 07be3e47..07ada54b 100644 --- a/pyonepassword/pyonepassword.py +++ b/pyonepassword/pyonepassword.py @@ -9,7 +9,7 @@ from .op_items.fields_sections.item_field import OPItemField from ._field_assignment import OPFieldTypeEnum -from ._py_op_commands import ( +from ._op_commands import ( EXISTING_AUTH_IGNORE, ExistingAuthEnum, _OPCommandInterface From 0321a6d4ef7bffbdc104f94d7b6ae75101658176 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 19:43:31 -0800 Subject: [PATCH 07/77] rearrange _document_*_argv methods in `_OPCommandInterface()` --- pyonepassword/_op_commands.py | 42 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/pyonepassword/_op_commands.py b/pyonepassword/_op_commands.py index e7f2ca4f..a94b56ea 100644 --- a/pyonepassword/_op_commands.py +++ b/pyonepassword/_op_commands.py @@ -427,27 +427,6 @@ def _account_list_argv(cls, op_path="op", encoding="utf-8"): argv = _OPArgv.account_list_argv(op_path, encoding=encoding) return argv - def _item_get_argv(self, item_name_or_id, vault=None, fields=None, include_archive=False): - vault_arg = vault if vault else self.vault - - lookup_argv = _OPArgv.item_get_argv( - self.op_path, item_name_or_id, vault=vault_arg, fields=fields, include_archive=include_archive) - return lookup_argv - - def _item_delete_argv(self, item_name_or_id, vault=None, archive=False): - vault_arg = vault if vault else self.vault - - delete_argv = _OPArgv.item_delete_argv( - self.op_path, item_name_or_id, vault=vault_arg, archive=archive) - return delete_argv - - def _item_get_totp_argv(self, item_name_or_id, vault=None): - vault_arg = vault if vault else self.vault - - lookup_argv = _OPArgv.item_get_totp_argv( - self.op_path, item_name_or_id, vault=vault_arg) - return lookup_argv - def _document_get_argv(self, document_name_or_id: str, vault: Optional[str] = None, @@ -469,6 +448,27 @@ def _document_delete_argv(self, document_name_or_id: str, vault: Optional[str] = return document_delete_argv + def _item_get_argv(self, item_name_or_id, vault=None, fields=None, include_archive=False): + vault_arg = vault if vault else self.vault + + lookup_argv = _OPArgv.item_get_argv( + self.op_path, item_name_or_id, vault=vault_arg, fields=fields, include_archive=include_archive) + return lookup_argv + + def _item_delete_argv(self, item_name_or_id, vault=None, archive=False): + vault_arg = vault if vault else self.vault + + delete_argv = _OPArgv.item_delete_argv( + self.op_path, item_name_or_id, vault=vault_arg, archive=archive) + return delete_argv + + def _item_get_totp_argv(self, item_name_or_id, vault=None): + vault_arg = vault if vault else self.vault + + lookup_argv = _OPArgv.item_get_totp_argv( + self.op_path, item_name_or_id, vault=vault_arg) + return lookup_argv + def _user_get_argv(self, user_name_or_id: str): get_user_argv = _OPArgv.user_get_argv(self.op_path, user_name_or_id) return get_user_argv From 3a6eb0de61745c597d7498ca3154f26c81709bf3 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 19:47:21 -0800 Subject: [PATCH 08/77] group all _*_argv methods in `_OPCommandInterface()` together --- pyonepassword/_op_commands.py | 352 +++++++++++++++++----------------- 1 file changed, 176 insertions(+), 176 deletions(-) diff --git a/pyonepassword/_op_commands.py b/pyonepassword/_op_commands.py index a94b56ea..1e81f282 100644 --- a/pyonepassword/_op_commands.py +++ b/pyonepassword/_op_commands.py @@ -422,83 +422,6 @@ def _run_with_auth_check(cls, decode=decode, env=env) - @classmethod - def _account_list_argv(cls, op_path="op", encoding="utf-8"): - argv = _OPArgv.account_list_argv(op_path, encoding=encoding) - return argv - - def _document_get_argv(self, - document_name_or_id: str, - vault: Optional[str] = None, - include_archive: Optional[bool] = False): - vault_arg = vault if vault else self.vault - document_get_argv = _OPArgv.document_get_argv(self.op_path, - document_name_or_id, - vault=vault_arg, - include_archive=include_archive) - print(document_get_argv) - - return document_get_argv - - def _document_delete_argv(self, document_name_or_id: str, vault: Optional[str] = None, archive=False): - vault_arg = vault if vault else self.vault - - document_delete_argv = _OPArgv.document_delete_argv( - self.op_path, document_name_or_id, vault=vault_arg, archive=archive) - - return document_delete_argv - - def _item_get_argv(self, item_name_or_id, vault=None, fields=None, include_archive=False): - vault_arg = vault if vault else self.vault - - lookup_argv = _OPArgv.item_get_argv( - self.op_path, item_name_or_id, vault=vault_arg, fields=fields, include_archive=include_archive) - return lookup_argv - - def _item_delete_argv(self, item_name_or_id, vault=None, archive=False): - vault_arg = vault if vault else self.vault - - delete_argv = _OPArgv.item_delete_argv( - self.op_path, item_name_or_id, vault=vault_arg, archive=archive) - return delete_argv - - def _item_get_totp_argv(self, item_name_or_id, vault=None): - vault_arg = vault if vault else self.vault - - lookup_argv = _OPArgv.item_get_totp_argv( - self.op_path, item_name_or_id, vault=vault_arg) - return lookup_argv - - def _user_get_argv(self, user_name_or_id: str): - get_user_argv = _OPArgv.user_get_argv(self.op_path, user_name_or_id) - return get_user_argv - - def _user_list_argv(self, group_name_or_id=None, vault=None): - user_list_argv = _OPArgv.user_list_argv( - self.op_path, group_name_or_id=group_name_or_id, vault=vault) - return user_list_argv - - def _group_get_argv(self, group_name_or_id: str): - group_get_argv = _OPArgv.group_get_argv( - self.op_path, group_name_or_id) - return group_get_argv - - def _group_list_argv(self, user_name_or_id=None, vault=None): - group_list_argv = _OPArgv.group_list_argv( - self.op_path, user_name_or_id=user_name_or_id, vault=vault) - return group_list_argv - - def _vault_get_argv(self, vault_name_or_id: str): - - get_vault_argv = _OPArgv.vault_get_argv( - self.op_path, vault_name_or_id) - return get_vault_argv - - def _vault_list_argv(self, group_name_or_id=None, user_name_or_id=None): - vault_list_argv = _OPArgv.vault_list_argv( - self.op_path, group_name_or_id=group_name_or_id, user_name_or_id=user_name_or_id) - return vault_list_argv - @classmethod def _item_template_list_special(cls, op_path, env: Dict[str, str] = None): if not env: @@ -752,20 +675,6 @@ def _account_forget(cls, account: str, op_path=None): # pragma: no cover argv = _OPArgv.account_forget_argv(op_path, account) cls._run(argv) - def _item_list_argv(self, categories=[], include_archive=False, tags=[], vault=None): - # default lists to the categories & list kwargs - # get initialized at module load - # so its the same list object on every call to this funciton - # This really isn't what we want, so the easiest - # mitigation is to just make a copy of whatever list was passed in - # or of the default kwarg if nothing was passed in - categories = list(categories) - tags = list(tags) - vault_arg = vault if vault else self.vault - list_items_argv = _OPArgv.item_list_argv(self.op_path, - categories=categories, include_archive=include_archive, tags=tags, vault=vault_arg) - return list_items_argv - def _item_list(self, categories=[], include_archive=False, tags=[], vault=None, decode="utf-8"): # default lists to the categories & list kwargs # get initialized at module load @@ -784,91 +693,6 @@ def _item_list(self, categories=[], include_archive=False, tags=[], vault=None, raise OPItemListException.from_opexception(e) return output - def _item_create_argv(self, item, password_recipe, vault): - vault_arg = vault if vault else self.vault - item_create_argv = _OPArgv.item_create_argv( - self.op_path, item, password_recipe=password_recipe, vault=vault_arg - ) - return item_create_argv - - def _item_edit_set_field_value_argv(self, - item_identifier: str, - field_type: OPFieldTypeEnum, - value: str, - field_label: str, - section_label: Optional[str], - vault: Optional[str]): - vault_arg = vault if vault else self.vault - item_edit_argv = _OPArgv.item_edit_set_field_value(self.op_path, - item_identifier, - field_type, - value, - field_label=field_label, - section_label=section_label, - vault=vault_arg) - return item_edit_argv - - def _item_edit_favorite_argv(self, - item_identifier: str, - favorite: bool, - vault: Optional[str]): - vault_arg = vault if vault else self.vault - - item_edit_argv = _OPArgv.item_edit_favorite(self.op_path, - item_identifier, - favorite, - vault=vault_arg) - return item_edit_argv - - def _item_edit_generate_password_argv(self, - item_identifier: str, - password_recipe: OPPasswordRecipe, - vault: Optional[str]): - - vault_arg = vault if vault else self.vault - item_edit_argv = _OPArgv.item_edit_generate_password_argv(self.op_path, - item_identifier, - password_recipe, - vault=vault_arg) - return item_edit_argv - - def _item_edit_tags_argv(self, - item_identifier: str, - tags: List[str], - vault: Optional[str]): - vault_arg = vault if vault else self.vault - - item_edit_argv = _OPArgv.item_edit_tags(self.op_path, - item_identifier, - tags, - vault=vault_arg) - - return item_edit_argv - - def _item_edit_title_argv(self, - item_identifier: str, - item_title: str, - vault: Optional[str]): - vault_arg = vault if vault else self.vault - - item_edit_argv = _OPArgv.item_edit_title(self.op_path, - item_identifier, - item_title, - vault=vault_arg) - return item_edit_argv - - def _item_edit_url_argv(self, - item_identifier: str, - url: str, - vault: Optional[str]): - vault_arg = vault if vault else self.vault - - item_edit_argv = _OPArgv.item_edit_url(self.op_path, - item_identifier, - url, - vault=vault_arg) - return item_edit_argv - def _item_create(self, item, vault, password_recipe, decode="utf-8"): argv = self._item_create_argv(item, password_recipe, vault) try: @@ -959,3 +783,179 @@ def _item_edit_url(self, output = self._item_edit_run(argv, decode) return output + + @classmethod + def _account_list_argv(cls, op_path="op", encoding="utf-8"): + argv = _OPArgv.account_list_argv(op_path, encoding=encoding) + return argv + + def _document_get_argv(self, + document_name_or_id: str, + vault: Optional[str] = None, + include_archive: Optional[bool] = False): + vault_arg = vault if vault else self.vault + document_get_argv = _OPArgv.document_get_argv(self.op_path, + document_name_or_id, + vault=vault_arg, + include_archive=include_archive) + print(document_get_argv) + + return document_get_argv + + def _document_delete_argv(self, document_name_or_id: str, vault: Optional[str] = None, archive=False): + vault_arg = vault if vault else self.vault + + document_delete_argv = _OPArgv.document_delete_argv( + self.op_path, document_name_or_id, vault=vault_arg, archive=archive) + + return document_delete_argv + + def _item_get_argv(self, item_name_or_id, vault=None, fields=None, include_archive=False): + vault_arg = vault if vault else self.vault + + lookup_argv = _OPArgv.item_get_argv( + self.op_path, item_name_or_id, vault=vault_arg, fields=fields, include_archive=include_archive) + return lookup_argv + + def _item_delete_argv(self, item_name_or_id, vault=None, archive=False): + vault_arg = vault if vault else self.vault + + delete_argv = _OPArgv.item_delete_argv( + self.op_path, item_name_or_id, vault=vault_arg, archive=archive) + return delete_argv + + def _item_get_totp_argv(self, item_name_or_id, vault=None): + vault_arg = vault if vault else self.vault + + lookup_argv = _OPArgv.item_get_totp_argv( + self.op_path, item_name_or_id, vault=vault_arg) + return lookup_argv + + def _user_get_argv(self, user_name_or_id: str): + get_user_argv = _OPArgv.user_get_argv(self.op_path, user_name_or_id) + return get_user_argv + + def _user_list_argv(self, group_name_or_id=None, vault=None): + user_list_argv = _OPArgv.user_list_argv( + self.op_path, group_name_or_id=group_name_or_id, vault=vault) + return user_list_argv + + def _group_get_argv(self, group_name_or_id: str): + group_get_argv = _OPArgv.group_get_argv( + self.op_path, group_name_or_id) + return group_get_argv + + def _group_list_argv(self, user_name_or_id=None, vault=None): + group_list_argv = _OPArgv.group_list_argv( + self.op_path, user_name_or_id=user_name_or_id, vault=vault) + return group_list_argv + + def _vault_get_argv(self, vault_name_or_id: str): + + get_vault_argv = _OPArgv.vault_get_argv( + self.op_path, vault_name_or_id) + return get_vault_argv + + def _vault_list_argv(self, group_name_or_id=None, user_name_or_id=None): + vault_list_argv = _OPArgv.vault_list_argv( + self.op_path, group_name_or_id=group_name_or_id, user_name_or_id=user_name_or_id) + return vault_list_argv + + def _item_create_argv(self, item, password_recipe, vault): + vault_arg = vault if vault else self.vault + item_create_argv = _OPArgv.item_create_argv( + self.op_path, item, password_recipe=password_recipe, vault=vault_arg + ) + return item_create_argv + + def _item_edit_set_field_value_argv(self, + item_identifier: str, + field_type: OPFieldTypeEnum, + value: str, + field_label: str, + section_label: Optional[str], + vault: Optional[str]): + vault_arg = vault if vault else self.vault + item_edit_argv = _OPArgv.item_edit_set_field_value(self.op_path, + item_identifier, + field_type, + value, + field_label=field_label, + section_label=section_label, + vault=vault_arg) + return item_edit_argv + + def _item_edit_favorite_argv(self, + item_identifier: str, + favorite: bool, + vault: Optional[str]): + vault_arg = vault if vault else self.vault + + item_edit_argv = _OPArgv.item_edit_favorite(self.op_path, + item_identifier, + favorite, + vault=vault_arg) + return item_edit_argv + + def _item_edit_generate_password_argv(self, + item_identifier: str, + password_recipe: OPPasswordRecipe, + vault: Optional[str]): + + vault_arg = vault if vault else self.vault + item_edit_argv = _OPArgv.item_edit_generate_password_argv(self.op_path, + item_identifier, + password_recipe, + vault=vault_arg) + return item_edit_argv + + def _item_edit_tags_argv(self, + item_identifier: str, + tags: List[str], + vault: Optional[str]): + vault_arg = vault if vault else self.vault + + item_edit_argv = _OPArgv.item_edit_tags(self.op_path, + item_identifier, + tags, + vault=vault_arg) + + return item_edit_argv + + def _item_edit_title_argv(self, + item_identifier: str, + item_title: str, + vault: Optional[str]): + vault_arg = vault if vault else self.vault + + item_edit_argv = _OPArgv.item_edit_title(self.op_path, + item_identifier, + item_title, + vault=vault_arg) + return item_edit_argv + + def _item_edit_url_argv(self, + item_identifier: str, + url: str, + vault: Optional[str]): + vault_arg = vault if vault else self.vault + + item_edit_argv = _OPArgv.item_edit_url(self.op_path, + item_identifier, + url, + vault=vault_arg) + return item_edit_argv + + def _item_list_argv(self, categories=[], include_archive=False, tags=[], vault=None): + # default lists to the categories & list kwargs + # get initialized at module load + # so its the same list object on every call to this funciton + # This really isn't what we want, so the easiest + # mitigation is to just make a copy of whatever list was passed in + # or of the default kwarg if nothing was passed in + categories = list(categories) + tags = list(tags) + vault_arg = vault if vault else self.vault + list_items_argv = _OPArgv.item_list_argv(self.op_path, + categories=categories, include_archive=include_archive, tags=tags, vault=vault_arg) + return list_items_argv From f3117e220f1a73e5aec6132b5307413d4e38b87e Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 20:01:21 -0800 Subject: [PATCH 09/77] add clarifying comments regarding OPItemDeleteMultipleException --- pyonepassword/_op_commands.py | 3 +++ pyonepassword/pyonepassword.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/pyonepassword/_op_commands.py b/pyonepassword/_op_commands.py index 1e81f282..056631e1 100644 --- a/pyonepassword/_op_commands.py +++ b/pyonepassword/_op_commands.py @@ -531,6 +531,9 @@ def _item_delete_multiple(self, batch_json, vault, archive=False): self._run_with_auth_check( self.op_path, self._account_identifier, item_delete_argv, input_string=batch_json) except OPCmdFailedException as ocfe: + # OPItemDeleteException will get turned into + # OPItemDeleteMultipleException by the caller, so + # any sucessfully deleted items can be included in the exception object raise OPItemDeleteException.from_opexception(ocfe) return diff --git a/pyonepassword/pyonepassword.py b/pyonepassword/pyonepassword.py index 07ada54b..fe889006 100644 --- a/pyonepassword/pyonepassword.py +++ b/pyonepassword/pyonepassword.py @@ -1466,6 +1466,9 @@ def item_delete_multiple(self, try: self._item_delete_multiple(batch_json, vault, archive=archive) except OPCmdFailedException as ope: # pragma: no coverage + # we have to raise OPItemDeleteMultipleException from here + # so we can give it the list of successully deleted items + # that isn't known from inside _item_delete_multiple() raise OPItemDeleteMultipleException.from_opexception( ope, deleted_items) deleted_items.extend(batch) From cb0ec0541cb5c077102d7425798d693d015b3218 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 20:21:39 -0800 Subject: [PATCH 10/77] rearrange _document_get/delete methods in `_OPCommandInterface()` --- pyonepassword/_op_commands.py | 100 +++++++++++++++++----------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/pyonepassword/_op_commands.py b/pyonepassword/_op_commands.py index 056631e1..e9bdea55 100644 --- a/pyonepassword/_op_commands.py +++ b/pyonepassword/_op_commands.py @@ -495,6 +495,56 @@ def _whoami(cls, op_path, env: Dict[str, str] = None, account: str = None) -> OP account_obj = OPAccount(account_json) return account_obj + def _document_get(self, + document_name_or_id: str, + vault: Optional[str] = None, + include_archive: Optional[bool] = False): + """ + Download a document object from a 1Password vault by name or UUID. + + Arguments: + - 'item_name_or_id': The item to look up + Raises: + - OPDocumentGetException if the lookup fails for any reason. + - OPNotFoundException if the 1Password command can't be found. + Returns: + - Bytes: document bytes + """ + + get_document_argv = self._document_get_argv( + document_name_or_id, vault=vault, include_archive=include_archive) + + try: + document_bytes = self._run_with_auth_check( + self.op_path, self._account_identifier, get_document_argv, capture_stdout=True) + except OPCmdFailedException as ocfe: + raise OPDocumentGetException.from_opexception(ocfe) from ocfe + + if self._cli_version <= DOCUMENT_BYTES_BUG_VERSION: # pragma: no cover + # op versions 2.0.0 - 2.2.0 append an erroneous \x0a ('\n') byte to document bytes + # trim it off if its present + if document_bytes[-1] == 0x0a: + document_bytes = document_bytes[:-1] + else: + # this shouldn't happen but maybe an edge case? + pass + + return document_bytes + + def _document_delete(self, document_name_or_id: str, vault: Optional[str] = None, archive=False): + + document_delete_argv = self._document_delete_argv( + document_name_or_id, vault=vault, archive=archive) + try: + # 'op document delete' doesn't have any output if successful + # if it fails, stderr will be in the exception object + self._run_with_auth_check( + self.op_path, self._account_identifier, document_delete_argv) + except OPCmdFailedException as ocfe: + raise OPDocumentDeleteException.from_opexception(ocfe) + + return + def _item_get(self, item_name_or_id, vault=None, fields=None, include_archive=False, decode="utf-8"): item_get_argv = self._item_get_argv( item_name_or_id, vault=vault, fields=fields, include_archive=include_archive) @@ -549,56 +599,6 @@ def _item_get_totp(self, item_name_or_id, vault=None, decode="utf-8"): return output - def _document_get(self, - document_name_or_id: str, - vault: Optional[str] = None, - include_archive: Optional[bool] = False): - """ - Download a document object from a 1Password vault by name or UUID. - - Arguments: - - 'item_name_or_id': The item to look up - Raises: - - OPDocumentGetException if the lookup fails for any reason. - - OPNotFoundException if the 1Password command can't be found. - Returns: - - Bytes: document bytes - """ - - get_document_argv = self._document_get_argv( - document_name_or_id, vault=vault, include_archive=include_archive) - - try: - document_bytes = self._run_with_auth_check( - self.op_path, self._account_identifier, get_document_argv, capture_stdout=True) - except OPCmdFailedException as ocfe: - raise OPDocumentGetException.from_opexception(ocfe) from ocfe - - if self._cli_version <= DOCUMENT_BYTES_BUG_VERSION: # pragma: no cover - # op versions 2.0.0 - 2.2.0 append an erroneous \x0a ('\n') byte to document bytes - # trim it off if its present - if document_bytes[-1] == 0x0a: - document_bytes = document_bytes[:-1] - else: - # this shouldn't happen but maybe an edge case? - pass - - return document_bytes - - def _document_delete(self, document_name_or_id: str, vault: Optional[str] = None, archive=False): - - document_delete_argv = self._document_delete_argv( - document_name_or_id, vault=vault, archive=archive) - try: - # 'op document delete' doesn't have any output if successful - # if it fails, stderr will be in the exception object - self._run_with_auth_check( - self.op_path, self._account_identifier, document_delete_argv) - except OPCmdFailedException as ocfe: - raise OPDocumentDeleteException.from_opexception(ocfe) - - return - @classmethod def _signed_in_accounts(cls, op_path, decode="utf-8"): account_list_argv = cls._account_list_argv(op_path, encoding=decode) From a9e8bfeb6b791da002dea02b0a89bda8527ea7e7 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 20:59:12 -0800 Subject: [PATCH 11/77] add "document edit" to service account support dictionary --- pyonepassword/data/svc_acct_commands/document.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyonepassword/data/svc_acct_commands/document.json b/pyonepassword/data/svc_acct_commands/document.json index f022c0e2..11ecf05f 100644 --- a/pyonepassword/data/svc_acct_commands/document.json +++ b/pyonepassword/data/svc_acct_commands/document.json @@ -17,6 +17,13 @@ "--vault" ], "prohibited_options": [] + }, + "edit": { + "has_arg": true, + "required_options": [ + "--vault" + ], + "prohibited_options": [] } } } From 8d24721ca5ee30de9b6c7c1f803e4ef3b1aabcf9 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 21:01:17 -0800 Subject: [PATCH 12/77] rename input_string kwarg to input in _OPCLIExecute._run() --- pyonepassword/_op_cli.py | 14 +++++++------- pyonepassword/_op_commands.py | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pyonepassword/_op_cli.py b/pyonepassword/_op_cli.py index ed33ad05..d378fb56 100644 --- a/pyonepassword/_op_cli.py +++ b/pyonepassword/_op_cli.py @@ -44,14 +44,14 @@ def _should_log_op_errors(cls) -> bool: return should_log @classmethod - def _run_raw(cls, argv, input_string=None, capture_stdout=False, ignore_error=False, env=environ): + def _run_raw(cls, argv, input=None, capture_stdout=False, ignore_error=False, env=environ): stdout = subprocess.PIPE if capture_stdout else None - if input_string: - if isinstance(input_string, str): - input_string = input_string.encode("utf-8") + if input: + if isinstance(input, str): + input = input.encode("utf-8") _ran = subprocess.run( - argv, input=input_string, stderr=subprocess.PIPE, stdout=stdout, env=env) + argv, input=input, stderr=subprocess.PIPE, stdout=stdout, env=env) stdout = _ran.stdout stderr = _ran.stderr @@ -90,12 +90,12 @@ def _run_raw(cls, argv, input_string=None, capture_stdout=False, ignore_error=Fa return (stdout, stderr, returncode) @classmethod - def _run(cls, argv, capture_stdout=False, input_string=None, decode=None, env=environ): + def _run(cls, argv, capture_stdout=False, input=None, decode=None, env=environ): cls.logger.debug(f"Running: {argv.cmd_str()}") output = None try: output, _, _ = cls._run_raw( - argv, input_string=input_string, capture_stdout=capture_stdout, env=env) + argv, input=input, capture_stdout=capture_stdout, env=env) if decode and output is not None: output = output.decode(decode) except FileNotFoundError as err: diff --git a/pyonepassword/_op_commands.py b/pyonepassword/_op_commands.py index e9bdea55..c3d61bcb 100644 --- a/pyonepassword/_op_commands.py +++ b/pyonepassword/_op_commands.py @@ -372,7 +372,7 @@ def _get_existing_token(self, account: OPAccount): def _run_signin(self, argv, password=None): try: output = self._run(argv, capture_stdout=True, - input_string=password, decode="utf-8") + input=password, decode="utf-8") except OPCmdFailedException as ocfe: raise OPSigninException.from_opexception(ocfe) from ocfe @@ -384,7 +384,7 @@ def _run_with_auth_check(cls, account: str, argv: _OPArgv, capture_stdout: bool = False, - input_string: str = None, + input: Union[str, bytes] = None, decode: str = None, env: Mapping = environ): # this somewhat of a hack to detect if authentication has expired @@ -418,7 +418,7 @@ def _run_with_auth_check(cls, return cls._run(argv, capture_stdout=capture_stdout, - input_string=input_string, + input=input, decode=decode, env=env) @@ -579,7 +579,7 @@ def _item_delete_multiple(self, batch_json, vault, archive=False): # 'op item delete' doesn't have any output if successful # if it fails, stderr will be in the exception object self._run_with_auth_check( - self.op_path, self._account_identifier, item_delete_argv, input_string=batch_json) + self.op_path, self._account_identifier, item_delete_argv, input=batch_json) except OPCmdFailedException as ocfe: # OPItemDeleteException will get turned into # OPItemDeleteMultipleException by the caller, so From 779fd9eba8aa43a5816a2c2f2ac01f038206ada6 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 21:01:46 -0800 Subject: [PATCH 13/77] add OPDocumentEditException --- pyonepassword/py_op_exceptions.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyonepassword/py_op_exceptions.py b/pyonepassword/py_op_exceptions.py index 60e3e1ef..2f6be0e3 100644 --- a/pyonepassword/py_op_exceptions.py +++ b/pyonepassword/py_op_exceptions.py @@ -161,6 +161,13 @@ def __init__(self, stderr_out, returncode): super().__init__(stderr_out, returncode) +class OPDocumentEditException(OPCmdFailedException): + MSG = "1Password 'document edit' failed." + + def __init__(self, stderr_out, returncode): + super().__init__(stderr_out, returncode) + + class OPUserGetException(OPCmdFailedException): MSG = "1Password 'get user' failed." From 238681fe511337c3edaa581b554165a35db951bd Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 21:02:33 -0800 Subject: [PATCH 14/77] add document editing methods to _OPCommandInterface --- pyonepassword/_op_commands.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pyonepassword/_op_commands.py b/pyonepassword/_op_commands.py index c3d61bcb..ee715a48 100644 --- a/pyonepassword/_op_commands.py +++ b/pyonepassword/_op_commands.py @@ -32,6 +32,7 @@ OPCmdFailedException, OPCmdMalformedSvcAcctTokenException, OPDocumentDeleteException, + OPDocumentEditException, OPDocumentGetException, OPGroupGetException, OPGroupListException, @@ -531,6 +532,20 @@ def _document_get(self, return document_bytes + def _document_edit(self, document_identifier: str, document_bytes: bytes, vault: Optional[str] = None): + + document_edit_argv = self._document_edit_argv( + document_identifier, vault=vault) + try: + # 'op document edit' doesn't have any output if successful + # if it fails, stderr will be in the exception object + self._run_with_auth_check( + self.op_path, self._account_identifier, document_edit_argv, input=document_bytes) + except OPCmdFailedException as ocfe: + raise OPDocumentEditException.from_opexception(ocfe) + + return + def _document_delete(self, document_name_or_id: str, vault: Optional[str] = None, archive=False): document_delete_argv = self._document_delete_argv( @@ -805,6 +820,17 @@ def _document_get_argv(self, return document_get_argv + def _document_edit_argv(self, + document_identifier: str, + vault: Optional[str] = None): + vault_arg = vault if vault else self.vault + document_edit_argv = _OPArgv.document_edit_argv(self.op_path, + document_identifier, + vault=vault_arg) + print(document_edit_argv) + + return document_edit_argv + def _document_delete_argv(self, document_name_or_id: str, vault: Optional[str] = None, archive=False): vault_arg = vault if vault else self.vault From 2ea50b256361366059b6b69f74207b2e1c6bddab Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 21:04:15 -0800 Subject: [PATCH 15/77] add `OP.document_edit()` --- pyonepassword/pyonepassword.py | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/pyonepassword/pyonepassword.py b/pyonepassword/pyonepassword.py index fe889006..59d32284 100644 --- a/pyonepassword/pyonepassword.py +++ b/pyonepassword/pyonepassword.py @@ -3,6 +3,7 @@ import fnmatch import logging from os import environ as env +from pathlib import Path from typing import TYPE_CHECKING, List, Optional, Type, Union if TYPE_CHECKING: # pragma: no coverage @@ -45,6 +46,7 @@ from .py_op_exceptions import ( OPCmdFailedException, OPDocumentDeleteException, + OPDocumentEditException, OPDocumentGetException, OPFieldExistsException, OPForgetException, @@ -172,6 +174,70 @@ def document_get(self, document_name_or_id, vault=None, include_archive=False, r return (file_name, document_bytes) + def document_edit(self, + document_identifier: str, + file_path: Union[str, Path], + vault: Optional[str] = None, + relaxed_validation: bool = False) -> str: + """ + Edit a document object based on document name or unique identifier + + Parameters + ---------- + document_identifier : str + Name or identifier of the document to edit + file_path: Union[str, Path], + Path to the file to replace the current document with + vault : str, optional + The name or ID of a vault to override the default vault, by default None + relaxed_validation: bool, optional + Whether to enable relaxed item validation for this query, in order to parse non-conformant data + by default False + Returns + ------- + document_id: str + Unique identifier of the item edited + + Raises + ------ + OPDocumentEditException + - If the document to be edit is not found + - If there is more than one item matching 'document_identifier' + - If the edit operation fails for any other reason + + Service Account Support + ----------------------- + Supported + required keyword arguments: vault + """ + + file_path = Path(file_path) + document_bytes = file_path.read_bytes() + + # to satisfy mypy + generic_item_class: Type[_OPGenericItem] + if relaxed_validation: + generic_item_class = _OPGenericItemRelaxedValidation + else: + generic_item_class = _OPGenericItem + + try: + output = self._item_get(document_identifier, vault=vault) + item = generic_item_class(output) + except OPItemGetException as e: + raise OPDocumentEditException.from_opexception(e) + # we want to return the explicit ID even if we were + # given an document name or other identifier + # that way the caller knows exactly what got deleted + # can match it up with what they expected to be deleted, if desired + document_id = item.unique_id + + # 'op document edit' doesn't have any stdout, so we're not + # capturing any here + self._document_edit(document_id, document_bytes, vault=vault) + + return document_id + def document_delete(self, document_identifier: str, vault: Optional[str] = None, archive: bool = False, relaxed_validation: bool = False) -> str: """ Delete a document object based on document name or unique identifier From c3d1101a40eea5ed64a520cb7f535b66d64bbd04 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 21:04:52 -0800 Subject: [PATCH 16/77] add get_op() to ipython_snippets functions library --- ipython_snippets/_util/functions.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ipython_snippets/_util/functions.py b/ipython_snippets/_util/functions.py index 0f2003d9..0a8ff6df 100644 --- a/ipython_snippets/_util/functions.py +++ b/ipython_snippets/_util/functions.py @@ -1,5 +1,8 @@ import pathlib +from pyonepassword import OP +from pyonepassword.logging import console_debug_logger + def snippet_dir(): main_file = pathlib.Path(__file__) @@ -12,3 +15,9 @@ def scratch_dir(): scratch = pathlib.Path(main_dir, "scratch") scratch.mkdir(exist_ok=True) return scratch + + +def get_op(logger_name): + logger = console_debug_logger(logger_name) + op = OP(logger=logger) + return op From c62f84acc9de88bc8fefc916dc6932cc31487ccd Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 21:07:01 -0800 Subject: [PATCH 17/77] delete item-editing-todo.md --- item-editing-todo.md | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 item-editing-todo.md diff --git a/item-editing-todo.md b/item-editing-todo.md deleted file mode 100644 index 9dafca28..00000000 --- a/item-editing-todo.md +++ /dev/null @@ -1,31 +0,0 @@ - -github issue: [143](https://github.com/zcutlip/pyonepassword/issues/143) - -- [x] `OP.item_edit_generate_password()` - - [x] implemented - - [x] tested -- [x] `OP.item_edit_set_password()` - - [x] implemented - - [x] tested -- [x] `OP.item_edit_set_title()` - - [x] implemented - - [x] tested -- [x] `OP.item_edit_set_favorite()` - - [x] implemented - - [x] tested -- [x] `OP.item_edit_set_tags()` - - [x] implemented - - [x] tested -- [x] `OP.item_edit_set_url()` - - [x] implemented - - [x] tested -- [x] Set field types: - - [x] password - - [x] implemented - - [x] tested - - [ ] text - - [ ] implemented - - [ ] tested - - [ ] url - - [ ] implemented - - [ ] tested From 5fca6475266ebec6bf18db87536e825c75fbaf4f Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 7 Nov 2023 21:08:07 -0800 Subject: [PATCH 18/77] add document editing snippet for ipython --- ipython_snippets/document_edit.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 ipython_snippets/document_edit.py diff --git a/ipython_snippets/document_edit.py b/ipython_snippets/document_edit.py new file mode 100644 index 00000000..7981a813 --- /dev/null +++ b/ipython_snippets/document_edit.py @@ -0,0 +1,11 @@ +from _util.functions import get_op +from dotenv import load_dotenv + +from pyonepassword.api.exceptions import OPCmdFailedException # noqa: F401 + +load_dotenv("./dot_env_files/.env_pyonepassword_test_rw") + +print("run: op = get_op(\"document-edit\")") + +vault = "Test Data 1" +document_name = "screenshot.png" From 52a4801868ddc85a3358623a88bd8a4f656624d7 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Fri, 10 Nov 2023 19:16:45 -0800 Subject: [PATCH 19/77] remove extraneious print statements --- pyonepassword/_op_commands.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyonepassword/_op_commands.py b/pyonepassword/_op_commands.py index ee715a48..13b7bccf 100644 --- a/pyonepassword/_op_commands.py +++ b/pyonepassword/_op_commands.py @@ -816,7 +816,6 @@ def _document_get_argv(self, document_name_or_id, vault=vault_arg, include_archive=include_archive) - print(document_get_argv) return document_get_argv @@ -827,7 +826,6 @@ def _document_edit_argv(self, document_edit_argv = _OPArgv.document_edit_argv(self.op_path, document_identifier, vault=vault_arg) - print(document_edit_argv) return document_edit_argv From d019f9c5d9e132d90a6376200dad375668602fc8 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 14 Nov 2023 22:22:16 -0800 Subject: [PATCH 20/77] add binary input data for tests --- .../test-input-data/binary-data-registry.json | 6 ++++++ .../binary-data/images/image_01.png | Bin 0 -> 1830 bytes .../binary-data/images/image_02.png | Bin 0 -> 1959 bytes .../binary-data/images/image_03.png | Bin 0 -> 1982 bytes .../binary-data/images/image_04.png | Bin 0 -> 1875 bytes .../binary-data/images/image_05.png | Bin 0 -> 1962 bytes .../binary-data/images/image_06.png | Bin 0 -> 2014 bytes .../binary-data/images/image_07.png | Bin 0 -> 1905 bytes .../binary-data/images/image_08.png | Bin 0 -> 1990 bytes .../binary-data/images/image_09.png | Bin 0 -> 2016 bytes .../binary-data/images/image_10.png | Bin 0 -> 1862 bytes .../binary-data/images/registry.json | 6 ++++++ .../binary-data/images/replacement_image_01.png | Bin 0 -> 2462 bytes .../binary-data/images/replacement_image_02.png | Bin 0 -> 2602 bytes .../binary-data/images/replacement_image_03.png | Bin 0 -> 2626 bytes .../binary-data/images/replacement_image_04.png | Bin 0 -> 2502 bytes .../binary-data/images/replacement_image_05.png | Bin 0 -> 2612 bytes .../binary-data/images/replacement_image_06.png | Bin 0 -> 2650 bytes .../binary-data/images/replacement_image_07.png | Bin 0 -> 2554 bytes .../binary-data/images/replacement_image_08.png | Bin 0 -> 2638 bytes .../binary-data/images/replacement_image_09.png | Bin 0 -> 2655 bytes .../binary-data/images/replacement_image_10.png | Bin 0 -> 2509 bytes 22 files changed, 12 insertions(+) create mode 100644 tests/data/test-input-data/binary-data-registry.json create mode 100644 tests/data/test-input-data/binary-data/images/image_01.png create mode 100644 tests/data/test-input-data/binary-data/images/image_02.png create mode 100644 tests/data/test-input-data/binary-data/images/image_03.png create mode 100644 tests/data/test-input-data/binary-data/images/image_04.png create mode 100644 tests/data/test-input-data/binary-data/images/image_05.png create mode 100644 tests/data/test-input-data/binary-data/images/image_06.png create mode 100644 tests/data/test-input-data/binary-data/images/image_07.png create mode 100644 tests/data/test-input-data/binary-data/images/image_08.png create mode 100644 tests/data/test-input-data/binary-data/images/image_09.png create mode 100644 tests/data/test-input-data/binary-data/images/image_10.png create mode 100644 tests/data/test-input-data/binary-data/images/registry.json create mode 100644 tests/data/test-input-data/binary-data/images/replacement_image_01.png create mode 100644 tests/data/test-input-data/binary-data/images/replacement_image_02.png create mode 100644 tests/data/test-input-data/binary-data/images/replacement_image_03.png create mode 100644 tests/data/test-input-data/binary-data/images/replacement_image_04.png create mode 100644 tests/data/test-input-data/binary-data/images/replacement_image_05.png create mode 100644 tests/data/test-input-data/binary-data/images/replacement_image_06.png create mode 100644 tests/data/test-input-data/binary-data/images/replacement_image_07.png create mode 100644 tests/data/test-input-data/binary-data/images/replacement_image_08.png create mode 100644 tests/data/test-input-data/binary-data/images/replacement_image_09.png create mode 100644 tests/data/test-input-data/binary-data/images/replacement_image_10.png diff --git a/tests/data/test-input-data/binary-data-registry.json b/tests/data/test-input-data/binary-data-registry.json new file mode 100644 index 00000000..57235eaf --- /dev/null +++ b/tests/data/test-input-data/binary-data-registry.json @@ -0,0 +1,6 @@ +{ + "binary-image-data": { + "name": "images", + "type": "registry" + } +} diff --git a/tests/data/test-input-data/binary-data/images/image_01.png b/tests/data/test-input-data/binary-data/images/image_01.png new file mode 100644 index 0000000000000000000000000000000000000000..fca5a57662d6d27ae7226924d577a285969ae415 GIT binary patch literal 1830 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 literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/image_03.png b/tests/data/test-input-data/binary-data/images/image_03.png new file mode 100644 index 0000000000000000000000000000000000000000..ff701af8382e97f6d144296bc6ab1321c6d335dc GIT binary patch literal 1982 zcmaKtdo=5T}sqj5>{(0AW|2Sv=@qG8*&-$#r*V@lsPolGvtu$Gg zOb~=L-EOZ7L5QV@e5S-I(V4U1CmWGy9Jh0EB#6`B5kzz>L3|OVqQ?m$ghCL)qXc1= zNf1gwSNI2Z5d`UovxBP*2m(Gn5Ls0fVsR0} z!`QeHPo7|Y9^KuTnSqfJ=yZJjig)iI5a8oSOih78L3lV^T~SvDIXOs5A}0rfgIK*9 zn>HaX4(ryTs0btyw6(Fag1I@YUyoI*(AS4UhY%c$)>e?ou(CpIEN8>Xgs{~l}CVsa9D_Tb7DczPl?7ZVe>cMn&u!rvdCKHpnl)%di?(W#P53{of4TXULmX;70h{{TQ_<)QINJ+uk z8q?EYFtB|)_Q$$vAm3=B;33S2?<=fggbX|_%NP5Lt`U`hQQ$< zCI*FtIDHzgUct=`Terf{5bEl1c1A-3xLjCRfW<;W0;HwU+Y5Vp&}h)oLU}pv-^Z?9 z*t{9fpF=?b(b4er1(k|5YjF88G&KFs?tU#KWzKk*vduEWu6A z_A&DxMg+1AA0Mp~WW^hryq`*vlmA=mB2FdbT(gp_R4}J^e80d9^~Gtg65@ai2YtC={rC-q!Jt(NxrBxjERe&bFz zx-X-S>Z*6Yaf^Mq>oo7-{m8)8miV?xy>t&AR$?R{H!4GZ^Pj%sq_@>4}`A z9nGIuc>X|=*|)YoJf=&K7b;bLP&GovZk9$k3K>-;iqx})${`y5Bp<wmAWrk4K646=ATZH_ITgmvTe_>!_GB$CYh$nEQWeKpuKA~NFC1YHE(liQqoDu zP@7vwoRb}`_Q^7CD1D&ed~6`{AJLIt9mB?~Qg^?ostH>q-ruCtpczbAs&})fA=MM5Xp&+mcck0A!cN8` z=E9Z$@OV25jtU*+yP6@BlhI1xc$!~g{S|`>U9E$mupY4rnQ!f5? z%BDljLs6O=zyC3Jr)Tzm|J?>bfF7J3#AG$U9 z&?Mc$VE>cPYL*%H1JV~5w5|@hvr}oKT`o&Z(R>r@;`GE6qE<9xUl%Ev^Xi1wm(Hqw zeSCf}(P;F^DD$dR$&BN=>$aAIe2#p3r*(KcH_SlML~f$?(p&nMlIC9Cz|2T|rN1B~ z;NFptmT~oxt|rTPe&IL#@SQ#BH4ho@%23_b7v$5*<(P~}KBq)V7N~p}8W}p-7TkB) zs*~-or0)`;yb763iY~^Usb>OCZ6fU`EQ<|zP19QYpL31w4*wSayVdO43ep$t2E$To zS<%NvXmV{lxJ)lD%j|eCOC*Fb#n?pO$VlIa>Pj&-qi#1dGSa0`%qSFvoNWgG2e1Q~ zzTOdk4IFQ|kR}4O|5t(Q%Vu%7UhJU1X0{EK{MnVvpG<()F;)QK%l10K(x8}pj?fJf P-4Jver@f_CNB{c=_)+I} literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/image_04.png b/tests/data/test-input-data/binary-data/images/image_04.png new file mode 100644 index 0000000000000000000000000000000000000000..6e33a2d1f41c850da7111108860f6c93e7467594 GIT binary patch literal 1875 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 literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/image_06.png b/tests/data/test-input-data/binary-data/images/image_06.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf048d25abd77c9589afad1d940f6c7bb5da49f GIT binary patch literal 2014 zcmaKtc{J1u8^?b}8A~Ed%UH5pOUjtBmIf7*5jwr0NGf3%3|%ISvgB6QqQ#PA+^&=* zTk6VEi8RVmN}?=j;ZjJu%Jds2!Kd6HCVI=85tNJ#_TL!zeavOG&CS41|J`^w&MMJeEy8CE`)?Y zTpUlH;L|5Oc!23?(CLtnKy@{K{zOj?u3Q0$1R4!dQE+udSsAWhhrB$bq#zKWzaR7F zAvqa_hOoEC%nbbeps$a)Ieh#GMMXS%1W!+>s^Y)_w6x&xVO+e3eftm|jBHZ~9nVQPw7w~&*A zp&`6|i>p^rUk@%9=H{51!nJE~bVObrCMK|B2Y&w@fBl8#W}G{RpdftsfG=M#IEchV zI5}a-5-2HQWCSNqqPrU#H-b#Y<;(E)#`f)4za9}0pi=SU2SP(}`ZQ!@U~7wa@8IEq z)vMv)fP@6BT7{Sxw6)>XDWs&JxEPX>7#KiiCjR^rUS8|3k&G!VZj3E>Y}m|#>QYUprV53 z&!M0IUth$>gTuk(B<9aYb~eVxp`(MiILOIi*)nu?V)0_6rNP7m3m4+T1sE8hstPx5 z;P!3Yy9Z58goUBD7LAQ?b3=POnws$NAu1{$Ee#e6xw*K1AL;2}G7%Vv$Vi>>((j^; z6x-`)Z$~7}S7V71GS9)8NgkDvBU#FL^o4IAh&2j-5-0LzvFR!dB9k z$ENAMkwJ9>J!>A=nfY##`0>d2#2PQMNws{fp_H(*s-7|0)^T=?CZFvcaijfADu2E~ zt(wCTE#{q^&`7?;<&%3jXDHqGe@$c^x$kyfj(Y1{grL`Xg1XA|<$zG3xJ65G)vmDg zfzj6twwy;w!-3M0#v6VkyLKqm6~k%0=cZe0Q`LVn`i*$h7ILxNkqH%b zYMo|>cGTmvWA573i_`nOvcf%N`3KcXY;Vo#4aX=vEwJHBvpyS=$M3mT(vt#rOI|I~ zWI87~J)6g{%GXU}n^=nnXBo1b2l}g51f3nYv*tvPysy%xi3q!fwcW4#G$_p67rnd3 zI`_U+;G{}Kj` zpS_cXbGIDXO|gYZ4QUZpQ?X2oS8l2_fvR1XdoB^?b4tHxIf)W|ZU1&viCtGjBdns# z)a6f!wFk9CxR%^Bsq09vm@ZO^a%#3aK6W&?$x}B+@y@e9I6I^C%#*dg=x>R3>MGq5 z63OrMF)Q5O)$@~GrJnxM%Zew+iL2h$IH;EGGM3snvcLG~C7A-ht1l=+4ZXuP?ki@y z2v6tf{LJ(@a;fIj#PwP84(&`%QvKFUBL69mosu& z_s4(JdrR%&k4$RXkQ}yC?cXZ~w%GM#|9I-Jem8bu(^_L<=R5VTaPtLV=`r3siJ*(e z+&p}UQC}KfP%C@lO{s19tKDnMkF=}Ld4?8QT;^+6e@d7eYW_55W8fL;WEy4FW>)i{ zf3m_*|4VuO%*BB_&aw7oL%+7M$p_bV)QZLR#TXQN-4)XJYg;CF{t+RN=9JzZn^+SESK{HQQ91{Irf^cANwkzMTC*g1QRQHkq literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/image_07.png b/tests/data/test-input-data/binary-data/images/image_07.png new file mode 100644 index 0000000000000000000000000000000000000000..4060379e278ee2653ef3ef2943e6cc427362160c GIT binary patch literal 1905 zcmaKtc{J6F7RP_4lnfz5rl?36I%dul$&fitlyaqG3OR=kB3)D0E6L)xMTBtgMJkzx zOt)wm5^`&ql~*z!nU&J_o%_#Q>;2LD{;|jPS^J;8_P*g@e@uW+ijN=&0V_*03PEr% z*|FDFF1F1POEYIXc~47<9YI7W5kyQJL2R%~F;fH)N+O7va|A(7CkTn4tU5TL*fsY???;hmkF){)(GxYUgbrr8(VPOFp8Za;biG=WQ zI62|bBRqM69XqgX8**|mGz4yL?A!@)alCketSl%ipmqSGbU%$f85CH*@l|^nYrlzpAhMpd{xPXHLZ{FbZXG~5aBLnvKc>EaS zv1p}QN^)zH#{pdj+|aqu9@%FxsV1_OOZT<;bC*kjELuvwPYu}Ay#(gyp!97ILX^j4+bA42(ED}GZUxq zA=bd`DJN&iEel=0YW(c+yn&niC;z!LF)1z4#BIJOJ$L$BXj)uNyCck-XB(VgCSY^( z5x*VffK6HXRMP0&T5{F;m2T1o)o8$@cr;~lJvJ;yD>E#+tD<}GyhB3#|J9Td^Vg9M zKW$c;p?j1`-Y#)!b8&V5q`@t*_DYY>g?DnjuGOhChXYD_f_=L09zGB`F}6l=)|FW1 zBxf-$w*8`7+SqX5;U1UM`8KOZM+`2~h35}eM7o{m8+B1#l^e-43U#*&y20vPk{>ip z^XS{G$_pCjaIUE|s+)U8`Qm%o)boV*VnQlo!GYfXm;YKz_;Z<^Mp75fY`QG#(B#@g zDXyhTk^X9ZgJ-iOp2Vt#i{vSnM#(lG=O~`IRT%rNT{E}W@TM-eaDrK{e5`hjf>Gq& z1=|8UeikK%=S8+wS3JGEQU4Hw%jDwqnUTcsaGRI9bvH7IHx;E((x>@F(iK)oSH-IPC#>l5C7FwK{phYP$ydh7D;;rq z3k7`p6iLhP|Ku`A@MJioJ$0SdHELk-i_kTzGDfrMankL%yJjc5ekzb_t1nn-T>pOK zn&DXO2BG7odBu{KA);Sp{ds{}*Cmy8l75qVB6**N!Mnf$89iq5OBd*TOtt1Ll73bH z6D389%xv)u_BqrWo7MG;P*1=fbIIQx=&c49=(ZSpT=9E*TZfsPa<~5D%6|V6K`+T7 z{|wqZld`TpILwi<85gOAPR$0Cu5c~7MHJOYcM_z_PlAyr=eU0h(C@iXGk|IAk z5&Xt_^hQ*Xd-^)(hEO@rQvUM$e0yDwB#MBGg6NE$d{wRLdMD#~=W807sh#}b@d+`j)M3qZPXhk-)tUEsl7D^Z| z@QW=OT6?Mh0B9L?DC z57xgfJNF%N`kLzK{{7J5y^ez|(Xy)Ba{S)KxcM|M1ePh`6IXV>E;&r6N3U*RbiU_< z(D3$5De*-pKxi|inBuxv$g)xRaIh5=|8edJR7W20dX$(q@v7OnQed!2gps(Z^>#L= zKeA&jbcgVd)!Q}hZqZos{Z?adw^J$Lm#hnLBJ literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/image_08.png b/tests/data/test-input-data/binary-data/images/image_08.png new file mode 100644 index 0000000000000000000000000000000000000000..5e235c1eafcf85bb391ad8826332d06d463857ed GIT binary patch literal 1990 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 literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/registry.json b/tests/data/test-input-data/binary-data/images/registry.json new file mode 100644 index 00000000..9c5a0132 --- /dev/null +++ b/tests/data/test-input-data/binary-data/images/registry.json @@ -0,0 +1,6 @@ +{ + "replacement-image-01": { + "name": "replacement_image_01.png", + "type": "binary" + } +} diff --git a/tests/data/test-input-data/binary-data/images/replacement_image_01.png b/tests/data/test-input-data/binary-data/images/replacement_image_01.png new file mode 100644 index 0000000000000000000000000000000000000000..f83a90b299d5ca05bd9e1690536837eb9c2ab534 GIT binary patch literal 2462 zcmaKuX*ktsAIJaptchePoYY8`)1fRQr(`<^Z5+y4Sq{!bwqp`mN5iy8NfCxjBuhn$ zee0maq(sSDqlSpGNBBNx-aOa!yqM?v;=FJCN82NLJ)+wCEd)H zAb66vwdX26Zp@OoYR*k054!C>f(TP3i0C+iSmYi>j}Sx%g&;?s%p`qaF=1q`D5EO)u4<0bRxZVv73 zaBx6pCx(ZSmWI=(AuEfaAzZwOD_5|4H+JkmeLejApr;2dc=HAx9yop+d-pZFy6k!u3cas-H{;$t=;*-6 z2vSlI69bEd(NX;H0|W#R6@}-|At8Yc8}R56Hf=(9IJR#`Z7tH%(a?aPAe5J*rUtF8 zpwn^vI?T)1#Gwvwn3tv`*biw)jEOO1hWV$rx(*-Uy`=!>0z?S3jT7na&Iu;5=7~ zBdPpfjZRg*kC{_fl6Cf`LqjhT;A81IFV-(eeQn$vSEB3-BbCbU8|$BK*x54 ziP|*@Bi^nfs|ADnjf@M8-7Cd?k_-5>)vUynVsDf*FHk5+;hw8+UJ$!@PI+T`+@(-@ zrfMQDU&Y~Zsiz#d;$H1gvz48C!Y!OwjU;V3{asB|x12t=ExCEQyA6-HW}H92m2r!? zKT6YfhtTB|>L#sSVSj5<)rTkhs%PGM%$E4Ml>N9MFz|Sb*@q7mr>6g={kYSp;#dcR zbz4;Wj9RReM}NYADX;9keaq~Nyz?_W?Z+-1WikAX3VWOAmqBg_w!S9dOlqw$E}@;@ zW??xfQ$HQnUur!aR`-r`j(Lc*jpzND>1g@Un6IVlb3baVDYH`QeNr=}E;1F}b^M*H zaFI-+#5CtpnnbmpL-p_CdlkEv^gIQnvZMV*Lju**+Dsow+zeqc)YaKlMAD7A5{HCr z(Z<6Sk(_ju&C=%fCcb-{RUeY`Pg_SmyIj&Jc9VCajQQoy+>vdK8MbXR32|bf(uzYl zg-utB)h16^OZEDSLGA#b4T^pmQ$JTjlTKDzPbA*Luq9t^#Max zF9c$L>Z(1b5K$|;v$L{seEa@GsWG4LQnRC~m22V*qW3I*pt9$cMrLT`@e!p7f|A&uMJqh-n>3-1E$d-Ho(L#m^kG3bOK8@(ZcX zw2MUtFV+UhWv!ar`e-b96K&J-6Z?W8b-8mTGP8+~gJ&(NiTxWTy<=W8o_LMc#~Iw= zElJU0NJ)_$f)h8cf zvx{77H_kdA%+A+795tuN8@Tq~z6gGCX63x2d_v8Gt-`}`jw)N|eDe9%r+rE+@3bCn zK2Xe5bmy(CYqI$A#gjDG zk+(LZtGKUon_w`>=1*lcrjD0_(95a1TYN3X<4JzQwX#AV3$8S^2&J_|Wq45eelEXj z>~tXWmmdCp=jC6!t<%Ha3H6hkcdTiPNw6r=Bl}jb)p*m?{jktw)yo(ca?1CzQWt8e zy4zBU$E%#cm7$C=`FzeYzkB*(&~K9>DvO2G#zQ@9^BOWeye;12h2Z6js>^R%O)PU< zWUsA6-jmqZ?EKnxXq=XjdZSYIlYfIrCy5i4u|3IH@qE{6zsQ26qoldp_b&|gcUP!O zIRiR@K0L-sr4}`73nLXg5|1>2Tp9L z)s%{~m^_8R=f=Dt6g(JvJX+9QCE%X5c+KhPJUuYv%8HV^hF{v*qqGFAH<#S)B|3~7 z7mY$&8PV&N9+E2te$8`vca~BYza$v9ysII8_e^-}aswf|0Fv;3IBY&XAve`j{QDdv8m2!($bUpIHAFA>BH@OATG`Y}(iNi07% YZzhSN9qTC_#&r>v=KIa=m>i4!52~KjVgLXD literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/replacement_image_02.png b/tests/data/test-input-data/binary-data/images/replacement_image_02.png new file mode 100644 index 0000000000000000000000000000000000000000..7dc5555605727bad7eddc63abf83e2a761617097 GIT binary patch literal 2602 zcma);c~s3?8^?c@(msB$Ycl#V%IKQzYZxWWMtsoJIu_WzaNE#(ALI<3+U~| z*ck5Kg_|4r_z)3+i3vzb;^j*`dxkGxK%>FK1Jl!JYs1J0goQz+!pR9&uj2M?h=}0q zS#)<}(IT8Yi5)xO>kD;t%+KTdcgV;v(NT<#qp1n@_9!dEhYv_g zgS;Oq<=8~FJ_ObnYh!`&UKs_^lFg#|WlM0hwfH6bK~ z(o!&)aCJpj7dC7Fn++{3goMD*5ZT$dc@thXlTIN zwMa<7rAugU$FgNmQ9)Q3%F7WIg`pv=SOIZyw6?<57Fk*N;}1|MxN`@JikO{+wKWV3 z(9!}WB_t)`!2?{o209(<)%3 zi;|8g%`}{ZEI;xq>_HM zT385ithX?PK8Z>28;iMjg>51TK{IRfjZTr>Bb~FJvd;2CU-}FjSefP>q|E-JqTjW= zcT20U4J;z7CyN~Qb<9;$50cIGNId9rBtlbGM@DR0o8#t+yle|!woCU!$Y8#XUqY8V zJ*LwuvT*8K^BIMf{eH1LZdfL5lkoCn$^R)AJBCwc?>HNiud%qMg5T|)Crk;QNfaXO zGFdLMSpVP>g`p?&)A=3zG>OXOeV-?s$O3gt1(k$UDeu*-ivpZsJwuOVr}u9M}{>KQ8ZH#vq064o-~lB^R{ca{7^ zb#48oju{uS1nY|OiE&}p8mkCA@>gBi+F!=TEC4eX zqxe>N{Tf+zovT2A&)d-EQc7V&??F*lvNnHh!_kBvy@_A4Nd4IXOwR{5Cx&&=I9#s@nF#6pj>$2$Y z)oEA7%GoC2MUN{ehexWIYC3kEm8UB9DRh21@X#?qej&k{xBey$wW~Ceh0R?(tm|Ke z9usQhrjgv*ivQHM65QP|y=3Ua{Kn5xu@wh*nf&QYP8pJDHeDvYH6w-QF=}TKH?=SF zRLGdnrBs$>eckcs_eS0&k_Wv=-ss z;Wj(${^3^e5G{IY%Oi3A7MjbUZ)N?X!&<3HKSRe4%Rgo2GB*_r&EMDJr^!AmsFu={ z3!P-Bq~5(QeZ&xbkE^OQ=Y@^y2#>vyYl8h;w zSiUxc+OgCo_c*EB!VsSxn$fqJ`gRnTPg7nRxiI^d(i>t6&Yx9T&7owpl(bmJX60)h zSU%JGh=|dAkliF*XD~c&vtroRiF{QdvpYf4wQv8<>)i0;B7F3Ww$KCk#pSTAi{5qg zcUH&b&Kk2!*KZlHCs%JT$?;Do2Xb$v4A@XQ>ihU3%yuXTRPOnFgy$I(k|0~8XMM~_ zo$@}G_HZg`%dYmqzwWjd9_T#t!#gT5QtabU#^Bu+`P32-k12t6=YF2R^RvdTvm=d` zhs`*}*&aSei{$(mZb2KTN2_@zG3g1qCz%dPJpES{HXCBAzAlSOWAtb+$m3F0?;>7| zX%hzWCPB61PC4HNY_z%MI)c6ai8JM1GO7XHylyX2k?BPGM9aMI%gGZl63?^4&m3JY z)0viM)t4RDIP)h{v683s`n6f7FGV@q|6Zy5^HcnmwgG&5j$fY2*cpFrr=Q_?UQBSm zcDVb^5o)Q<)qh_v`az$k^!BzVIk@CwG^6wv<;-+efi3qp`;=n3V%N{s@W$tRJG7ax z=FwygOnqP6JhEzBv|&~{`a;i+DWNdZ{VTzGd5K$tZwF@^v>p<#)qE1y80F@-xV~BL;)s}RJx8PjiyP{ zbE49X^$d+^Gzyh!Or=Vn)z$hhASlGg-*^8%1FZYUvK9dK|3u*U2eHFA%%DC0%;|hSrKZxnaCR6E3L7VO^oFc3l_U2`qeoy=x|Jf8C literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/replacement_image_03.png b/tests/data/test-input-data/binary-data/images/replacement_image_03.png new file mode 100644 index 0000000000000000000000000000000000000000..614e2d02699a0024297a348a07ade932bf6477ef GIT binary patch literal 2626 zcmb7`X*AW_8^?bc;t+*U##4wQ9b>Li#*mUZN2B53#EFZfB$OLza@~v(skoV^3L#{c z5Hf|3YbZk^34QOmZ~kljU)&e>S$jRt-h1uO`mVj6XYKu5H#0Tl;S%8@2!hAhNZ*1W z)8HNXn=zQe0*SNi1+W&*a&H9#KvN95KBvV`V{W&2nxdX?a0f+moKQV$H|j0 zHAQwdK7PdQ+mMw-bTkSIprr+IaU>^Wd>r4t!PXWX9T*!!TpTW4g0L_~MsVj2Hg3e- zyV$=Us;a1{z>61PFrcoEnHhZg1RWj3#9(m|0|N*R#oQdKs<5(xloTW;!rUCMUt?kd zmX=6JfSny4Jix10=<0%_Bi!6@=n$Hl(borSYaBcX7Z-4ILr)J=Q=n3@bt?`WfUhrh z?gR%1va(=rkE2J?(}R8cK%+rX5gs1U&_GEEL_`o3h3C(4;skc>!XJNNbrs>^P*6ZX z0Gyri z^71Gx#qQk@6~)!7sH;P5Epl_QcQ5$)L8n7a4KgxdXGdTl-n_x%$Kd6Km>8ZtgOn8f z{h^|Q@^aj}hg-K$S&5<|G&RA<2=VdI*GGCf1O?$%u5z7O#A_T(4E2dHc5x%-g2Tu7 zumQ&y_j(phZfcLWEE z~qow8oX5RJGj4Yccjt8?oTM3*Gy>Jw0}#x=CAyN_OdQCS*<-fs-`+`I_RY0 z_N0Q`XzjT<7pJtkjdIJ5LtoARdK9;--mSSvvA|ilnE#Yh^mgypHQo;w#81ZWUK;(J zxg>KlO1Cw?q)Ds#d64tu(Go#w+M>T8cj+T*pvE>;Pxtt~b+?N#ox}s#kGi$9n z*(Q?CDdN4NaEF8>A#);4a})PXVI=_52f7hSfL-))TRmh*iGdiXSl zdgk|5*L$lZwmyR;zDcK5!k7D00!LJ%ms*70Lg;8+XzL$&uf})DOSN|Ti|zZXYdJ_N zg(0@Djr)jTR8MUGNwVge<_<&i9obXnTQ}S)JXq$!=c6ZasYj_?@pku_!sefB`NyM^ zhE=G%o{s#Bqux}~PQ9xoPQUfintr`h*&Wj@BY#U)VPGV^`kdNE72jlI*}aA~@t*mK z+Vd=oG~bVn6`S_Ru(TOv#Co<0ghd{DsKroxe`@nofn;!f+N!Fjb4hhbPVufmxup9# z_gyTX&-D1K?_am6%64=4!n#F?^QNkEqq^CAdX$r04@}PmI`0V{XH&J@z4hdUhhZbZ zu8*ySM)q3Da2+e`+PdSF>q7*P`BI94Y@T_ZD!1IXD#3AATjB7f8wLTx2Gd-DmqoQ+ zmDQ~#$G7#3q_yydFYjY*Be|wdv)_BW%)ee=J}dIN26gW6s@Dx)5xYR$%G)AFK7AbF z%NEJUt7mg$SsQd#D-y>z3Z&jgS;?NNw<@ihSefss%+c;OJrQb0|@zpft3J)}UjHv2i+oqxJ? zQKKxWT=Tm?nDb-?t&uN;A>bc&z-}~NL(%iwjhZ~$vbKoO8R4oHt>(F&COs-?u||4u zy?P4u7aEU+>Hg32>)Oh!O4+?9BSy4LCBt%Fz-CT93 z`I4b9a2h>Bl6dzOl5K24oEMcUGM}9y7B=gucFgw$IGQUo`Ic zQnKjFE@eYWSsP}m2ZM7DI~VOx4&LKCWO7%&{1>jG+K$DDA?$D zk^NP-FTosZht(F!yz{beM2XfEQ>FT=MwjeU>&+*913&#dWBH}+>wy<5fnUB0l_pd% z9(rtvVDliKyWWUrqLkY4VA9x;}7aBgl-XwJAoAEs) zxk^#a7j0=Nwec1gYsQ!V!|Qz|B#`)hs^eVFH=AhYpCjXAVC&;#??cmc^rA5Xp-fR$ z*{P(oQ%TK=qO7T=p{b-KPoZd1DEvvPivI^NJe=sx7ycb^thyP=1mymw;6rE7ynXB$ zp8w9Mc4aZ!JVN9j#@*h5=1zFgJl*XbX$;y~A2OX`??NL}RNT*a*)UHL#s;SP*}A8% F{0$ERH2MGl literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/replacement_image_04.png b/tests/data/test-input-data/binary-data/images/replacement_image_04.png new file mode 100644 index 0000000000000000000000000000000000000000..4162f83b866f1b483bf25c5007dcd6044358b450 GIT binary patch literal 2502 zcmaKuc{J8r7sr3dkSRmP=suZJrUwNuZKcM3Brd=5VX?-p>~HL1U&Con5q*5 zeUyoT`8orCf2>Pd8b~BCF~P+J#l_&}MobI_2C%%0kr6z20A*$T{0TZb`1xUB0bE@8 z{247Rn3;j1A{ZI*@grDRKqkZ79J#qDFUQ7>NJ&9g7dC7_a4@8$v9^Z!dGPXrfdQ?p zu(5%R41WB;;v%kGL1rdAJ@M=r=;`tLHC9*Q>kBFsIy&g-!JmIZLIQX0puZmz6DTQx zn;Swyv111c3o$i?*;$-C2_qxq=VN#nQBe>S#P;n-Ohj)lzJEti5%%qas3;yj#ONqK ze1Me|+S>5-EAHM!P!I$JFf@edXl&k$_;?&RfL*&#SBJ_gMo5PD2c=QO#$uKp=yLT8H!_lL-e;?!HIDQ%-X@Y;4ff#N;Hbtsy1`M@Jk!jDrUuCkJL`sCB{ihuxcaNyG?965rB2xMiUstUrwSXqId9#mAYWeYA}#;aFo zYC=H)l$5~316NnjXpoddNC=)hL31;NguuxO5fMCpj=(^qr=z9@NlB=$hqpJ%%1~X6 zw{LOp9<;Q;%8D~*z{iKldo4`sBTHw0L`RE=U=-C|cbKVqhT6Zi zSFNu5$uX1^Z%OQEGdZGct|XHuJ6`MR8IEq;%GG5jBW~;GWe%Tn4D#(9!tG@{QaJ?0S>-LvJgS?J$s`SQ! z%!j4QgI6+I_rCrB5r2*{YIrs=Y42 zZk(*J*;=U1Mzf)NZ(ZBL_a2%~q+nL7j6SaLONTajQ%QM8l0KQHcK--vw{@e2yRjB) z+)qgAzhJq6lA5I-A=lpd^SXtwiRwIdhbwn%uL*q=Q{q^*~gn475YG`GDW&*F05vv(R3jIu|k&o@mP^KUGANM9Jgr*TNLw~7Ac z$c-KyRT8}%S6kMiLmO>XZQ|HCk6%ltwJVdi^g_Yf?6!ICK{C^LvT;kRpUD1%?v+q+ zTBm7{lY+YTco`&0c<&Y?`64B($Uv<+1JT4irn`m2J4`p*qKUZ6KyFzrZVMDq6 zsj=h%v$mwt+yR%1!-6&ZgIgv({r<}M%8#fV^KOgKHP+5Bdz-)Z24o6u?`CN@`Ea4F z&{~bW%_v(#HrgnYa*f({iLd$M z<`Z~b!r0B;OBQ$T>=+3g$~^F}nMESkYQO!hyV!q2J& zBgb=32n=Q0j%dViN<1;xUz@;3OSITHR4Za5@W+Cv^C{yH(XCQkZ`(}Mn`9ycA3xZZ z_$gzY=5w%1!6QmV{W#CS?8G?jYH+8<+{d)1)o$_f@#BLn{mffh9IGg+ZdI!ht*sVI zV&7!S`0v&XO@w_PKb;#~P?ghjfNQ*MZ&Uxd2@$@C^x|wL>nARALLOFh0dIL0(nrr9 zeGtTSY_#-))Q>x_eY3;USta)HXwSJWzr8S!__NFVFROUnpL~+HgI;}MnC+ctguehh}w&Z-L(crYHXT-HG*`-AO!ql}4 z^??dzkWXia3g;nZ@qMR2EKWfI*h;cnGH(wf?xu%3jaMTRA|2In*7mMz0COjp%D zR}^=oQ_KF$xn}i=eDDFf_8~ZXDI7f^hzCTgTi!$ zq$${gcVWuJbHGi;?}zWdfDX-CHldR1Z=r4MXts4mJ{dzxdM{%hYU^l#TJO=^v~z`j0~Gk9jt`b!{5)wZHK+EFQL4&Ib? zLnx7zl;so^^dO*zZ0mg z?v(RXJ9p22W_EStt$(!$;a`lKojt{k@TPdW**Q?$Dd(spS9d#S3W>aHj`QondKRIl MZKRcd==7z(0oA$n761SM literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/replacement_image_05.png b/tests/data/test-input-data/binary-data/images/replacement_image_05.png new file mode 100644 index 0000000000000000000000000000000000000000..bbd79f476f630d469017c00bef9a3bfa693c0fa1 GIT binary patch literal 2612 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 bmml4OAy3vO5v&f*F2c-c4=s1+!H9nWnIkjC literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/replacement_image_07.png b/tests/data/test-input-data/binary-data/images/replacement_image_07.png new file mode 100644 index 0000000000000000000000000000000000000000..4c8938b5680dee08894777483cc20148805fc0c6 GIT binary patch literal 2554 zcma);c{tTu7sr1QGL@MOIVDqxV~7&DCuB@@NXj)k$*hcV-OI_1E4L($%tNM1N+q+4 zYwRcr8S0WEb0w9CzVEs3AMf+Lf86JN_aAHRy`KHqYwc&RXRZC)5i1jZ9!Va8Ao$Hp zji>~%E|E2N-@wk2Iid_>mLj>CQV$VCxB@{$#Sp{_%M>+55W!@Em~kcu-D?CP9*|jc zRF5Fol8;#0uo#4efi(&WKq7&Y6Q@t(!2<{iA~6xKUSVYg6BEeJ#>3#l;8+z`c9exf9>MK~E1sK`=4F_U*WK4Wpx2UdG%U zDk|XPgQzGdE2F#|@7`fy0UaH1bcB@^%E~Z4j!TyyApu22Fc|pjFMR!q`}d)*4;dNc z=3;6JU%sHb8+LZ+>%-(E($etLPY@T!n>V<88Og~oFo2d88XHkt3twMoYvcWUR8=7_ z52>kGT*T56Mn(`Di;o}C+>F&#c(fq}Sl2mJha_6!ylNJ>In97;-1R|iQ+n3+LG2U1cve;)1a zXlujWyATor4-feG;OU85w=gpUd3kVf;Fn+U^eLV^!RF1_xDgK@LQW155zy2`VIdkC z(A0#pXHj1dCKINnpi+^Zj+-~(+AHoSV&zC^lik^J!~NBF9A9?i|i-+crj*C{Zd5rcpBePO;m8vFc6vKlppN%ZV?m6&neJ7KwwfMuNSZ7X9 zI%zC2OK{iqOF{*q+cVel1^S)r)}On($UC8?dnoaAZVE|VpEJnxd9;McR#z@J(@X`c zy4QJm5^rMFn zyfJJGZyi-irG@vAn9G&D6%rO~4ih2V_xjjHOfHVQCV#T$tSgyeILtU!)$ysNWYFvQ zV#K=E6?O8Di7J}!v~8@Q);?_Gj}Tqo%9b!3M*)lpBN7 z^|a0OL18<_$g#J>4yp&cVnkY!hDqz*?~vl+8}QgsuGnMjmqQxdKJVCfb78+vYVeu) z0WKyVWn-U=jjZesvRgO0CQ8=DW{;c+bE+NTkWLDWU5M6S*uJ;J(9xbgC}hX@F7WF| zUESk6u4cYRJpAaisXKFmRTsEwI_8Dl)9%TRxzXI1WXdh3qL;vr^l&#O&m~(;lZ6`s zIW8HJ()+f&lc_xDc-&B}O-yT0sN42DXXa@`fe89@i+0+Mrtv1v=;L1OTwgNiQ;)_g zf|mT6B-T6)xHHpl2D}Qqt?D$DlYM|O)OS5}PA^M_EmJUmz1!n}_f_}LQeUVxB!A&+ zdm-)h`%Jfwp@2Ob^I3bMO<7&HC*96kN~QUnOF_pK?LERWi$A|Hpm3T8=1pYTzDVp{ zNclcJFj&khG?H6k*C+a8-_3meKia!kr}`(jc9CbNdntDs4pV%%RV-vF>w zNqm#Z{pl<6o>#}}q^BfDFOme?*bA>-nqDz3_%f+X(KwMNjvhh&;SJfW*21SaIob9ymY+0LU@YC9m3U-Ql zqIcm*FjP|PpG&%l+x_8O7n)h0-5@#Dtw-!(NK6ThW{_NOOJ&ECU)eq=wJ1}(p)6jdny{2O8kN{;$ox>N zTj`}1V(nMlRQ^ot-yv`9@VzZHTAe|1wD7*Zs-U>>)*HLoJ_T{=tI`rmQA5R=OXf`N zrpNTSOap6bR;83S@3GWt8HJt|Gk@r=lvmE!UYGmSQp5D?H=Rw5QP}-m^o`sT)woSu zhKVcY-T9HBqAlLj`#i4eiQlqi2Huws)=YgHyGPPQYW_P9gR7=lCi+BW8MEZw=ZFpz z&hk+0?^1@$S7oN`7Ze?iCoY%lQEi#%Em>CVseFC7ri`RXO?(jP&KBRzv0}AqJ|JrJ za?1Yb8)<6T?w%#e|51u-Hh`^Bvm=ZDTId~C-;fV7whMB138Lw`ou#o9p+VNr+@-F* zOMSNuSwnaC9$j_yon*2unJko}rTSlhufMzJsdN7fxHTsvu>ht2cnI?Jr3D7L_y+tl zqcw1w^*tjb|7Lt#TxmYUSz3UPiyO_C<`+cr^mXx|k;ppUTn`Vkb`fUARz_t9oaz4p D3e5#V literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/replacement_image_08.png b/tests/data/test-input-data/binary-data/images/replacement_image_08.png new file mode 100644 index 0000000000000000000000000000000000000000..03191b46cd6c946ba66ff006d6ac0dbe4a25e10e GIT binary patch literal 2638 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 ZQGIC&WZi_?%wIK>urRSTE;RBu@n0YCITio_ literal 0 HcmV?d00001 diff --git a/tests/data/test-input-data/binary-data/images/replacement_image_10.png b/tests/data/test-input-data/binary-data/images/replacement_image_10.png new file mode 100644 index 0000000000000000000000000000000000000000..98d663d8ca027bd41dab19cb127d51ecbb6a2f72 GIT binary patch literal 2509 zcma)-c{J5)7sr1@I1(X6WKOx_pgNM_#*w2?W-=5xrYJ-Rx7-Ye_jWrCh6eMja7~$A zL_$%~HI+((DReVNeDAqyz3W};{o}6peg4?{*?T>o{p`Khvz{G$%+!#NBt{|#g3pLX zH75u*CTs7?y^bYQHzyddl+-Djxd}mB*g+7NA_-!d<+?OR5P@WZm^eugnn?t)#rJNF znHE8?|9Z^WlEol67_60*1t}@4Uk?utl$WEn7GJ(#(5O1%lP;aDJfuMLr@Ur z=OG|~^XKu$A9(f*s;c1T2AK>?OZfTW{(V$egNFyHsTdpt2M2_Ok)4g5JF&Kgxj6_4 zVck0P^uXR8+S-_z!PFEYBaxd6Utg4#A|L>UhIsV~9UYL9LsAmnyur6``1~0a74Y`P zrAyeg3ne9(p2nYl;_+iRIlfP@6RevPFil$Ak30%>U&8^gi^ zy1QX(i{4(0j^frWgoRfE;phkz72LRi)m6mBp```k;b?D%n;Y`;F){*cYqYjPQ4tXl$jQOWmyndi z_U$-#4#mZ|Z~=ULc<};9j^O%rFc`?o!w)~8t`1^iSXqIQ5hxUF+lI@R(bk4XkMP@X zP*a1J76b*cVFNrpF);yod2n*#;ze|IVdF-Ki{rrq$jTx#6zb||XuzF2XljDLKdP!w zUysgC&}g`Q8&oPtBoq|D%L|(~!!Ny4hV^9GT#gu02?nPGjb(5J7?~Jwjq>udYi?+( z|MZR^IKLWE4_XEfP9?3L5H=8RYdf0eB0eI0erW^AMelkBdu&|9;WXbYH}l&$Cj-np z^64kj<#kS{y9^2?jOcqtAGa1!bmKqnX}3yw+BK~hT3dJ1>6JvCQ|h9MdKqOlxqc?} ztlL7QRHT3&xAgxMHCo!fC(`s{qTb{$Qj5EIUma-9o2%A+vH2xM>DUP=ISyl5fNs!} zWNUZQIKMtE)wYU@Dm4;8d{P+WFlKOh$jTM9HFlA-xO13ITLopKH$MEb^rPF(#~enq z+-qd^9OkuHqfFOpT4Ma`m9(33@9>D;___CBG&6>59q$>eacp2b;05_iSWRd%wfdoH z$Kxj#Tp$Cnu<{KKJmmr=1!80ynexBKHO>*AV+yH~#GW$*f6AXVVHovd%a&dEPB z!%JS!roATcRcCQpm4I#i`r-J-f;YfLH!N-469rHV0NY zvY7cQKV2l8>83B_!t+|hf+jd@M%N;%^~N>?N$2%+1ep~NhW_T*d1S%^}-y1seZ%x2>|A!(h~eJ?e_`T4U&{^X5Tmya!VVZ$s41vzx#EyAc z##r%`biy-JJ>}ExT2@i%hJ8?t9`{7QsOynuLG3sN&J2Pc>{g%t!un^)h{* zl$308yREBDKGak^H5U?;j4-dhvlc8?rPy-xjChUQ^^1oF_QUVIw5h}|zn^!sbqrm3 ze.aN>kmn097s{H6)*zauk};!YUGKJ8-;hp##8iDJx0eX-77*Qb5liB$Krkh78Q zTo?0wJ#|f|DMq)q+Nz=7r1lzTpW={4tw8R^Xy!J5N<#=m`X`G{YrlKjxL*3*_wg{4 z9#wl=blAYuF|X&lZY1NouDaT5%I$r;@rhOUHrvf#!a?i z{4Oy{X4Rj5Svt$FkV5Zvj9M}YpACpy44c=SdgaYCwUg>#yLH@4bjYWxZp!&n;iUhD zKD}_>rmRU)zREyWN5zstZ>6AdO%XFHPgAC)@CI#_@^6QosK>C5CJ)_RFI?eZ_9SVO z&9YT?O-!QGhWYUSL>OjKzrk&3HSz(7g$Ny05qMDY_5+On{W9kFz^nN|pRMSg??FiZC)Tr55R({P{20 CPw>Y8 literal 0 HcmV?d00001 From 50644afd98d41f360dce798372541a9025681f39 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 14 Nov 2023 22:23:27 -0800 Subject: [PATCH 21/77] support loading binary data from file in test fixture ValidData class --- tests/fixtures/valid_data.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/fixtures/valid_data.py b/tests/fixtures/valid_data.py index 7cbc5a88..dee30e59 100644 --- a/tests/fixtures/valid_data.py +++ b/tests/fixtures/valid_data.py @@ -28,10 +28,11 @@ def _load_registry_dict(self, item_path): "registry": reg_dict, "registry_path": registry_path} return registry - def _load_text_or_json(self, item_path, item_type, strip): + def _load_data_from_file(self, item_path, item_type, strip): if item_type in ["text", "json"]: mode = "r" else: + strip = False mode = "rb" data = open(item_path, mode).read() if item_type == "json": @@ -54,7 +55,8 @@ def data_for_name(self, entry_name, version=0): if item_type == "registry": data = self._load_registry_dict(item_path) else: - data = self._load_text_or_json(item_path, item_type, strip) + # text, json, binary + data = self._load_data_from_file(item_path, item_type, strip) return data From 8df0c8dc5d2f520bcde99f90f5d6a4dd12cb0bbe Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 14 Nov 2023 22:23:46 -0800 Subject: [PATCH 22/77] add data_path_for_name() method to ValidData test fixture class --- tests/fixtures/valid_data.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/fixtures/valid_data.py b/tests/fixtures/valid_data.py index dee30e59..96601851 100644 --- a/tests/fixtures/valid_data.py +++ b/tests/fixtures/valid_data.py @@ -42,6 +42,16 @@ def _load_data_from_file(self, item_path, item_type, strip): data = data.rstrip() return data + def data_path_for_name(self, entry_name, version=0): + entry: Dict = self._registry[entry_name] + if "versions" in entry: + entry = entry["versions"][version] + + item_filename = entry["name"] + + item_path = Path(self._data_path, item_filename) + return item_path + def data_for_name(self, entry_name, version=0): entry: Dict = self._registry[entry_name] if "versions" in entry: From 0d549d62e7eddd5ac55cc5b0f9e941915d25aad5 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 14 Nov 2023 22:24:45 -0800 Subject: [PATCH 23/77] add test fixture for loading binary input test data --- tests/fixtures/op_fixtures.py | 35 +++++++++++++++++++++++++++++++++++ tests/fixtures/paths.py | 15 +++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/tests/fixtures/op_fixtures.py b/tests/fixtures/op_fixtures.py index fdb6a879..8c3d9de9 100644 --- a/tests/fixtures/op_fixtures.py +++ b/tests/fixtures/op_fixtures.py @@ -8,6 +8,7 @@ from pyonepassword import OP, logging from pyonepassword.api.exceptions import OPCmdFailedException +from .binary_input_data import BinaryImageData from .expected_account_data import ExpectedAccountData from .expected_api_credential_data import ExpectedAPICredentialData from .expected_credit_card import ExpectedCreditCardData @@ -40,6 +41,7 @@ from .non_comformant_data import NonConformantData from .paths import ( ALT_RESP_DIRECTORY_PATH, + DOCUMENT_EDIT_STATE_CONFIG_PATH, ITEM_DELETE_MULTIPLE_STATE_CONFIG_PATH, ITEM_DELETE_MULTIPLE_TITLE_GLOB_STATE_CONFIG_PATH, ITEM_EDIT_STATE_CONFIG_PATH, @@ -235,6 +237,33 @@ def setup_stateful_item_edit(): # temp_dir will get cleaned up once we return +@fixture +def setup_stateful_document_edit(): + + # set up a temporary directory to copy the state config to, since it gets modified + # during state iteration + config_file_name = DOCUMENT_EDIT_STATE_CONFIG_PATH.name + temp_dir = tempfile.TemporaryDirectory() + state_config_dir = temp_dir.name + state_config_path = Path(state_config_dir, config_file_name) + shutil.copyfile( + DOCUMENT_EDIT_STATE_CONFIG_PATH, state_config_path) + + # now pop MOCK_OP_RESPONSE_DIRECTORY to ensure it doesn't conflict with with + # the stateful config + old_mock_op_resp_dir = os.environ.pop("MOCK_OP_RESPONSE_DIRECTORY", None) + os.environ["MOCK_OP_STATE_DIR"] = str(state_config_path) + yield # pytest will return us here after the test runs + # get rid of MOCK_OP_STATE_DIR + os.environ.pop("MOCK_OP_STATE_DIR") + + # restore MOCK_OP_RESPONSE_DIRECTORY if it was previously set + if old_mock_op_resp_dir is not None: + os.environ["MOCK_OP_RESPONSE_DIRECTORY"] = old_mock_op_resp_dir + + # temp_dir will get cleaned up once we return + + @fixture def setup_stateful_svc_acct_auth(): config_file_name = SVC_ACCT_NOT_YET_AUTH_STATE_CONFIG_PATH.name @@ -528,6 +557,12 @@ def non_conformant_data(): return data +@fixture +def binary_image_data(): + data = BinaryImageData() + return data + + @fixture def valid_op_cli_config_homedir(): config_obj = ValidOPCLIConfig() diff --git a/tests/fixtures/paths.py b/tests/fixtures/paths.py index eb198359..1db44a32 100644 --- a/tests/fixtures/paths.py +++ b/tests/fixtures/paths.py @@ -23,6 +23,13 @@ ITEM_EDIT_RESP_PATH, "item-edit-state-config.json" ) +DOCUMENT_EDIT_RESP_PATH = Path( + MOCK_OP_CONFIG_PATH, "responses-document-edit" +) +DOCUMENT_EDIT_STATE_CONFIG_PATH = Path( + DOCUMENT_EDIT_RESP_PATH, "document-edit-state-config.json" +) + UNAUTH_RESP_DIRECTORY_PATH = Path( MOCK_OP_CONFIG_PATH, "unauth-response-directory.json") @@ -46,12 +53,20 @@ VALID_DATA_REGISTRY_PATH = Path( TEST_INPUT_DATA_PATH, "valid-data-registry.json") VALID_DATA_PATH = Path(TEST_INPUT_DATA_PATH, "valid-data") + INVALID_DATA_REGISTRY_PATH = Path( TEST_INPUT_DATA_PATH, "invalid-data-registry.json") INVALID_DATA_PATH = Path(TEST_INPUT_DATA_PATH, "invalid-data") + NON_CONFORMANT_REGISTRY_PATH = Path( TEST_INPUT_DATA_PATH, "non-conformant-data-registry.json") NON_CONFORMANT_DATA_PATH = Path(TEST_INPUT_DATA_PATH, "non-conformant-data") + +BINARY_DATA_REGISTRY_PATH = Path( + TEST_INPUT_DATA_PATH, "binary-data-registry.json") +BINARY_DATA_PATH = Path(TEST_INPUT_DATA_PATH, "binary-data") + + EXPECTED_DATA_REGISTRY_PATH = Path( TEST_DATA_PATH, "expected-data-registry.json") EXPECTED_DATA_PATH = Path(TEST_DATA_PATH, "expected-data") From 6ba0f320f4f58e972d9be8f865d1010f20fa44dc Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 14 Nov 2023 22:27:11 -0800 Subject: [PATCH 24/77] add test fixture classes for BinaryData, BinaryImageData --- tests/fixtures/binary_input_data.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/fixtures/binary_input_data.py diff --git a/tests/fixtures/binary_input_data.py b/tests/fixtures/binary_input_data.py new file mode 100644 index 00000000..b0654084 --- /dev/null +++ b/tests/fixtures/binary_input_data.py @@ -0,0 +1,29 @@ +from typing import Dict + +from .paths import BINARY_DATA_PATH, BINARY_DATA_REGISTRY_PATH +from .valid_data import ValidData + + +class BinaryData(ValidData): + REGISTRY_PATH = BINARY_DATA_REGISTRY_PATH + DATA_PATH = BINARY_DATA_PATH + + @property + def binary_image_data(self) -> Dict[str, Dict]: + item_data_registry = self.data_for_name("binary-image-data") + return item_data_registry + + +class BinaryImageData(ValidData): + + def __init__(self): + binary_data = BinaryData() + binary_image_data_registry: Dict = binary_data.binary_image_data + registry = binary_image_data_registry["registry"] + super().__init__(registry=registry) + self._data_path = binary_image_data_registry["data_path"] + self._registry_path = binary_image_data_registry["registry_path"] + + def data_for_name(self, entry_name) -> bytes: + data = super().data_for_name(entry_name) + return data From bc6b407a68953483f69c7033947af6221fc64057 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 14 Nov 2023 22:27:50 -0800 Subject: [PATCH 25/77] add mock-op query and responses for editing example document 01 --- .../response-generation-document-edit-1.cfg | 36 +++++++++++ .../response-generation-document-edit-2.cfg | 20 ++++++ .../document-edit-state-config.json | 20 ++++++ .../response-directory-1.json | 61 ++++++++++++++++++ .../response-directory-2.json | 30 +++++++++ .../responses-1/cli-version/error_output | 0 .../responses-1/cli-version/output | 1 + .../error_output | 0 .../document-edit-example-document-01/output | 0 .../error_output | 0 .../output | 30 +++++++++ .../error_output | 0 .../document-get-example-document-01/output | Bin 0 -> 1830 bytes .../list-signed-in-accounts/error_output | 0 .../list-signed-in-accounts/output | 20 ++++++ .../whoami-account-uuid/error_output | 0 .../responses-1/whoami-account-uuid/output | 8 +++ .../responses-1/whoami/error_output | 0 .../responses-1/whoami/output | 8 +++ .../error_output | 0 .../output | 30 +++++++++ .../error_output | 0 .../document-get-example-document-01/output | Bin 0 -> 2462 bytes .../whoami-account-uuid/error_output | 0 .../responses-2/whoami-account-uuid/output | 8 +++ 25 files changed, 272 insertions(+) create mode 100644 tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg create mode 100644 tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg create mode 100644 tests/config/mock-op/responses-document-edit/document-edit-state-config.json create mode 100644 tests/config/mock-op/responses-document-edit/response-directory-1.json create mode 100644 tests/config/mock-op/responses-document-edit/response-directory-2.json create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/cli-version/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/cli-version/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-01/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-01/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01-filename/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01-filename/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/list-signed-in-accounts/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/list-signed-in-accounts/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/whoami-account-uuid/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/whoami-account-uuid/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/whoami/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/whoami/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-01-filename/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-01-filename/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-01/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-01/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/whoami-account-uuid/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/whoami-account-uuid/output diff --git a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg new file mode 100644 index 00000000..59c0b478 --- /dev/null +++ b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg @@ -0,0 +1,36 @@ +[MAIN] +config-path = ./tests/config/mock-op/responses-document-edit +response-path = responses-1 +input-path = input +response-dir-file = response-directory-1.json +state-iteration = 0 +state-config = ./tests/config/mock-op/responses-document-edit/document-edit-state-config.json +# Be sure to set RESP_GEN_DOT_ENV_FILE=path/to/.env_corrupt_svc_account +# to have response-generator load the service account token +existing-auth = required + +[cli-version] +type = cli-version +enabled = true + +[list-signed-in-accounts] +type = account-list +enabled = true + +[whoami] +type = whoami +enabled = true + +[document-get-example-document-01] +type = document-get +vault=Test Data 2 +item-identifier = example document 01 +enabled = true + +[document-edit-example-document-01] +type = document-edit +vault = Test Data 2 +document_identifier = example document 01 +new-document-path = working_data/images/replacement_image_01.png +changes-state = true +enabled = true diff --git a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg new file mode 100644 index 00000000..5d1813c0 --- /dev/null +++ b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg @@ -0,0 +1,20 @@ +[MAIN] +config-path = ./tests/config/mock-op/responses-document-edit +response-path = responses-2 +input-path = input +response-dir-file = response-directory-2.json +state-iteration = 1 +state-config = ./tests/config/mock-op/responses-document-edit/document-edit-state-config.json +# Be sure to set RESP_GEN_DOT_ENV_FILE=path/to/.env_corrupt_svc_account +# to have response-generator load the service account token +existing-auth = required + +[whoami] +type = whoami +enabled = false + +[document-get-example-document-01] +type = document-get +vault=Test Data 2 +item-identifier = example document 01 +enabled = true diff --git a/tests/config/mock-op/responses-document-edit/document-edit-state-config.json b/tests/config/mock-op/responses-document-edit/document-edit-state-config.json new file mode 100644 index 00000000..413eb2ae --- /dev/null +++ b/tests/config/mock-op/responses-document-edit/document-edit-state-config.json @@ -0,0 +1,20 @@ +{ + "iteration": 0, + "max-iterations": 2, + "state-list": [ + { + "response-directory": "tests/config/mock-op/responses-document-edit/response-directory-1.json", + "env-vars": { + "set": {}, + "pop": [] + } + }, + { + "response-directory": "tests/config/mock-op/responses-document-edit/response-directory-2.json", + "env-vars": { + "set": {}, + "pop": [] + } + } + ] +} \ No newline at end of file diff --git a/tests/config/mock-op/responses-document-edit/response-directory-1.json b/tests/config/mock-op/responses-document-edit/response-directory-1.json new file mode 100644 index 00000000..176a4f9a --- /dev/null +++ b/tests/config/mock-op/responses-document-edit/response-directory-1.json @@ -0,0 +1,61 @@ +{ + "meta": { + "response_dir": "tests/config/mock-op/responses-document-edit/responses-1", + "input_dir": "input" + }, + "commands": { + "--account|5GHHPJK5HZC5BAT7WDUXW57G44|--format|json|whoami": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "whoami-account-uuid", + "changes_state": false + }, + "--version": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "cli-version", + "changes_state": false + }, + "--format|json|account|list": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "list-signed-in-accounts", + "changes_state": false + }, + "--format|json|whoami": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "whoami", + "changes_state": false + }, + "--format|json|document|get|example document 01|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-01", + "changes_state": false + }, + "--format|json|item|get|example document 01|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-01-filename", + "changes_state": false + } + }, + "commands_with_input": { + "910404ace404544ed7606e75f15b3753": { + "--format|json|document|edit|p7rtertk6746yb6tm5fc2zf66i|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-edit-example-document-01", + "changes_state": true + } + } + } +} \ No newline at end of file diff --git a/tests/config/mock-op/responses-document-edit/response-directory-2.json b/tests/config/mock-op/responses-document-edit/response-directory-2.json new file mode 100644 index 00000000..9dc9174a --- /dev/null +++ b/tests/config/mock-op/responses-document-edit/response-directory-2.json @@ -0,0 +1,30 @@ +{ + "meta": { + "response_dir": "tests/config/mock-op/responses-document-edit/responses-2", + "input_dir": "input" + }, + "commands": { + "--format|json|document|get|example document 01|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-01", + "changes_state": false + }, + "--format|json|item|get|example document 01|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-01-filename", + "changes_state": false + }, + "--account|5GHHPJK5HZC5BAT7WDUXW57G44|--format|json|whoami": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "whoami-account-uuid", + "changes_state": false + } + }, + "commands_with_input": {} +} \ No newline at end of file diff --git a/tests/config/mock-op/responses-document-edit/responses-1/cli-version/error_output b/tests/config/mock-op/responses-document-edit/responses-1/cli-version/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/cli-version/output b/tests/config/mock-op/responses-document-edit/responses-1/cli-version/output new file mode 100644 index 00000000..f48f82fa --- /dev/null +++ b/tests/config/mock-op/responses-document-edit/responses-1/cli-version/output @@ -0,0 +1 @@ +2.22.0 diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-01/error_output b/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-01/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-01/output b/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-01/output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01-filename/error_output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01-filename/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01-filename/output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01-filename/output new file mode 100644 index 00000000..ffbb2618 --- /dev/null +++ b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01-filename/output @@ -0,0 +1,30 @@ +{ + "id": "p7rtertk6746yb6tm5fc2zf66i", + "title": "example document 01", + "version": 7, + "vault": { + "id": "vkjyqsbkf63zycqigbg3yxd7ce", + "name": "Test Data 2" + }, + "category": "DOCUMENT", + "last_edited_by": "FZTDCNIJAOEBZZ2VQFNDVHC3K6", + "created_at": "2023-11-15T03:26:35Z", + "updated_at": "2023-11-15T06:08:40Z", + "fields": [ + { + "id": "notesPlain", + "type": "STRING", + "purpose": "NOTES", + "label": "notesPlain", + "reference": "op://Test Data 2/example document 01/notesPlain" + } + ], + "files": [ + { + "id": "bdwjqbnbmeaehyz7g6tbmgqbze", + "name": "image_01.png", + "size": 1830, + "content_path": "/v1/vaults/vkjyqsbkf63zycqigbg3yxd7ce/items/p7rtertk6746yb6tm5fc2zf66i/files/bdwjqbnbmeaehyz7g6tbmgqbze/content" + } + ] +} diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01/error_output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01/output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-01/output new file mode 100644 index 0000000000000000000000000000000000000000..fca5a57662d6d27ae7226924d577a285969ae415 GIT binary patch literal 1830 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 YZzhSN9qTC_#&r>v=KIa=m>i4!52~KjVgLXD literal 0 HcmV?d00001 diff --git a/tests/config/mock-op/responses-document-edit/responses-2/whoami-account-uuid/error_output b/tests/config/mock-op/responses-document-edit/responses-2/whoami-account-uuid/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-2/whoami-account-uuid/output b/tests/config/mock-op/responses-document-edit/responses-2/whoami-account-uuid/output new file mode 100644 index 00000000..edc59bd5 --- /dev/null +++ b/tests/config/mock-op/responses-document-edit/responses-2/whoami-account-uuid/output @@ -0,0 +1,8 @@ +{ + "url": "https://pyonepassword.1password.com", + "URL": "https://pyonepassword.1password.com", + "user_uuid": "FZTDCNIJAOEBZZ2VQFNDVHC3K6", + "account_uuid": "M5C4BT3KMQ7HROISKYLWDUXW57", + "user_type": "SERVICE_ACCOUNT", + "ServiceAccountType": "SERVICE_ACCOUNT" +} From 0fff0e4815903478da62924bf3b982fb2bbf8eaf Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 14 Nov 2023 22:28:20 -0800 Subject: [PATCH 26/77] add test module test_document_edit --- tests/test_document_edit/__init__.py | 0 .../test_document_edit/test_document_edit.py | 37 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/test_document_edit/__init__.py create mode 100644 tests/test_document_edit/test_document_edit.py diff --git a/tests/test_document_edit/__init__.py b/tests/test_document_edit/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_document_edit/test_document_edit.py b/tests/test_document_edit/test_document_edit.py new file mode 100644 index 00000000..cae25b8e --- /dev/null +++ b/tests/test_document_edit/test_document_edit.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pyonepassword import OP + + from ..fixtures.binary_input_data import BinaryImageData + +import pytest + +from ..test_support.util import digest + +pytestmark = pytest.mark.usefixtures("valid_op_cli_config_homedir") + + +@pytest.mark.usefixtures("setup_stateful_document_edit") +def test_document_edit_01(signed_in_op: OP, binary_image_data: BinaryImageData): + item_name = "example document 01" + vault = "Test Data 2" + input_data_path = binary_image_data.data_path_for_name( + "replacement-image-01") + input_data = binary_image_data.data_for_name("replacement-image-01") + input_data_digest = digest(input_data) + + filename_1, data_1 = signed_in_op.document_get(item_name, vault=vault) + digest_1 = digest(data_1) + + assert digest_1 != input_data_digest + signed_in_op.document_edit(item_name, input_data_path, vault=vault) + + filename_2, data_2 = signed_in_op.document_get(item_name, vault=vault) + digest_2 = digest(data_2) + + # filename shouldn't change because we didn't explicitly set it + assert filename_2 == filename_1 + assert digest_2 == input_data_digest From 34ef73b8833872031910c7f4e6f641637c923689 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 14 Nov 2023 22:28:33 -0800 Subject: [PATCH 27/77] add script to autogenerate .png files --- scripts/generate-pngs.sh | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100755 scripts/generate-pngs.sh diff --git a/scripts/generate-pngs.sh b/scripts/generate-pngs.sh new file mode 100755 index 00000000..bc953155 --- /dev/null +++ b/scripts/generate-pngs.sh @@ -0,0 +1,49 @@ +#!/bin/sh -e + + +image_num="$1" +count="$2" +output_path="$3" + +if [ -z "$image_num" ] || [ -z "$count" ] || [ -z "$output_path" ]; +then + echo "USAGE: $0 " + exit 1 +fi + +_gen_filename(){ + printf "image_%02d.png" "$1" +} + +_gen_image_text(){ + printf "image %02d" "$1" +} + +_gen_replacement_filename(){ + printf "replacement_image_%02d.png" "$1" +} + +_gen_replacement_image_text(){ + printf "replacement image %02d" "$1" +} + + +max=$((image_num + count)) + +while [ "$image_num" -lt $max ]; +do + _image_filename_1="$(_gen_filename "$image_num")" + _image_path_1="$output_path/$_image_filename_1" + _image_text_1="$(_gen_image_text "$image_num")" + + _image_filename_2="$(_gen_replacement_filename "$image_num")" + _image_path_2="$output_path/$_image_filename_2" + _image_text_2="$(_gen_replacement_image_text "$image_num")" + + echo "Creating $_image_path_1" + convert -size 400x100 -background "red" -fill "white" -pointsize 24 -gravity center label:"$_image_text_1" "$_image_path_1" + echo "Creating $_image_path_2" + convert -size 400x100 -background "blue" -fill "white" -pointsize 24 -gravity center label:"$_image_text_2" "$_image_path_2" + + image_num=$((image_num + 1)) +done From 95e070e77f9da67b446d8386b34e28a59088f278 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Wed, 15 Nov 2023 19:44:39 -0800 Subject: [PATCH 28/77] update document_edit.py ipython snippet --- ipython_snippets/document_edit.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ipython_snippets/document_edit.py b/ipython_snippets/document_edit.py index 7981a813..ca98e57e 100644 --- a/ipython_snippets/document_edit.py +++ b/ipython_snippets/document_edit.py @@ -7,5 +7,6 @@ print("run: op = get_op(\"document-edit\")") -vault = "Test Data 1" -document_name = "screenshot.png" +vault = "Test Data 2" +document_name = "no such document" +new_file_path = "working_data/images/replacement_image_10.png" From 8c87a4ee41fc033686d65e6ede00b95fd614d78a Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Wed, 15 Nov 2023 21:08:40 -0800 Subject: [PATCH 29/77] move test_document_edit under tes_op_api --- tests/{ => test_op_api}/test_document_edit/__init__.py | 0 .../test_document_edit/test_document_edit.py | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/{ => test_op_api}/test_document_edit/__init__.py (100%) rename tests/{ => test_op_api}/test_document_edit/test_document_edit.py (91%) diff --git a/tests/test_document_edit/__init__.py b/tests/test_op_api/test_document_edit/__init__.py similarity index 100% rename from tests/test_document_edit/__init__.py rename to tests/test_op_api/test_document_edit/__init__.py diff --git a/tests/test_document_edit/test_document_edit.py b/tests/test_op_api/test_document_edit/test_document_edit.py similarity index 91% rename from tests/test_document_edit/test_document_edit.py rename to tests/test_op_api/test_document_edit/test_document_edit.py index cae25b8e..d519be8e 100644 --- a/tests/test_document_edit/test_document_edit.py +++ b/tests/test_op_api/test_document_edit/test_document_edit.py @@ -5,11 +5,11 @@ if TYPE_CHECKING: from pyonepassword import OP - from ..fixtures.binary_input_data import BinaryImageData + from ...fixtures.binary_input_data import BinaryImageData import pytest -from ..test_support.util import digest +from ...test_support.util import digest pytestmark = pytest.mark.usefixtures("valid_op_cli_config_homedir") From 3489b51f4a4d7819f46c1ba0917c4dacfd3e7e00 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Wed, 15 Nov 2023 21:09:13 -0800 Subject: [PATCH 30/77] add __init__.py to test_op_api --- tests/test_op_api/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/test_op_api/__init__.py diff --git a/tests/test_op_api/__init__.py b/tests/test_op_api/__init__.py new file mode 100644 index 00000000..e69de29b From 670010babb69bd13187b0e4c3b5c905b9c08280a Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Thu, 16 Nov 2023 19:12:09 -0800 Subject: [PATCH 31/77] export OPDocumentEditException as API --- pyonepassword/api/exceptions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyonepassword/api/exceptions.py b/pyonepassword/api/exceptions.py index 9ac2fecc..cd8fd612 100644 --- a/pyonepassword/api/exceptions.py +++ b/pyonepassword/api/exceptions.py @@ -29,6 +29,7 @@ OPCmdMalformedSvcAcctTokenException, OPConfigNotFoundException, OPDocumentDeleteException, + OPDocumentEditException, OPDocumentGetException, OPForgetException, OPGroupGetException, @@ -61,6 +62,7 @@ "OPConfigNotFoundException", "OPDocumentDeleteException", "OPDocumentGetException", + "OPDocumentEditException", "OPFieldNotFoundException", "OPForgetException", "OPGroupGetException", From fc4eb96d973929c5aa40e4379d498fa46b960e5c Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Thu, 16 Nov 2023 19:12:56 -0800 Subject: [PATCH 32/77] allow document_edit() to take a file path or replacement document bytes --- pyonepassword/pyonepassword.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pyonepassword/pyonepassword.py b/pyonepassword/pyonepassword.py index 59d32284..0f348552 100644 --- a/pyonepassword/pyonepassword.py +++ b/pyonepassword/pyonepassword.py @@ -176,7 +176,7 @@ def document_get(self, document_name_or_id, vault=None, include_archive=False, r def document_edit(self, document_identifier: str, - file_path: Union[str, Path], + file_path_or_document_bytes: Union[str, Path, bytes], vault: Optional[str] = None, relaxed_validation: bool = False) -> str: """ @@ -186,8 +186,9 @@ def document_edit(self, ---------- document_identifier : str Name or identifier of the document to edit - file_path: Union[str, Path], - Path to the file to replace the current document with + file_path_or_document_bytes: Union[str, Path, bytes], + Either the path to the file to replace the current document with, + or the actual bytes representation of the replacement document vault : str, optional The name or ID of a vault to override the default vault, by default None relaxed_validation: bool, optional @@ -211,8 +212,11 @@ def document_edit(self, required keyword arguments: vault """ - file_path = Path(file_path) - document_bytes = file_path.read_bytes() + if isinstance(file_path_or_document_bytes, bytes): + document_bytes = file_path_or_document_bytes + else: + file_path_or_document_bytes = Path(file_path_or_document_bytes) + document_bytes = file_path_or_document_bytes.read_bytes() # to satisfy mypy generic_item_class: Type[_OPGenericItem] From 95f088db9f474fde83e0c525413a42e2810aadb0 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Fri, 17 Nov 2023 11:58:57 -0800 Subject: [PATCH 33/77] add docstring and comments to test_document_edit_01() test case --- .../test_document_edit/test_document_edit.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_op_api/test_document_edit/test_document_edit.py b/tests/test_op_api/test_document_edit/test_document_edit.py index d519be8e..2f53d785 100644 --- a/tests/test_op_api/test_document_edit/test_document_edit.py +++ b/tests/test_op_api/test_document_edit/test_document_edit.py @@ -16,6 +16,16 @@ @pytest.mark.usefixtures("setup_stateful_document_edit") def test_document_edit_01(signed_in_op: OP, binary_image_data: BinaryImageData): + """ + Test: OP.document_edit() with path to a replacement file + - Retrieve document bytes and filename via OP.document_get() + - Call document_edit(), providing the path to a new file to replace the document + - Retreive the same item a second time + Verify: + - The digest of the original document bytes does not match the digest of the replacement document bytes + - The the original document filename remains unchanged after the edit + - The edited document's digest matches the digest of the replacement document bytes + """ item_name = "example document 01" vault = "Test Data 2" input_data_path = binary_image_data.data_path_for_name( @@ -26,7 +36,12 @@ def test_document_edit_01(signed_in_op: OP, binary_image_data: BinaryImageData): filename_1, data_1 = signed_in_op.document_get(item_name, vault=vault) digest_1 = digest(data_1) + # these should be different, else we've messed up + # and the document has already been edited assert digest_1 != input_data_digest + + # Provide path to the input file + # we'll test providing input bytes separately signed_in_op.document_edit(item_name, input_data_path, vault=vault) filename_2, data_2 = signed_in_op.document_get(item_name, vault=vault) @@ -34,4 +49,5 @@ def test_document_edit_01(signed_in_op: OP, binary_image_data: BinaryImageData): # filename shouldn't change because we didn't explicitly set it assert filename_2 == filename_1 + # The updated document digest should now match the digest of the input file assert digest_2 == input_data_digest From 0d1766bb3ace4fde026e39dfd5ed0e826bd70b1d Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Fri, 17 Nov 2023 12:00:09 -0800 Subject: [PATCH 34/77] add test case for: - editing a document item by providing the literal bytes - vs providing path to a new file --- .../test_document_edit/test_document_edit.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/test_op_api/test_document_edit/test_document_edit.py b/tests/test_op_api/test_document_edit/test_document_edit.py index 2f53d785..ca1da5d1 100644 --- a/tests/test_op_api/test_document_edit/test_document_edit.py +++ b/tests/test_op_api/test_document_edit/test_document_edit.py @@ -51,3 +51,41 @@ def test_document_edit_01(signed_in_op: OP, binary_image_data: BinaryImageData): assert filename_2 == filename_1 # The updated document digest should now match the digest of the input file assert digest_2 == input_data_digest + + +@pytest.mark.usefixtures("setup_stateful_document_edit") +def test_document_edit_02(signed_in_op: OP, binary_image_data: BinaryImageData): + """ + Test: OP.document_edit() with the actual bytes of a replacement file + - Retrieve document bytes and filename via OP.document_get() + - Call document_edit(), providing the actual bytes of a new file to replace the document + - Retreive the same item a second time + Verify: + - The digest of the original document bytes does not match the digest of the replacement document bytes + - The the original document filename remains unchanged after the edit + - The edited document's digest matches the digest of the replacement document bytes + """ + item_name = "example document 01" + vault = "Test Data 2" + + input_data = binary_image_data.data_for_name("replacement-image-01") + input_data_digest = digest(input_data) + + filename_1, data_1 = signed_in_op.document_get(item_name, vault=vault) + digest_1 = digest(data_1) + + # these should be different, else we've messed up + # and the document has already been edited + assert digest_1 != input_data_digest + + # Provide the literal bytes of the input file + # we'll test providingthe path to the input file separately + signed_in_op.document_edit(item_name, input_data, vault=vault) + + filename_2, data_2 = signed_in_op.document_get(item_name, vault=vault) + digest_2 = digest(data_2) + + # filename shouldn't change because we didn't explicitly set it + assert filename_2 == filename_1 + # The updated document digest should now match the digest of the input file + assert digest_2 == input_data_digest From 18e24e691560305902a731865d9403450f7f699b Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Fri, 17 Nov 2023 12:01:13 -0800 Subject: [PATCH 35/77] add test_document_edit_errors test module - test case for document_edit() on a document that doesn't exist --- .../test_document_edit_errors.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/test_op_api/test_document_edit/test_document_edit_errors.py diff --git a/tests/test_op_api/test_document_edit/test_document_edit_errors.py b/tests/test_op_api/test_document_edit/test_document_edit_errors.py new file mode 100644 index 00000000..9543beea --- /dev/null +++ b/tests/test_op_api/test_document_edit/test_document_edit_errors.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pyonepassword import OP + from ...fixtures.binary_input_data import BinaryImageData + +import pytest + +from pyonepassword.api.exceptions import OPDocumentEditException + + +@pytest.mark.usefixtures("valid_op_cli_config_homedir") +def test_document_edit_invalid_document_01(signed_in_op: OP, + binary_image_data: BinaryImageData): + document_name = "Invalid Document" + input_data_path = binary_image_data.data_path_for_name( + "replacement-image-01") + with pytest.raises(OPDocumentEditException): + signed_in_op.document_edit(document_name, input_data_path) From 2668f6dfab0f681a92c76bf61fe5eea1059786ab Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Fri, 17 Nov 2023 17:14:30 -0800 Subject: [PATCH 36/77] clarify in-line comment for OP.document_edit() --- pyonepassword/pyonepassword.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyonepassword/pyonepassword.py b/pyonepassword/pyonepassword.py index 0f348552..0ca7634d 100644 --- a/pyonepassword/pyonepassword.py +++ b/pyonepassword/pyonepassword.py @@ -232,8 +232,8 @@ def document_edit(self, raise OPDocumentEditException.from_opexception(e) # we want to return the explicit ID even if we were # given an document name or other identifier - # that way the caller knows exactly what got deleted - # can match it up with what they expected to be deleted, if desired + # that way the caller knows exactly what got edited + # can match it up with what they expected to be edited, if desired document_id = item.unique_id # 'op document edit' doesn't have any stdout, so we're not From f479be4f3bbc837ebd599db0fdcb760c46ef4b92 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Fri, 17 Nov 2023 18:41:05 -0800 Subject: [PATCH 37/77] add support for setting new filename and item title when calling OP.document_edit() --- pyonepassword/_op_cli_argv.py | 12 +++++++++++- pyonepassword/_op_commands.py | 13 +++++++++++-- pyonepassword/pyonepassword.py | 9 ++++++++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/pyonepassword/_op_cli_argv.py b/pyonepassword/_op_cli_argv.py index 82e677a4..6f9016f7 100644 --- a/pyonepassword/_op_cli_argv.py +++ b/pyonepassword/_op_cli_argv.py @@ -89,9 +89,19 @@ def document_get_argv(cls, op_exe, document_name_or_id, vault=None, include_arch return argv @classmethod - def document_edit_argv(cls, op_exe, document_identifier, vault=None): + def document_edit_argv(cls, + op_exe, + document_identifier, + file_name=None, + new_title=None, + vault=None): sub_cmd_args = [document_identifier] + + if file_name: + sub_cmd_args.extend(["--file-name", file_name]) + if new_title: + sub_cmd_args.extend(["--title", new_title]) if vault: sub_cmd_args.extend(["--vault", vault]) argv = cls._document_generic_argv(op_exe, "edit", sub_cmd_args) diff --git a/pyonepassword/_op_commands.py b/pyonepassword/_op_commands.py index 13b7bccf..dda407f1 100644 --- a/pyonepassword/_op_commands.py +++ b/pyonepassword/_op_commands.py @@ -532,10 +532,15 @@ def _document_get(self, return document_bytes - def _document_edit(self, document_identifier: str, document_bytes: bytes, vault: Optional[str] = None): + def _document_edit(self, + document_identifier: str, + document_bytes: bytes, + file_name: Optional[str] = None, + new_title: Optional[str] = None, + vault: Optional[str] = None): document_edit_argv = self._document_edit_argv( - document_identifier, vault=vault) + document_identifier, file_name=file_name, new_title=new_title, vault=vault) try: # 'op document edit' doesn't have any output if successful # if it fails, stderr will be in the exception object @@ -821,10 +826,14 @@ def _document_get_argv(self, def _document_edit_argv(self, document_identifier: str, + file_name: Optional[str] = None, + new_title: Optional[str] = None, vault: Optional[str] = None): vault_arg = vault if vault else self.vault document_edit_argv = _OPArgv.document_edit_argv(self.op_path, document_identifier, + file_name=file_name, + new_title=new_title, vault=vault_arg) return document_edit_argv diff --git a/pyonepassword/pyonepassword.py b/pyonepassword/pyonepassword.py index 0ca7634d..3c598a1d 100644 --- a/pyonepassword/pyonepassword.py +++ b/pyonepassword/pyonepassword.py @@ -177,6 +177,8 @@ def document_get(self, document_name_or_id, vault=None, include_archive=False, r def document_edit(self, document_identifier: str, file_path_or_document_bytes: Union[str, Path, bytes], + file_name: Optional[str] = None, + new_title: Optional[str] = None, vault: Optional[str] = None, relaxed_validation: bool = False) -> str: """ @@ -189,6 +191,10 @@ def document_edit(self, file_path_or_document_bytes: Union[str, Path, bytes], Either the path to the file to replace the current document with, or the actual bytes representation of the replacement document + file_name: str, optional + Optionally set the document's fileName attribute to this value + new_title: str, optional + Optionally update the title of the document to this value vault : str, optional The name or ID of a vault to override the default vault, by default None relaxed_validation: bool, optional @@ -238,7 +244,8 @@ def document_edit(self, # 'op document edit' doesn't have any stdout, so we're not # capturing any here - self._document_edit(document_id, document_bytes, vault=vault) + self._document_edit(document_id, document_bytes, + file_name=file_name, new_title=new_title, vault=vault) return document_id From e271ff744a0e7f6ab25248a6cacfa1776308d868 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Sat, 18 Nov 2023 21:56:36 -0800 Subject: [PATCH 38/77] add replacement-image-02 to binary image data registry --- tests/data/test-input-data/binary-data/images/registry.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/data/test-input-data/binary-data/images/registry.json b/tests/data/test-input-data/binary-data/images/registry.json index 9c5a0132..0a306f80 100644 --- a/tests/data/test-input-data/binary-data/images/registry.json +++ b/tests/data/test-input-data/binary-data/images/registry.json @@ -2,5 +2,9 @@ "replacement-image-01": { "name": "replacement_image_01.png", "type": "binary" + }, + "replacement-image-02": { + "name": "replacement_image_02.png", + "type": "binary" } } From 60a5acdc250e0cdf67bdeba27c66f4696146b312 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Sat, 18 Nov 2023 22:13:29 -0800 Subject: [PATCH 39/77] add mock-op query and responses for editing example document 02 --- .../response-generation-document-edit-1.cfg | 17 +++++++++- .../response-generation-document-edit-2.cfg | 6 ++++ .../response-directory-1.json | 23 ++++++++++++++ .../response-directory-2.json | 14 ++++++++ .../responses-1/cli-version/output | 2 +- .../error_output | 0 .../document-edit-example-document-02/output | 0 .../error_output | 0 .../output | 30 ++++++++++++++++++ .../error_output | 0 .../document-get-example-document-02/output | Bin 0 -> 1959 bytes .../list-signed-in-accounts/output | 12 +++---- .../error_output | 0 .../output | 30 ++++++++++++++++++ .../error_output | 0 .../output | Bin 0 -> 2602 bytes 16 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-02/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-02/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02-filename/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02-filename/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated/output diff --git a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg index 59c0b478..57d17bc0 100644 --- a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg +++ b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg @@ -25,7 +25,7 @@ enabled = true type = document-get vault=Test Data 2 item-identifier = example document 01 -enabled = true +enabled = false [document-edit-example-document-01] type = document-edit @@ -33,4 +33,19 @@ vault = Test Data 2 document_identifier = example document 01 new-document-path = working_data/images/replacement_image_01.png changes-state = true +enabled = false + +[document-get-example-document-02] +type = document-get +vault=Test Data 2 +item-identifier = example document 02 +enabled = true + +[document-edit-example-document-02] +type = document-edit +vault = Test Data 2 +document_identifier = example document 02 +new-title = example document 02 - updated +new-document-path = working_data/images/replacement_image_02.png +changes-state = true enabled = true diff --git a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg index 5d1813c0..13e2049f 100644 --- a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg +++ b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg @@ -17,4 +17,10 @@ enabled = false type = document-get vault=Test Data 2 item-identifier = example document 01 +enabled = false + +[document-get-example-document-02-updated] +type = document-get +vault=Test Data 2 +item-identifier = example document 02 - updated enabled = true diff --git a/tests/config/mock-op/responses-document-edit/response-directory-1.json b/tests/config/mock-op/responses-document-edit/response-directory-1.json index 176a4f9a..c6433a96 100644 --- a/tests/config/mock-op/responses-document-edit/response-directory-1.json +++ b/tests/config/mock-op/responses-document-edit/response-directory-1.json @@ -45,6 +45,20 @@ "stderr": "error_output", "name": "document-get-example-document-01-filename", "changes_state": false + }, + "--format|json|document|get|example document 02|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-02", + "changes_state": false + }, + "--format|json|item|get|example document 02|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-02-filename", + "changes_state": false } }, "commands_with_input": { @@ -56,6 +70,15 @@ "name": "document-edit-example-document-01", "changes_state": true } + }, + "d1857eefc7b8dcf80c5137ad54b96215": { + "--format|json|document|edit|okeubqaxp4bdjywf7xbvqov2ou|--title|example document 02 - updated|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-edit-example-document-02", + "changes_state": true + } } } } \ No newline at end of file diff --git a/tests/config/mock-op/responses-document-edit/response-directory-2.json b/tests/config/mock-op/responses-document-edit/response-directory-2.json index 9dc9174a..06e5d2c7 100644 --- a/tests/config/mock-op/responses-document-edit/response-directory-2.json +++ b/tests/config/mock-op/responses-document-edit/response-directory-2.json @@ -24,6 +24,20 @@ "stderr": "error_output", "name": "whoami-account-uuid", "changes_state": false + }, + "--format|json|document|get|example document 02 - updated|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-02-updated", + "changes_state": false + }, + "--format|json|item|get|example document 02 - updated|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-02-updated-filename", + "changes_state": false } }, "commands_with_input": {} diff --git a/tests/config/mock-op/responses-document-edit/responses-1/cli-version/output b/tests/config/mock-op/responses-document-edit/responses-1/cli-version/output index f48f82fa..e9763f6b 100644 --- a/tests/config/mock-op/responses-document-edit/responses-1/cli-version/output +++ b/tests/config/mock-op/responses-document-edit/responses-1/cli-version/output @@ -1 +1 @@ -2.22.0 +2.23.0 diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-02/error_output b/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-02/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-02/output b/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-02/output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02-filename/error_output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02-filename/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02-filename/output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02-filename/output new file mode 100644 index 00000000..b5150cd7 --- /dev/null +++ b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02-filename/output @@ -0,0 +1,30 @@ +{ + "id": "okeubqaxp4bdjywf7xbvqov2ou", + "title": "example document 02", + "version": 1, + "vault": { + "id": "vkjyqsbkf63zycqigbg3yxd7ce", + "name": "Test Data 2" + }, + "category": "DOCUMENT", + "last_edited_by": "FZTDCNIJAOEBZZ2VQFNDVHC3K6", + "created_at": "2023-11-15T03:26:36Z", + "updated_at": "2023-11-15T03:26:36Z", + "fields": [ + { + "id": "notesPlain", + "type": "STRING", + "purpose": "NOTES", + "label": "notesPlain", + "reference": "op://Test Data 2/example document 02/notesPlain" + } + ], + "files": [ + { + "id": "qpca6u4b4ikwfnw23m3mk7z63u", + "name": "image_02.png", + "size": 1959, + "content_path": "/v1/vaults/vkjyqsbkf63zycqigbg3yxd7ce/items/okeubqaxp4bdjywf7xbvqov2ou/files/qpca6u4b4ikwfnw23m3mk7z63u/content" + } + ] +} diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02/error_output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02/output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-02/output new file mode 100644 index 0000000000000000000000000000000000000000..9bb30960710aa2d1840d69574da17a699a67eff0 GIT binary patch literal 1959 zcmaKtc{J4f8^^!aagC*0NnvW@Dp|*5YfxFnu8^goamgfQZZcy@SyQ%dlop{zT*_%t zX;Em?rUl88T_TK~q?F#j`Tg@d=l4hV{l~L>KIe6w=bYy`pHGU*23uKaC24{nWbN&& z-3US?Ll_50i3u%V;S^KosN3z_oCzXo1wq6m62z?VC~klt!e|5`_>&+QSp=aNl6%k9 zj37k4U7XyRAPDT-388M@#P7c&BLm&tn4LvmAI_Zvl?pvQ6cnJR2V-Nne;=DSqp1ng z)2OS%_&D_Sv2`oHenmqAMn*uRAu_v3obBrZ6*u&Q2sH!O01VideW1IyxYcaODd8{NUvU z8yi?yU~&@S;n3B^k002x2cn`VEyctH$YfYqVapbnm_S<_)z!$%#M~TGQ&C(DDJgVx z;N(f%xr1%n(9!~Vd9<~G%Y~#Q;^R?Ngs3QZdg6~iAP_)J4HXqoQo_ZH;PJ3_E!b=< zTZZr7VQ&vvS=86V(GkYRSh*54HMn*SbUMt;psbAccFdm-EiJ^wK}H5aK^Pr{p&^=^ zar!jW)e#$ur%$nD3FPGP-~ptip`wD@x3PLP3JamBiR;&qlY?W&5E_cIGQ50=%1U^6 z;Pq=fdW4b^*x4aF8?Rm=JsqZ|*tH8wmqI}S5fK;t_eu%(PsHER)|yC`px6l$63^b5 zN$Mxdi!#VtTDX=3Ax^fpws4PZ9eF?G?aovojekfRd3;=hd_#LzUU^?=ij&y(2z`<2 zUDf&dPDb{1lQ&e|1{d|IYc5D}c$DZc;BU|5-O>ub-o|fyom=@nE!tInxN$D4X2LY+%$4m+II&B@$*>f=4S>wQtJXv;FQ@zdnJl_cXVR%gX6O&8Zyjvj`8 zEzFlR9?ZPt>L10LYI?J|U}$T*s<{lq~jbMatTuceZqkB8z{Ol!9)t)~rJ6vzc|N%@D;iMIMG>$>8hf`?xk zsyP>pD$Tyzizg)LzO58{TUVnwv68z1yB*t2jrlUVrZR^ZoISf_97PaGu7`o1-Cil@)8n9xz5@JtZbp ze;}qOy7tqf0+r*4)2cT z?CP9uhn7g+W}{rMzJuWhB42*4A6~VI8diR+(9|a*zJd9+Pkgtv7Y4Y#TUxqOkvn z^zPR9je$;judmW2dbARJ|LWz-itx!3OtVvs)S?FsUCVu$$4qr*GCh6l(x(g;d8Ce} zWn~z@G2Y47EH%ht@kavMt?o;xbVV<#lAm3dctb%Y;$vP6<@?)%b;IHz#p}##?nM8c zv^+KVU`OTX$)Bs+9$ny3^e|5e}xaoAj*A1CD3 rj6w4i;lE1A{g(;$^JfPWK^(t8HkC#{8l(J4cthATH&|b_{4?P{k<{MJ literal 0 HcmV?d00001 diff --git a/tests/config/mock-op/responses-document-edit/responses-1/list-signed-in-accounts/output b/tests/config/mock-op/responses-document-edit/responses-1/list-signed-in-accounts/output index f83f2c73..0f19f028 100644 --- a/tests/config/mock-op/responses-document-edit/responses-1/list-signed-in-accounts/output +++ b/tests/config/mock-op/responses-document-edit/responses-1/list-signed-in-accounts/output @@ -1,16 +1,16 @@ [ - { - "url": "example-account.1password.com", - "email": "example_user@example.email", - "user_uuid": "5GHHPJK5HZC5BAT7WDUXW57G44", - "account_uuid": "GRXJAN4BY5DPROISKYL55IRCPY" - }, { "url": "pyonepassword.1password.com", "email": "uid000@gmail.com", "user_uuid": "4J4NLDK7GFAXJFOR7RF2KDUAMI", "account_uuid": "M5C4BT3KMQ7HROISKYLWDUXW57" }, + { + "url": "example-account.1password.com", + "email": "example_user@example.email", + "user_uuid": "5GHHPJK5HZC5BAT7WDUXW57G44", + "account_uuid": "GRXJAN4BY5DPROISKYL55IRCPY" + }, { "url": "my.1password.com", "email": "guest_user@example.email", diff --git a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/error_output b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/output b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/output new file mode 100644 index 00000000..9f432bfa --- /dev/null +++ b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/output @@ -0,0 +1,30 @@ +{ + "id": "okeubqaxp4bdjywf7xbvqov2ou", + "title": "example document 02 - updated", + "version": 2, + "vault": { + "id": "vkjyqsbkf63zycqigbg3yxd7ce", + "name": "Test Data 2" + }, + "category": "DOCUMENT", + "last_edited_by": "A47WW2CN6BEMDDS7RXRKBFQIZ4", + "created_at": "2023-11-15T03:26:36Z", + "updated_at": "2023-11-19T03:20:20Z", + "fields": [ + { + "id": "notesPlain", + "type": "STRING", + "purpose": "NOTES", + "label": "notesPlain", + "reference": "op://Test Data 2/example document 02 - updated/notesPlain" + } + ], + "files": [ + { + "id": "z2u4b47rl4m423cob7uqtu5n4q", + "name": "image_02.png", + "size": 2602, + "content_path": "/v1/vaults/vkjyqsbkf63zycqigbg3yxd7ce/items/okeubqaxp4bdjywf7xbvqov2ou/files/z2u4b47rl4m423cob7uqtu5n4q/content" + } + ] +} diff --git a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated/error_output b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated/output b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated/output new file mode 100644 index 0000000000000000000000000000000000000000..7dc5555605727bad7eddc63abf83e2a761617097 GIT binary patch literal 2602 zcma);c~s3?8^?c@(msB$Ycl#V%IKQzYZxWWMtsoJIu_WzaNE#(ALI<3+U~| z*ck5Kg_|4r_z)3+i3vzb;^j*`dxkGxK%>FK1Jl!JYs1J0goQz+!pR9&uj2M?h=}0q zS#)<}(IT8Yi5)xO>kD;t%+KTdcgV;v(NT<#qp1n@_9!dEhYv_g zgS;Oq<=8~FJ_ObnYh!`&UKs_^lFg#|WlM0hwfH6bK~ z(o!&)aCJpj7dC7Fn++{3goMD*5ZT$dc@thXlTIN zwMa<7rAugU$FgNmQ9)Q3%F7WIg`pv=SOIZyw6?<57Fk*N;}1|MxN`@JikO{+wKWV3 z(9!}WB_t)`!2?{o209(<)%3 zi;|8g%`}{ZEI;xq>_HM zT385ithX?PK8Z>28;iMjg>51TK{IRfjZTr>Bb~FJvd;2CU-}FjSefP>q|E-JqTjW= zcT20U4J;z7CyN~Qb<9;$50cIGNId9rBtlbGM@DR0o8#t+yle|!woCU!$Y8#XUqY8V zJ*LwuvT*8K^BIMf{eH1LZdfL5lkoCn$^R)AJBCwc?>HNiud%qMg5T|)Crk;QNfaXO zGFdLMSpVP>g`p?&)A=3zG>OXOeV-?s$O3gt1(k$UDeu*-ivpZsJwuOVr}u9M}{>KQ8ZH#vq064o-~lB^R{ca{7^ zb#48oju{uS1nY|OiE&}p8mkCA@>gBi+F!=TEC4eX zqxe>N{Tf+zovT2A&)d-EQc7V&??F*lvNnHh!_kBvy@_A4Nd4IXOwR{5Cx&&=I9#s@nF#6pj>$2$Y z)oEA7%GoC2MUN{ehexWIYC3kEm8UB9DRh21@X#?qej&k{xBey$wW~Ceh0R?(tm|Ke z9usQhrjgv*ivQHM65QP|y=3Ua{Kn5xu@wh*nf&QYP8pJDHeDvYH6w-QF=}TKH?=SF zRLGdnrBs$>eckcs_eS0&k_Wv=-ss z;Wj(${^3^e5G{IY%Oi3A7MjbUZ)N?X!&<3HKSRe4%Rgo2GB*_r&EMDJr^!AmsFu={ z3!P-Bq~5(QeZ&xbkE^OQ=Y@^y2#>vyYl8h;w zSiUxc+OgCo_c*EB!VsSxn$fqJ`gRnTPg7nRxiI^d(i>t6&Yx9T&7owpl(bmJX60)h zSU%JGh=|dAkliF*XD~c&vtroRiF{QdvpYf4wQv8<>)i0;B7F3Ww$KCk#pSTAi{5qg zcUH&b&Kk2!*KZlHCs%JT$?;Do2Xb$v4A@XQ>ihU3%yuXTRPOnFgy$I(k|0~8XMM~_ zo$@}G_HZg`%dYmqzwWjd9_T#t!#gT5QtabU#^Bu+`P32-k12t6=YF2R^RvdTvm=d` zhs`*}*&aSei{$(mZb2KTN2_@zG3g1qCz%dPJpES{HXCBAzAlSOWAtb+$m3F0?;>7| zX%hzWCPB61PC4HNY_z%MI)c6ai8JM1GO7XHylyX2k?BPGM9aMI%gGZl63?^4&m3JY z)0viM)t4RDIP)h{v683s`n6f7FGV@q|6Zy5^HcnmwgG&5j$fY2*cpFrr=Q_?UQBSm zcDVb^5o)Q<)qh_v`az$k^!BzVIk@CwG^6wv<;-+efi3qp`;=n3V%N{s@W$tRJG7ax z=FwygOnqP6JhEzBv|&~{`a;i+DWNdZ{VTzGd5K$tZwF@^v>p<#)qE1y80F@-xV~BL;)s}RJx8PjiyP{ zbE49X^$d+^Gzyh!Or=Vn)z$hhASlGg-*^8%1FZYUvK9dK|3u*U2eHFA%%DC0%;|hSrKZxnaCR6E3L7VO^oFc3l_U2`qeoy=x|Jf8C literal 0 HcmV?d00001 From d39cd8661223ef058c74537a7be955cdbd09fe01 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Sat, 18 Nov 2023 22:42:00 -0800 Subject: [PATCH 40/77] add test case for OP.document_edit() with setting new item title --- .../test_document_edit/test_document_edit.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/test_op_api/test_document_edit/test_document_edit.py b/tests/test_op_api/test_document_edit/test_document_edit.py index ca1da5d1..44a1ea02 100644 --- a/tests/test_op_api/test_document_edit/test_document_edit.py +++ b/tests/test_op_api/test_document_edit/test_document_edit.py @@ -4,6 +4,7 @@ if TYPE_CHECKING: from pyonepassword import OP + from pyonepassword.api.object_types import OPDocumentItem from ...fixtures.binary_input_data import BinaryImageData @@ -89,3 +90,33 @@ def test_document_edit_02(signed_in_op: OP, binary_image_data: BinaryImageData): assert filename_2 == filename_1 # The updated document digest should now match the digest of the input file assert digest_2 == input_data_digest + + +@pytest.mark.usefixtures("setup_stateful_document_edit") +def test_document_edit_03(signed_in_op: OP, binary_image_data: BinaryImageData): + """ + Test: OP.document_edit() while setting a new item title + - Retrieve document item via OP.item_get() + - Call document_edit(), providing the new file path along with a new title + - Retreive the same item a second time + Verify: + - The title of the original document item does not match the new document title + - The title of the second retrieved itemmatches the teh new document title + """ + item_name = "example document 02" + new_item_title = "example document 02 - updated" + vault = "Test Data 2" + + input_data_path = binary_image_data.data_path_for_name( + "replacement-image-02") + document_item_1: OPDocumentItem = signed_in_op.item_get( + item_name, vault=vault) + assert document_item_1.title != new_item_title + # Provide path to the input file + # we'll test providing input bytes separately + signed_in_op.document_edit( + item_name, input_data_path, new_title=new_item_title, vault=vault) + + document_item_2: OPDocumentItem = signed_in_op.item_get( + new_item_title, vault=vault) + assert document_item_2.title == new_item_title From 13f7d65096f8cecb6b93c4d37395b3560c3cc8af Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Sun, 19 Nov 2023 18:47:54 -0800 Subject: [PATCH 41/77] updated document_edit.py ipython snippet --- ipython_snippets/document_edit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipython_snippets/document_edit.py b/ipython_snippets/document_edit.py index ca98e57e..99f858b5 100644 --- a/ipython_snippets/document_edit.py +++ b/ipython_snippets/document_edit.py @@ -8,5 +8,5 @@ print("run: op = get_op(\"document-edit\")") vault = "Test Data 2" -document_name = "no such document" +document_name = "example document 10" new_file_path = "working_data/images/replacement_image_10.png" From b27844ed86862e4f91b1ad71db7682b28a8a8d06 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Sun, 19 Nov 2023 19:21:38 -0800 Subject: [PATCH 42/77] disable query definitions for example document 02 --- .../document-edit/response-generation-document-edit-1.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg index 57d17bc0..1fb750fb 100644 --- a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg +++ b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg @@ -39,7 +39,7 @@ enabled = false type = document-get vault=Test Data 2 item-identifier = example document 02 -enabled = true +enabled = false [document-edit-example-document-02] type = document-edit @@ -48,4 +48,4 @@ document_identifier = example document 02 new-title = example document 02 - updated new-document-path = working_data/images/replacement_image_02.png changes-state = true -enabled = true +enabled = false From d8a0d05cad7cee4ff5e20c22cf0e3298fdbd4c4a Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Sun, 19 Nov 2023 19:42:46 -0800 Subject: [PATCH 43/77] add mock-op query and responses for editing example document 03 --- .../response-generation-document-edit-1.cfg | 19 +++++++++-- .../response-generation-document-edit-2.cfg | 8 ++++- .../response-directory-1.json | 23 +++++++++++++ .../response-directory-2.json | 14 ++++++++ .../error_output | 0 .../document-edit-example-document-03/output | 0 .../error_output | 0 .../output | 31 ++++++++++++++++++ .../error_output | 0 .../document-get-example-document-03/output | Bin 0 -> 1982 bytes .../error_output | 0 .../output | 30 +++++++++++++++++ .../error_output | 0 .../document-get-example-document-03/output | Bin 0 -> 2626 bytes 14 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-03/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-03/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03-filename/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03-filename/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03-filename/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03-filename/output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03/error_output create mode 100644 tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03/output diff --git a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg index 1fb750fb..c9f122fd 100644 --- a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg +++ b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-1.cfg @@ -15,11 +15,11 @@ enabled = true [list-signed-in-accounts] type = account-list -enabled = true +enabled = false [whoami] type = whoami -enabled = true +enabled = false [document-get-example-document-01] type = document-get @@ -49,3 +49,18 @@ new-title = example document 02 - updated new-document-path = working_data/images/replacement_image_02.png changes-state = true enabled = false + +[document-get-example-document-03] +type = document-get +vault=Test Data 2 +item-identifier = example document 03 +enabled = false + +[document-edit-example-document-03] +type = document-edit +vault = Test Data 2 +document_identifier = example document 03 +file-name = replacement_image_03.png +new-document-path = working_data/images/replacement_image_03.png +changes-state = true +enabled = false diff --git a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg index 13e2049f..cb2b7f0d 100644 --- a/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg +++ b/tests/config/mock-op/response-generation/document-edit/response-generation-document-edit-2.cfg @@ -23,4 +23,10 @@ enabled = false type = document-get vault=Test Data 2 item-identifier = example document 02 - updated -enabled = true +enabled = false + +[document-get-example-document-03] +type = document-get +vault=Test Data 2 +item-identifier = example document 03 +enabled = false diff --git a/tests/config/mock-op/responses-document-edit/response-directory-1.json b/tests/config/mock-op/responses-document-edit/response-directory-1.json index c6433a96..4a65bb2f 100644 --- a/tests/config/mock-op/responses-document-edit/response-directory-1.json +++ b/tests/config/mock-op/responses-document-edit/response-directory-1.json @@ -59,6 +59,20 @@ "stderr": "error_output", "name": "document-get-example-document-02-filename", "changes_state": false + }, + "--format|json|document|get|example document 03|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-03", + "changes_state": false + }, + "--format|json|item|get|example document 03|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-03-filename", + "changes_state": false } }, "commands_with_input": { @@ -79,6 +93,15 @@ "name": "document-edit-example-document-02", "changes_state": true } + }, + "cfaff0eafdc4c29a71dd009b4c996cb0": { + "--format|json|document|edit|znj7rkttvpz7femlp2wzflizgq|--file-name|replacement_image_03.png|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-edit-example-document-03", + "changes_state": true + } } } } \ No newline at end of file diff --git a/tests/config/mock-op/responses-document-edit/response-directory-2.json b/tests/config/mock-op/responses-document-edit/response-directory-2.json index 06e5d2c7..2efbb0db 100644 --- a/tests/config/mock-op/responses-document-edit/response-directory-2.json +++ b/tests/config/mock-op/responses-document-edit/response-directory-2.json @@ -38,6 +38,20 @@ "stderr": "error_output", "name": "document-get-example-document-02-updated-filename", "changes_state": false + }, + "--format|json|document|get|example document 03|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-03", + "changes_state": false + }, + "--format|json|item|get|example document 03|--vault|Test Data 2": { + "exit_status": 0, + "stdout": "output", + "stderr": "error_output", + "name": "document-get-example-document-03-filename", + "changes_state": false } }, "commands_with_input": {} diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-03/error_output b/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-03/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-03/output b/tests/config/mock-op/responses-document-edit/responses-1/document-edit-example-document-03/output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03-filename/error_output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03-filename/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03-filename/output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03-filename/output new file mode 100644 index 00000000..c3b7bcde --- /dev/null +++ b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03-filename/output @@ -0,0 +1,31 @@ +{ + "id": "znj7rkttvpz7femlp2wzflizgq", + "title": "example document 03", + "version": 5, + "vault": { + "id": "vkjyqsbkf63zycqigbg3yxd7ce", + "name": "Test Data 2" + }, + "category": "DOCUMENT", + "last_edited_by": "4J4NLDK7GFAXJFOR7RF2KDUAMI", + "created_at": "2023-11-15T03:26:37Z", + "updated_at": "2023-11-20T03:36:55Z", + "additional_information": "1 KB", + "fields": [ + { + "id": "notesPlain", + "type": "STRING", + "purpose": "NOTES", + "label": "notesPlain", + "reference": "op://Test Data 2/example document 03/notesPlain" + } + ], + "files": [ + { + "id": "lazeuf52yj2y6rwsv7zgw5mf4i", + "name": "image_03.png", + "size": 1982, + "content_path": "/v1/vaults/vkjyqsbkf63zycqigbg3yxd7ce/items/znj7rkttvpz7femlp2wzflizgq/files/lazeuf52yj2y6rwsv7zgw5mf4i/content" + } + ] +} diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03/error_output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03/output b/tests/config/mock-op/responses-document-edit/responses-1/document-get-example-document-03/output new file mode 100644 index 0000000000000000000000000000000000000000..ff701af8382e97f6d144296bc6ab1321c6d335dc GIT binary patch literal 1982 zcmaKtdo=5T}sqj5>{(0AW|2Sv=@qG8*&-$#r*V@lsPolGvtu$Gg zOb~=L-EOZ7L5QV@e5S-I(V4U1CmWGy9Jh0EB#6`B5kzz>L3|OVqQ?m$ghCL)qXc1= zNf1gwSNI2Z5d`UovxBP*2m(Gn5Ls0fVsR0} z!`QeHPo7|Y9^KuTnSqfJ=yZJjig)iI5a8oSOih78L3lV^T~SvDIXOs5A}0rfgIK*9 zn>HaX4(ryTs0btyw6(Fag1I@YUyoI*(AS4UhY%c$)>e?ou(CpIEN8>Xgs{~l}CVsa9D_Tb7DczPl?7ZVe>cMn&u!rvdCKHpnl)%di?(W#P53{of4TXULmX;70h{{TQ_<)QINJ+uk z8q?EYFtB|)_Q$$vAm3=B;33S2?<=fggbX|_%NP5Lt`U`hQQ$< zCI*FtIDHzgUct=`Terf{5bEl1c1A-3xLjCRfW<;W0;HwU+Y5Vp&}h)oLU}pv-^Z?9 z*t{9fpF=?b(b4er1(k|5YjF88G&KFs?tU#KWzKk*vduEWu6A z_A&DxMg+1AA0Mp~WW^hryq`*vlmA=mB2FdbT(gp_R4}J^e80d9^~Gtg65@ai2YtC={rC-q!Jt(NxrBxjERe&bFz zx-X-S>Z*6Yaf^Mq>oo7-{m8)8miV?xy>t&AR$?R{H!4GZ^Pj%sq_@>4}`A z9nGIuc>X|=*|)YoJf=&K7b;bLP&GovZk9$k3K>-;iqx})${`y5Bp<wmAWrk4K646=ATZH_ITgmvTe_>!_GB$CYh$nEQWeKpuKA~NFC1YHE(liQqoDu zP@7vwoRb}`_Q^7CD1D&ed~6`{AJLIt9mB?~Qg^?ostH>q-ruCtpczbAs&})fA=MM5Xp&+mcck0A!cN8` z=E9Z$@OV25jtU*+yP6@BlhI1xc$!~g{S|`>U9E$mupY4rnQ!f5? z%BDljLs6O=zyC3Jr)Tzm|J?>bfF7J3#AG$U9 z&?Mc$VE>cPYL*%H1JV~5w5|@hvr}oKT`o&Z(R>r@;`GE6qE<9xUl%Ev^Xi1wm(Hqw zeSCf}(P;F^DD$dR$&BN=>$aAIe2#p3r*(KcH_SlML~f$?(p&nMlIC9Cz|2T|rN1B~ z;NFptmT~oxt|rTPe&IL#@SQ#BH4ho@%23_b7v$5*<(P~}KBq)V7N~p}8W}p-7TkB) zs*~-or0)`;yb763iY~^Usb>OCZ6fU`EQ<|zP19QYpL31w4*wSayVdO43ep$t2E$To zS<%NvXmV{lxJ)lD%j|eCOC*Fb#n?pO$VlIa>Pj&-qi#1dGSa0`%qSFvoNWgG2e1Q~ zzTOdk4IFQ|kR}4O|5t(Q%Vu%7UhJU1X0{EK{MnVvpG<()F;)QK%l10K(x8}pj?fJf P-4Jver@f_CNB{c=_)+I} literal 0 HcmV?d00001 diff --git a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03-filename/error_output b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03-filename/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03-filename/output b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03-filename/output new file mode 100644 index 00000000..c7ead150 --- /dev/null +++ b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03-filename/output @@ -0,0 +1,30 @@ +{ + "id": "znj7rkttvpz7femlp2wzflizgq", + "title": "example document 03", + "version": 6, + "vault": { + "id": "vkjyqsbkf63zycqigbg3yxd7ce", + "name": "Test Data 2" + }, + "category": "DOCUMENT", + "last_edited_by": "FZTDCNIJAOEBZZ2VQFNDVHC3K6", + "created_at": "2023-11-15T03:26:37Z", + "updated_at": "2023-11-20T03:37:05Z", + "fields": [ + { + "id": "notesPlain", + "type": "STRING", + "purpose": "NOTES", + "label": "notesPlain", + "reference": "op://Test Data 2/example document 03/notesPlain" + } + ], + "files": [ + { + "id": "7bzfthc5o2t25gkmnygjukj24i", + "name": "replacement_image_03.png", + "size": 2626, + "content_path": "/v1/vaults/vkjyqsbkf63zycqigbg3yxd7ce/items/znj7rkttvpz7femlp2wzflizgq/files/7bzfthc5o2t25gkmnygjukj24i/content" + } + ] +} diff --git a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03/error_output b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03/error_output new file mode 100644 index 00000000..e69de29b diff --git a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03/output b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-03/output new file mode 100644 index 0000000000000000000000000000000000000000..614e2d02699a0024297a348a07ade932bf6477ef GIT binary patch literal 2626 zcmb7`X*AW_8^?bc;t+*U##4wQ9b>Li#*mUZN2B53#EFZfB$OLza@~v(skoV^3L#{c z5Hf|3YbZk^34QOmZ~kljU)&e>S$jRt-h1uO`mVj6XYKu5H#0Tl;S%8@2!hAhNZ*1W z)8HNXn=zQe0*SNi1+W&*a&H9#KvN95KBvV`V{W&2nxdX?a0f+moKQV$H|j0 zHAQwdK7PdQ+mMw-bTkSIprr+IaU>^Wd>r4t!PXWX9T*!!TpTW4g0L_~MsVj2Hg3e- zyV$=Us;a1{z>61PFrcoEnHhZg1RWj3#9(m|0|N*R#oQdKs<5(xloTW;!rUCMUt?kd zmX=6JfSny4Jix10=<0%_Bi!6@=n$Hl(borSYaBcX7Z-4ILr)J=Q=n3@bt?`WfUhrh z?gR%1va(=rkE2J?(}R8cK%+rX5gs1U&_GEEL_`o3h3C(4;skc>!XJNNbrs>^P*6ZX z0Gyri z^71Gx#qQk@6~)!7sH;P5Epl_QcQ5$)L8n7a4KgxdXGdTl-n_x%$Kd6Km>8ZtgOn8f z{h^|Q@^aj}hg-K$S&5<|G&RA<2=VdI*GGCf1O?$%u5z7O#A_T(4E2dHc5x%-g2Tu7 zumQ&y_j(phZfcLWEE z~qow8oX5RJGj4Yccjt8?oTM3*Gy>Jw0}#x=CAyN_OdQCS*<-fs-`+`I_RY0 z_N0Q`XzjT<7pJtkjdIJ5LtoARdK9;--mSSvvA|ilnE#Yh^mgypHQo;w#81ZWUK;(J zxg>KlO1Cw?q)Ds#d64tu(Go#w+M>T8cj+T*pvE>;Pxtt~b+?N#ox}s#kGi$9n z*(Q?CDdN4NaEF8>A#);4a})PXVI=_52f7hSfL-))TRmh*iGdiXSl zdgk|5*L$lZwmyR;zDcK5!k7D00!LJ%ms*70Lg;8+XzL$&uf})DOSN|Ti|zZXYdJ_N zg(0@Djr)jTR8MUGNwVge<_<&i9obXnTQ}S)JXq$!=c6ZasYj_?@pku_!sefB`NyM^ zhE=G%o{s#Bqux}~PQ9xoPQUfintr`h*&Wj@BY#U)VPGV^`kdNE72jlI*}aA~@t*mK z+Vd=oG~bVn6`S_Ru(TOv#Co<0ghd{DsKroxe`@nofn;!f+N!Fjb4hhbPVufmxup9# z_gyTX&-D1K?_am6%64=4!n#F?^QNkEqq^CAdX$r04@}PmI`0V{XH&J@z4hdUhhZbZ zu8*ySM)q3Da2+e`+PdSF>q7*P`BI94Y@T_ZD!1IXD#3AATjB7f8wLTx2Gd-DmqoQ+ zmDQ~#$G7#3q_yydFYjY*Be|wdv)_BW%)ee=J}dIN26gW6s@Dx)5xYR$%G)AFK7AbF z%NEJUt7mg$SsQd#D-y>z3Z&jgS;?NNw<@ihSefss%+c;OJrQb0|@zpft3J)}UjHv2i+oqxJ? zQKKxWT=Tm?nDb-?t&uN;A>bc&z-}~NL(%iwjhZ~$vbKoO8R4oHt>(F&COs-?u||4u zy?P4u7aEU+>Hg32>)Oh!O4+?9BSy4LCBt%Fz-CT93 z`I4b9a2h>Bl6dzOl5K24oEMcUGM}9y7B=gucFgw$IGQUo`Ic zQnKjFE@eYWSsP}m2ZM7DI~VOx4&LKCWO7%&{1>jG+K$DDA?$D zk^NP-FTosZht(F!yz{beM2XfEQ>FT=MwjeU>&+*913&#dWBH}+>wy<5fnUB0l_pd% z9(rtvVDliKyWWUrqLkY4VA9x;}7aBgl-XwJAoAEs) zxk^#a7j0=Nwec1gYsQ!V!|Qz|B#`)hs^eVFH=AhYpCjXAVC&;#??cmc^rA5Xp-fR$ z*{P(oQ%TK=qO7T=p{b-KPoZd1DEvvPivI^NJe=sx7ycb^thyP=1mymw;6rE7ynXB$ zp8w9Mc4aZ!JVN9j#@*h5=1zFgJl*XbX$;y~A2OX`??NL}RNT*a*)UHL#s;SP*}A8% F{0$ERH2MGl literal 0 HcmV?d00001 From 6872f2f032d8b526ea0db2021170305b386c486a Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Sun, 19 Nov 2023 19:43:27 -0800 Subject: [PATCH 44/77] add replacement-image-03 to binary image data registry --- tests/data/test-input-data/binary-data/images/registry.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/data/test-input-data/binary-data/images/registry.json b/tests/data/test-input-data/binary-data/images/registry.json index 0a306f80..9058d26d 100644 --- a/tests/data/test-input-data/binary-data/images/registry.json +++ b/tests/data/test-input-data/binary-data/images/registry.json @@ -6,5 +6,9 @@ "replacement-image-02": { "name": "replacement_image_02.png", "type": "binary" + }, + "replacement-image-03": { + "name": "replacement_image_03.png", + "type": "binary" } } From 9114954547809d9d3eda92cbc3d3d24157de4220 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Sun, 19 Nov 2023 19:47:44 -0800 Subject: [PATCH 45/77] fix minor docstring typo --- tests/test_op_api/test_document_edit/test_document_edit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_op_api/test_document_edit/test_document_edit.py b/tests/test_op_api/test_document_edit/test_document_edit.py index 44a1ea02..17f432f2 100644 --- a/tests/test_op_api/test_document_edit/test_document_edit.py +++ b/tests/test_op_api/test_document_edit/test_document_edit.py @@ -101,7 +101,7 @@ def test_document_edit_03(signed_in_op: OP, binary_image_data: BinaryImageData): - Retreive the same item a second time Verify: - The title of the original document item does not match the new document title - - The title of the second retrieved itemmatches the teh new document title + - The title of the second retrieved item matches the the new document title """ item_name = "example document 02" new_item_title = "example document 02 - updated" From c1ad2b0a593eff8705693c93f1081b61b31bbdd2 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Sun, 19 Nov 2023 19:54:56 -0800 Subject: [PATCH 46/77] add test case for OP.document_edit() with setting new filename --- .../test_document_edit/test_document_edit.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/test_op_api/test_document_edit/test_document_edit.py b/tests/test_op_api/test_document_edit/test_document_edit.py index 17f432f2..f2be749c 100644 --- a/tests/test_op_api/test_document_edit/test_document_edit.py +++ b/tests/test_op_api/test_document_edit/test_document_edit.py @@ -120,3 +120,34 @@ def test_document_edit_03(signed_in_op: OP, binary_image_data: BinaryImageData): document_item_2: OPDocumentItem = signed_in_op.item_get( new_item_title, vault=vault) assert document_item_2.title == new_item_title + + +@pytest.mark.usefixtures("setup_stateful_document_edit") +def test_document_edit_04(signed_in_op: OP, binary_image_data: BinaryImageData): + """ + Test: OP.document_edit() while setting a new filename + - Retrieve document item via OP.item_get() + - Call document_edit(), providing the new file path along with a new filename + - Retreive the same item a second time + Verify: + - The filename of the original document item does not match the new filename + - The filename of the second retrieved item matches the the new document filename + """ + item_name = "example document 03" + vault = "Test Data 2" + + input_data_path = binary_image_data.data_path_for_name( + "replacement-image-03") + new_file_name = input_data_path.name + + document_item_1: OPDocumentItem = signed_in_op.item_get( + item_name, vault=vault) + assert document_item_1.file_name != new_file_name + # Provide path to the input file + # we'll test providing input bytes separately + signed_in_op.document_edit( + item_name, input_data_path, file_name=new_file_name, vault=vault) + + document_item_2: OPDocumentItem = signed_in_op.item_get( + item_name, vault=vault) + assert document_item_2.file_name == new_file_name From 81a10f428b2c2d0705ed0e8a0f35494c4a29d804 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Sun, 19 Nov 2023 19:56:15 -0800 Subject: [PATCH 47/77] updated a couple response output files --- .../document-get-example-document-01-filename/output | 2 +- .../document-get-example-document-02-updated-filename/output | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-01-filename/output b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-01-filename/output index 10a6f4e7..563eae77 100644 --- a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-01-filename/output +++ b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-01-filename/output @@ -7,7 +7,7 @@ "name": "Test Data 2" }, "category": "DOCUMENT", - "last_edited_by": "A47WW2CN6BEMDDS7RXRKBFQIZ4", + "last_edited_by": "FZTDCNIJAOEBZZ2VQFNDVHC3K6", "created_at": "2023-11-15T03:26:35Z", "updated_at": "2023-11-15T06:09:25Z", "fields": [ diff --git a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/output b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/output index 9f432bfa..974d4060 100644 --- a/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/output +++ b/tests/config/mock-op/responses-document-edit/responses-2/document-get-example-document-02-updated-filename/output @@ -7,7 +7,7 @@ "name": "Test Data 2" }, "category": "DOCUMENT", - "last_edited_by": "A47WW2CN6BEMDDS7RXRKBFQIZ4", + "last_edited_by": "FZTDCNIJAOEBZZ2VQFNDVHC3K6", "created_at": "2023-11-15T03:26:36Z", "updated_at": "2023-11-19T03:20:20Z", "fields": [ From cd85aedcc8e81b36141cd70a783dbdc038b2d620 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Wed, 22 Nov 2023 17:09:21 -0800 Subject: [PATCH 48/77] add document_editing.py example --- examples/document_editing.py | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 examples/document_editing.py diff --git a/examples/document_editing.py b/examples/document_editing.py new file mode 100644 index 00000000..7eececf7 --- /dev/null +++ b/examples/document_editing.py @@ -0,0 +1,38 @@ +from pathlib import Path + +from pyonepassword import OP + + +def replace_document(): + op = OP() + document_title = "example document 01" + replacement_file_path = "path/to/replacement_image_01.png" + + op.document_edit(document_title, replacement_file_path) + + # or replacmenet document can be bytes instead of str/Path: + replacement_bytes = open(replacement_file_path, "rb").read() + + op.document_edit(document_title, replacement_bytes) + + +def replace_document_set_title(): + op = OP() + document_title = "example document 01" + replacement_file_path = "path/to/replacement_image_01.png" + new_document_title = "updated example document 01" + op.document_edit(document_title, replacement_file_path, + new_title=new_document_title) + + +def replace_document_set_filename(): + op = OP() + document_title = "example document 01" + + # replacement path may be Path or str + replacement_file_path = Path("path/to/replacement_image_01.png") + + # get basename: "replacement_image_01.png" + new_document_filename = replacement_file_path.name + op.document_edit(document_title, replacement_file_path, + file_name=new_document_filename) From bd7feb19c6dacf77854df248b02405273942b57d Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Mon, 27 Nov 2023 15:33:28 -0800 Subject: [PATCH 49/77] add document-editing.md --- docs/document-editing.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docs/document-editing.md diff --git a/docs/document-editing.md b/docs/document-editing.md new file mode 100644 index 00000000..cc59a119 --- /dev/null +++ b/docs/document-editing.md @@ -0,0 +1,22 @@ +# PYONEPASSWORD DOCUMENT EDITING + +## Description +As of version 4.1.0, `pyonepassword` supports in-place document editing. There is API to match the operations supported by the `op document edit` command. + +The API for document editing is the `OP.docuemnt_edit()` method. This method replaces the bytes of an existing document item with the contents of a new file. + +The `document_edit()` method takes two mandatory arguments: + +- `document_identitifer`: A string representing the title or unique ID of a document item +- `file_path_or_document_bytes`: This is what the document should be replaced with. It may be either: + - A `str` or `Path` object referencing existing file on disk to read + - A `bytes` object that is the new file's contents + +Additionally, you may *also* change the document item's: + + - filename via the `file_name=` kwarg + - title via the `new_title=` kwarg + +**Note**: You may not set a new filename or document item title via document_edit() without also specifying a path or bytes to set the document's contents to. This is not supported by `op document edit`. If this behavior is required, the equivalent would be to provide the original document's contents + +## Examples From d63325541c400f6e58e30e434e06e1eec2cda82c Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Mon, 27 Nov 2023 15:33:52 -0800 Subject: [PATCH 50/77] add section to README on document editing --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 73892c24..e3644b2c 100644 --- a/README.md +++ b/README.md @@ -352,6 +352,12 @@ For details on editing existing items in a 1Password vault, see [item-editing.md Also see the examles in [examples/item_editing](examples/item_editing/) +### Document Editing + +For details on editing existing document item file contents, see [document-editing.md](docs/document-editing.md) + +See examples in [examples/document_editing](examples/document_editing.py) + ### More Examples Lots more examples are available in the `examples` directory From 263b29e777fcea240af86ccfb018c2dcd8d07a49 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Mon, 27 Nov 2023 15:39:11 -0800 Subject: [PATCH 51/77] added documentation about OP.document_edit() return value --- docs/document-editing.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/document-editing.md b/docs/document-editing.md index cc59a119..275d5e53 100644 --- a/docs/document-editing.md +++ b/docs/document-editing.md @@ -5,6 +5,8 @@ As of version 4.1.0, `pyonepassword` supports in-place document editing. There i The API for document editing is the `OP.docuemnt_edit()` method. This method replaces the bytes of an existing document item with the contents of a new file. + +## Use and arguments The `document_edit()` method takes two mandatory arguments: - `document_identitifer`: A string representing the title or unique ID of a document item @@ -19,4 +21,6 @@ Additionally, you may *also* change the document item's: **Note**: You may not set a new filename or document item title via document_edit() without also specifying a path or bytes to set the document's contents to. This is not supported by `op document edit`. If this behavior is required, the equivalent would be to provide the original document's contents -## Examples +### Return value + +If successful, the `document_edit()` function returns a string representing the unique ID of the document item edited. This may be useful for confirming the expected document item is the one that was edited, in the event a document title was provided. From ec8d77931b273ddde7c8b94aaa2f1c8e937fa024 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Mon, 27 Nov 2023 15:47:31 -0800 Subject: [PATCH 52/77] update CHANGELOG for work in progress --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7a4a276..f67a0964 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ All notable changes to this project will be documented in this file. +## [DEVELOPMENT] 2023-11-27 + +### Added + +- Document editing (gh-150): + - `OP.document_edit()` + +### Documentation +- Describe document editing in `docs/document-editing.md` +- Added set of document editing examples under `examples/document_editing` + ## [4.0.0] 2023-11-15 ### Fixed From 79745b7ac50da57a3957f631e82ae091c98091f4 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 10:55:03 -0800 Subject: [PATCH 53/77] bump version to 4.1.0 --- pyonepassword/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyonepassword/__about__.py b/pyonepassword/__about__.py index 6ca31d2d..92db4692 100644 --- a/pyonepassword/__about__.py +++ b/pyonepassword/__about__.py @@ -1,5 +1,5 @@ __title__ = "pyonepassword" -__version__ = "4.1.0.dev0" +__version__ = "4.1.0" __summary__ = "A python API to query a 1Password account using the 'op' command-line tool" """ From cddbbec73f4dd19ac25b4e7041acc7fce9ac6aa1 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:02:22 -0800 Subject: [PATCH 54/77] move test_item_edit under test_op_api --- tests/{ => test_op_api}/test_item_edit/test_field_assignment.py | 0 tests/{ => test_op_api}/test_item_edit/test_item_edit.py | 0 .../{ => test_op_api}/test_item_edit/test_item_edit_add_field.py | 0 .../test_item_edit/test_item_edit_delete_field.py | 0 tests/{ => test_op_api}/test_item_edit/test_item_edit_errors.py | 0 .../test_item_edit/test_item_edit_set_field_value.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/{ => test_op_api}/test_item_edit/test_field_assignment.py (100%) rename tests/{ => test_op_api}/test_item_edit/test_item_edit.py (100%) rename tests/{ => test_op_api}/test_item_edit/test_item_edit_add_field.py (100%) rename tests/{ => test_op_api}/test_item_edit/test_item_edit_delete_field.py (100%) rename tests/{ => test_op_api}/test_item_edit/test_item_edit_errors.py (100%) rename tests/{ => test_op_api}/test_item_edit/test_item_edit_set_field_value.py (100%) diff --git a/tests/test_item_edit/test_field_assignment.py b/tests/test_op_api/test_item_edit/test_field_assignment.py similarity index 100% rename from tests/test_item_edit/test_field_assignment.py rename to tests/test_op_api/test_item_edit/test_field_assignment.py diff --git a/tests/test_item_edit/test_item_edit.py b/tests/test_op_api/test_item_edit/test_item_edit.py similarity index 100% rename from tests/test_item_edit/test_item_edit.py rename to tests/test_op_api/test_item_edit/test_item_edit.py diff --git a/tests/test_item_edit/test_item_edit_add_field.py b/tests/test_op_api/test_item_edit/test_item_edit_add_field.py similarity index 100% rename from tests/test_item_edit/test_item_edit_add_field.py rename to tests/test_op_api/test_item_edit/test_item_edit_add_field.py diff --git a/tests/test_item_edit/test_item_edit_delete_field.py b/tests/test_op_api/test_item_edit/test_item_edit_delete_field.py similarity index 100% rename from tests/test_item_edit/test_item_edit_delete_field.py rename to tests/test_op_api/test_item_edit/test_item_edit_delete_field.py diff --git a/tests/test_item_edit/test_item_edit_errors.py b/tests/test_op_api/test_item_edit/test_item_edit_errors.py similarity index 100% rename from tests/test_item_edit/test_item_edit_errors.py rename to tests/test_op_api/test_item_edit/test_item_edit_errors.py diff --git a/tests/test_item_edit/test_item_edit_set_field_value.py b/tests/test_op_api/test_item_edit/test_item_edit_set_field_value.py similarity index 100% rename from tests/test_item_edit/test_item_edit_set_field_value.py rename to tests/test_op_api/test_item_edit/test_item_edit_set_field_value.py From 1ba1ea696ba5b5f53a1261b3ad1d837259cd0c82 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:02:47 -0800 Subject: [PATCH 55/77] move test_user_list under test_op_api --- tests/{ => test_op_api}/test_user_list/test_user_list_all.py | 0 tests/{ => test_op_api}/test_user_list/test_user_list_group.py | 0 tests/{ => test_op_api}/test_user_list/test_user_list_vault.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/{ => test_op_api}/test_user_list/test_user_list_all.py (100%) rename tests/{ => test_op_api}/test_user_list/test_user_list_group.py (100%) rename tests/{ => test_op_api}/test_user_list/test_user_list_vault.py (100%) diff --git a/tests/test_user_list/test_user_list_all.py b/tests/test_op_api/test_user_list/test_user_list_all.py similarity index 100% rename from tests/test_user_list/test_user_list_all.py rename to tests/test_op_api/test_user_list/test_user_list_all.py diff --git a/tests/test_user_list/test_user_list_group.py b/tests/test_op_api/test_user_list/test_user_list_group.py similarity index 100% rename from tests/test_user_list/test_user_list_group.py rename to tests/test_op_api/test_user_list/test_user_list_group.py diff --git a/tests/test_user_list/test_user_list_vault.py b/tests/test_op_api/test_user_list/test_user_list_vault.py similarity index 100% rename from tests/test_user_list/test_user_list_vault.py rename to tests/test_op_api/test_user_list/test_user_list_vault.py From 3e0177cedaf5b942c54ba4c32bb1a370831958e1 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:03:04 -0800 Subject: [PATCH 56/77] move test_vault_list under test_op_api --- tests/{ => test_op_api}/test_vault_list/test_vault_list_all.py | 0 .../{ => test_op_api}/test_vault_list/test_vault_list_error.py | 0 .../{ => test_op_api}/test_vault_list/test_vault_list_group.py | 2 +- tests/{ => test_op_api}/test_vault_list/test_vault_list_user.py | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename tests/{ => test_op_api}/test_vault_list/test_vault_list_all.py (100%) rename tests/{ => test_op_api}/test_vault_list/test_vault_list_error.py (100%) rename tests/{ => test_op_api}/test_vault_list/test_vault_list_group.py (97%) rename tests/{ => test_op_api}/test_vault_list/test_vault_list_user.py (100%) diff --git a/tests/test_vault_list/test_vault_list_all.py b/tests/test_op_api/test_vault_list/test_vault_list_all.py similarity index 100% rename from tests/test_vault_list/test_vault_list_all.py rename to tests/test_op_api/test_vault_list/test_vault_list_all.py diff --git a/tests/test_vault_list/test_vault_list_error.py b/tests/test_op_api/test_vault_list/test_vault_list_error.py similarity index 100% rename from tests/test_vault_list/test_vault_list_error.py rename to tests/test_op_api/test_vault_list/test_vault_list_error.py diff --git a/tests/test_vault_list/test_vault_list_group.py b/tests/test_op_api/test_vault_list/test_vault_list_group.py similarity index 97% rename from tests/test_vault_list/test_vault_list_group.py rename to tests/test_op_api/test_vault_list/test_vault_list_group.py index c205163f..7c861456 100644 --- a/tests/test_vault_list/test_vault_list_group.py +++ b/tests/test_op_api/test_vault_list/test_vault_list_group.py @@ -10,7 +10,7 @@ if TYPE_CHECKING: from pyonepassword import OP - from ..fixtures.expected_vault_data import ( + from ...fixtures.expected_vault_data import ( ExpectedVaultListData, ExpectedVaultListEntry ) diff --git a/tests/test_vault_list/test_vault_list_user.py b/tests/test_op_api/test_vault_list/test_vault_list_user.py similarity index 100% rename from tests/test_vault_list/test_vault_list_user.py rename to tests/test_op_api/test_vault_list/test_vault_list_user.py From 702284c1882e76015093db2cc4615ac5a65f99f9 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:03:36 -0800 Subject: [PATCH 57/77] move test modules for document delete/get under test_op_api --- tests/{ => test_op_api}/test_document_delete.py | 4 ++-- tests/{ => test_op_api}/test_document_get.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename tests/{ => test_op_api}/test_document_delete.py (97%) rename tests/{ => test_op_api}/test_document_get.py (98%) diff --git a/tests/test_document_delete.py b/tests/test_op_api/test_document_delete.py similarity index 97% rename from tests/test_document_delete.py rename to tests/test_op_api/test_document_delete.py index 7aa6dfb9..5e104dfc 100644 --- a/tests/test_document_delete.py +++ b/tests/test_op_api/test_document_delete.py @@ -14,9 +14,9 @@ if TYPE_CHECKING: from pyonepassword import OP - from .fixtures.expected_document_data import ExpectedDocumentData + from ..fixtures.expected_document_data import ExpectedDocumentData -from .test_support.util import digest +from ..test_support.util import digest # ensure HOME env variable is set, and there's a valid op config present pytestmark = pytest.mark.usefixtures("valid_op_cli_config_homedir") diff --git a/tests/test_document_get.py b/tests/test_op_api/test_document_get.py similarity index 98% rename from tests/test_document_get.py rename to tests/test_op_api/test_document_get.py index 3222c23d..bb0c57dc 100644 --- a/tests/test_document_get.py +++ b/tests/test_op_api/test_document_get.py @@ -13,7 +13,7 @@ ) from pyonepassword.api.object_types import OPDocumentFile, OPDocumentItem -from .test_support.util import digest +from ..test_support.util import digest pytestmark = pytest.mark.usefixtures("valid_op_cli_config_homedir") From 80d834272741d685304ddd27896efb79dacc8d95 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:04:09 -0800 Subject: [PATCH 58/77] move test modules for item delete under test_op_api --- tests/{ => test_op_api}/test_item_delete.py | 0 tests/{ => test_op_api}/test_item_delete_multiple.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/{ => test_op_api}/test_item_delete.py (100%) rename tests/{ => test_op_api}/test_item_delete_multiple.py (100%) diff --git a/tests/test_item_delete.py b/tests/test_op_api/test_item_delete.py similarity index 100% rename from tests/test_item_delete.py rename to tests/test_op_api/test_item_delete.py diff --git a/tests/test_item_delete_multiple.py b/tests/test_op_api/test_item_delete_multiple.py similarity index 100% rename from tests/test_item_delete_multiple.py rename to tests/test_op_api/test_item_delete_multiple.py From 720376dd1868ef671eb51840745935be48e3d53a Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:04:52 -0800 Subject: [PATCH 59/77] Revert "bump version to 4.1.0" This reverts commit 79745b7ac50da57a3957f631e82ae091c98091f4. --- pyonepassword/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyonepassword/__about__.py b/pyonepassword/__about__.py index 92db4692..6ca31d2d 100644 --- a/pyonepassword/__about__.py +++ b/pyonepassword/__about__.py @@ -1,5 +1,5 @@ __title__ = "pyonepassword" -__version__ = "4.1.0" +__version__ = "4.1.0.dev0" __summary__ = "A python API to query a 1Password account using the 'op' command-line tool" """ From bc850f5975961d823c1dbf26f24e43ae2da68e2e Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:05:21 -0800 Subject: [PATCH 60/77] move test_vault_get under test_op_api --- tests/{ => test_op_api}/test_vault_get.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/{ => test_op_api}/test_vault_get.py (96%) diff --git a/tests/test_vault_get.py b/tests/test_op_api/test_vault_get.py similarity index 96% rename from tests/test_vault_get.py rename to tests/test_op_api/test_vault_get.py index 6372fdd3..0b5882f6 100644 --- a/tests/test_vault_get.py +++ b/tests/test_op_api/test_vault_get.py @@ -6,7 +6,7 @@ if TYPE_CHECKING: from pyonepassword import OP - from .fixtures.expected_vault_data import ( + from ..fixtures.expected_vault_data import ( ExpectedVaultData, ExpectedVault ) From c60d6e1139195ff6b312c3b32d6576163009fc84 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:08:24 -0800 Subject: [PATCH 61/77] create nested subdirectories under test_op_api: - item/edit - move item edit tests under appropriate subdirectories --- .../{test_item_edit => item/edit}/test_field_assignment.py | 0 tests/test_op_api/{test_item_edit => item/edit}/test_item_edit.py | 0 .../{test_item_edit => item/edit}/test_item_edit_add_field.py | 0 .../{test_item_edit => item/edit}/test_item_edit_delete_field.py | 0 .../{test_item_edit => item/edit}/test_item_edit_errors.py | 0 .../edit}/test_item_edit_set_field_value.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/test_op_api/{test_item_edit => item/edit}/test_field_assignment.py (100%) rename tests/test_op_api/{test_item_edit => item/edit}/test_item_edit.py (100%) rename tests/test_op_api/{test_item_edit => item/edit}/test_item_edit_add_field.py (100%) rename tests/test_op_api/{test_item_edit => item/edit}/test_item_edit_delete_field.py (100%) rename tests/test_op_api/{test_item_edit => item/edit}/test_item_edit_errors.py (100%) rename tests/test_op_api/{test_item_edit => item/edit}/test_item_edit_set_field_value.py (100%) diff --git a/tests/test_op_api/test_item_edit/test_field_assignment.py b/tests/test_op_api/item/edit/test_field_assignment.py similarity index 100% rename from tests/test_op_api/test_item_edit/test_field_assignment.py rename to tests/test_op_api/item/edit/test_field_assignment.py diff --git a/tests/test_op_api/test_item_edit/test_item_edit.py b/tests/test_op_api/item/edit/test_item_edit.py similarity index 100% rename from tests/test_op_api/test_item_edit/test_item_edit.py rename to tests/test_op_api/item/edit/test_item_edit.py diff --git a/tests/test_op_api/test_item_edit/test_item_edit_add_field.py b/tests/test_op_api/item/edit/test_item_edit_add_field.py similarity index 100% rename from tests/test_op_api/test_item_edit/test_item_edit_add_field.py rename to tests/test_op_api/item/edit/test_item_edit_add_field.py diff --git a/tests/test_op_api/test_item_edit/test_item_edit_delete_field.py b/tests/test_op_api/item/edit/test_item_edit_delete_field.py similarity index 100% rename from tests/test_op_api/test_item_edit/test_item_edit_delete_field.py rename to tests/test_op_api/item/edit/test_item_edit_delete_field.py diff --git a/tests/test_op_api/test_item_edit/test_item_edit_errors.py b/tests/test_op_api/item/edit/test_item_edit_errors.py similarity index 100% rename from tests/test_op_api/test_item_edit/test_item_edit_errors.py rename to tests/test_op_api/item/edit/test_item_edit_errors.py diff --git a/tests/test_op_api/test_item_edit/test_item_edit_set_field_value.py b/tests/test_op_api/item/edit/test_item_edit_set_field_value.py similarity index 100% rename from tests/test_op_api/test_item_edit/test_item_edit_set_field_value.py rename to tests/test_op_api/item/edit/test_item_edit_set_field_value.py From eaf3b72994e851b5757c6f2fdd366954fec3f83f Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:11:31 -0800 Subject: [PATCH 62/77] move "item get" test modules under test_op_api/item/get --- tests/test_op_api/{ => item/get}/test_item_get_login.py | 4 ++-- tests/test_op_api/{ => item/get}/test_item_get_totp.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename tests/test_op_api/{ => item/get}/test_item_get_login.py (96%) rename tests/test_op_api/{ => item/get}/test_item_get_totp.py (97%) diff --git a/tests/test_op_api/test_item_get_login.py b/tests/test_op_api/item/get/test_item_get_login.py similarity index 96% rename from tests/test_op_api/test_item_get_login.py rename to tests/test_op_api/item/get/test_item_get_login.py index 6a93be09..4bb92926 100644 --- a/tests/test_op_api/test_item_get_login.py +++ b/tests/test_op_api/item/get/test_item_get_login.py @@ -7,8 +7,8 @@ if TYPE_CHECKING: from pyonepassword import OP - from ..fixtures.expected_item import ExpectedItemData - from ..fixtures.expected_login import ExpectedLoginItemData + from ....fixtures.expected_item import ExpectedItemData + from ....fixtures.expected_login import ExpectedLoginItemData from pyonepassword.api.exceptions import OPItemGetException from pyonepassword.api.object_types import OPLoginItem diff --git a/tests/test_op_api/test_item_get_totp.py b/tests/test_op_api/item/get/test_item_get_totp.py similarity index 97% rename from tests/test_op_api/test_item_get_totp.py rename to tests/test_op_api/item/get/test_item_get_totp.py index 1218f6b2..51a751ee 100644 --- a/tests/test_op_api/test_item_get_totp.py +++ b/tests/test_op_api/item/get/test_item_get_totp.py @@ -10,7 +10,7 @@ # circular imports. # this also reduced exercising tested code simply by importing if TYPE_CHECKING: - from ..fixtures.expected_totp_data import ExpectedTOTP, ExpectedTOTPData + from ....fixtures.expected_totp_data import ExpectedTOTP, ExpectedTOTPData from pyonepassword import OP from pyonepassword.api.exceptions import OPItemGetException From bdceb78058d0252a5e5ababfd7d20a7b4dbd1a47 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:14:24 -0800 Subject: [PATCH 63/77] move "document edit" test modules under test_op_api/document/edit --- .../test_op_api/{test_document_edit => document}/__init__.py | 0 tests/test_op_api/document/edit/__init__.py | 0 .../edit}/test_document_edit.py | 4 ++-- .../edit}/test_document_edit_errors.py | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename tests/test_op_api/{test_document_edit => document}/__init__.py (100%) create mode 100644 tests/test_op_api/document/edit/__init__.py rename tests/test_op_api/{test_document_edit => document/edit}/test_document_edit.py (98%) rename tests/test_op_api/{test_document_edit => document/edit}/test_document_edit_errors.py (91%) diff --git a/tests/test_op_api/test_document_edit/__init__.py b/tests/test_op_api/document/__init__.py similarity index 100% rename from tests/test_op_api/test_document_edit/__init__.py rename to tests/test_op_api/document/__init__.py diff --git a/tests/test_op_api/document/edit/__init__.py b/tests/test_op_api/document/edit/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_op_api/test_document_edit/test_document_edit.py b/tests/test_op_api/document/edit/test_document_edit.py similarity index 98% rename from tests/test_op_api/test_document_edit/test_document_edit.py rename to tests/test_op_api/document/edit/test_document_edit.py index f2be749c..9815f485 100644 --- a/tests/test_op_api/test_document_edit/test_document_edit.py +++ b/tests/test_op_api/document/edit/test_document_edit.py @@ -6,11 +6,11 @@ from pyonepassword import OP from pyonepassword.api.object_types import OPDocumentItem - from ...fixtures.binary_input_data import BinaryImageData + from ....fixtures.binary_input_data import BinaryImageData import pytest -from ...test_support.util import digest +from ....test_support.util import digest pytestmark = pytest.mark.usefixtures("valid_op_cli_config_homedir") diff --git a/tests/test_op_api/test_document_edit/test_document_edit_errors.py b/tests/test_op_api/document/edit/test_document_edit_errors.py similarity index 91% rename from tests/test_op_api/test_document_edit/test_document_edit_errors.py rename to tests/test_op_api/document/edit/test_document_edit_errors.py index 9543beea..e846b8ed 100644 --- a/tests/test_op_api/test_document_edit/test_document_edit_errors.py +++ b/tests/test_op_api/document/edit/test_document_edit_errors.py @@ -4,7 +4,7 @@ if TYPE_CHECKING: from pyonepassword import OP - from ...fixtures.binary_input_data import BinaryImageData + from ....fixtures.binary_input_data import BinaryImageData import pytest From c8a8be1b8dbdb12b0c15243842a4cb4cec54be7b Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:17:16 -0800 Subject: [PATCH 64/77] move "document get" test modules under test_op_api/document/get --- tests/test_op_api/document/get/__init__.py | 0 tests/test_op_api/{ => document/get}/test_document_get.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 tests/test_op_api/document/get/__init__.py rename tests/test_op_api/{ => document/get}/test_document_get.py (98%) diff --git a/tests/test_op_api/document/get/__init__.py b/tests/test_op_api/document/get/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_op_api/test_document_get.py b/tests/test_op_api/document/get/test_document_get.py similarity index 98% rename from tests/test_op_api/test_document_get.py rename to tests/test_op_api/document/get/test_document_get.py index bb0c57dc..3b0d0c29 100644 --- a/tests/test_op_api/test_document_get.py +++ b/tests/test_op_api/document/get/test_document_get.py @@ -13,7 +13,7 @@ ) from pyonepassword.api.object_types import OPDocumentFile, OPDocumentItem -from ..test_support.util import digest +from ....test_support.util import digest pytestmark = pytest.mark.usefixtures("valid_op_cli_config_homedir") From a7c803b356ae3db3eb4fb8b9cfe13099ba5f1cd1 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:20:05 -0800 Subject: [PATCH 65/77] move "document delete" test modules under test_op_api/document/delete --- tests/test_op_api/document/delete/__init__.py | 0 .../test_op_api/{ => document/delete}/test_document_delete.py | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 tests/test_op_api/document/delete/__init__.py rename tests/test_op_api/{ => document/delete}/test_document_delete.py (96%) diff --git a/tests/test_op_api/document/delete/__init__.py b/tests/test_op_api/document/delete/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_op_api/test_document_delete.py b/tests/test_op_api/document/delete/test_document_delete.py similarity index 96% rename from tests/test_op_api/test_document_delete.py rename to tests/test_op_api/document/delete/test_document_delete.py index 5e104dfc..5bdcaa31 100644 --- a/tests/test_op_api/test_document_delete.py +++ b/tests/test_op_api/document/delete/test_document_delete.py @@ -14,9 +14,9 @@ if TYPE_CHECKING: from pyonepassword import OP - from ..fixtures.expected_document_data import ExpectedDocumentData + from ....fixtures.expected_document_data import ExpectedDocumentData -from ..test_support.util import digest +from ....test_support.util import digest # ensure HOME env variable is set, and there's a valid op config present pytestmark = pytest.mark.usefixtures("valid_op_cli_config_homedir") From 5572a8b23419c2e51cd88fe48a215bff1974fa18 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:30:26 -0800 Subject: [PATCH 66/77] move "user list" test modules under test_op_api/user/list --- .../{test_user_list => user/list}/test_user_list_all.py | 0 .../{test_user_list => user/list}/test_user_list_group.py | 0 .../{test_user_list => user/list}/test_user_list_vault.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/test_op_api/{test_user_list => user/list}/test_user_list_all.py (100%) rename tests/test_op_api/{test_user_list => user/list}/test_user_list_group.py (100%) rename tests/test_op_api/{test_user_list => user/list}/test_user_list_vault.py (100%) diff --git a/tests/test_op_api/test_user_list/test_user_list_all.py b/tests/test_op_api/user/list/test_user_list_all.py similarity index 100% rename from tests/test_op_api/test_user_list/test_user_list_all.py rename to tests/test_op_api/user/list/test_user_list_all.py diff --git a/tests/test_op_api/test_user_list/test_user_list_group.py b/tests/test_op_api/user/list/test_user_list_group.py similarity index 100% rename from tests/test_op_api/test_user_list/test_user_list_group.py rename to tests/test_op_api/user/list/test_user_list_group.py diff --git a/tests/test_op_api/test_user_list/test_user_list_vault.py b/tests/test_op_api/user/list/test_user_list_vault.py similarity index 100% rename from tests/test_op_api/test_user_list/test_user_list_vault.py rename to tests/test_op_api/user/list/test_user_list_vault.py From 32d132170cc653007751c8002611daeab45fb34b Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 11:32:23 -0800 Subject: [PATCH 67/77] move "user get" test modules under test_op_api/user/get --- tests/test_op_api/{ => user/get}/test_user_get.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/test_op_api/{ => user/get}/test_user_get.py (94%) diff --git a/tests/test_op_api/test_user_get.py b/tests/test_op_api/user/get/test_user_get.py similarity index 94% rename from tests/test_op_api/test_user_get.py rename to tests/test_op_api/user/get/test_user_get.py index a998d60a..8ea7b11e 100644 --- a/tests/test_op_api/test_user_get.py +++ b/tests/test_op_api/user/get/test_user_get.py @@ -6,7 +6,7 @@ if TYPE_CHECKING: from pyonepassword import OP - from ..fixtures.expected_user_data import ExpectedUserData + from ....fixtures.expected_user_data import ExpectedUserData from pyonepassword.api.exceptions import OPUserGetException from pyonepassword.api.object_types import OPUser From 2eb25e28b24e13ad1f12897882cbe50511375432 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 13:31:18 -0800 Subject: [PATCH 68/77] enable pytest_pyop to be run from subdirectories of the project --- .init/00_pyonepassword | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/.init/00_pyonepassword b/.init/00_pyonepassword index 9345f236..7cfccd66 100644 --- a/.init/00_pyonepassword +++ b/.init/00_pyonepassword @@ -10,6 +10,11 @@ then alias cdpyonepw='cd "$_pyonepasswd_src_root"; ./scripts/archive_op_binary.sh' fi +_readlink(){ readlink "$1" || echo "$1"; } +# Don't shadow the 'realpath' executable which may be installed on +# some systems (e.g., via homebrew) +_realpath() { _path="$1"; cd "$(dirname "$_path")" && _readlink "$(pwd)"/"$(basename "$_path")"; } + function _local_branches() { if [ "$PWD" != "$_pyonepasswd_src_root" ]; then @@ -27,6 +32,27 @@ function _local_branch_completion(){ _arguments "1:first:($(local_branches "$branch"))" } +_is_subdir() { + local _ret + local parent_dir sub_dir + parent_dir=$(_realpath "$1") + sub_dir=$(_realpath "$2") + if [ -d "$sub_dir" ]; + then + if [[ $sub_dir = $parent_dir/* ]]; + then + _ret=0 + else + _ret=1 + fi + else + echo "sub_dir: $sub_dir is not a directory" >&2 + _ret=1 + fi + return $_ret +} + + function deletebranch_pyop(){ local branch="$1" if [ "$PWD" != "$_pyonepasswd_src_root" ]; @@ -38,6 +64,14 @@ function deletebranch_pyop(){ } function pytest_pyop(){ + + local _popd=0 + if _is_subdir "$_pyonepasswd_src_root" "$PWD"; + then + pushd "$_pyonepasswd_src_root" + _popd=1 + fi + if [ "$PWD" != "$_pyonepasswd_src_root" ]; then echo "wrong directory to run 'pytest_pyop'" @@ -47,7 +81,16 @@ function pytest_pyop(){ # _nproc="$(nproc)" # echo "pytest: $_nproc parallel processes" # pytest -n "$_nproc" + pytest -n auto + + if [ $_popd -eq 1 ]; + then + dirs + popd + _popd=0 + fi + } function mypy_pyop(){ From ef95d577dae80aa89f6e5f85905b4ede605ebe05 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 13:38:44 -0800 Subject: [PATCH 69/77] move "item delete" test modules under test_op_api/item/delete --- tests/test_op_api/{ => item/delete}/test_item_delete.py | 0 tests/test_op_api/{ => item/delete}/test_item_delete_multiple.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/test_op_api/{ => item/delete}/test_item_delete.py (100%) rename tests/test_op_api/{ => item/delete}/test_item_delete_multiple.py (100%) diff --git a/tests/test_op_api/test_item_delete.py b/tests/test_op_api/item/delete/test_item_delete.py similarity index 100% rename from tests/test_op_api/test_item_delete.py rename to tests/test_op_api/item/delete/test_item_delete.py diff --git a/tests/test_op_api/test_item_delete_multiple.py b/tests/test_op_api/item/delete/test_item_delete_multiple.py similarity index 100% rename from tests/test_op_api/test_item_delete_multiple.py rename to tests/test_op_api/item/delete/test_item_delete_multiple.py From 7d13a106505740f75eca7e462eec0895fcda1688 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 13:40:14 -0800 Subject: [PATCH 70/77] move "vault get" test modules under test_op_api/vault/get --- tests/test_op_api/{ => vault/get}/test_vault_get.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/test_op_api/{ => vault/get}/test_vault_get.py (96%) diff --git a/tests/test_op_api/test_vault_get.py b/tests/test_op_api/vault/get/test_vault_get.py similarity index 96% rename from tests/test_op_api/test_vault_get.py rename to tests/test_op_api/vault/get/test_vault_get.py index 0b5882f6..191a8aeb 100644 --- a/tests/test_op_api/test_vault_get.py +++ b/tests/test_op_api/vault/get/test_vault_get.py @@ -6,7 +6,7 @@ if TYPE_CHECKING: from pyonepassword import OP - from ..fixtures.expected_vault_data import ( + from ....fixtures.expected_vault_data import ( ExpectedVaultData, ExpectedVault ) From 9310311cb5f7eb7a736908028d0920e69d38aa97 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 13:40:57 -0800 Subject: [PATCH 71/77] move "group get" test modules under test_op_api/group/get --- tests/test_op_api/{ => group/get}/test_group_get.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/test_op_api/{ => group/get}/test_group_get.py (100%) diff --git a/tests/test_op_api/test_group_get.py b/tests/test_op_api/group/get/test_group_get.py similarity index 100% rename from tests/test_op_api/test_group_get.py rename to tests/test_op_api/group/get/test_group_get.py From 392c0220953d93782fcd28d3d20136aacfb069ae Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 13:42:25 -0800 Subject: [PATCH 72/77] move "vault list" test modules under test_op_api/vault/list --- .../{test_vault_list => vault/list}/test_vault_list_all.py | 0 .../{test_vault_list => vault/list}/test_vault_list_error.py | 0 .../{test_vault_list => vault/list}/test_vault_list_group.py | 0 .../{test_vault_list => vault/list}/test_vault_list_user.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/test_op_api/{test_vault_list => vault/list}/test_vault_list_all.py (100%) rename tests/test_op_api/{test_vault_list => vault/list}/test_vault_list_error.py (100%) rename tests/test_op_api/{test_vault_list => vault/list}/test_vault_list_group.py (100%) rename tests/test_op_api/{test_vault_list => vault/list}/test_vault_list_user.py (100%) diff --git a/tests/test_op_api/test_vault_list/test_vault_list_all.py b/tests/test_op_api/vault/list/test_vault_list_all.py similarity index 100% rename from tests/test_op_api/test_vault_list/test_vault_list_all.py rename to tests/test_op_api/vault/list/test_vault_list_all.py diff --git a/tests/test_op_api/test_vault_list/test_vault_list_error.py b/tests/test_op_api/vault/list/test_vault_list_error.py similarity index 100% rename from tests/test_op_api/test_vault_list/test_vault_list_error.py rename to tests/test_op_api/vault/list/test_vault_list_error.py diff --git a/tests/test_op_api/test_vault_list/test_vault_list_group.py b/tests/test_op_api/vault/list/test_vault_list_group.py similarity index 100% rename from tests/test_op_api/test_vault_list/test_vault_list_group.py rename to tests/test_op_api/vault/list/test_vault_list_group.py diff --git a/tests/test_op_api/test_vault_list/test_vault_list_user.py b/tests/test_op_api/vault/list/test_vault_list_user.py similarity index 100% rename from tests/test_op_api/test_vault_list/test_vault_list_user.py rename to tests/test_op_api/vault/list/test_vault_list_user.py From 4f2843908f2ce676faa89cd0a37d6cfa208039a4 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 13:46:14 -0800 Subject: [PATCH 73/77] move "group list" test modules under test_op_api/group/list --- .../group/list}/test_group_list_all.py | 0 .../group/list}/test_group_list_user.py | 0 .../group/list}/test_group_list_vault.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/{test_group_list => test_op_api/group/list}/test_group_list_all.py (100%) rename tests/{test_group_list => test_op_api/group/list}/test_group_list_user.py (100%) rename tests/{test_group_list => test_op_api/group/list}/test_group_list_vault.py (100%) diff --git a/tests/test_group_list/test_group_list_all.py b/tests/test_op_api/group/list/test_group_list_all.py similarity index 100% rename from tests/test_group_list/test_group_list_all.py rename to tests/test_op_api/group/list/test_group_list_all.py diff --git a/tests/test_group_list/test_group_list_user.py b/tests/test_op_api/group/list/test_group_list_user.py similarity index 100% rename from tests/test_group_list/test_group_list_user.py rename to tests/test_op_api/group/list/test_group_list_user.py diff --git a/tests/test_group_list/test_group_list_vault.py b/tests/test_op_api/group/list/test_group_list_vault.py similarity index 100% rename from tests/test_group_list/test_group_list_vault.py rename to tests/test_op_api/group/list/test_group_list_vault.py From 67ef4561e7f657fa9e8b933308a1b613f26850e8 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 13:53:14 -0800 Subject: [PATCH 74/77] move "item list" test modules under test_op_api/item/list --- .../item/list}/test_item_list_error.py | 0 .../item/list}/test_item_list_include_archive.py | 0 .../item/list}/test_item_list_include_categories.py | 0 .../item/list}/test_item_list_include_tags.py | 0 .../item/list}/test_item_list_misc.py | 0 .../item/list}/test_item_list_password.py | 0 .../item/list}/test_item_list_ssh_key.py | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename tests/{test_item_list => test_op_api/item/list}/test_item_list_error.py (100%) rename tests/{test_item_list => test_op_api/item/list}/test_item_list_include_archive.py (100%) rename tests/{test_item_list => test_op_api/item/list}/test_item_list_include_categories.py (100%) rename tests/{test_item_list => test_op_api/item/list}/test_item_list_include_tags.py (100%) rename tests/{test_item_list => test_op_api/item/list}/test_item_list_misc.py (100%) rename tests/{test_item_list => test_op_api/item/list}/test_item_list_password.py (100%) rename tests/{test_item_list => test_op_api/item/list}/test_item_list_ssh_key.py (100%) diff --git a/tests/test_item_list/test_item_list_error.py b/tests/test_op_api/item/list/test_item_list_error.py similarity index 100% rename from tests/test_item_list/test_item_list_error.py rename to tests/test_op_api/item/list/test_item_list_error.py diff --git a/tests/test_item_list/test_item_list_include_archive.py b/tests/test_op_api/item/list/test_item_list_include_archive.py similarity index 100% rename from tests/test_item_list/test_item_list_include_archive.py rename to tests/test_op_api/item/list/test_item_list_include_archive.py diff --git a/tests/test_item_list/test_item_list_include_categories.py b/tests/test_op_api/item/list/test_item_list_include_categories.py similarity index 100% rename from tests/test_item_list/test_item_list_include_categories.py rename to tests/test_op_api/item/list/test_item_list_include_categories.py diff --git a/tests/test_item_list/test_item_list_include_tags.py b/tests/test_op_api/item/list/test_item_list_include_tags.py similarity index 100% rename from tests/test_item_list/test_item_list_include_tags.py rename to tests/test_op_api/item/list/test_item_list_include_tags.py diff --git a/tests/test_item_list/test_item_list_misc.py b/tests/test_op_api/item/list/test_item_list_misc.py similarity index 100% rename from tests/test_item_list/test_item_list_misc.py rename to tests/test_op_api/item/list/test_item_list_misc.py diff --git a/tests/test_item_list/test_item_list_password.py b/tests/test_op_api/item/list/test_item_list_password.py similarity index 100% rename from tests/test_item_list/test_item_list_password.py rename to tests/test_op_api/item/list/test_item_list_password.py diff --git a/tests/test_item_list/test_item_list_ssh_key.py b/tests/test_op_api/item/list/test_item_list_ssh_key.py similarity index 100% rename from tests/test_item_list/test_item_list_ssh_key.py rename to tests/test_op_api/item/list/test_item_list_ssh_key.py From 91e084dba71cd293e2e06492bfce1ce75b877e4b Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 13:53:33 -0800 Subject: [PATCH 75/77] move "account list" test modules under test_op_api/account/list --- tests/{ => test_op_api/account/list}/test_account_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/{ => test_op_api/account/list}/test_account_list.py (96%) diff --git a/tests/test_account_list.py b/tests/test_op_api/account/list/test_account_list.py similarity index 96% rename from tests/test_account_list.py rename to tests/test_op_api/account/list/test_account_list.py index 4f49505a..5755064a 100644 --- a/tests/test_account_list.py +++ b/tests/test_op_api/account/list/test_account_list.py @@ -9,7 +9,7 @@ if TYPE_CHECKING: from pyonepassword import OP - from .fixtures.expected_account_data import ExpectedAccountData + from ....fixtures.expected_account_data import ExpectedAccountData pytestmark = pytest.mark.usefixtures("valid_op_cli_config_homedir") From cfc6c92e1b3b3ac4c4de8453229cbad4b7ff2a37 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 14:09:39 -0800 Subject: [PATCH 76/77] bump version to 4.1.0 --- pyonepassword/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyonepassword/__about__.py b/pyonepassword/__about__.py index 6ca31d2d..92db4692 100644 --- a/pyonepassword/__about__.py +++ b/pyonepassword/__about__.py @@ -1,5 +1,5 @@ __title__ = "pyonepassword" -__version__ = "4.1.0.dev0" +__version__ = "4.1.0" __summary__ = "A python API to query a 1Password account using the 'op' command-line tool" """ From 69bd2021c34f10e76e6dfd14bf95ce61882bee88 Mon Sep 17 00:00:00 2001 From: Zachary Cutlip Date: Tue, 28 Nov 2023 14:11:05 -0800 Subject: [PATCH 77/77] update CHANGELOG.md for 4.1.0 --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f67a0964..c7c66d9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -## [DEVELOPMENT] 2023-11-27 +## [4.1.0] 2023-11-28 ### Added @@ -10,9 +10,14 @@ All notable changes to this project will be documented in this file. - `OP.document_edit()` ### Documentation + - Describe document editing in `docs/document-editing.md` - Added set of document editing examples under `examples/document_editing` +### Misc + +Substantial reorganization of `tests/` + ## [4.0.0] 2023-11-15 ### Fixed