diff --git a/.gitignore b/.gitignore index ae3778db..f0fb349b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ __pycache__/ # C extensions *.so +venv # Distribution / packaging .Python diff --git a/healthchain/cli.py b/healthchain/cli.py index 292b55bf..20aa7583 100644 --- a/healthchain/cli.py +++ b/healthchain/cli.py @@ -1,56 +1,217 @@ import argparse import subprocess +import sys +from pathlib import Path def run_file(filename): + """Run a Python file using poetry with enhanced error handling.""" + # Validate file exists and has .py extension + file_path = Path(filename) + + if not file_path.exists(): + print(f"āŒ Error: File '{filename}' not found") + print("šŸ’” Tip: Check the file path and make sure the file exists") + print(" Example: healthchain run my_script.py") + return + + if not filename.endswith('.py'): + print(f"āŒ Error: '{filename}' is not a Python file") + print("šŸ’” Tip: HealthChain can only run Python (.py) files") + print(" Example: healthchain run my_healthchain_app.py") + return + try: - result = subprocess.run(["poetry", "run", "python", filename], check=True) - print(result.stdout) + print(f"šŸš€ Running {filename}...") + result = subprocess.run( + ["poetry", "run", "python", filename], + check=True, + capture_output=True, + text=True + ) + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + + except FileNotFoundError: + print("āŒ Error: Poetry not found") + print("šŸ’” Tip: Install Poetry or run the file directly with Python:") + print(f" python {filename}") + print("šŸ“š Poetry installation: https://python-poetry.org/docs/#installation") + except subprocess.CalledProcessError as e: - print(f"An error occurred while trying to run the file: {e}") + print(f"āŒ Error: Script execution failed with exit code {e.returncode}") + if e.stdout: + print("šŸ“‹ Output:") + print(e.stdout) + if e.stderr: + print("šŸ” Error details:") + print(e.stderr) + print("\nšŸ’” Common fixes:") + print(" • Check for syntax errors in your Python file") + print(" • Ensure all required dependencies are installed") + print(" • Verify your HealthChain code follows the documentation examples") + print("šŸ“š Documentation: https://dotimplement.github.io/HealthChain/") def init_configs(target_dir: str): - """Initialize configuration templates for customization.""" + """Initialize configuration templates for customization with enhanced validation.""" + # Validate target directory name + target_path = Path(target_dir) + + # Check if target is a file + if target_path.exists() and target_path.is_file(): + print(f"āŒ Error: '{target_dir}' is a file, not a directory") + print("šŸ’” Tip: Choose a directory name instead:") + print(f" healthchain init-configs {target_dir}_configs") + return + + # Warn if target directory name might cause issues + if ' ' in target_dir: + print("āš ļø Warning: Directory name contains spaces, which may cause issues") + print("šŸ’” Tip: Consider using underscores instead:") + print(f" healthchain init-configs {target_dir.replace(' ', '_')}") + try: from healthchain.interop import init_config_templates + print(f"šŸ“ Creating configuration templates in: {target_dir}") target_path = init_config_templates(target_dir) print(f"\nšŸŽ‰ Success! Configuration templates created at: {target_path}") print("\nšŸ“– Next steps:") print(" 1. Customize the configuration files in the created directory") + print(" • Edit template files in templates/ subdirectory") + print(" • Modify code mappings in mappings/ subdirectory") + print(" • Adjust validation rules in environments/ subdirectory") print(" 2. Use them in your code:") print(" from healthchain.interop import create_interop") print(f" engine = create_interop(config_dir='{target_dir}')") - print("\nšŸ“š See documentation for configuration options") + print("\nšŸ“š Documentation: https://dotimplement.github.io/HealthChain/reference/interop/configuration/") + print("šŸ’¬ Need help? Join our Discord: https://discord.gg/UQC6uAepUz") except FileExistsError as e: print(f"āŒ Error: {str(e)}") - print("šŸ’” Tip: Choose a different directory name or remove the existing one") + print("šŸ’” Possible solutions:") + print(f" • Choose a different directory name:") + print(f" healthchain init-configs {target_dir}_new") + print(f" • Remove the existing directory:") + print(f" rm -rf {target_dir} # Linux/Mac") + print(f" rmdir /s {target_dir} # Windows") + print(f" • Use the existing directory if it already contains configs") + + except ImportError as e: + print(f"āŒ Error: Missing required HealthChain components: {str(e)}") + print("šŸ’” Fix: Reinstall HealthChain with all dependencies:") + print(" pip install --upgrade healthchain") + print(" # or") + print(" poetry add healthchain") + + except PermissionError as e: + print(f"āŒ Error: Permission denied: {str(e)}") + print("šŸ’” Possible solutions:") + print(" • Run with appropriate permissions") + print(" • Choose a directory you have write access to:") + print(" healthchain init-configs ~/my_healthchain_configs") + print(" • Check if the target location is write-protected") + except Exception as e: print(f"āŒ Error initializing configs: {str(e)}") - print("šŸ’” Tip: Make sure HealthChain is properly installed") + print("šŸ’” Troubleshooting steps:") + print(" 1. Ensure HealthChain is properly installed:") + print(" pip install --upgrade healthchain") + print(" 2. Check if you have write permissions to the target directory") + print(" 3. Try a different target directory name") + print(" 4. If the issue persists, please report it:") + print(" https://github.com/dotimplement/HealthChain/issues") + print("šŸ’¬ Get help on Discord: https://discord.gg/UQC6uAepUz") def main(): - parser = argparse.ArgumentParser(description="HealthChain command-line interface") + parser = argparse.ArgumentParser( + description="HealthChain CLI - Build and deploy healthcare AI applications", + epilog=""" +Examples: + healthchain run my_cds_service.py # Run a HealthChain application + healthchain init-configs ./my_configs # Create customizable config templates + healthchain init-configs # Create configs in default location + +For more help: + Documentation: https://dotimplement.github.io/HealthChain/ + Discord Community: https://discord.gg/UQC6uAepUz + GitHub Issues: https://github.com/dotimplement/HealthChain/issues + """, + formatter_class=argparse.RawDescriptionHelpFormatter + ) subparsers = parser.add_subparsers(dest="command", required=True) # Subparser for the 'run' command - run_parser = subparsers.add_parser("run", help="Run a specified file") - run_parser.add_argument("filename", type=str, help="The filename to run") + run_parser = subparsers.add_parser( + "run", + help="Run a HealthChain Python application", + description=""" +Run a HealthChain Python application using Poetry. + +This command executes your HealthChain script with proper dependency management, +ensuring all required packages are available in the Poetry environment. + """, + epilog=""" +Examples: + healthchain run cds_service.py # Run a CDS Hooks service + healthchain run clinical_pipeline.py # Run a clinical NLP pipeline + healthchain run fhir_gateway.py # Run a FHIR gateway application + +Note: This command requires Poetry to be installed. If Poetry is not available, +you can run your script directly with: python your_script.py + """, + formatter_class=argparse.RawDescriptionHelpFormatter + ) + run_parser.add_argument( + "filename", + type=str, + help="Python file to run (must be a .py file)" + ) # Subparser for the 'init-configs' command init_parser = subparsers.add_parser( "init-configs", - help="Initialize configuration templates for interop customization", + help="Initialize customizable configuration templates", + description=""" +Create a complete set of customizable configuration templates for HealthChain +interoperability features. These templates allow you to customize FHIR ↔ CDA +conversions, code system mappings, and validation rules. + """, + epilog=""" +Examples: + healthchain init-configs # Create in ./healthchain_configs/ + healthchain init-configs ./my_configs # Create in custom directory + healthchain init-configs ~/hospital_configs # Create in home directory + +The created directory will contain: + • templates/ - CDA ↔ FHIR conversion templates + • mappings/ - Code system mappings (SNOMED, LOINC, etc.) + • environments/ - Development, testing, production configs + • defaults.yaml - Base configuration settings + +After creation, you can use your custom configs with: + from healthchain.interop import create_interop + engine = create_interop(config_dir="./my_configs") + """, + formatter_class=argparse.RawDescriptionHelpFormatter ) init_parser.add_argument( "target_dir", type=str, nargs="?", default="./healthchain_configs", - help="Directory to create configuration templates (default: ./healthchain_configs)", + help="Directory to create configuration templates (default: ./healthchain_configs)" + ) + + # Add aliases for common commands + parser.add_argument( + "--version", "-v", + action="version", + version="HealthChain CLI - Run 'pip show healthchain' for version info" ) args = parser.parse_args() @@ -62,4 +223,4 @@ def main(): if __name__ == "__main__": - main() + main() \ No newline at end of file