Skip to content
This repository was archived by the owner on Sep 20, 2023. It is now read-only.

Commit 35e3b74

Browse files
feat: update ReviewDocumentRequest to allow set priority and enable validation (#172)
Committer: @busunkim96 PiperOrigin-RevId: 382142900 Source-Link: googleapis/googleapis@513440f Source-Link: https://github.com/googleapis/googleapis-gen/commit/7b1e2c31233f79a704ec21ca410bf661d6bc68d0 feat: add always_use_jwt_access feat: add the processor management methods fix: disable always_use_jwt_access
1 parent 6551ffd commit 35e3b74

17 files changed

Lines changed: 267 additions & 387 deletions

File tree

google/cloud/documentai_v1/services/document_processor_service/transports/base.py

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from google.api_core import retry as retries # type: ignore
2626
from google.api_core import operations_v1 # type: ignore
2727
from google.auth import credentials as ga_credentials # type: ignore
28+
from google.oauth2 import service_account # type: ignore
2829

2930
from google.cloud.documentai_v1.types import document_processor_service
3031
from google.longrunning import operations_pb2 # type: ignore
@@ -47,8 +48,6 @@
4748
except pkg_resources.DistributionNotFound: # pragma: NO COVER
4849
_GOOGLE_AUTH_VERSION = None
4950

50-
_API_CORE_VERSION = google.api_core.__version__
51-
5251

5352
class DocumentProcessorServiceTransport(abc.ABC):
5453
"""Abstract transport class for DocumentProcessorService."""
@@ -66,6 +65,7 @@ def __init__(
6665
scopes: Optional[Sequence[str]] = None,
6766
quota_project_id: Optional[str] = None,
6867
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
68+
always_use_jwt_access: Optional[bool] = False,
6969
**kwargs,
7070
) -> None:
7171
"""Instantiate the transport.
@@ -89,6 +89,8 @@ def __init__(
8989
API requests. If ``None``, then default info will be used.
9090
Generally, you only need to set this if you're developing
9191
your own client library.
92+
always_use_jwt_access (Optional[bool]): Whether self signed JWT should
93+
be used for service account credentials.
9294
"""
9395
# Save the hostname. Default to port 443 (HTTPS) if none is specified.
9496
if ":" not in host:
@@ -98,7 +100,7 @@ def __init__(
98100
scopes_kwargs = self._get_scopes_kwargs(self._host, scopes)
99101

100102
# Save the scopes.
101-
self._scopes = scopes or self.AUTH_SCOPES
103+
self._scopes = scopes
102104

103105
# If no credentials are provided, then determine the appropriate
104106
# defaults.
@@ -117,13 +119,20 @@ def __init__(
117119
**scopes_kwargs, quota_project_id=quota_project_id
118120
)
119121

122+
# If the credentials is service account credentials, then always try to use self signed JWT.
123+
if (
124+
always_use_jwt_access
125+
and isinstance(credentials, service_account.Credentials)
126+
and hasattr(service_account.Credentials, "with_always_use_jwt_access")
127+
):
128+
credentials = credentials.with_always_use_jwt_access(True)
129+
120130
# Save the credentials.
121131
self._credentials = credentials
122132

123-
# TODO(busunkim): These two class methods are in the base transport
133+
# TODO(busunkim): This method is in the base transport
124134
# to avoid duplicating code across the transport classes. These functions
125-
# should be deleted once the minimum required versions of google-api-core
126-
# and google-auth are increased.
135+
# should be deleted once the minimum required versions of google-auth is increased.
127136

128137
# TODO: Remove this function once google-auth >= 1.25.0 is required
129138
@classmethod
@@ -144,27 +153,6 @@ def _get_scopes_kwargs(
144153

145154
return scopes_kwargs
146155

147-
# TODO: Remove this function once google-api-core >= 1.26.0 is required
148-
@classmethod
149-
def _get_self_signed_jwt_kwargs(
150-
cls, host: str, scopes: Optional[Sequence[str]]
151-
) -> Dict[str, Union[Optional[Sequence[str]], str]]:
152-
"""Returns kwargs to pass to grpc_helpers.create_channel depending on the google-api-core version"""
153-
154-
self_signed_jwt_kwargs: Dict[str, Union[Optional[Sequence[str]], str]] = {}
155-
156-
if _API_CORE_VERSION and (
157-
packaging.version.parse(_API_CORE_VERSION)
158-
>= packaging.version.parse("1.26.0")
159-
):
160-
self_signed_jwt_kwargs["default_scopes"] = cls.AUTH_SCOPES
161-
self_signed_jwt_kwargs["scopes"] = scopes
162-
self_signed_jwt_kwargs["default_host"] = cls.DEFAULT_HOST
163-
else:
164-
self_signed_jwt_kwargs["scopes"] = scopes or cls.AUTH_SCOPES
165-
166-
return self_signed_jwt_kwargs
167-
168156
def _prep_wrapped_messages(self, client_info):
169157
# Precompute the wrapped methods.
170158
self._wrapped_methods = {

google/cloud/documentai_v1/services/document_processor_service/transports/grpc.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def __init__(
6363
client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
6464
quota_project_id: Optional[str] = None,
6565
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
66+
always_use_jwt_access: Optional[bool] = False,
6667
) -> None:
6768
"""Instantiate the transport.
6869
@@ -103,6 +104,8 @@ def __init__(
103104
API requests. If ``None``, then default info will be used.
104105
Generally, you only need to set this if you're developing
105106
your own client library.
107+
always_use_jwt_access (Optional[bool]): Whether self signed JWT should
108+
be used for service account credentials.
106109
107110
Raises:
108111
google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport
@@ -156,6 +159,7 @@ def __init__(
156159
scopes=scopes,
157160
quota_project_id=quota_project_id,
158161
client_info=client_info,
162+
always_use_jwt_access=always_use_jwt_access,
159163
)
160164

161165
if not self._grpc_channel:
@@ -211,14 +215,14 @@ def create_channel(
211215
and ``credentials_file`` are passed.
212216
"""
213217

214-
self_signed_jwt_kwargs = cls._get_self_signed_jwt_kwargs(host, scopes)
215-
216218
return grpc_helpers.create_channel(
217219
host,
218220
credentials=credentials,
219221
credentials_file=credentials_file,
220222
quota_project_id=quota_project_id,
221-
**self_signed_jwt_kwargs,
223+
default_scopes=cls.AUTH_SCOPES,
224+
scopes=scopes,
225+
default_host=cls.DEFAULT_HOST,
222226
**kwargs,
223227
)
224228

google/cloud/documentai_v1/services/document_processor_service/transports/grpc_asyncio.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,14 @@ def create_channel(
8484
aio.Channel: A gRPC AsyncIO channel object.
8585
"""
8686

87-
self_signed_jwt_kwargs = cls._get_self_signed_jwt_kwargs(host, scopes)
88-
8987
return grpc_helpers_async.create_channel(
9088
host,
9189
credentials=credentials,
9290
credentials_file=credentials_file,
9391
quota_project_id=quota_project_id,
94-
**self_signed_jwt_kwargs,
92+
default_scopes=cls.AUTH_SCOPES,
93+
scopes=scopes,
94+
default_host=cls.DEFAULT_HOST,
9595
**kwargs,
9696
)
9797

@@ -109,6 +109,7 @@ def __init__(
109109
client_cert_source_for_mtls: Callable[[], Tuple[bytes, bytes]] = None,
110110
quota_project_id=None,
111111
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
112+
always_use_jwt_access: Optional[bool] = False,
112113
) -> None:
113114
"""Instantiate the transport.
114115
@@ -150,6 +151,8 @@ def __init__(
150151
API requests. If ``None``, then default info will be used.
151152
Generally, you only need to set this if you're developing
152153
your own client library.
154+
always_use_jwt_access (Optional[bool]): Whether self signed JWT should
155+
be used for service account credentials.
153156
154157
Raises:
155158
google.auth.exceptions.MutualTlsChannelError: If mutual TLS transport
@@ -202,6 +205,7 @@ def __init__(
202205
scopes=scopes,
203206
quota_project_id=quota_project_id,
204207
client_info=client_info,
208+
always_use_jwt_access=always_use_jwt_access,
205209
)
206210

207211
if not self._grpc_channel:

google/cloud/documentai_v1/types/document.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ class Page(proto.Message):
212212
form_fields (Sequence[google.cloud.documentai_v1.types.Document.Page.FormField]):
213213
A list of visually detected form fields on
214214
the page.
215+
provenance (google.cloud.documentai_v1.types.Document.Provenance):
216+
The history of this page.
215217
"""
216218

217219
class Dimension(proto.Message):
@@ -552,6 +554,8 @@ class FormField(proto.Message):
552554
- blank (this indicates the field_value is normal text)
553555
- "unfilled_checkbox"
554556
- "filled_checkbox".
557+
provenance (google.cloud.documentai_v1.types.Document.Provenance):
558+
The history of this annotation.
555559
"""
556560

557561
field_name = proto.Field(
@@ -567,6 +571,9 @@ class FormField(proto.Message):
567571
proto.MESSAGE, number=4, message="Document.Page.DetectedLanguage",
568572
)
569573
value_type = proto.Field(proto.STRING, number=5,)
574+
provenance = proto.Field(
575+
proto.MESSAGE, number=8, message="Document.Provenance",
576+
)
570577

571578
class DetectedLanguage(proto.Message):
572579
r"""Detected language for a structural component.
@@ -615,6 +622,9 @@ class DetectedLanguage(proto.Message):
615622
form_fields = proto.RepeatedField(
616623
proto.MESSAGE, number=11, message="Document.Page.FormField",
617624
)
625+
provenance = proto.Field(
626+
proto.MESSAGE, number=16, message="Document.Provenance",
627+
)
618628

619629
class Entity(proto.Message):
620630
r"""A phrase in the text that is a known entity type, such as a
@@ -819,7 +829,9 @@ class PageRef(proto.Message):
819829
Required. Index into the
820830
[Document.pages][google.cloud.documentai.v1.Document.pages]
821831
element, for example using [Document.pages][page_refs.page]
822-
to locate the related page element.
832+
to locate the related page element. This field is skipped
833+
when its value is the default 0. See
834+
https://developers.google.com/protocol-buffers/docs/proto3#json.
823835
layout_type (google.cloud.documentai_v1.types.Document.PageAnchor.PageRef.LayoutType):
824836
Optional. The type of the layout element that
825837
is being referenced if any.
@@ -899,11 +911,16 @@ class Parent(proto.Message):
899911
revision (int):
900912
The index of the [Document.revisions] identifying the parent
901913
revision.
914+
index (int):
915+
The index of the parent revisions
916+
corresponding collection of items (eg. list of
917+
entities, properties within entities, etc.)
902918
id (int):
903919
The id of the parent provenance.
904920
"""
905921

906922
revision = proto.Field(proto.INT32, number=1,)
923+
index = proto.Field(proto.INT32, number=3,)
907924
id = proto.Field(proto.INT32, number=2,)
908925

909926
revision = proto.Field(proto.INT32, number=1,)

google/cloud/documentai_v1/types/document_processor_service.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,24 @@ class ReviewDocumentRequest(proto.Message):
212212
Required. The resource name of the
213213
HumanReviewConfig that the document will be
214214
reviewed with.
215+
enable_schema_validation (bool):
216+
Whether the validation should be performed on
217+
the ad-hoc review request.
218+
priority (google.cloud.documentai_v1.types.ReviewDocumentRequest.Priority):
219+
The priority of the human review task.
215220
"""
216221

222+
class Priority(proto.Enum):
223+
r"""The priority level of the human review task."""
224+
DEFAULT = 0
225+
URGENT = 1
226+
217227
inline_document = proto.Field(
218228
proto.MESSAGE, number=4, oneof="source", message=gcd_document.Document,
219229
)
220230
human_review_config = proto.Field(proto.STRING, number=1,)
231+
enable_schema_validation = proto.Field(proto.BOOL, number=3,)
232+
priority = proto.Field(proto.ENUM, number=5, enum=Priority,)
221233

222234

223235
class ReviewDocumentResponse(proto.Message):

google/cloud/documentai_v1beta2/services/document_understanding_service/transports/base.py

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from google.api_core import retry as retries # type: ignore
2626
from google.api_core import operations_v1 # type: ignore
2727
from google.auth import credentials as ga_credentials # type: ignore
28+
from google.oauth2 import service_account # type: ignore
2829

2930
from google.cloud.documentai_v1beta2.types import document
3031
from google.cloud.documentai_v1beta2.types import document_understanding
@@ -48,8 +49,6 @@
4849
except pkg_resources.DistributionNotFound: # pragma: NO COVER
4950
_GOOGLE_AUTH_VERSION = None
5051

51-
_API_CORE_VERSION = google.api_core.__version__
52-
5352

5453
class DocumentUnderstandingServiceTransport(abc.ABC):
5554
"""Abstract transport class for DocumentUnderstandingService."""
@@ -67,6 +66,7 @@ def __init__(
6766
scopes: Optional[Sequence[str]] = None,
6867
quota_project_id: Optional[str] = None,
6968
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
69+
always_use_jwt_access: Optional[bool] = False,
7070
**kwargs,
7171
) -> None:
7272
"""Instantiate the transport.
@@ -90,6 +90,8 @@ def __init__(
9090
API requests. If ``None``, then default info will be used.
9191
Generally, you only need to set this if you're developing
9292
your own client library.
93+
always_use_jwt_access (Optional[bool]): Whether self signed JWT should
94+
be used for service account credentials.
9395
"""
9496
# Save the hostname. Default to port 443 (HTTPS) if none is specified.
9597
if ":" not in host:
@@ -99,7 +101,7 @@ def __init__(
99101
scopes_kwargs = self._get_scopes_kwargs(self._host, scopes)
100102

101103
# Save the scopes.
102-
self._scopes = scopes or self.AUTH_SCOPES
104+
self._scopes = scopes
103105

104106
# If no credentials are provided, then determine the appropriate
105107
# defaults.
@@ -118,13 +120,20 @@ def __init__(
118120
**scopes_kwargs, quota_project_id=quota_project_id
119121
)
120122

123+
# If the credentials is service account credentials, then always try to use self signed JWT.
124+
if (
125+
always_use_jwt_access
126+
and isinstance(credentials, service_account.Credentials)
127+
and hasattr(service_account.Credentials, "with_always_use_jwt_access")
128+
):
129+
credentials = credentials.with_always_use_jwt_access(True)
130+
121131
# Save the credentials.
122132
self._credentials = credentials
123133

124-
# TODO(busunkim): These two class methods are in the base transport
134+
# TODO(busunkim): This method is in the base transport
125135
# to avoid duplicating code across the transport classes. These functions
126-
# should be deleted once the minimum required versions of google-api-core
127-
# and google-auth are increased.
136+
# should be deleted once the minimum required versions of google-auth is increased.
128137

129138
# TODO: Remove this function once google-auth >= 1.25.0 is required
130139
@classmethod
@@ -139,33 +148,20 @@ def _get_scopes_kwargs(
139148
packaging.version.parse(_GOOGLE_AUTH_VERSION)
140149
>= packaging.version.parse("1.25.0")
141150
):
142-
scopes_kwargs = {"scopes": scopes, "default_scopes": cls.AUTH_SCOPES}
151+
# Documentai uses a regional host (us-documentai.googleapis.com) as the default
152+
# so self-signed JWT cannot be used.
153+
# Intentionally pass default scopes as user scopes so the auth library
154+
# does not use the self-signed JWT flow.
155+
# https://github.com/googleapis/python-documentai/issues/174
156+
scopes_kwargs = {
157+
"scopes": scopes or cls.AUTH_SCOPES,
158+
"default_scopes": cls.AUTH_SCOPES,
159+
}
143160
else:
144161
scopes_kwargs = {"scopes": scopes or cls.AUTH_SCOPES}
145162

146163
return scopes_kwargs
147164

148-
# TODO: Remove this function once google-api-core >= 1.26.0 is required
149-
@classmethod
150-
def _get_self_signed_jwt_kwargs(
151-
cls, host: str, scopes: Optional[Sequence[str]]
152-
) -> Dict[str, Union[Optional[Sequence[str]], str]]:
153-
"""Returns kwargs to pass to grpc_helpers.create_channel depending on the google-api-core version"""
154-
155-
self_signed_jwt_kwargs: Dict[str, Union[Optional[Sequence[str]], str]] = {}
156-
157-
if _API_CORE_VERSION and (
158-
packaging.version.parse(_API_CORE_VERSION)
159-
>= packaging.version.parse("1.26.0")
160-
):
161-
self_signed_jwt_kwargs["default_scopes"] = cls.AUTH_SCOPES
162-
self_signed_jwt_kwargs["scopes"] = scopes
163-
self_signed_jwt_kwargs["default_host"] = cls.DEFAULT_HOST
164-
else:
165-
self_signed_jwt_kwargs["scopes"] = scopes or cls.AUTH_SCOPES
166-
167-
return self_signed_jwt_kwargs
168-
169165
def _prep_wrapped_messages(self, client_info):
170166
# Precompute the wrapped methods.
171167
self._wrapped_methods = {

0 commit comments

Comments
 (0)