willisapi-client 1.9.2__tar.gz → 1.9.4__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.
Files changed (54) hide show
  1. willisapi_client-1.9.4/PKG-INFO +132 -0
  2. willisapi_client-1.9.4/README.md +120 -0
  3. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/__init__.py +4 -8
  4. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/__version__.py +1 -1
  5. willisapi_client-1.9.4/willisapi_client/services/api.py +8 -0
  6. willisapi_client-1.9.4/willisapi_client/services/metadata/__init__.py +4 -0
  7. willisapi_client-1.9.4/willisapi_client/services/metadata/upload.py +194 -0
  8. willisapi_client-1.9.4/willisapi_client/services/metadata/utils.py +746 -0
  9. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/willisapi_client.py +4 -10
  10. willisapi_client-1.9.4/willisapi_client.egg-info/PKG-INFO +132 -0
  11. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client.egg-info/SOURCES.txt +2 -17
  12. willisapi_client-1.9.2/PKG-INFO +0 -83
  13. willisapi_client-1.9.2/README.md +0 -71
  14. willisapi_client-1.9.2/tests/test_auth.py +0 -69
  15. willisapi_client-1.9.2/tests/test_csv_validation.py +0 -556
  16. willisapi_client-1.9.2/tests/test_download.py +0 -62
  17. willisapi_client-1.9.2/tests/test_upload.py +0 -126
  18. willisapi_client-1.9.2/willisapi_client/services/api.py +0 -11
  19. willisapi_client-1.9.2/willisapi_client/services/auth/__init__.py +0 -6
  20. willisapi_client-1.9.2/willisapi_client/services/auth/auth_utils.py +0 -52
  21. willisapi_client-1.9.2/willisapi_client/services/auth/login_manager.py +0 -52
  22. willisapi_client-1.9.2/willisapi_client/services/download/__init__.py +0 -6
  23. willisapi_client-1.9.2/willisapi_client/services/download/download_handler.py +0 -50
  24. willisapi_client-1.9.2/willisapi_client/services/download/download_utils.py +0 -319
  25. willisapi_client-1.9.2/willisapi_client/services/metadata/__init__.py +0 -4
  26. willisapi_client-1.9.2/willisapi_client/services/metadata/upload.py +0 -83
  27. willisapi_client-1.9.2/willisapi_client/services/metadata/utils.py +0 -336
  28. willisapi_client-1.9.2/willisapi_client/services/upload/__init__.py +0 -6
  29. willisapi_client-1.9.2/willisapi_client/services/upload/csv_validation.py +0 -643
  30. willisapi_client-1.9.2/willisapi_client/services/upload/multipart_upload_handler.py +0 -61
  31. willisapi_client-1.9.2/willisapi_client/services/upload/upload_utils.py +0 -389
  32. willisapi_client-1.9.2/willisapi_client/services/upload/utils.py +0 -3
  33. willisapi_client-1.9.2/willisapi_client.egg-info/PKG-INFO +0 -83
  34. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/LICENSE +0 -0
  35. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/MANIFEST.in +0 -0
  36. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/RELEASE.md +0 -0
  37. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/requirements.txt +0 -0
  38. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/setup.cfg +0 -0
  39. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/setup.py +0 -0
  40. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/tests/test_diarize.py +0 -0
  41. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/tests/test_diarize_call_remaining.py +0 -0
  42. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/logging_setup.py +0 -0
  43. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/services/__init__.py +0 -0
  44. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/services/diarize/__init__.py +0 -0
  45. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/services/diarize/diarize_utils.py +0 -0
  46. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/services/diarize/willisdiarize.py +0 -0
  47. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/services/diarize/willisdiarize_call_remaining.py +0 -0
  48. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/services/exceptions.py +0 -0
  49. {willisapi_client-1.9.2/willisapi_client/services/upload → willisapi_client-1.9.4/willisapi_client/services/metadata}/language_choices.py +0 -0
  50. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client/timer.py +0 -0
  51. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client.egg-info/dependency_links.txt +0 -0
  52. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client.egg-info/not-zip-safe +0 -0
  53. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client.egg-info/requires.txt +0 -0
  54. {willisapi_client-1.9.2 → willisapi_client-1.9.4}/willisapi_client.egg-info/top_level.txt +0 -0
@@ -0,0 +1,132 @@
1
+ Metadata-Version: 2.1
2
+ Name: willisapi_client
3
+ Version: 1.9.4
4
+ Summary: A Python client for willisapi
5
+ Home-page: https://github.com/bklynhlth/willsiapi_client
6
+ Author: bklynhlth
7
+ Author-email: admin@brooklyn.health
8
+ License: Apache
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+
13
+ <!-- Output copied to clipboard! -->
14
+
15
+ <!-----
16
+
17
+ Yay, no errors, warnings, or alerts!
18
+
19
+ Conversion time: 0.36 seconds.
20
+
21
+
22
+ Using this Markdown file:
23
+
24
+ 1. Paste this output into your source file.
25
+ 2. See the notes and action items below regarding this conversion run.
26
+ 3. Check the rendered output (headings, lists, code blocks, tables) for proper
27
+ formatting and use a linkchecker before you publish this page.
28
+
29
+ Conversion notes:
30
+
31
+ * Docs to Markdown version 1.0β34
32
+ * Mon Aug 21 2023 13:41:56 GMT-0700 (PDT)
33
+ * Source doc: README.md
34
+ ----->
35
+
36
+
37
+
38
+ ### WillisAPI Client
39
+
40
+ WillisAPI Client is the Python interface for Brooklyn Health’s WillisAPI.
41
+
42
+ Official documentation for WillisAPI Client can be found in the [Github Wiki](http://www.github.com/bklynhlth/willisapi_client/wiki).
43
+
44
+ To learn more about Brooklyn Health or WillisAPI, visit [brooklyn.health](https://www.brooklyn.health) or [getintouch@brooklyn.health](mailto:getintouch@brooklyn.health).
45
+
46
+ ---
47
+
48
+ #### Installation
49
+
50
+
51
+ ```bash
52
+ pip install willisapi_client
53
+ ```
54
+
55
+ ---
56
+
57
+ #### Getting a Personal Access Token (PAT)
58
+ 1. Log in to the Brooklyn Health web application.
59
+ 2. Go to your profile section.
60
+ 3. Navigate to Personal Access Token (PAT) and copy it for use in the client.
61
+
62
+ ---
63
+
64
+ #### Usage
65
+
66
+ **Upload**
67
+ To upload a CSV file:
68
+
69
+ ```python
70
+ summary = willisapi.upload(key, '/path/to/data.csv')
71
+ ```
72
+
73
+ How to Call the Function
74
+ - key: Your PAT token.
75
+ - data.csv: Path to your CSV file.
76
+
77
+ How to Reupload
78
+
79
+ If you need to reupload the same or updated file, simply call the upload function again:
80
+
81
+ ```python
82
+ summary = willisapi.upload(key, 'data.csv', force_uploade=True)
83
+ ```
84
+ ---
85
+ #### Understanding Returned DataFrame and Errors
86
+
87
+ - The upload function returns a summary DataFrame containing the results of your upload.
88
+ - Columns typically include status, error messages, and metadata for each row in your CSV.
89
+ - If there are errors, they will be listed in the DataFrame under an error or message column.
90
+ - Review the DataFrame to identify and resolve any issues before reuploading.
91
+
92
+ ---
93
+
94
+ #### CSV Validation Details
95
+
96
+ Before uploading, the client validates your CSV for:
97
+
98
+ - **Required Columns**: Must include study_id, site_id, participant_id, visit_name, visit_order, coa_name, coa_item_number, coa_item_value, file_path, time_collected.
99
+ - **Optional Columns**: rater_id, age, sex, race, language.
100
+ - **Valid COA Name**: Only these values are allowed: MADRS, YMRS, PHQ-9, GAD-7.
101
+ - **Valid Audio File**: The file path in each row must exist and be accessible.
102
+ - **Valid Data Types**: visit_order, age, coa_item_number, and coa_item_value must be numeric.
103
+ - **Language**: If present, must be in the allowed language choices.
104
+
105
+ If any validation fails, errors are collected and returned for review before upload proceeds.
106
+
107
+ ---
108
+
109
+ **Processed Data Upload**
110
+
111
+ To upload a processed data CSV file:
112
+
113
+ ```python
114
+ summary = willisapi.processed_upload(key, '/path/to/processed-data.csv')
115
+ ```
116
+
117
+ How to Call the Function
118
+ - key: Your PAT token.
119
+ - processed-data.csv: Path to your processed data CSV file.
120
+
121
+ ---
122
+
123
+ For more information on how to organize the `data.csv`, visit the [Github Wiki](http://www.github.com/bklynhlth/willisapi_client/wiki).
124
+
125
+
126
+ If you run into trouble while using the client, please raise it in the [Issues](http://www.github.com/bklynhlth/willisapi_client/issues) tab.
127
+
128
+ ***
129
+
130
+ Brooklyn Health is a small team of clinicians, scientists, and engineers based in Brooklyn, NY.
131
+
132
+ We develop and maintain [OpenWillis](http://www.github.com/bklynhlth/openwillis), an open source python library for digital health measurement.
@@ -0,0 +1,120 @@
1
+ <!-- Output copied to clipboard! -->
2
+
3
+ <!-----
4
+
5
+ Yay, no errors, warnings, or alerts!
6
+
7
+ Conversion time: 0.36 seconds.
8
+
9
+
10
+ Using this Markdown file:
11
+
12
+ 1. Paste this output into your source file.
13
+ 2. See the notes and action items below regarding this conversion run.
14
+ 3. Check the rendered output (headings, lists, code blocks, tables) for proper
15
+ formatting and use a linkchecker before you publish this page.
16
+
17
+ Conversion notes:
18
+
19
+ * Docs to Markdown version 1.0β34
20
+ * Mon Aug 21 2023 13:41:56 GMT-0700 (PDT)
21
+ * Source doc: README.md
22
+ ----->
23
+
24
+
25
+
26
+ ### WillisAPI Client
27
+
28
+ WillisAPI Client is the Python interface for Brooklyn Health’s WillisAPI.
29
+
30
+ Official documentation for WillisAPI Client can be found in the [Github Wiki](http://www.github.com/bklynhlth/willisapi_client/wiki).
31
+
32
+ To learn more about Brooklyn Health or WillisAPI, visit [brooklyn.health](https://www.brooklyn.health) or [getintouch@brooklyn.health](mailto:getintouch@brooklyn.health).
33
+
34
+ ---
35
+
36
+ #### Installation
37
+
38
+
39
+ ```bash
40
+ pip install willisapi_client
41
+ ```
42
+
43
+ ---
44
+
45
+ #### Getting a Personal Access Token (PAT)
46
+ 1. Log in to the Brooklyn Health web application.
47
+ 2. Go to your profile section.
48
+ 3. Navigate to Personal Access Token (PAT) and copy it for use in the client.
49
+
50
+ ---
51
+
52
+ #### Usage
53
+
54
+ **Upload**
55
+ To upload a CSV file:
56
+
57
+ ```python
58
+ summary = willisapi.upload(key, '/path/to/data.csv')
59
+ ```
60
+
61
+ How to Call the Function
62
+ - key: Your PAT token.
63
+ - data.csv: Path to your CSV file.
64
+
65
+ How to Reupload
66
+
67
+ If you need to reupload the same or updated file, simply call the upload function again:
68
+
69
+ ```python
70
+ summary = willisapi.upload(key, 'data.csv', force_uploade=True)
71
+ ```
72
+ ---
73
+ #### Understanding Returned DataFrame and Errors
74
+
75
+ - The upload function returns a summary DataFrame containing the results of your upload.
76
+ - Columns typically include status, error messages, and metadata for each row in your CSV.
77
+ - If there are errors, they will be listed in the DataFrame under an error or message column.
78
+ - Review the DataFrame to identify and resolve any issues before reuploading.
79
+
80
+ ---
81
+
82
+ #### CSV Validation Details
83
+
84
+ Before uploading, the client validates your CSV for:
85
+
86
+ - **Required Columns**: Must include study_id, site_id, participant_id, visit_name, visit_order, coa_name, coa_item_number, coa_item_value, file_path, time_collected.
87
+ - **Optional Columns**: rater_id, age, sex, race, language.
88
+ - **Valid COA Name**: Only these values are allowed: MADRS, YMRS, PHQ-9, GAD-7.
89
+ - **Valid Audio File**: The file path in each row must exist and be accessible.
90
+ - **Valid Data Types**: visit_order, age, coa_item_number, and coa_item_value must be numeric.
91
+ - **Language**: If present, must be in the allowed language choices.
92
+
93
+ If any validation fails, errors are collected and returned for review before upload proceeds.
94
+
95
+ ---
96
+
97
+ **Processed Data Upload**
98
+
99
+ To upload a processed data CSV file:
100
+
101
+ ```python
102
+ summary = willisapi.processed_upload(key, '/path/to/processed-data.csv')
103
+ ```
104
+
105
+ How to Call the Function
106
+ - key: Your PAT token.
107
+ - processed-data.csv: Path to your processed data CSV file.
108
+
109
+ ---
110
+
111
+ For more information on how to organize the `data.csv`, visit the [Github Wiki](http://www.github.com/bklynhlth/willisapi_client/wiki).
112
+
113
+
114
+ If you run into trouble while using the client, please raise it in the [Issues](http://www.github.com/bklynhlth/willisapi_client/issues) tab.
115
+
116
+ ***
117
+
118
+ Brooklyn Health is a small team of clinicians, scientists, and engineers based in Brooklyn, NY.
119
+
120
+ We develop and maintain [OpenWillis](http://www.github.com/bklynhlth/openwillis), an open source python library for digital health measurement.
@@ -2,19 +2,15 @@
2
2
 
3
3
  # import the required packages
4
4
  from willisapi_client.services.api import (
5
- login,
6
- upload,
7
- download,
8
5
  willis_diarize_call_remaining,
9
6
  willis_diarize,
10
- metadata_upload,
7
+ upload,
8
+ processed_upload
11
9
  )
12
10
 
13
11
  __all__ = [
14
- "login",
15
- "upload",
16
- "download",
17
12
  "willis_diarize_call_remaining",
18
13
  "willis_diarize",
19
- "metadata_upload",
14
+ "upload",
15
+ "processed_upload"
20
16
  ]
@@ -1,7 +1,7 @@
1
1
  """Version details for willisapi_client"""
2
2
 
3
3
  __client__ = "willisapi_client"
4
- __latestVersion__ = "1.9.2"
4
+ __latestVersion__ = "1.9.4"
5
5
  __url__ = "https://github.com/bklynhlth/willsiapi_client"
6
6
  __short_description__ = "A Python client for willisapi"
7
7
  __content_type__ = "text/markdown"
@@ -0,0 +1,8 @@
1
+ # website: https://www.brooklyn.health
2
+
3
+ # import the required packages
4
+ from willisapi_client.services.diarize import (
5
+ willis_diarize_call_remaining,
6
+ willis_diarize,
7
+ )
8
+ from willisapi_client.services.metadata import upload, processed_upload
@@ -0,0 +1,4 @@
1
+ # website: https://www.brooklyn.health
2
+ from .upload import upload, processed_upload
3
+
4
+ __all__ = ["upload", "processed_upload"]
@@ -0,0 +1,194 @@
1
+ import pandas as pd
2
+ from tqdm import tqdm
3
+ from datetime import datetime
4
+ import requests
5
+ import mimetypes
6
+ import os
7
+
8
+ from willisapi_client.timer import measure
9
+ from willisapi_client.willisapi_client import WillisapiClient
10
+ from willisapi_client.logging_setup import logger as logger
11
+ from willisapi_client.services.metadata.utils import (
12
+ MetadataValidation,
13
+ ProcessedMetadataValidation,
14
+ UploadUtils,
15
+ find_files_with_pattern,
16
+ get_last_n_directories,
17
+ )
18
+
19
+
20
+ @measure
21
+ def upload(api_key: str, csv_path: str, **kwargs):
22
+
23
+ force_upload = kwargs.get("force_upload", False)
24
+ csv = MetadataValidation(csv_path=csv_path, force_upload=force_upload)
25
+ if csv.load_and_validate():
26
+ logger.info(f'{datetime.now().strftime("%H:%M:%S")}: csv check passed')
27
+ csv.create_final_csv()
28
+
29
+ wc = WillisapiClient(env=kwargs.get("env"))
30
+ url = wc.get_upload_url()
31
+ headers = wc.get_headers()
32
+ headers["Authorization"] = f"token {api_key}"
33
+ logger.info(f'{datetime.now().strftime("%H:%M:%S")}: beginning upload')
34
+
35
+ results = []
36
+ for index, row in tqdm(
37
+ csv.transformed_df.iterrows(), total=csv.transformed_df.shape[0]
38
+ ):
39
+ u = UploadUtils(row)
40
+ valid, err = u.validate_row()
41
+ result_row = row.to_dict()
42
+ if valid:
43
+ payload = u.generate_payload()
44
+ res = u.post(api_key, url, headers, payload)
45
+ if res.get("upload_status") == "Success":
46
+ result_row["upload_status"] = "Success"
47
+ result_row["error"] = None
48
+
49
+ # Handle S3 upload if presigned URL is provided
50
+ presigned = res.get("response", {}).get("presigned")
51
+ if presigned:
52
+ try:
53
+ content_type, _ = mimetypes.guess_type(
54
+ payload.get("filename")
55
+ )
56
+ if not content_type:
57
+ content_type = "application/octet-stream"
58
+ with open(row.file_path, "rb") as f:
59
+ response = requests.put(
60
+ presigned,
61
+ data=f,
62
+ headers={
63
+ "x-amz-checksum-sha256": payload.get(
64
+ "checksum"
65
+ ),
66
+ "x-amz-sdk-checksum-algorithm": "SHA256",
67
+ "Content-Type": content_type,
68
+ },
69
+ )
70
+ if response.status_code == 200:
71
+ result_row["upload_status"] = "Success"
72
+ else:
73
+ result_row["upload_status"] = "Failed"
74
+ result_row["error"] = (
75
+ f"S3 upload failed with status code {response.status_code}"
76
+ )
77
+ except Exception as ex:
78
+ result_row["upload_status"] = "Failed"
79
+ result_row["error"] = str(ex)
80
+ else:
81
+ result_row["upload_status"] = "Failed"
82
+ result_row["error"] = (
83
+ "Collect recording upload URL not received"
84
+ )
85
+ else:
86
+ result_row["upload_status"] = "Failed"
87
+ result_row["error"] = res.get("error")
88
+ else:
89
+ result_row["upload_status"] = "Failed"
90
+ result_row["error"] = f"{err}"
91
+ results.append(result_row)
92
+
93
+ results_df = pd.DataFrame(results)
94
+ return results_df
95
+ else:
96
+ logger.error(f'{datetime.now().strftime("%H:%M:%S")}: csv check failed')
97
+ logger.error(csv.errors)
98
+ return None
99
+
100
+
101
+ @measure
102
+ def processed_upload(api_key: str, csv_path: str, output_path: str, **kwargs):
103
+
104
+ force_upload = kwargs.get("force_upload", False)
105
+ csv = ProcessedMetadataValidation(csv_path=csv_path, force_upload=force_upload)
106
+ if csv.load_and_validate():
107
+ logger.info(f'{datetime.now().strftime("%H:%M:%S")}: csv check passed')
108
+ csv.create_final_csv()
109
+
110
+ wc = WillisapiClient(env=kwargs.get("env"))
111
+ url = wc.get_processed_upload_url()
112
+ headers = wc.get_headers()
113
+ headers["Authorization"] = f"token {api_key}"
114
+ logger.info(f'{datetime.now().strftime("%H:%M:%S")}: beginning upload')
115
+
116
+ results = []
117
+ for index, row in tqdm(
118
+ csv.transformed_df.iterrows(), total=csv.transformed_df.shape[0]
119
+ ):
120
+ u = UploadUtils(row)
121
+ valid, err = u.validate_processed_data_row()
122
+ result_row = row.to_dict()
123
+ if valid:
124
+ filename = os.path.basename(row.recording).split(".")[0]
125
+ files = []
126
+ for file in find_files_with_pattern(output_path, filename):
127
+ key, error = get_last_n_directories(file, n=2)
128
+ if error:
129
+ continue
130
+ checksum = u.calculate_file_checksum(file)
131
+ files.append(
132
+ {
133
+ "index": index,
134
+ "recording": file,
135
+ "key": key,
136
+ "checksum": checksum,
137
+ }
138
+ )
139
+ payload = u.generate_processed_payload(files)
140
+ res = u.post(api_key, url, headers, payload)
141
+ if res.get("upload_status") == "Success":
142
+ result_row["upload_status"] = "Success"
143
+ result_row["error"] = None
144
+
145
+ # Handle S3 upload if presigned URL is provided
146
+ for file_presigned in res.get("response", []):
147
+ presigned = file_presigned.get("presigned")
148
+ checksum = file_presigned.get("checksum")
149
+ recording = file_presigned.get("recording")
150
+ index = file_presigned.get("index")
151
+ try:
152
+ content_type, _ = mimetypes.guess_type(recording)
153
+ if not content_type:
154
+ content_type = "text/csv"
155
+ with open(recording, "rb") as f:
156
+ response = requests.put(
157
+ presigned,
158
+ data=f,
159
+ headers={
160
+ "x-amz-checksum-sha256": checksum,
161
+ "x-amz-sdk-checksum-algorithm": "SHA256",
162
+ "Content-Type": content_type,
163
+ },
164
+ )
165
+ if response.status_code == 200:
166
+ result_row["upload_status"] = "Success"
167
+ else:
168
+ result_row["upload_status"] = "Failed"
169
+ if result_row["error"] is None:
170
+ result_row["error"] = ""
171
+ result_row["error"] = (
172
+ result_row["error"]
173
+ + "\n"
174
+ + f"S3 upload failed with status code {response.status_code} for file {recording}"
175
+ )
176
+ except Exception as ex:
177
+ result_row["upload_status"] = "Failed"
178
+ if result_row["error"] is None:
179
+ result_row["error"] = ""
180
+ result_row["error"] = result_row["error"] + "\n" + str(ex)
181
+ else:
182
+ result_row["upload_status"] = "Failed"
183
+ result_row["error"] = res.get("error")
184
+ else:
185
+ result_row["upload_status"] = "Failed"
186
+ result_row["error"] = f"{err}"
187
+ results.append(result_row)
188
+
189
+ results_df = pd.DataFrame(results)
190
+ return results_df
191
+ else:
192
+ logger.error(f'{datetime.now().strftime("%H:%M:%S")}: csv check failed')
193
+ logger.error(csv.errors)
194
+ return None