priority -50

###########################################################################
#                            TEXTMATE SNIPPETS                            #
###########################################################################

#! header
snippet #! "#!/usr/bin/env python" b
#!/usr/bin/env python
$0
endsnippet

snippet #!2 "#!/usr/bin/env python2" b
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
$0
endsnippet

snippet #!3 "#!/usr/bin/env python3" b
#!/usr/bin/env python3
$0
endsnippet

snippet "^# ?[uU][tT][fF]-?8" "# encoding: UTF-8" r
# -*- coding: utf-8 -*-
$0
endsnippet

snippet ifmain "ifmain" b
if __name__ == `!p snip.rv = get_quoting_style(snip)`__main__`!p snip.rv = get_quoting_style(snip)`:
	${1:${VISUAL:main()}}
endsnippet

snippet with "with" b
with ${1:expr}`!p snip.rv = " as " if t[2] else ""`${2:var}:
	${3:${VISUAL:pass}}
$0
endsnippet

snippet for "for loop" b
for ${1:item} in ${2:iterable}:
	${3:${VISUAL:pass}}
endsnippet

##########
# COMMON #
##########

# The smart def and smart class snippets use a global option called
# "g:ultisnips_python_style" which, if set to "doxygen" will use doxygen
# style comments in docstrings.

global !p

NORMAL  = 0x1
DOXYGEN = 0x2
SPHINX  = 0x3
GOOGLE  = 0x4
NUMPY   = 0x5
JEDI    = 0x6

SINGLE_QUOTES = "'"
DOUBLE_QUOTES = '"'


class Arg(object):
	def __init__(self, arg):
		self.arg = arg
		name_and_type = arg.split('=')[0].split(':')
		self.name = name_and_type[0].strip()
		self.type = name_and_type[1].strip() if len(name_and_type) == 2 else None

	def __str__(self):
		return self.name

	def __unicode__(self):
		return self.name

	def is_kwarg(self):
		return '=' in self.arg

	def is_vararg(self):
		return '*' in self.name


def get_args(arglist):
	args = []
	n = len(arglist)
	i = 0
	while i < n:
		l_bracket = 0
		start = i
		while i < n and (l_bracket > 0 or arglist[i] != ','):
			if arglist[i] == '[':
				l_bracket += 1
			elif arglist[i] == ']' and l_bracket > 0:
				l_bracket -= 1
			i += 1
		arg = arglist[start:i]
		if arg:
			args.append(Arg(arg))
		i += 1

	args = [arg for arg in args if arg.name != 'self']

	return args


def get_quoting_style(snip):
	style = snip.opt("g:ultisnips_python_quoting_style", "double")
	if style == 'single':
		return SINGLE_QUOTES
	return DOUBLE_QUOTES

def triple_quotes(snip):
	style = snip.opt("g:ultisnips_python_triple_quoting_style")
	if not style:
		return get_quoting_style(snip) * 3
	return (SINGLE_QUOTES if style == 'single' else DOUBLE_QUOTES) * 3

def triple_quotes_handle_trailing(snip, quoting_style):
	"""
	Generate triple quoted strings and handle any trailing quote char,
	which might be there from some autoclose/autopair plugin,
	i.e. when expanding ``"|"``.
	"""
	if not snip.c:
		# Do this only once, otherwise the following error would happen:
		# RuntimeError: The snippets content did not converge: …
		row, col = vim.current.window.cursor

		# before ultisnip expansion, chars ahead cursor is at row - 1, col
		# after ultisnip expansion, they are pushed to row + 1, col - 1
		# when this function is run, it's already after ultisni expansion
		line = snip.buffer[row + 1]

		# Handle already existing quote chars after the trigger.
		_ret = quoting_style * 3
		while True:
			try:
				nextc = line[col - 1]
			except IndexError:
				break
			if nextc == quoting_style and len(_ret):
				_ret = _ret[1:]
				col = col+1
			else:
				break
		snip.rv = _ret
	else:
		snip.rv = snip.c

def get_style(snip):
	style = snip.opt("g:ultisnips_python_style", "normal")

	if    style == "doxygen": return DOXYGEN
	elif  style == "sphinx": return SPHINX
	elif  style == "google": return GOOGLE
	elif  style == "numpy": return NUMPY
	elif  style == "jedi": return JEDI
	else: return NORMAL


def format_arg(arg, style):
	if style == DOXYGEN:
		return "@param %s TODO" % arg
	elif style == SPHINX:
		return ":param %s: TODO" % arg
	elif style == NORMAL:
		return ":%s: TODO" % arg
	elif style == GOOGLE:
		return "%s (%s): TODO" % (arg, arg.type or "TODO")
	elif style == JEDI:
		return ":type %s: TODO" % arg
	elif style == NUMPY:
		return "%s : TODO" % arg


def format_return(style):
	if style == DOXYGEN:
		return "@return: TODO"
	elif style in (NORMAL, SPHINX, JEDI):
		return ":returns: TODO"
	elif style == GOOGLE:
		return "Returns: TODO"


def write_docstring_args(args, snip):
	if not args:
		snip.rv += ' {0}'.format(triple_quotes(snip))
		return

	snip.rv += '\n' + snip.mkline('', indent='')

	style = get_style(snip)

	if style == GOOGLE:
		write_google_docstring_args(args, snip)
	elif style == NUMPY:
		write_numpy_docstring_args(args, snip)
	else:
		for arg in args:
			snip += format_arg(arg, style)


def write_google_docstring_args(args, snip):
	kwargs = [arg for arg in args if arg.is_kwarg()]
	args = [arg for arg in args if not arg.is_kwarg()]

	if args:
		snip += "Args:"
		snip.shift()
		for arg in args:
			snip += format_arg(arg, GOOGLE)
		snip.unshift()
		snip.rv += '\n' + snip.mkline('', indent='')

	if kwargs:
		snip += "Kwargs:"
		snip.shift()
		for kwarg in kwargs:
			snip += format_arg(kwarg, GOOGLE)
		snip.unshift()
		snip.rv += '\n' + snip.mkline('', indent='')


def write_numpy_docstring_args(args, snip):
	if args:
		snip += "Parameters"
		snip += "----------"

	kwargs = [arg for arg in args if arg.is_kwarg()]
	args = [arg for arg in args if not arg.is_kwarg()]

	if args:
		for arg in args:
			snip += format_arg(arg, NUMPY)
	if kwargs:
		for kwarg in kwargs:
			snip += format_arg(kwarg, NUMPY) + ', optional'
	snip.rv += '\n' + snip.mkline('', indent='')


def write_init_body(args, parents, snip):
	parents = [p.strip() for p in parents.split(",")]
	parents = [p for p in parents if p != 'object']

	for p in parents:
		snip += p + ".__init__(self)"

	if parents:
		snip.rv += '\n' + snip.mkline('', indent='')

	for arg in filter(lambda arg: not arg.is_vararg(), args):
		snip += "self._%s = %s" % (arg, arg)


def write_slots_args(args, snip):
	quote = get_quoting_style(snip)
	arg_format = quote + '_%s' + quote
	args = [arg_format % arg for arg in args]
	snip += '__slots__ = (%s,)' % ', '.join(args)


def write_function_docstring(t, snip):
	"""
	Writes a function docstring with the current style.

	:param t: The values of the placeholders
	:param snip: UltiSnips.TextObjects.SnippetUtil object instance
	"""
	snip.rv = ""
	snip >> 1

	args = get_args(t[2])
	if args:
		write_docstring_args(args, snip)

	style = get_style(snip)

	if style == NUMPY:
		snip += 'Returns'
		snip += '-------'
		snip += 'TODO'
	else:
		snip += format_return(style)
	snip.rv += '\n' + snip.mkline('', indent='')
	snip += triple_quotes(snip)

def get_dir_and_file_name(snip):
	return os.getcwd().split(os.sep)[-1] + '.' + snip.basename

endglobal

########################################
# Class & Special Method Name Snippets #
########################################

snippet class "class with docstrings" b
class ${1:MyClass}(${2:object}):

	`!p snip.rv = triple_quotes(snip)`${3:Docstring for $1. }`!p snip.rv = triple_quotes(snip)`

	def __init__(self$4):
		`!p snip.rv = triple_quotes(snip)`${5:TODO: to be defined.}`!p
snip.rv = ""
snip >> 2

args = get_args(t[4])

write_docstring_args(args, snip)
if args:
	snip.rv += '\n' + snip.mkline('', indent='')
	snip += '{0}'.format(triple_quotes(snip))

write_init_body(args, t[2], snip)
`
		$0
endsnippet


snippet slotclass "class with slots and docstrings" b
class ${1:MyClass}(${2:object}):

	`!p snip.rv = triple_quotes(snip)`${3:Docstring for $1. }`!p snip.rv = triple_quotes(snip)`
`!p
snip >> 1
args = get_args(t[4])
write_slots_args(args, snip)
`

	def __init__(self$4):
		`!p snip.rv = triple_quotes(snip)`${5:TODO: to be defined.}`!p
snip.rv = ""
snip >> 2

args = get_args(t[4])

write_docstring_args(args, snip)
if args:
	snip.rv += '\n' + snip.mkline('', indent='')
	snip += triple_quotes(snip)

write_init_body(args, t[2], snip)
`
		$0
endsnippet


snippet dcl "dataclass" b
@dataclass
class ${1:MyClass}:
	`!p snip.rv = triple_quotes(snip)`${2:Docstring for $1. }`!p snip.rv = triple_quotes(snip)`
	${3:var_1}: ${4:int}
	${5:var_2}: ${6:float} = ${7:0}

	def ${8:total}(self): -> $6:
		return ${0:self.$3 * self.$5}
endsnippet


snippet contain "methods for emulating a container type" b
def __len__(self):
	${1:pass}

def __getitem__(self, key):
	${2:pass}

def __setitem__(self, key, value):
	${3:pass}

def __delitem__(self, key):
	${4:pass}

def __iter__(self):
	${5:pass}

def __reversed__(self):
	${6:pass}

def __contains__(self, item):
	${7:pass}
endsnippet


snippet context "context manager methods" b
def __enter__(self):
	${1:pass}

def __exit__(self, exc_type, exc_value, traceback):
	${2:pass}
endsnippet


snippet attr "methods for customizing attribute access" b
def __getattr__(self, name):
	${1:pass}

def __setattr__(self, name, value):
	${2:pass}

def __delattr__(self, name):
	${3:pass}
endsnippet


snippet desc "methods implementing descriptors" b
def __get__(self, instance, owner):
	${1:pass}

def __set__(self, instance, value):
	${2:pass}

def __delete__(self, instance):
	${3:pass}
endsnippet


snippet cmp "methods implementing rich comparison"
def __eq__(self, other):
	${1:pass}

def __ne__(self, other):
	${2:pass}

def __lt__(self, other):
	${3:pass}

def __le__(self, other):
	${4:pass}

def __gt__(self, other):
	${5:pass}

def __ge__(self, other):
	${6:pass}

def __cmp__(self, other):
	${7:pass}
endsnippet


snippet repr "methods implementing string representation"
def __repr__(self):
	${1:pass}

def __str__(self):
	${2:pass}

def __unicode__(self):
	${3:pass}
endsnippet


# note: reflected operands and augmented arithmeitc assignements have been
# intentionally ommited to reduce verbosity.
snippet numeric "methods for emulating a numeric type" b
def __add__(self, other):
	${1:pass}

def __sub__(self, other):
	${2:pass}

def __mul__(self, other):
	${3:pass}

def __div__(self, other):
	${4:pass}

def __truediv__(self, other):
	${5:pass}

def __floordiv__(self, other):
	${6:pass}


def __mod__(self, other):
	${7:pass}

def __divmod__(self, other):
	${8:pass}

def __pow__(self, other):
	${9:pass}


def __lshift__(self, other):
	${10:pass}

def __rshift__(self, other):
	${11:pass}

def __and__(self, other):
	${12:pass}

def __xor__(self, other):
	${13:pass}

def __or__(self, other):
	${14:pass}


def __neg__(self):
	${15:pass}

def __pos__(self):
	${16:pass}

def __abs__(self):
	${17:pass}

def __invert__(self):
	${18:pass}


def __complex__(self):
	${19:pass}

def __int__(self):
	${20:pass}

def __long__(self):
	${21:pass}

def __float__(self):
	${22:pass}


def __oct__(self):
	${22:pass}

def __hex__(self):
	${23:pass}


def __index__(self):
	${24:pass}

def __coerce__(self, other):
	${25:pass}
endsnippet

snippet deff "function or class method"
def ${1:fname}(`!p snip.rv = "self, " if snip.indent else ""`$2):
	$0
endsnippet

snippet def "function with docstrings" b
def ${1:function}(`!p
if snip.indent:
	snip.rv = 'self' + (", " if len(t[2]) else "")`${2:arg1}):
	`!p snip.rv = triple_quotes(snip)`${4:TODO: Docstring for $1.}`!p
write_function_docstring(t, snip) `
	${5:${VISUAL:pass}}
endsnippet


snippet defc "class method with docstrings" b
@classmethod
def ${1:function}(`!p
if snip.indent:
	snip.rv = 'cls' + (", " if len(t[2]) else "")`${2:arg1}):
	`!p snip.rv = triple_quotes(snip)`${4:TODO: Docstring for $1.}`!p
write_function_docstring(t, snip) `
	${5:${VISUAL:pass}}
endsnippet


snippet defs "static method with docstrings" b
@staticmethod
def ${1:function}(${2:arg1}):
	`!p snip.rv = triple_quotes(snip)`${4:TODO: Docstring for $1.}`!p
write_function_docstring(t, snip) `
	${5:${VISUAL:pass}}
endsnippet


# doesn't expand when there is a word in front
snippet /(^|(?<=\W))\./ "self." r
self.
endsnippet

snippet from "from module import name" b
from ${1:module} import ${2:Stuff}
endsnippet


##############
# PROPERTIES #
##############
snippet roprop "Read Only Property" b
@property
def ${1:name}(self):
	${2:return self._$1}$0
endsnippet

snippet rwprop "Read write property" b
def ${1:name}():
	`!p snip.rv = triple_quotes(snip) if t[2] else ''
`${2:TODO: Docstring for $1.}`!p
if t[2]:
	snip >> 1

	style = get_style(snip)
	snip.rv += '\n' + snip.mkline('', indent='')
	snip += format_return(style)
	snip.rv += '\n' + snip.mkline('', indent='')
	snip += triple_quotes(snip)
else:
	snip.rv = ""`
	def fget(self):
		return self._$1$0

	def fset(self, value):
		self._$1 = value
	return locals()

$1 = property(**$1(), doc=$1.__doc__)
endsnippet


############################
# If / Else / Elif / Match #
############################
snippet if "If" b
if ${1:condition}:
	${2:${VISUAL:pass}}
endsnippet

snippet ife "If / Else" b
if ${1:condition}:
	${2:${VISUAL:pass}}
else:
	${3:pass}
endsnippet

snippet ifee "If / Elif / Else" b
if ${1:condition}:
	${2:${VISUAL:pass}}
elif ${3:condition}:
	${4:pass}
else:
	${5:pass}
endsnippet

snippet match "Structural pattern matching" b
match ${1:expression}:
	case ${2:pattern_1}:
		${3:pass}
	case ${4:pattern_2}:
		${0:pass}
endsnippet

snippet matchw "Pattern matching with wildcard" b
match ${1:expression}:
	case ${2:pattern_1}:
		${3:pass}
	case _:
		${0:pass}
endsnippet


##########################
# Try / Except / Finally #
##########################
snippet try "Try / Except" b
try:
	${1:${VISUAL:pass}}
except ${2:Exception} as ${3:e}:
	${4:raise $3}
endsnippet

snippet trye "Try / Except / Else" b
try:
	${1:${VISUAL:pass}}
except ${2:Exception} as ${3:e}:
	${4:raise $3}
else:
	${5:pass}
endsnippet

snippet tryf "Try / Except / Finally" b
try:
	${1:${VISUAL:pass}}
except ${2:Exception} as ${3:e}:
	${4:raise $3}
finally:
	${5:pass}
endsnippet

snippet tryef "Try / Except / Else / Finally" b
try:
	${1:${VISUAL:pass}}
except${2: ${3:Exception} as ${4:e}}:
	${5:raise}
else:
	${6:pass}
finally:
	${7:pass}
endsnippet


######################
# Assertions & Tests #
######################

snippet ae "Assert equal" b
self.assertEqual(${1:${VISUAL:first}}, ${2:second})
endsnippet

snippet at "Assert True" b
self.assertTrue(${1:${VISUAL:expression}})
endsnippet

snippet af "Assert False" b
self.assertFalse(${1:${VISUAL:expression}})
endsnippet

snippet aae "Assert almost equal" b
self.assertAlmostEqual(${1:${VISUAL:first}}, ${2:second})
endsnippet

snippet ar "Assert raises" b
self.assertRaises(${1:exception}, ${2:${VISUAL:func}}${3/.+/, /}${3:arguments})
endsnippet

snippet an "Assert is None" b
self.assertIsNone(${1:${VISUAL:expression}})
endsnippet

snippet ann "Assert is not None" b
self.assertIsNotNone(${1:${VISUAL:expression}})
endsnippet

snippet testcase "pyunit testcase" b
class Test${1:Class}(${2:unittest.TestCase}):

	`!p snip.rv = triple_quotes(snip)`${3:Test case docstring.}`!p snip.rv = triple_quotes(snip)`

	def setUp(self):
		${4:pass}

	def tearDown(self):
		${5:pass}

	def test_${6:name}(self):
		${7:${VISUAL:pass}}
endsnippet

snippet " "triple quoted string (double quotes)" b
"""
${1:${VISUAL:doc}}
`!p triple_quotes_handle_trailing(snip, '"')`
endsnippet

snippet ' "triple quoted string (single quotes)" b
'''
${1:${VISUAL:doc}}
`!p triple_quotes_handle_trailing(snip, "'")`
endsnippet

snippet doc "doc block (triple quotes)"
`!p snip.rv = triple_quotes(snip)`
${1:${VISUAL:doc}}
`!p snip.rv = triple_quotes(snip)`
endsnippet

snippet pmdoc "pocoo style module doc string" b
# -*- coding: utf-8 -*-
"""
	`!p snip.rv = get_dir_and_file_name(snip)`
	`!p snip.rv = '~' * len(get_dir_and_file_name(snip))`

	${1:DESCRIPTION}

	:copyright: (c) `date +%Y` by ${2:YOUR_NAME}.
	:license: ${3:LICENSE_NAME}, see LICENSE for more details.
"""
$0
endsnippet

# vim:ft=snippets:
