Best Python code snippet using fMBT_python
atlascreator.py
Source:atlascreator.py  
1'''2    Launcher for the Atlas Creator3'''4import glob5from subprocess import call6import getopt7import os8import sys9import socket10'''=========================================================================================='''11def info( message ):12    '''13        Print message to stdout and flush14    '''15    print str( message )16    import sys17    # flush, to always show the output18    sys.stdout.flush()19'''=========================================================================================='''20def is_int( s ):21    try:22        int( s )23        return True24    except ValueError:25        return False26'''=========================================================================================='''27def ConvertDirectoryToString( directory ):28    '''29        Convert a directory to a string of filePaths with space as delimiter. While reading the directory,30        only real files are added to the list, sub-directories as well as links are ignored.31        32        directory33            a String containing the path to the directory34            35        Returns36            string of filePaths with space as delimiter37    '''38    output = ""39    if not directory:40        return listOfFilePaths41    if not os.path.isdir( directory ):42        return listOfFilePaths43    # loop through the directory44    for entry in glob.glob( os.path.join( directory, '*.*' ) ):45        if os.path.isfile( entry ) and not os.path.islink( entry ):46            # this is a real file and not a link or subdir47            # add it to the string48            output += str( os.path.normpath( entry ) )49            # add the delimiter50            output += " "51    return output.rstrip()52'''=========================================================================================='''53def ConvertListToString( list ):54    '''55        Convert a list to a string of items with space as delimiter.56        57        list58            a list object59            60        Returns61            string of list items with space as delimiter62    '''63    output = ""64    for i in list:65        output += str( i )66        output += " "67    return output.rstrip()68'''=========================================================================================='''69def usage():70    '''71        Print the help information.72    '''73    info( "Usage:" )74    info( "" )75    info( "-h, --help" )76    info( "        Show this information." )77    info( "" )78    info( "-i, --images DIR" )79    info( "        Directory containing original images." )80    info( "" )81    info( "-s, --segmentations DIR" )82    info( "        Directory containing segmentations." )83    info( "" )84    info( "-o, --output DIR" )85    info( "        Output directory." )86    info( "" )87    info( "--cmtk" )88    info( "        Use the CMTK toolkit for registration and resampling, instead of BRAINSFit." )89    info( "        The CMTK4Slicer extensions have to be installed in order to use CMTK." )90    info( "" )91    info( "--dramms" )92    info( "        Use the DRAMMS toolkit for registration and resampling, in addition to BRAINSFit or CMTK." )93    info( "" )94    info( "--skipRegistration" )95    info( "        Skip the registration and use existing transforms." )96    info( "" )97    info( "        The following arguments have to be specified if the registration is skipped:" )98    info( "" )99    info( "        --transforms DIR" )100    info( "                Directory containing existing transforms." )101    info( "" )102    info( "        --existingTemplate FILEPATH" )103    info( "                Filepath to an existing template used for resampling only." )104    info( "" )105    info( "--dynamic" )106    info( "        Use a dynamic template for registration based on means of images." )107    info( "" )108    info( "        The following arguments have to be specified if dynamic registration is chosen:" )109    info( "" )110    info( "        -m, --meanIterations INT" )111    info( "                Number of iterations to compute and register against a mean image." )112    info( "" )113    info( "--fixed" )114    info( "        Use a fixed template for registration." )115    info( "" )116    info( "        The following arguments have to be specified if fixed registration is chosen:" )117    info( "" )118    info( "        --template FILEPATH" )119    info( "                Filepath to an image used as a template for fixed registration." )120    info( "" )121    info( "        --ignoreTemplateSegmentation" )122    info( "                If activated, the template's segmentation will not be added to the atlases." )123    info( "" )124    info( "--affine" )125    info( "        Use 9 DOF affine registration additionally." )126    info( "" )127    info( "--affine12" )128    info( "        Use 12 DOF affine registration additionally. This includes --affine automatically." )129    info( "" )130    info( "-n, --non-rigid" )131    info( "        Use Non-Rigid registration additionally. This includes --affine and --affine12 automatically." )132    info( "" )133    info( "-w, --writeTransforms" )134    info( "        Write transforms to output directory." )135    info( "" )136    info( "--keepAligned" )137    info( "        Keep the aligned images and segmentations." )138    info( "" )139    info( "-l, --labels STRING" )140    info( "        List of labels to include for the atlases, f.e. \"3 4 5 6 8 10\"." )141    info( "        DEFAULT: detect labels automatically" )142    info( "" )143    info( "--normalize" )144    info( "        Normalize Atlases to 0..1." )145    info( "        If activated, the output cast will be set to Double." )146    info( "" )147    info( "        --normalizeTo INT" )148    info( "                The upper value to normalize the atlases to." )149    info( "                DEFAULT: 1" )150    info( "" )151    info( "--outputCast INT" )152    info( "        Output cast for the atlases. Possible values:" )153    info( "        0: char" )154    info( "        1: unsigned char" )155    info( "        2: double" )156    info( "        3: float" )157    info( "        4: int" )158    info( "        5: unsigned int" )159    info( "        6: long" )160    info( "        7: unsigned long" )161    info( "        8: short" )162    info( "        9: unsigned short" )163    info( "        DEFAULT: 8" )164    info( "" )165    info( "-c, --cluster" )166    info( "        Use the cluster mode." )167    info( "" )168    info( "        The following arguments have to be specified if cluster mode is chosen:" )169    info( "" )170    info( "        --schedulerCommand EXECUTABLE" )171    info( "                The executable to use as a scheduler in cluster mode, f.e. \"qsub\"." )172    info( "" )173    info( "--numberOfThreads" )174    info( "        Specify the number of threads to use for Registration." )175    info( "        By default, this is set to use the maximal number of threads for your machine." )176    info( "        DEFAULT: -1" )177    info( "" )178    info( "--pca" )179    info( "        Perform PCA Analysis on top of Resampling." )180    info( "" )181    info( "        --pcaMaxEigenVectors INT" )182    info( "                The number of maximal Eigenvectors to use for model generation." )183    info( "                DEFAULT: 10" )184    info( "" )185    info( "        --pcaCombine" )186    info( "                Combine the PCA output." )187    info( "" )188    info( "--slicer FILEPATH" )189    info( "        Filepath to the 3D Slicer launcher including arguments, f.e. \"/usr/bin/Slicer3 --tmp_dir /var/tmp\"." )190    info( "        DEFAULT: Find the 3D Slicer launcher automatically." )191    info( "" )192    info( "-d, --debug" )193    info( "        Enable debug information." )194    info( "" )195    info( "--dryrun" )196    info( "        Output executable commands instead of running the registration or resampling." )197    info( "" )198    info( "--examples" )199    info( "        Show usage examples." )200    info( "" )201    info( "" )202    info( "Developed by Daniel Haehn and Kilian Pohl, University of Pennsylvania. The research was funded by an ARRA supplement to NIH NCRR (P41 RR13218)." )203    info( "" )204    info( "Thanks to everyone!" )205    info( "" )206'''=========================================================================================='''207def examples():208    info( "Examples:" )209    info( "-----------------------------------------------------------------------------------------------" )210    info( "1. Run fixed registration with the testdata and normalize the atlases to 1:" )211    info( "" )212    info( '        python atlascreator.py -i TestData/originals/ -s TestData/segmentations/ -o /tmp/acout --fixed --template TestData/originals/case62.nrrd -w -l "3 4 5 6 7 8 9" --normalize' )213    info( "" )214    info( "-----------------------------------------------------------------------------------------------" )215    info( "2. Run fixed registration with the testdata and use CMTK instead of BRAINSFit and label auto-detection:" )216    info( "" )217    info( '        python atlascreator.py -i TestData/originals/ -s TestData/segmentations/ -o /tmp/acout --fixed --template TestData/originals/case62.nrrd -w --cmtk' )218    info( "" )219    info( "-----------------------------------------------------------------------------------------------" )220    info( "3. Run fixed registration with the testdata and use CMTK, label auto-detection and 12 DOF affine registration:" )221    info( "" )222    info( '        python atlascreator.py -i TestData/originals/ -s TestData/segmentations/ -o /tmp/acout --fixed --template TestData/originals/case62.nrrd -w --cmtk --affine12' )223    info( "" )224    info( "-----------------------------------------------------------------------------------------------" )225    info( "4. Run fixed registration with the testdata and use CMTK, label auto-detection and non-rigid registration:" )226    info( "" )227    info( '        python atlascreator.py -i TestData/originals/ -s TestData/segmentations/ -o /tmp/acout --fixed --template TestData/originals/case62.nrrd -w --cmtk --non-rigid' )228    info( "" )229    info( "-----------------------------------------------------------------------------------------------" )230    info( "5. Run dynamic registration with the testdata and normalize the atlases to 0..100:" )231    info( "" )232    info( '        python atlascreator.py -i TestData/originals/ -s TestData/segmentations/ -o /tmp/acout --dynamic --meanIterations 5 -w -l "3 4 5 6 7 8 9" --normalize --normalizeTo 100' )233    info( "" )234    info( "-----------------------------------------------------------------------------------------------" )235    info( "6. Run dynamic registration with the testdata on a cluster (scheduler command \"qsub -l centos5\"):" )236    info( "" )237    info( '        python atlascreator.py -i TestData/originals/ -s TestData/segmentations/ -o /tmp/acout --dynamic --meanIterations 5 -w -l "3 4 5 6 7 8 9" --normalize --cluster --schedulerCommand \"qsub -l centos5\"' )238    info( "" )239    info( "-----------------------------------------------------------------------------------------------" )240    info( "7. Use existing registrations and just re-sample" )241    info( "" )242    info( '        python atlascreator.py --skipRegistration --transforms /tmp/acout --existingTemplate TestData/segmentations/case62.nrrd -s TestData/segmentations/ -o /tmp/acout -l "3 4 5 6 7 8 9" --normalize --outputCast 3' )243    info( "" )244'''=========================================================================================='''245def main( argv ):246    '''247        Starting point, parse the command line args.248    '''249    info( "AtlasCreator for 3D Slicer" )250    info( "Version v0.42" )251    info( "Hostname: " + str( socket.gethostname() ) )252    info( "" )253    if len( argv ) == 0:254        usage()255        info( "Error: No arguments specified." )256        info( "" )257        sys.exit( 2 )258    try:259        opts, args = getopt.getopt( argv, "hdi:s:o:m:nwl:c", ["help",260                                                        "images=",261                                                        "segmentations=",262                                                        "output=",263                                                        "cmtk",264                                                        "dramms",265                                                        "skipRegistration",266                                                        "transforms=",267                                                        "existingTemplate=",268                                                        "dynamic",269                                                        "meanIterations=",270                                                        "fixed",271                                                        "template=",272                                                        "ignoreTemplateSegmentation",273                                                        "affine",274                                                        "affine12",275                                                        "non-rigid",276                                                        "writeTransforms",277                                                        "keepAligned",278                                                        "labels=",279                                                        "normalize",280                                                        "normalizeTo=",281                                                        "outputCast=",282                                                        "cluster",283                                                        "schedulerCommand=",284                                                        "numberOfThreads=",285                                                        "pca",286                                                        "pcaMaxEigenVectors=",287                                                        "pcaCombine",288                                                        "slicer=",289                                                        "debug",290                                                        "dryrun",291                                                        "testMode",292                                                        "examples"] )293    except getopt.GetoptError, err:294        usage()295        info( "Error: " + str( err ) )296        info( "" )297        sys.exit( 2 )298    # set some default switches299    skipRegistration = False300    slicerLauncherFilePath = None301    imagesDir = None302    segmentationsDir = None303    outputDir = None304    useCMTK = False305    useDRAMMS = False306    transformsDir = None307    existingTemplate = None308    dynamic = False309    meanIterations = 0310    fixed = False311    template = None312    ignoreTemplateSegmentation = False313    affine = False314    affine12 = False315    nonRigid = False316    writeTransforms = False317    keepAligned = False318    labels = None319    normalize = False320    normalizeTo = 1321    outputCast = 8322    cluster = False323    schedulerCommand = None324    numberOfThreads = -1325    pca = False326    pcaMaxEigenVectors = 10327    pcaCombine = False328    debug = False329    dryrun = False330    testMode = False331    for opt, arg in opts:332        if opt in ( "-h", "--help" ):333            usage()334            sys.exit()335        elif opt in ( "-i", "--images" ):336            imagesDir = arg337        elif opt in ( "-s", "--segmentations" ):338            segmentationsDir = arg339        elif opt in ( "-o", "--output" ):340            outputDir = arg341        elif opt in ( "--cmtk" ):342            useCMTK = True343        elif opt in ( "--dramms" ):344            useDRAMMS = True345        elif opt in ( "--skipRegistration" ):346            skipRegistration = True347        elif opt in ( "--transforms" ):348            transformsDir = arg349        elif opt in ( "--existingTemplate" ):350            existingTemplate = arg351        elif opt in ( "--dynamic" ):352            dynamic = True353        elif opt in ( "-m", "--meanIterations" ):354            meanIterations = arg355        elif opt in ( "--fixed" ):356            fixed = True357        elif opt in ( "--template" ):358            template = arg359        elif opt in ( "--ignoreTemplateSegmentation" ):360            ignoreTemplateSegmentation = True361        elif opt in ( "--affine" ):362            affine = True363        elif opt in ( "--affine12" ):364            affine12 = True365        elif opt in ( "-n", "--non-rigid" ):366            nonRigid = True367        elif opt in ( "-w", "--writeTransforms" ):368            writeTransforms = True369        elif opt in ( "--keepAligned" ):370            keepAligned = True371        elif opt in ( "-l", "--labels" ):372            labels = arg.strip().split( " " )373        elif opt in ( "--normalize" ):374            normalize = True375        elif opt in ( "--normalizeTo" ):376            normalize = True377            normalizeTo = arg378        elif opt in ( "--outputCast" ):379            outputCast = arg380        elif opt in ( "-c", "--cluster" ):381            cluster = True382        elif opt in ( "--schedulerCommand" ):383            schedulerCommand = arg384        elif opt in ( "--numberOfThreads" ):385            numberOfThreads = arg386        elif opt in ( "--pca" ):387            pca = True388        elif opt in ( "--pcaMaxEigenVectors" ):389            pca = True390            pcaMaxEigenVectors = arg391        elif opt in ( "--pcaCombine" ):392            pca = True393            pcaCombine = True394        elif opt in ( "--slicer" ):395            slicerLauncherFilePath = arg396        elif opt in ( "-d", "--debug" ):397            debug = True398        elif opt in ( "--dryrun" ):399            debug = True400            dryrun = True401        elif opt in ( "--testMode" ):402            testMode = True403            debug = True404        elif opt in ( "--examples" ):405            examples()406            sys.exit()407        else:408            assert False, "unhandled option"409    # now check if we have all we need410    errorOccured = False411    # we need 3D Slicer, find the launcher412    if not slicerLauncherFilePath:413        # try to find the slicer launcher automatically414        slicerLauncherFilePath = sys.path[0] + os.sep + "../../../../Slicer3"415        slicerLauncherFilePath = os.path.abspath( slicerLauncherFilePath )416        if os.path.isfile( slicerLauncherFilePath ):417            # running in bin directory418            info( "Found 3D Slicer launcher at " + str( slicerLauncherFilePath ) )419        else:420            slicerLauncherFilePath = sys.path[0] + os.sep + "../../../Slicer3-build/Slicer3"421            slicerLauncherFilePath = os.path.abspath( slicerLauncherFilePath )422            if os.path.isfile( slicerLauncherFilePath ):423                # running in src directory424                info( "Found 3D Slicer3 launcher at " + str( slicerLauncherFilePath ) )425            else:426                info( "Error: Could not find the 3D Slicer launcher!" )427                info( "Error: Try to specify the location with --slicer /path/Slicer3" )428                errorOccured = True429    else:430        info( "3D Slicer manually specified: " + str( slicerLauncherFilePath ) )431    # check if we have a valid images dir432    if not ( imagesDir and os.path.isdir( imagesDir ) ) and not skipRegistration:433        # no valid imagesDir and registration is not skipped434        # we have to abort435        info( "Error: Could not find the images!" )436        info( "Error: Location of --images is invalid: " + str( imagesDir ) )437        errorOccured = True438    elif imagesDir:439        imagesDir = os.path.abspath( imagesDir ) + os.sep440    if not ( segmentationsDir and os.path.isdir( segmentationsDir ) ):441        # no valid segmentationsDir442        # we have to abort443        info( "Error: Could not find the segmentations!" )444        info( "Error: Location of --segmentations is invalid: " + str( segmentationsDir ) )445        errorOccured = True446    elif segmentationsDir:447        segmentationsDir = os.path.abspath( segmentationsDir ) + os.sep448    if not outputDir:449        info( "Error: Location of --output is invalid or not a directory: " + str( outputDir ) )450        errorOccured = True451    # check if we have everything if skipRegistration is enabled452    if skipRegistration and transformsDir and existingTemplate:453        # check if transformDir and existingTemplate are not valid454        if not os.path.isdir( transformsDir ):455            # transformDir invalid456            info( "Error: Could not find the directory of existing transforms!" )457            info( "Error: Location of --transforms is invalid: " + str( transformsDir ) )458            errorOccured = True459        else:460            transformsDir = os.path.abspath( transformsDir ) + os.sep461        if not os.path.isfile( existingTemplate ):462            # existingTemplate invalid 463            info( "Error: Could not find the existing template!" )464            info( "Error: Location of --existingTemplate is invalid: " + str( existingTemplate ) )465            errorOccured = True466        else:467            existingTemplate = os.path.abspath( existingTemplate )468    elif skipRegistration:469        # we don't have everything, abort!470        info( "Error: To skip the registration, --transforms and --existingTemplate are required!" )471        info( "Error: Location of --transforms is invalid: " + str( transformsDir ) )472        info( "Error: Location of --existingTemplate is invalid: " + str( existingTemplate ) )473        errorOccured = True474    # check if either dynamic or fixed registration is configured475    if not dynamic and not fixed and not skipRegistration:476        info( "Error: The registration type was not set. Either --fixed or --dynamic are required!" )477        errorOccured = True478    # check if both, dynamic and fixed were configured479    if dynamic and fixed:480        info( "Error: Either --fixed or --dynamic are required - not both!" )481        errorOccured = True482    # check if we have everything if it is dynamic mode483    if dynamic and meanIterations:484        # check if meanIterations is valid485        if not is_int( meanIterations ) or not ( int( meanIterations ) >= 1 ):486            info( "Error: The value of --meanIterations has to be an INT greater than 1." )487            if not is_int( meanIterations ):488                info( "Error: Value of --meanIterations is invalid: NaN" )489            else:490                info( "Error: Value of --meanIterations is invalid: " + str( int( meanIterations ) ) )491            errorOccured = True492    elif dynamic:493        # we don't have everything, abort!494        info( "Error: For dynamic registration, --meanIterations is required!" )495        info( "Error: Value of --meanIterations is invalid: " + str( int( meanIterations ) ) )496        errorOccured = True497    # check if we have everything if it is fixed mode498    if fixed and template:499        # check if template is valid500        if not os.path.isfile( template ):501            # existingTemplate invalid 502            info( "Error: Could not find the template!" )503            info( "Error: Location of --template is invalid: " + str( template ) )504            errorOccured = True505        else:506            template = os.path.abspath( template )507    elif fixed:508        # we don't have everything, abort!509        info( "Error: For fixed registration, --template is required!" )510        info( "Error: Location of --template is invalid: " + str( template ) )511        errorOccured = True512    # check if at least one label was specified513    if labels and type( labels ).__name__ == 'list' and len( labels ) >= 1:514        # convert to integer list515        realLabels = []516        for l in labels:517            if is_int( l ):518                realLabels.append( int( l ) )519        if len( realLabels ) < 1:520            # invalid label list521            info( "Error: At least one label (INT) is required!" )522            info( "Error: Value of --labels: " + str( labels ) )523            errorOccured = True524        else:525            labels = list( set( realLabels ) )526    elif labels:527        info( "Error: At least one label (INT) is required!" )528        info( "Error: Value of --labels: " + str( labels ) )529        errorOccured = True530    # if normalizeTo was set, check if it is an integer531    if normalizeTo != 1 and not is_int( normalizeTo ):532        info( "Error: The normalizeTo value must be an integer." )533        info( "Error: Value of --normalizeTo: " + str( normalizeTo ) )534        errorOccured = True535    # check if pcaMaxEigenVectors is an integer536    if not is_int( pcaMaxEigenVectors ):537        info( "Error: The pcaMaxEigenVectors value must be an integer." )538        info( "Error: Value of --pcaMaxEigenVectors: " + str( pcaMaxEigenVectors ) )539        errorOccured = True540    # check if we have a valid outputCast541    if outputCast and is_int( outputCast ):542        if not ( int( outputCast ) > 0 and int( outputCast ) <= 9 ):543            info( "Error: The specified output cast is invalid - only values from 0-9 accepted." )544            info( "Error: Value of --outputCast: " + str( outputCast ) )545            errorOccured = True546        # valid outputCast integer, convert to string547        if int( outputCast ) == 0:548            outputCast = "char"549        elif int( outputCast ) == 1:550            outputCast = "unsigned char"551        elif int( outputCast ) == 2:552            outputCast = "double"553        elif int( outputCast ) == 3:554            outputCast = "float"555        elif int( outputCast ) == 4:556            outputCast = "int"557        elif int( outputCast ) == 5:558            outputCast = "unsigned int"559        elif int( outputCast ) == 6:560            outputCast = "long"561        elif int( outputCast ) == 7:562            outputCast = "unsigned long"563        elif int( outputCast ) == 8:564            outputCast = "short"565        elif int( outputCast ) == 9:566            outputCast = "unsigned short"567    elif outputCast:568        info( "Error: The specified output cast is invalid - only values from 0-9 accepted." )569        info( "Error: Value of --outputCast: " + str( outputCast ) )570        errorOccured = True571    # check if we have everything if cluster mode is activated572    if cluster and not schedulerCommand:573        info( "Error: In cluster mode, a schedulerCommand is required." )574        info( "Error: Value of --schedulerCommand: " + str( schedulerCommand ) )575        errorOccured = True576    if not is_int( numberOfThreads ):577        info( "Error: The number of threads must be an integer." )578        info( "Error: Value of --numberOfThreads: " + str( numberOfThreads ) )579        errorOccured = True580    if errorOccured:581        info( "" )582        info( "Try --help or --examples to understand the usage of the Atlas Creator." )583        info( "" )584        sys.exit( 2 )585    # lets create the --evalpython command!!586    evalpythonCommand = "from Slicer import slicer;"587    # we create a new vtkMRMLAtlasCreatorNode and configure it..588    evalpythonCommand += "n=slicer.vtkMRMLAtlasCreatorNode();"589    if debug or dryrun or testMode:590        evalpythonCommand += "n.SetDebugMode(1);"591    if dryrun:592        evalpythonCommand += "n.SetDryrunMode(1);"593    if testMode:594        evalpythonCommand += "n.SetTestMode(1);"595    # set special settings if clusterMode or skipRegistrationMode is requested596    if cluster:597        # cluster Mode598        evalpythonCommand += "n.SetUseCluster(1);"599        evalpythonCommand += "n.SetSchedulerCommand('" + schedulerCommand + "');"600    elif skipRegistration:601        # skipRegistration Mode602        evalpythonCommand += "n.SetSkipRegistration(1);"603        evalpythonCommand += "n.SetTransformsDirectory('" + transformsDir + "');"604        evalpythonCommand += "n.SetExistingTemplate('" + existingTemplate + "');"605    # now the configuration options which are valid for all606    if imagesDir:607        evalpythonCommand += "n.SetOriginalImagesFilePathList('" + ConvertDirectoryToString( imagesDir ) + "');"608    if segmentationsDir:609        evalpythonCommand += "n.SetSegmentationsFilePathList('" + ConvertDirectoryToString( segmentationsDir ) + "');"610    if outputDir:611        evalpythonCommand += "n.SetOutputDirectory('" + outputDir + "');"612    if useCMTK:613        evalpythonCommand += "n.SetToolkit('CMTK');"614    else:615        evalpythonCommand += "n.SetToolkit('BRAINSFit');"616    if fixed:617        evalpythonCommand += "n.SetTemplateType('fixed');"618        evalpythonCommand += "n.SetFixedTemplateDefaultCaseFilePath('" + template + "');"619        if ignoreTemplateSegmentation:620            evalpythonCommand += "n.SetIgnoreTemplateSegmentation(1);"621        else:622            evalpythonCommand += "n.SetIgnoreTemplateSegmentation(0);"623    else:624        evalpythonCommand += "n.SetTemplateType('dynamic');"625        evalpythonCommand += "n.SetDynamicTemplateIterations(" + str( meanIterations ) + ");"626    if labels:627        evalpythonCommand += "n.SetLabelsList('" + ConvertListToString( labels ) + "');"628    else:629        # activate label auto-detection630        evalpythonCommand += "n.SetLabelsList(None);"631    if nonRigid:632        evalpythonCommand += "n.SetRegistrationType('Non-Rigid');"633    elif affine12:634        evalpythonCommand += "n.SetRegistrationType('Affine12');"635    elif affine:636        evalpythonCommand += "n.SetRegistrationType('Affine');"637    else:638        evalpythonCommand += "n.SetRegistrationType('Rigid');"639    if writeTransforms:640        evalpythonCommand += "n.SetSaveTransforms(1);"641    else:642        evalpythonCommand += "n.SetSaveTransforms(0);"643    if keepAligned:644        evalpythonCommand += "n.SetDeleteAlignedImages(0);"645        evalpythonCommand += "n.SetDeleteAlignedSegmentations(0);"646    else:647        evalpythonCommand += "n.SetDeleteAlignedImages(1);"648        evalpythonCommand += "n.SetDeleteAlignedSegmentations(1);"649    if normalize:650        evalpythonCommand += "n.SetNormalizeAtlases(1);"651        evalpythonCommand += "n.SetNormalizeTo(" + str( normalizeTo ) + ");"652    else:653        evalpythonCommand += "n.SetNormalizeAtlases(0);"654        evalpythonCommand += "n.SetNormalizeTo(-1);"655    if pca:656        evalpythonCommand += "n.SetPCAAnalysis(1);"657        evalpythonCommand += "n.SetPCAMaxEigenVectors(" + str( pcaMaxEigenVectors ) + ");"658    else:659        evalpythonCommand += "n.SetPCAAnalysis(0);"660        evalpythonCommand += "n.SetPCAMaxEigenVectors(10);"661    if pcaCombine:662        evalpythonCommand += "n.SetPCACombine(1);"663    else:664        evalpythonCommand += "n.SetPCACombine(0);"665    if useDRAMMS:666        evalpythonCommand += "n.SetUseDRAMMS(1);"667    else:668        evalpythonCommand += "n.SetUseDRAMMS(0);"669    evalpythonCommand += "n.SetNumberOfThreads(" + str( numberOfThreads ) + ");"670    evalpythonCommand += "n.SetOutputCast('" + outputCast + "');"671    # add the new node to the MRML scene672    evalpythonCommand += "slicer.MRMLScene.AddNode(n);"673    evalpythonCommand += "n.Launch();"674    command = slicerLauncherFilePath + ' --no_splash --evalpython "' + evalpythonCommand + '"'675    # now run the command676    try:677        r = call( command, shell=True )678    except OSError, e:679        self.info( "Execution failed " + str( e ) )680'''=========================================================================================='''681if __name__ == "__main__":...backend.py
Source:backend.py  
...43        if included:44            raise LookupError(u"in " + included + u":" + u(line) + u": pointer " + name)45        else:46            raise LookupError(u"in " + u(line) + u": pointer " + name)47def evalPython(expr):48    try:49        result = eval(u(expr), pythonFunc)50        if type(result) is str:51            return codecs.decode(result, encoding)52        else:53            return result54    except:55        name, parm, tb = sys.exc_info()56        msg = u"in python expression: " + u(parm)57        if name is exceptions.SyntaxError:58            tbl = traceback.format_exception(name, parm, tb)59            msg += u"\n" + tbl[-3] + tbl[-2]60        else:61            msg += u": " + expr + u"\n"62        if included:63            raise name(u"in " + included + u":" + u(line) + u": " + msg)64        else:65            raise name(u"in " + u(line) + u": " + msg)66    67def execPython(script):68    try:69        if type(script) is unicode:70            exec script in pythonFunc71        else:72            exec codecs.decode(script, encoding) in pythonFunc73    except:74        name, parm, tb = sys.exc_info()75        msg = u"in python script: " + u(parm)76        if name is exceptions.SyntaxError:77            tbl = traceback.format_exception(name, parm, tb)78            msg += u"\n" + tbl[-3] + tbl[-2]79        else:80            msg += u": " + expr + u"\n"81        if included:82            raise name(u"in " + included + u":" + u(line) + u": " + msg)83        else:84            raise name(u"in " + u(line) + u": " + msg)85def textOut(text):86    if not text:87        return u""88    if type(text) is not unicode:89        text = codecs.decode(text, encoding)90    text = text.replace(r'\"', r'\\"')91    text = u'u"""' + text.replace('"', r'\"') + u'"""'92    try:93        textFunc = ymlFunc["text"]94        parms = ['text', ('parm', [text])]95        c, result = textFunc(parms)96        if c:97            if type(textFunc.alias) is unicode:98                result += u"</" + textFunc.alias + u">"99            else:100                result += u"</" + codecs.decode(textFunc.alias, encoding) + u">"101        return result102    except:103        return escape(eval(text))104def strRepl(text):105    if not text:106        return u""107    if type(text) is not unicode:108        text = codecs.decode(text, encoding)109    text = text.replace(r'\"', r'\\"')110    text = u'u"""' + text.replace('"', r'\"') + u'"""'111    if type(text) is unicode:112        return escape(eval(text))113def applyMacros(macros, text):114    result = text115    for key, value in macros.iteritems():116        result = result.replace(key, value)117    return result118class YF:119    def __init__(self, name):120        self.name = name121        self.parms = []122        self.descends = []123        self.values = {}124        self.content = None125        self.pointers = {}126        self.macros = {}127        if in_ns:128            self.alias = in_ns + u":" + name.replace("_", "-")129        else:130            self.alias = name.replace("_", "-")131        pythonFunc["yml_" + name] = self132        if emitlinenumbers:133            self.values["yml:declared"] = u(line)134    def copy(self, newName):135        yf = YF(newName)136        yf.parms.extend(self.parms)137        yf.descends.extend(self.descends)138        yf.values = self.values.copy()139        yf.content = self.content140        yf.pointers = self.pointers.copy()141        yf.macros = self.macros.copy()142        yf.alias = self.alias143        return yf144    def patch(self, second):145        self.parms.extend(second.parms)146        self.descends.extend(second.descends)147        self.values.update(second.values)148        if second.content:149            self.content = second.content150        self.pointers.update(second.pointers)151        self.macros.update(second.macros)152    def __call__(self, called_with, hasContent = False, avoidTag = False):153        global pointers154        parms = []155        vals = {}156        if self.pointers:157            pointers.update(self.pointers)158   159        for data in called_with:160            if type(data) is tuple or type(data) is Symbol:161                if data[0] == "parm":162                    l = data[1]163                    parm = l[0]164                    if parm[0] == "*":165                        parm = pointer(parm)166                    if len(l) == 1:167                        if type(parm) is tuple or type(parm) is Symbol:168                            if parm[0] == "pyExp":169                                val = evalPython(parm[1][0])170                                parms.append(val)171                        else:172                            parms.append(evalPython((parm)))173                    else:174                        if type(parm) is tuple or type(parm) is Symbol:175                            if parm[0] == "pyExp":176                                parm = evalPython(parm[1][0])177                        val = l[1]178                        if type(val) is tuple or type(val) is Symbol:179                            if val[0] == "pyExp":180                                val = evalPython(val[1][0])181                        if val[0] == "*":182                            val = pointer(val)183                        if u(val)[0] == '"' or u(val)[0] == "'":184                            vals[parm] = evalPython(u(val))185                        else:186                            vals[parm] = u(val)187                elif data[0] == "content":188                    hasContent = True189        if enable_tracing:190            text = u(parms) + u", " + u(vals)191            pointers["_trace_info"] = u'"' + u(line) + u": " + u(self.name) + u" " + text.replace(u'"', u'#') + u'"'192        if emitlinenumbers:193            global first194            if first:195                vals["xmlns:yml"] = u"http://fdik.org/yml"196                first = False197            vals["yml:called"] = u(line)198        return self.xml(parms, vals, hasContent, avoidTag)199    def addParm(self, parm):200        if parm[0] == "%":201            for i in range(len(self.parms)):202                if self.parms[i][0] != "%":203                    self.parms.insert(i, parm)204                    return205        self.parms.append(parm)206    def addDescend(self, desc):207        if desc[0] == "+" or desc[0] == "@":208            self.descends.append(desc[1:])209        else:210            self.descends.append(desc)211    def addValue(self, parm, value):212        if type(value) is str or type(value) is unicode:213            self.values[parm] = u(evalPython(value))214        else:215            self.values[parm] = u(evalPython(u(value)))216    def xml(self, callParms, callValues, hasContent, avoidTag = False):217        global pointers218        extraContent = u""219        if self.content:220            hasContent = True221        resultParms = self.values.copy()222        macros = self.macros.copy()223        toDelete = resultParms.keys()224        for key in toDelete:225            if key[0] == "*":226                del resultParms[key]227        for key, value in callValues.iteritems():228            if key[0] == "%":229                macros[key] = value230            else:231                resultParms[key] = value232        i = 0233        for cp in callParms:234            if i < len(self.parms):235                if self.parms[i][0] == "*":236                    cp = u(cp)237                    if "'" in cp:238                        pointers[self.parms[i][1:]] = u'"' + cp + u'"'239                    else:240                        pointers[self.parms[i][1:]] = u"'" + cp + u"'"241                elif self.parms[i][0] == "%":242                    macros[self.parms[i]] = u(cp)243                else:244                    resultParms[self.parms[i]] = cp245            else:246                extraContent += u(cp)247                hasContent = True248            i += 1249        result = u""250        for p, v in resultParms.iteritems():251            if p[0] == "'" or p[0] == '"':252                p = eval(p)253            result += u" "+ p + u"=" + quoteattr(applyMacros(macros, u(v)))254        if hasContent:255            if avoidTag:256                return True, strRepl(extraContent)257            else:258                return True, u"<" + self.alias + result + u">" + strRepl(extraContent)259        else:260            if avoidTag:261                return False, u""262            else:263                return False, u"<" + self.alias + result + u"/>"264def replaceContent(tree, subtree):265    n = 0266    while n < len(tree):267        obj = tree[n]268        if obj[0] == "func":269            l = obj[1]270            if l[0] == "content":271                d = 1272                if subtree:273                    for el in subtree:274                        tree.insert(n+d, el)275                        d += 1276                del tree[n]277                n += d278            else:279                try:280                    if l[-1][0] == "content":281                        replaceContent(l[-1][1], subtree)282                except: pass283        elif obj[0] == "funclist":284            replaceContent(obj[1], subtree)285        n += 1286    return tree287def executeCmd(text):288    if type(text) is not unicode:289        text = codecs.decode(text, encoding)290    for (regex, pattern) in operator:291        match = re.search(regex, text)292        while match:293            cmd = pattern294            opt = match.groups()295            for i in range(len(opt)):296                cmd = cmd.replace(u"%" + u(i+1), opt[i])297            text = text[:match.start()] + u"`" + cmd + u"`"+ text[match.end():]298            match = re.search(regex, text)299    result = u""300    m = re.search(bq, text)301    while text and m:302        cmd  = m.group(1)303        head = textOut(text[:m.start()])304        text = text[m.end():]305        try:306            r, rest = parseLine(cmd, _inner, [], True, comment)307            if rest: raise SyntaxError(cmd)308        except SyntaxError:309            if included:310                raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())311            else:312                raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())313        inner = _finish(r)314        result += head + inner315        m = re.search(bq, text)316    result += textOut(text)317    return result318def codegen(obj):319    global in_ns, pointers, line, included320    ctype = obj[0]321    if type(obj) is code:322        return obj323    try:324        if ctype.line: line = ctype.line325    except: pass326    if ctype == "empty":327        return code(u"")328    if ctype == "in_ns":329        in_ns = obj[1][0]330        subtree = obj[1]331        for sel in subtree:332            codegen(sel)333        in_ns = u""334        return code(u"")335    elif ctype == "decl":336        name = u""337        for data in obj[1]:338            if type(data) is unicode or type(data) is str:339                name = data340                try:341                    yf = ymlFunc[name]342                    yf.alias343                except:344                    ymlFunc[name] = YF(name)345                    yf = ymlFunc[name]346                    if in_ns:347                        yf.alias = in_ns + u":" + name348                        if not enable_tracing:349                            if in_ns == "xsl" and (name == "debug" or name=="assert" or name[:7]=="_trace_"):350                                yf.alias = "-"351                                yf.addParm("skip1")352                                yf.addParm("skip2")353                                break354            elif type(data) is tuple or type(data) is Symbol:355                if data[0] == "base":356                    base = data[1][0]357                    try:358                        yf = ymlFunc[name] = ymlFunc[base].copy(name)359                    except KeyError:360                        if included:361                            raise KeyError(u"in " + included + u":" + u(line) + u": " + base + u" as base for " + name)362                        else:363                            raise KeyError(u"in " + u(line) + u": " + base + u" as base for " + name)364                elif data[0] == "shape":365                    shape = ymlFunc[data[1]]366                    try:367                        yf = ymlFunc[name]368                        yf.patch(shape)369                    except KeyError:370                        if included:371                            raise KeyError(u"in " + included + u":" + u(line) + u": " + base + u" as shape for " + name)372                        else:373                            raise KeyError(u"in " + u(line) + u": " + base + u" as shape for " + name)374                elif data[0] == "descend":375                    yf.addDescend(data[1])376                elif data[0] == "declParm":377                    l = data[1]378                    parmName = l[0]379                    if len(l)==1:380                        yf.addParm(parmName)381                    else:382                        value = l[1]383                        if parmName[0] != "%":384                            yf.addValue(parmName, value)385                        if parmName[0] == "*":386                            yf.pointers[parmName[1:]] = value387                            yf.addParm(parmName)388                        elif parmName[0] == "%":389                            if type(value) is unicode or type(value) is str:390                                yf.macros[parmName] = u(evalPython(value))391                            else:392                                yf.macros[parmName] = u(evalPython(u(value)))393                            yf.addParm(parmName)394                elif data[0] == "alias":395                    if in_ns:396                        yf.alias = in_ns + u":" + data[1][0]397                    else:398                        yf.alias = data[1][0]399                elif data[0] == "content":400                    yf.content = data[1]401        return code(u"")402    elif ctype == "funclist":403        result = u""404        for f in obj[1]:405            result += codegen(f)406        return code(result)407    elif ctype == "parentheses":408        if len(obj[1]):409            return codegen(('func', ['_parentheses', ('content', [obj[1][0]])]))410        else:411            return u""412    elif ctype == "fparm":413        if len(obj[1]):414            return codegen(('func', ['_parm', ('content', [obj[1][0]])]))415        else:416            return u""417    elif ctype == "generic":418        return codegen(('func', ['_generic', ('content', [obj[1][0]])]))419    elif ctype == "xbase":420        return codegen(('func', ['_base', ('content', [obj[1][0]])]))421    elif ctype == "func":422        avoidTag = False423        name = obj[1][0]424        if name == "decl":425            if ymlFunc[name] == "#error":426                if included:427                    raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in decl statement")428                else:429                    raise SyntaxError(u"in " + u(line) + u": syntax error in decl statement")430        if name == "define" or name == "operator":431            if ymlFunc[name] == "#error":432                if included:433                    raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in define statement")434                else:435                    raise SyntaxError(u"in " + u(line) + u": syntax error in define statement")436        if name[0] == "&":437            avoidTag = True438            name = name[1:]439        hasContent = False440        if len(name) > 2:441            if name[0:2] == "**":442                return code(eval('u'+pointer(name[1:])))443        if name[0] == "*":444            name = eval(pointer(name))445            if name[0] == "&":446                avoidTag = True447                name = name[1:]448        try:449            ymlFunc[name]450        except:451            try:452                ymlFunc["_"]453                return codegen(('func', ['_', ('content', [('funclist', [obj])])]))454            except:455                ymlFunc[name] = YF(name)456        457        if ymlFunc[name].alias == "-": avoidTag = True458        to_add = []459        if len(ymlFunc[name].descends):460            if obj[1][-1][0] != 'content':461                if included:462                    raise KeyError(u"in " + included + u":" + u(line) + u": " + name + u" has descending attributes, but no descendants are following")463                else:464                    raise KeyError(u"in " + u(line) + u": " + name + u" has descending attributes, but no descendants are following")465            def first_func(obj):466                if type(obj) is tuple or type(obj) is Symbol:467                    if obj[0] == 'func':468                        return obj469                    elif obj[0] == 'funclist':470                        return first_func(obj[1])471                    elif obj[0] == 'content':472                        return first_func(obj[1])473                    else:474                        return None475                elif type(obj) == list:476                    for e in obj:477                        f = first_func(e)478                        if f: return f479                    return None480            def copy_without_first_func(o, found = False):481                c = []482                for obj in o:483                    if found:484                        c.append(obj)485                    else:486                        if obj[0] == 'func':487                            if obj[1][-1][0] == 'content':488                                c.extend( obj[1][-1][1] )489                            found = True490                        else:491                            c.append( ( obj[0], copy_without_first_func(obj[1], False ) ) )492                return c493            def get_parms(obj):494                result = []495                for e in obj[1]:496                    if type(e) is tuple or type(e) is Symbol:497                        if e[0] == "parm":498                            result.append( e )499                return result500            try:501                add_params = get_parms(obj)502                for e in obj[1][-1][1]:503                    c = e[1]504                    for dname in ymlFunc[name].descends:505                        f, c = first_func(c), copy_without_first_func(c)506                        if dname[0] == "*":507                            pointers[dname[1:]] = "'" + f[1][0] + "'"508                        else:509                            add_params.append( ('parm', [dname, u"'" + f[1][0] + u"'"]) )510                        try:511                            add_params.extend( get_parms(f) )512                        except: pass513                    new_things = [ e[1][0] ]514                    new_things.extend( add_params )515                    new_things.append( ('content', c) )516                    517                    to_add.append( ('func', new_things ) )518            except:519                if included:520                    raise KeyError(u"in " + included + u":" + u(line) + u": " + name + u" has descending attributes, and too less descendants are following")521                else:522                    raise KeyError(u"in " + u(line) + u": " + name + u" has descending attributes, and too less descendants are following")523        if not to_add:524            to_add = ( obj, )525        complete = u""526        for obj in to_add:527            subtree = None528            try:529                if obj[1][-1][0] == "content":530                    subtree = obj[1][-1][1]531            except: pass532     533            if ymlFunc[name].content:534                hasContent = True535                treetemplate = deepcopy(ymlFunc[name].content)536                subtree = replaceContent(treetemplate, subtree)537            if subtree:538                hasContent = True539            hasContent, result = ymlFunc[name](obj[1], hasContent, avoidTag)540            if subtree:541                for sel in subtree:542                    result += codegen(sel)543            if hasContent and not(avoidTag):544                result += u"</" + ymlFunc[name].alias + u">"545            complete += result546        return code(complete)547    elif ctype == "textsection":548        result = u''549        ll = obj[1].splitlines()550        space = len(ll[-1]) - 2551        for l in ll[1:-1]:552            m = re.match(bqq, l)553            if m:554                cmd = m.group(1)555                try:556                    r, x = parseLine(cmd, _inner, [], True, comment)557                    if x: raise SyntaxError(cmd)558                    result += _finish(r)559                except SyntaxError:560                    if included:561                        raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())562                    else:563                        raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())564            else:565                result += codegen(Symbol(u'lineQuote', u'| ' + l[space:]))566        return code(result)567    elif ctype == "textsectionu":568        result = u''569        ll = obj[1].splitlines()570        space = len(ll[-1]) - 2571        for l in ll[1:-1]:572            m = re.match(bqq, l)573            if m:574                cmd = m.group(1)575                try:576                    r, x = parseLine(cmd, _inner, [], True, comment)577                    if x: raise SyntaxError(cmd)578                    result += _finish(r)579                except SyntaxError:580                    if included:581                        raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())582                    else:583                        raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())584            else:585                if result != u'': result += u' '586                result += codegen(Symbol(u'quote', [u'> ' + l[space:]]))587        return code(result)588    elif ctype == "lineQuote" or ctype == "quote":589        m, text, base, inds = None, u"", 0, 0590        if ctype == "lineQuote":591            text = obj[1]592            m = lq.match(text)593            if m:594                inds = len(m.group(1))595                text = m.group(2)[1:]596            else: inds = 0597        elif ctype == "quote":598            inds = -1599            text = obj[1][0]600            m = sq.match(text)601            if m:602                if m.group(1):603                    inds = int(m.group(1))604                text = m.group(2)[1:]605            else:606                if type(text) is unicode or type(text) is str:607                    text = u(evalPython(text))608        ind = u""609        if inds > -1:610            try:611                cmd = evalPython(u"indent(" + u(inds) + u")")612                result, rest = parseLine(u(cmd), _inner, [], True, comment)613                if rest:614                    raise SyntaxError()615                ind = _finish(result)616            except: pass617        618        if ctype == "lineQuote": text += u"\n"619        hasTextFunc = False620        try:621            ymlFunc["text"]622            hasTextFunc = True623        except: pass624        text = executeCmd(text)625        return code(ind + text) 626    elif ctype == "tagQuote":627        m = tq.match(obj[1])628        if m.group(1) == "<":629            return code(u"<" + m.group(2))630        else:631            return code(m.group(2))632    elif ctype == "operator":633        operator.append((re.compile(evalPython(obj[1][0])), obj[1][1]))634        return code(u"")635    elif ctype == "constant":636        name = obj[1][0]637        if name[0] == "*":638            name = name[1:]639        value = obj[1][1]640        pointers[name] = value641        return code(u"")642    elif ctype == "include":643        reverse = False644        ktext, kxml = False, False645        for arg in obj[1]:646            if type(arg) is tuple or type(arg) is Symbol:647                if arg[0] == "reverse":648                    reverse = True649                elif arg[0] == "ktext":650                    ktext = True651                elif arg[0] == "kxml":652                    kxml = True653            elif type(arg) is unicode or type(arg) is str:654                filemask = arg655        if filemask[0] == '/' or filemask[0] == '.':656            files = sorted(glob(filemask))657        else:658            files = []659            for directory in includePath:660                path = os.path.join(directory, filemask)661                files.extend(sorted(glob(path)))662        if files and reverse:663            files = files[-1::-1]664        if not(files):665            if included:666                raise IOError(u"in " + included + ":" + u(line) + u": include file(s) '" + filemask + u"' not found")667            else:668                raise IOError(u"in " + u(line) + u": include file(s) '" + filemask + u"' not found")669        includeFile = fileinput.input(files, mode="rU", openhook=fileinput.hook_encoded(encoding))670        _included = included671        if ktext or kxml:672            text = u""673            for line in includeFile:674                included = includeFile.filename()675                if kxml:676                    if (not line[:6] == '<?xml ') and (not line[:6] == '<?XML '):677                        text += line678                else:679                    text += executeCmd(line)680            included = _included681            return code(text)682        else:683            result = parse(ymlCStyle(), includeFile, True, comment)684            included = u(filemask)685            x = _finish(result)686            included = _included687            return code(x)688    elif ctype == "pyExp":689        exp = obj[1][0]690        cmd = evalPython(exp)691        result, rest = parseLine(u(cmd), _inner, [], True, comment)692        if rest:693            raise SyntaxError(cmd)694        return code(_finish(result))695    elif ctype == "pythonCall":696        parms = []697        data = obj[1]698        for p in data:699            if type(p) is unicode or type(p) is str:700                name = p701            elif type(p) is tuple or type(p) is Symbol:702                ptype = p[0]703                if ptype == "parm":704                    if p[1][0][0] == "*":705                        parms.append(pointer(p[1][0]))706                    else:707                        parms.append(p[1][0])708        if len(parms) == 0:709            exp = name + u"()"710        elif len(parms) == 1:711            exp = name + u"(" + u(parms[0]) + u")"712        else:713            exp = name + u(tuple(parms))714        cmd = evalPython(exp)715        result, rest = parseLine(u(cmd), _inner, [], True, comment)716        if rest:717            raise SyntaxError()718        return code(_finish(result))719    else:720        return code(u"")721def _finish(tree):722    result = u""723    python = u""724    for el in tree:725        if el[0] == "python":726            if el[1][0][:2] == "!!":727                python += el[1][0][2:-2]728            else:...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
