How can I format a user selection matrix?

[quote=“markfilipak, post:12, topic:10868”]
Oh, I think I get it.
1, The command is on 3 lines instead of 1 line – why that was done is unknown.
2, The example turns this string:
def myfunc():
into this string:
static PyObject\npy_myfunc(void)\n{
(lord, this forum software is awful – plain text would be much easier and clearer)
3, The parenthese are capturing (as indicated by ‘\1’ in the replacement)

Wow. Such an obscure example.

I think that gives me enough info to complete the processing of ‘configSuper’. I’ll post the results in a bit.

What does “REPL” mean?

Petr’s solution still requires regexp filtering.

Read-Eval-Print-Loop.

It means “what you get when you just start ‘python’” without a script - the environment with the >>> where you can run Python interactively.

Python 3.9.1 (tags/v3.9.1:1e5d33e, Dec  7 2020, 17:08:21) [MSC v.1927 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> petrs_solution = ( ""
...  # Does not
...  # + "require"
...  + "any filtering"
...  # at all
... )
>>>

This is very strange.

Under normal circumstances, there is a bunch of things added by the site
module, which includes adding the help() built-in:

https://docs.python.org/3/library/functions.html#help

I don’t understand why you don’t have those things installed. They
include builtins help and quit.

Have you installed a custom version of Python? How did you install it?
Are you running it in the Windows shell, or Powershell, or are you using
an IDE, or something else?

Your installation is, in my opinion, significantly broken, but I don’t
know why. It would be good to know what the python command on your
system is actually doing. If you are running Powershell, I think you can
run:

where python

to see what it runs.

Here’s a thought: try running py3 instead and see if anything is
different.

The string, configSuper, must reduce to ‘{gpu:0,pel:2,scale{up:2,down:4},rc:0}’ on one line with no spaces. That requires regexp.

Read-Eval-Print-Loop, eh? I don’t know why you wrote “REPL” but I’m pretty dense sometimes.

I’m not going to post back the result “in a bit”. It’s 3AM where I live. I’m going to catch some Zzzzz. I’ll post back tomorrow.

Thanks All. I couldn’t have done it without you.

>>> configSuper = ("{"
... # To configure, add/move/remove lefthand '#'s"
... # +   "gpu:1,full:true,"        #           Use GPU; set precision to whole pixels.
... # +   "gpu:1,full:false,"       #           Use GPU;                  whole pixels; limits memory demand when processing very large (e.g. 4K) frames.
... # +   "gpu:0,pel:1,"            #                                     whole pixels.
... # +   "gpu:0,pel:1,full:true,"  #                                     whole pixels.
... # +   "gpu:0,pel:1,full:false." #                                     whole pixels; limits memory demand when processing very large (e.g. 4K) frames.
...   +   "gpu:0,pel:2,scale:{"     # -default-                            half pixels (i.e. upscale clipSuper to clipSource via 1x1-to-2x2 pixel duplication).
... # +   "gpu:0,pel:4,scale:{"     #                                   quarter pixels (i.e. upscale clipSuper to clipSource via 1x1-to-4x4 pixel duplication); not recommended.
... # +       "up:0,"               #           Upscale interim clip method: Bilinear.
... # +       "up:1,"               #                                        Bicubic, 4 tap Catmull-Rom.
...   +       "up:2,"               # -default-                              Bicubic, 6 tap Wiener -- like Lanczos; sharper.
... # +       "down:0},"            #           Downscale result method: Simple 4-pixel average -- like AviSynth's unfiltered SimpleResize; minimum anti-aliasing.
... # +       "down:1},"            #                                    Triangle (shifted)     -- like ReduceBy2;
      moderate anti-aliasing.
... # +       "down:2},"            #                                    Triangle               -- like BilinearResize;
          more anti-aliasing.
... # +       "down:3},"            #                                    Quadratic              --
     even more anti-aliasing.
...   +       "down:4},"            # -default-                          Cubic                  -- like BicubicResize(b=1,c=0);             maximum anti-aliasing.
...   +   "rc:0}"                   #           The 'rc' attribute is required by Super(); this merely creates it.
... )
>>> configSuper
'{gpu:0,pel:2,scale:{up:2,down:4},rc:0}'
>>>

It’s a fairly common term that’s used with many interpreted languages, but there’s absolutely nothing wrong with not being familiar with it. :slight_smile:

Do you mean py?

Hi Mark,

You said:

“It is documentation written by codesmiths for codesmiths.”

Well, yes :slight_smile:

Have you considered doing the tutorial? That is documentation written

for beginners and may help you a lot.

https://docs.python.org/3/tutorial/index.html

Are you familiar with regular expressions in other languages? Python

regexes are pretty close to identical to the standard regex syntax used

by most languages. You just need to adjust to a few minor differences.

One minor difference compared to, say, Perl, is that regexes do not have

their own special type. Regexes in Python are just strings. So if you

know how to write a string:

food = "cheese"

then you know how to write a regular expression pattern:

pattern = "cheese"  # Matches the exact string 'cheese'.

The only tricky part is that Python strings, by default, interpret

backslash as an escape sequence for control characters. So:

newline = '\n'

is a one character string, not two, containing an ASCII newline, not

backslash followed by d. That can clashes with the use of actual

backslashes in regular expressions:

match_digits = '\d+'  # Match one or more digits. (Maybe...)

Without actually trying it, I don’t know whether that will be:

  • backslash d plus

  • or some special control character plus.

The rules for when backslashes are interpreted as escape sequences for

control characters (like newline, tab, carriage return etc) and when

they are left in are unfortunately confusing.

There are two easy ways to fix that:

# Double-up the backslashes so that they are escaped.

match_digits = '\\d+'  # Match one or more digits.



# Use a so-called "raw string".

match_digits = r'\d+'  # Match one or more digits.

Both of those will result it match_digits being the string:

  • backslash d plus

which can be used as a regular expression pattern to match one or more

digits.

Raw strings disable the special interpretation of backslash escape

sequences, so that backslashes become just a plain old character like

the rest. So while it is not compulsory, nearly everyone using Python

prefers to use raw strings for regex patterns. It just makes it easier.

So in this example from the docs, we have this function call:


re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):',

       r'static PyObject*\npy_\1(void)\n{',

       'def myfunc():')

Let’s break it down. The first argument is the pattern to match, the

second is the replacement string, and the third is the text to match

against:

target = r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):'

replacement = r'static PyObject*\npy_\1(void)\n{'

text = 'def myfunc():'

re.sub(target, replacement, text)

which returns:

'static PyObject*\npy_myfunc(void)\n{'

(Personally, I think this is a horribly complicated example for

beginners to be exposed to in the docs. Oh well.)

Let’s analyse the target. The leading r’ tells the interpreter that this

is a string, and to treat backslash as an ordinary character, not a

control character escape sequence. So we have the pattern:

def              # Literally the letters d e f

\s+              # one or more spaces

(                # begins a group

[a-zA-Z_]        # a letter a...z, A...Z or underscore

[a-zA-Z_0-9]*    # zero or more letters, underscores or digits

)                # ends the group

\s*              # zero or more spaces

\(               # a literal left-bracket (

\s*              # zero or more spaces

\)               # a literal right-bracket )

:                # a colon

So that’s the regex pattern being searched for. The replacement is:

static PyObject*     # literally what you see

\n                   # newline

py_                  # literally the letters p y underscore

\1                   # the contents of Group 1 in the matched text

(void)               # literally what you see

\n                   # another newline

{                    # and an left-brace {

The text being searched is “def myfunc():”. It matches the regex, with

the word “myfunc” matching group 1. So the regular expression index

extracts out the group “myfunc” and inserts it where the backslash-1 is,

giving us the resulting text:

# This original

def myfunc():



# becomes this

static PyObject*

py_myfunc(void)

{

Regular expressions are a special language of their own. They are

complex and powerful, and (aside from some minor differences) shared by

most programming languages, but also painfully terse. If you have never

used them before, I can understand the culture shock you are

experiencing.

You are mistaking an object oriented style for the objected oriented
programming model.

Python’s language model is 100% object oriented. Everything is an
object: strings and ints and floats, lists and dicts are all objects. It
is also a class-based object model rather than a protocol-based
object model.

Even modules, functions and classes are themselves objects.

def myfunction():
    pass

isinstance(myfunction, object)
# returns True

Functions have attributes and methods, and they belong to a class. Even
classes are instances of a class, their metaclass.

But Python doesn’t force everything to be an object-oriented style. We
sometimes prefer to use functions where other languages use methods.

https://docs.python.org/3/faq/design.html#why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list

That doesn’t make the language model any less object oriented, it just
means that we sometimes prefer the functional style of writing code.
Both styles and pros and cons, and Python has the flexibility to let you
choose.

We often say that Python is a multi-paradigm language in that we can
write code in many combinations of:

  • Imperative style
  • Procedural style
  • Object oriented style
  • Functional style
  • Asyncronous style
  • Event-driven style
  • Concatenative style
  • Declarative style

and more. (Although some styles are a better fit to the language than
others.)

I don’t know, do I mean py? Isn’t that likely to try to run Python 2

instead of Python 3? I’m not a Windows user.

Mark said:

“The string, configSuper, must reduce to
‘{gpu:0,pel:2,scale{up:2,down:4},rc:0}’ on one line with no spaces.”

Then why not just write:

configSuper = '{gpu:0,pel:2,scale{up:2,down:4},rc:0}'

instead of messing about writing this giant config string with lines
commented out, and then trying to cut it down to the one line that’s not
commented out? I don’t understand what problem you are trying to solve
by making it more complicated rather than less.

Besides, you don’t need a regex to remove commented out lines. As I
suggested earlier, the easiest way to write a multi-line string in
Python is to use a triple-quoted string:

configSuper = """
    # comment
    # another comment
    # more comments
    keep this line
    # more comments

    # the line above is blank
    """

L = configSuper.splitlines()
lines = []
for line in lines:
    line = line.strip()
    if line and not line.startswith("#"):
        lines.append(line)

if len(lines) != 1:
    print('too many uncommented lines')
else:
    configSuper = lines[0]

No regex required.

Wake up fresh… :grinning_face_with_smiling_eyes:

GOT IT!

https://discuss.python.org/t/how-can-i-format-a-user-selection-matrix/10868/4?u=markfilipak
Third block down… I had the quotes in the wrong places.

Then why not just write:
configSuper = '{gpu:0,pel:2,scale{up:2,down:4},rc:0}'

The string presentation is intended to be a self-documenting selection block that shows the default settings (i.e. “-default-”) with exposition (the comments) and with the current user selections (via lines that don’t begin with “#”) in the most compact but easily readable form possible. It’s my style of script user interface.

Thank you, All! I have an excellent start now.
I do see how I had the quotes in the wrong places – I was grasping at straws. Now I see how python parses the input. Good lesson, well learned. There is Joy.

PS: To recapitulate, This works.

configSuper = (   # To configure, add/move/remove lefthand '#'s
"{"
# +   "gpu:1,full:true,"        #           Use GPU; set precision to whole pixels.
# +   "gpu:1,full:false,"       #           Use GPU;                  whole pixels; limits memory demand when processing very large (e.g. 4K) frames.
# +   "gpu:0,pel:1,"            #                                     whole pixels.
# +   "gpu:0,pel:1,full:true,"  #                                     whole pixels.
# +   "gpu:0,pel:1,full:false." #                                     whole pixels; limits memory demand when processing very large (e.g. 4K) frames.
  +   "gpu:0,pel:2,scale:{"     # -default-                            half pixels (i.e. upscale clipSuper to clipSource via 1x1-to-2x2 pixel duplication).
# +   "gpu:0,pel:4,scale:{"     #                                   quarter pixels (i.e. upscale clipSuper to clipSource via 1x1-to-4x4 pixel duplication); not recommended.
# +       "up:0,"               #           Upscale interim clip method: Bilinear.
# +       "up:1,"               #                                        Bicubic, 4 tap Catmull-Rom.
  +       "up:2,"               # -default-                              Bicubic, 6 tap Wiener -- like Lanczos; sharper.
# +       "down:0},"            #           Downscale result method: Simple 4-pixel average -- like AviSynth's unfiltered SimpleResize; minimum anti-aliasing.
# +       "down:1},"            #                                    Triangle (shifted)     -- like ReduceBy2;                         moderate anti-aliasing.
# +       "down:2},"            #                                    Triangle               -- like BilinearResize;                        more anti-aliasing.
# +       "down:3},"            #                                    Quadratic              --                                        even more anti-aliasing.
  +       "down:4},"            # -default-                          Cubic                  -- like BicubicResize(b=1,c=0);             maximum anti-aliasing.
  +   "rc:0}"                   #           The 'rc' attribute is required by Super(); this merely creates it.
)

py.exe is the name of the Python launcher executable on Windows. You can tell if to launch Python 2 (py -2) if you want to for some reason. You can also tell it explicitly that you want Python 3 (py -3). As far as I know, it always defaults to Python 3, but it’s been a very long time since I’ve used a Windows system with Python 2.x installed.

Hmmm… Below are all the files (in vapoursynth) that seem to be python related:

_asyncio.pyd
_bz2.pyd
_ctypes.pyd
_decimal.pyd
_elementtree.pyd
_hashlib.pyd
_lzma.pyd
_msi.pyd
_multiprocessing.pyd
_overlapped.pyd
_queue.pyd
_socket.pyd
_sqlite3.pyd
_ssl.pyd
pyexpat.pyd
python.cat
python.exe
python3.dll
python38._pth
python38.dll
pythonw.exe
seek-test.py
select.pyd
setup.py
unicodedata.pyd
vapoursynth.cp38-win_amd64.pyd
vs_plugin_check.py
vsrepo.py
winsound.pyd

You folks have put a fair bit of time into my education/experimentation, so I feel I should illuminate my application for your possible profit. The application is conversion of 3 video types: film, NTSC & PAL TV, and mixed film-TV (such as “Making Of” documentaries), to 120 frames per second [note 1] by anyone regardless of their video or python knowledge. The eventual goal is a one-click conversion, regardless of the type of source video, and with no diddling of parameters at all. Amazingly, the 120 FPS, HEVC encoded targets wind up 1/8th the file size of the original Blu-ray & DVD sources, so anyone with a media server will profit greatly. The target videos are essentially lossless. This approach should even benefit digital cinemas due to the smaller file sizes and consequential bits-per-second increase. It may even benefit streaming if the procedures are followed by a variable frame rate compressor prior to encoding.

[note 1] Some people don’t like the effect and call it “soap opera effect”. What it is in reality is the real frame images as seen in theaters, at the true running time in theaters (0.1% faster than Blu-rays & DVDs) and with 5x shutter speed (at 120 pictures-per-second) instead of 3x shutter speed (at 24 pictures-per-second) – in other words even smoother image motion than is seen in theaters.