18.1. Modules Stdlib

  • Python Standard Library

  • pprint

  • random

  • datetime + zoneinfo

  • pathlib

  • logging

  • json

  • csv

  • itertools

  • re

  • dataclasses

  • doctest

  • unittest

18.1.1. PPrint

SetUp:

>>> from pprint import pprint

Pretty print:

>>> data = [[1,2,3], [4,5,6], [7,8,9]]
>>>
>>> pprint(data, width=20, sort_dicts=False)
[[1, 2, 3],
 [4, 5, 6],
 [7, 8, 9]]

18.1.2. Random

SetUp:

>>> from random import random, randint, choice, shuffle, sample, seed
>>> seed(0)

Generate random float between 0.0 and 1.0:

>>> random()
0.8444218515250481

Generate random integer between a and b (both ends inclusive):

>>> randint(0, 10)
6

Select k elements from data:

>>> data = ['red', 'green', 'blue']
>>>
>>> sample(data, k=2)
['red', 'green']

Select one from data:

>>> data = ['red', 'green', 'blue']
>>>
>>> choice(data)
'blue'

Shuffle data:

>>> data = ['red', 'green', 'blue']
>>>
>>> shuffle(data)
>>> print(data)
['red', 'blue', 'green']

18.1.3. Datetime

SetUp:

>>> from datetime import date, time, datetime, timezone, timedelta
>>> from zoneinfo import ZoneInfo

Create objects:

>>> d = date(2000, 1, 1)
>>> t = time(1, 2, 3, 4)
>>> dt = datetime(2000, 1, 1, 1, 2, 3, 4)

Get date and time from datetime:

>>> dt = datetime(2000, 1, 1, 1, 2, 3, 4)
>>>
>>> dt.date()
datetime.date(2000, 1, 1)
>>>
>>> dt.time()
datetime.time(1, 2, 3, 4)

Get parts from datetime:

>>> dt = datetime(2000, 1, 1, 1, 2, 3, 4)
>>>
>>> dt.year
2000
>>> dt.month
1
>>> dt.day
1
>>> dt.hour
1
>>> dt.minute
2
>>> dt.second
3
>>> dt.microsecond
4

Current date and time in local timezone:

>>> date.today()
datetime.date(2000, 1, 1)
>>>
>>> datetime.now()
datetime.datetime(2000, 1, 1, 0, 1, 2, 3)

Current date and time with timezone information:

>>> datetime.now(timezone.utc)
datetime.datetime(2000, 1, 1, 0, 1, 2, 3, tzinfo=datetime.timezone.utc)
>>>
>>> datetime.now(ZoneInfo('UTC'))
datetime.datetime(2000, 1, 1, 0, 1, 2, 3, tzinfo=zoneinfo.ZoneInfo(key='UTC'))
>>>
>>> datetime.now(ZoneInfo('Europe/Warsaw'))
datetime.datetime(2000, 1, 1, 1, 1, 2, 3, tzinfo=zoneinfo.ZoneInfo(key='Europe/Warsaw'))

Convert timezones:

>>> dt = datetime(2000, 1, 1, 0, 1, 2, 3, tzinfo=ZoneInfo('UTC'))
>>>
>>> dt.astimezone(ZoneInfo('Europe/Warsaw'))
datetime.datetime(2000, 1, 1, 1, 1, 2, 3, tzinfo=zoneinfo.ZoneInfo(key='Europe/Warsaw'))

Date offset:

>>> date(2000, 1, 1) + timedelta(days=4)
datetime.date(2000, 1, 5)

Date difference:

>>> a = date(2000, 1, 1)
>>> b = date(2025, 1, 1)
>>>
>>> diff = (b - a)
>>> years = diff.days / 365.25
>>> round(years)
25

Format date:

>>> dt = datetime(2000, 1, 1, 0, 1, 2, 3)
>>>
>>> dt.strftime('%Y-%m-%d')
'2000-01-01'
>>>
>>> dt.strftime('%Y-%m-%d %H:%M:%S')
'2000-01-01 00:01:02'
>>>
>>> dt.strftime('%Y-%m-%d %H:%M:%S %a %A %b %B')
'2000-01-01 00:01:02 Sat Saturday Jan January'

Parse date:

>>> text = '2000-01-01 00:01:02'
>>>
>>> datetime.strptime(text, '%Y-%m-%d %H:%M:%S')
datetime.datetime(2000, 1, 1, 0, 1, 2)

ISO-8601:

>>> dt = datetime(2000, 1, 1, 0, 1, 2, 3)
>>> dt.isoformat()
'2000-01-01T00:01:02.000003'
>>>
>>> text = '2000-01-01 00:01:02'
>>> datetime.fromisoformat(text)
datetime.datetime(2000, 1, 1, 0, 1, 2)

Timestamp:

>>> dt = datetime(2000, 1, 1, 0, 1, 2, 3)
>>> dt.timestamp()
946681262.000003
>>>
>>> datetime.fromtimestamp(946681262.000003)
datetime.datetime(2000, 1, 1, 0, 1, 2, 3)

18.1.4. Pathlib

SetUp:

>>> from pathlib import Path

Current directory:

>>> current = Path.cwd()
>>> current
PosixPath('/tmp/')

Check:

>>> mydir = Path('/tmp')
>>>
>>> current.exists()
True
>>>
>>> current.is_file()
False
>>>
>>> current.is_dir()
True

Directory:

>>> mydir = Path('/tmp/mydir')
>>>
>>> mydir.mkdir(parents=True, exist_ok=True)
>>>
>>> mydir.rmdir()

File:

>>> myfile = Path('/tmp/myfile.txt')
>>>
>>> myfile.touch()
>>>
>>> myfile.write_text('hello\n')
6
>>> myfile.read_text()
'hello\n'
>>>
>>> myfile.unlink()

Join paths:

>>> mydir = Path('/tmp/mydir')
>>> myfile = mydir / 'myfile.txt'
>>>
>>> myfile
PosixPath('/tmp/mydir/myfile.txt')
>>>
>>> myfile.absolute()
PosixPath('/tmp/mydir/myfile.txt')
>>>
>>> myfile.relative_to('/tmp/')
PosixPath('mydir/myfile.txt')

Names:

>>> myfile = Path('/tmp/mydir/myfile.txt')
>>>
>>> myfile.name
'myfile.txt'
>>>
>>> myfile.stem
'myfile'
>>>
>>> myfile.suffix
'.txt'
>>>
>>> myfile.parent
PosixPath('/tmp/mydir')
>>>
>>> myfile.parent.parent
PosixPath('/tmp')

18.1.5. Logging

SetUp:

>>> import logging

Configuration:

>>> logging.basicConfig(
...     level='DEBUG',
...     filename='/tmp/myfile.log',
...     datefmt='%Y-%m-%d, %H:%M:%S',
...     format='{asctime}, {levelname}, {message}',
...     style='{',
... )

Create logger instance:

>>> log = logging.getLogger('myapp')

Log:

>>> log.debug('Something happened in myapp')
>>> log.info('Something happened in myapp')
>>> log.warning('Something happened in myapp')
>>> log.error('Something happened in myapp')
>>> log.critical('Something happened in myapp')

Usecase:

>>> class User:
...     def __init__(self, username, password):
...         self.username = username
...         self.password = password
...         log.debug(f'User {username} created')
...
...     def login(self):
...         self.authenticated = True
...         log.info('User logged-in')
...
...     def logout(self):
...         self.authenticated = False
...         log.info('User logged-out')

18.1.6. JSON

SetUp:

>>> import json

To JSON:

>>> data = {'username': 'alice', 'password': 'secret'}
>>>
>>> json.dumps(data)
'{"username": "alice", "password": "secret"}'

From JSON:

>>> data = '{"username": "alice", "password": "secret"}'
>>>
>>> json.loads(data)
{'username': 'alice', 'password': 'secret'}

18.1.7. CSV

SetUp:

>>> import csv

Dump list[tuple] to CSV:

>>> DATA = [
...     ('firstname', 'lastname', 'age'),
...     ('Alice', 'Apricot', 30),
...     ('Bob', 'Banana', 31),
...     ('Carol', 'Corn', 32),
...     ('Dave', 'Durian', 33),
...     ('Eve', 'Elderberry', 34),
...     ('Mallory', 'Melon', 15),
... ]
>>>
>>> with open('/tmp/myfile.csv', mode='wt') as file:
...     writer = csv.writer(file, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL, lineterminator='\n')
...     writer.writerows(DATA)
>>>
>>> print(Path('/tmp/myfile.csv').read_text())
"firstname","lastname","age"
"Alice","Apricot","30"
"Bob","Banana","31"
"Carol","Corn","32"
"Dave","Durian","33"
"Eve","Elderberry","34"
"Mallory","Melon","15"

Dump list[dict] to CSV:

>>> DATA = [
...     {'firstname': 'Alice', 'lastname': 'Apricot', 'age': 30},
...     {'firstname': 'Bob', 'lastname': 'Banana', 'age': 31},
...     {'firstname': 'Carol', 'lastname': 'Corn', 'age': 32},
...     {'firstname': 'Dave', 'lastname': 'Durian', 'age': 33},
...     {'firstname': 'Eve', 'lastname': 'Elderberry', 'age': 34},
...     {'firstname': 'Mallory', 'lastname': 'Melon', 'age': 15},
... ]
>>>
>>> with open('/tmp/myfile.csv', mode='wt') as file:
...     writer = csv.DictWriter(file, fieldnames=['firstname', 'lastname', 'age'], delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL, lineterminator='\n')
...     writer.writeheader()
...     writer.writerows(DATA)
29
>>>
>>> print(Path('/tmp/myfile.csv').read_text())
"firstname","lastname","age"
"Alice","Apricot","30"
"Bob","Banana","31"
"Carol","Corn","32"
"Dave","Durian","33"
"Eve","Elderberry","34"
"Mallory","Melon","15"

18.1.8. Itertools

SetUp:

>>> from itertools import permutations, product

Generate test data for music or video player:

>>> actions = ['stop', 'start', 'next']
>>> result = permutations(actions)
>>>
>>> pprint(list(result))
[('stop', 'start', 'next'),
 ('stop', 'next', 'start'),
 ('start', 'stop', 'next'),
 ('start', 'next', 'stop'),
 ('next', 'stop', 'start'),
 ('next', 'start', 'stop')]

Generate test cases for file parsing:

>>> files = ['myfile.json', 'myfile.csv']
>>> encoding = ['utf-8', 'cp1250']
>>> modes = ['r', 'w', 'a']
>>> result = product(files, encoding, modes)
>>>
>>> pprint(list(result))
[('myfile.json', 'utf-8', 'r'),
 ('myfile.json', 'utf-8', 'w'),
 ('myfile.json', 'utf-8', 'a'),
 ('myfile.json', 'cp1250', 'r'),
 ('myfile.json', 'cp1250', 'w'),
 ('myfile.json', 'cp1250', 'a'),
 ('myfile.csv', 'utf-8', 'r'),
 ('myfile.csv', 'utf-8', 'w'),
 ('myfile.csv', 'utf-8', 'a'),
 ('myfile.csv', 'cp1250', 'r'),
 ('myfile.csv', 'cp1250', 'w'),
 ('myfile.csv', 'cp1250', 'a')]

18.1.9. RE - Regular Expressions

SetUp:

>>> import re
>>> text = 'Mail from Alice <alice@example.com> date: 2000-01-01, time: 00:00.'

Search date in text:

>>> date = r'\d{4}-\d{2}-\d{2}'
>>> re.findall(date, text)
['2000-01-01']

Search email in text:

>>> email = r'<([a-z]+@example.com)>'
>>> re.findall(email, text)
['alice@example.com']

18.1.10. Dataclasses

Instead:

>>> class User:
...     def __init__(self, username, password):
...         self.username = username
...         self.password = password
...
...     def __str__(self):
...         return self.__repr__()
...
...     def __repr__(self):
...         clsname = self.__class__.__name__
...         username = self.username
...         password = self.password
...         return f'{clsname}({username=}, {password=})'

You can:

>>> from dataclasses import dataclass
>>>
>>> @dataclass
... class User:
...     username: str
...     password: str

18.1.11. Doctest

SetUp:

>>> def add(a, b):
...     """
...     >>> add(1, 2)
...     3
...     >>> add(1.0, 2.0)
...     3.0
...     """
...     return a + b

Run tests:

>>> import doctest
>>>
>>> doctest.testmod()
TestResults(failed=0, attempted=2)

18.1.12. Unittest

SetUp:

>>> def add(a, b):
...     return a + b

Write tests:

>>> from unittest import TestCase
>>>
>>> class TestAdd(TestCase):
...     def test_add_int(self):
...         result = add(1,2)
...         self.assertEqual(result, 3)
...
...     def test_add_float(self):
...         result = add(1.0,2.0)
...         self.assertAlmostEqual(result, 3.0, places=16)

Run tests:

>>> import unittest
>>>
>>> unittest.main()