Functions/Get-VirtualEnv.ps1

# ===========================================================================
# Get-VirtualEnv.ps1 ------------------------------------------------------
# ===========================================================================

# validaation -------------------------------------------------------------
# ---------------------------------------------------------------------------
Class ValidateVirtualEnv : System.Management.Automation.IValidateSetValuesGenerator {
    [String[]] GetValidValues() {
        return [String[]] (Get-VirtualEnv | Select-Object -ExpandProperty Name)
    }
}

# function ----------------------------------------------------------------
# ---------------------------------------------------------------------------
function Get-VirtualEnv {

    <#
    .SYNOPSIS
        List all existing virtual environments in predefined directory.
 
    .DESCRIPTION
        Return all existing virtual environments in predefined virtual environment directory as PSObject with version number. All available virtual environments can be accessed by autocompletion.
 
    .PARAMETER Name
 
    .PARAMETER Python
 
    .EXAMPLE
        PS C:\> Get-VirtualEnv
 
        Name Version
        ---- -------
        venv 3.7.3
 
        -----------
        Description
        Return all existing virtual environments in predefined directory. Flags 'Full' and 'Unformatted' does not have any implications if merely virtual environments are queried.
 
 
    .EXAMPLE
        PS C:\> ls-venv
 
        Name Version
        ---- -------
        venv 3.7.3
 
         Return all existing virtual environments in predefined directory with predefined alias.
 
    .EXAMPLE
        PS C:\> Get-VirtualEnv -Name venv
 
        Name Version Latest
        ---- ------- ------
        Click 7.0
        pip 19.2.3
        setuptools 41.2.0
        wheel 0.33.6
 
        -----------
        Description
        Return information about all independent packages installed in the specified virtual environment 'venv' and shows potentially newer versions. Flags 'Full' lists additionally all packages of the virtual environment, and "Unformatted' does not pipe results to cmdlet 'Format-Table'.
 
    .EXAMPLE
        PS C:\> Get-VirtualEnv -Python
 
        Name Version Latest
        ---- ------- ------
        pip 19.2.3
        setuptools 41.2.0
        virtualenv 16.6.1
 
        -----------
        Description
        RReturn information about all independent packages installed in the default python distribution. Flags 'Full' lists additionally all packages of the virtual environment, and "Unformatted' does not pipe results to cmdlet 'Format-Table'.
 
    .INPUTS
        System.Strings. Name of existing virtual environment.
 
    .OUTPUTS
        PSCustomObject. Object with contain information about all virtual environments.
 
    .NOTES
    #>


    [CmdletBinding(PositionalBinding=$True)]

    [OutputType([PSCustomObject])]

    Param (
        [ValidateSet([ValidateVirtualEnv])]
        [Parameter(Position=1, ValueFromPipeline=$True, HelpMessage="Information about all packages installed in the specified virtual environment will be returned.")]
        [System.String] $Name,

        [Parameter(HelpMessage="If switch 'Python' is true, information about all packages installed in the default python distribution will be returned.")]
        [Switch] $Python,

        [Parameter(HelpMessage="Return information about required packages.")]
        [Switch] $Full,

        [Parameter(HelpMessage="Return information not as readable table with additional details.")]
        [Switch] $Unformatted
    )

    Process {

        # return information about python distribution
        if ($Python) {
            return $(Get-VirtualEnvPackage -Python $PSVirtualEnv.Python -full:$Full -Unformatted:$Unformatted)
        }
        
        # return information about specified virtual distribution
        if ($Name) {                     
            # check whether the specified virtual environment exists
            if (-not $(Test-VirtualEnv -Name $Name -Verbose)){
                Get-VirtualEnv
                return $Null
            }

            return $(Get-VirtualEnvPackage -Python $(Get-VirtualPython -Name $Name) -full:$Full -Unformatted:$Unformatted)
        }

        # return information about all virtual environments in the predefined directory are gathered
        if (-not $Name -and -not $Python) {
            # get all virtual environment directories in predefined directory as well as the local directories and requirement files
            $virtualEnvSubDirs = Get-ChildItem -Path $PSVirtualEnv.WorkDir | Select-Object -ExpandProperty Name

            $virtualEnvs = $Null

            # call the python distribution of each virtual environnment and determine the version number
            if ($VirtualEnvSubDirs.length) {
                $virtualEnvs= $VirtualEnvSubDirs | ForEach-Object {
                    if (Test-VirtualEnv -Name $_) {
                         # set environment variable, get name of virtual environment and python version and set the pythonhome variable in scope process to the stored backup variable
                        Set-VirtualEnvSystem -Name $_
                        $python_venv = Get-VirtualPython -Name $_
                        [PSCustomObject]@{
                            Name = $_
                            Version = (((. $python_venv --version 2>&1) -replace "`r|`n","") -split " ")[1]
                        }
                        Restore-VirtualEnvSystem
                    }
                }

                return $virtualEnvs
            } 
            else {
                Write-FormattedError -Message "In predefined directory do not exist any virtual environments" -Module $PSVirtualEnv.Name -Space 
            }
        }

    }
}

# function ----------------------------------------------------------------
# ---------------------------------------------------------------------------
function Get-VirtualEnvPackage {

    <#
    .DESCRIPTION
        Gets the properties of all packages in a python environment.
     
    .PARAMETER Python
     
    .OUTPUTS
        PSCustomObject. Properties of all packages in a python environment
    #>


    [CmdletBinding(PositionalBinding=$True)]

    [OutputType([PSCustomObject])]

    Param (
        [Parameter(Position=1, Mandatory=$True, ValueFromPipeline=$True, HelpMessage="Executable of system's python distribution or of a virtual environment.")]
        [System.String] $Python,

        [Parameter(HelpMessage="Return information about required packages.")]
        [Switch] $Full,

        [Parameter(HelpMessage="Return information not as readable table with additional details.")]
        [Switch] $Unformatted
    )

    Set-VirtualEnvSystem -Python $Python

    # get all packages in the specified virtual environment, get all outdated packages and get all independent packages
    $venv_package = . $Python -m pip list --format json | ConvertFrom-Json 
    $venv_outdated = . $Python -m pip list --format json --outdated | ConvertFrom-Json 
    $venv_independent = . $Python -m pip list --format json --not-required | ConvertFrom-Json 

    # combine all gathered properties about the packages in the specified virtual environment
    $venv_package = $venv_package | ForEach-Object{
        $package = $_
        $package_outdated = $venv_outdated | Where-Object {$_.Name -eq $package.Name}
        $package_independent = $venv_independent | Where-Object {$_.Name -eq $Package.Name}

        [PSCustomObject]@{
            Name = $package.Name
            Version = $package.Version
            Latest = $package_outdated.Latest
            Required = if ( $package_independent ) {$Null} else {$True}

        }
    } 

    # return all packages which are independent from others in a separated table
    $result = $venv_package
    # | Format-Table -Property Name, Version, Latest
    $result = $venv_package | Where-Object {-not $_.Required} 

    if ($Full) {
    $requires_dict = @{}
    $result | ForEach-Object{
        $package = $_.Name
        $result_info = . $Python -m pip show $package
        $result_info | ForEach-Object{
                $result_requires = $_ -Split "^Requires: "
                if ($result_requires.Length -gt 1){
                    foreach($required_package in ($result_requires[1] -Split ", ")){
                        $requires_dict[$required_package] = $package
                    }
                }
            }
        }
   
    Restore-VirtualEnvSystem
   
    $result_required = $venv_package | Where-Object {$_.Required} 
    $result_required | ForEach-Object {
            if ($requires_dict.ContainsKey($_.Name)) {
                $_ | Add-Member -MemberType NoteProperty -Name "Required-by" -Value $requires_dict[$_.Name]
            }
        }
    }
    
    if ($Unformatted){
        return $result,  $result_required
    }
    else {
        return  ($result | Format-Table -Property Name, Version, Latest), ($result_required | Format-Table -Property Name, Version, Required-by, Latest)
    }
}