thepyedpiper / pyp

The Pyed Piper: Python Power At the Prompt
13 stars 0 forks source link

Clarify that `+` operator on arrays isn't concatenation #1

Open krackers opened 1 year ago

krackers commented 1 year ago

Very nice tool! But I wasted a lot of time trying to figure out why + didn't do what I expected

echo "this is a test" | pyp "p.split()[:-1] + ['a'] | ' '.join(p)"

I'd expect this to just be normal python array concatenation, so I was surprised when I got

error: sequence item 0: expected str instance, list found :  ' '.join(p)

Seem this is because of the following quirk

With this in mind, pyp, unlike normal python, allows you to print out any type of objects next to each other without converting them to strings. That is, you can use “+” and “,” to concatenate objects or join them with spaces

so that internally it's not concatenating the array, but creating a new array with 2 sub-arrays.

Since you can use either , or + to do so, for self-use I modified the code to

                if not open_parenth and not open_bracket and letter in [',']: #these are actual formatting characters
                    cmd_array.append(cmd)
                    cmd = ''
                    string_format = string_format + letter.replace('+', '%s').replace(',', ' %s')
                    continue

which allows concatenation to function as expected.

thepyedpiper commented 1 year ago

Cool, I'll look into that. That's a cool use of pyp...in general the list functions are a little neglected as the built in functions are typically used for split/join operations and lists are mostly used for analysis mode. Thanks for posting!

krackers commented 1 year ago

in general the list functions are a little neglected

Another thing to consider might be passing tuples, which should basically be treated identically to arrays

 echo 'this is a test' | pyp '(w[0], w[1]) | w'

this can be fixed by allowing tuple in the types that have access to array_joiner variables:

elif type(self.p) in [list, PypList, tuple] and not power_pipe:                 # p is list of lists, constructs various joins

and then updating update_history so it doesn't try to format the tuple:

            contains_list = False
            for out in total_output: # forms an array called_output array of strings or array_traced strings
                history_array.append(out) # for feeding back to pipe
                if type(out)  in [list, PypList, tuple]:
                    contains_list = True

If this is done then theoretically you can remove the special-case formatting for comma , altogether:

if not open_parenth and not open_bracket and letter in [',']

since then we can just use native python tuples. But it is a breaking change, since you'd have to add back a w at the end to get the previous behavior. I.e. if previously

echo 'this is a test' | pyp 'w[0], w[1]'`

outputted, this is

then if you apply this change to allow passing tuples and remove the special-case handling for comma, then

echo 'this is a test' | pyp 'w[0], w[1]'`

will print (this, is) so you'd need to add | w at the end. If it is combined with #4 however so that when piping into some other program all tuples/arrays are automatically joined with whitespace, then maybe it's less of an issue.