Я решил проблему через сторонний скрипт, взятый отсюда.
Привожу код скрипта здесь:
#!/bin/bash
PSS_DIR=~/.local/share/pypi-simple-search
export PKG_DIR="${PSS_DIR}/pkg"
export PSS_CACHE=${PSS_DIR}/simple.txt
curl_pypi() {
echo "Updating cache of PyPi packages"
curl -s https://pypi.org/simple/ > "${PSS_CACHE}.tmp"
# Remove header text
tail -n +7 "${PSS_CACHE}.tmp" > "$PSS_CACHE" && rm "${PSS_CACHE}.tmp"
# Remove html tags and whitespace
perl -pi -e 's/[\t ]+|<.+?>//g' "$PSS_CACHE"
}
print_help() {
echo "pypi-simple-search: a stop-gap replacement for \"pip search\""
echo " Usage:"
echo " $0 [-hum] [query]"
echo " Options:"
echo " -h show this menu"
echo " -u update cache of pypi packages"
echo " -m display package descriptions from metadata"
echo " Arguments:"
echo " query package name to search"
echo " Environment:"
echo " \$PYPI_SIMPLE_SEARCH search command to use, defaults to \"grep\""
}
update=0
metadata=0
OPTIND=1 # Reset in case getopts has been used previously in the shell
while getopts "h?um" opt; do
case "$opt" in
h|\?)
print_help
exit 0
;;
u)
# Update the pypi package cache
update=1
;;
m)
# Prepare directory to cache JSON metadata
mkdir -p "$PKG_DIR"
metadata=1
;;
esac
done
shift $((OPTIND-1))
[ "${1:-}" = "--" ] && shift
# Export global variables because xargs calls a bash subprocess
export update
export PLATFORM=$(uname)
export NOW=$(date +%s)
# Thanks to @lfom for the Linux portability fix
case "${PLATFORM}" in
Darwin* | FreeBSD*)
_stat_time_mod() {
stat -f%c "$1"
};
_xargs_parallel() {
xargs -P 4 "$@"
}
;;
Linux* | CYGWIN*)
_stat_time_mod() {
stat -c%Y "$1"
};
_xargs_parallel() {
xargs -P 0 "$@"
}
;;
*)
echo "Sorry, unsuported or unknown system: $(uname)!"
echo "Please submit an issue here: https://github.com/jeffmm/pypi-simple-search/issues"
exit
esac
# Export global functions
export -f _stat_time_mod
export -f _xargs_parallel
if [ ! -d "$PSS_DIR" ]; then
mkdir -p "$PSS_DIR"
curl_pypi
elif [ ! -f "$PSS_CACHE" ]; then
curl_pypi
fi
get_age() {
set -u
local file="$1"
local cache_time=$(_stat_time_mod "$file")
local elapsed_time=$(( ${NOW} - ${cache_time} ))
printf "%d" $elapsed_time
}
json_missing() {
# $1 package name
# $2 package cache .json file path
set -u
echo "json_missing($1 $2)" >> log
TMP_JSON=$(cat <<- EOF
{
"info": {
"description": "** EMPTY PACKAGE **<br><br>This package never released any files",
"description_content_type": "text/markdown",
"license": "Unknown",
"name": "$1",
"summary": "** $1 has no released files",
"version": "?.?.?"
}
}
EOF
)
echo "$(echo ${TMP_JSON})" > $2
}
json_pypi() {
set -u
local pkg="$1"
local pkg_cache="${PKG_DIR}/${pkg}.json"
# Get JSON metadata and cache it
# https://warehouse.pypa.io/api-reference/json.html
if [ $update -eq 1 ] || [ ! -f "${pkg_cache}" ] || [ $(get_age "${pkg_cache}") -gt 604800 ]; then
(
set -eu
curl -L --silent --fail "https://pypi.org/pypi/${pkg}/json" -o "${pkg_cache}"
)
fi
if [ ! -f ${pkg_cache} ]; then
printf "$(json_missing ${pkg} ${pkg_cache})"
echo "$(json_missing ${pkg} ${pkg_cache})" >> log
fi
printf "%s " "${pkg_cache}"
}
export -f get_age
export -f json_pypi
export -f json_missing
if [ $(get_age "${PSS_CACHE}") -gt 604800 ]; then
# Update automatically if the cache is over 1 week old
echo "It's been over a week since the package cache was updated"
curl_pypi
fi
# Allow just updating the cache ie: $0 -u
if [ $update -eq 1 ]; then
curl_pypi
fi
# If the user sets their own search preference (e.g. ag, rg, etc), use it
# Otherwise just use grep, because it's universal
: "${PYPI_SIMPLE_SEARCH:=grep}"
search_pypi() {
"$PYPI_SIMPLE_SEARCH" "$1" "$PSS_CACHE"
}
if [ -n "$1" ]; then
if [ $metadata -eq 0 ]; then
search_pypi "$1"
else
# Loop over packages, get JSON metadata and display as a table
search_pypi "$1" \
| _xargs_parallel -I {} bash -c "json_pypi '{}'" \
| xargs jq -r '[.info.name, .info.version, .info.summary] | @tsv' \
| column -t -s $'\t' \
| sort
fi
elif [ $update -eq 0 ]; then
# If no arg given and we are not updating the cache, educate the user
print_help
exit 1
fi
Дальнейший порядок действий
Для поиска нужного модуля поступаем так:
Сохраняем скрипт с каким нибудь именем, например pypi-simple-search.sh
Не забываем сделать файл выполняемым:
chmod +x pypi-simple-search.sh
Теперь ищем нужный нам модуль:
./pypi-simple-search.sh ^jira$
На всякий случай поясню что "^" означает начало строки, а "$" - конец (что бы найти именно искомое ключевое слово, а не Myjira2, Yourjira3, и так далее)
У меня получилось найти этот Jira модуль
% ./pypi-simple-search.sh ^jira$
jira
Далее, просто добавляем его через pip3:
% pip3 install jira
.....
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests, pyparsing, oauthlib, typing-extensions, requests-toolbelt, requests-oauthlib, packaging, defusedxml, jira
.....
Successfully installed certifi-2022.9.24 charset-normalizer-2.1.1 defusedxml-0.7.1 idna-3.4 jira-3.4.1 oauthlib-3.2.2 packaging-21.3 pyparsing-3.0.9 requests-2.28.1 requests-oauthlib-1.3.1 requests-toolbelt-0.10.1 typing-extensions-4.4.0 urllib3-1.26.12
После этого запускаем python3 и убеждаемся что искомый модуль доступен:
% python3
Python 3.9.6 (default, Aug 5 2022, 15:21:02)
[Clang 14.0.0 (clang-1400.0.29.102)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import jira