Показать статистику
0 голосов
от (4.6тыс. баллов)

Сегодня узнал что pip в Python больше не может искать пакеты. Разработчики отключили этот функционал в связи с "возросшей нагрузкой на инфраструктуру". При попытке что либо найти через pip получаем такое сообщение (в примере ниже я пытался доставить библиотеку для работы с Jira): 

# pip3 search Jira  
ERROR: XMLRPC request failed [code: -32500]
RuntimeError: PyPI's XMLRPC API is currently disabled due to unmanageable load and will be deprecated in the near future. See https://status.python.org/ for more information.

Как обойти данное ограничение? Похоже что pip может ставить модули, но поиск отключен.

386 просмотров 1 ответов

1 Ответ

0 голосов
от (17.4тыс. баллов)

Я решил проблему через сторонний скрипт, взятый отсюда

Привожу код скрипта здесь: 

#!/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
...