Skip to main content

aliasing

Tests Status Coverage Status Flake8 Status Code style: black

PyPi

aliasing is a small utility library for python which adds aliases to class members using python descriptors.

Usage

Direct use of @aliased

This is the recommended way to use the library if you are going to call the generated members in your scripts, as it supports IDE completion.

Basic usage involves a similar process to the builtin @property and @<property_name>.getter/setter. Instead we use @aliased to indicate the method whose register is being duplicated and @<aliased_name>.alias to indicate which method's name should be used to point to the "aliased" method:

from aliasing import aliased


class Example:
    @aliased
    def method(self):
        return "my method call"

    @method.alias
    def method_alias(self): ...

# elsewhere...

example = Example()
# note that `==` and `is` always returns False for function objects
# i.e., this is False:
#   example.method == example.method
assert example.method.__code__ is example.method_alias.__code__
assert example.method_alias() == "my method call"

Using "Virtual" Aliases to create a number of aliases at once

This is not strictly recommended for use in most cases unless your class will be processed by some framework which relies on the class members to generate something an end-user might want.

Basic usage involves decorating your class's methods with @valiases and specifying the names of however many aliases you want for that method.

For instance, if you want to make the function's old name available so as not to break the api, but remove it from IDE completion, you can add it as a virtual alias:

from aliasing import valiases

class Example:
    @valiases("my_func_old_name")
    def my_func(self):
        return "foo"

# elsewhere
example = Example()
# this is available with auto-complete:
foo = example.my_func()
# this will _work_ but will give the user an "Unresolved attribute" warning:
foo_old = example.my_func_old_name()

This is a more convenient and shorter method of adding aliass to your

For example, in Google's python-fire cli tool, cli commands are "generated" using the members of a class, so you can easily add several commands at once using this library's @valiases decorator:

# fire_alias_example.py
import fire
from aliasing import valiases

class Example:
    @valiases("c", "cfg", "conf")
    def config(self):
        return "foo"

if __name__ == "__main__":
    fire.Fire(Example())

Then from cli, the user can call the aliased method or its aliases to achieve the same result:

$ python fire_alias_example.py config
foo
$ python fire_alias_example.py cfg
foo
$ python fire_alias_example.py conf
foo
$ python fire_alias_example.py c
foo

Or you might want to add names functions which do not follow PEP 8 naming conventions without disabling your linter or ide inspection settings. Perhaps this code will be called in another language, and you want to make sure the methods follow that language's style as well:

from aliasing import valiases

class Example:
    @valiases("MyFunc", "myFunc", "MY_FUNC")
    def my_func(self):
        return "foo"

Advanced Usage

alias Descriptor

Since alias objects are just python descriptors (docs), you can use them with more granularity too:

from aliasing import alias


class Example:
    my_alias = alias(alias_for="prop")
    
    def __init__(self, val):
        self.prop = val

# elsewhere
example = Example(object())
assert example.prop is example.my_alias

You can define them independently from classes then attach them to any number of classes without hierarchical relation.

class Foo:
    def __init__(self, val):
        self.prop = val
        
class Bar:
    def __init__(self, val):
        self._prop = val
        
    @property
    def prop(self):
        return f"Bar.prop: {self._prop}"

# elsewhere
from aliasing import alias

prop_alias = alias(alias_for="prop", alias_name="my_alias")

prop_alias.attach(Foo)
prop_alias.attach(Bar)

# now both classes have the alias named "my_alias" pointing to "prop"
assert Foo('baz').my_alias == 'baz'
assert Bar('baz').my_alias == 'Bar.prop: baz'

You can check out the tests to see some more examples of alternative ways to attach alaiss to your classes.

aliased Descriptor

You can also initialize aliased descriptors independently from classes:

from aliasing import aliased

trample_ok Parameters

By default, the aliasing library will raise a TrampleAliasError if you try to override existing class attributes or members without specifying trample_ok for that alias.

For instance, this will fail when alias.attach is called:

class Foo:
    def __init__(self, val):
        self.prop = val
    
    @staticmethod
    def my_alias():
        return "don't trample me"

# elsewhere
from aliasing import alias

prop_alias = alias(alias_for="prop", alias_name="my_alias")

# fails with TrampleAliasError("Owner calls Foo already has member with name my_alias. [..]")
prop_alias.attach(Foo)

And this will fail whenever the class is imported:

from aliasing import valiases

class Foo:
    # fails with TrampleAliasError("Owner class Foo already has member with name __str__. [..]")
    @valiases("__str__")
    def to_str(self): ...

But you can pass trample_ok in a couple different ways to override this behavior.

For alias:

class Foo:
    def __init__(self, val):
        self.prop = val

    @staticmethod
    def my_alias():
        return "don't trample me"

# elsewhere
from aliasing import alias

prop_alias = alias(alias_for="prop", alias_name="my_alias")

# trample_ok causes a warning TrampleAliasWarning, but no longer fails
prop_alias.attach(Foo, trample_ok=True)

assert Foo('change is good').my_alias == 'change is good'

# OR if you prefer you can set `trample_ok` on the alias itself:
prop_alias = alias(alias_for="prop", alias_name="new_alias", trample_ok=True)
prop_alias.attach(Foo)
assert Foo('this also works').new_alias == 'this also works'

For valiases:

from aliasing import valiases

class Foo:
    # trample_ok causes a warning TrampleAliasWarning, but no longer fails
    @valiases("__str__", trample_ok=['__str__'])
    def to_str(self):
        return 'new __str__ for Foo'

# I would not recommend 'trampling' magic methods like __str__
# ... but it's your life
assert Foo().__str__() == 'new __str__ for Foo'

The major benefit of this is that your can easily override several methods at once if they all do the same thing (like return "NotImplemented"):

import abc
from typing import Any

class CrudBase(abc.ABC):
    @abc.abstractmethod
    def create(self, name: str, data: Any) -> Any: ...

    @abc.abstractmethod
    def read(self, name: str) -> Any: ...

    @abc.abstractmethod
    def update(self, name: str, partial_data: Any) -> Any: ...

    @abc.abstractmethod
    def delete(self, name: str) -> Any: ...

# elsewhere
from aliasing import valiases
from some_persistence_lib import read_method

class ReadOnlyBase(CrudBase, abc.ABC):
    options = {'arg': 'val'}
    
    # now if any of these methods are called, they will get 'NotImplemented'
    # this saves you from redefining the same 2-liner method 3 times.
    # obviously the benefits are better the more methods there are to override
    @valiases('create', 'update', 'delete', trample_ok=['create', 'update', 'delete'])
    def _not_implemented(self, *args, **kwargs) -> Any:
        return NotImplemented
    
    def read(self, name: str) -> Any:
        return read_method(name, **self.options)

Questions, Contributing, Feature requests

If you'd like to get in touch for any reason, the easiest thing is opening a GitHub issue.

Please give older issues (including closed!) a look before opening anything and I'll try to respond whenever I can.

Metadata

Release files for aliasing 0.4.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aliasing 0.4.2
File Size Uploaded
aliasing-0.4.2.tar.gz 12.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aliasing 0.4.2
File Interpreter ABI Platform
aliasing-0.4.2-py3-none-any.whl Python 3 none any Details

Total release size: 22.6 kB

Release files / aliasing-0.4.2.tar.gz

Download URL aliasing-0.4.2.tar.gz
Size 12.6 kB
Tags Source
SHA-256 checksum
How to use checksums
ca224a4436e71fe8cafda46e6cbb401e38e45c9bed17f74948677a011f317243
BLAKE2b-256 checksum
How to use checksums
2424a6d2f18bda9b16efa593ea137af8e93698d0a02c5857d25f876ae3757313
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via pdm/2.15.4 CPython/3.12.3 Linux/6.5.0-1021-azure

Release files / aliasing-0.4.2-py3-none-any.whl

Download URL aliasing-0.4.2-py3-none-any.whl
Size 10.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ce75676617504cb9d42b0e9ac518e8820813357ac802a7e8658aa911ab081ed7
BLAKE2b-256 checksum
How to use checksums
9e1c5734b3ebe4fcc84332e326f5c897da35e67eb06ed5eabcb2c659458b14df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via pdm/2.15.4 CPython/3.12.3 Linux/6.5.0-1021-azure

Release history Release notifications | RSS feed

This release

0.4.2 This release

2 release files

0.3.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page