This assumes you are using Python 3. (I am also using Git Bash as my shell)
Venv
Setup a virtual environment
It is a good idea to install packages in virtual environment so that we do not clutter our main python install, and we can easily get rid of the packages if we want. First we need to create the virtual enveronment. Navigat to a folder where you want your venv and type cd into it and then run:
winpty python3 -m venv /path/to/new/virtual/environment
Note if you use Git Bash you need to use the winpty utility to run some programs. See here for more info
What this will do is to create a virtual environment (inside a new folder called venv) that will be placed inside the current directory. The next step is to activate the environment, we do this by runnung:
. venv/Scripts/activate
If the venv was activated your terminal should display (venv) in front of the drive letter.
If you wish to deactivate the venv run this:
deactivate
Use the venv in SublimeText
There are probably better ways of running a venv in sublime but this brute force method works fine. Just add a new build system and point it to the python.exe in you venv.
{
"cmd": ["C:/path/to/venv/Scripts/python.exe", "-u", "$file"],
"selector": "source.python",
"file_regex": "^\\s*File \"(...*?)\", line ([0-9]*)"
}
Pip
To see which packages that are already installed we can ran:
pip list
Package Version
---------- -------
pip 20.2.1
setuptools 49.2.1
Path
Relative
rel_dir_str = '../B'
root_path_str = 'C:/Path/To/Dir/A'
rel_path = Path(root_path_str).joinpath(rel_dir_str)
print(rel_path) # C:\Path\To\Dir\A\..\B
abs_path = rel_path.resolve()
print(abs_path) # C:\Path\To\Dir\B
abs_path_str = str(abs_path).replace('\\', '/')
print(abs_path_str) # C:/Path/To/Dir/B
Dictionary
Sorting
Sort a list of dicts based on dict value
list_of_dicts = [
{'name': 'b', 'package_path': '/Game/Mesh/barrier/wall_end_0'},
{'name': 'a', 'package_path': '/Game/Mesh/barrier/wall_mid_0'},
{'name': 'c', 'package_path': '/Game/Mesh/barrier/wall_start_0'}
]
for info_dict in sorted(list_of_dicts, key=lambda d: d['name']) :
print(info_dict)
Sorting dicts
data = {'B':(2, 1), 'C':(0, 2), 'A':(1, 0)}
print(dict(sorted(data.items())))
# {'A': (1, 0), 'B': (2, 1), 'C': (0, 2)}
print(dict(sorted(data.items(), key=lambda item: item[1][0])))
# {'C': (0, 2), 'A': (1, 0), 'B': (2, 1)}
print(dict(sorted(data.items(), key=lambda item: item[1][1])))
{'A': (1, 0), 'B': (2, 1), 'C': (0, 2)}
data = {'B':{'width':2, 'height':1}, 'C':{'width':0, 'height':2}, 'A':{'width':1, 'height':0}}
print(dict(sorted(data.items())))
# {'A': {'width': 1, 'height': 0}, 'B': {'width': 2, 'height': 1}, 'C': {'width': 0, 'height': 2}}
print(dict(sorted(data.items(), key=lambda item: item[1]['width'])))
# {'C': {'width': 0, 'height': 2}, 'A': {'width': 1, 'height': 0}, 'B': {'width': 2, 'height': 1}}
print(dict(sorted(data.items(), key=lambda item: item[1]['height'])))
# {'A': {'width': 1, 'height': 0}, 'B': {'width': 2, 'height': 1}, 'C': {'width': 0, 'height': 2}}
String
f-string
Padding
print(f"- {'left':<10}-")
# - left -
print(f"- {'right':>10}-")
# - right-
print(f"- {'center':^10}-")
# - center -
num = 1
print(f'{num:04}')
# 0001
Type Formating
number = 1024
padding = 10
print(f"{'decimal':<{padding}}{number:d}")
print(f"{'octal':<{padding}}{number:o}")
print(f"{'hex':<{padding}}{number:X}")
print(f"{'binary':<{padding}}{number:b}")
(Format Specification)[https://docs.python.org/3/library/string.html#format-specification-mini-language]
msg = 'hello'
fill = '-'
align = '^'
width = 24
print(f'{msg:{fill}{align}{width}}')
# ---------hello----------
fill = '.'
align = '<'
print(f'{msg:{fill}{align}{width}}')
# hello...................
regex
import re
RE_MULTI_SLASH_AND_SPACE = re.compile(r'[/ ]{2,}')
name_list = [
'/Game/ car/////wheel///////// ////last /',
'/Game /one two three// ///box///// / / / / / ////'
]
for name in name_list:
print(RE_MULTI_SLASH_AND_SPACE.sub('/', name))
# /Game/car/wheel/last/
# /Game/one two three/box/
REPLACE_LAST_DIGITS = re.compile(r'^(.*)_\d{2}$')
cam_name_list = [
'cam_A__adsdasdas_01',
'cam_A__adsdasdas_01_A',
'cam_B_02'
]
for name in cam_name_list:
m = REPLACE_LAST_DIGITS.match(name)
if m:
replaced_name = REPLACE_LAST_DIGITS.sub(r'\1', name)
print(f'Match\n\t{name} matched\n\t-> {replaced_name}\n')
else:
print(f'No Match\n\t{name}\n\tx\n')
Misc
Context Manager
class Thing(object):
def __init__(self):
super(Thing, self).__init__()
self.state = 'initial'
def reload(self):
self.state = 'reloaded'
def get_state(self):
return self.state
def set_state(self, state):
self.state = state
def __str__(self):
return self.state
class KeepState(object):
def __init__(self, thing):
self.thing = thing
self.state = thing.get_state()
def __enter__(self):
self.thing.reload()
return self.thing
# you do not need to return anything, but if you do not you cant use
# "as t" in "with KeepState(thing) as t:..."
# you could also return something else than jsut the "Thing" if the
# __enter__ method generates something you need in the with block
def __exit__(self, type, value, traceback):
self.thing.set_state(self.state)
thing = Thing()
print(thing) # State: initial
with KeepState(thing) as t:
print(t) # State: reloaded
print(thing) # State: reloaded
print(thing) # State: initial
Super
I stumbeled on an error when using QtWidgets.QStyledItemDelegate in PySide and realized it was caused by how I called the super class.
The old usage of super required an explicit passing of both the class and instance it must operate from, requiring a breaking of the DRY (Don’t Repeat Yourself) rule. This hinders any change in class name, and is often considered a wart by many.
The premise of the new super usage suggested is as follows:
super().foo(1, 2)
to replace the old:
super(Foo, self).foo(1, 2)
Function
You can call an instance method like class method by passing in an instance of the class… Weird thing to do, but I have done it sometimes when calling an instance method of a Qt widget when deving.
my_class.cool_function(my_class())
Module
If you want to import a module without it beeing on the sys.path you can do this
from importlib.machinery import SourceFileLoader
module_file_path = 'C:/path/to/module/cool_script.py'
my_module = SourceFileLoader("pet.external_drag_drop", module_file_path).load_module()
my_module.call_cool_def(arg_0, arg_1, ...)
Inspect
Module
If you want to get information of a module you can use the inspact module
import inspect
from pathlib import Path
import soputils
# Lets say we want the filepath to the soputils module
mod_path = inspect.getfile(soputils)
# you can use pathlib if you want to resolve the path to make it more readablr
print(Path(mod_path).resolve())
# lets print the source code of the module
print(inspect.getsource(soputils))
# you can getdoc to get documentation, which is None in this case...
inspect.getdoc(soputils)
Or you might want to open the actual module in a text editor
import inspect
import os
from pathlib import Path
import soputils
mod_path = inspect.getfile(soputils)
mod_dir = Path(mod_path).parent.resolve()
mod_file_name = Path(mod_path).name
print(f'Module:\n\t{mod_file_name}\nDir:\n\t{mod_dir}')
# open dir
# os.startfile(mod_dir)
# open file (be careful, do not edit and overwrite)
os.startfile(mod_path)
MRO
Method Resolution Order
MRO is a concept used in inheritance. It is the order in which a method is searched for in a classes hierarchy and is especially useful in Python because Python supports multiple inheritance.
In Python, the MRO is from bottom to top and left to right. This means that, first, the method is searched in the class of the object. If it’s not found, it is searched in the immediate super class. In the case of multiple super classes, it is searched left to right, in the order by which was declared by the developer. For example:
node = hou.node('/obj/geo1/null1')
node.__class__.__mro__
# (<class 'hou.SopNode'>, <class 'hou.Node'>, <class 'hou.NetworkMovableItem'>, <class 'hou.NetworkItem'>, <class 'object'>)
Environment variables
You can use os.environ to “inspect” environment variables
import os
for k, v in os.environ.items():
print(f'{k}={v}')
print(os.environ['OCIO'])
print(os.environ.get('OCIO'))
OS
environ
import os
os.environ['monty'] = 'python'
# note! On Windows, the keys are converted to uppercase.
name = os.environ['MONTY']
print(f'MONTY {name}')
# Note if we access dict in f-string we use outer double quotationmarks
print(f"MONTY {os.environ['MONTY']}")
```