|
"""Not finished yet""" |
|
|
|
import os |
|
import subprocess |
|
|
|
# This works on my machines, at least: |
|
PIPE = subprocess.PIPE |
|
startupinfo = None |
|
|
|
if os.name == 'nt': |
|
units_path = 'C:/Program Files/GnuWin32/bin/units' |
|
|
|
# For launching a subprocess windowless in Windows |
|
# http://code.activestate.com/recipes/409002/ |
|
startupinfo = subprocess.STARTUPINFO() |
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW |
|
if os.name == 'posix': |
|
units_path = '/usr/bin/units' |
|
|
|
command = [units_path, '-v'] |
|
proc = subprocess.Popen(command, stdin=PIPE, stdout=PIPE, universal_newlines=True, startupinfo=startupinfo) |
|
|
|
# Eat up everything to the first prompt |
|
preamble = '' |
|
while 'You have:' not in preamble: |
|
preamble = preamble + proc.stdout.read(1) |
|
|
|
|
|
def units(expression, desired_units=''): |
|
"""Call GNU Units and return its response |
|
|
|
The expression is what you want evaluated, like '50 million grams', and |
|
desired_units is what you want converted to, like 'lb'. |
|
|
|
""" |
|
|
|
def sanitize(r): |
|
"""Remove all the extraneous stuff""" |
|
|
|
r = r[:-10] # Remove '\nYou have:' prompt at end |
|
if 'nt' in os.name: # HACK HACK HACK |
|
r = r.split('\n', 1)[1] # Remove echo of unit at beginning |
|
r = r.strip(' ^\n\t') # Remove ' ^\n' that appears in errors, or Tab that appears with results |
|
r = r.split('\n')[0] # Remove explanatory text after the newline, return just the error itself |
|
|
|
# Some tweaks |
|
if r == '': |
|
r = 'Enter an expression' |
|
elif r == 'conformability error' or r == 'reciprocal conversion': |
|
r = r.capitalize() |
|
|
|
return r |
|
|
|
# Send expression to "You have:" prompt |
|
proc.stdin.write(expression + '\n') |
|
proc.stdin.flush() |
|
|
|
# Get response 1 character at a time to avoid blocking |
|
response = '' |
|
while 'You have:' not in response and 'You want:' not in response: |
|
response = response + proc.stdout.read(1) |
|
|
|
# Errors or definitions pop back to "You have:" prompt |
|
if 'You have:' in response: |
|
return sanitize(response) |
|
|
|
# Send desired units to "You want:" prompt |
|
proc.stdin.write(desired_units + '\n') |
|
proc.stdin.flush() |
|
|
|
response = '' |
|
while 'You have:' not in response and 'You want:' not in response: |
|
response = response + proc.stdout.read(1) |
|
|
|
# Errors can pop back to "You want:" prompt |
|
if 'You want:' in response: |
|
# Enter nothing and then eat everything back to "You have:" prompt |
|
proc.stdin.write('\n') |
|
proc.stdin.flush() |
|
while 'You have:' not in response: |
|
response = response + proc.stdout.read(1) |
|
|
|
return sanitize(response) |
|
|
|
|
|
def units_command(expression, desired_units=''): |
|
"""Call the units command and get the response (about 50 times slower)""" |
|
|
|
comm = command[:] |
|
comm.append(expression) |
|
if desired_units: |
|
comm.append(desired_units) |
|
|
|
proc = subprocess.Popen(comm, stdout=PIPE, universal_newlines=True, startupinfo=startupinfo)#.wait() |
|
|
|
out = proc.communicate()[0] |
|
result = out.split('\n')[0].strip() |
|
return result |
|
|
|
def test(): |
|
# Do some tests to see if it handles all known outputs correctly |
|
print('Preamble: ' + preamble[:-10]) |
|
|
|
print('Conversion\n\t' + units('m', 'ft')) |
|
print('Definition\n\t' + units('km')) |
|
print('Nothing\n\t' + units('')) |
|
print('Conformability (m to W)\n\t' + units('m', 'W')) |
|
print('Unknown unit (q) at You have\n\t' + units('q')) |
|
print('Unknown unit (q) at You want\n\t' + units('m', 'q')) |
|
print('Wrong dimension to function pH(W)\n\t' + units('pH(W)')) |
|
print('Parse error\n\t' + units('(')) |
|
print('Reciprocal conversion\n\t' + units('s', 'Hz')) |
|
print('Conformability sum\n\t' + units('1 + m')) |
|
print('Not a root\n\t' + units('sqrt(m)')) |
|
print('Not dimensionless\n\t' + units('sin(m)')) |
|
|
|
if __name__ == '__main__': |
|
test() |
(I haven't used this in a long time. I stopped using Launchy when I started using Windows 7, and now Wolfram Alpha also exists for unit calculations (though it's even slower than Google Calc).)