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

时间:2017-03-07 16:09:16

标签: python python-3.x sublimetext3 sublimetext sublime-text-plugin

1。摘要

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

Sublime Text使用自己的Python环境,而不是机器的Python环境。 Developers needs 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项。
  4. 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
    Sublime Text:
    建立3126
    的Python:
    3.6.0

4 个答案:

答案 0 :(得分:3)

如果您想在计算机上使用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模块的位置。 此外,您需要找到一种方法将您想要使用的选择或字符串/网址传输到第二个脚本。

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

答案 1 :(得分:3)

错误:

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依赖项。 &#34;为什么找到错误的?&#34;,你可能会问。很难肯定地说,但我认为OdatNurd's answer gives us some clues - ST出于某种原因看到的sys.path包括你所有的全局Python包。默认情况下,ST应仅使用其可执行文件所在的文件夹和ST数据目录中的Packages文件夹。例如,在我的系统上,在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依赖包,但实际上这只是一个临时措施。最好是: 湾调整ST正在使用的路径环境变量(项目的顺序)。 (即删除对site-packages的所有引用,或者至少移动它们以便它们位于ST文件夹之后。)

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

答案 2 :(得分:2)

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包,这就是为什么它没有t默认为你做这件事。

答案 3 :(得分:1)

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

问题

1。 Python 3.3兼容性

2018年开始:

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

1.1。论证

1.1.1。 Sublime Text sys.path order

例如,我添加到Default.sublime-package存档文件0000.py。 Sublime Text start Default.sublime-package中的模块为loaded first

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兼容,但not compatible with 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→我得到same traceback,好像0000.py没有实现。

1.2。 2018年开始的情况

请参阅Sublime Text论坛讨论:

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

2。环境变量

如果您知道,可能不会添加新的环境变量,请回答this question

2.1。插件代码

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

您需要像OdatNurd answer中一样添加代码行:

# 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到你的插件→你从examplesashamodule文件夹中删除site-packages→插件将作为{{ 1}}仍在examplesashamodule文件夹中。在这种情况下,AutomaticPackageReloader包不起作用。

你重新启动Sublime Text→你在Sublime Text控制台中得到追溯,site-packages

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