本文介绍了如何正确使用 Sublime Text 插件的 3rd 方依赖项?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为 Sublime Text 3 编写一个插件.

I'm trying to write a plugin for Sublime Text 3.

我必须在我的代码中使用几个第三方包.我设法通过手动将包复制到 /home/user/.config/sublime-text-3/Packages/User/ 来使代码工作,然后我使用相对导入来获得所需的代码.我将如何将插件分发给最终用户?告诉他们将所需的依赖项复制到适当的位置当然不是要走的路.3rd 方模块应该如何与 Sublime Text 插件一起正确使用?我在网上找不到任何文档;我所看到的只是将模块放在文件夹中的建议.

I have to use several third party packages in my code. I have managed to get the code working by manually copying the packages into /home/user/.config/sublime-text-3/Packages/User/, then I used relative imports to get to the needed code. How would I distribute the plugin to the end users? Telling them to copy the needed dependencies to the appropriate location is certainly not the way to go. How are 3rd party modules supposed to be used properly with Sublime Text plugins? I can't find any documentation online; all I see is the recommendation to put the modules in the folder.

推荐答案

Sublime 使用它自己的嵌入式 Python 解释器(目前是 Python 3.3.6,但下一版本也将支持 Python 3.8),因此它会完全忽略任何您的系统上可能已安装或未安装的 Python 版本,以及为该版本安装的任何库.

Sublime uses it's own embedded Python interpreter (currently Python 3.3.6 although the next version will also support Python 3.8 as well) and as such it will completely ignore any version of Python that you may or may not have installed on your system, as well as any libraries that are installed for that version.

因此,如果您想使用外部模块(以下称为dependencies),您需要做额外的工作.有多种方法可以实现这一点,每种方法都有自己的优缺点.

For that reason, if you want to use external modules (hereafter dependencies) you need to do extra work. There are a variety of ways to accomplish this, each with their own set of pros and cons.

以下列出了实现此目的的各种方法;所有这些都需要对模块在 Python 中的工作方式有一定的了解,以便了解正在发生的事情.总的来说,除了所涉及的路径之外,没有什么关于正在发挥作用的机制的崇高文本".

The following lists the various ways that you can achieve this; all of them require a bit of an understanding about how modules work in Python in order to understand what's going on. By and large except for the paths involved there's nothing too "Sublime Text" about the mechanisms at play.

注意:以下内容在本回答时准确无误.然而,包控制计划改变它与即将到来的依赖项的工作方式,这些依赖项可能会改变这方面的某些方面.

这与即将推出的支持当前包控制机制不支持的多个 Python 版本(以及它支持它们的方式)的 Sublime 版本有关.

This is related to the upcoming version of Sublime supporting multiple versions of Python (and the manner in which it supports them) which the current Package Control mechanism does not support.

目前尚不清楚更改是否会带来指定依赖项的新方法,或者是否仅更改依赖项安装方式的内部工作方式.然而,现有的机制可能会保持不变,而不仅仅是为了向后兼容.

It's unclear at the moment if the change will bring a new way to specify dependencies or if only the inner workings of how the dependencies are installed will change. The existing mechanism may remain in place regardless just for backwards compatibility, however.

从 Sublime 插件访问 Python dependency 的所有途径都涉及将其代码放在 Python 解释器将要查找的地方.这类似于标准 Python 的工作方式,除了检查的位置包含在 Sublime 用于存储配置的区域内(称为 Data 目录),而不是独立的 Python解释器,Python 在插件宿主中运行.

All roads to accessing a Python dependency from a Sublime plugin involve putting the code for it in a place where the Python interpreter is going to look for it. This is similar to how standard Python would do things, except that locations that are checked are contained within the area that Sublime uses to store your configuration (referred to as the Data directory) and instead of a standalone Python interpreter, Python is running in the plugin host.

从 3.0 版本(build 3143)开始,Sublime 将在数据目录中创建一个名为 Lib 的文件夹,并在其中创建一个基于 Python 版本名称的目录.如果您使用 Preferences >浏览 Packages 并上一级文件夹,您将看到 Lib,其中有一个名为例如的文件夹.python3.3(或者,如果您使用的是较新的版本,请使用 python33python38).

Since version 3.0 (build 3143), Sublime will create a folder named Lib in the data directory and inside of it a directory based on the name of the Python version. If you use Preferences > Browse Packages and go up one folder level, you'll see Lib, and inside of it a folder named e.g. python3.3 (or if you're using a newer build, python33 and python38).

默认情况下,这些目录直接位于 Python sys.path 上,因此放置在其中的任何内容都将立即可供任何插件使用,就像普通的 Python 库(或任何内置库)一样将是.您可以将这些文件夹视为类似于标准 Python 中的 site-packages 文件夹.

Those directories are directly on the Python sys.path by default, so anything placed inside of them will be immediately available to any plugin just as a normal Python library (or any of those built in) would be. You could consider these folders to be something akin to the site-packages folder in standard Python.

因此,可以使用任何可以安装标准 Python 库的方法,只要结果是文件位于此文件夹中即可.例如,您可以通过 pip 安装一个库,然后从 site-packages 手动将文件复制到该位置,从源等手动安装.

So, any method by which you could install a standard Python library can be used so long as the result is files ending up in this folder. You could for example install a library via pip and then manually copy the files to that location from site-packages, manually install from sources, etc.

Lib/python3.3/
|-- librarya
|   `-- file1.py
|-- libraryb
|   `-- file2.py
`-- singlefile.py

此处适用版本限制;您要使用的 dependency 必须支持 Sublime 使用的 Python 版本,否则它将无法工作.这对于具有本机组件(例如 .dll.so.dylib)的 Python 库尤其重要,这可能需要手动编译代码.

Version restrictions apply here; the dependency that you want to use must support the version of Python that Sublime is using, or it won't work. This is particularly important for Python libraries with a native component (e.g. a .dll, .so or .dylib), which may require hand compiling the code.

这个方法不是自动的;你需要这样做才能在本地使用你的包,任何想要使用你的包的人也需要这样做.由于 Sublime 当前使用的是旧版本的 Python,因此获取正确版本的库也可能存在问题.

This method is not automatic; you would need to do it to use your package locally, and anyone that wants to use your package would also need to do it as well. Since Sublime is currently using an older version of Python, it can be problematic to obtain a correct version of libraries as well.

将来,Package Control 将在此位置安装 dependencies(将在运行至 3.0 版期间专门为此目的添加文件夹),但截至我撰写本文时答案目前并非如此.

In the future, Package Control will install dependencies in this location (Will added the folder specifically for this purpose during the run up to version 3.0), but as of the time I'm writing this answer that is not currently the case.

Packages 文件夹默认也在 sys.path 上;这就是 Sublime 查找和加载包的方式.物理 Packages 文件夹以及包含 sublime-package 文件内容的虚拟"包文件夹都是如此.

The Packages folder is on the sys.path by default as well; this is how Sublime finds and loads packages. This is true of both the physical Packages folder, as well as the "virtual" packages folder that contains the contents of sublime-package files.

例如,可以通过以下方式访问提供 exec 命令的类:

For example, one can access the class that provides the exec command via:

from Default.exec import ExecCommand

即使 exec.py 文件实际上存储在 Sublime 文本安装文件夹中的 Default.sublime-package 中,并且实际上不存在于 Packages 文件夹.

This will work even though the exec.py file is actually stored in Default.sublime-package in the Sublime text install folder and not physically present in the Packages folder.

因此,您可以直接在自己的包中vendor任何依赖项.这可能是 User 包或您正在创建的任何其他包.

As a result of this, you can vendor any dependencies that you require directly inside of your own package. Here this could be the User package or any other package that you're creating.

需要注意的是,Sublime 会将包顶层中的任何 Python 文件视为插件,并尝试将其作为插件加载.因此,重要的是,如果你走这条路,你会在你的包中创建一个子文件夹并将库放在那里.

It's important to note that Sublime will treat any Python file in the top level of a package as a plugin and try to load it as one. Hence it's important that if you go this route you create a sub-folder in your package and put the library in there.

MyPackage/
|-- alibrary
|   `-- code.py
`-- my_plugin.py

有了这个结构,就可以直接访问模块了:

With this structure, you can access the module directly:

import MyPackage.alibrary

from MyPackage.alibrary import someSymbol

并非所有 Python 模块都无需修改即可直接使用此方法;可能需要对 dependency 进行一些代码更改,以允许库的不同部分查看自身的其他部分,例如,如果它不使用相对 import获取兄弟文件.许可限制也可能会妨碍这一点,具体取决于您使用的库.

Not all Python modules lend themselves to this method directly without modification; some code changes in the dependency may be required in order to allow different parts of the library to see other parts of itself, for example if it doesn't use relative import to get at sibling files. License restrictions may also get in the way of this as well, depending on the library that you're using.

另一方面,这会直接将您使用的库版本锁定为您测试时使用的版本,从而确保您以后不会遇到任何不适当的意外.

On the other hand, this directly locks the version of the library that you're using to exactly the version that you tested with, which ensures that you won't be in for any undue surprises further on down the line.

使用此方法,您为分发包所做的任何事情也将自动分发包含在其中的供应商库.因此,如果您通过 Package Control 进行分发,则无需执行任何特殊操作,它就可以使用 Just Work™.

Using this method, anything you do to distribute your package will automatically also distribute the vendored library that's contained inside. So if you're distributing by Package Control, you don't need to do anything special and it will Just Work™.

嵌入到 Sublime 中的 Python 仍然是标准 Python,因此如果需要,您可以手动操作 sys.path,它描述了要在哪些文件夹中查找包,以便它会在除了 Sublime 自动设置的标准位置之外,您还可以选择.

The Python that's embedded into Sublime is still standard Python, so if desired you can manually manipulate the sys.path that describes what folders to look for packages in so that it will look in a place of your choosing in addition to the standard locations that Sublime sets up automatically.

这通常不是一个好主意,因为如果做得不正确,事情很快就会变成梨形.它还需要您先在自己的某个位置手动安装库,在这种情况下,您最好使用上面概述的 Lib 文件夹,该文件夹已经在 sys.path.

This is generally not a good idea since if done incorrectly things can go pear shaped quickly. It also still requires you to manually install libraries somewhere yourself first, and in that case you're better off using the Lib folder as outlined above, which is already on the sys.path.

我认为这种方法是一种高级解决方案,您可以在开发过程中用于测试目的,否则不会是面向用户的.如果您计划通过包控制分发您的包,对您的包的审查可能会通过请求使用另一种方法来阻止对 sys.path 的操作.

I would consider this method an advanced solution and one you might use for testing purposes during development but otherwise not something that would be user facing. If you plan to distribute your package via Package Control, the review of your package would likely kick back a manipulation of the sys.path with a request to use another method.

包控件包含一个依赖机制,该机制结合使用两种先前的方法来提供一种方法自动安装依赖项.还有一个可用依赖项列表,尽管该列表可能不完整.

Package control contains a dependency mechanism that uses a combination of the two prior methods to provide a way to install a dependency automatically. There is a list of available dependencies as well, though the list may not be complete.

如果您有兴趣使用的 dependency 已经可用,那么您就可以开始使用了.有两种不同的方法可以声明您的包需要一个或多个依赖项.

If the dependency that you're interested in using is already available, you're good to go. There are two different ways to go about declaring that you need one or more dependencies on your package.

注意:Package Control 目前不支持依赖的依赖;如果某个依赖项还需要安装另一个库,则您需要自己明确提及它们.

第一个涉及向包控制通道文件中包的条目添加 dependencies 键.这是您将包添加到包控制时要采取的步骤,这超出了本答案的范围.

The first involves adding a dependencies key to the entry for your package in the package control channel file. This is a step that you'd take at the point where you're adding your package to Package Control, which is something that's outside the scope of this answer.

当您正在开发您的包时(或者如果您决定在完成后不想通过包控制分发您的包),那么您可以改为添加一个 dependencies.json 文件到你的包的根目录(一个 example dependencies.json 文件可用于说明这一点).

While you're developing your package (or if you decide that you don't want to distribute your package via Package Control when you're done), then you can instead add a dependencies.json file into the root of your package (an example dependencies.json file is available to illustrate this).

完成此操作后,您可以从命令 Palette 中选择 Package Control: Satisfy Dependencies 以让 Package Control 为您下载并安装依赖项(如果需要).

Once you do that, you can choose Package Control: Satisfy Dependencies from the command Palette to have Package Control download and install the dependency for you (if needed).

如果您的包是由包控制分发和安装的,则此步骤是自动的;否则,您需要告诉您的用户在安装软件包后执行此步骤.

This step is automatic if your package is being distributed and installed by Package Control; otherwise you need to tell your users to take this step once they install the package.

Package Control 用于安装 dependencies 的方法如问题顶部所述,在未来(可能不久)的某个时间点可能会发生变化.这可能会影响此处的说明.就设置而言,整体机制可能保持不变,只是安装位置发生了变化,但目前仍有待观察.

Package Control 通过 vendoring 和操作 sys.path 的特殊组合来安装依赖项,以允许找到东西.为此,它要求您以特定方式布置您的依赖项并提供一些额外的元数据.

Package Control installs dependencies via a special combination of vendoring and also manipulation of the sys.path to allow things to be found. In order to do so, it requires that you lay out your dependency in a particular way and provide some extra metadata as well.

构建时包含依赖项的包的布局将具有类似于以下的结构:

The layout for the package that contains the dependency when you're building it would have a structure similar to the following:

Packages/my_dependency/
├── .sublime-dependency
└── prefix
    └── my_dependency
        └── file.py

Package Control 将一个 dependency 安装为一个 Package,并且由于 Sublime 将包根目录中的每个 Python 文件都视为一个插件,因此该依赖项的代码不会保留在包的顶层包裹.如上所示,依赖项的实际内容存储在上面标记为 prefix 的文件夹中(稍后会详细介绍).

Package Control installs a dependency as a Package, and since Sublime treats every Python file in the root of a package as a plugin, the code for the dependency is not kept in the top level of the package. As seen above, the actual content of the dependency is stored inside of the folder labeled as prefix above (more on that in a second).

安装依赖项后,Package Control 会在其特殊的 0_package_control_loader 包中添加一个条目,从而将 prefix 文件夹添加到 sys.path,这使得它里面的所有内容都可以正常用于 import 语句.这就是库名称存在固有重复的原因(在此示例中为 my_dependency).

When the dependency is installed, Package Control adds an entry to it's special 0_package_control_loader package that causes the prefix folder to be added to the sys.path, which makes everything inside of it available to import statements as normal. This is why there's an inherent duplication of the name of the library (my_dependency in this example).

关于 prefix 文件夹,它实际上并没有被命名,而是有一个特殊的名称,用于确定依赖项可用的 Sublime Text 版本、平台和架构的组合(对于包含二进制文件,例如).

Regarding the prefix folder, this is not actually named that and instead has a special name that determines what combination of Sublime Text version, platform and architecture the dependency is available on (important for libraries that contain binaries, for example).

prefix 文件夹的名称实际上遵循以下形式 {st_version}_{os}_{arch}, {st_version}_{os}{st_version}all.{st_version} 可以是 st2st3{os} 可以是 windowslinuxosx{arch} 可以是 x32x64.

The name of the prefix folder actually follows the form {st_version}_{os}_{arch}, {st_version}_{os}, {st_version} or all. {st_version} can be st2 or st3, {os} can be windows, linux or osx and {arch} can be x32 or x64.

因此您可以说您的依赖项仅支持 st3st3_linuxst3_windows_x64 或其任意组合.对于具有本机代码的内容,您可以通过具有多个文件夹来指定几个不同的版本,尽管当 dependency 包含纯 Python 代码时,通常会使用 all、操作系统或架构.

Thus you could say that your dependency supports only st3, st3_linux, st3_windows_x64 or any combination thereof. For something with native code you may specify several different versions by having multiple folders, though commonly all is used when the dependency contains pure Python code that will work regardless of the Sublime version, OS or architecture.

在这个例子中,如果我们假设 prefix 文件夹被命名为 all 因为 my_dependency 是纯 Python,那么安装这个的结果依赖关系是 Packages/my_dependency/all 将被添加到 sys.path,这意味着如果你 import my_dependency 你得到该文件夹内的代码.

In this example, if we assume that the prefix folder is named all because my_dependency is pure Python, then the result of installing this dependency would be that Packages/my_dependency/all would be added to the sys.path, meaning that if you import my_dependency you're getting the code from inside of that folder.

在开发期间(或者如果您不想通过包控制分发您的依赖项),您可以在包的根目录中创建一个 .sublime-dependency 文件,如上所示.这应该是一个文本文件,单行包含 2 位数字(例如 0150).这控制了每个安装的依赖项将被添加到 sys.path 的顺序.如果您的依赖项没有其他依赖项,您通常会选择一个较低的数字,如果有,则选择更高的值(以便在这些依赖项之后注入).

During development (or if you don't want to distribute your dependency via Package Control), you create a .sublime-dependency file in the root of the package as shown above. This should be a text file with a single line that contains a 2 digit number (e.g. 01 or 50). This controls in what order each installed dependency will get added to the sys.path. You'd typically pick a lower number if your dependency has no other dependencies and a higher value if it does (so that it gets injected after those).

一旦您在 Packages 文件夹中以正确的格式布置了初始依赖项,您将使用命令面板中的 Package Control: Install Local Dependency 命令,然后选择依赖项的名称.

Once you have the initial dependency laid out in the correct format in the Packages folder, you would use the command Package Control: Install Local Dependency from the Command Palette, and then select the name of your dependency.

这会导致包控制安装"依赖项(即更新 0_package_control_loader 包)以激活依赖项.这一步通常会在 Package Control 首次安装依赖项时自动执行,因此如果您还手动分发依赖项,则需要提供执行此步骤的说明.

This causes Package Control to "install" the dependency (i.e. update the 0_package_control_loader package) to make the dependency active. This step would normally be taken by Package Control automatically when it installs a dependency for the first time, so if you are also manually distributing your dependency you need to provide instructions to take this step.

这篇关于如何正确使用 Sublime Text 插件的 3rd 方依赖项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-03 22:18
查看更多