繁体   English   中英

Sublime Text插件开发中的全局Python包

[英]Global Python packages in Sublime Text plugin development

1.总结

我没有发现,Sublime Text插件开发人员如何使用Sublime Text查找全局Python包,而不是Sublime Text目录的Python包。

Sublime Text使用自己的Python环境,而不是机器的Python环境。 开发人员需要sys.path来设置不是内置的Sublime Text Python包。

是否有任何方法,在Sublime Text插件中使用全局安装的Python包? 例如,如果有人告诉我,如何更改我的插件,那将是很好的 - 请参阅此问题的3.2项。


2.使用Sublime Text 3环境的缺点

  1. Sublime Text 3 Build 3126使用Python 3.3,但在撰写本期时,发布Python 3.6稳定版。 Python 3.6有更多功能。
  2. 开发人员需要添加和更新第三方Python包,即使是为用户安装的也是如此。 它花了一些时间的开发人员。
  3. 对于开发人员,可能存在包的依赖性问题,请参阅此问题的6.2项。

3.例子

1. Python代码

例如,我编写了Python代码 - 将Поиск Кристиниты替换为[**Поиск Кристиниты**](https://github.com/Kristinita/Kristinita.github.io) ,其中https://github.com/Kristinita/Kristinita.github.io - DuckDuckGo查询Поиск Кристиниты第一个链接。

# -*- coding: utf-8 -*-
import re
import urllib

from bs4 import BeautifulSoup

from w3lib.url import safe_url_string


# ASCII link for solved encoding problems —
# https://stackoverflow.com/a/40654295/5951529
ascii_link = safe_url_string(
    u'http://duckduckgo.com/html/?q=' + 'Поиск Кристиниты',
    encoding="UTF-8")
print(ascii_link)
# SERP DuckDuckGo
serp = urllib.request.urlopen(ascii_link)
# Reading SERP
read_serp = serp.read()
# BeautifulSoup — https://stackoverflow.com/a/11923803/5951529
parsed = BeautifulSoup(read_serp, "lxml")
# Parsed first link
first_link = parsed.findAll(
    'div', {'class': re.compile('links_main*')})[0].a['href']
# Remove DuckDuckGo specific characters —
# https://stackoverflow.com/a/3942100/5951529
remove_duckduckgo_symbols = first_link.replace("/l/?kh=-1&uddg=", "")
# https://stackoverflow.com/a/32451970/5951529
final_link = (urllib.parse.unquote(remove_duckduckgo_symbols))
# Markdown link
markdown_link = '[' + 'Поиск Кристиниты' + ']' + \
    '(' + final_link + ')'

print(markdown_link)

如果我在终端或SublimeREPL中运行此文件,我会输入:

[**Поиск Кристиниты**](https://github.com/Kristinita/Kristinita.github.io/)

2. Sublime Text插件

现在,基于这段代码,我编写了Sublime Text插件,用于将example text替换为[**example text**](http://<first link for DuckDuckGo query “example link”>)

import re
import urllib

from bs4 import BeautifulSoup

from w3lib.url import safe_url_string

import sublime_plugin


class KristinitaLuckyLinkCommand(sublime_plugin.TextCommand):

    def run(self, edit):
        # Get selection text
        print('KristinitaLuckyLink called')
        select = self.view.sel()
        selection_region = select[0]
        selection_text = self.view.substr(selection_region)
        print(selection_text)

        # ASCII link for solved encoding problems —
        # https://stackoverflow.com/a/40654295/5951529
        ascii_link = safe_url_string(
            u'http://duckduckgo.com/html/?q=' + (selection_text),
            encoding="UTF-8")
        print(ascii_link)
        # SERP DuckDuckGo
        serp = urllib.request.urlopen(ascii_link)
        # Reading SERP
        read_serp = serp.read()
        # BeautifulSoup — https://stackoverflow.com/a/11923803/5951529
        parsed = BeautifulSoup(read_serp, "lxml")
        # Parsed first link
        first_link = parsed.findAll(
            'div', {'class': re.compile('links_main*')})[0].a['href']
        # Remove DuckDuckGo specific characters —
        # https://stackoverflow.com/a/3942100/5951529
        remove_duckduckgo_symbols = first_link.replace("/l/?kh=-1&uddg=", "")
        # Final link — https://stackoverflow.com/a/32451970/5951529
        final_link = (urllib.parse.unquote(remove_duckduckgo_symbols))
        markdown_link = '[' + selection_text + ']' + \
            '(' + final_link + ')'
        print(markdown_link)

        # Replace selected text to Markdown link
        self.view.replace(
            edit, selection_region, markdown_link)

4.预期的行为

如果用户已安装Python并安装包

  • pip install beautifulsoup4
  • pip install lxml
  • pip install w3lib

我想,我的2.2项目的插件成功为用户工作。


5.实际行为

如果我保存我的插件,我会得到堆栈跟踪:

Traceback (most recent call last):
  File "D:\Sublime Text Build 3126 x64 For Debug\sublime_plugin.py", line 109, in reload_plugin
    m = importlib.import_module(modulename)
  File "./python3.3/importlib/__init__.py", line 90, in import_module
  File "<frozen importlib._bootstrap>", line 1584, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1565, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1532, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 584, in _check_name_wrapper
  File "<frozen importlib._bootstrap>", line 1022, in load_module
  File "<frozen importlib._bootstrap>", line 1003, in load_module
  File "<frozen importlib._bootstrap>", line 560, in module_for_loader_wrapper
  File "<frozen importlib._bootstrap>", line 868, in _load_module
  File "<frozen importlib._bootstrap>", line 313, in _call_with_frames_removed
  File "D:\Sublime Text Build 3126 x64 For Debug\Data\Packages\Grace Splitter\kristi.py", line 4, in <module>
    from bs4 import BeautifulSoup
ImportError: No module named 'bs4'

6.没有帮助

1.使用计算机的全局Python环境

我没有找到,我怎么做。 我可以找到的问题示例:

2.使用Sublime Text环境

我安装

我将我的w3lib目录从C:\\Python36\\Lib\\site-packages复制到Sublime Text的Data\\Packages目录。

我在Sublime Text 3控制台中运行:

>>> window.run_command("kristinita_lucky_link")

我得到堆栈跟踪:

Traceback (most recent call last):
  File "D:\Sublime Text 3 x64\sublime_plugin.py", line 818, in run_
    return self.run(edit)
  File "D:\Sublime Text 3 x64\Data\Packages\KristinitaLuckyLink\KristinitaLuckyLink.py", line 32, in run
    parsed = BeautifulSoup(read_serp, "lxml")
  File "D:\Sublime Text 3 x64\Data\Packages\bs4\__init__.py", line 165, in __init__
    % ",".join(features))
bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?

我没有找到,我怎么能设置lxml

3.在2个文件中使用变量

比如我有KristinitaLuckyLink.pyKrisDuckDuckGo.py在同一个目录中的文件。

我的KristinitaLuckyLink.py文件:

import re
import requests
import sublime_plugin
import subprocess
import sys
sys.path.append(
    'D:\Sublime Text 3 x64\Data\Packages\KristinitaLuckyLink\KrisDuckDuckGo.py')

from KrisDuckDuckGo import final_link
from bs4 import BeautifulSoup


class KristinitaLuckyLinkCommand(sublime_plugin.TextCommand):

    def run(self, edit):
        # Get selection text
        print('KristinitaLuckyLink called')
        select = self.view.sel()
        selection_region = select[0]
        selection_text = self.view.substr(selection_region)
        print(selection_text)

        # Get terminal output — https://stackoverflow.com/a/4760517/5951529
        # Paths is correct
        result = subprocess.run(["C:\Python36\python.exe", "D:\Sublime Text 3 x64\Data\Packages\KristinitaLuckyLink\krisduckduckgo.py"],
                                stdout=subprocess.PIPE)
        final_link = result.stdout.decode('utf-8')
        print(final_link)

        # Markdown link
        markdown_link = '[' + selection_text + ']' + \
            '(' + final_link + ')'
        print(markdown_link)

        # Replace selected text to Markdown link
        self.view.replace(
            edit, selection_region, markdown_link)

我的KrisDuckDuckGo.py文件:

import urllib

import sys
sys.path.append(
    'D:\Sublime Text 3 x64\Data\Packages\KristinitaLuckyLink\KristinitaLuckyLink.py')

from w3lib.url import safe_url_string

from KristinitaLuckyLink import selection_text

from bs4 import BeautifulSoup


# ASCII link for solved encoding problems —
# https://stackoverflow.com/a/40654295/5951529
ascii_link = safe_url_string(
    u'http://duckduckgo.com/html/?q=' + (selection_text),
    encoding="UTF-8")
print(ascii_link)
# SERP DuckDuckGo
serp = urllib.request.urlopen(ascii_link)
# Reading SERP
read_serp = serp.read()
# BeautifulSoup — https://stackoverflow.com/a/11923803/5951529
parsed = BeautifulSoup(read_serp, "lxml")
# Parsed first link
first_link = parsed.findAll(
    'div', {'class': re.compile('links_main*')})[0].a['href']
# Remove DuckDuckGo specific characters —
# https://stackoverflow.com/a/3942100/5951529
remove_duckduckgo_symbols = first_link.replace("/l/?kh=-1&uddg=", "")
# Final link — https://stackoverflow.com/a/32451970/5951529
final_link = (urllib.parse.unquote(remove_duckduckgo_symbols))
print(final_link)

我选择任何文本→我在Sublime Text控制台中打印:

window.run_command( “kristinita_lucky_link”)

我没有在Sublime Text控制台中获得输出。


7.环境

操作系统和版本:
Windows 10企业版LTSB 64位EN
崇高文字:
建立3126
蟒蛇:
3.6.0

如果您想在计算机上使用Python版本(Sublime不提供),您可以使用以下Sublime命令:

window.run_command("exec", {"shell_cmd" : '<your command here>'})

此命令允许您在Sublime之外的计算机上执行应用程序。 只需将<your command here>替换为您要执行的shell命令即可。 输出将在sublime的输出面板(终端)中返回。 该输出面板与Sublime控制台不同。

您可以将要使用的本地Python的路径放在那里,并使用脚本(需要额外的Python模块)作为参数。 例如:

window.run_command("exec", {"shell_cmd" : 'C:\\Python36\\python.exe D:\\Sublime Text 3 x64\\Data\\Packages\\KristinitaLuckyLink\\LuckyLink\\LuckyLink.py'})

您需要将包拆分为两个文件。 一个文件,描述您的包和Sublime内部所需的命令。 另一个文件(应该位于程序包目录的子目录中 - 因此Sublime不作为插件处理)包含其余的代码。 第二个文件是导入未包含在Sublime内部Python中的Python模块的位置。 此外,您需要找到一种方法将您想要使用的选择或字符串/ URL转移到第二个脚本。

您可以在我的Sublime包PlotGraph中查看我是如何做到的

错误:

bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?

很可能是因为Sublime Text发现lxml是作为全局Python环境的一部分安装的 - 它是为不同版本的Python编译而不是ST使用的 - 所以它无法加载它。

我们想要的是让ST找到你在问题中链接的sublime-lxml依赖项。 “你为什么找错了?”,你可能会问。 很难说肯定,但我认为OdatNurd的回答给了我们一些线索 - 由于某种原因ST看到的sys.path包括你所有的全局Python包。 默认情况下,ST应该只使用其可执行文件所在的文件夹和ST数据目录中的Packages文件夹。 例如,在我的系统上,执行import sys; sys.path ST的控制台中的import sys; sys.path给了我:

[
 'C:\\Program Files\\Sublime Text 3',
 'C:\\Program Files\\Sublime Text 3/python3.3.zip',
 'C:\\Users\\Keith\\AppData\\Roaming\\Sublime Text 3\\Packages',
 'C:\\Users\\Keith\\AppData\\Roaming\\SUBLIM~1\\Packages\\lxml\\ST3_WI~2'
]

即没有site-packages文件夹。

因此解决方案是:

一种。 您可以尝试卸载系统范围的lxml软件包,以便ST只能找到sublime-lxml依赖软件包,但实际上这只是一个临时措施。 最好是:b。 调整ST正在使用的路径环境变量(项目的顺序)。 (即删除对site-packages所有引用,或者至少移动它们以便它们位于ST文件夹之后。)

选项B不应该影响任何其他ST插件,因为它们也会遇到同样的问题。 我怀疑其他一些软件包改变了ST正在使用的路径,但是可能不容易找出哪一个,而不是全部搜索它们。 使用构建系统时,用于那些的路径与插件用于加载其模块的路径完全不同,因此构建系统也应该不受此“修复”的影响。

Python通过sys.path从它知道的位置加载模块,在Sublime Text 3中, sys.path仅指向几个位置(例如Sublime可执行文件附带的软件包的位置,当前用户的用户安装软件包的位置)等)。

要从Sublime文本插件中访问全局安装的Python模块,您需要从插件中将其位置显式添加到sys.path

假设一台Linux机器的python软件包安装在/usr/local/lib/python3.4/site-packages (将其修改为适用于Windows机器的适当路径),其示例如下:

import sublime
import sublime_plugin
import sys

site_path="/usr/local/lib/python3.4/site-packages"
if site_path not in sys.path:
    sys.path.append(site_path)

from bs4 import BeautifulSoup

class ExampleCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        parser = BeautifulSoup('<a href="#">Link Text</a>', "html.parser")
        a = parser.find("a")
        text = a.contents[0]
        self.view.insert(edit, 0, text)

这特别添加了sys.path的路径(如果它尚不存在),允许导入和使用模块。

Sublime包含自己独特的Python版本,专门用于沙盒本身,因此它根本不依赖于任何版本的python或正在用于运行它的计算机上安装的任何python包,这就是为什么它不这样做对你默认。

是的,插件可以与Python模块一起使用,用户可以全局安装。 您没有义务向Sublime Text插件介绍模块。

问题

1. Python 3.3兼容性

对于 2018年开始:

您在插件中使用的所有全局模块都必须与Python 3.3兼容。

1.1。 论证

1.1.1。 Sublime Text sys.path命令

例如,我添加到Default.sublime-package存档文件0000.py Default.sublime-package中的模块首先由Sublime Text start 加载

0000.py内容:

import sys

sys.path.append('C:\\Python36')
sys.path.append('C:\\Python36\\python36.zip')
sys.path.append('C:\\Python36\\DLLs')
sys.path.append('C:\\Python36\\lib')
sys.path.append('C:\\Python36\\lib\\site-packages')

路径 - 我的全局sys.path

>>> import sys; sys.path
['', 'C:\\Python36', 'C:\\Python36\\python36.zip', 'C:\\Python36\\DLLs', 'C:\\Python36\\lib', 'C:\\Python36\\lib\\site-packages']

我重新启动Sublime Text→我在控制台中看到:

DPI scale: 1
startup, version: 3143 windows x64 channel: stable
executable: /D/Sublime Text Build 3143 x64 For Debug/sublime_text.exe
working dir: /D/Kristinita
packages path: /D/Sublime Text Build 3143 x64 For Debug/Data/Packages
state path: /D/Sublime Text Build 3143 x64 For Debug/Data/Local
zip path: /D/Sublime Text Build 3143 x64 For Debug/Packages
zip path: /D/Sublime Text Build 3143 x64 For Debug/Data/Installed Packages
ignored_packages: ["Anaconda", "Vintage"]
pre session restore time: 0.458819
startup time: 0.493818
first paint time: 0.506818
reloading plugin Default.0000
reloading plugin Default.auto_indent_tag
reloading plugin Default.block
# And so on
>>> import sys; sys.path
['D:\\Sublime Text Build 3143 x64 For Debug', 'D:\\Sublime Text Build 3143 x64 For Debug\\python3.3.zip', 'D:\\Sublime Text Build 3143 x64 For Debug\\Data\\Lib\\python3.3', 'D:\\Sublime Text Build 3143 x64 For Debug\\Data\\Packages', 'C:\\Python36', 'C:\\Python36\\python36.zip', 'C:\\Python36\\DLLs', 'C:\\Python36\\lib', 'C:\\Python36\\lib\\site-packages']

来自内部环境的路径在前方,即全球环境中的路径。 我不知道,我怎么能改变它。

1.1.2。 Python 3.6模块

例如,我想在我的插件Python Google Search API PyPI模块中使用。 它与Python 3.6兼容,但与Python 3.3不兼容

我按照上面的小节注入文件0000.py →我创建插件SashaGSearch.py ,它内容:

import sublime_plugin

from gsearch.googlesearch import search


class GoogleSearchCommand(sublime_plugin.TextCommand):

    def run(self, edit):

        results = search('kristinitaluckylife', num_results=1)
        r = results[0][1]
        print(r)

我重新启动Sublime Text→我得到相同的回溯 ,就像0000.py没有实现一样。

1.2。 2018年初的情况

请参阅Sublime Text论坛讨论:

我希望,在内部Sublime Text环境中,Python 3.3将在最近的将来被替换为3.6或下一个3.7版本。


2.环境变量

如果您知道,那可能不添加新的环境变量,请回答这个问题

2.1。 插件代码

您需要在您的PC环境变量上创建值 - 路径到site-packages文件夹。 例如,我将其命名为PYTHONPACKAGES

您需要添加到代码行,如OdatNurd答案

# PYTHONPACKAGES path:
# https://stackoverflow.com/a/4907053/5951529
# Disable duplicate paths:
# https://stackoverflow.com/a/42656754/5951529
site_packages = (os.environ['PYTHONPACKAGES'])
if site_packages not in sys.path:
    sys.path.append(site_packages)

2.2。 激活说明

您的插件用户还必须在操作系统中添加环境变量PYTHONPACKAGES 在您的包的描述中,您需要添加说明,如何做。


3.重启

对于开发过程:

如果更改site-packages文件夹或子文件夹中的文件,则可能需要重新启动Sublime Text。

3.1。

你可以从pip安装examplesashamodule →你启动Sublime Text→你将examplesashamodule导入你的插件→你从site-packages文件夹中删除examplesashamodule →插件将作为examplesashamodule仍然在site-packages文件夹中。 在这种情况下, AutomaticPackageReloader包没有帮助。

你重新启动Sublime Text→你在Sublime Text控制台得到回溯,那就是ImportError: No module named 'examplesashamodule'

显然,Sublime Text会话来自会话中外部模块的数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM