Update main_app.py
Browse files- main_app.py +185 -0
main_app.py
CHANGED
@@ -785,6 +785,191 @@ def _(create_yaml_tempfile, deployment_client, package_meta):
|
|
785 |
|
786 |
return pe_metadata, yaml_file_path
|
787 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
788 |
|
789 |
@app.cell
|
790 |
def _(
|
|
|
785 |
|
786 |
return pe_metadata, yaml_file_path
|
787 |
|
788 |
+
@app.cell(hide_code=True)
|
789 |
+
def _():
|
790 |
+
### Helper function for checking if a python library is in the standard software spec.
|
791 |
+
def analyze_software_spec(sw_spec_response, required_libraries, return_full_sw_package_list=False):
|
792 |
+
"""
|
793 |
+
Analyzes a software specification against a list of required libraries.
|
794 |
+
|
795 |
+
Args:
|
796 |
+
sw_spec_response (dict): The software specification response from the API
|
797 |
+
required_libraries (list): List of required libraries in format ["package_name", "package_name==version", etc.]
|
798 |
+
return_full_sw_package_list (bool): Whether to return the complete package list from sw_spec
|
799 |
+
|
800 |
+
Returns:
|
801 |
+
dict: A dictionary with analysis results containing:
|
802 |
+
- not_present: Dict of libraries not found in the software spec
|
803 |
+
- version_mismatch: Dict of libraries with version mismatches, with [sw_version, required_version] as values
|
804 |
+
- present: Dict of libraries that are present with matching versions
|
805 |
+
- sw_packages: (Optional) Complete dict of all packages in the software spec
|
806 |
+
"""
|
807 |
+
result = {
|
808 |
+
"present": {},
|
809 |
+
"not_present": {},
|
810 |
+
"version_mismatch": {}
|
811 |
+
}
|
812 |
+
|
813 |
+
# Extract all packages from the software specification
|
814 |
+
sw_packages = {}
|
815 |
+
|
816 |
+
try:
|
817 |
+
# Extract packages from included_packages in the software specification
|
818 |
+
included_packages = sw_spec_response["entity"]["software_specification"]["software_configuration"]["included_packages"]
|
819 |
+
|
820 |
+
# Create a dictionary of all packages in the software specification
|
821 |
+
for package in included_packages:
|
822 |
+
package_name = package["name"]
|
823 |
+
package_version = package["version"]
|
824 |
+
sw_packages[package_name] = package_version
|
825 |
+
except KeyError as e:
|
826 |
+
raise ValueError(f"Invalid software specification format: {e}")
|
827 |
+
|
828 |
+
# Parse required libraries
|
829 |
+
for lib in required_libraries:
|
830 |
+
if "==" in lib:
|
831 |
+
lib_name, lib_version = lib.split("==", 1)
|
832 |
+
lib_name = lib_name.strip()
|
833 |
+
lib_version = lib_version.strip()
|
834 |
+
else:
|
835 |
+
lib_name = lib.strip()
|
836 |
+
lib_version = None
|
837 |
+
|
838 |
+
# Check if library is present in software specification
|
839 |
+
if lib_name not in sw_packages:
|
840 |
+
result["not_present"][lib_name] = None
|
841 |
+
elif lib_version is not None and lib_version != sw_packages[lib_name]:
|
842 |
+
# Check version mismatch
|
843 |
+
result["version_mismatch"][lib_name] = [sw_packages[lib_name], lib_version]
|
844 |
+
else:
|
845 |
+
# Library is present with matching version (or no specific version required)
|
846 |
+
result["present"][lib_name] = sw_packages[lib_name]
|
847 |
+
|
848 |
+
if return_full_sw_package_list:
|
849 |
+
# Extract just the library names from required_libraries
|
850 |
+
req_libs_names = [lib.split("==")[0].strip() if "==" in lib else lib.strip() for lib in required_libraries]
|
851 |
+
|
852 |
+
def sort_key(pkg_name):
|
853 |
+
if pkg_name in result["not_present"]:
|
854 |
+
return (0, pkg_name) # Missing packages first
|
855 |
+
elif pkg_name in result["version_mismatch"]:
|
856 |
+
return (1, pkg_name) # Version mismatch second
|
857 |
+
elif pkg_name in req_libs_names:
|
858 |
+
return (2, pkg_name) # Required packages that match third
|
859 |
+
else:
|
860 |
+
return (3, pkg_name) # All other packages last
|
861 |
+
|
862 |
+
# Sort sw_packages using the custom sorting key
|
863 |
+
result["sw_packages"] = {k: sw_packages[k] for k in sorted(sw_packages.keys(), key=sort_key)}
|
864 |
+
|
865 |
+
# Add missing packages to the top of sw_packages
|
866 |
+
for pkg in result["not_present"]:
|
867 |
+
result["sw_packages"] = {pkg: None, **result["sw_packages"]}
|
868 |
+
|
869 |
+
|
870 |
+
return result
|
871 |
+
|
872 |
+
def visualize_software_spec(analysis_result, required_libraries=None):
|
873 |
+
"""
|
874 |
+
Visualizes the results of analyze_software_spec in a DataFrame with status indicators.
|
875 |
+
For use in Marimo notebooks.
|
876 |
+
|
877 |
+
Args:
|
878 |
+
analysis_result (dict): The result from analyze_software_spec function
|
879 |
+
required_libraries (list, optional): The original list of required libraries
|
880 |
+
used in analyze_software_spec
|
881 |
+
|
882 |
+
Returns:
|
883 |
+
pandas.DataFrame: A DataFrame showing the analysis results with status indicators
|
884 |
+
"""
|
885 |
+
import pandas as pd
|
886 |
+
|
887 |
+
# Parse required libraries to get the exact names for lookup
|
888 |
+
req_libs_parsed = {}
|
889 |
+
if required_libraries:
|
890 |
+
for lib in required_libraries:
|
891 |
+
if "==" in lib:
|
892 |
+
lib_name, lib_version = lib.split("==", 1)
|
893 |
+
lib_name = lib_name.strip()
|
894 |
+
lib_version = lib_version.strip()
|
895 |
+
req_libs_parsed[lib_name] = lib_version
|
896 |
+
else:
|
897 |
+
lib_name = lib.strip()
|
898 |
+
req_libs_parsed[lib_name] = None
|
899 |
+
|
900 |
+
# Determine if we have the full sw_packages list
|
901 |
+
has_full_list = "sw_packages" in analysis_result
|
902 |
+
|
903 |
+
# Create a DataFrame based on available data
|
904 |
+
if has_full_list:
|
905 |
+
# Use the full package list
|
906 |
+
packages = analysis_result["sw_packages"]
|
907 |
+
|
908 |
+
# Prepare data rows
|
909 |
+
rows = []
|
910 |
+
for package, version in packages.items():
|
911 |
+
if package in analysis_result.get("not_present", {}):
|
912 |
+
status = "❌ Missing"
|
913 |
+
priority = 0 # Top priority
|
914 |
+
elif package in analysis_result.get("version_mismatch", {}):
|
915 |
+
status = "⚠️ Version Mismatch"
|
916 |
+
priority = 1 # Second priority
|
917 |
+
elif package in req_libs_parsed:
|
918 |
+
status = "✅ Present"
|
919 |
+
priority = 2 # Third priority
|
920 |
+
else:
|
921 |
+
status = "Other"
|
922 |
+
priority = 3 # Lowest priority
|
923 |
+
|
924 |
+
rows.append({
|
925 |
+
"Package": package,
|
926 |
+
"Version": version if version is not None else "Not Present",
|
927 |
+
"Status": status,
|
928 |
+
"_priority": priority # Temporary field for sorting
|
929 |
+
})
|
930 |
+
|
931 |
+
df = pd.DataFrame(rows)
|
932 |
+
|
933 |
+
# Sort by priority and then package name
|
934 |
+
df = df.sort_values(by=["_priority", "Package"]).drop("_priority", axis=1).reset_index(drop=True)
|
935 |
+
|
936 |
+
else:
|
937 |
+
# Only use the packages mentioned in required_libraries
|
938 |
+
packages = set(list(analysis_result.get("not_present", {}).keys()) +
|
939 |
+
list(analysis_result.get("version_mismatch", {}).keys()) +
|
940 |
+
list(analysis_result.get("present", {}).keys()))
|
941 |
+
|
942 |
+
# Create dataframe rows
|
943 |
+
rows = []
|
944 |
+
for package in packages:
|
945 |
+
if package in analysis_result.get("not_present", {}):
|
946 |
+
version = "Not Present"
|
947 |
+
status = "❌ Missing"
|
948 |
+
priority = 0 # Top priority
|
949 |
+
elif package in analysis_result.get("version_mismatch", {}):
|
950 |
+
version = analysis_result["version_mismatch"][package][0] # sw_spec version
|
951 |
+
status = "⚠️ Version Mismatch"
|
952 |
+
priority = 1 # Second priority
|
953 |
+
else:
|
954 |
+
version = analysis_result["present"][package]
|
955 |
+
status = "✅ Present"
|
956 |
+
priority = 2 # Third priority
|
957 |
+
|
958 |
+
rows.append({
|
959 |
+
"Package": package,
|
960 |
+
"Version": version,
|
961 |
+
"Status": status,
|
962 |
+
"_priority": priority # Temporary field for sorting
|
963 |
+
})
|
964 |
+
|
965 |
+
df = pd.DataFrame(rows)
|
966 |
+
|
967 |
+
# Sort by priority and then package name
|
968 |
+
df = df.sort_values(by=["_priority", "Package"]).drop("_priority", axis=1).reset_index(drop=True)
|
969 |
+
|
970 |
+
return df
|
971 |
+
return analyze_software_spec, visualize_software_spec
|
972 |
+
|
973 |
|
974 |
@app.cell
|
975 |
def _(
|