Programming, Photography, Guides, Thoughts

Python 3.8 end of life coming soon


Python 3.8 will/has rea­ched it’s end of life 1 mon­th ago. Soon, you will be for­ced to upgra­de as tools and lib­ra­ries gra­du­ally start remo­ving it’s sup­port. If you have the opti­on to upgra­de to the latest Python ver­si­on, take it. But espe­ci­ally lib­ra­ry main­ta­i­ners don’t have that luxu­ry and still have to keep 3.9 sup­port around. It’s been a whi­le sin­ce all the „What’s new in Python 3.9″ articles came out. So here’s a farewell of what’s going away and hello to what can you start using instead.

Befo­re we go into the details of what’s chan­ging, I would recom­mend try­ing a tool called pyupgrade first to see what Python 3.9+ chan­ges can be done for you automatically.

typing Generic (PEP 585)

Whi­le typing gene­rics such as list[...] and dict[..., ...] have been possi­ble sin­ce Python 3.7 thanks to from __future__ import annotations, the­re might be still pla­ces in the code base that use the old typing.List / typing.Dict gene­rics. After Python 3.8, these can offi­ci­ally go. What can be replaced?

  • typing.Tuple -> tuple
  • typing.List -> list
  • typing.Dict -> dict
  • typing.Set -> set
  • typing.FrozenSet -> frozenset
  • typing.Type -> type
  • typing.ContextManager -> contextlib.AbstractContextManager
  • typing.AsyncContextManager -> contextlib.AbstractAsyncContextManager
  • typing.Pattern -> re.Pattern
  • typing.Match -> re.Match

The­re are also other gene­rics that are com­ple­te­ly new.

Operator for merging dicts (PEP 884)

{**d1, **d2} -> d1 | d2

d1.update(d2) -> d1 |= d2

New String Methods to Remove Prefixes and Suffixes (PEP 616)

You may have vari­ous local or back-por­ted imple­men­tati­ons that can now be repla­ced with built-in ones:

removeprefix(string, prefix) -> string.removeprefix(prefix)

removesuffix(string, prefix) -> string.removesuffix(prefix)

IANA Time Zone Database in the Standard Library (PEP 615)

Time zone data has been pre­vi­ous­ly avai­la­ble via a thi­rd-par­ty lib­ra­ry dateutil.tz. It is bac­ked by the sys­tem time zone data. If it’s mis­sing, tzdata installati­on is required.

dateutil.tz.gettz -> zoneinfo.ZoneInfo

Exam­ple use:

from datetime import datetime
from zoneinfo import ZoneInfo

print(datetime.now(ZoneInfo("Europe/Prague")))
from datetime import datetime

from dateutil.tz import gettz

print(datetime.now(gettz("Europe/Prague")))

Flexible function and variable annotations (PEP 593)

If you­’re a use of the FastA­PI web fra­mework, you are like­ly used to the Annotated key­word alrea­dy for spe­ci­fy­ing que­ry para­me­ters, vali­dati­on, etc. Unless you are upgra­ding the ver­si­on of FastA­PI as well, only the import locati­on chan­ges for you:

from typing_extensions import Annotated -> from typing import Annotated

typing.Annotated does­n’t add any functi­o­na­li­ty on its own but rather allows type chec­kers and other tools to be smar­ter. You will find exam­ples sug­ges­ting it as a way to pro­vi­de more details about the type. But for such pur­po­se, typing.TypeAlias or typing.NewType would be more suitable.

from typing import Annotated

Kilometers = Annotated[float, "kilometers"]
Seconds = Annotated[float, "seconds"]
KilometersPerHour = Annotated[float, "kilometers per hour"]

def speed(distance: Kilometers, time: Seconds) -> KilometersPerHour:
    ...
from typing import TypeAlias

Kilometers: TypeAlias = float
Seconds: TypeAlias = float
KilometersPerHour: TypeAlias = float

def speed(distance: Kilometers, time: Seconds) -> KilometersPerHour:
    ...
from typing import NewType

Kilometers = NewType("Kilometers", float)
Seconds = NewType("Seconds", float)
KilometersPerHour = NewType("KilometersPerHour", float)

def speed(distance: Kilometers, time: Seconds) -> KilometersPerHour:
    ...

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.