Package: extype
ExTypeExtype stands for extensible types, a Python package that enables extending types.InstallationpipinstallextypeAlternatively, you can install through git (make sure to have pip 22.0 or higher):python-mpipinstall--upgradepip
pipinstallgit+https://github.com/xpodev/extype/UsageFirst, in your Python code, import the package:importextypeThen, you can use the built-in extensions for the builtin types. In order to apply these extensions,
import theextend_allmodule from theextype.builtin_extensionspackage:fromextype.builtin_extensionsimportextend_allThis will apply the extensions to all builtins we support,as a side-effect of the import(to extend only some builtins, you can use the dedicated modules, see below).Sometimes you don't want to apply all the extensions that we provide, but only for some specific type(s).Say, for example, we only want to apply the provided extensions forlist. We'll need to manually
apply them like so:fromextype.builtin_extensionsimportlist_extlist_ext.extend()Note:All built-in extension modules have anextendfunction which will apply the extensions in the module to the relevant type.Currently, we provide the following extensions:fileextended typesdict_ext.pydict_keys, dict_values, dict_itemsfloat_ext.pyfloatfunction_ext.pyFunctionType, LambdaTypeint_ext.pyintlist_ext.pylistseq_ext.pymap, filter, range, zipstr_ext.pyto_int, to_floatThen you can use these extensions. Here's an example of using thelist.mapextension:print([1,2,3].map(lambdax:x+1))# [2, 3, 4]There's a list of all the built-in extensionshereCreating your own extensionsYou can create your own extension methods, with which you can extend any type you want! (not only builtins)
For example, let's make our owntofloatfunction in theinttype.
What we want to have at the end is:x=10print(isinstance(x.tofloat(),float))# TrueFirst, we'll need some tools:fromextypeimportextension,extend_type_withNext, we'll define our class which will hold the extension method. Note that this class will not get instantiated.
It is also recommended to make this class inherit the type you want to extend, so you get better typing support.classIntExtension(int):# inheriting `int` for typing@extension# marks this method to be added as an extensiondeftofloat(self):# self will be of the same type we extend, which, in this case, is `int`returnfloat(self)# convert the int to float and return the resultAfter we create the class which will contain the extension methods, we need to apply them to the types we want to extend:extend_type_with(int,IntExtension)Now, we can run the code from above:x=10print(isinstance(x.tofloat(),float))# TrueWe can also apply multiple extensions to the same type or even the same extension to multiple types.Only methods marked with@extensionwill be added as extension methods.Note:Extending a type will extend it in all modules, not just the one that called theextend_type_with,
so make sure you don't override an existing function, unless, of course, it is what you want.FeaturesExteranlly extend type via another typeBasic support for magic method extensionsNumber protocolMapping protocolSequence protocolAdd support for reverse methods (e.g.__radd__)Make this features/todo list look nicerAdd support for the rich comparison functionMaintainersBuild & InstallationWe useHatchto manage the build environment,
andmesonpyto build the package.Note:Currently, we use unreleased mesonpy features, so we install it from git.First, install Hatch:https://hatch.pypa.io/latest/install/. We recommend usingpipx.After you've installed Hatch, you can build the package with the following command:hatchruninstall_editableWith this, you can start using the package in your code.
Spawn shell within the build environment:hatchshellIt'll rebuild the package every time you import it, so you can test your changes.
If you don't want to rebuild the package every time you import it, you can install it with:hatchruninstallBut note that any changes you make won't be reflected in the installed package.To build the wheel, you can use:hatchrundist:buildThis will build the wheel for all python versions, and put it in thedistfolder.TestingTo run tests for all python versions, run:hatchrundist:testTo run tests for a specific python version, run:hatchrun+py=39dist:testBoth commands will build, install the package into an isolated environment,
and run the tests in it.Built-in ExtensionsNote:All of the followinglistextensions also exist ondict_keys,dict_valuesanddict_items.list.all(self:List[T],fn:Callable[[T],bool]=bool)->boolReturns true if all elements, mapped through the givenfn, areTrue.list.any(self:List[T],fn:Callable[[T],bool]=bool)->boolReturns true if any of the elements, mapped through the givenfn, isTrue.list.map(self:List[T],fn:Callable[[T],U])->List[U]Returns a new list whose elements are the result of applying the given function on each element in the original list.list.reduce(self:List[T],fn:Callable[[T,T],T])->TReduces the list to a single value, using the given function as the reduction (combination) function.RaisesTypeErrorif the list is empty.list.reduce(self:List[T],fn:Callable[[U,T],U],initial_value:U)->UReduces the list to a single value, using the given function as the reduction (combination) function and the initial value.list.filter(self:List[T],fn:Callable[[T],bool])->List[T]Returns a new list containing all the elements that match the given predicatefn.list.first(self:List[T])->T,raiseIndexErrorReturns the first element in the list, or raises anIndexErrorif the list is empty.list.last(self:List[T])->T,raiseIndexErrorReturns the last element in the list, or raisesIndexErrorif the list is empty.float.round(self:float)->intRounds the floating point number to the nearest integer.float.round(self:float,ndigits:int)->int|floatRound the floating point number to the nearest float withndigitsfraction digits.# function @ functioinfunction.__matmul__(self:Callable[[T],U],other:Callable[...,T])->Callable[...,U]Compose 2 functions such that doing(foo @ bar)(*args, **kwargs)will have the same result as callingfoo(bar(*args, **kwargs)).int.hex(self:int)->strReturns the hexadecimal representation of the integer.int.oct(self:int)->strReturns the octal representation of the integer.int.bin(self:int)->strReturns the binary representation of the integer.str.to_int(self:str,base:int=10,default:T=...)->int|TConverts the given string to an int with the given base. If it can't be
converted anddefaultis given, it is returned. Otherwise, aValueErroris thrown.str.to_float(self:str,default:T=...)->float|TConverts the given string to a float. If it can't be
converted anddefaultis given, it is returned. Otherwise, aValueErroris thrown.The following extensions are valid formap,filter,rangeandzip.tolist(self:Iterable[T])->List[T]Exhausts the iterble and creates a list from it..map(self:Iterable[T],fn:Callable[[T],U])->Iterable[U]Maps the iterable with the given function to create a new iterable.This does not iterates through the original iterable..filter(self:Iterable[T],fn:Callable[[T],bool])->Iterable[T]Filters the iterable with the given function as the predicate function.This does not iterates through the original iterable.