Here you can find a couple of tutorials. Mostly they help me to remember stuff. Code boxes based on prism.js.

Loading ..

Windows


Edit context menu

Open registry editor and navigate to the following location(s) and put a minus sign in front of key-values to hide menu (allows to enable them again later):
HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers
HKEY_CLASSES_ROOT\*\shell
HKEY_CLASSES_ROOT\AllFileSystemObjects\ShellEx\ContextMenuHandlers
For folders:
HKEY_CLASSES_ROOT\Folder\shellex\ContextMenuHandlers
HKEY_CLASSES_ROOT\Directory\shell
For desktop:
HKEY_CLASSES_ROOT\Directory\Background\shell
HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers

Linux


Move files with progress indicator

rsync --r --progress source destination

Copy remote files via SSH

Copy local file to remote SSH host (port: 1234, remote username: user, remote address can be ip aswell):
scp -P 1234 localfile.txt [email protected]:/path/to/remote/folder
Alternatively with rsync to show progress (-avz applies compression to reduce transmitted data):
rsync -rsh='ssh -p1234' -avz localfile.txt [email protected]:/path/to/remote/folder
Copy file from remote SSH host to local drive:
scp -P 1234 [email protected]:/path/to/remote/filename.txt /path/to/local/folder
Alternatively with rsync to show progress:
rsync -rsh='ssh -p1234' -avz [email protected]:/path/to/remote/filename.txt /path/to/local/folder

Cleanup apt sources

# get latest release from github
wget https://github.com/davidfoerster/aptsources-cleanup/releases/download/v0.1.7.5.2/aptsources-cleanup.pyz
# give file executable rights
chmod a+x aptsources-cleanup.pyz
# run
sudo ./aptsources-cleanup.pyz
Cleanup apt sources list manually:
sudo nano /etc/apt/sources.list

GIT


Show branches:
git branch
Show branches including remote branches:
git fetch && git branch -a
Checkout a branch 'test':
git fetch && git checkout test
Add and push:
git add filename.txt  # stage a single file
git add --all  # stage all changes
git commit -m "commit message"
git push
Global config username & email:
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
Merge remote repository into current branch:
# create new branch 'test' in repository and checkout
git branch test && git fetch && git checkout test
# add remote repository
git remote add remote-test https://github.com/Mnikley/Some-Test-Repo.git
# fetch remote repo
git fetch remote-test
# merge repos
git merge remote-test --allow-unrelated-histories
git merge remote-test/branch_name --allow-unrelated-histories  # to merge certain branch
# resolve conflicts in .gitignore if there are any, delete stuff in .gitignore (>>>HEAD usw.)
git add .gitignore
git commit -m "Initial test-branch commit"
git push
# move merged old repository to new subfolder (by hand / in explorer)
# remove old remote repo
git remote rm remote-test
# add changes, commit and push
git add *
git commit -m "Merged remote-branch to subfolder FOLDERNAME"
git push
Merge 'test' branch into 'develop' branch:
git fetch && git checkout test
git pull  # fetch latest changes
git fetch && git checkout develop
git merge test
git commit -m "Merged test into develop"
git push
Show tags:
git tag
Create annotated tag:
git tag -a v1.5.12 -m "Bugfix for some function" && git push
Create annotated tag and push to master (release)
git tag -a v2.0 -m "Release codename 'XY'" && git push origin --tags
Delete a tag:
git tag -d v1.5.0 && git push
Revert changes to last commit:
git reset --hard
Get release information:
git describe
git describe branchname
Check history of a file:
git log --follow -p -- filename.txt
Get log of repository:
# standard
git log
# only id and commit text
git log --oneline
# pretty
git log --pretty=format:"%h%x09%an%x09%ad%x09%s"
# tags
git log --oneline --decorate --tags --no-walk
git log --oneline --decorate --tags
# graph with lines
git log --all --decorate --oneline --graph
Toubleshoot if file was already indexed and added to .gitignore later:
git rm --cache path_to_file/added_to_gitignore.txt
git add --all && git commit -m “removed XY from commit” && git push
# alternatively
git rm -r --cached .
git add .

Various stuff


JetBrains

My JetBrains config (pyCharm, intelliJ)

FFmpeg

Download FFmpeg

Convert x265 to x264:
ffmpeg -ss 00:03:00 -i "input file x265.mkv" -t 00:00:50 -map 0 -c copy -c:v libx264 -crf 18 "output file x264.mkv"
Cut from:to [hh:mm:ss]:
ffmpeg --ss 00:03:00 -i "inputfile.mp4" -to 00:05:00 "outputfile.mp4"
Remove audio track #3 (index starts at 0):
ffmpeg -i input -map 0 -map -0:a:2 -c copy output
Windows batch file (1080p.bat) to convert to 1080p x264 - batch file content (replace path to ffmpeg.exe):
"C:\FFMPEG\bin\ffmpeg.exe" -i %1 -c:a aac -b:a 128k -c:v libx264 -b:v 4500k -vf scale=-1:1080 -preset veryslow -crf 24 %~n1_web.mp4
Windows batch file (1080p.bat) to convert to 1080p x264 - call:
1080p yourfile.mp4

Sublime Text

Install package control:
CTRL + Shift + P --> Package Control Install --> Enter
Install and set theme:
CTRL + Shift + P --> Package Control: Install Packages --> Agila Theme --> Enter
CTRL + Shift + P --> UI: Select Theme --> Agila.sublime-theme --> Enter
My sublime config:
CTRL + Shift + P --> Preferences: Settings --> Enter --> Copy paste next block to right column
// Settings in here override those in "Default/Preferences.sublime-settings",
// and are overridden in turn by syntax-specific settings.
{
	"theme": "Default Dark.sublime-theme",
	"auto_hide_menu": true,
	"auto_hide_tabs": true,
	"auto_hide_status_bar": true,
	"overlay_scroll_bars": "enabled",
	"enable_tab_scrolling": false,
	"font_face": "consolas",
	"margin": 0,
	"animation_enabled": false,
	"font_size": 11,
	"hot_exit": false,
	"remember_layout": false,
	"remember_open_files": false,
	"ignored_packages":
	[
		"Vintage",
	],
}

Tools

  • OOSU10 - great tool to disable certain privacy-concerning windows services. Also, here is my config.
  • CPU-Z - information of your processor, mainboard, chipset, memory etc.
  • MemTest64 - test your memory on a hardware level
  • EcMenu - tool to customize the Windows context menu
  • HackBGRT - change the Windows boot logo
  • PeerBlock - nice freeware firewall, some lists require subscriptions though
  • Everything - locate files and folders on your PC instantly
  • GIMP - free image manipulation
  • Inkscape - free vector image tool
  • Flameshot - a simple screenshot app, useful for documentation

Linux Server


General

First-time connect to ubuntu server via SSH (pw=ubuntu):
ssh ubuntu@IPADDRESS
# if necessary, add entry in C:\users\USER\.ssh\known_hosts
192.168.0.80 ecdsa-sha2-nistp256 KEYFROMCOMMANDLINE
# upgrade packages
sudo apt update
sudo apt upgade

List all users:
compgen -u

Create backup image:
# find device name
sudo fdisk -l
# create image (replace device name)
sudo sudo dd bs=4M if=/dev/mmcblk0 of=backup.img
# flash SD card from image
sudo dd bs=4M if=backup.img of=/dev/mmcblk0
# windows: DL https://etcher.io/ > chose backup image > chose sd card > click "Flash"

Systemctl commands (substitute apache2 for any service):
# start service
sudo systemctl start apache2
# restart service
sudo systemctl restart apache2
# stop service
sudo systemctl stop apache2
# reload without dropping connections
sudo systemctl reload apache2
# disable autostart
sudo systemctl disable apache2
# enable autostart
sudo systemctl enable apache2

Install Webmin - an awesome server webinterface for various operations (tutorial):
sudo nano /etc/apt/sources.list
# copy paste: deb http://download.webmin.com/download/repository sarge contrib
wget -q -O- http://www.webmin.com/jcameron-key.asc | sudo apt-key add
sudo apt update
sudo apt install webmin
# start using webmin via LOCALIP:10000

PiHole Setup

Pi-hole basically gives you network-wide ad blocking. Check the official documentation here and here.
# add as first line to sudo nano /etc/resolv.conf:
nameserver 127.0.0.1
# install pihole - WARNING - Install Web Interface during install but DO NOT INSTALL WEBSERVER
curl -sSL https://install.pi-hole.net | bash
# edit sudo nano /etc/lighttpd/lighttpd.conf:
server.port = 10001
# add to UFW
sudo ufw allow 10001
# restart lighttpd service:
sudo systemctl restart lighttpd
# check services
service --status-all
# access webinterface
http://192.168.0.80:10001/admin
FIX if installed with webinterface and previous apache webserver is not working anymore:
pihole uninstall
cd /etc/apache2/sites-available
sudo a2ensite leysolutions.conf
sudo systemctl restart apache2
apachectl -t
apachectl -f /etc/apache2/apache2.conf -k stop
apachectl -f /etc/apache2/apache2.conf -k start
sudo /etc/init.d/apache2 start
sudo apachectl -f /etc/apache2/apache2.conf -k start
sudo reboot

UFW - Uncomplicated Firewall

Just a very simple firewall to allow certain ports for communication to the LAN. Some basic commands:
# see available applications
ufw app list
# allow OpenSSH
ufw allow OpenSSH
# enable, check status
ufw enable
ufw status
ufw status verbose
ufw status numbered
ufw app info OpenSSH
# delete
sudo ufw delete NUM
Create a custom profile:
sudo nano /etc/ufw/applications.d/custom.ufw.profile
# copy paste
[Webmin]
title=Webmin Server Webinterface
description=intern 10000 extern 1005
ports=10000

[Postgres]
title=PSQL Server
description=intern 5432 extern 1004
ports=5432

[Mail]
title=Mail server ports
description=intern extern gleich 587 993  intern 25 extern 1025
ports=25,578,993/tcp

[Webmail]
title=Webmail port
description=intern extern gleich 8983 11334
ports=8983,11334/tcp
Allow sections from custom profile:
sudo ufw allow Webmin
sudo ufw allow Postgres
sudo ufw allow Mail
sudo ufw allow Webmail

Apache Web Server

Install apache (tutorial):
sudo apt install apache2
sudo ufw allow "Apache Full"
curl -4 icanhazip.com
# go to browser, check http://IPADDRESS > see if it works (not https yet)
# create directory for webserver content
sudo mkdir /var/www/leysolutions
sudo chown -R $USER:$USER /var/www/leysolutions
sudo chmod -R 755 /var/www/leysolutions
# copy repo into /var/www/leysolutions if you have one, otherwise start with raw index.html
cd /var/www/leysolutions
# this will not work without auth, since my repository is private
git clone https://github.com/mnikley/Pi.git
# create venv
sudo apt-get install python3-venv
python3 -m venv venv
# set include-system-site-packages to true in pyvenv.cfg
sudo nano venv/pyvenv.cfg
# activate venv, install dependencies
. venv/bin/activate
pip install --upgrade pip
pip install wheel
pip install flask-blogging flask-sqlalchemy flask-migrate flask-admin
pip install plotly pandas numpy --user
sudo apt-get install gcc
sudo apt-get install build-essential
sudo apt install libpython3.8-dev
pip install uwsgi
# go to sites-enabled, copy/rename default conf, edit
cd /etc/apache2/sites-available
sudo cp 000-default.conf leysolutions.conf
sudo mv 000-default.conf 000-default.conf.old
# copy paste to leysolutions.conf:
<VirtualHost _default_:80>
        ServerName leysolutions.com
        ServerAdmin matthias@localhost
        Serveralias www.leysolutions.com
        WSGIDaemonProcess piapp user=ubuntu group=www-data threads=5
        WSGIScriptAlias / /var/www/leysolutions/Pi/wsgi.py
        <Directory "/var/www/leysolutions/Pi">
                WSGIProcessGroup piapp
                WSGIScriptReloading On
                WSGIApplicationGroup &{GLOBAL}
                Require all granted
        </Directory>
	# SSLEngine off
	# SSLCertificateFile /home/pi/ssl/server.crt
	# SSLCertificateKeyFile /home/pi/ssl/server.key
</VirtualHost>
# enable site
sudo /usr/sbin/a2ensite leysolutions.conf
# reload apache
sudo systemctl reload apache2
# if not working, go to /etc/apache2/sites-available
sudo a2dissite 000-default.conf
sudo a2dissite leysolutions.com
sudo systemctl reload apache2
sudo apt install libapache2-mod-wsgi-py3 -y
If its not working, follow this tutorial.
Apache - create certificate (source):
# create server key server.key
openssl genrsa -des3 -out server.key 2048
# create signing request server.csr
openssl req -new -key server.key -out server.csr
# go to cloudflare, get csr signed
# check status
openssl x509 -noout -text -in server.crt
#config apache:
SSLCertificateFile    "/path/to/this/server.crt"
SSLCertificateKeyFile "/path/to/this/server.key"
# csr can be deleted

PostgreSQL

PostgreSQL is an open-source relational database which has nice tools for administration, such as pgAdmin for Windows.

Install PostgreSQL:
# install postgreSQL
sudo apt update
sudo apt install postgresql postgresql-contrib
# check if process is up
sudo systemctl status postgresql
Intermediate steps (optional):
# edit sudoers file
sudo nano /etc/sudoers
# copy paste below %admin
user_name ALL=(ALL)  ALL
# save, quit; create db flask, add user flask
createdb flask
sudo adduser flask
# enable psql as a service
sudo systemctl enable postgresql.service
# edit psql config, uncomment connection="localhost" and change to ="*"
sudo nano /etc/postgresql/12/main/postgresql.conf
# edit pg_hba.conf and add (subtitute XYZ123 for your real IP address):
host    all             all             XYZ123/32       trust
host	all		all		192.168.0.1/32		trust
# install dependencies
sudo apt install libpq-dev
# activate VENV (substitute VENVPATH with your local path to do your venv)
source VENVPATH/bin/activate
# install dependencies
pip install psycopg2-binary
# navigate to root folder of your project (substitute PROJECTROOT)
cd PROJECTROOT
# do some flask migration stuff
flask db stamp head
flask db migrate
flask db upgrade
Use the PostgreSQL console:
# switch to postgres user
sudo su postgres
# start psql console
psql
# show config
SHOW hba_file;
# edit pg_hba.conf and add:

# list dbs
\l
# create database
CREATE DATABASE flaskdb;
# change db
\c flaskdb;
# display everything from table 'info_table'
SELECT * FROM info_table
Edit the PostgreSQL config:
# change back to original user (undo sudo su postgres)
exit
sudo nano /etc/postgresql/11/main/pg_hba.conf
sudo nano /etc/postgresql/11/main/postgresql.conf
Restart PostgreSQL:
sudo /etc/init.d/postgresql restart
Localize PostgreSQL:
which psql
Change PW of postgres user PostgreSQL:
sudo -u postgres psql
\password postgres  # -> Enter PW
\q
Connect PostgreSQL with Flask (Tutorial):
# https://www.askpython.com/python-modules/flask/flask-postgresql
cd /var/www/folder_to_your_project
# optional: activate venv if you have any
source venv/bin/activate
# install dependencies
sudo python3 -m pip install psycopg2-binary
sudo python3 -m pip install flask-sqlalchemy
sudo python3 -m pip install flask-migrate
# set environmental variable, replace piapp.py
export FLASK_APP=piapp.py
# migrate database
flask db init
flask db migrate
flask db upgrade

GIT authentication for server

Generate new SSH key on server (source):
cd /var/www/leysolutions
ssh-keygen -t rsa -b 4096 -C "[email protected]"
# save as: github_mnikley; no password-phrase etc
cd Pi
eval "$(ssh-agent -s)"
ssh-add ../github_mnikley
cat ../github_mnikley.pub
# Copy paste key to clipboard, remove email at end
Add SSH key to github (source):
  1. goto github.com > profile (top right) > settings
  2. user settings > SSH and GPG keys
  3. click New SSH key or Add SSH key
  4. paste SSH key

Python


General

Cool string formatting:
var = "foo"
f"{var!s}"

Sphinx

Install Sphinx & rtd-theme, Quickstart:
pip install sphinx sphinx-rtd-theme
# Navigate to your project folder
# Create docs subfolder
mkdir docs
# Change folder to docs
cd docs
# Start sphinx quickstart
sphinx-quickstart
Edit the conf.py (tutorial):
# uncomment & modify the following lines:
import os
import sys
sys.path.insert(0, os.path.abspath(".." + os.sep + ".."))
# specify project information, add extensions:
extensions = ["sphinx.ext.napoleon",
              "sphinx.ext.todo",
              "sphinx.ext.autodoc",
              "sphinx.ext.viewcode",
              "sphinx.ext.autosummary"]
# set RTD theme
html_theme = 'sphinx_rtd_theme'
# add line for logo (logo must be relative to source folder)
html_logo = ".." + os.sep + ".." + os.sep + "static" + os.sep + "icon_dev.ico"
# define napoleon and TODO settings
napoleon_google_docstring = False
napoleon_numpy_docstring = True
napoleon_include_init_with_doc = False
napoleon_include_private_with_doc = False
napoleon_include_special_with_doc = True
napoleon_use_admonition_for_examples = True
napoleon_use_admonition_for_notes = True
napoleon_use_admonition_for_references = False
napoleon_use_ivar = False
napoleon_use_param = True
napoleon_use_rtype = True
napoleon_preprocess_types = False
napoleon_type_aliases = None
napoleon_attr_annotations = True
todo_include_todos = True
Populate .rst files - Example folder structure:
root_folder/
|-- docs/
|   |-- build/
|   |-- source/
|   |   |-- conf.py
|   |   |-- doc_frontend.rst
|   |   |-- doc_library.rst
|   |   |-- doc_library_utils.rst
|   |   |-- doc_library_video.rst
|   |   |-- doc_library_backend.rst
|   |   |-- doc_quickstart.rst
|   |   |-- doc_static.rst
|   |   |-- index.rst
|   |   |-- screenshot_one.jpg
|   |   `-- screenshot_two.jpg
|   |-- make.bat
|   `-- Makefile
|-- lib/
|   |-- utils.py
|   |-- video.py
|   `-- backend.py
|-- static/
|   `-- icon_dev.ico
|-- app.py
`-- requirements.txt
index.rst example:
===========================================
Welcome to the documentation of project XY!
===========================================
This documentation is based on the docstring comments in the related python files (numpy format). Package dependencies
are specified in the requirements.txt, which should work for Linux and Windows.
The most relevant files of this project can be found :ref:`here <usefullinks>`.

First Launch
############
After the first launch of the application, do:
- this
- and that (or navigate to ``some\path``)

.. toctree::
   :maxdepth: 1
   :caption: Quickstart
   :hidden:

   Quickstart <doc_quickstart.rst>

.. toctree::
   :maxdepth: 2
   :caption: Python Documentation
   :hidden:

   Frontend <doc_frontend.rst>
   Backend <doc_library.rst>

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
doc_quickstart.rst example:
============
Useful links
============

.. _usefullinks:

Additional documentation files can be found at the following locations:
    - Requirements: ``project_folder/requirements.txt``
    - `InnoSetup <https://jrsoftware.org/isdl.php>`_ config: ``path/to/innosetup/conf.iss``
    - `MongoDB web interface <https://cloud.mongodb.com/>`_
    - `HTerm for serial debugging <https://www.der-hammer.info/pages/terminal.html>`_
    - `FTDI drivers <https://ftdichip.com/drivers/d2xx-drivers/>`_
    - `Tips for docstring formatting <https://thomas-cokelaer.info/tutorials/sphinx/rest_syntax.html#simple-tables>`_


=====
Usage
=====

Control panel
=============

You can do this and that.
- The **Control Panel** is great
- But also not that great

.. figure:: screenshot_one.png
    :width: 200px
    :height: 100px
    :alt: This is a screenshot of the control panel

Support panel
=============
The **Support Panel** is also pretty good, and might include some useful `links <https://www.google.at>`_.
doc_frontend.rst example:
========
Frontend
========
This section describes the frontend of the application

Main UI class
#############
.. autoclass:: app.UI
  :members:

Logger class
############
.. autoclass:: app.Logger
    :members:

ToolTip class
#############
.. autoclass:: app.ToolTip
    :members:

Module functions
################
.. automodule:: app
    :members:
    :exclude-members: UI, Logger, ToolTip
doc_library.rst example:
=======
Backend
=======

This is the overhead of the backend library describing all submodules

.. toctree::
   :maxdepth: 2
   :caption: Documentation of the backend library

   utilities <doc_library_utils.rst>
   video tools <doc_library_video.rst>
   backend tools <doc_library_backend.rst>


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
doc_library_video.rst example:
T3_video
========

Examples
########

transformation example
**********************
.. figure:: screenshot_two.png
    :width: 200px
    :height: 100px
    :alt: Video transform example

Module functions
################
.. automodule:: lib.video
	:members:
Build a html template:
make html

Numpy docstring examples (additional source)

class Cars():
    """This is an example class showing the numpy docstring format
    - Author: Matthias Ley
    - Created: 31.10.2021
    - Some other information

    Examples
    --------
    This is an example block with a code example::

        from this_lib import Cars
        c = Cars()  # create an instance of the Cars class
        c.cars_available()  # get available cars
    """
    def __init__(self, param1, param2, param3):
        """Example of docstring on the __init__ method.

        The __init__ method may be documented in either the class level
        docstring, or as a docstring on the __init__ method itself.

        Either form is acceptable, but the two should not be mixed. Choose one
        convention to document the __init__ method and be consistent with it.

        Note
        ----
        Do not include the `self` parameter in the ``Parameters`` section.

        Parameters
        ----------
        param1 : str
            Description of `param1`.
        param2 : list(str)
            Description of `param2`. Multiple
            lines are supported.
        param3 : :obj:`int`, optional
            Description of `param3`.

        """
        self.attr1 = param1
        self.attr2 = param2
        self.attr3 = param3  #: Doc comment *inline* with attribute

        #: list(str): Doc comment *before* attribute, with type specified
        self.attr4 = ["attr4"]

        self.attr5 = None
        """str: Docstring *after* attribute, with type specified."""

    my_cars = 5

    def cars_available(self):
        """Class function that returns some integer

        Returns
        -------
        my_cars : int
            An integer defined in the class

        Todo
        ----
        This block is highlighted
        """
        return self.my_cars

    def _private(self):
        """By default private members are not included.

        Private members are any methods or attributes that start with an
        underscore and are *not* special. By default they are not included
        in the output.

        This behavior can be changed such that private members *are* included
        by changing the following setting in Sphinx's conf.py::

            napoleon_include_private_with_doc = True

        """
        pass


def write_data(c=None, name="Matthias", data={}):
    """This is an ordinary function with a couple of arguments and returns

    Parameters
    ----------
    c : this_lib.Cars
        Cars object instance
    name : string
        Some name
    data : dict
        - Some data dictionary
        - Very important for the Cars class

    Returns
    -------
    string
        Some status message including the handed over name

    Notes
    -----
    This is a highlighted notes block, which can also include code.
    Make sure to add an empty line and a tab after the doubledots::

        some_code = "Is great"
    """
    if not c:
        print("No cars class instanced")
        return

    return f"Thank you for your submission {name}"


def example_generator(n):
    """Generators have a ``Yields`` section instead of a ``Returns`` section.

    Parameters
    ----------
    n : int
        The upper limit of the range to generate, from 0 to `n` - 1.

    Yields
    ------
    int
        The next number in the range of 0 to `n` - 1.

    Examples
    --------
    Examples should be written in doctest format, and should illustrate how
    to use the function.

    >>> print([i for i in example_generator(4)])
    [0, 1, 2, 3]

    """
    for i in range(n):
        yield i


def module_level_function(param1, param2=None, *args, **kwargs):
    """This is an example of a module level function.

    Function parameters should be documented in the ``Parameters`` section.
    The name of each parameter is required. The type and description of each
    parameter is optional, but should be included if not obvious.

    If ``*args`` or ``**kwargs`` are accepted,
    they should be listed as ``*args`` and ``**kwargs``.

    The format for a parameter is::

        name : type
            description

            The description may span multiple lines. Following lines
            should be indented to match the first line of the description.
            The ": type" is optional.

            Multiple paragraphs are supported in parameter
            descriptions.

    Parameters
    ----------
    param1 : int
        The first parameter.
    param2 : :obj:`str`, optional
        The second parameter.
    *args
        Variable length argument list.
    **kwargs
        Arbitrary keyword arguments.

    Returns
    -------
    bool
        True if successful, False otherwise.

        The return type is not optional. The ``Returns`` section may span
        multiple lines and paragraphs. Following lines should be indented to
        match the first line of the description.

        The ``Returns`` section supports any reStructuredText formatting,
        including literal blocks::

            {
                'param1': param1,
                'param2': param2
            }

    Raises
    ------
    AttributeError
        The ``Raises`` section is a list of all exceptions
        that are relevant to the interface.
    ValueError
        If `param2` is equal to `param1`.

    """
    if param1 == param2:
        raise ValueError('param1 may not be equal to param2')
    return True

Logger

Simple example of how to use a logger to log to a file and console at the same time. Refer to the logging docs for an overview of available attributes.
import logging
# setup logging to file
logging.basicConfig(filename="test.log",
                    filemode="a",
                    format="[%(asctime)s:%(msecs)d]\t%(filename)s\t%(funcName)s\t%(lineno)d\t%(module)s\t%(message)s",
                    datefmt="%Y/%m/%d-%H:%M:%S",
                    level=logging.DEBUG)

# set up logging to console
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
# simpler format for console
formatter = logging.Formatter('%(filename)s\t%(funcName)s\t%(lineno)d\t%(module)s\t%(message)s')
console.setFormatter(formatter)
# add handler to root logger
logging.getLogger('').addHandler(console)
logger = logging.getLogger(__name__)


def some_func():
    x = 5
    logger.info(f"X is {x}")
    logger.warning("Dont let it go below 10!")


logging.info("test from outside")
some_func()