pyex — Allows for methods that can be used with class str, etc.
pyex
is a preprocessor. You write a .pyex
file in just slightly
extended Python, then pyex.py
processes that into Python in the actual
form Python wants, all without monkeypatching or otherwise compromising
execution reliability.
This is a Python v2 project.
This project grew indirectly from my annoyance with Python's inability to extend the built-in classes, particularly the string class. I have often wanted to just do something to a string as a method, mainly — and I know this is a simple thing, but — mainly because I consistently tend to think this way...
x = 'foo'.upper()
...rather than this way:
x = upper('foo')
I've had some discussions with some really well-informed Python types, and they all assure me that you simply can't extend the built-in classes without incurring a risk of actually breaking the Python interpreter. Well. That was bad news.
But eventually it dawned on me that even if it was impossible in Python, who says it has to be Python? There's a ton of functionality in the C language that comes from a preprocessor; why not a preprocessor for Python?
And so... pyex
.
pyex
means Python, Extended
and that's exactly what it is. You write
using pyex
syntax — which is exactly the same as Python syntax —
except for two things.
The first is that you can write a method and attach it to any class object it is written to understand.
The second is that you declare this with a tiny bit of new syntax.
Here's a for-instance. Say you have a method that takes a string object and validates that it is a dotted quad and you want to be able to use it as a method on strings. Here's something you might write:
extend:testDottedQuad
def testDottedQuad(strObject):
if not isinstance(strObject, basestring): return False
listStrings = strObject.split('.')
if len(listStrings) != 4: return False
for strNum in listStrings:
try: val = int(strNum)
except: return False
if val < 0: return False
if val > 255: return False
return True
Now, at some point, you have a string in your program you'd like to
validate. Here are some of the things you can do via pyex
with the
above in place:
if '192.168.1.100'.testDottedQuad():
doSomething()
dq = '216.126.621.5'
if not dq.testDottedQuad():
throwWarning();
dqt = ''.join(['127','.','0','.','0','.','1']).testDottedQuad()
if dqt:
print 'well, that was fun'
Syntactically speaking, you can use these as extended methods on strings, functions that return strings, and variables that contain strings as if the methods were actual members of the string class. They aren't, of course, so it's advisable to do some checking inside your methods to make sure that they're receiving the kind of object they expect.
The process is simple. First, you write a .pyex
file that contains your
Python, plus this extended syntax. Then you run it through pyex.py
.
pyex.py
, in turn, will produce an output file in pure Python that has
changed the syntax to be normal function call based; this is the final
end product, what you actually run.
pyex
strips comments, although if you ask it to, it will put your
original lines in as comments above the generated lines so you can
examine the metamorphosis from pyex
to Python.
Basically that's it. Typing pyex.py
by itself will generate help text.
I often edit Python (and now, pyex
) in Midnight Commander's
cooledit
editor. I've created a (very) slightly modifed syntax
highlighting file for .pyex
files (pyex.syntax
) for this editor by
taking the Python syntax file and adding the extend
keyword. If you
are going to use pyex
, I think you'll find it useful to implement a
syntax file for your editor as well, and most likely, you can do what I
did — grab the Python syntax, modify it by adding one keyword, assign
the result to pyex
, and done.
Console input | Result |
---|---|
pyex.py myStuff | myStuff.pyex --> myStuff.py |
pyex.py myStuff.pyex | myStuff.pyex --> myStuff.py |
pyex.py myStuff -o yourStuff | mystuff.pyex --> yourStuff.py |
pyex.py myStuff.pyex -o herStuff | myStuff.pyex --> herStuff.py |
pyex.py myStuff.pyex -o hisStuff.py | myStuff.pyex --> hisStuff.py |
pyex.py myStuff -c | myStuff.pyex --> myStuff.py + your code inserted as comments in myStuff.py |
pyex.py myStuff -c -b | myStuff.pyex --> myStuff.py + your code inserted as comments with leading blank lines in myStuff.py |
pyex.py myStuff -v -b | myStuff.pyex --> myStuff.py + verbose dump of progress incorporating blank lines between conversions |
pyex.py | You get a bunch of help about the options |
Executing test_pyex.py
will generate pyextest.py
from pyextest.pyex
and compare the result with expected.py
. If the results match, then
pyex.py is working at least as well for you as it does for me. If they
do not match, a list of the differences will be provided and a warning
generated.
- pyex.py -- the preprocessor
- pyextest.pyex -- a test file you can run through pyex.py
- pyex.syntax -- a syntax file for Midnite Commander
- README.md -- this file
- test_pyex.py -- unit test
- expected.py -- base result for successful unit test
Application to provide extended Python syntax for methods on built-in classes
Most particularly, string.
Author: fyngyrz (Ben)
Contact: fyngyrz@gmail.com (bugs, feature requests, kudos, bitter rejections)
Project: pyex.py
Homepage: https://github.com/fyngyrz/pyex
License: None. It's free. *Really* free. Defy invalid social and legal norms.
Disclaimers: 1) Probably completely broken. Do Not Use. You were explicitly warned. Phbbbbt.
2) This code is blackbox, meaning I wrote it without reference to other people's code
3) I can't check other people's forks effectively, so if you use any other version
of pyex.py that incorporates accepted commits from others, you are risking
the use of OPC, which may or may not be protected by copyright, patent, and the
like, because our intellectual property system is pathological. The risks and
responsibilities and any subsequent consequences are entirely yours. Have you
written your congresscritter about patent and copyright reform yet?
Incep Date: October 29th, 2016 (for Project)
Last Update: October 30th, 2016 (for Project)
Dev Env: OS X 10.6.8, Python 2.6.1
Status: BETA