Sublime Text 3 Creating Plugin adding external python libraries - python-3.x

So I'm trying to create a plugin and execute it with the context menu. In my plugin, I want to make use of the mechanical soup module.
I have configured the Context.sublime-menu file as follows to create the Context menu option:
[
{
"id": "SlackSnippets",
"caption": "SlackSnippets",
"children":
[
{"id": "wrap"},
{ "command": "slacksnippet" }
]
}
]
Now, with this, the extreme basic functionality of the context menu works, it shows up when you right-click, and it's child command is clickable:
.
However, where I'm running into trouble is when I then try to import the mechanical soup module in the python file where the 'SlackSnippet' command is defined:
from __future__ import print_function
import os
import mechanicalsoup """If Commented out, I can click the command in the context window"""
import sublime
import sublime_plugin
class SlacksnippetCommand(sublime_plugin.TextCommand):
def run(self, edit):
## Code
The command in the Context menu then greys out and I am unable to use it:
I am new to creating plugins in Sublime Text 3 and any help with this would be greatly appreciated!

The reason that your command is grayed out in the second case is because Sublime can't load the plugin with the line you mention in place. Thus it doesn't know about the command the menu entry is telling it to execute, and so it is disabled (if you were using the command palette, the command would not appear at all in this case).
If you open the Sublime console with Ctrl+` or View > Show Console you'll see a stack trace saying this:
ImportError: No module named 'mechanicalsoup'
The first thing to note is that Sublime Text contains its own embedded version of Python 3.3.6 that is completely distinct from any version of Python you may have installed on your computer.
As such, it is unable to load system installed Python modules by default because it doesn't know anything about them. It's possible to make Sublime look at system locations, but it's generally not a good idea because it introduces a lot of external dependencies that users of your plugin/package will need to install before your code works (including installing Python 3.3.6 itself).
Generally speaking, the Python interpreter embedded in Sublime looks for Python files/modules in a few locations, but the only ones that are meant for users to interact with are:
The Sublime Text Packages folder, which you can get to by selecting Preferences > Browse Packages from the menu
A folder named Lib/python3.3 (Lib is stored in the same place as the Packages folder; use that command and go up one folder level)
You have the option of putting your module (e.g. mechanicalsoup in the Packages folder. However, this is not a particular good idea because Sublime will try to load the top level Python source files automatically (because it thinks it is a package) which is not what you want and may not actually work except in simple cases.
Sublime ignores any Python files that are not in the top level of a package folder unless you tell it explicitly to load it (i.e. via import). So you can put your modules directly inside of your package folder and import them from there.
For example, if your package was named SlackSnippets, your package folder might look like this:
SlackSnippets/
|-- mechanicalsoup
| |-- __init__.py
| |-- __version__.py
| |-- browser.py
| |-- form.py
| |-- stateful_browser.py
| `-- utils.py
`-- slack_snippet_cmd.py
Now you can import the module by specifying the module name SlackSnippets.mechanicalsoup:
from __future__ import print_function
import os
import SlackSnippets.mechanicalsoup
import sublime
import sublime_plugin
class SlacksnippetCommand(sublime_plugin.TextCommand):
def run(self, edit):
pass
(Note: This still won't work because this module requires other modules to be installed, such as requests. I'm not sure how deep that particular rabbit hole goes, however, since I don't use this module.)
Depending on the module in question and how it's written, there may be more work involved in getting things to work this way, such as if there are operating system specific libraries that are needed.
That leaves us with the second option mentioned above, which is to put your modules in the Lib/python3.3 folder so Sublime will be able to find them.
In this case since that folder is in the search path, your code as originally posted will load the module without any changes (although it will still fail to work here due to no requests module being available).
You (and your users) are still still responsible for putting the module(s) there, though; Sublime doesn't do that sort of thing for you on it's own. If you plan on using Package Control to distribute your package when you're finished, you can get a little respite from this.
Package Control supports the notion of dependency modules and with some set up will install modules for the user (if they're not already installed) when your package is installed.
Currently this is handled by Package Control by putting the module into the Packages folder with a special package layout followed by doing some work behind the scenes so that Sublime will see it as a regular module.
In order to get this to work you need to have the dependencies that you require also be stored in Package Control, which requires more set up work by you if the modules that you're interested in aren't already available.
Currently mechanicalsoup is not available, although requests is. The list of available dependencies is here.

Related

ImportError: No module named functions

Image
I don't know what am I doing wrong here. I am importing the module from the functions package in the tests package. I tried every method but couldn't solve this problem while I tried to run valid_test.py
You need to use one dot before the functions so the python will know it is in the folder "above" the current location (import statement).
This look like this issue.
When specifying what module to import you do not have to specify the
absolute name of the module. When a module or package is contained
within another package it is possible to make a relative import within
the same top package without having to mention the package name. By
using leading dots in the specified module or package after from you
can specify how high to traverse up the current package hierarchy
without specifying exact names. One leading dot means the current
package where the module making the import exists. Two dots means up
one package level. Three dots is up two levels, etc. So if you execute
from . import mod from a module in the pkg package then you will end
up importing pkg.mod. If you execute from ..subpkg2 import mod from
within pkg.subpkg1 you will import pkg.subpkg2.mod. The specification
for relative imports is contained within PEP 328.
There is another way to solve this issue by adding the "father" folder to the sys.path
by:
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__, '..')))
I have been getting the same problem again and again while using SPYDER with anaconda.
I make my own function in other file and import those functions. The code was still not running giving me the error "ModuleNotFoundError: No module named 'my_functions".
I am sure you are selecting lines and executing only selected line only\
Solution to problem is here below
To execute your code as whole/line by line Follow the steps.
Change the working directory of spyder to the folder of current file as here https://pasteboard.co/ee79y0dLqzu4.png .
select lines and execute or you can also execute the whole code.

How to import specific files from a scoped node package?

How can I import subdirectories or files from imported packages that are scoped?
For example I perfectly can do:
import array from "lodash/array".
But as soon as my package is scoped the array.js file (or array/index.js) becomes becomes unavailable, as the following will not work:
import array from "#myscope/lodash/array"
Based on #estus' hint I inspected #angular/common/http (https://github.com/angular/angular/tree/master/packages/common/http) and tried to replicate its file structure and package to understand what's going on.
Apparently You can only deep import from scoped packages with a specific file structure, which is skipping the dist or any other kind of directory that holds Your bundled files. You need to directly have the directory or file You wish to deep import in the scoped package.
Not working example:
node_modules/#angular/common/dist/http/index.js
Here you will not be able to do import http from "#angular/common/http" no matter how you setup your package.jsons. This is the structure I bundled my scoped package into though.
Working example:
node_modules/#angular/common/http/index.js
Here you will be able to do import http from "#angular/common/http". You don't even need a node_modules/#angular/common/http/package.json for that, a node_modules/#angular/common/package.json is sufficient.

How can I set up an alias for imports in Python?

I want my project to work in two different situations. It should work as a standalone library, but also as sub package of a larger project. The main use case is that of a standalone library, where its internal imports should be of the form
from my_library import sub_package
When using the code as sub package of a larger project, these imports don't work as there is no global name my_library. Instead, I would have to use relative or absolute imports, for example
from large_project.my_library import sub_package
Let's assume I wrote my library as shown in the first example. How can I overwrite importing behavior when running as part of a larger project to automatically adjust import paths?
Thanks to #MatrixTai's suggestion of adding the parent directory of the package to the the module path, I came up with this dynamic solution. At the top of my_library/__init__.py:
# Make package global even if used as a sub package to enable short imports.
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
We have to navigate up two directories here to do from the my_library/__init__.py to my_library and from there to its parent direction, where imports will find the library.
You don't have much choice.
If you want to reference the my_library.py anywhere, there is 2 method (as I known) can do similar work.
1: add system path. Like those module you installed by pip. pip module is installed in /Python/Scripts. You can add a new path or simply put my_library.py into one of the path. For adding, that's in Computer(right-click)-> Properties -> Environment Variable -> Choose Path and Click Edit
(Though you may not want to use this.)
2: Changing __init__.py, but still at least one line you must add in my_library.py.
For example,
/Directory
/large_project
-__init__.py #call this sub_init
-my_library.py
-__init__.py #call this main_init, this fake
-main.py
In main_init,
import sys
sys.path.append('\\Directory\\large_project')
As main_init is not executed when you execute main.py (this is fake), so in main.py
import __init__
from my_library import sub_package
But as well you can take this main_init as the starter of library, like declaring __all__, etc.

pytest cannot find module on import but code runs just fine

The goal is to use the pytest unit test framework for a Python3 project that uses Cython. This is not a plug-and-play thing, because pytest by default is not able to import the Cython modules. Namely, I get the following error when importing from a Cython .pyx module, in my case named 'calculateScore':
package/mainmodule.py:5: in <module>
from calculateScore import some_functions
E ImportError: No module named 'calculateScore'
This problem occurs both when using the pytest-runner as well as the pytest-cython approach. Strangely enough, the code runs just fine as a python application when you're not trying to test it using pytest.
Changing the import style to import calculateScore or import package.calculateScore does not help.
I have no idea why this is happening, but for me the easiest solution was to use the pytest-cython approach and change one or multiple things listed below in the package's setup.py file:
when defining your Extension for the ext_modules to include the Cython .pyx files, do not use distutils.extension.Extension but rather use setuptools.Extension
The reason why I manually create an Extension instead of using the Cython.Build.cythonize function, is not important here. But please note that for the pytest-runner approach:
do not use the cythonize function, but create the Extension manually
After writing this post I cannot even seem to reproduce the problem using pytest-cython anymore, which suggests that maybe something else is the cause of the problem. An additional thing you could try is to make sure that:
when manually creating an Extension for your .pyx module, make sure the name of the Extension is identical to the name of the module (so name it 'calculateScore' and not for instance 'package.calculateScore').
delete the compiled .so file corresponding to your .pyx file and then re-run.

How to structure my little python framework

I wrote a simple set of python3 files for emulating a small set of mongodb features on a 32 bit platform. I fired up PyCharm and put together a directory that looked like:
minu/
client.py
database.py
collection.py
test_client.py
test_database.py
test_client.py
My imports are simple. For example, client.py has the following at the top:
from collection import Collection
Basically, client has a Client class, collection has a Collection class, and database has a Database class. Not too tough.
As long as I cd into the minu directory, I can fire up a python3 interpreter and do things like:
>>> from client import Client
>>> c = Client(pathstring='something')
And everything just works. I can run the test_files as well, which use the same sorts of imports.
I'd like to modularize this, so I can use it another project by just dropping the minu directory alongside my application's .py files and just have everything work. When I do this though, and am running python3 from another directory, the local imports don't work. I placed an empty init.py in the minu directory. That made it so I could import minu. But the others broke. I tried using things like from .collection import Collection (added the dot), but then I can't run things in the original directory anymore, like I could before. What is the simple/right way to do this?
I have looked around a bit with Dr. Google, but none of the examples really clarify it well, feel free to point out the one I missed
In this file ...minu/__init__.py import the submodules you wish to expose externally.
If the __init__.py file contains the following lines, and the client.py file has a variable foo.
import client
import collection
import database
Then from above the minu directory, the following will work:
from minu.client import foo

Resources