python-service-builder 0.1.0__tar.gz → 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python-service-builder-1.0.1/PKG-INFO +86 -0
- python-service-builder-1.0.1/README.md +73 -0
- python-service-builder-1.0.1/pyproject.toml +43 -0
- python-service-builder-1.0.1/python_service_builder.egg-info/PKG-INFO +86 -0
- {python-service-builder-0.1.0 → python-service-builder-1.0.1}/python_service_builder.egg-info/SOURCES.txt +0 -2
- python-service-builder-1.0.1/service_framework/__init__.py +115 -0
- python-service-builder-1.0.1/service_framework/__init_test.py +116 -0
- {python-service-builder-0.1.0 → python-service-builder-1.0.1}/service_framework/list_services.py +2 -1
- {python-service-builder-0.1.0 → python-service-builder-1.0.1}/service_framework/service_builder.py +19 -36
- {python-service-builder-0.1.0 → python-service-builder-1.0.1}/service_framework/services.py +22 -5
- {python-service-builder-0.1.0 → python-service-builder-1.0.1}/service_framework/services_test.py +4 -7
- python-service-builder-0.1.0/PKG-INFO +0 -19
- python-service-builder-0.1.0/README.md +0 -2
- python-service-builder-0.1.0/pyproject.toml +0 -3
- python-service-builder-0.1.0/python_service_builder.egg-info/PKG-INFO +0 -19
- python-service-builder-0.1.0/python_service_builder.egg-info/not-zip-safe +0 -1
- python-service-builder-0.1.0/service_framework/__init__.py +0 -67
- python-service-builder-0.1.0/service_framework/__init_test.py +0 -29
- python-service-builder-0.1.0/setup.py +0 -58
- {python-service-builder-0.1.0 → python-service-builder-1.0.1}/python_service_builder.egg-info/dependency_links.txt +0 -0
- {python-service-builder-0.1.0 → python-service-builder-1.0.1}/python_service_builder.egg-info/requires.txt +0 -0
- {python-service-builder-0.1.0 → python-service-builder-1.0.1}/python_service_builder.egg-info/top_level.txt +0 -0
- {python-service-builder-0.1.0 → python-service-builder-1.0.1}/setup.cfg +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: python-service-builder
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Helper library for easier creation of Google services.
|
|
5
|
+
Author-email: David Harcombe <david.harcombe@gmail.com>
|
|
6
|
+
License: Apache 2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/google/python-service-builder
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/google/python-service-builder/issues
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# Python Library for helping to create Python services from Google APIs
|
|
15
|
+
|
|
16
|
+
Something I have to do a lot is create connections to Google Service
|
|
17
|
+
endpoints. This generally requires a fair amount of boiler-plate code that io
|
|
18
|
+
just copied and pasted from other locations. Also any time a new service is
|
|
19
|
+
needed, I need to find that specific implementation of the service builder and
|
|
20
|
+
add the new endpoint.
|
|
21
|
+
|
|
22
|
+
Obviously this can lead to potential errors and if a bug is found, I have to
|
|
23
|
+
remember where I created these services and fix it in many projects.
|
|
24
|
+
|
|
25
|
+
This has led me to create a small helper library to make the process easier.
|
|
26
|
+
Included in the library is a complete and updated (at time of publishing) list
|
|
27
|
+
of all the Google APIs along with their versions and endpoints as `Enum`s
|
|
28
|
+
ready for use.
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
`service_builder.build_service()` needs two mandatory pieces of information:
|
|
33
|
+
|
|
34
|
+
| Parameter | Description |
|
|
35
|
+
| :-: | - |
|
|
36
|
+
| key | The credentials to use to authenticate the user to the service it has to create |
|
|
37
|
+
| service | The Google API endpoint it is trying to connect to. |
|
|
38
|
+
|
|
39
|
+
### `key`
|
|
40
|
+
|
|
41
|
+
These can be supplied in one of 4 ways.
|
|
42
|
+
|
|
43
|
+
1. A valid `google.oauth2.Credentials` object, created and passed to the
|
|
44
|
+
service builder.
|
|
45
|
+
1. An `str` which is the name of a local file containing the `json`
|
|
46
|
+
representation of an OAuth credentials object.
|
|
47
|
+
1. A `Mapping` object which is a `json` keyfile `dict`
|
|
48
|
+
2. An `OAuthKey` object from this package, which is a `dataclass` object
|
|
49
|
+
comprising of the minimum fields necessary to perform the OAuth connection.
|
|
50
|
+
|
|
51
|
+
### `service`
|
|
52
|
+
|
|
53
|
+
This is an Enum in the `service_framework.service` module, which defines
|
|
54
|
+
the Google service you're planning to connect to. All of these services are
|
|
55
|
+
dynamically built, but their names match the Google-defined name.
|
|
56
|
+
|
|
57
|
+
### Example
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
from service_framework.services import Service
|
|
61
|
+
from service_framework import service_builder
|
|
62
|
+
|
|
63
|
+
key = service_builder.OAuthKey(
|
|
64
|
+
access_token="<YOUR ACCESS TOKEN>",
|
|
65
|
+
refresh_token="<YOUR REFRESH TOKEN>",
|
|
66
|
+
token_uri="https://oauth2.googleapis.com/token",
|
|
67
|
+
client_id="<YOUR CLIENT ID>",
|
|
68
|
+
client_secret="<YOUR CLIENT SECRET>"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
service = service_builder.build_service(service=Service.GMAIL, key=key)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Here, we are creating the key as an `OAuthKey` object as we have clearly got the
|
|
75
|
+
tokens and client_[id|secret] from elsewhere. Creating the service is then as
|
|
76
|
+
simple as invoking the `service_builder.build_service` method which will return
|
|
77
|
+
you a service you can use.
|
|
78
|
+
|
|
79
|
+
### Other parameters
|
|
80
|
+
|
|
81
|
+
`service_builder.build_service()` can also take 2 other optional parameters.
|
|
82
|
+
|
|
83
|
+
| Parameter | Description |
|
|
84
|
+
| :-: | - |
|
|
85
|
+
| api_key | Some APIs require an API key as well as the OAuth credentials |
|
|
86
|
+
| extra_scopes | Any extra OAUth scopes required for the operation |
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Python Library for helping to create Python services from Google APIs
|
|
2
|
+
|
|
3
|
+
Something I have to do a lot is create connections to Google Service
|
|
4
|
+
endpoints. This generally requires a fair amount of boiler-plate code that io
|
|
5
|
+
just copied and pasted from other locations. Also any time a new service is
|
|
6
|
+
needed, I need to find that specific implementation of the service builder and
|
|
7
|
+
add the new endpoint.
|
|
8
|
+
|
|
9
|
+
Obviously this can lead to potential errors and if a bug is found, I have to
|
|
10
|
+
remember where I created these services and fix it in many projects.
|
|
11
|
+
|
|
12
|
+
This has led me to create a small helper library to make the process easier.
|
|
13
|
+
Included in the library is a complete and updated (at time of publishing) list
|
|
14
|
+
of all the Google APIs along with their versions and endpoints as `Enum`s
|
|
15
|
+
ready for use.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
`service_builder.build_service()` needs two mandatory pieces of information:
|
|
20
|
+
|
|
21
|
+
| Parameter | Description |
|
|
22
|
+
| :-: | - |
|
|
23
|
+
| key | The credentials to use to authenticate the user to the service it has to create |
|
|
24
|
+
| service | The Google API endpoint it is trying to connect to. |
|
|
25
|
+
|
|
26
|
+
### `key`
|
|
27
|
+
|
|
28
|
+
These can be supplied in one of 4 ways.
|
|
29
|
+
|
|
30
|
+
1. A valid `google.oauth2.Credentials` object, created and passed to the
|
|
31
|
+
service builder.
|
|
32
|
+
1. An `str` which is the name of a local file containing the `json`
|
|
33
|
+
representation of an OAuth credentials object.
|
|
34
|
+
1. A `Mapping` object which is a `json` keyfile `dict`
|
|
35
|
+
2. An `OAuthKey` object from this package, which is a `dataclass` object
|
|
36
|
+
comprising of the minimum fields necessary to perform the OAuth connection.
|
|
37
|
+
|
|
38
|
+
### `service`
|
|
39
|
+
|
|
40
|
+
This is an Enum in the `service_framework.service` module, which defines
|
|
41
|
+
the Google service you're planning to connect to. All of these services are
|
|
42
|
+
dynamically built, but their names match the Google-defined name.
|
|
43
|
+
|
|
44
|
+
### Example
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
from service_framework.services import Service
|
|
48
|
+
from service_framework import service_builder
|
|
49
|
+
|
|
50
|
+
key = service_builder.OAuthKey(
|
|
51
|
+
access_token="<YOUR ACCESS TOKEN>",
|
|
52
|
+
refresh_token="<YOUR REFRESH TOKEN>",
|
|
53
|
+
token_uri="https://oauth2.googleapis.com/token",
|
|
54
|
+
client_id="<YOUR CLIENT ID>",
|
|
55
|
+
client_secret="<YOUR CLIENT SECRET>"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
service = service_builder.build_service(service=Service.GMAIL, key=key)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Here, we are creating the key as an `OAuthKey` object as we have clearly got the
|
|
62
|
+
tokens and client_[id|secret] from elsewhere. Creating the service is then as
|
|
63
|
+
simple as invoking the `service_builder.build_service` method which will return
|
|
64
|
+
you a service you can use.
|
|
65
|
+
|
|
66
|
+
### Other parameters
|
|
67
|
+
|
|
68
|
+
`service_builder.build_service()` can also take 2 other optional parameters.
|
|
69
|
+
|
|
70
|
+
| Parameter | Description |
|
|
71
|
+
| :-: | - |
|
|
72
|
+
| api_key | Some APIs require an API key as well as the OAuth credentials |
|
|
73
|
+
| extra_scopes | Any extra OAUth scopes required for the operation |
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ['setuptools>=61.0.0', 'wheel']
|
|
3
|
+
build-backend = 'setuptools.build_meta'
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "python-service-builder"
|
|
7
|
+
version = "1.0.1"
|
|
8
|
+
authors = [{ name = "David Harcombe", email = "david.harcombe@gmail.com" }]
|
|
9
|
+
description = "Helper library for easier creation of Google services."
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Operating System :: OS Independent",
|
|
15
|
+
]
|
|
16
|
+
license = { text = "Apache 2.0" }
|
|
17
|
+
dependencies = [
|
|
18
|
+
'absl-py>=0.12.0',
|
|
19
|
+
'dataclasses-json>=0.5.2',
|
|
20
|
+
'gcs-oauth2-boto-plugin>=2.7',
|
|
21
|
+
'google-api-core>=1.26.1',
|
|
22
|
+
'google-api-python-client>=2.0.2',
|
|
23
|
+
'google-auth-httplib2>=0.1.0',
|
|
24
|
+
'google-auth-oauthlib>=0.4.3',
|
|
25
|
+
'google-auth>=1.28.0',
|
|
26
|
+
'google-reauth>=0.1.1',
|
|
27
|
+
'googleapis-common-protos>=1.53.0',
|
|
28
|
+
'httplib2>=0.19.0',
|
|
29
|
+
'immutabledict>=2.2.1',
|
|
30
|
+
'oauth2client>=4.1.3',
|
|
31
|
+
'oauthlib>=3.1.0',
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[tool.setuptools]
|
|
35
|
+
include-package-data = false
|
|
36
|
+
|
|
37
|
+
[tool.setuptools.packages.find]
|
|
38
|
+
include = ["service_framework*"]
|
|
39
|
+
exclude = ["*_test.py"]
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
"Homepage" = "https://github.com/google/python-service-builder"
|
|
43
|
+
"Bug Tracker" = "https://github.com/google/python-service-builder/issues"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: python-service-builder
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Helper library for easier creation of Google services.
|
|
5
|
+
Author-email: David Harcombe <david.harcombe@gmail.com>
|
|
6
|
+
License: Apache 2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/google/python-service-builder
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/google/python-service-builder/issues
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# Python Library for helping to create Python services from Google APIs
|
|
15
|
+
|
|
16
|
+
Something I have to do a lot is create connections to Google Service
|
|
17
|
+
endpoints. This generally requires a fair amount of boiler-plate code that io
|
|
18
|
+
just copied and pasted from other locations. Also any time a new service is
|
|
19
|
+
needed, I need to find that specific implementation of the service builder and
|
|
20
|
+
add the new endpoint.
|
|
21
|
+
|
|
22
|
+
Obviously this can lead to potential errors and if a bug is found, I have to
|
|
23
|
+
remember where I created these services and fix it in many projects.
|
|
24
|
+
|
|
25
|
+
This has led me to create a small helper library to make the process easier.
|
|
26
|
+
Included in the library is a complete and updated (at time of publishing) list
|
|
27
|
+
of all the Google APIs along with their versions and endpoints as `Enum`s
|
|
28
|
+
ready for use.
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
`service_builder.build_service()` needs two mandatory pieces of information:
|
|
33
|
+
|
|
34
|
+
| Parameter | Description |
|
|
35
|
+
| :-: | - |
|
|
36
|
+
| key | The credentials to use to authenticate the user to the service it has to create |
|
|
37
|
+
| service | The Google API endpoint it is trying to connect to. |
|
|
38
|
+
|
|
39
|
+
### `key`
|
|
40
|
+
|
|
41
|
+
These can be supplied in one of 4 ways.
|
|
42
|
+
|
|
43
|
+
1. A valid `google.oauth2.Credentials` object, created and passed to the
|
|
44
|
+
service builder.
|
|
45
|
+
1. An `str` which is the name of a local file containing the `json`
|
|
46
|
+
representation of an OAuth credentials object.
|
|
47
|
+
1. A `Mapping` object which is a `json` keyfile `dict`
|
|
48
|
+
2. An `OAuthKey` object from this package, which is a `dataclass` object
|
|
49
|
+
comprising of the minimum fields necessary to perform the OAuth connection.
|
|
50
|
+
|
|
51
|
+
### `service`
|
|
52
|
+
|
|
53
|
+
This is an Enum in the `service_framework.service` module, which defines
|
|
54
|
+
the Google service you're planning to connect to. All of these services are
|
|
55
|
+
dynamically built, but their names match the Google-defined name.
|
|
56
|
+
|
|
57
|
+
### Example
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
from service_framework.services import Service
|
|
61
|
+
from service_framework import service_builder
|
|
62
|
+
|
|
63
|
+
key = service_builder.OAuthKey(
|
|
64
|
+
access_token="<YOUR ACCESS TOKEN>",
|
|
65
|
+
refresh_token="<YOUR REFRESH TOKEN>",
|
|
66
|
+
token_uri="https://oauth2.googleapis.com/token",
|
|
67
|
+
client_id="<YOUR CLIENT ID>",
|
|
68
|
+
client_secret="<YOUR CLIENT SECRET>"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
service = service_builder.build_service(service=Service.GMAIL, key=key)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Here, we are creating the key as an `OAuthKey` object as we have clearly got the
|
|
75
|
+
tokens and client_[id|secret] from elsewhere. Creating the service is then as
|
|
76
|
+
simple as invoking the `service_builder.build_service` method which will return
|
|
77
|
+
you a service you can use.
|
|
78
|
+
|
|
79
|
+
### Other parameters
|
|
80
|
+
|
|
81
|
+
`service_builder.build_service()` can also take 2 other optional parameters.
|
|
82
|
+
|
|
83
|
+
| Parameter | Description |
|
|
84
|
+
| :-: | - |
|
|
85
|
+
| api_key | Some APIs require an API key as well as the OAuth credentials |
|
|
86
|
+
| extra_scopes | Any extra OAUth scopes required for the operation |
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
README.md
|
|
2
2
|
pyproject.toml
|
|
3
|
-
setup.py
|
|
4
3
|
python_service_builder.egg-info/PKG-INFO
|
|
5
4
|
python_service_builder.egg-info/SOURCES.txt
|
|
6
5
|
python_service_builder.egg-info/dependency_links.txt
|
|
7
|
-
python_service_builder.egg-info/not-zip-safe
|
|
8
6
|
python_service_builder.egg-info/requires.txt
|
|
9
7
|
python_service_builder.egg-info/top_level.txt
|
|
10
8
|
service_framework/__init__.py
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Copyright 2022 David Harcombe
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
import dataclasses
|
|
15
|
+
from typing import Any, Callable, Mapping
|
|
16
|
+
|
|
17
|
+
import dataclasses_json
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def lazy_property(f: Callable):
|
|
21
|
+
"""Decorator that makes a property lazy-evaluated.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
f: the function to convert to a lazy property.
|
|
25
|
+
"""
|
|
26
|
+
attr_name = '_lazy_' + f.__name__
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def _lazy_property(self) -> Any:
|
|
30
|
+
if not hasattr(self, attr_name):
|
|
31
|
+
setattr(self, attr_name, f(self))
|
|
32
|
+
return getattr(self, attr_name)
|
|
33
|
+
return _lazy_property
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def metadata(base: Mapping[str, Any], **custom) -> Mapping[str, Any]:
|
|
37
|
+
"""Merges properties into the metadata and returns the merged result.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
base (Mapping[str, Any]): the existing metadata
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Mapping[str, Any]: the merged result
|
|
44
|
+
"""
|
|
45
|
+
for key in custom:
|
|
46
|
+
if not custom[key] and key in base:
|
|
47
|
+
del base[key]
|
|
48
|
+
|
|
49
|
+
elif custom[key]:
|
|
50
|
+
base.update({key: custom[key]})
|
|
51
|
+
|
|
52
|
+
return base
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def field(default: Any = None,
|
|
56
|
+
default_factory: Any = None, **kwargs) -> dataclasses.field:
|
|
57
|
+
"""A generic dataclass field.
|
|
58
|
+
|
|
59
|
+
Only one of `default` or `default_factory` should be supplied. If both are
|
|
60
|
+
given, `default_factory` will take precedence.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
default (Any, optional): the default field value. Defaults to None.
|
|
64
|
+
default_factory (Any, optional): the default field factory. Defaults to None.
|
|
65
|
+
**kwargs (Any...): any extra metadata args.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
dataclasses.field: the field
|
|
69
|
+
"""
|
|
70
|
+
base = {
|
|
71
|
+
'exclude': lambda x: not x
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if default_factory:
|
|
75
|
+
f = dataclasses.field(default_factory=default_factory,
|
|
76
|
+
metadata=dataclasses_json.config(
|
|
77
|
+
**metadata(base=base, **kwargs)))
|
|
78
|
+
else:
|
|
79
|
+
f = dataclasses.field(default=default,
|
|
80
|
+
metadata=dataclasses_json.config(
|
|
81
|
+
**metadata(base=base, **kwargs)))
|
|
82
|
+
|
|
83
|
+
return f
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def snake_field(default: Any = None,
|
|
87
|
+
default_factory: Any = None, **kwargs) -> dataclasses.field:
|
|
88
|
+
"""Defines a generic dataclass field with a `camelCase` rendered name.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
default (Any, optional): the default field value. Defaults to None.
|
|
92
|
+
default_factory (Any, optional): the default field factory. Defaults to None.
|
|
93
|
+
**kwargs (Any...): any extra metadata args.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
dataclasses.field: the field
|
|
97
|
+
"""
|
|
98
|
+
return field(default=default, default_factory=default_factory,
|
|
99
|
+
letter_case=dataclasses_json.LetterCase.SNAKE, **kwargs)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def camel_field(default: Any = None,
|
|
103
|
+
default_factory: Any = None, **kwargs) -> dataclasses.field:
|
|
104
|
+
"""Defines a generic dataclass field with a `camelCase` rendered name.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
default (Any, optional): the default field value. Defaults to None.
|
|
108
|
+
default_factory (Any, optional): the default field factory. Defaults to None.
|
|
109
|
+
**kwargs (Any...): any extra metadata args.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
dataclasses.field: the field
|
|
113
|
+
"""
|
|
114
|
+
return field(default=default, default_factory=default_factory,
|
|
115
|
+
letter_case=dataclasses_json.LetterCase.CAMEL, **kwargs)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Copyright 2022 David Harcombe
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
import unittest
|
|
15
|
+
|
|
16
|
+
from service_framework import lazy_property, camel_field
|
|
17
|
+
import dataclasses
|
|
18
|
+
from dataclasses import Field, dataclass
|
|
19
|
+
|
|
20
|
+
from dataclasses_json import dataclass_json
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class LazyPropertyTest(unittest.TestCase):
|
|
24
|
+
class Foo(object):
|
|
25
|
+
@lazy_property
|
|
26
|
+
def lazy_thing(self) -> str:
|
|
27
|
+
return 'lazy'
|
|
28
|
+
|
|
29
|
+
def test_lazy_thing(self):
|
|
30
|
+
foo = LazyPropertyTest.Foo()
|
|
31
|
+
self.assertFalse(hasattr(foo, '_lazy_lazy_thing'))
|
|
32
|
+
self.assertEqual('lazy', foo.lazy_thing)
|
|
33
|
+
self.assertTrue(hasattr(foo, '_lazy_lazy_thing'))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class CamelFieldTest(unittest.TestCase):
|
|
37
|
+
def test_base_camel_field(self) -> None:
|
|
38
|
+
@dataclass_json
|
|
39
|
+
@dataclass
|
|
40
|
+
class Base(object):
|
|
41
|
+
_field: str = camel_field()
|
|
42
|
+
|
|
43
|
+
base = Base()
|
|
44
|
+
base._field = 'foo'
|
|
45
|
+
|
|
46
|
+
f: Field = base.__dataclass_fields__.get('_field')
|
|
47
|
+
self.assertIsNone(f.default)
|
|
48
|
+
self.assertTrue(isinstance(f.default_factory, dataclasses._MISSING_TYPE))
|
|
49
|
+
self.assertIsNotNone(f.metadata)
|
|
50
|
+
self.assertIn('letter_case', f.metadata['dataclasses_json'])
|
|
51
|
+
self.assertIn('exclude', f.metadata['dataclasses_json'])
|
|
52
|
+
|
|
53
|
+
def test_field_with_metadata_removed(self) -> None:
|
|
54
|
+
@dataclass_json
|
|
55
|
+
@dataclass
|
|
56
|
+
class Base(object):
|
|
57
|
+
_field: str = camel_field(exclude=None)
|
|
58
|
+
|
|
59
|
+
base = Base()
|
|
60
|
+
base._field = 'foo'
|
|
61
|
+
|
|
62
|
+
f = base.__dataclass_fields__.get('_field')
|
|
63
|
+
self.assertIsNone(f.default)
|
|
64
|
+
self.assertTrue(isinstance(f.default_factory, dataclasses._MISSING_TYPE))
|
|
65
|
+
self.assertIsNotNone(f.metadata)
|
|
66
|
+
self.assertIn('letter_case', f.metadata['dataclasses_json'])
|
|
67
|
+
self.assertNotIn('exclude', f.metadata['dataclasses_json'])
|
|
68
|
+
|
|
69
|
+
def test_field_with_metadata_edited(self) -> None:
|
|
70
|
+
@dataclass_json
|
|
71
|
+
@dataclass
|
|
72
|
+
class Base(object):
|
|
73
|
+
_field: str = camel_field(exclude=True)
|
|
74
|
+
|
|
75
|
+
base = Base()
|
|
76
|
+
base._field = 'foo'
|
|
77
|
+
|
|
78
|
+
f = base.__dataclass_fields__.get('_field')
|
|
79
|
+
self.assertIsNone(f.default)
|
|
80
|
+
self.assertTrue(isinstance(f.default_factory, dataclasses._MISSING_TYPE))
|
|
81
|
+
self.assertIsNotNone(f.metadata)
|
|
82
|
+
self.assertIn('letter_case', f.metadata['dataclasses_json'])
|
|
83
|
+
self.assertTrue(f.metadata['dataclasses_json']['exclude'])
|
|
84
|
+
|
|
85
|
+
def test_field_with_default(self) -> None:
|
|
86
|
+
@dataclass_json
|
|
87
|
+
@dataclass
|
|
88
|
+
class Base(object):
|
|
89
|
+
_field: str = camel_field(default='Princess Buttercup')
|
|
90
|
+
|
|
91
|
+
base = Base()
|
|
92
|
+
|
|
93
|
+
f = base.__dataclass_fields__.get('_field')
|
|
94
|
+
self.assertIsNotNone(f.default)
|
|
95
|
+
self.assertTrue(isinstance(f.default_factory, dataclasses._MISSING_TYPE))
|
|
96
|
+
self.assertEquals(base._field, 'Princess Buttercup')
|
|
97
|
+
|
|
98
|
+
def test_field_with_no_value_is_excluded(self) -> None:
|
|
99
|
+
@dataclass_json
|
|
100
|
+
@dataclass
|
|
101
|
+
class Base(object):
|
|
102
|
+
_field: str = camel_field()
|
|
103
|
+
_other_field: str = camel_field()
|
|
104
|
+
|
|
105
|
+
base = Base()
|
|
106
|
+
base._field = None
|
|
107
|
+
base._other_field = 'foo'
|
|
108
|
+
|
|
109
|
+
print(base.to_json())
|
|
110
|
+
|
|
111
|
+
f = base.__dataclass_fields__.get('_field')
|
|
112
|
+
self.assertIsNone(f.default)
|
|
113
|
+
self.assertTrue(isinstance(f.default_factory, dataclasses._MISSING_TYPE))
|
|
114
|
+
self.assertIsNotNone(f.metadata)
|
|
115
|
+
self.assertIn('letter_case', f.metadata['dataclasses_json'])
|
|
116
|
+
self.assertTrue(f.metadata['dataclasses_json']['exclude'])
|
{python-service-builder-0.1.0 → python-service-builder-1.0.1}/service_framework/service_builder.py
RENAMED
|
@@ -28,22 +28,24 @@ from google.auth import exceptions
|
|
|
28
28
|
from google.oauth2 import credentials as oauth
|
|
29
29
|
from httplib2 import Http
|
|
30
30
|
from oauth2client import service_account
|
|
31
|
+
from oauth2client import client
|
|
31
32
|
|
|
32
|
-
from .services import Service
|
|
33
|
-
from
|
|
33
|
+
from service_framework.services import Service
|
|
34
|
+
from service_framework import snake_field
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
|
|
37
|
+
@dataclasses_json.dataclass_json(undefined=dataclasses_json.Undefined.EXCLUDE)
|
|
36
38
|
@dataclasses.dataclass
|
|
37
39
|
class OAuthKey(object):
|
|
38
40
|
"""Dataclass from the json key.
|
|
39
41
|
|
|
40
42
|
NOTE: This is by no means the entire key; just the fields neccessary for OAuth.
|
|
41
43
|
"""
|
|
42
|
-
access_token: Optional[str] =
|
|
43
|
-
refresh_token: Optional[str] =
|
|
44
|
-
token_uri: Optional[str] =
|
|
45
|
-
client_id: Optional[str] =
|
|
46
|
-
client_secret: Optional[str] =
|
|
44
|
+
access_token: Optional[str] = snake_field(field_name='token')
|
|
45
|
+
refresh_token: Optional[str] = snake_field()
|
|
46
|
+
token_uri: Optional[str] = snake_field()
|
|
47
|
+
client_id: Optional[str] = snake_field()
|
|
48
|
+
client_secret: Optional[str] = snake_field()
|
|
47
49
|
|
|
48
50
|
|
|
49
51
|
def build_service(service: Service,
|
|
@@ -74,22 +76,10 @@ def build_service(service: Service,
|
|
|
74
76
|
if extra_scopes:
|
|
75
77
|
kwargs['scopes'] = extra_scopes
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
credentials = oauth.Credentials(**kwargs)
|
|
79
|
-
https = google_auth_httplib2.AuthorizedHttp(credentials)
|
|
80
|
-
|
|
81
|
-
except KeyError:
|
|
82
|
-
logging.exception(
|
|
83
|
-
'Invalid credentials received: missing a part of the credentials')
|
|
84
|
-
raise
|
|
85
|
-
|
|
86
|
-
except exceptions.RefreshError as error:
|
|
87
|
-
logging.exception('Invalid credentials received')
|
|
88
|
-
raise
|
|
79
|
+
credentials = oauth.Credentials(**kwargs)
|
|
89
80
|
|
|
90
81
|
elif isinstance(key, oauth.Credentials):
|
|
91
82
|
credentials = key
|
|
92
|
-
https = google_auth_httplib2.AuthorizedHttp(credentials)
|
|
93
83
|
|
|
94
84
|
elif isinstance(key, str):
|
|
95
85
|
kwargs = {
|
|
@@ -98,32 +88,25 @@ def build_service(service: Service,
|
|
|
98
88
|
if extra_scopes:
|
|
99
89
|
kwargs['scopes'] = extra_scopes
|
|
100
90
|
|
|
101
|
-
credentials =
|
|
102
|
-
service_account.ServiceAccountCredentials.from_json_keyfile_name(
|
|
103
|
-
**kwargs)
|
|
104
|
-
https = credentials.authorize(Http())
|
|
91
|
+
credentials = oauth.Credentials.from_authorized_user_file(**kwargs)
|
|
105
92
|
|
|
106
93
|
elif isinstance(key, Mapping):
|
|
107
|
-
kwargs =
|
|
108
|
-
'keyfile_dict': key,
|
|
109
|
-
}
|
|
94
|
+
kwargs = OAuthKey(**key).to_dict()
|
|
110
95
|
|
|
111
96
|
if extra_scopes:
|
|
112
97
|
kwargs['scopes'] = extra_scopes
|
|
113
98
|
|
|
114
|
-
credentials =
|
|
115
|
-
service_account.ServiceAccountCredentials.from_json_keyfile_dict(
|
|
116
|
-
key, scopes=extra_scopes)
|
|
117
|
-
https = credentials.authorize(Http())
|
|
99
|
+
credentials = oauth.Credentials(**kwargs)
|
|
118
100
|
|
|
119
101
|
else:
|
|
120
102
|
raise Exception('No valid credentials provided.')
|
|
121
103
|
|
|
104
|
+
https = google_auth_httplib2.AuthorizedHttp(credentials)
|
|
122
105
|
discovery_args = {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
106
|
+
'http': https,
|
|
107
|
+
'developerKey': api_key,
|
|
108
|
+
'cache_discovery': False,
|
|
109
|
+
**definition.to_dict()
|
|
127
110
|
}
|
|
128
111
|
|
|
129
112
|
return discovery.build(**discovery_args)
|
|
@@ -20,18 +20,24 @@ from typing import Any, Optional
|
|
|
20
20
|
import dataclasses_json
|
|
21
21
|
import immutabledict
|
|
22
22
|
|
|
23
|
-
from . import
|
|
23
|
+
from . import camel_field, lazy_property
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
@dataclasses_json.dataclass_json
|
|
27
27
|
@dataclasses.dataclass
|
|
28
28
|
class ServiceDefinition(object):
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
"""Defines a Google Service for the builder."""
|
|
30
|
+
service_name: Optional[str] = camel_field()
|
|
31
|
+
version: Optional[str] = camel_field()
|
|
32
|
+
discovery_service_url: Optional[str] = camel_field()
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
class S(enum.Enum):
|
|
36
|
+
"""Defines the generic Enum for any service.
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
ValueError: if no enum is defined.
|
|
40
|
+
"""
|
|
35
41
|
@lazy_property
|
|
36
42
|
def definition(self) -> ServiceDefinition:
|
|
37
43
|
"""Fetch the ServiceDefinition.
|
|
@@ -52,7 +58,18 @@ class S(enum.Enum):
|
|
|
52
58
|
f'?version={version}'))
|
|
53
59
|
|
|
54
60
|
@classmethod
|
|
55
|
-
def from_value(cls, value) -> S:
|
|
61
|
+
def from_value(cls, value: str) -> S:
|
|
62
|
+
"""Creates a service enum from the name of the service.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
value (str): the service name
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
ValueError: no service found
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
S: the service definition
|
|
72
|
+
"""
|
|
56
73
|
for k, v in cls.__members__.items():
|
|
57
74
|
if k == value.upper():
|
|
58
75
|
return v
|
{python-service-builder-0.1.0 → python-service-builder-1.0.1}/service_framework/services_test.py
RENAMED
|
@@ -17,8 +17,8 @@ from service_framework import services
|
|
|
17
17
|
|
|
18
18
|
SA360_DEFINITION = \
|
|
19
19
|
services.ServiceDefinition(
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
service_name='doubleclicksearch',
|
|
21
|
+
discovery_service_url='https://doubleclicksearch.googleapis.com/$discovery/rest?version=v2',
|
|
22
22
|
version='v2')
|
|
23
23
|
GMAIL_ARGS = {
|
|
24
24
|
'serviceName': 'gmail',
|
|
@@ -29,10 +29,7 @@ GMAIL_ARGS = {
|
|
|
29
29
|
|
|
30
30
|
class ServicesTest(unittest.TestCase):
|
|
31
31
|
def test_valid_service(self):
|
|
32
|
-
self.assertGreater(services.Service.
|
|
32
|
+
self.assertGreater(services.Service.DOUBLECLICKSEARCH.value, 0)
|
|
33
33
|
|
|
34
34
|
def test_single_definition(self):
|
|
35
|
-
self.assertEqual(SA360_DEFINITION, services.Service.
|
|
36
|
-
|
|
37
|
-
def test_single_to_args(self):
|
|
38
|
-
self.assertEqual(GMAIL_ARGS, services.Service.GMAIL.definition.to_args)
|
|
35
|
+
self.assertEqual(SA360_DEFINITION, services.Service.DOUBLECLICKSEARCH.definition)
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: python-service-builder
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Helper library for easier creation of Google services.
|
|
5
|
-
Home-page:
|
|
6
|
-
Author: David Harcombe
|
|
7
|
-
Author-email: david.harcombe@gmail.com
|
|
8
|
-
License: Apache 2.0
|
|
9
|
-
Classifier: Development Status :: 4 - Beta
|
|
10
|
-
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: Topic :: Software Development
|
|
12
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
-
Requires-Python: >=3.9
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
|
|
18
|
-
# Python Library for helping to create Python services from Google APIs
|
|
19
|
-
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: python-service-builder
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Helper library for easier creation of Google services.
|
|
5
|
-
Home-page:
|
|
6
|
-
Author: David Harcombe
|
|
7
|
-
Author-email: david.harcombe@gmail.com
|
|
8
|
-
License: Apache 2.0
|
|
9
|
-
Classifier: Development Status :: 4 - Beta
|
|
10
|
-
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: Topic :: Software Development
|
|
12
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
-
Requires-Python: >=3.9
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
|
|
18
|
-
# Python Library for helping to create Python services from Google APIs
|
|
19
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
# Copyright 2022 David Harcombe
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
import dataclasses
|
|
15
|
-
from typing import Any, Callable, Mapping
|
|
16
|
-
|
|
17
|
-
import dataclasses_json
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def lazy_property(f: Callable):
|
|
21
|
-
"""Decorator that makes a property lazy-evaluated.
|
|
22
|
-
|
|
23
|
-
Args:
|
|
24
|
-
f: the function to convert to a lazy property.
|
|
25
|
-
"""
|
|
26
|
-
attr_name = '_lazy_' + f.__name__
|
|
27
|
-
|
|
28
|
-
@property
|
|
29
|
-
def _lazy_property(self) -> Any:
|
|
30
|
-
if not hasattr(self, attr_name):
|
|
31
|
-
setattr(self, attr_name, f(self))
|
|
32
|
-
return getattr(self, attr_name)
|
|
33
|
-
return _lazy_property
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def metadata(base: Mapping[str, Any], **custom) -> Mapping[str, Any]:
|
|
37
|
-
for key in custom:
|
|
38
|
-
if not custom[key] and key in base:
|
|
39
|
-
del base[key]
|
|
40
|
-
|
|
41
|
-
elif custom[key]:
|
|
42
|
-
base.update({key: custom[key]})
|
|
43
|
-
|
|
44
|
-
return base
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def field(default: Any = None, default_factory: Any = None, **kwargs):
|
|
48
|
-
base = {
|
|
49
|
-
'letter_case': dataclasses_json.LetterCase.CAMEL,
|
|
50
|
-
'exclude': lambda x: not x
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if kwargs:
|
|
54
|
-
exclude = kwargs.get('exclude', lambda x: not x)
|
|
55
|
-
else:
|
|
56
|
-
def exclude(x): return not x
|
|
57
|
-
|
|
58
|
-
if default_factory:
|
|
59
|
-
f = dataclasses.field(default_factory=default_factory,
|
|
60
|
-
metadata=dataclasses_json.config(
|
|
61
|
-
**metadata(base=base, **kwargs)))
|
|
62
|
-
else:
|
|
63
|
-
f = dataclasses.field(default=default,
|
|
64
|
-
metadata=dataclasses_json.config(
|
|
65
|
-
**metadata(base=base, **kwargs)))
|
|
66
|
-
|
|
67
|
-
return f
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Copyright 2022 David Harcombe
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
import unittest
|
|
15
|
-
|
|
16
|
-
from . import lazy_property
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class LazyPropertyTest(unittest.TestCase):
|
|
20
|
-
class Foo(object):
|
|
21
|
-
@lazy_property
|
|
22
|
-
def lazy_thing(self) -> str:
|
|
23
|
-
return 'lazy'
|
|
24
|
-
|
|
25
|
-
def test_lazy_thing(self):
|
|
26
|
-
foo = LazyPropertyTest.Foo()
|
|
27
|
-
self.assertFalse(hasattr(foo, '_lazy_lazy_thing'))
|
|
28
|
-
self.assertEqual('lazy', foo.lazy_thing)
|
|
29
|
-
self.assertTrue(hasattr(foo, '_lazy_lazy_thing'))
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# Copyright 2022 David Harcombe. All Rights Reserved.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
import setuptools
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
with open("README.md", "r", encoding="utf-8") as fh:
|
|
18
|
-
long_description = fh.read()
|
|
19
|
-
|
|
20
|
-
setuptools.setup(
|
|
21
|
-
name='python-service-builder',
|
|
22
|
-
version='0.1.0',
|
|
23
|
-
description='Helper library for easier creation of Google services.',
|
|
24
|
-
long_description=long_description,
|
|
25
|
-
long_description_content_type='text/markdown',
|
|
26
|
-
url='',
|
|
27
|
-
author='David Harcombe',
|
|
28
|
-
author_email='david.harcombe@gmail.com',
|
|
29
|
-
license='Apache 2.0',
|
|
30
|
-
zip_safe=False,
|
|
31
|
-
include_package_data=True,
|
|
32
|
-
packages=setuptools.find_packages(),
|
|
33
|
-
classifiers=[
|
|
34
|
-
'Development Status :: 4 - Beta',
|
|
35
|
-
'Intended Audience :: Developers',
|
|
36
|
-
'Topic :: Software Development',
|
|
37
|
-
'License :: OSI Approved :: Apache Software License',
|
|
38
|
-
'Programming Language :: Python :: 3',
|
|
39
|
-
'Programming Language :: Python :: 3.9',
|
|
40
|
-
],
|
|
41
|
-
python_requires=">=3.9",
|
|
42
|
-
install_requires=[
|
|
43
|
-
'absl-py>=0.12.0',
|
|
44
|
-
'dataclasses-json>=0.5.2',
|
|
45
|
-
'gcs-oauth2-boto-plugin>=2.7',
|
|
46
|
-
'google-api-core>=1.26.1',
|
|
47
|
-
'google-api-python-client>=2.0.2',
|
|
48
|
-
'google-auth-httplib2>=0.1.0',
|
|
49
|
-
'google-auth-oauthlib>=0.4.3',
|
|
50
|
-
'google-auth>=1.28.0',
|
|
51
|
-
'google-reauth>=0.1.1',
|
|
52
|
-
'googleapis-common-protos>=1.53.0',
|
|
53
|
-
'httplib2>=0.19.0',
|
|
54
|
-
'immutabledict>=2.2.1',
|
|
55
|
-
'oauth2client>=4.1.3',
|
|
56
|
-
'oauthlib>=3.1.0',
|
|
57
|
-
],
|
|
58
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|