Skip to main content

The library provides a lightweight API using which you can in a minute add a pattern processing function "stringify(pattern: str) -> str" to any class.

Project description

Overview

The library allows you to get a string representation of a class at RUNTIME, without overloading __repr__, __str__ or defining your own specific get_repr() -> str (or even several for different cases).
The library provides a lightweight API using which you can in a minute add a pattern processing function stringify(pattern: str) -> str to any class.

This tool is more intended to help developers that want to allow users specify their own data representation patterns.

Motivation

You're a developer. Let's assume that song_downloader is a library you wrote using strify. song_downloader.search_in_web() searchs for a song on the Internet and returns an instance of Song class that allows to download the song using Song.download_mp3()

>>> from song_downloader import search_in_web
>>> song = search_in_web(title='Loosing My Mind', artist='Falling In Reverse')
>>> print(song)
Song(Loosing My Mind, Falling In Reverse, 2018)
>>> song.download_mp3('[artist] — [title] ([year])')

The code will download the mp3 and save it as "Falling In Reverse — Loosing My Mind (2018).mp3".

You may ask: "why should I use strify if I could do that like *the code below*?"

>>> from song_downloader import search_in_web
>>> song = search_in_web(title='Loosing My Mind', artist='Falling In Reverse')
>>> print(song)
Song(Loosing My Mind, Falling In Reverse, 2018)
>>> song.download_mp3(f'{song.artist}{song.title} ({song.year})')

You definitely can. But there is no flexibility for the end user that can't change sources; usually, he/she just is not assumed to do that, it's not a good practice.

strify's approach is to ask a user to enter whatever pattern he/she wants and supply it to the program in any way (args, json, data base etc.) and just use the value in the script. That's the power: it's not necessary to define a pattern in the source code.

Now we can change the example and save it as download_mp3.py:

from song_downloader import search_in_web
args = parse_args()
song = search_in_web(title=args['title'], artist=args['artist'])
song.download_mp3(args['mp3_name_pattern'])

Then run it like this:

python3 download_mp3.py --title='loosing my mind' --artist='falling in reverse' --mp3-name-pattern='[artist] — [title] ([year])'

And check what's happened:

user@computer:~/$ ls -1
...
download_mp3.py
Falling In Reverse  Loosing My Mind (2018).mp3
...
user@computer:~/$

Usage Guide

Let's continue with our Song class:

from random import randrange

class Song:
    def __init__(self, title, artist):
        self.title = title
        self.artist = artist

    def get_year(self):
        year = randrange(1960, 2020)
        return year

Notice: Song.get_year() is a mock. In a real code it has to connect to the net and find all the data there using self.title and self.artist.

Diving in

First of all, you need to take a look at the terminology:

  • stringification — process of building class instance representation (according to a pattern)
  • pattern — a string with markers. After stringification all the markers will be replaced with marker values (or final_marker_value, see preprocessing function)
  • markerf'[{marker_name}]'
  • marker attribute — name of a class instance attribute which value is used during stringification.
  • marker value: the way strify gets marker value looks like this:
import inspect
def get_marker_value(class_instance, marker_attribute):
    marker_value = getattr(class_instance, marker_attribute)
    if inspect.ismethod(marker_value):
        marker_value = marker_value()
    return str(marker_value)
  • preprocessing function:
def preprocessing_function(marker_value: str) -> str:
    final_marker_value = whatever_magic_you_want(marker_value)
    return final_marker_value

Way #1: use stringifiable and StringifyInfo

stringifiable gets list of StringifyInfo and adds stringify(pattern: str) -> str method to the class it decorates.
One StringifyInfo in the list describes one marker.

Signature:
StringifyInfo(marker_name, marker_attribute=None, preprocessing_function=None)
If marker_attribute isn't passed to the constructor (i.e. is None) then it's assumed to be the same as passed marker_name.

from strify import stringifiable, StringifyInfo

from random import randrange

# transforms 'tHis striNg' into 'This String'
def format_proper_name(string):
    return ' '.join(word[0].upper() + word[1:].lower() for word in string.split(' '))

@stringifiable([
    StringifyInfo('title', None, format_proper_name),
    StringifyInfo('artist', 'artist', format_proper_name),
    StringifyInfo('year', 'get_year'),
])
class Song:
    def __init__(self, title, artist):
        self.title = title
        self.artist = artist

    def get_year(self):
        year = randrange(1960, 2020)
        return year

Now, the following is possible:

>>> song = Song('loosing my mind', 'falling in reverse')
>>> song.stringify('[artist] — [title] ([year])')
Falling In Reverse  Loosing My Mind (2018)
>>> song.stringify('[title]: [artist], [year]')
Loosing My Mind: Falling In Reverse, 2018

Way #2: use stringifiable and stringify

Signature:
stringify(preprocessing_func=None, marker_name=None)
If marker_name equals None (i.e. not passed) then it's assumed that marker_name == func.__name__

from strify import stringifiable, stringify

from random import randrange

# transforms 'tHis striNg' into 'This String'
def format_proper_name(string):
    return ' '.join(word[0].upper() + word[1:].lower() for word in string.split(' '))

@stringifiable()
class Song:
    def __init__(self, title, artist):
        self._title = title
        self._artist = artist

    @stringify(format_proper_name)
    def artist(self):
        return self._artist

    @stringify(format_proper_name)
    def title(self):
        return self._title

    @stringify(marker_name='year')
    def get_year(self):
        year = randrange(1960, 2020)
        return year

Notice: it would be more usual to make properties. In this case, stringify must be the first decorator that's applied to the function.

@property
@stringify(format_proper_name)
def title(self):
    return self._title

Now you can test the code we ran at the end of Way #1 and ensure that we achieved the same interface and results:

>>> song = Song('loosing my mind', 'falling in reverse')
>>> song.stringify('[artist] — [title] ([year])')
Falling In Reverse  Loosing My Mind (2018)
>>> song.stringify('[title]: [artist], [year]')
Loosing My Mind: Falling In Reverse, 2018

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

strify-1.0.2.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

strify-1.0.2-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file strify-1.0.2.tar.gz.

File metadata

  • Download URL: strify-1.0.2.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/45.1.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/3.6.9

File hashes

Hashes for strify-1.0.2.tar.gz
Algorithm Hash digest
SHA256 79914a3d40916f8d8f2530c1254fc54b032e2c31c4c98de7fbbc6825b5cc5aa7
MD5 d50cfdc30e1ca3fab726225c2bf40e93
BLAKE2b-256 f3d84c0a2876752fa8cb06fea544925efd58cab947c7834cdbdd306bd35dacd9

See more details on using hashes here.

File details

Details for the file strify-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: strify-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 13.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/45.1.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/3.6.9

File hashes

Hashes for strify-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 31436d632605c7859e17435f532409dc889fb51866a69fc229aa3d367d4a8464
MD5 e71b772c43029ab83bbcf9ba7fa79ccc
BLAKE2b-256 09bff9a8fa864a7afaaf8e59c280d77b926e7973204cfe53ef535f0fc712096a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page