medicafe 0.240613.0__py3-none-any.whl → 0.240809.0__py3-none-any.whl

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.

Potentially problematic release.


This version of medicafe might be problematic. Click here for more details.

@@ -12,7 +12,7 @@ sys.path.append(project_dir)
12
12
  from MediBot import MediBot_Preprocessor_lib
13
13
  load_insurance_data_from_mains = MediBot_Preprocessor_lib.load_insurance_data_from_mains
14
14
  from MediBot import MediBot_Crosswalk_Library
15
- from MediLink_API_v2 import fetch_payer_name_from_api
15
+ from MediLink_API_v3 import fetch_payer_name_from_api
16
16
 
17
17
  # Converts date format from one format to another.
18
18
  def convert_date_format(date_str):
@@ -288,7 +288,7 @@ def resolve_payer_name(payer_id, config, primary_endpoint, insurance_name, parse
288
288
  MediLink_ConfigLoader.log("API Resolved to standard insurance name: {} for corrected payer ID: {}".format(resolved_name, corrected_payer_id), config, level="INFO")
289
289
 
290
290
  confirmation = input("Is the standard insurance name '{}' correct? (yes/no): ".format(resolved_name)).strip().lower()
291
-
291
+ # BUG There is duplication of code here.
292
292
  if confirmation in ['yes', 'y']:
293
293
  if MediBot_Crosswalk_Library.update_crosswalk_with_corrected_payer_id(payer_id, corrected_payer_id):
294
294
  return resolved_name
@@ -309,11 +309,16 @@ def resolve_payer_name(payer_id, config, primary_endpoint, insurance_name, parse
309
309
 
310
310
  def prompt_user_for_payer_id(insurance_name):
311
311
  """
312
- Prompts the user to input the payer ID manually.
312
+ Prompts the user to input the payer ID manually and ensures that a valid ID is provided.
313
313
  """
314
- print("Manual intervention required: No payer ID found for insurance name '{}'.".format(insurance_name))
315
- payer_id = input("Please enter the payer ID manually: ").strip()
316
- return payer_id
314
+ while True:
315
+ print("Manual intervention required: No payer ID found for insurance name '{}'.".format(insurance_name))
316
+ payer_id = input("Please enter the payer ID manually: ").strip()
317
+
318
+ if payer_id:
319
+ return payer_id
320
+ else:
321
+ print("Error: Payer ID cannot be empty. Please try again.")
317
322
 
318
323
  def build_nm1_segment(payer_name, payer_id):
319
324
  # Step 1: Build NM1 segment using payer name and ID
@@ -407,7 +412,7 @@ def handle_missing_payer_id(insurance_name, config):
407
412
 
408
413
  # Ask for user confirmation
409
414
  confirmation = input("Is the standard insurance name '{}' correct? (yes/no): ".format(standard_insurance_name)).strip().lower() or 'yes'
410
-
415
+ # BUG There is duplication of code here.
411
416
  if confirmation in ['yes', 'y']:
412
417
  # Update the crosswalk with the new payer ID and insurance name mapping
413
418
  MediBot_Crosswalk_Library.update_crosswalk_with_new_payer_id(insurance_name, payer_id, config)
@@ -520,32 +525,9 @@ def insurance_type_selection(parsed_data):
520
525
 
521
526
  print("\nInsurance Type Validation Error: Select the insurance type for patient {}: ".format(parsed_data['LAST']))
522
527
 
523
- # Define insurance options with codes and descriptions
524
- insurance_options = {
525
- "11": "Other Non-Federal Programs",
526
- "12": "Preferred Provider Organization (PPO)",
527
- "13": "Point of Service (POS)",
528
- "14": "Exclusive Provider Organization (EPO)",
529
- "15": "Indemnity Insurance",
530
- "16": "Health Maintenance Organization (HMO) Medicare Risk",
531
- "17": "Dental Maintenance Organization",
532
- "AM": "Automobile Medical",
533
- "BL": "Blue Cross/Blue Shield",
534
- "CH": "Champus",
535
- "CI": "Commercial Insurance Co.",
536
- "DS": "Disability",
537
- "FI": "Federal Employees Program",
538
- "HM": "Health Maintenance Organization",
539
- "LM": "Liability Medical",
540
- "MA": "Medicare Part A",
541
- "MB": "Medicare Part B",
542
- "MC": "Medicaid",
543
- "OF": "Other Federal Program",
544
- "TV": "Title V",
545
- "VA": "Veterans Affairs Plan",
546
- "WC": "Workers Compensation Health Claim",
547
- "ZZ": "Mutually Defined"
548
- }
528
+ # Retrieve insurance options with codes and descriptions
529
+ config, _ = MediLink_ConfigLoader.load_configuration()
530
+ insurance_options = config['MediLink_Config'].get('insurance_options')
549
531
 
550
532
  def prompt_display_insurance_options():
551
533
  # Prompt to display full list
@@ -870,10 +852,17 @@ def winscp_validate_output_directory(output_directory):
870
852
 
871
853
  def get_output_directory(config):
872
854
  # Retrieve desired default output file path from config
873
- output_directory = config.get('outputFilePath', '')
855
+ output_directory = config.get('outputFilePath', '').strip()
874
856
  # BUG (Low SFTP) Add WinSCP validation because of the mishandling of spaces in paths. (This shouldn't need to exist.)
857
+ if not output_directory:
858
+ print("Output file path is not specified in the configuration.")
859
+ output_directory = input("Please enter a valid output directory path: ").strip()
860
+
861
+ # Validate the directory path (checks for spaces and existence)
875
862
  output_directory = winscp_validate_output_directory(output_directory)
863
+
876
864
  if not os.path.isdir(output_directory):
877
- print("Output directory does not exist. Please check the configuration.")
865
+ print("Output directory does not exist or is not accessible. Please check the configuration.")
878
866
  return None
867
+
879
868
  return output_directory
@@ -0,0 +1,246 @@
1
+ # This script requires Python 3.11 and is to be used for intalling new API clients.
2
+ import os
3
+ import time
4
+ import subprocess
5
+ import shutil
6
+ import tempfile
7
+ from pathlib import Path
8
+ from watchdog.observers import Observer
9
+ from watchdog.events import FileSystemEventHandler
10
+ from MediLink_API_v3 import ConfigLoader
11
+ import shlex
12
+ import re
13
+
14
+ class SwaggerHandler(FileSystemEventHandler):
15
+ def __init__(self, json_folder):
16
+ self.json_folder = json_folder
17
+
18
+ def on_created(self, event):
19
+ if event.is_directory:
20
+ return
21
+ if event.src_path.endswith('.yaml') or event.src_path.endswith('.json'):
22
+ print(f"New file detected: {event.src_path}")
23
+ time.sleep(2) # Add a short delay to ensure the file is ready for reading
24
+ self.process_swagger_file(event.src_path)
25
+
26
+ def process_swagger_file(self, file_path):
27
+ print(f"Processing file: {file_path}")
28
+ # Sanitize filename to replace spaces with underscores
29
+ sanitized_file_path = os.path.join(os.path.dirname(file_path), sanitize_filename(os.path.basename(file_path)))
30
+ if sanitized_file_path != file_path:
31
+ os.rename(file_path, sanitized_file_path)
32
+ print(f"Renamed file to: {sanitized_file_path}")
33
+ file_path = sanitized_file_path
34
+
35
+ with tempfile.TemporaryDirectory() as temp_dir:
36
+ temp_dir_path = Path(temp_dir)
37
+ temp_file_path = temp_dir_path / Path(file_path).name
38
+ config_path = temp_dir_path / 'openapi_config.json'
39
+ output_dir = temp_dir_path / "generated_client"
40
+
41
+ shutil.copy(file_path, temp_file_path)
42
+ config_source_path = Path(__file__).parent.parent / 'json' / 'openapi_config.json'
43
+ shutil.copy(config_source_path, config_path)
44
+ print(f"Copied files to: {temp_file_path} and {config_path}")
45
+
46
+ swagger_definitions = ConfigLoader.load_swagger_file(str(temp_file_path))
47
+ if swagger_definitions:
48
+ print(f"Swagger definitions loaded successfully from: {temp_file_path}")
49
+ if generate_api_client(temp_file_path, output_dir, config_path):
50
+ backport_code(output_dir)
51
+ move_generated_client(temp_dir, file_path)
52
+ provide_instructions(file_path)
53
+ else:
54
+ print(f"Failed to load Swagger definitions from: {temp_file_path}")
55
+
56
+ def sanitize_filename(filename):
57
+ return filename.replace(' ', '_')
58
+
59
+ def find_executable(name):
60
+ """Find the full path to an executable."""
61
+ for path in os.environ["PATH"].split(os.pathsep):
62
+ full_path = Path(path) / name
63
+ if full_path.is_file():
64
+ return str(full_path)
65
+ return None
66
+
67
+ def generate_api_client(swagger_path, output_path, config_path):
68
+ """
69
+ Generate the API client using openapi-generator-cli.
70
+ """
71
+ openapi_generator_path = find_executable('openapi-generator-cli.cmd')
72
+ if not openapi_generator_path:
73
+ print("openapi-generator-cli not found in PATH.")
74
+ return False
75
+
76
+ command = [
77
+ openapi_generator_path,
78
+ 'generate',
79
+ '-i', str(swagger_path),
80
+ '-g', 'python',
81
+ '-o', str(output_path),
82
+ '-c', str(config_path)
83
+ ]
84
+
85
+ print(f"Attempting command: {' '.join(command)}")
86
+
87
+ try:
88
+ result = subprocess.run(command, check=True, capture_output=True, text=True)
89
+ print("API client generated successfully.")
90
+ print(result.stdout)
91
+ print(result.stderr)
92
+ return True
93
+ except subprocess.CalledProcessError as e:
94
+ print("First attempt failed.")
95
+ print("Error generating API client:")
96
+ print(e.stdout)
97
+ print(e.stderr)
98
+
99
+ try:
100
+ print("Attempting with shell=True.")
101
+ result = subprocess.run(' '.join(command), check=True, shell=True, capture_output=True, text=True)
102
+ print("API client generated successfully with shell=True.")
103
+ print(result.stdout)
104
+ print(result.stderr)
105
+ return True
106
+ except subprocess.CalledProcessError as e:
107
+ print("Second attempt with shell=True failed.")
108
+ print("Error generating API client:")
109
+ print(e.stdout)
110
+ print(e.stderr)
111
+
112
+ try:
113
+ quoted_command = [
114
+ openapi_generator_path,
115
+ 'generate',
116
+ '-i', shlex.quote(str(swagger_path)),
117
+ '-g', 'python',
118
+ '-o', shlex.quote(str(output_path)),
119
+ '-c', shlex.quote(str(config_path))
120
+ ]
121
+ print(f"Attempting quoted command: {' '.join(quoted_command)}")
122
+ result = subprocess.run(' '.join(quoted_command), check=True, shell=True, capture_output=True, text=True)
123
+ print("API client generated successfully with quoted command.")
124
+ print(result.stdout)
125
+ print(result.stderr)
126
+ return True
127
+ except subprocess.CalledProcessError as e:
128
+ print("Third attempt with quoted command failed.")
129
+ print("Error generating API client:")
130
+ print(e.stdout)
131
+ print(e.stderr)
132
+
133
+ try:
134
+ print("Attempting with batch script.")
135
+ batch_script_content = f"""
136
+ @echo off
137
+ {openapi_generator_path} generate -i "{swagger_path}" -g python -o "{output_path}" -c "{config_path}"
138
+ """
139
+ batch_script_path = Path(tempfile.gettempdir()) / "generate_client.bat"
140
+ with open(batch_script_path, 'w') as batch_script:
141
+ batch_script.write(batch_script_content)
142
+
143
+ result = subprocess.run(str(batch_script_path), check=True, shell=True, capture_output=True, text=True)
144
+ print("API client generated successfully with batch script.")
145
+ print(result.stdout)
146
+ print(result.stderr)
147
+ return True
148
+ except subprocess.CalledProcessError as e:
149
+ print("Fourth attempt with batch script failed.")
150
+ print("Error generating API client:")
151
+ print(e.stdout)
152
+ print(e.stderr)
153
+
154
+ print("All attempts to generate API client failed.")
155
+ return False
156
+
157
+ def backport_code(output_dir):
158
+ for root, _, files in os.walk(output_dir):
159
+ for file in files:
160
+ if file.endswith('.py'):
161
+ file_path = os.path.join(root, file)
162
+ with open(file_path, 'r') as f:
163
+ code = f.read()
164
+
165
+ code = re.sub(r'f"(.*?)"', r'"\1".format', code) # Replace f-strings
166
+ code = re.sub(r'async def', 'def', code) # Remove async syntax
167
+ code = re.sub(r'await ', '', code) # Remove await syntax
168
+ code = re.sub(r':\s*\w+ =', '=', code) # Remove type hints in variable assignments
169
+ code = re.sub(r'def (\w+)\(.*?\) -> .*?:', r'def \1(', code) # Remove type hints in function definitions
170
+ code = re.sub(r'(from pydantic import.*)', '# \1', code) # Comment out pydantic imports
171
+ code = re.sub(r'(import pydantic)', '# \1', code) # Comment out pydantic imports
172
+
173
+ with open(file_path, 'w') as f:
174
+ f.write(code)
175
+ print(f"Backported {file_path}")
176
+
177
+ def move_generated_client(temp_dir, original_file_path):
178
+ api_name = Path(original_file_path).stem
179
+ destination_dir = Path('generated_clients') / api_name
180
+ if destination_dir.exists():
181
+ shutil.rmtree(destination_dir)
182
+ try:
183
+ shutil.move(str(Path(temp_dir) / 'generated_client'), str(destination_dir))
184
+ print(f"Moved generated client to {destination_dir}")
185
+ except FileNotFoundError as e:
186
+ print(f"Error moving generated client: {e}")
187
+ except Exception as e:
188
+ print(f"Unexpected error moving generated client: {e}")
189
+
190
+ def provide_instructions(swagger_path):
191
+ api_name = Path(swagger_path).stem
192
+ instructions = f"""
193
+ API Client for {api_name} has been generated successfully.
194
+
195
+ Integration Steps:
196
+ 1. Locate the generated client code in the 'generated_clients/{api_name}' directory.
197
+ 2. Integrate the generated client code into your project by following these steps:
198
+ a. Copy the generated client directory to your project's client directory.
199
+ b. Import the client classes in your project as needed.
200
+ c. Ensure that the generated client adheres to the BaseAPIClient interface if integrating with the existing system.
201
+ 3. Update your configuration to include the new API endpoint details.
202
+ 4. Test the integration thoroughly to ensure compatibility and functionality.
203
+
204
+ Example Integration:
205
+ from clients.generated.{api_name}.api_client import ApiClient as {api_name}Client
206
+
207
+ class New{api_name}APIClient(BaseAPIClient):
208
+ def __init__(self, config):
209
+ super().__init__(config)
210
+ self.generated_client = {api_name}Client()
211
+
212
+ def get_access_token(self, endpoint_name):
213
+ # Implement token retrieval logic
214
+ pass
215
+
216
+ def make_api_call(self, endpoint_name, call_type, url_extension="", params=None, data=None):
217
+ # Use the generated client to make the API call
218
+ if call_type == 'GET':
219
+ response = self.generated_client.call_api(url_extension, 'GET', params=params, header_params=headers)
220
+ elif call_type == 'POST':
221
+ response = self.generated_client.call_api(url_extension, 'POST', body=data, header_params=headers)
222
+ elif call_type == 'DELETE':
223
+ response = self.generated_client.call_api(url_extension, 'DELETE', header_params=headers)
224
+ else:
225
+ raise ValueError("Unsupported call type")
226
+ return response
227
+
228
+ """
229
+ print(instructions)
230
+
231
+ def main():
232
+ json_folder = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'json'))
233
+ event_handler = SwaggerHandler(json_folder)
234
+ observer = Observer()
235
+ observer.schedule(event_handler, path=json_folder, recursive=False)
236
+ observer.start()
237
+ print(f"Monitoring folder: {json_folder}")
238
+ try:
239
+ while True:
240
+ time.sleep(1)
241
+ except KeyboardInterrupt:
242
+ observer.stop()
243
+ observer.join()
244
+
245
+ if __name__ == "__main__":
246
+ main()
@@ -1,3 +1,5 @@
1
+ # Unused archive backup. This has been superceded by API_v3
2
+
1
3
  import time
2
4
  import requests
3
5