Skip to content

Instantly share code, notes, and snippets.

@blakedrumm
Last active November 13, 2024 03:37
Show Gist options
  • Save blakedrumm/172d017ab6406f44af1f8dd6d140162a to your computer and use it in GitHub Desktop.
Save blakedrumm/172d017ab6406f44af1f8dd6d140162a to your computer and use it in GitHub Desktop.
Fetch and display PyPI dependencies for a specified Python module and version in a formatted table.
<#
.SYNOPSIS
This script retrieves dependency information for specified Python modules and versions from PyPI.
.DESCRIPTION
The `Get-PythonModuleDependencies` function fetches dependency details for multiple specified Python modules and versions by accessing the PyPI JSON metadata. The dependencies, if any, are displayed in a structured table format, showing the module name, operator, version, and any conditions. Additionally, the script outputs information about each main module and version being checked, along with URLs for the PyPI project and JSON metadata.
.PARAMETER ModuleNames
An array of Python module names to check for dependencies.
.PARAMETER ModuleVersions
An array of corresponding versions for each Python module. Must match the number of module names.
.EXAMPLE
# Retrieve dependencies for a specific module and version
Get-PythonModuleDependencies -ModuleNames "azure-storage-blob" -ModuleVersions "12.22.0"
.EXAMPLE
# Retrieve dependencies for multiple modules and versions
Get-PythonModuleDependencies -ModuleNames "azure-storage-blob", "requests" -ModuleVersions "12.22.0", "2.26.0"
.NOTES
Author: Blake Drumm ([email protected])
Creation Date: November 12th, 2024
License: MIT License
This script utilizes the PyPI JSON API to retrieve module information and requires internet access to function.
=================================================
Example output
=================================================
Dependency list for Python Module:
======================================================================
Python module name : azure-storage-blob
Python module version : 12.22.0
Python module release : November 12th, 2024 @ 12:00 PM (EST)
Python PyPi Project URL: https://pypi.org/project/azure-storage-blob/12.22.0
Python PyPi Json URL : https://pypi.org/pypi/azure-storage-blob/12.22.0/json
======================================================================
Module Operator Version Condition
------ -------- ------- ---------
azure-core >= (Greater than or equal to) 1.28.0
cryptography >= (Greater than or equal to) 2.1.4
typing-extensions >= (Greater than or equal to) 4.6.0
isodate >= (Greater than or equal to) 0.6.1
azure-core[aio] >= (Greater than or equal to) 1.28.0 extra == "aio"
--------------------------------------------------------------------------------
Copyright (c) Microsoft Corporation. MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
.LINK
https://pypi.org
#>
[CmdletBinding()]
param
(
[Parameter(Mandatory = $false)]
[Alias('Name', 'Names')]
[string[]]$ModuleNames,
[Parameter(Mandatory = $false)]
[Alias('Version', 'Versions')]
[string[]]$ModuleVersions
)
BEGIN
{
Write-Verbose "Script Starting @ $(Get-Date)"
function Get-PythonModuleDependencies
{
param
(
[Parameter(Mandatory = $true)]
[Alias('Name', 'Names')]
[string[]]$ModuleNames,
[Parameter(Mandatory = $true)]
[Alias('Version', 'Versions')]
[string[]]$ModuleVersions
)
# Ensure the ModuleNames and ModuleVersions arrays have the same length
if ($ModuleNames.Count -ne $ModuleVersions.Count)
{
Write-Output "Error: The number of module names must match the number of module versions."
return
}
# Loop through each module/version pair
for ($i = 0; $i -lt $ModuleNames.Count; $i++)
{
$ModuleName = $ModuleNames[$i]
$ModuleVersion = $ModuleVersions[$i]
# Construct the URL to fetch the JSON data
$url = "https://pypi.org/pypi/$ModuleName/$ModuleVersion/json"
Write-Verbose "Fetching data from: $url"
try
{
# Fetch the JSON data from PyPI
$response = Invoke-RestMethod -Uri $url -Method Get -ErrorAction Stop
Write-Verbose "Data fetched successfully."
# Extract release date if available
$releaseDate = if ($response.urls[0].upload_time) { $response.urls[0].upload_time }
else { "Unknown" }
# Format the release date in the specified format
if ($releaseDate -ne "Unknown")
{
$TodaysDate = [datetime]::Parse($releaseDate).ToUniversalTime()
# Format the date components for "November 12th, 2024 @ 12:00 PM (EST)"
$daySuffix = switch ($TodaysDate.Day)
{
1 { "st" }
21 { "st" }
31 { "st" }
2 { "nd" }
22 { "nd" }
3 { "rd" }
23 { "rd" }
default { "th" }
}
$monthName = $TodaysDate.ToString("MMMM")
$day = $TodaysDate.Day
$year = $TodaysDate.Year
$hour = $TodaysDate.ToString("hh") # 12-hour format with leading zero
$minute = $TodaysDate.ToString("mm") # Pad minute with leading zero
$amPm = $TodaysDate.ToString("tt") # AM/PM
$timeZone = [System.TimeZoneInfo]::Local.StandardName
$releaseDateFormatted = "$monthName $day$daySuffix, $year @ $hour`:$minute $amPm ($timeZone)"
}
else
{
$releaseDateFormatted = "Unknown"
}
# Check if info and requires_dist exist
if ($response -and $response.info -and $response.info.requires_dist)
{
Write-Verbose "'requires_dist' found with dependencies."
# Define a mapping of operators to full descriptions
$operatorDescriptions = @{
">=" = "Greater than or equal to"
"<=" = "Less than or equal to"
">" = "Greater than"
"<" = "Less than"
"==" = "Equal to"
"!=" = "Not equal to"
"~=" = "Compatible with"
}
# Process dependencies, handling conditions and extras
$dependencies = @()
foreach ($requirement in $response.info.requires_dist)
{
if ($requirement -match '^(?<Module>[\w\.\-\[\]]+)\s*(?<Operator>>=|<=|>|<|==|!=|~=)?\s*(?<Version>[\d\.]*)\s*(;(?<Condition>.*))?$')
{
$formattedOperator = if ($matches['Operator']) { "$($matches['Operator']) ($($operatorDescriptions[$matches['Operator']]))" }
else { "" }
$dependencies += [PSCustomObject]@{
Module = if ($matches['Module']) { $matches['Module'].Trim() } else { "Unknown" }
Operator = $formattedOperator
Version = if ($matches['Version']) { $matches['Version'].Trim() } else { "" }
Condition = if ($matches['Condition']) { $matches['Condition'].Trim() } else { "" }
}
}
}
Write-Output "Dependency list for Python Module:`n`r"
# Display module name, version, and release date with a box around it
$boxLine = "=" * 70
Write-Output $boxLine
Write-Output "Python module name : $ModuleName"
Write-Output "Python module version : $ModuleVersion"
Write-Output "Python module release : $releaseDateFormatted"
Write-Output "Python PyPi Project URL: $($url.Replace('/pypi/', '/project/').Replace('/json', ''))"
Write-Output "Python PyPi Json URL : $url"
Write-Output $boxLine
Write-Output ""
# Display dependencies in a table format
if ($dependencies.Count -gt 0)
{
($dependencies | Format-Table -AutoSize | Out-String -Width 2048).Trim()
}
else
{
Write-Output "No dependencies parsed successfully."
}
}
else
{
Write-Output "'requires_dist' is either missing or empty."
}
}
catch
{
Write-Output "Error retrieving information for $ModuleName $ModuleVersion`: $_"
}
# Add a separator line between modules if there are multiple
if ($i -lt ($ModuleNames.Count - 1))
{
Write-Output "`n" + ("-" * 70) + "`n"
}
}
}
}
PROCESS
{
if ($ModuleNames -and $ModuleVersions)
{
Get-PythonModuleDependencies -ModuleNames $ModuleNames -ModuleVersions $ModuleVersions
}
else
{
# Modify the line below to change what happens when the script is ran without any parameters. This is useful when running from PowerShell ISE.
Get-PythonModuleDependencies
# =================================================
# Example usage
# =================================================
# Get-PythonModuleDependencies -ModuleNames "azure-storage-blob" -ModuleVersions "12.22.0"
# To check multiple Python Modules:
# Get-PythonModuleDependencies -ModuleNames "azure-storage-blob", "requests" -ModuleVersions "12.22.0", "2.26.0"
}
}
END
{
Write-Verbose "Script Completed @ $(Get-Date)"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment