pip卸载所有包_pip导出包

pip卸载所有包_pip导出包pip批量完全卸载包

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

创作背景

因为我本机环境中安装的第三方库太多了,所以今天我准备把它们都卸载了,但因为太多了,所以不可能手动一个一个来,于是我便写了个小脚本,本文就记录这个脚本的作用及使用。

如果觉得我这篇文章写的好的话,能不能给我 点个赞评论收藏 一条龙(☆▽☆)。如果要点个 关注 的话也不是不可以?。

请各位参加一下文末的 投票 哦,如果 有什么不足之处,还 请各位大佬在评论区提出,不胜感激。

问题分析

要实现上述功能,我们需要解决以下问题:

  1. 获取所有已安装的包
  2. 获取每个包的依赖
  3. 命令行交互,卸载指定包

解决方法

上述三个问题均可以使用 subprocess.Popen 包进行解决。为了方便,第三问题使用 subprocess.run 解决。
网上已经有好多文章都对 subprocess.Popensubprocess.run 的参数进行解释,这里不多赘述。
对于 subprocess.Popen ,除了要执行的命令外,我只设置了 stdinstdoutstderr 参数。
对于subprocess.run ,除了要执行的命令外,我只设置了如下参数:

  • universal_newlines ,设置输入输出的数据类型,True 为字符串,否则为字节串。
  • capture_output ,设置是否显示命令执行结果,True 显示,否则不显示。
  • input ,这个是关键,使得代码可以与命令行进行交互,即指定命令后,在命令行输入内容执行。在本文中的作用是执行 pip uninstall 【包名】 后输入 y 进行确定。

代码详解

首先导入所需的库:resubprocess
然后将卸载一个包的代码封装成一个函数,如下(本菜鸡代码水平不足,还请各位大佬指出问题):

def uninstall_completely(name):
    # 必备的或不需要卸载的库,可以自行设置
    skips = ['pip', 'urllib3', 'setuptools', 'wheel']
    if name in skips or name.startswith('-'):
        return
        
    print(f'Start to uninstall { 
     name}')
    
    # 初始化 Popen,读取命令 pip show 【包名】 的执行结果
    pipe = subprocess.Popen(f'pip show { 
     name}', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    
    # 如果没有安装该包,则退出
    if b'WARNING: Package(s) not found: ' in pipe.stderr.read():
        print(f'An error occurred when uninstalling { 
     name}: { 
     name} 不存在\n')
        return
        
    # 正则匹配获得所有依赖包名
    # stdout.read() 的结果是字节串,需要转换为字符串
    requirements = ''.join(re.findall('Requires: (.*?)\r\n', pipe.stdout.read().decode()))
    print(f"{ 
     name}'s requirements: { 
     requirements}")
    
    # 关闭命令行
    pipe.terminate()
    
    # 卸载指定包
    try:
        # 执行命令 pip uninstall 【包名】
        # 执行命令后需要输入是否卸载 [y/n],因为要卸载,所以指定 input 参数为 'y'
        obj = subprocess.run(f'pip uninstall { 
     name}', universal_newlines=True, capture_output=True, input='y')
        
        # 如果出错,则输出报错原因
        if not obj.stderr == '':
            print(obj.stderr)
            return
        # 否则卸载成功
        else:
            print(f'Uninstall { 
     name} successfully.')
            
    # 防止中途报错导致程序停止运行
    except Exception as e:
        print(f'An error occurred when uninstalling { 
     name}: { 
     e}')
    
    # 输出结果分隔
    print('-------------------------------------------')
    
    # 卸载指定包的所有依赖包,递归调用本函数
    for _ in requirements.split(', '):
        if r == '':
            continue
        uninstall_completely(_)

调用函数代码如下:

for line in subprocess.Popen('pip list', stdout=subprocess.PIPE).stdout.read().decode().split('\n')[2:]:
    name = line.split(' ')[0]
    if name == '':
        continue
    uninstall_completely(name)

其中:

  • pip list 可以查看当前安装的所有包。
  • .decode() 是因为 stdout.read() 的结果是字节串,需要将其转为字符串。
  • [2:] 去除如下图所示的无用行
    在这里插入图片描述
    如果只卸载单个包的话,直接调用函数。
    如果卸载部分包的话,遍历列表并分别调用函数。

改 BUG

写代码的时候 BUG 并不少见,但这次挺少的。出错的原因是读取执行结果时编码错误导致。
具体过程为 run 函数中调用 Popen.communicate() 函数,如下:

with Popen(*popenargs, **kwargs) as process:
    try:
        stdout, stderr = process.communicate(input, timeout=timeout)
    except TimeoutExpired as exc:
        process.kill()

然后调用 Popen._communicate() 函数,如下:

try:
    stdout, stderr = self._communicate(input, endtime, timeout)
except KeyboardInterrupt:
    ...

又调用 Popen._readerthread() 函数,如下:

self.stdout_thread = threading.Thread(target=self._readerthread, 
                                      args=(self.stdout, self._stdout_buff))

看一下 Popen._readerthread() ,如下:

def _readerthread(self, fh, buffer):
    buffer.append(fh.read())
    fh.close()

此时会从 Popen.stdout 中读取命令执行结果。

再看一下 Popen.stdout 的初始化代码,如下:

self.text_mode = encoding or errors or text or universal_newlines
...
self.stdout = io.open(c2pread, 'rb', bufsize)
if self.text_mode:
    self.stdout = io.TextIOWrapper(self.stdout, encoding=encoding, errors=errors)

此时就明了了,如果指定了 encodingerrorstextuniversal_newlines 中任意一个或多个参数,就意味着输出的结果是 字符串 ,而如果没有指定 encoding 参数的话,默认是使用 gbk 编码,如果和环境中的编码方式不一致的话会导致编码报错。

那我们可以修改一下 Popen 的源码,在 subprocess 中第 767self.text_mode 的定义下一行加入如下代码:

if self.text_mode and encoding is None:
    encoding = sys.getdefaultencoding()

如果要将字节串转为字符串并且没有指定编码格式的话,就使用环境默认编码。




结尾

有想要一起学习 python 的小伙伴可以 私信我 进群哦。

以上就是我要分享的内容,因为 学识尚浅会有不足,还 请各位大佬指正
有什么问题也可在评论区留言。
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181096.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • linux收发邮件_python邮件发送

    linux收发邮件_python邮件发送linux邮件传输一般用在特定的网络环境下,记住,只要有网络,就能办事;闲话少扯,直接上干货:步骤1邮箱设置开启STMP服务,开启后会收到STMP授权码。多种邮箱都有这个功能,申请后把你的授权码记住了。步骤2linux命令:/etc/mail.rc配置邮件发送参数将以下数据加到最下面(如下图):#邮箱setfrom=843903492@qq.com#默…

    2022年10月20日
  • linux(10)linux vi/vim

    linux(10)linux vi/vim前言所有的UnixLike系统都会内建vi文书编辑器,其他的文书编辑器则不一定会存在。但是目前我们使用比较多的是vim编辑器。vim具有程序编辑的能力,可以主动的以字体颜色辨别语法的

  • supermemo怎么用_mono效果器板

    supermemo怎么用_mono效果器板Supermemo是个不错的背单词的软件(本人并不代理该软件,并非给它做广告),但实际上它可以用来记忆其它的材料。这个软件写得非常早,1992与就有DOS版本,可使用习惯与微软常见软件的风格很不一样,

  • 漏洞扫描和渗透性测试_漏洞扫描软件有哪些

    漏洞扫描和渗透性测试_漏洞扫描软件有哪些目录1.nessus2.AWVS3.WPscan1.nessus1.Nessus软件是什么?如图,我们可以从百度百科得知:Nessus是全世界最多人使用的系统漏洞扫描与分析软件。总共有超过75,000个机构使用Nessus作为扫描该机构电脑系统的软件。2.Nessus软件的安装1.下载地址DownloadNessus|Tenable®https://www.tenable.com/downloads/nessus如图所示,这个是下载官网。我们以..

  • 并发与并行的区别_并发执行和并行执行

    并发与并行的区别_并发执行和并行执行学习多线程的时候会遇到一个名词:并发。这是属于操作系统中的词汇,需要了解并发和并行的区别,从网上搜集了几种说法帮助理解。一:并发是指一个处理器同时处理多个任务。并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。并发是逻辑上的同时发生(simultaneous),而并行是物理上的同时发生。来个比喻:并发是一个人同时吃三个馒头,而并行是三个人同时吃三个馒头。二:并行

    2022年10月23日
  • 手机来电通核心模块——归属地数据库设计(Winsym原创)「建议收藏」

    手机来电通核心模块——归属地数据库设计(Winsym原创)「建议收藏」说到Symbian,确实让人头痛。不仅开发平台和SDK版本众多,难以选择,而且对程序员确实要求很高,光是SymbianC++的熟悉就要花上很长时间,更麻烦的是测试和调试。模拟器只能提供一部分功能,和电话通信有关的全部要在真机上测试。很多时候,在模拟器上能跑的代码,放到真机上就不行了,这其中的心酸想必开发过得朋友深有体会。小弟我因为工程实践项目的要求,和几位嵌入式的高手一起搞了Symbian来电通项目。其实来电通项目已经有很多人做了,比较有名的是CallMaster和柳丁,但是这方面的关键技术和源码至今没有

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号