Skip to main content

Rich Tong's Not-so-Famous Python Utilities

For convenience, some useful utilities because importing Python modules is pretty unfun and it is easy to just publish them to PyPi and use them everywhere.

Version 2 Logging

The previous version 1 logging required complex keeping of log names with a Log_root. Turns out after much reading this is much simpler than I thought. The trick is that all that is happening is that logging has virtual tree based on the name of the logger, so a logger named netqr.params means that in the directory ./netqr/params.py is where the module (that is the file) is located. This is kept in a dunder __name__

So instead of having to do base names and so forth, you can just calculate log names based on the name and then add some more information.

The way that this works is that you first create a logging.yaml that has the logging parameters. Then at the top of each file (aka module) you manipulate a global variable with this to get the current active loggers:

import logging
log = logging.getLogger(__name__)

This is the main thing needed because

In most cases though, you will actually be better off just adding different format strings since they have so much more data in them, for example, the name of the function and then the type s for string, d for digit, etc.

Note that you can also says 10s which means the first 10 characters of the string only and it becomes a fixed width field:

String Meaning
%{asctime}s LogRecord creation time
%{filename}s Current file
%{funcName}s Current function
%{levelname}s Logging level (eg DEBUG, INFO)
%{levelno}s Logging number {eg 1-100}
%{lineno}d Current line number
%{message}s Message of log
%{module}s File without the .py
%{name}s Name of the logger
%{pathname}s Full path of file
%{process}d Process id
%{processName}s Name of process
%{thread}d Thread id
%{threadName}s Thread name

So most of the time you will be fine with this level of detail, the main thing missing is that for class objects, you are missing some detail, but you know the file location and the line number.

The second trick is that if you want more logging detail then in a function you can create a logger by create more dotted names, :

import logging

# this logger will be used for all functions in this module
log = logging.getLogger(__name__)

class new_class():
  def __init__(self):
    # use the class logger for all methods that appends the class type to the
    # current file/module
    self.log = logging.getLogger(__name__ + '.' + type(self).__name__)

  def add():
    # log with the instance name and class type
    self.log("Entering a new method to add to the database")

Version 2 Logging helper function

This is much simpler than version 1 and the only helper needed is to load the YAML file with the configuration:

import logging
from pytong import config_log

# this is the module wide logging by setting a global variable
log = logging.getLogger(__name__)

# setLog creates a logger named <module path>/<class name>
@setLog
class test:
  def __init__(self):
    # the logger name is '__main__.test'
    self.log(f"In {self=}")

def main():
  config_log()
  # the logger name is '__main__' and funcname will be printed
  log.debug(f"{log=} created")

Version 1 Logging (deprecated)

Usage is pretty simple, we use inheritance to have the right logging compared with v2 which uses a class decorator.

from pytong import Log, BaseLog  #type: ignore

# then for each class you create have a log member to remember it
# set a log_root which is the top and then on each Class initiation
# instantiate a new class
# if you set this base class you get logging
class <Your Class>(BaseLog)
    # Use the decorator pattern that Keras and other use with chaining
    # so every class has a set_logger method that returns the class
    # this allows constructs like foo.set_logger.next_method...
    # note that we pass the name which is by default __name__
    # which for classes is the class name
    def set_logger(self, name: str = __name__) -> <Your Class>:
      """Set Log.

      Setup the root logger and log
      """
      self.log_root = Log(name)
      self.log = self.log_root.log
      return self

   def <some method>(self, <0ther functions>):
      # a convenience as self.log is a lot of typing
      log = self.log
      log.debug(f'I am here with {log=}')

Log by call tree

The logging module automatically creates loggers and lists logs by the call stack. It also sends different prefixes for class calls.

Building

You can install the needed pieces with and then upload to test.pypi.org or pypi.org

make pip-install
# edit .envrc with the your API Token for test do not include the pypi- that is
# added in the makefile
make test-pypi
# add the pypi api token without the pypi-
make pypi

Testing

The test scaffolding is not working yet.

File Layout

We adopt the scheme that seems a little redundent where we have a strudture that is ./pytong/src/pytong and the tests are in ./pytong/tests. Ionel explains why this is important. And also HYnek explains why as well.

The biggest reason for this is that you are forced to install code and can check for packaging breaks. And you don't want to include test modules with your source code.

Release files for pytong 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytong 0.2.2
File Size Uploaded
pytong-0.2.2.tar.gz 10.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pytong 0.2.2
File Interpreter ABI Platform
pytong-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 20.4 kB

Release files / pytong-0.2.2.tar.gz

Download URL pytong-0.2.2.tar.gz
Size 10.8 kB
Tags Source
SHA-256 checksum
How to use checksums
55f8149d05f00b6230038aed9a7c11bf0c6a12024b2ab5c7810ad8d95610356a
BLAKE2b-256 checksum
How to use checksums
e02037cde265ca82cf27c9192dd991e6a49876b5eb406b9b023a178f20badf33
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.7

Release files / pytong-0.2.2-py3-none-any.whl

Download URL pytong-0.2.2-py3-none-any.whl
Size 9.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1566422b86725f56316219c63454405708ffe3190070997c19c4d6e730dfbcd8
BLAKE2b-256 checksum
How to use checksums
fa77ae58a5fdfee02a9fe2aa0e684687ae2670d65cf0c354d91daa00163c8c48
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.7

Release history Release notifications | RSS feed

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.1.1

2 release files

0.0.11

2 release files

0.0.10

2 release files

0.0.9

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page