1212# along with this program. If not, see <http://www.gnu.org/licenses/>.
1313
1414# packages.py
15- # Copyright (C) 2014-2021 Fracpete (pythonwekawrapper at gmail dot com)
15+ # Copyright (C) 2014-2022 Fracpete (pythonwekawrapper at gmail dot com)
1616
17+ import argparse
1718import javabridge
19+ import json
1820import sys
1921import traceback
2022import weka .core .jvm as jvm
@@ -118,6 +120,22 @@ def install(self):
118120 """
119121 return javabridge .call (self .jobject , "install" , "()V" )
120122
123+ def as_dict (self ):
124+ """
125+ Turns the package information into a dictionary. Not to be confused with 'to_dict'!
126+
127+ :return: the package information as dictionary
128+ :rtype: dict
129+ """
130+ return {
131+ "name" : self .name ,
132+ "version" : self .version ,
133+ "url" : self .url ,
134+ "is_installed" : self .is_installed ,
135+ "dependencies" : self .dependencies ,
136+ "metadata" : self .metadata ,
137+ }
138+
121139 def __str__ (self ):
122140 """
123141 Just returns name/version.
@@ -531,19 +549,25 @@ def uninstall_packages(names):
531549 "(Ljava/lang/String;Z[Ljava/io/PrintStream;)V" , name , True , [])
532550
533551
534- def is_installed (name ):
552+ def is_installed (name , version = None ):
535553 """
536554 Checks whether a package with the name is already installed.
537555
538556 :param name: the name of the package
539557 :type name: str
558+ :param version: the version to check as well, ignored if None
559+ :type version: str
540560 :return: whether the package is installed
541561 :rtype: bool
542562 """
543563 pkgs = installed_packages ()
544564 for pkge in pkgs :
545565 if pkge .name == name :
546- return True
566+ if version is not None :
567+ if pkge .version == version :
568+ return True
569+ else :
570+ return True
547571 return False
548572
549573
@@ -562,42 +586,260 @@ def suggest_package(name, exact=False):
562586 return classes .suggest_package (name , exact )
563587
564588
565- if __name__ == "__main__" :
566- jvm .start ()
589+ def _output_text (content , format_lambda , output ):
590+ """
591+ Outputs the text to the specified file or, if None, to stdout.
592+
593+ :param content: the content to output
594+ :type content: list
595+ :param format_lambda: the lambda to format the list
596+ :param output: the file to output the content to, uses stdout if None
597+ :type output: str
598+ """
599+ formatted = []
600+ for c in content :
601+ formatted .append (format_lambda (c ))
602+ if output is None :
603+ print ("\n " .join (formatted ))
604+ else :
605+ with open (output , "w" ) as fp :
606+ fp .write ("\n " .join (formatted ))
607+
608+
609+ def _output_json (content , content_filter , output ):
610+ """
611+ Outputs the content to the specified json file or, if None, to stdout.
612+
613+ :param content: the content to output
614+ :type content: list
615+ :param content_filter: the lambda for filtering the content dictionaries, ignored if None
616+ :param output: the file to output the content to, uses stdout if None
617+ :type output: str
618+ """
619+ if content_filter is None :
620+ filtered = content
621+ else :
622+ filtered = [content_filter (x ) for x in content ]
623+ if output is None :
624+ print (json .dumps (filtered , indent = 2 ))
625+ else :
626+ with open (output , "w" ) as fp :
627+ json .dump (filtered , fp , indent = 2 )
628+
629+
630+ def _output_pkg_list (pkgs , args ):
631+ """
632+ Outputs a package list.
633+
634+ :param pkgs: the list of packages
635+ :type pkgs: list
636+ :param args: the parsed command-line arguments
637+ :type args: argparse.Namespace
638+ """
639+ content = [pkg .as_dict () for pkg in pkgs ]
640+ if args .format == "text" :
641+ _output_text (content , lambda x : "%s/%s" % (x ["name" ], x ["version" ]), args .output )
642+ elif args .format == "json" :
643+ _output_json (content , lambda x : {"name" : x ["name" ], "version" : x ["version" ]}, args .output )
644+
645+
646+ def _output_pkg_info (pkgs , args ):
647+ """
648+ Outputs package information.
649+
650+ :param pkgs: the list of packages
651+ :type pkgs: list
652+ :param args: the parsed command-line arguments
653+ :type args: argparse.Namespace
654+ """
655+ if args .format == "text" :
656+ if args .type == "brief" :
657+ _output_text (pkgs , lambda x : "%s/%s\n dependencies: %s" % (x ["name" ], x ["version" ], x ["dependencies" ]),
658+ args .output )
659+ elif args .type == "full" :
660+ _output_text (pkgs , lambda x : "%s/%s\n url: %s\n dependencies: %s\n metadata: %s" % (
661+ x ["name" ], x ["version" ], x ["url" ], x ["dependencies" ], x ["metadata" ]), args .output )
662+ else :
663+ raise Exception ("Unhandled type: %s" % args .type )
664+ elif args .format == "json" :
665+ if args .type == "brief" :
666+ _output_json (pkgs ,
667+ lambda x : {"name" : x ["name" ], "version" : x ["version" ], "dependencies" : x ["dependencies" ]},
668+ args .output )
669+ elif args .type == "full" :
670+ _output_json (pkgs , None , args .output )
671+ else :
672+ raise Exception ("Unhandled type: %s" % args .type )
673+
674+
675+ def _subcmd_list (args ):
676+ """
677+ Lists packages (name and version).
678+ """
679+ if args .type == "all" :
680+ pkgs = all_packages ()
681+ elif args .type == "installed" :
682+ pkgs = installed_packages ()
683+ elif args .type == "available" :
684+ pkgs = available_packages ()
685+ else :
686+ raise Exception ("Unhandled list type: %s" % args .type )
687+ _output_pkg_list (pkgs , args )
688+
689+
690+ def _subcmd_info (args ):
691+ """
692+ Outputs information for packages.
693+ """
694+ pkgs = [all_package (x ).as_dict () for x in args .name ]
695+ _output_pkg_info (pkgs , args )
696+
697+
698+ def _subcmd_install (args ):
699+ """
700+ Installs one or more packages. Specific versions are suffixed with "==VERSION".
701+ """
702+ for pkg in args .packages :
703+ version = LATEST
704+ if "==" in pkg :
705+ pkg , version = pkg .split ("==" )
706+ print ("Installing: %s/%s" % (pkg , version ))
707+ success = install_package (pkg , version )
708+ print (" installed successfully" if success else " failed to install" )
709+
710+
711+ def _subcmd_uninstall (args ):
712+ """
713+ Uninstalls one or more packages.
714+ """
715+ for pkg in args .packages :
716+ print ("Uninstalling: %s" % pkg )
717+ if is_installed (pkg ):
718+ uninstall_package (pkg )
719+ print (" uninstalled" )
720+ else :
721+ print (" not installed, skipping" )
722+
723+
724+ def _subcmd_suggest (args ):
725+ """
726+ Suggests packages that contain the specified classname.
727+ """
728+ suggestions = []
729+ for classname in args .classname :
730+ suggestions .extend (suggest_package (classname , exact = args .exact ))
731+ pkgs = []
732+ for suggestion in suggestions :
733+ if suggestion is None :
734+ continue
735+ pkgs .append (all_package (suggestion ))
736+ _output_pkg_list (pkgs , args )
737+
738+
739+ def _subcmd_is_installed (args ):
740+ content = []
741+ for name in args .name :
742+ version = None
743+ if "==" in name :
744+ name , version = name .split ("==" )
745+ installed = is_installed (name , version = version )
746+ if version is None :
747+ if installed :
748+ version = installed_package (name ).version
749+ else :
750+ version = LATEST
751+ content .append ({"name" : name , "version" : version , "installed" : installed })
752+
753+ if args .format == "text" :
754+ _output_text (content , lambda x : "%s/%s: %s" % (x ["name" ], x ["version" ], str (x ["installed" ])), args .output )
755+ elif args .format == "json" :
756+ _output_json (content , None , args .output )
757+
758+
759+ def main (args = None ):
760+ """
761+ Performs the specified package operation from the command-line. Calls JVM start/stop automatically.
762+ Use -h to see all options.
763+
764+ :param args: the command-line arguments to use, uses sys.argv if None
765+ :type args: list
766+ """
767+
768+ main_parser = argparse .ArgumentParser (
769+ description = 'Manages Weka packages.' )
770+ sub_parsers = main_parser .add_subparsers ()
771+
772+ # list
773+ parser = sub_parsers .add_parser ("list" , help = "For listing all/installed/available packages" )
774+ parser .add_argument ("type" , nargs = "?" , choices = ["all" , "installed" , "available" ], default = "all" , help = "defines what packages to list" )
775+ parser .add_argument ("-f" , "--format" , choices = ["text" , "json" ], default = "text" , help = "the output format to use" )
776+ parser .add_argument ("-o" , "--output" , metavar = "FILE" , default = None , help = "the file to store the output in, uses stdout if not supplied" )
777+ parser .set_defaults (func = _subcmd_list )
778+
779+ # info
780+ parser = sub_parsers .add_parser ("info" , help = "Outputs information about packages" )
781+ parser .add_argument ("name" , nargs = "+" , help = "the package(s) to output the information for" )
782+ parser .add_argument ("-t" , "--type" , choices = ["brief" , "full" ], default = "brief" , help = "the type of information to output" )
783+ parser .add_argument ("-f" , "--format" , choices = ["text" , "json" ], default = "text" , help = "the output format to use" )
784+ parser .add_argument ("-o" , "--output" , metavar = "FILE" , default = None , help = "the file to store the output in, uses stdout if not supplied" )
785+ parser .set_defaults (func = _subcmd_info )
786+
787+ # install
788+ parser = sub_parsers .add_parser ("install" , help = "For installing one or more packages" )
789+ parser .add_argument ("packages" , nargs = "+" , help = "the name of the package(s) to install, append '==VERSION' to pin to a specific version" )
790+ parser .set_defaults (func = _subcmd_install )
791+
792+ # uninstall/remove
793+ parser = sub_parsers .add_parser ("uninstall" , aliases = ["remove" ], help = "For uninstalling one or more packages" )
794+ parser .add_argument ("packages" , nargs = "+" , help = "the name of the package(s) to uninstall" )
795+ parser .set_defaults (func = _subcmd_uninstall )
796+
797+ # suggest
798+ parser = sub_parsers .add_parser ("suggest" , help = "For suggesting packages that contain the specified class" )
799+ parser .add_argument ("classname" , nargs = 1 , help = "the classname to suggest packages for" )
800+ parser .add_argument ("-e" , "--exact" , action = "store_true" , help = "whether to match the name exactly or perform substring matching" )
801+ parser .add_argument ("-f" , "--format" , choices = ["text" , "json" ], default = "text" , help = "the output format to use" )
802+ parser .add_argument ("-o" , "--output" , metavar = "FILE" , default = None , help = "the file to store the output in, uses stdout if not supplied" )
803+ parser .set_defaults (func = _subcmd_suggest )
804+
805+ # is-installed
806+ parser = sub_parsers .add_parser ("is-installed" , help = "Checks whether a package is installed, simply outputs true/false" )
807+ parser .add_argument ("name" , nargs = "+" , help = "the name of the package to check, append '==VERSION' to pin to a specific version" )
808+ parser .add_argument ("-f" , "--format" , choices = ["text" , "json" ], default = "text" , help = "the output format to use" )
809+ parser .add_argument ("-o" , "--output" , metavar = "FILE" , default = None , help = "the file to store the output in, uses stdout if not supplied" )
810+ parser .set_defaults (func = _subcmd_is_installed )
811+
812+ parsed = main_parser .parse_args (args = args )
813+
814+ # execute action
815+ jvm .start (packages = True )
567816 try :
568- print ("Establish cache" )
569- print ("===============" )
570- establish_cache ()
571-
572- print ("Refresh cache" )
573- print ("=============" )
574- refresh_cache ()
575-
576- print ("All packages" )
577- print ("============" )
578- packages = all_packages ()
579- for pkg in packages :
580- print (pkg .name )
581- print (" url: " + pkg .url )
582- print ("" )
583-
584- print ("Available packages" )
585- print ("==================" )
586- packages = available_packages ()
587- p = packages [0 ]
588- for pkg in packages :
589- print (pkg .name )
590- print (" url: " + pkg .url )
591- print ("" )
592-
593- print ("Installed packages" )
594- print ("==================" )
595- packages = installed_packages ()
596- for pkg in packages :
597- print (pkg .name )
598- print (" url: " + pkg .url )
599- print ("" )
600- except Exception as e :
601- print (e )
817+ parsed .func (parsed )
818+ except Exception :
819+ print (traceback .format_exc ())
602820 finally :
603821 jvm .stop ()
822+
823+
824+ def sys_main ():
825+ """
826+ Runs the main function using the system cli arguments, and
827+ returns a system error code.
828+
829+ :return: 0 for success, 1 for failure.
830+ :rtype: int
831+ """
832+
833+ try :
834+ main ()
835+ return 0
836+ except Exception :
837+ print (traceback .format_exc ())
838+ return 1
839+
840+
841+ if __name__ == "__main__" :
842+ try :
843+ main ()
844+ except Exception :
845+ print (traceback .format_exc ())
0 commit comments