Configure isort to be compatible with flake8-import-order - flake8

The pre-commit of our project is using flake8-import-order to ckeck import order validity.
I use to re-order imports using isort which produce an incompatible result specifically concerning the imports of the same sections.
isort doesn't insert a blank line between each different packages in the same section whereas flake8-import-order (I202) expect one
Did someone succeed to configure isort to make it compatible with flake8-import-order ?
my_pkg_1 and my_pkg_2 are both "first party" for isort, but I want this result :
# known_first_party=my_pkg_1,my_pkg2
from my_pkg_1 import XXX
from my_pkg_1.AAA import YYY
from my_pkg2 import ZZZ
I know I can create custom sections using known_XXX but this django project have a lot of local packages.

Related

How to import whole python file and not break F403 flake8 rule?

Imports like this:
from .file import *
are "anti-patterns". How can I import one python file into another, without breaking flake8 F430 rule? I have settings.py in the Django project that I want to "overwrite" in test_settings.py like this,
from settings import *
# make tests faster
DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
to test with in-memory database, and I cant figure out how to do it without breaking the rule.
According to authors of the book "Two Scoops of Django 3.x" this is actually an exception when they advocate using
import *
the singular case of Django setting modules we want to override all the namespace
in order to allow usage of multiple settings files. Therefore in this situation, the best solution is to exclude test_settings.py from the flake8 scan, in the flake8 configuration file.

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.

Python 3.5 How do I list classes/functions available in an import package?

I'm porting all my Python code from 2.7 to 3.5 and keep running into issues where my imported packages don't contain the same classes/functions as they did in 2.7. I DO NOT want to use one of the methods where you can support both 2.7 and 3x. I'm dropping 2.7 entirely.
Is there a way to search an imported package for a specific thing or to list the classes/functions in a nested display?
Right now, I'm trying to find the escape_string() function in mysql-connector-python (v8x) but I keep needing something to explore packages. The docs for the mysql-connector-python package say that it's in mysql.connector.MySQL but there's no such attribute.
Thanks...
If you believe the documentation is wrong, I would open an issue with them and also double and triple check that you have installed the correct package.
To list the classes/functions of a module you can use:
import os # or whatever
print(list(os.__dict__.keys()))

Sublime Text 3 Creating Plugin adding external python libraries

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.

yaml octal integer generate errors

In my YAML file I have the below entry:
- type: dir
name: .ssh
chmod: 0o700
According to the YAML 1.2 specification section 3.2.1.3 the 0o700 is the way to specify octals (there is also an example in section 2.4)
However when I process the loaded file and do:
import os
import yaml
filename = "in.yml"
with open(filename) as fp:
for e in yaml.load(open(filename)):
if e['type'] == 'dir':
os.mkdir(e['name'], e['chmod'])
I get TypeError: an integer is required. What is going wrong here?
I am using Python 3.5
What's wrong is that you assume that your YAML library supports the latest version 1.2. That YAML version is from 2009, but you are using PyYaml and that still only supports 1.1. From the non-activity the last few years it seems to be a dead project, so don't expect this to be solved any time soon.
You can add
from yaml.resolver import Resolver
Resolver.add_implicit_resolver(
'tag:yaml.org,2002:int',
re.compile(r'''^(?:[-+]?0b[0-1_]+
|[-+]?0o?[0-7_]+
|[-+]?0[0-7_]+
|[-+]?(?:0|[1-9][0-9_]*)
|[-+]?0x[0-9a-fA-F_]+
|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),
list('-+0123456789'))
in your program to add recognition of 0o123 kinda octals (it also still recognizes the 1.1 octals).
Please note that the above only works for Python 3, as PyYaml has different code for Python 2.
You should also consider using pathlib.Path types and their .mkdir() instead of os.mkdir()
Install ruamel.yaml ( pip install ruamel.yaml ). It defaults to loading 1.2 as documented here:
unless the YAML document is loaded with an explicit version==1.1 or the document starts with:
% YAML 1.1
, ruamel.yaml will load the document as version 1.2.
and
YAML 1.2 no longer accepts strings that start with a 0 and solely consist of number characters as octal, you need to specify such strings with 0o[0-7]+ (zero + lower-case o for octal + one or more octal characters).

Resources