Rioran Tech Notes
41 subscribers
68 photos
1 file
53 links
Some notes on IT or tech staff I see along the way.
Download Telegram
The way I like my imports to be refactored in #python - is for them to be grouped and each name on a single line. It is highly readable, less prone for errors.

A simple way to refactor imports - is to use the isort library. I prefer to utilize the following flags:

mode 3 - stands for VERTICAL_HANGING_INDENT

force grid wrap 2 - to start grid wrapping with only 2 imported names

trailing comma - so that all lines are similar

With some shortcuts the final command looks like this:

isort file-name.py -m 3 -fgw 2 -tc

You can edit the isort config file in order to NOT TO use all those flags each time. For these and other helpful details you can always refer to the isort official documentation: https://pycqa.github.io/isort/index.html
Finally got my hands on the Jupyter Notebook 7. Whoa, I like those new features!

Here is my screenshot with the debugger and table of contents pane out of the box. Nice and clean! And those just scratch the tip of the iceberg!

Though, not everything is ideal. Some users, me included, could face difficulties to upgrade Notebook 6 to 7 from the Anaconda Navigator on Windows machine. Pity, I do love the Anaconda Distribution. So, terminal is our best friend. Install:

pip install jupyter
pip install notebook

And run:

jupyter notebook
Here is a nice library to be aware about: https://pypi.org/project/python-dotenv/

Python-dotenv reads key-value pairs from a .env file and can set them as environment variables. It helps in the development of applications following the 12-factor principles.
Hey, dear #python enthusiasts, PyPI just went through a public audit! A huge masterpiece report can be found in the Trail Of Bits repository . Shortly: 8 medium and 6 low severity exposures, low test coverage, but overall all is good.
By the way, did you know that you can unpack strings with multiple assignment in #python ?
πŸ”₯3
A must-have technique for a huge or feature-rich application - feature flags. It is a great way to control your project without the need to redeploy. You decide what parts of the project you want to work and in what way, remotely and smoothly.

Here is a well written entry article for the topic.
❀1πŸ‘1πŸ”₯1πŸ’―1
tempfile - a nice built-in Python library to create temporary directories and files. You can use those tmp objects directly in Python or in complex scenarios like execution of a terminal command with BashOperator inside Airflow DAG.

Official docs: https://docs.python.org/3/library/tempfile.html

Example:

from tempfile import NamedTemporaryFile


with NamedTemporaryFile('w') as file:
file.write('Roman\nRioran\nVoronov\n')
file.flush()
print(f'{file.name = }') # file.name = '/tmp/tmpbrotweh8'
with open(file.name, 'r') as tmp_file:
print(f'{tmp_file.readlines() = }') # tmp_file.readlines() = ['Roman\n', 'Rioran\n', 'Voronov\n']
Channel photo updated
Several years ago during my analyst work in Yandex I regularly performed SQL related tasks via one hell of an internal tool. Not sure if NDA allows me to announce its internal name. But! Lo and behold - a huge and powerful part of that tool is now publicly released as YTsaurus! As I see it - the name is a mix of several geek words like "thesaurus" including one internal joke.

Just check out the number and quality of those features! https://ytsaurus.tech/

This tool allowed me to perform intensive and complicated calculations over billions of samples of user activity data in Taxi service.
πŸ‘3
As I continue reading "Refactoring" by Martin Fowler, chapter 6 discusses data access, particularly reference versus value. This topic brings back memories from years ago when I witnessed a team spend weeks debugging issues caused by poor data access practices.

Here is my Python 3.10 illustration of the technique Martin mentions. The two code samples have common parts. If you don't encapsulate - sooner or later, you'll run into trouble. As shown here: employee_b data gets modified by changes to seemingly unrelated objects. The overhead of copying is negligible, but the risks drop dramatically.

Risky code:

from dataclasses import dataclass, field


@dataclass
class Employee:
name: str = 'No name'
birth_year: int | None = None
projects: list[str] = field(default_factory=list)

def __repr__(self):
return f'Employee({self.name}, {self.projects})'


if __name__ == '__main__':
employee_a = Employee(name='Roman')
employee_b = Employee(name='Rioran')

new_projects = ['Party', 'New Year']

employee_a.projects = employee_b.projects = new_projects
employee_a.projects.append('Gym')
new_projects[0] = 'Dance'

print(f'{employee_b = }')
# employee_b = Employee(Rioran, ['Dance', 'New Year', 'Gym'])


Encapsulated data:

from dataclasses import dataclass, field


@dataclass
class Employee:
name: str = 'No name'
birth_year: int | None = None
_projects: list[str] = field(default_factory=list)

def __repr__(self):
return f'Employee({self.name}, {self.projects})'

@property
def projects(self):
return self._projects.copy()

@projects.setter
def projects(self, new_value: list):
self._projects = new_value.copy()


if __name__ == '__main__':
employee_a = Employee(name='Roman')
employee_b = Employee(name='Rioran')

new_projects = ['Party', 'New Year']

employee_a.projects = employee_b.projects = new_projects
employee_a.projects.append('Gym')
new_projects[0] = 'Dance'

print(f'{employee_b = }')
# employee_b = Employee(Rioran, ['Party', 'New Year'])
πŸ‘1
Reminder on #postgresql indexes types.
I participated in my first LeetCode contest ever and ranked 1873 out of 33,261 participants, placing me in the top 6%
πŸ”₯5🀯1😱1
Here is how py2puml & plantuml tools combination could help you visualize your Python project entities.

Both are easily installed. PlantUML is even available as a PyCharm plugin. Normally going from zero to image would take less than a minute.

Minor hickups are possible though. On Windows py2puml tryed standard output instead of file creation. And output redirection was polluted with NULL symbols. Also by default py2puml didn't capture method names.

Here is my Kettle in Python:

class Heater:
def __init__(self, min_temperature: int = 0, max_temperature: int = 100):
self.enabled: bool = False
self.temperature: int = 0
self.min_temperature: int = min_temperature
self.max_temperature: int = max_temperature

def start(self):
self.enabled = True

def update(self):
if self.enabled:
self.temperature += 1
self.temperature = min(self.max_temperature, self.temperature)
else:
self.temperature -= 1
self.temperature = max(self.min_temperature, self.temperature)


class Reservoir:
def __init__(self, volume: int = 1000):
self.volume: int = volume
self.water: int = 0

def fill(self, input_water):
total_water = self.water + input_water
self.water = min(self.volume, self.water + input_water)
spilled = total_water - self.water

return spilled

def pour(self, amount):
pour_amount = min(self.water, amount)
self.water -= pour_amount

return pour_amount


class Kettle(Heater, Reservoir):
def __init__(self, volume=1000, min_temperature=0, max_temperature=100):
Reservoir.__init__(self, volume)
Heater.__init__(self, min_temperature, max_temperature)


That's what py2puml produced:

@startuml tea
!pragma useIntermediatePackages false

class tea.Heater {
enabled: bool
temperature: int
min_temperature: int
max_temperature: int
+ __init__(min_temperature: int = 0, max_temperature: int = 100)
+ start()
+ update()
}
class tea.Kettle {
}
class tea.Reservoir {
volume: int
water: int
+ __init__(volume: int = 1000)
+ fill(input_water: int): int
+ pour(amount: int): int
}
tea.Heater <|-- tea.Kettle
tea.Reservoir <|-- tea.Kettle
footer Generated by //py2puml//
@enduml
❀1πŸ‘1
Yo, check out an awesome package and project manager for #python !

https://docs.astral.sh/uv/

Easily installed on Windows even with:

pip install uv


Though take notice:

If installing from PyPI, we recommend installing uv into an isolated environment, e.g., with pipx


Here are some official documentation highlights:

πŸš€ A single tool to replace pip, pip-tools, pipx, poetry, pyenv, twine, virtualenv, and more.
⚑️ 10-100x faster than pip.
πŸ—‚ Provides comprehensive project management, with a universal lockfile.
❇️ Runs scripts, with support for inline dependency metadata.
🐍 Installs and manages Python versions.
πŸ›  Runs and installs tools published as Python packages.
πŸ”© Includes a pip-compatible interface for a performance boost with a familiar CLI.
🏒 Supports Cargo-style workspaces for scalable projects.
πŸ’Ύ Disk-space efficient, with a global cache for dependency deduplication.
⏬ Installable without Rust or Python via curl or pip.
πŸ–₯ Supports macOS, Linux, and Windows.

uv is backed by Astral, the creators of Ruff.
πŸ”₯1
Hey there! Here is a quick recap on asyncio Event Loop in #python

Asyncio itself is written in pure Python but depends on platform-specific C-functions.

Event Loop Policy is a global per-process object. Controls the Event Loop. Could be changed via API. Single event loop per thread by default.

Event Loop itself is an object too. Can be passed into different contexts. Has 2 stages: running or stopped. Relies on monotonic clock to avoid errors of going back in time (essentially the system's uptime).

Event loop collects coroutines, Tasks and Futures as handles. Assigns callbacks to these handles. Plans execution in a timed heap if possible. And checks for events needed by some handles.

Related links:

https://peps.python.org/pep-3153/ - Asynchronous IO support - precedes PEP 3156

https://peps.python.org/pep-3156/ - Asynchronous IO Support Rebooted: the β€œasyncio” Module - the key PEP which inspired this post

https://peps.python.org/pep-0418/#time-monotonic - Add monotonic time, performance counter, and process time functions - monotonic related link

https://peps.python.org/pep-3148/ - futures - execute computations asynchronously

https://peps.python.org/pep-0380/ - Syntax for Delegating to a Subgenerator (yield from)

https://peps.python.org/pep-0492/ - Coroutines with async and await syntax

https://github.com/python/cpython/blob/main/Lib/asyncio/base_events.py - source code containing the actual loop of Event Loop inside the method called "run_forever". Each iteration is processed inside the method "_run_once".

https://github.com/python/cpython/blob/main/Lib/selectors.py - key "select" method which crucial for collecting events

https://www.youtube.com/watch?v=RIVcqT2OGPA - AsyncIO and the Event Loop explained by ArjanCodes

https://www.youtube.com/watch?v=Ww2HBNpu98g - Demystifying AsyncIO: Building Your Own Event Loop in Python β€” Arthur Pastel
I like to examine top solutions to #leetcode problems if they are better than mine to learn something new. Here is a nice dynamic programming problem to find largest square area in a matrix of "0" and "1" strings. I was shocked to find a really short solution among leaders:

class Solution:
def maximalSquare(_, m):
s,a=[int(''.join(r),2) for r in m],0
while any(s):s,a=[a&b for a,b in pairwise([a&(a<<1) for a in s])],a+1
return a**2


Seems like magic! Way above my own solution. And it's really hard to understand how it works in current form, completely unreadable. So I start refactoring. First I apply basic Pythonic spacing and remove redundant function parameter:

from itertools import pairwise


class Solution:
@staticmethod
def maximalSquare(m):
s, a = [int(''.join(r), 2) for r in m], 0

while any(s):
s, a = [a & b for a, b in pairwise([a & (a << 1) for a in s])], a + 1

return a ** 2


Still no idea what makes this solution tick. Now let me disjoint multiple assignments, rename some variables...

from itertools import pairwise


class Solution:
@staticmethod
def maximalSquare(matrix):
matrix_rows_in_binary = [int(''.join(matrix_row), 2) for matrix_row in matrix]
top_square_side = 0

while any(matrix_rows_in_binary):
matrix_rows_in_binary = [
a & b
for a, b in pairwise([
binary_value & (binary_value << 1)
for binary_value in matrix_rows_in_binary
])
]
top_square_side += 1

return top_square_side ** 2


And now the first glimpse of understanding visits me! Author reduces each matrix row to just an integer. Pairwise function helps to reduce rows with some bitwise operations. Let me rename and reshuffle further:

from itertools import pairwise


class Solution:
@staticmethod
def maximalSquare(matrix):
matrix_rows_in_binary = [int(''.join(matrix_row), 2) for matrix_row in matrix]
top_square_side = 0

while any(matrix_rows_in_binary):
row_to_row_pairs = pairwise([value & (value << 1) for value in matrix_rows_in_binary])
matrix_rows_in_binary = [value & next_value for value, next_value in row_to_row_pairs]
top_square_side += 1

return top_square_side ** 2


And thus I learned a new technique. Pretty neat to reduce rows amount unless all rows are empty. Bitwise AND ensures we go unless square cant continue to grow.
πŸ”₯1
Forwarded from Roman Voronov
Today I had a technical interview using https://codepad.app/ editor. It is an awesome one! Fast, no delays, access to file system so you can model whole application. I didn't even need to log in. I used terminal to open Python shell to test a mechanism. Features are impressive and they claim they are free!
πŸ‘3