草庐IT

python - 检查包是否从源代码树中导入

coder 2023-08-18 原文

用户应该通过 pip 安装我们的 python 包,或者它可以从 github 存储库中克隆并从源代码安装。出于多种原因,用户不应从源代码树目录中运行 import Foo,例如缺少 C 扩展(numpy 有同样的问题:read here)。因此,我们想检查用户是否正在从源代码树中运行 import Foo,但是如何在支持 Python 3 和 2 的情况下干净、高效、稳健地执行此操作?

编辑:请注意,此处的源代码树也被定义为下载代码的位置(例如,通过 git 或从源存档),它与安装代码的安装目录形成对比。

我们考虑了以下几点:

  • 检查 setup.py 或其他文件,如 PKG-INFO,它们应该只出现在源代码中。这不是那么优雅,检查文件是否存在也不是很便宜,因为每次有人 import Foo 时都会进行此检查。此外,也没有什么可以阻止某人将 setup.py 放在他们的 lib/python3.X/site-packages/ 目录或类似目录中的源代码树之外。
  • 解析 setup.py 的内容以获得包名,但它也增加了开销并且解析起来不是那么干净。
  • 创建一个仅存在于源代码树中的虚拟标志文件。
  • 一些聪明但可能过于复杂且容易出错的想法,例如在安装期间修改 Foo/__init__.py 以注意我们现在位于源代码树之外。

最佳答案

由于您在评论中提到了 numpy 并且想像他们那样做但又不完全理解它,所以我想我会分解它并看看您是否可以实现类似的过程。


__init__.py

您正在寻找的错误开始here这是您在评论和答案中链接到的内容,因此您已经知道了。它只是尝试导入 __config__.py,如果它不存在或无法导入,则会失败。

    try:
        from numpy.__config__ import show as show_config
    except ImportError:
        msg = """Error importing numpy: you should not try to import numpy from
        its source directory; please exit the numpy source tree, and relaunch
        your python interpreter from there."""
        raise ImportError(msg)

那么 __config__.py 文件从何而来,这有什么帮助?下面就让我们跟随...

setup.py

当包被安装时,setup 被调用来运行,它反过来做一些 configuration actions .这实质上是确保包正确安装而不是从下载目录运行的原因(我认为这是您想要确保的)。

这里的关键是这一行:

config.make_config_py() # installs __config__.py

misc_util.py

那是从distutils/misc_util.py导入的我们可以一直跟踪到 here .

    def make_config_py(self,name='__config__'):
        """Generate package __config__.py file containing system_info
        information used during building the package.
        This file is installed to the
        package installation directory.
        """
        self.py_modules.append((self.name, name, generate_config_py))

然后正在运行here它在 __config__.py 文件中写入了一些系统信息和你的 show() 函数。


总结
尝试导入 __config__.py 并失败,如果未运行 setup.py 会生成您想要引发的错误,这就是触发该文件的原因正确创建。这不仅确保了文件检查正在进行,而且该文件仅存在于安装目录中。在每次导入时导入一个额外的文件仍然会产生一些开销,但无论您做什么,都会增加一些开销,首先要进行此检查。


建议

我认为您可以实现 numpy 正在做的事情的更轻量级版本,同时完成同样的事情。

删除 distutils 子函数并在 setup.py 文件中创建已检查的文件作为标准安装的一部分。它只会在安装后存在于已安装的目录中,而不会存在于其他地方,除非用户伪造了它(在这种情况下,他们可能会绕过你尝试的任何东西)。

作为替代方案(不知道你的应用程序和你的安装文件在做什么)可能你有一个通常导入的函数,它不是应用程序运行的关键但很好用(在 numpy 的情况下,函数是有关安装的信息,如 version()。不是将这些函数保留在您现在放置它们的位置,而是将它们作为创建的文件的一部分。然后你至少加载了一些你无论如何都会从其他地方加载的东西。

使用这种方法,您无论如何都会导入一些东西,这会产生一些开销,或者引发错误。我认为就引发错误的方法而言,因为它们不在安装目录之外工作,这是一种非常干净和直接的方法。无论您使用哪种方法,使用该方法都会产生一些开销,因此我会专注于保持开销低、简单,并且不会导致错误。

我不会做一些复杂的事情,比如解析安装文件或修改必要的文件,比如某处的 __init__.py。我认为您是对的,这些方法更容易出错。

检查 setup.py 是否存在可以工作,但我认为它不如尝试 import 干净,后者已经作为标准 Python 函数进行了优化。他们完成了类似的事情,但我认为实现 numpy 风格会更加直接。

关于python - 检查包是否从源代码树中导入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55900956/

有关python - 检查包是否从源代码树中导入的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  5. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  6. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  7. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  8. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  9. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  10. ruby - 检查日期是否在过去 7 天内 - 2

    我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/

随机推荐