【问题标题】:python conflicts in two external packages两个外部包中的python冲突
【发布时间】:2012-08-09 20:18:41
【问题描述】:

我正在编写代码来组合 python rawdog RSS 阅读器库和 BeautifulSoup 网络抓取库中的函数。我正在努力克服内心的某个地方的冲突。

我可以用这个简化的代码复制这个问题:

    import sys, gzip
    def scrape(filename):
        contents = gzip.open(filename,'rb').read()
        contents = contents.decode('utf-8','replace')
        import BeautifulSoup as BS
        print 'before rawdog: ', len(BS.BeautifulSoup(contents)) # prints 4, correct answer
        from rawdoglib import rawdog as rd
        print 'after rawdog: ', len(BS.BeautifulSoup(contents)) # prints 3, incorrect answer

无论我以什么顺序或在哪里进行导入,rawdog 的导入总是会导致 BS.BeautifulSoup() 方法返回错误的响应。当我需要 BeautifulSoup 时,我实际上不再需要 rawdog,所以我当时尝试删除包,但 BS 仍然坏了。我尝试过但无效的修复:

  • 我注意到 rawdog 代码自己导入 BeautifulSoup。所以我尝试从 rawdog 代码中删除 import BeautifulSoup 并重新安装 rawdog
  • 在导入 BeautifulSoup 之前删除 rawdog 模块:
    • for x in filter(lambda y: y.startswith('rawdog'), sys.modules.keys()): del sys.modules[x]
  • 从 rawdog 导入更具体的类/方法,例如from rawdoglib.rawdog import FeedState
  • 给问题方法一个新名字,在导入rawdog之前和之后:from BeautifulSoup import BeautifulSoup as BS
  • from __future__ import absolute_import

不走运,如果 rawdog 曾被导入命名空间,我总是得到 len(BeautifulSoup(contents)) == 3。这两个包都足够复杂,以至于我无法确切地弄清楚问题重叠是什么,而且我不确定使用什么工具来尝试解决这个问题,除了通过 dir(BeautifulSoup) 和 dir( rawdog),我还没有找到好的线索。

更新,回复答案: 我省略了每个输入文件都不会出现问题,这是至关重要的,抱歉。有问题的文件很大,所以我认为我不能在这里发布它们。我将尝试找出好文件和坏文件之间的关键区别并将其发布。感谢到目前为止的调试帮助。

进一步调试!我已将输入文本中的此块标识为有问题:

    function SwitchMenu(obj){
      if(document.getElementById){
      var el = document.getElementById(obj);
      var ar = document.getElementById("masterdiv").getElementsByTagName("span"); //DynamicDrive.com change
         if(el.style.display != "block"){ //DynamicDrive.com change
         for (var i=0; i<ar.length; i++){
            if (ar[i].className=="submenu") //DynamicDrive.com change
            ar[i].style.display = "none";
      }
      el.style.display = "block";
      }else{
        el.style.display = "none";
    }
}

}

如果我注释掉这个块,那么无论是否导入 rawdog,我都会通过 BeautifulSoup 获得正确的解析。使用该块,rawdog + BeautifulSoup 是错误的。那么我应该只在我的输入中搜索这样的块,还是有更好的解决方法?

【问题讨论】:

  • 这看起来很奇怪(对我来说),尽管我从未使用过这两个库。我想知道rawdoglib猴子补丁BeautifulSoup。我会尝试寻找rawdoglib 的来源,寻找BeautifulSoup 的导入,看看他们是否在这些模块中做了什么奇怪的事情。
  • 你能发布有问题的文件吗?因为如果我处理内容为&lt;a&gt;&lt;b&gt;&lt;c&gt;c&lt;/c&gt;&lt;/b&gt;&lt;/a&gt; 的文件,我会得到正确的结果,而rawdoglib 导入不会改变任何事情。
  • 我查看了 rawdog 源代码,它似乎只在一个地方导入 BeautifulSoup。删除并不能解决问题?您应该发布一个包含数据的最小示例。不要从用 UTF-8 解码的 gzip 压缩外部文件导入它,除非结果证明这是问题的一个组成部分。
  • “那么我应该在我的输入中搜索这样的块,还是有更好的解决方法?”但是你不知道触发问题的这个块是什么。那么谁知道还有哪些其他块也会触发它呢?现在你有了问题块,你可以将它嵌入到一个 short 文件中并创建一个独立的演示吗?如果无法重现问题,就很难解开这个问题......

标签: python packages conflict


【解决方案1】:

这是rawdoglib.feedparser.py 中的一个错误。 rawdog 是猴子补丁smglib: 第 198 行显示:

if sgmllib.endbracket.search(' <').start(0):
    class EndBracketMatch:
        endbracket = re.compile('''([^'"<>]|"[^"]*"(?=>|/|\s|\w+=)|'[^']*'(?=>|/|\s|\w+=))*(?=[<>])|.*?(?=[<>])''')
        def search(self,string,index=0):
            self.match = self.endbracket.match(string,index)
            if self.match: return self
        def start(self,n):
            return self.match.end(n)
    sgmllib.endbracket = EndBracketMatch()

这是重现错误的脚本:

contents = '''<a><ar "none";                                                 
</a> '''                                                                     
import BeautifulSoup as BS                                                   
print 'before rawdog: ', len(BS.BeautifulSoup(contents)) # prints 4, correct answer
from rawdoglib import rawdog as rd                                           
print 'after rawdog: ', len(BS.BeautifulSoup(contents)) # prints 3, incorrect

它在“a”标签内的“for (var i=0; i<ar.length; i++){(注意“

在 rawdog 的 ML 上提交的问题:http://lists.us-lot.org/pipermail/rawdog-users/2012-August/000327.html

【讨论】:

  • 不错的发现。一些经验教训:(1)monkey patching 几乎总是一个坏主意; (2) 包 A 可能与直接导入的包 B 不直接冲突,而是与它们都导入的包 C 冲突。
【解决方案2】:

我认为您遇到的问题是imports 链;您导入 BS 包的两个不同位置存在冲突。

This thread 可能就是你需要的。

(另外,BS package 在严肃的环境中是一件很棒的事情。)

【讨论】:

  • 由于从 rawdog 源中删除 import BeautifulSoup 后问题仍然存在,因此不可能是这样(除非有误报)。
  • 我更多的是暗示他应该尝试删除主文件中的 BeautifulSoup 导入,我不明白他已经这样做了。 IIRC Python 将允许您递归访问导入,因此它将运行 rawdog 中的 BeautifulSoup 导入。
  • import os; print sys.path 不起作用,即使 os 导入 sys
  • 我确实尝试省略 BeautifulSoup 的单独导入,通过 rawdog 以这种方式调用它:from rawdoglib import rawdog; BS= sys.modules['BeautifulSoup']; print len(BS.BeautifulSoup(contents)),这给了我以前的答案“3”。尽管我可以看出 rawdog 没有明确修补 BeautifulSoup,但还是有一些奇怪的交互。
  • @chown 您使用的是哪个版本的 Python?显然,此功能在 3.x 中被设置为非默认值。
【解决方案3】:

如果 rawdog 可以在不导入 BeautifulSoup 的情况下触发错误(我认为您已经检查过它不是间接导入的?),那么它们必须具有以某种方式加载不一致的共享依赖项。但问题不一定是猴子补丁:如果他们加载同一个库的不同版本,你可能会得到不一致的行为。例如,如果其中一个使用特殊的导入路径,提供自己的顶级模块版本,或者具有如下代码:

try: 
    import ElementPath 
except ImportError: 
    ElementPath = _SimpleElementPath()

要查看这是否是问题所在,请尝试以下操作:仅加载 BeautifulSoup,仅此而已,然后转储模块列表及其位置:

import BeautifulSoup
import sys
sys.stdout = open("soup-modules.txt", "w")
for k,v in sorted(sys.modules.items()):
    if v:
        print k, v.__dict__.get('__file__')

然后对 rawdog 执行相同的操作并区分输出。如果您看到一个名称相同但来源不同的模块,那可能是您的罪魁祸首。

【讨论】:

  • “共享依赖”是sgmllibrawdog 对它进行了严重的猴子补丁。见我的回复:stackoverflow.com/questions/11937081/…
  • 哈,干得好!如果我比我晚几分钟阅读这个问题,我本可以省去麻烦......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多