На днях вышел Django 5.
▫️ GeneratedField
Поля, которые автоматически рассчитываются по экспрешену (Database generated model field).
▫️Фасетный фильтр для админки
Показывает количество элементов для каждого фильтра.
▫️Async
Добавлены асинхроные функции django.contrib.auth, ORM. Ряд декораторов теперь поддерживаются асинхронными вьюшками.
▫️ORM
Новые возможносте полей, такие как поддержка словарей и функций в choices, дефолтные значения на стороне БД (Database-computed default values) с аргументом db_default и другие.
▫️Шаблоны
Новые возможности шаблонов, позволяющие писать меньше кода в формах.
#django
▫️ GeneratedField
Поля, которые автоматически рассчитываются по экспрешену (Database generated model field).
▫️Фасетный фильтр для админки
Показывает количество элементов для каждого фильтра.
▫️Async
Добавлены асинхроные функции django.contrib.auth, ORM. Ряд декораторов теперь поддерживаются асинхронными вьюшками.
▫️ORM
Новые возможносте полей, такие как поддержка словарей и функций в choices, дефолтные значения на стороне БД (Database-computed default values) с аргументом db_default и другие.
▫️Шаблоны
Новые возможности шаблонов, позволяющие писать меньше кода в формах.
#django
🎉5❤1
Библиотеки для рабты с коллекциями файлов (секвенциями)
▫️ Поиск коллекций в директории
▫️ Проверка целостности
▫️ Поиск пересечений
▫️ Форматирование
И другие функции
➡️ CLIQUE https://clique.readthedocs.io/en/stable/
➡️ PYSEQ https://pyseq.rsgalloway.com/
У библиотек схожий функционал но в деталях различается.
#libs
▫️ Поиск коллекций в директории
▫️ Проверка целостности
▫️ Поиск пересечений
▫️ Форматирование
И другие функции
➡️ CLIQUE https://clique.readthedocs.io/en/stable/
import clique
files = [
'/tmp/file1_001.png',
'/tmp/file1_002.png',
'/tmp/file1_003.png',
'/tmp/file1_005.png',
]
collection = clique.assemble(files)[0][0]
collection.head
# '/tmp/file1_'
collection.tail
# '.png'
collection.padding
# 3
collection.indexes
# <SortedSet "[1, 2, 3, 5]">
collection.holes()
# <Collection "/tmp/file1_%03d.png [4]">
collection.separate()
# [<Collection "/tmp/file1_%03d.png [1-3]">,
# <Collection "/tmp/file1_%03d.png [5]">]
➡️ PYSEQ https://pyseq.rsgalloway.com/
import pyseq
files = [
'/tmp/file1_001.png',
'/tmp/file1_002.png',
'/tmp/file1_003.png',
'/tmp/file1_005.png',
]
sequence = pyseq.Sequence(files)
sequence.head()
# 'file1_'
sequence.tail()
# '.png'
sequence.path()
# '/tmp/file1_1-5.png'
sequence.frames()
# [1, 2, 3, 5]
sequence.format('%p')
# '%03d'
sequence.missing()
# [4]
У библиотек схожий функционал но в деталях различается.
clique не умеет работать с pathlib.Path а pyseq не понимает генератор как источник. Но обе могут найти все коллекции в директории и выдать много информации о них.#libs
👍10❤1
PEP471 добавил в Python3.5 в модуль
▫️это генератор с соответствующими возможностями
▫️возвращает не просто строку а объект DirEntry
▫️работает в 4-10 раз быстрей чем
Раньше это была отдельная библиотека, которая позже стала частью CPython, как и ряд других новых библиотек в Python 3.
В настоящий момент метод
Обёртка, заставляющая обычную функцию работать как генератор
В тоже время
#libs
os новую функцию scandir()▫️это генератор с соответствующими возможностями
▫️возвращает не просто строку а объект DirEntry
▫️работает в 4-10 раз быстрей чем
os.listdir и os.walkРаньше это была отдельная библиотека, которая позже стала частью CPython, как и ряд других новых библиотек в Python 3.
В настоящий момент метод
Path.iterdir() всё еще использует os.listdir(). Обёртка, заставляющая обычную функцию работать как генератор
def iterdir(self):
for name in os.listdir(self):
yield self._make_child_relpath(name)
В тоже время
Path.glob() и Path.rglob() уже используют os.scandir(), то есть полноценные генераторы.#libs
Python Enhancement Proposals (PEPs)
PEP 471 – os.scandir() function – a better and faster directory iterator | peps.python.org
This PEP proposes including a new directory iteration function, os.scandir(), in the standard library. This new function adds useful functionality and increases the speed of os.walk() by 2-20 times (depending on the platform and file system) by avoiding...
👍8🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
rich
Библиотека для нескучного принта!
Добавляет в ваш терминал цвет и разные способы форматирования текста.
https://github.com/willmcgugan/rich
➡️ Мой небольшой пример
#libs
Библиотека для нескучного принта!
Добавляет в ваш терминал цвет и разные способы форматирования текста.
https://github.com/willmcgugan/rich
➡️ Мой небольшой пример
#libs
👍10
Когда пишешь асинхронный код нужно учитывать особенности такого подхода. Всегда требуется держать в уме, когда возвращается корутина а когда реальный результат. Между этими двумя сущностями должен быть вызов через
Вот пример синхронного запроса в базу данных с помощь sqlalchemy. Query пишу инлайном для компактности.
Всё ясно и линейно. А вот он же асинхронный.
Это значит что
Не хочу сказать что это мастхэв практика, но простые асинхронные запросы тоже можно сократить до одной строки. Просто использовать скобки.
На самом деле я использую такую конструкцию только в прототипах тестов или вспомогательных функциях тестов. В продакшн такое обычно не попадает.
#tricks
await.Вот пример синхронного запроса в базу данных с помощь sqlalchemy. Query пишу инлайном для компактности.
entities = session.execute(select(EntityModel)).scalars().all()
Всё ясно и линейно. А вот он же асинхронный.
result = await session.execute(select(EntityModel))
entities = result.scalars().all()
Это значит что
session.execute возвращает корутину, или awaitable объект. Сначала его нужно выполнить через await, тогда получишь объект с которым можно дальше работать.Не хочу сказать что это мастхэв практика, но простые асинхронные запросы тоже можно сократить до одной строки. Просто использовать скобки.
entities = ( await session.execute(select(EntityModel)) ).scalars().all()
На самом деле я использую такую конструкцию только в прототипах тестов или вспомогательных функциях тестов. В продакшн такое обычно не попадает.
#tricks
👍9
Библиотека psutil предоставляет весьма широкий инструментарий для взаимодействия с процессами.
Одна из полезных функций - узнать какие файлы открыты в контексте процесса или узнать какой процесс занимает файл.
Узнаём какие файлы использует процесс
Функция вернёт имя процесса который занял файл. Если файл не занят то вернёт
Для использования требуются админские права.
#libs
Одна из полезных функций - узнать какие файлы открыты в контексте процесса или узнать какой процесс занимает файл.
Узнаём какие файлы использует процесс
import psutil
def list_file_handlers(process_name):
for proc in psutil.process_iter():
if proc.name().lower().startswith(process_name):
for file in proc.open_files():
print(file)
list_file_handlers('python')
Функция вернёт имя процесса который занял файл. Если файл не занят то вернёт
None.def who_is_use(fpath):
for proc in psutil.process_iter():
for item in proc.open_files():
if fpath == item.path:
return proc.name()
Для использования требуются админские права.
#libs
GitHub
GitHub - giampaolo/psutil: Cross-platform lib for process and system monitoring in Python
Cross-platform lib for process and system monitoring in Python - giampaolo/psutil
❤6👍4
Библиотека APScheduler для управления заданиями в Python.
Может запускать планировщик и задания как отдельный поток (синхронный код) и как коркутины (асинхронный код), отложенные или через интервал.
Что есть в APScheduler:
▫️гибкий функционал создания задачи
▫️удобное управление созданными заданиями (pause\resume, listing, modify, reschedule)
▫️кастомизация классов библиотеки
▫️различные хранилища заданий (Memory и различные БД)
▫️интеграции в фреймворки
▫️7 вариантов планировщика
Три варианта тригеров для задач:
▫️по дате с помощью datetime
▫️через интервал с помощью datetime
▫️через интервал с помощью cron
и другие полезности
В данный момент готовится к релизу 4я версия
PS. Всегда использую вместе с FastAPI, очень рекомендую к ознакомлению.
#libs
Может запускать планировщик и задания как отдельный поток (синхронный код) и как коркутины (асинхронный код), отложенные или через интервал.
Что есть в APScheduler:
▫️гибкий функционал создания задачи
▫️удобное управление созданными заданиями (pause\resume, listing, modify, reschedule)
▫️кастомизация классов библиотеки
▫️различные хранилища заданий (Memory и различные БД)
▫️интеграции в фреймворки
▫️7 вариантов планировщика
Три варианта тригеров для задач:
▫️по дате с помощью datetime
▫️через интервал с помощью datetime
▫️через интервал с помощью cron
и другие полезности
В данный момент готовится к релизу 4я версия
PS. Всегда использую вместе с FastAPI, очень рекомендую к ознакомлению.
#libs
GitHub
GitHub - agronholm/apscheduler at 3.x
Task scheduling library for Python. Contribute to agronholm/apscheduler development by creating an account on GitHub.
🔥4👍2
Функция
Но вы не сможете таким образом получить аутпут процесса который завершился с ненулевым кодом выхода. Вместо этого у вас выбрасывается исключение
Не так давно я столкнулся с этой ситуацией, когда процесс, будучи запущенным с флагом
За генерацию исключения отвечает аргумент
Нет, это не недосмотр разрабочтков и вам не потребуется искать обходные пути. Дело в том, что вся полезная нагрузка в таких случаях находится в классе исключения.
Классы TimeoutExpired и CalledProcessError имеют ряд атрибутов, которые хранят всю нужну инфу. Например, вызванная команда (
Итого, базовая фукнция для захвата аутпута для любого кода выхода будет выглядеть как-то так:
#tricks
subprocess.check_output() удобна, когда нужно просто получить аутпут процесса.info = subprocess.check_output(cmd, text=True)
Но вы не сможете таким образом получить аутпут процесса который завершился с ненулевым кодом выхода. Вместо этого у вас выбрасывается исключение
CalledProcessError: Command '[...]' returned non-zero exit status 1.
Не так давно я столкнулся с этой ситуацией, когда процесс, будучи запущенным с флагом
--help, вполне штатно печатает в аут нужную информацию но выходит с кодом 1. И это для него нормальное поведение.За генерацию исключения отвечает аргумент
check, который по умолчанию равен False но именно в check_output он равен True и не может быть переопределён при вызове.Нет, это не недосмотр разрабочтков и вам не потребуется искать обходные пути. Дело в том, что вся полезная нагрузка в таких случаях находится в классе исключения.
Классы TimeoutExpired и CalledProcessError имеют ряд атрибутов, которые хранят всю нужну инфу. Например, вызванная команда (
cmd), код выхода (returncode) и то что мы ищем - аутпут процесса (output)Итого, базовая фукнция для захвата аутпута для любого кода выхода будет выглядеть как-то так:
def get_proc_output(cmd):
try:
return subprocess.check_output(cmd, text=True)
except subprocess.CalledProcessError as e:
return e.output
#tricks
Python documentation
subprocess — Subprocess management
Source code: Lib/subprocess.py The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace seve...
👍13😁3🔥1
Нередко требуется удалять дубликаты инстансов класса. Для этого обычно используется либо циклы со сравнением некоторых атрибутов, либо тип данных
При добавлении элемента в
Далее для краткости метод `__repr__()` я буду пропускать
По умолчанию в расчёте хеша, помимо прочего, используется адрес в памяти, который можно получить с помощью функции
Теперь в дело вступает логика, описаная в документации.
Если вы переопределили
Отлично, теперь всё работает.
Этот же принцип действует и при наследовании. Допустим, вы создали дочерний класс
Теперь следует учитывать вот такое поведение
Инстансы А и В могут считаться идентичными, если они имеют одинаковые значения атрибутов и хеш, что может привести к неожиданным результатам при использовании множеств. Нужно учесть это в методах:
Но если вдруг решите как-то изменить способ сравнения в классе В...
Снова получите ошибку. Та же логика - при переопределении метода
#tricks
set().При добавлении элемента в
set происходит сравнение этого объекта по хешу. Если хеш совпадает с хешем уже существующего объекта, то происходит сравнение объектов на равенство. Если объекты равны, то новый объект не добавляется.class A:
def __init__(self, pk: int):
self.pk = pk
def __repr__(self):
return f"{self.__class__.__name__}(pk={self.pk})"
set([A(pk=1), A(pk=2), A(pk=2)])
>>> {A(pk=1), A(pk=2), A(pk=2)}
Далее для краткости метод `__repr__()` я буду пропускать
По умолчанию в расчёте хеша, помимо прочего, используется адрес в памяти, который можно получить с помощью функции
id(), поэтому все объекты считаются разными. Чтобы изменить способ сравнения объектов нам требуется переопределить метод __eq__()class A:
def __init__(self, pk: int):
self.pk = pk
def __eq__(self, other):
return self.pk == other.pk
set([A(pk=1), A(pk=2), A(pk=2)])
>>> TypeError: unhashable type: 'A'
Теперь в дело вступает логика, описаная в документации.
Если вы переопределили
__eq__() то следует переопределить и __hash__().class A:
def __init__(self, pk: int):
self.pk = pk
def __eq__(self, other):
return self.pk == other.pk
def __hash__(self):
return hash(self.pk)
set([A(pk=1), A(pk=2), A(pk=2)])
>>> {A(pk=1), A(pk=2)}
Отлично, теперь всё работает.
Этот же принцип действует и при наследовании. Допустим, вы создали дочерний класс
class B(A):
pass
set([B(pk=1), B(pk=2), B(pk=2)])
>>> {B(pk=1), B(pk=2)}
Теперь следует учитывать вот такое поведение
hash(A(1)) == hash(B(1))
>>> True
set([A(1), B(1)])
>>> {A(pk=1)}
Инстансы А и В могут считаться идентичными, если они имеют одинаковые значения атрибутов и хеш, что может привести к неожиданным результатам при использовании множеств. Нужно учесть это в методах:
class A:
...
def __eq__(self, other):
return isinstance(other, self.__class__) and self.pk == other.pk
def __hash__(self):
return hash((self.pk, self.__class__))
...
Но если вдруг решите как-то изменить способ сравнения в классе В...
class B(A):
def __eq__(self, other):
return abs(self.pk) == abs(other.pk)
set([B(pk=1), B(pk=2), B(pk=2)])
>>> TypeError: unhashable type: 'B'
Снова получите ошибку. Та же логика - при переопределении метода
__eq__() в новом классе метод __hash__() автоматически становится None и его тоже требуется переопределить.#tricks
Python documentation
3. Data model
Objects, values and types: Objects are Python’s abstraction for data. All data in a Python program is represented by objects or by relations between objects. Even code is represented by objects. Ev...
👍7🔥1
Три способа создать декоратор для метода класса.
▫️Способ 1. Обычная функция.
Единственное отличие от простого декоратора функции в том, что нужно учитывать аргумент
Если же он не нужен то просто пробрасываем его через
▫️Способ 2. Методы класса.
Но что, если декоратор жестко привязан к классу и используется только в нём. И стоит задача закрепить декоратор именно за этим классом и расположить внутри него.
В таком случае можно сделать
Очевидно, что декоратор должен быть объявлен раньше метода.
Тоже самое будет и с
Где-то потерялся аргумент
▫️Способ 3. Вложенный класс и staticmethod
Получаем чтото вроде микса способов 1 и 2: функция вложена в отдельный класс.
Лучшей практикой является способ 1 - обычные функции.
Всего пару раз за практику я использовал 3й способ, когда декоратор был намертво привязан к классу и нигде больше не мог использоваться (например, отправлял вызов метода на воркера в другой процесс, не спрашивайте почему так, просто так было нужно 🤪)
Способ 2 не советую. Это, скорей, разминка для ума чем практический пример.
PS
-
- в коментах дополнительная инфа
#tricks
▫️Способ 1. Обычная функция.
Единственное отличие от простого декоратора функции в том, что нужно учитывать аргумент
self. Если же он не нужен то просто пробрасываем его через
*argsdef decorator_func(func):
def wrapped(*args, **kwargs):
print('decorator_func')
return func(*args, **kwargs)
return wrapped
class MyClass:
@decorator_func
def method(self):
print('call method')
MyClass().method()
# decorator_func
# call method
▫️Способ 2. Методы класса.
Но что, если декоратор жестко привязан к классу и используется только в нём. И стоит задача закрепить декоратор именно за этим классом и расположить внутри него.
В таком случае можно сделать
staticmethod. Это будет выглядеть страшно, но работать будет (тестировано на 3.11)Очевидно, что декоратор должен быть объявлен раньше метода.
class MyClass:
@staticmethod
def decorator(func):
def wrapper(*args, **kwargs):
print('decorator from staticmethod')
return func(*args, **kwargs)
return wrapper
@decorator.__func__
def method(self):
print('method called')
MyClass().method()
# decorator from staticmethod
# method called
Тоже самое будет и с
classmethod, но еще хуже.class MyClass:
@classmethod
def decorator(func):
def wrapper(self, *args, **kwargs):
print('decorator from classmethod')
return func(self, *args, **kwargs)
return wrapper
@decorator.__func__
def method(self):
print('method called')
MyClass().method()
# decorator from classmethod
# method called
Где-то потерялся аргумент
cls. Скорее всего это можно решить но лучше не надо. Оба варианта выглядят страшненько 🫣▫️Способ 3. Вложенный класс и staticmethod
class MyClass:
class deco:
@staticmethod
def my_decorator(func):
def wrapper(*args, **kwargs):
print('decorator from subclass')
return func(*args, **kwargs)
return wrapper
@deco.my_decorator
def method(self):
print('method called')
MyClass().method()
# decorator from subclass
# method called
Получаем чтото вроде микса способов 1 и 2: функция вложена в отдельный класс.
Лучшей практикой является способ 1 - обычные функции.
Всего пару раз за практику я использовал 3й способ, когда декоратор был намертво привязан к классу и нигде больше не мог использоваться (например, отправлял вызов метода на воркера в другой процесс, не спрашивайте почему так, просто так было нужно 🤪)
Способ 2 не советую. Это, скорей, разминка для ума чем практический пример.
PS
-
wraps пропустил для краткости- в коментах дополнительная инфа
#tricks
👍7
Объекты
Можно разделить один интервал на другой, включая целочисленное деление. Так мы узнаем сколько раз один период помещается в другой.
А так же остаток от делния.
Объекты
И, что очевидно, операторы сравнения
А еще можно почитать про форматирование даты и времени здесь и здесь.
#tricks
datetime.timedelta поддерживают операторы деления и умноженияfrom datetime import timedelta
td1 = timedelta(hours=1)
# увеличим интервал в 2.5 раза
print(td1*2.5)
# 2:30:00
# разделим интервал на 2
print(td1/2)
# 0:30:00
Можно разделить один интервал на другой, включая целочисленное деление. Так мы узнаем сколько раз один период помещается в другой.
td2 = timedelta(minutes=25)
print(td1/td2)
# 2.4
print(td1//td2)
# 2
А так же остаток от делния.
print(td1%td2)
# 0:10:00
Объекты
datetime.timedelta поддерживают отрицательные значения. Эти две записи идентичны.datetime.now() - timedelta(hours=1)
datetime.now() + timedelta(hours=-1)
И, что очевидно, операторы сравнения
td1>td2
# True
А еще можно почитать про форматирование даты и времени здесь и здесь.
#tricks
Telegram
Python Заметки
Все знают как красиво написать дату и время с помощью библиотеки datetime:
>>> from datetime import datetime
>>>
>>> dt = datetime.now()
>>> dt.strftime('%Y.%m.%d %H:%I')
'2020.01.08 12:00'
Но мало кто знает, что тоже самое можно сделать и другим способом:…
>>> from datetime import datetime
>>>
>>> dt = datetime.now()
>>> dt.strftime('%Y.%m.%d %H:%I')
'2020.01.08 12:00'
Но мало кто знает, что тоже самое можно сделать и другим способом:…
🔥14👍3
Недавно была задача форматировать строки по шаблону. Шаблон обычный для метода
или
Проблема состояла в том, что некоторые переменные следует игнорировать, заменять только те, что у меня есть на данный момент (дальше идет ещё один обработчик). Если в метод строки
Какие варианты решения есть?
▫️ переопределить класс
▫️ написать отдельную функцию парсинга строки с использованием
▫️ сделать словарь, который возвращает исходную переменную при отсутствии ключа
Третий вариант и рассмотрим, он самый краткий, буквально 2 строки включая вызов!
1. Мы создаем кастомный класс наследуя его от
2. Это не сработает если переменные указаны в формате
3. Переменные можно передать и просто готовым словарём. Это же обычный конструктор объекта
4. Вместо
5. Ну да, не две строки. Просто класс нужно создать и в одну строку. Если кому надо именно 2х-строчное решение - забирайте:
6. Из минусов: вы не сможете так просто определить все ли вам нужные переменные заполнены, так как пропускаются ВСЕ отсутствующие.
#tricks
format()/path/to/app{version}/binили
/opt/{app_name}/bin:{DEFAULT_PATH}:/usr/binПроблема состояла в том, что некоторые переменные следует игнорировать, заменять только те, что у меня есть на данный момент (дальше идет ещё один обработчик). Если в метод строки
format() не передать все переменные то будет ошибка KeyError"/opt/{app_name}:{DEFAULT_PATH}".format(app_name="my_app")
# KeyError: 'DEFAULT_PATH'Какие варианты решения есть?
▫️ переопределить класс
srt и метод format▫️ написать отдельную функцию парсинга строки с использованием
regex▫️ сделать словарь, который возвращает исходную переменную при отсутствии ключа
Третий вариант и рассмотрим, он самый краткий, буквально 2 строки включая вызов!
class SkipDict(dict):
def __missing__(self, key):
return f"{{{key}}}"
"/opt/{app_name}:{DEFAULT_PATH}".format_map(SkipDict(app_name='my_app'))
# "/opt/my_app:{DEFAULT_PATH}"
1. Мы создаем кастомный класс наследуя его от
dict и переопределяем __missing__. Этот метод вызывается когда в словаре ключ не найден. По умолчанию он выбрасывает исключение KeyError. Всякий раз когда ключ не найден, мы возвращаем исходный вид этой переменной и ошибки теперь не будет.2. Это не сработает если переменные указаны в формате
${name}. Это совсем другой синтаксис из bash и подобных сред.3. Переменные можно передать и просто готовым словарём. Это же обычный конструктор объекта
dict"...".format_map(SkipDict(kwargs))
4. Вместо
format() используется format_map(), просто удобней в данном случае.5. Ну да, не две строки. Просто класс нужно создать и в одну строку. Если кому надо именно 2х-строчное решение - забирайте:
SkipDict = type('SkipDict', (dict, ),{'__missing__': lambda self, key: f"{{{key}}}"})6. Из минусов: вы не сможете так просто определить все ли вам нужные переменные заполнены, так как пропускаются ВСЕ отсутствующие.
#tricks
👍6❤1
При использовании PNG файлов в PySide/PyQt может появляется такой ворнинг
ICC Profile — это файлы, которые содержат информацию о том, как преобразовывать цвета из одного цветового пространства в другое. Они используются для обеспечения точного цветового соответствия между различными устройствами и программами, такими как сканеры, принтеры, мониторы и графические редакторы.
sRGB (standard Red Green Blue) — стандартное цветовое пространство, которое используется в цифровой фотографии и веб-дизайне.
Указанная выше ошибка говорит о том, что профиль устарел или повреждён. Qt-движок не может его считать. Если у вас множество иконок и иных картинок оформления, то ворнингов будет сыпаться довольно много.
Решение — пересохранить файл без профиля, то есть будет использоваться цветовое пространство на усмотрение приложения.
#tricks
libpng warning: iCCP: known incorrect sRGB profile
ICC Profile — это файлы, которые содержат информацию о том, как преобразовывать цвета из одного цветового пространства в другое. Они используются для обеспечения точного цветового соответствия между различными устройствами и программами, такими как сканеры, принтеры, мониторы и графические редакторы.
sRGB (standard Red Green Blue) — стандартное цветовое пространство, которое используется в цифровой фотографии и веб-дизайне.
Указанная выше ошибка говорит о том, что профиль устарел или повреждён. Qt-движок не может его считать. Если у вас множество иконок и иных картинок оформления, то ворнингов будет сыпаться довольно много.
Решение — пересохранить файл без профиля, то есть будет использоваться цветовое пространство на усмотрение приложения.
from PIL import Image
Image.open(input_path).save(output_path, icc_profile=None)
from PySide2.QtGui import QImage, QImageWriter
image = QImage(input_path)
image.setText("icc", "")
writer = QImageWriter(output_path)
writer.write(image)
#tricks
👍14
POSIX (Portable Operating System Interface) — это набор стандартов, определяющих интерфейсы для обеспечения совместимости между операционными системами.
Данный стандарт поддерживается всеми UNIX-системами (GNU/Linux, macOS, FreeBSD, OpenBSD и другие). А вот в Windows либо частично, либо через подсистемы (такие как WSL).
Помимо прочих условий, один из важных моментов этого стандарта - правила синтаксического анализа строк, разбиение на токены.
В Python разбиением строки на токены занимается функция
Этот аргумент определяет, следует ли функции использовать правила синтаксического анализа соответствующие стандарту POSIX, или использовать обратно совместимый, легаси режим.
▫️posix=True
В POSIX-совместимом режиме функция
▫️posix=False
В легаси режиме используется более старый способ разбиения строк на токены, который будет игнорировать переменную окружения
Теперь смотрим некоторые примеры.
Учитвая, что аргумент
Рекомендую самостоятельно поэксперементировать с этим аргументом!
#libs
Данный стандарт поддерживается всеми UNIX-системами (GNU/Linux, macOS, FreeBSD, OpenBSD и другие). А вот в Windows либо частично, либо через подсистемы (такие как WSL).
Помимо прочих условий, один из важных моментов этого стандарта - правила синтаксического анализа строк, разбиение на токены.
В Python разбиением строки на токены занимается функция
shlex.split(), которая имеет один важный аргумент - posix.Этот аргумент определяет, следует ли функции использовать правила синтаксического анализа соответствующие стандарту POSIX, или использовать обратно совместимый, легаси режим.
▫️posix=True
В POSIX-совместимом режиме функция
shlex.split() будет учитывать переменную окружения IFS (Internal Field Separator) для определения разделителей полей и будет более строго следовать стандарту POSIX. Из строки удаляются неэкранированные кавычки и обратные слеши.▫️posix=False
В легаси режиме используется более старый способ разбиения строк на токены, который будет игнорировать переменную окружения
IFS и использовать whitespaces как разделители полей.Теперь смотрим некоторые примеры.
import shlex
# кавычки
text = r'"Do"Not"Separate" \"This\"'
shlex.split(text, posix=False)
# ['"Do"', 'Not"Separate"', '\\"This\\"']
shlex.split(text, posix=True)
# ['DoNotSeparate', '"This"']
# специсимволы
text = r'A\tB\nС\fD\vE'
shlex.split(text, posix=False)
# ['A\\tB\\nС\\fD\\vE']
shlex.split(text, posix=True)
# ['AtBnСfDvE']
# обратный слеш
text = r"cmd.exe c:\games\mario.exe"
shlex.split(text, posix=False)
# ['cmd.exe', 'c:\\games\\mario.exe']
shlex.split(text, posix=True)
# ['cmd.exe', 'c:gamesmario.exe']
Учитвая, что аргумент
posix по умолчанию True, стоит помнить этот факт при обработке строк с Windows-путями!Рекомендую самостоятельно поэксперементировать с этим аргументом!
#libs
👍6❤1
Unofficial Windows Binaries for Python Extension Packages - известная страница с множеством скомпилированных python-библиотек для Windows. Её вёл Christoph Gohlke и любезно нам собирал whl пакеты. Очень часто эа страница помогала и мне и, вероятно, многим из вас.
В июне 2022 года из-за отсутствия финансирования проект был закрыт и обновления долго не выходили. Позже и страница была удалена😭
В начале 2023 года Christoph Gohlke создал репозитории на GitHub которые заменили этот "сервис". На его странице в самом верху можно найти несколько ссылок на эти репозитории.
В частности репозиторий Pymol-open-source wheels for Python on Windows. Не могу сказать что это уже полноценная замена, кажется новые библиотеки добавляются неспеша, но это уже что-то. Активность можете проследить самостоятельно.
А еще там есть эксперементальные сборки для ARM64.
PS. Если знаете где есть подобные архивы, поделитесь в коментах.
#libs
В июне 2022 года из-за отсутствия финансирования проект был закрыт и обновления долго не выходили. Позже и страница была удалена😭
В начале 2023 года Christoph Gohlke создал репозитории на GitHub которые заменили этот "сервис". На его странице в самом верху можно найти несколько ссылок на эти репозитории.
В частности репозиторий Pymol-open-source wheels for Python on Windows. Не могу сказать что это уже полноценная замена, кажется новые библиотеки добавляются неспеша, но это уже что-то. Активность можете проследить самостоятельно.
А еще там есть эксперементальные сборки для ARM64.
PS. Если знаете где есть подобные архивы, поделитесь в коментах.
#libs
GitHub
cgohlke - Overview
cgohlke has 63 repositories available. Follow their code on GitHub.
🔥2
Когда требуется быстро расшарить файлы в локальную сеть со своего компа можно использовать дефолтный python-сервер. Все решается одной командой.
Но это бывает неудобным если нужно скачать папку или залить файлы. В этом случае более удобным будет быстрый FTP сервер.
Я себе сделал шорткат для поднятия простого FTP сервера без авторизации на базе библиотеки pyftpdlib.
Варианты запуска:
Мой алиас для расшаривания в текущей директории
Теперь можно подключть FTP соединение как удалённую директорию стандартными средствами OS. В Windows это Add Network Location, в Linux - зависит от дистрибутива. Ищите в разделе Network вашего файлового браузера.
Также можно использовать сторонние клиенты, например FileZilla.
А здесь подробней про http.server
#libs #tricks
python3 -m http.server
Но это бывает неудобным если нужно скачать папку или залить файлы. В этом случае более удобным будет быстрый FTP сервер.
Я себе сделал шорткат для поднятия простого FTP сервера без авторизации на базе библиотеки pyftpdlib.
Варианты запуска:
# на рандомном порту read only
python3 -m pyftpdlib
# на указанном порту
python3 -m pyftpdlib -p 22222
# с доступом на запись
python3 -m pyftpdlib -w
# с авторизацией
python3 -m pyftpdlib -w --user=name --password=123
# полный список аргументолв
python3 -m pyftpdlib -h
Мой алиас для расшаривания в текущей директории
alias ftp="python3 -m pyftpdlib -w -p 22222"
Теперь можно подключть FTP соединение как удалённую директорию стандартными средствами OS. В Windows это Add Network Location, в Linux - зависит от дистрибутива. Ищите в разделе Network вашего файлового браузера.
Также можно использовать сторонние клиенты, например FileZilla.
А здесь подробней про http.server
#libs #tricks
GitHub
GitHub - giampaolo/pyftpdlib: Extremely fast and scalable Python FTP server library
Extremely fast and scalable Python FTP server library - giampaolo/pyftpdlib
🔥11👏2👍1
⭐️ Недавно состоялся релиз Python 3.13
Помимо других апдейтов, вот на что я обратил внимание:
◽️Экспериментальный компилятор JIT, должен в будущем значительно повысить скорость.
Активируется аргументом
◽️Экспериментальный режим без GIL. Думаю, все знаю что это.
Активируется аргументом
◽️Удалили ряд стандартных библиотек (PEP-594). Вместе с ними попала под нож
◽️Обновленный REPL с колоризацией.
Команда для быстрого запуска
Либо устанавливаем исталятором↗️
#release
Помимо других апдейтов, вот на что я обратил внимание:
◽️Экспериментальный компилятор JIT, должен в будущем значительно повысить скорость.
Активируется аргументом
–enable-experimental-jit◽️Экспериментальный режим без GIL. Думаю, все знаю что это.
Активируется аргументом
–without-gil◽️Удалили ряд стандартных библиотек (PEP-594). Вместе с ними попала под нож
lib2to3. Надеюсь больше никому она и не нужна)))◽️Обновленный REPL с колоризацией.
Команда для быстрого запуска
docker run --rm -it python:3.13
Либо устанавливаем исталятором↗️
#release
👍4🤔1