1

What are good recipes or light-weight libraries to - given a specified schema/template - compile strings from parameters and parse parameters from strings?

This is especially useful when working with URIs (file paths, URLs, etc.). One would like to define the template, along with any needed value converters, and be able to

  1. validate if a string obeys the template's rules
  2. produce (i.e. compile) a string given the template's parameters
  3. extract parameters from a valid string (i.e. parse)

It seems the builtin string.Formatter has a lot of what's needed (not the parameter extraction though), but the URI compiling and parsing use case seems so common that I'd be surprised if there wasn't already a go-to library for this.

Working example

I'm looking for something that would do the following

>>> ln = LinearNaming('/home/{user}/fav/{num}.txt',  # template
...                   format_dict={'user': '[^/]+', 'num': '\d+'},  
...                   process_info_dict={'num': int}  # param conversion
...                  )
>>> ln.is_valid('/home/USER/fav/123.txt')
True
>>> ln.is_valid('/home/US/ER/fav/123.txt')
False
>>> ln.is_valid('/home/US/ER/fav/not_a_number.txt')
False
>>> ln.mk('USER', num=123)  # making a string (with args or kwargs)
'/home/USER/fav/123.txt'
>>> # Note: but ln.mk('USER', num='not_a_number') would fail because num is not valid
>>> ln.info_dict('/home/USER/fav/123.txt')  # note in the output, 123 is an int, not a string
{'user': 'USER', 'num': 123}
>>>
>>> ####### prefix methods #######
>>> ln.is_valid_prefix('/home/USER/fav/')
True
>>> ln.is_valid_prefix('/home/USER/fav/12')
False  # too long
>>> ln.is_valid_prefix('/home/USER/fav')
False  # too short
>>> ln.is_valid_prefix('/home/')
True  # just right
>>> ln.is_valid_prefix('/home/USER/fav/123.txt')  # full path, so output same as is_valid() method
True
>>>
>>> ln.mk_prefix('ME')
'/home/ME/fav/'
>>> ln.mk_prefix(user='YOU', num=456)  # full specification, so output same as same as mk() method
'/home/YOU/fav/456.txt'

(The example above uses LinearNaming of https://gist.github.com/thorwhalen/7e6a967bde2a8ae4ddf8928f1c9d8ea5. Works, but the approach is ugly and doesn't use string.Formatter)

thorwhalen
  • 1,920
  • 14
  • 26
  • What version of python are you using? Have you looked at string interpolation options? https://stackoverflow.com/questions/4450592/is-there-a-python-equivalent-to-rubys-string-interpolation#4450610 – Hayden Sep 03 '19 at 01:19
  • @Hayden, I'm using 3.7 and about to give 3.8beta a run. Yes, string interpolation (especially with custom string.Format subclassing) could get me the (2) produce side, I could also get (1) validate (but with some work), but see nothing much for (3) extract. So far, it seems that going through regex is the best bet for validation and extraction. – thorwhalen Sep 03 '19 at 14:22

1 Answers1

0

Werkzeug is a set of tools for making web applications, and it provides a lot of functionality for dealing with urls.

For example:

url = "https://mywebsite.com/?location=paris&season=winter"

from werkzeug import urls

params = urls.url_parse(url).decode_query()
params['season']
>>> 'winter'

Give it a look:

https://werkzeug.palletsprojects.com/en/0.14.x/urls/

Edit: As for generic templating, another library from the flask toolset, namely Jinja, could be a good option.

f-strings are also a simple tool for the job.

Now, the specific use-case you presented is basically a combination of templating, like what you see in Jinja or f-strings, with regex for validating the variables. I don't know how something so specific could be accomplished in a simpler way than through something that will end up being equivalent with the LinearNaming library. You need to call a function (at least if you don't want to monkey patch the string class), you need to define the regex (otherwise the library cannot distinguish important characters in the template like '/'), and you need to pass the variable name/value pairs.

  • Thanks for your answer @David Moseler. It's not really what I'm going for though. First, I'm trying to solve the general problem of production/validation/extraction with parametrized strings. I wouldn't use werkzeug of flask for this because (1) they're solutions for specific templates and (2) I'd have to pull in a whole package for that (I'd rather use just builtins). Indeed, you point out the minimum necessary information, and my LinearNaming class takes care of it. But I'm sure there's a more elegant solution/interface. – thorwhalen Sep 20 '19 at 20:16