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']}")
```