Startup
This commit is contained in:
302
script/__Lib/diffcalc_old/diffcmd/ipython.py
Normal file
302
script/__Lib/diffcalc_old/diffcmd/ipython.py
Normal file
@@ -0,0 +1,302 @@
|
||||
import re
|
||||
from functools import wraps
|
||||
from IPython.core.magic import register_line_magic
|
||||
from IPython import get_ipython # @UnusedImport (used by register_line_magic)
|
||||
from diffcalc.gdasupport.scannable.hkl import Hkl
|
||||
|
||||
"""
|
||||
For wrapping functions:
|
||||
|
||||
In [1]: import diffcmd.ipython
|
||||
|
||||
In [2]: diffcmd.ipython.GLOBAL_NAMESPACE_DICT = globals()
|
||||
|
||||
In [3]: from IPython.core.magic import register_line_magic
|
||||
|
||||
In [4]: from diffcmd.ipython import parse_line
|
||||
|
||||
In [5]: @register_line_magic
|
||||
...: @parse_line
|
||||
...: def check_parser(*args):
|
||||
...: return args
|
||||
...:
|
||||
|
||||
In [6]: check_parser
|
||||
Out[6]: <function __main__.check_parser>
|
||||
|
||||
In [7]: del check_parser
|
||||
|
||||
In [8]: check_parser
|
||||
Out[8]: ()
|
||||
|
||||
In [9]: check_parser 1
|
||||
Out[9]: (1,)
|
||||
|
||||
In [10]: check_parser 1 2
|
||||
Out[10]: (1, 2)
|
||||
|
||||
In [11]: check_parser 1 2 [3]
|
||||
Out[11]: (1, 2, [3])
|
||||
|
||||
In [12]: b='bbb'
|
||||
|
||||
In [13]: check_parser 1 2 [3] b
|
||||
Out[13]: (1, 2, [3], 'bbb')
|
||||
|
||||
|
||||
And to create something dynamically from a function:
|
||||
|
||||
In [28]: def f(a, b, c):
|
||||
....: ....: return a, b, c
|
||||
....:
|
||||
|
||||
In [29]: register_line_magic(parse_line(f))
|
||||
Out[29]: <function __main__.f>
|
||||
|
||||
In [30]: del f
|
||||
|
||||
In [31]: f 'a' -2 [1 3 -4]
|
||||
Out[31]: ('a', -2, [1, 3, -4])
|
||||
|
||||
And from a list of functions:
|
||||
|
||||
In [32]: def one(a):
|
||||
....: return a
|
||||
....:
|
||||
|
||||
In [33]: def two(a, b):
|
||||
....: return a, b
|
||||
....:
|
||||
|
||||
In [34]: functions = one, two
|
||||
|
||||
In [35]: del one, two
|
||||
|
||||
In [36]: for f in functions:
|
||||
....: register_line_magic(parse_line(f))
|
||||
....:
|
||||
|
||||
In [37]: one 1
|
||||
Out[37]: 1
|
||||
|
||||
In [39]: two 1 2
|
||||
Out[39]: (1, 2)
|
||||
|
||||
And to check if we are running in iPython:
|
||||
|
||||
In [47]: 'get_ipython' in globals()
|
||||
Out[47]: True
|
||||
|
||||
def in_ipython():
|
||||
try:
|
||||
get_ipython()
|
||||
return True
|
||||
except NameError:
|
||||
return False
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
GLOBAL_NAMESPACE_DICT = {}
|
||||
|
||||
MATH_OPERATORS = set(['-', '+', '/', '*'])
|
||||
|
||||
# Keep a copy of python's original help as we may remove it later
|
||||
if 'help' in __builtins__:
|
||||
ORIGINAL_PYTHON_HELP = __builtins__['help']
|
||||
|
||||
|
||||
COMMA_USAGE_HELP = \
|
||||
'''
|
||||
| When calling a function without brackets, whitespace must be used in
|
||||
| place of commas. For example:
|
||||
|
|
||||
| >>> function a b [1 2 3] 'c'
|
||||
|
|
||||
| is equivalent to:
|
||||
|
|
||||
| >>> function(a, b, [1, 2, 3], 'c')
|
||||
|
|
||||
'''
|
||||
|
||||
|
||||
MATH_OPERATOR_USAGE_HELP = \
|
||||
'''
|
||||
| When calling a function without brackets, whitespace is used in place of
|
||||
| commas. Therefore terms which require evaluation must contain no space.
|
||||
| These will fail for example:
|
||||
|
|
||||
| >>> function - 1
|
||||
| >>> function a() * 2
|
||||
|
||||
| But this
|
||||
|
||||
| >>> function -1 1-1 +1 a()+1 [-1 0+1 b()] c+1
|
||||
|
|
||||
| is okay and equivalent to:
|
||||
|
|
||||
| >>> function(-1, 0, 1, a() + 1, [-1, 1, b()], c + 1)
|
||||
|
|
||||
|
||||
'''
|
||||
|
||||
comma_finder = re.compile(r'''((?:[^,"']|"[^"]*"|'[^']*')+)''')
|
||||
space_finder = re.compile(r'''((?:[^ "']|"[^"]*"|'[^']*')+)''')
|
||||
hash_finder = re.compile(r'''((?:[^#"']|"[^"]*"|'[^']*')+)''')
|
||||
open_square_finder = re.compile(r'''((?:[^["']|"[^"]*"|'[^']*')+)''')
|
||||
close_square_finder = re.compile(r'''((?:[^]"']|"[^"]*"|'[^']*')+)''')
|
||||
|
||||
def tokenify(s):
|
||||
|
||||
# Don't accept commas outside strings.
|
||||
# Users are frustrated by not knowing when commas _are_ required.
|
||||
# Making it clear when they are not helps them understand the
|
||||
# difference.
|
||||
|
||||
if ',' in comma_finder.split(s):
|
||||
print COMMA_USAGE_HELP
|
||||
print "(string was: %s)" % s
|
||||
raise SyntaxError('unexpected comma')
|
||||
|
||||
# ignore comment
|
||||
hash_split = hash_finder.split(s)
|
||||
if '#' in hash_split:
|
||||
s = '' if hash_split[0] == '#' else hash_split[1]
|
||||
|
||||
# surround square brackets with spaces to simplify token extraction
|
||||
s = ''.join(' [ ' if e == '[' else e for e in open_square_finder.split(s))
|
||||
s = ''.join(' ] ' if e == ']' else e for e in close_square_finder.split(s))
|
||||
|
||||
|
||||
# tokens are now separated by spaces
|
||||
|
||||
tokens = space_finder.split(s)[1::2]
|
||||
tokens = [tok for tok in tokens if tok != '']
|
||||
return tokens
|
||||
|
||||
|
||||
def parse(s, d):
|
||||
s = str(s)
|
||||
tokens = tokenify(s)
|
||||
for tok in tokens:
|
||||
if tok in MATH_OPERATORS:
|
||||
print MATH_OPERATOR_USAGE_HELP
|
||||
raise SyntaxError('could not evaluate: "%s"' % tok)
|
||||
|
||||
|
||||
s = ', '.join(tokens)
|
||||
|
||||
s = s.replace('[, ', '[')
|
||||
s = s.replace(',]', ']')
|
||||
s = s.replace(', ]', ']')
|
||||
|
||||
try:
|
||||
args = eval('[' + s + ']', d)
|
||||
except SyntaxError:
|
||||
raise SyntaxError('could not evaluate: "%s"' % s)
|
||||
return args
|
||||
|
||||
def parse_line(f, global_namespace_dict=None):
|
||||
'''A decorator that parses a single string argument into a list of arguments
|
||||
and calls the wrapped function with these.
|
||||
'''
|
||||
if not global_namespace_dict:
|
||||
global_namespace_dict = GLOBAL_NAMESPACE_DICT
|
||||
@wraps(f)
|
||||
def wrapper(line):
|
||||
args = parse(line, global_namespace_dict)
|
||||
return f(*args)
|
||||
return wrapper
|
||||
|
||||
|
||||
|
||||
_DEFAULT_HELP = \
|
||||
"""
|
||||
For help with diffcalc's orientation phase try:
|
||||
|
||||
>>> help ub
|
||||
|
||||
For help with moving in reciprocal lattice space try:
|
||||
|
||||
>>> help hkl
|
||||
|
||||
For more detailed help try for example:
|
||||
|
||||
>>> help newub
|
||||
|
||||
For help with driving axes or scanning:
|
||||
|
||||
>>> help pos
|
||||
>>> help scan
|
||||
|
||||
For help with regular python try for example:
|
||||
|
||||
>>> help list
|
||||
|
||||
For more detailed help with diffcalc go to:
|
||||
|
||||
https://diffcalc.readthedocs.io
|
||||
|
||||
"""
|
||||
|
||||
def magic_commands(global_namespace_dict):
|
||||
"""Magic commands left in global_namespace_dict by previous import from
|
||||
diffcalc.
|
||||
|
||||
Also creates a help command. NOTE that calling this will
|
||||
remove the original commands from the global namespace as otherwise these
|
||||
would shadow the ipython magiced versions.
|
||||
|
||||
Depends on hkl_commands_for_help & ub_commands_for_help list having been
|
||||
left in the global namespace and assumes there is pos and scan command.
|
||||
"""
|
||||
gnd = global_namespace_dict
|
||||
global GLOBAL_NAMESPACE_DICT
|
||||
GLOBAL_NAMESPACE_DICT = gnd
|
||||
|
||||
### Magic commands in namespace ###
|
||||
commands = list(gnd['hkl_commands_for_help'])
|
||||
commands += gnd['ub_commands_for_help']
|
||||
commands.append(gnd['pos'])
|
||||
commands.append(gnd['scan'])
|
||||
command_map = {}
|
||||
for f in commands:
|
||||
# Skip section headers like 'Motion'
|
||||
if not hasattr(f, '__call__'):
|
||||
continue
|
||||
# magic the function and remove from namespace (otherwise it would
|
||||
# shadow the magiced command)
|
||||
register_line_magic(parse_line(f, gnd))
|
||||
del gnd[f.__name__]
|
||||
command_map[f.__name__] = f
|
||||
|
||||
### Create help function ###
|
||||
#Expects python's original help to be named pythons_help and to be
|
||||
#available in the top-level global namespace (where non-diffcalc
|
||||
#objects may have help called from).
|
||||
def help(s): # @ReservedAssignment
|
||||
"""Diffcalc help for iPython
|
||||
"""
|
||||
if s == '':
|
||||
print _DEFAULT_HELP
|
||||
elif s == 'hkl':
|
||||
# Use help injected into hkl object
|
||||
print Hkl.dynamic_docstring
|
||||
elif s == 'ub':
|
||||
# Use help injected into ub command
|
||||
print command_map['ub'].__doc__
|
||||
elif s in command_map:
|
||||
print "%s (diffcalc command):" %s
|
||||
print command_map[s].__doc__
|
||||
else:
|
||||
exec('pythons_help(%s)' %s, gnd)
|
||||
|
||||
|
||||
### Setup help command ###
|
||||
gnd['pythons_help'] = ORIGINAL_PYTHON_HELP
|
||||
register_line_magic(help)
|
||||
# Remove builtin help
|
||||
# (otherwise it would shadow magiced command
|
||||
if 'help' in __builtins__:
|
||||
del __builtins__['help']
|
||||
Reference in New Issue
Block a user