Last active
November 13, 2024 03:37
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.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