Skip to content

Commit

Permalink
Bump Python versions, remove conditional imports
Browse files Browse the repository at this point in the history
Mako 1.1 now supports Python versions:

* 2.7
* 3.4 and higher

This includes that setup.py no longer includes any conditionals, allowing
for a pure Python wheel build, however this is not necessarily part of the
Pypi release process as of yet.  The test suite also raises for Python
deprecation warnings.

Fixes: #249

Replaced usage of ``inspect.getfullargspec()`` with the vendored version
used by SQLAlchemy, Alembic to avoid future deprecation warnings.  Also
cleans up an additional version of the same function that's apparently
been floating around for some time.

Fixes: #295
Change-Id: I98274c16b6022289d1890f4daf532bab323ab112
  • Loading branch information
zzzeek committed Jul 27, 2019
1 parent a79fbaa commit 338cad6
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 127 deletions.
14 changes: 14 additions & 0 deletions doc/build/unreleased/249.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.. change::
:tags: change, py3k, installer
:tickets: 249

Mako 1.1 now supports Python versions:

* 2.7
* 3.4 and higher

This includes that setup.py no longer includes any conditionals, allowing
for a pure Python wheel build, however this is not necessarily part of the
Pypi release process as of yet. The test suite also raises for Python
deprecation warnings.

9 changes: 9 additions & 0 deletions doc/build/unreleased/295.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. change::
:tags: bug, py3k
:tickets: 295

Replaced usage of ``inspect.getfullargspec()`` with the vendored version
used by SQLAlchemy, Alembic to avoid future deprecation warnings. Also
cleans up an additional version of the same function that's apparently
been floating around for some time.

3 changes: 2 additions & 1 deletion mako/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""provides functionality for rendering a parsetree constructing into module
source code."""

import json
import re
import time

Expand Down Expand Up @@ -176,7 +177,7 @@ def write_metadata_struct(self):
self.printer.writelines(
'"""',
"__M_BEGIN_METADATA",
compat.json.dumps(struct),
json.dumps(struct),
"__M_END_METADATA\n" '"""',
)

Expand Down
120 changes: 30 additions & 90 deletions mako/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,49 @@
# This module is part of Mako and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php

import json # noqa
import collections
import inspect
import sys

py3k = sys.version_info >= (3, 0)
py33 = sys.version_info >= (3, 3)
py2k = sys.version_info < (3,)
py27 = sys.version_info >= (2, 7)
jython = sys.platform.startswith("java")
win32 = sys.platform.startswith("win")
pypy = hasattr(sys, "pypy_version_info")

if py3k:
# create a "getargspec" from getfullargspec(), which is not deprecated
# in Py3K; getargspec() has started to emit warnings as of Py3.5.
# As of Py3.4, now they are trying to move from getfullargspec()
# to "signature()", but getfullargspec() is not deprecated, so stick
# with that for now.
ArgSpec = collections.namedtuple(
"ArgSpec", ["args", "varargs", "keywords", "defaults"]
)

import collections

ArgSpec = collections.namedtuple(
"ArgSpec", ["args", "varargs", "keywords", "defaults"]
)
from inspect import getfullargspec as inspect_getfullargspec
def inspect_getargspec(func):
"""getargspec based on fully vendored getfullargspec from Python 3.3."""

def inspect_getargspec(func):
return ArgSpec(*inspect_getfullargspec(func)[0:4])
if inspect.ismethod(func):
func = func.__func__
if not inspect.isfunction(func):
raise TypeError("{!r} is not a Python function".format(func))

co = func.__code__
if not inspect.iscode(co):
raise TypeError("{!r} is not a code object".format(co))

else:
from inspect import getargspec as inspect_getargspec # noqa
nargs = co.co_argcount
names = co.co_varnames
nkwargs = co.co_kwonlyargcount if py3k else 0
args = list(names[:nargs])

nargs += nkwargs
varargs = None
if co.co_flags & inspect.CO_VARARGS:
varargs = co.co_varnames[nargs]
nargs = nargs + 1
varkw = None
if co.co_flags & inspect.CO_VARKEYWORDS:
varkw = co.co_varnames[nargs]

return ArgSpec(args, varargs, varkw, func.__defaults__)


if py3k:
Expand Down Expand Up @@ -86,7 +98,7 @@ def octal(lit):
return eval("0" + lit)


if py33:
if py3k:
from importlib import machinery

def load_module(module_id, path):
Expand Down Expand Up @@ -125,85 +137,13 @@ def exception_as():
return sys.exc_info()[1]


try:
import threading

if py3k:
import _thread as thread
else:
import thread
except ImportError:
import dummy_threading as threading # noqa

if py3k:
import _dummy_thread as thread
else:
import dummy_thread as thread # noqa

try:
from functools import partial
except:

def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords)

return newfunc


all = all # noqa


def exception_name(exc):
return exc.__class__.__name__


try:
from inspect import CO_VARKEYWORDS, CO_VARARGS

def inspect_func_args(fn):
if py3k:
co = fn.__code__
else:
co = fn.func_code

nargs = co.co_argcount
names = co.co_varnames
args = list(names[:nargs])

varargs = None
if co.co_flags & CO_VARARGS:
varargs = co.co_varnames[nargs]
nargs = nargs + 1
varkw = None
if co.co_flags & CO_VARKEYWORDS:
varkw = co.co_varnames[nargs]

if py3k:
return args, varargs, varkw, fn.__defaults__
else:
return args, varargs, varkw, fn.func_defaults


except ImportError:
import inspect

def inspect_func_args(fn):
return inspect.getargspec(fn)


if py3k:
# TODO: this has been restored in py3k
def callable(fn): # noqa
return hasattr(fn, "__call__")


else:
callable = callable # noqa


################################################
# cross-compatible metaclass implementation
# Copyright (c) 2010-2012 Benjamin Peterson
Expand Down
2 changes: 1 addition & 1 deletion mako/ext/pygmentplugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class MakoLexer(RegexLexer):
),
(r"<%(?=([\w\.\:]+))", Comment.Preproc, "ondeftags"),
(
r"(<%(?:!?))(.*?)(%>)(?s)",
r"(?s)(<%(?:!?))(.*?)(%>)",
bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc),
),
(
Expand Down
19 changes: 10 additions & 9 deletions mako/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""provides runtime services for templates, including Context,
Namespace, and various helper functions."""

import functools
import sys

from mako import compat
Expand Down Expand Up @@ -37,7 +38,7 @@ def __init__(self, buffer, **data):

# "capture" function which proxies to the
# generic "capture" function
self._data["capture"] = compat.partial(capture, self)
self._data["capture"] = functools.partial(capture, self)

# "caller" stack used by def calls with content
self.caller_stack = self._data["caller"] = CallerStack()
Expand Down Expand Up @@ -625,7 +626,7 @@ def _get_star(self):

def get(key):
callable_ = self.template._get_def_callable(key)
return compat.partial(callable_, self.context)
return functools.partial(callable_, self.context)

for k in self.template.module._exports:
yield (k, get(k))
Expand All @@ -635,7 +636,7 @@ def __getattr__(self, key):
val = self.callables[key]
elif self.template.has_def(key):
callable_ = self.template._get_def_callable(key)
val = compat.partial(callable_, self.context)
val = functools.partial(callable_, self.context)
elif self.inherits:
val = getattr(self.inherits, key)

Expand Down Expand Up @@ -686,15 +687,15 @@ def _get_star(self):
for key in dir(self.module):
if key[0] != "_":
callable_ = getattr(self.module, key)
if compat.callable(callable_):
yield key, compat.partial(callable_, self.context)
if callable(callable_):
yield key, functools.partial(callable_, self.context)

def __getattr__(self, key):
if key in self.callables:
val = self.callables[key]
elif hasattr(self.module, key):
callable_ = getattr(self.module, key)
val = compat.partial(callable_, self.context)
val = functools.partial(callable_, self.context)
elif self.inherits:
val = getattr(self.inherits, key)
else:
Expand Down Expand Up @@ -731,7 +732,7 @@ def capture(context, callable_, *args, **kwargs):
"""

if not compat.callable(callable_):
if not callable(callable_):
raise exceptions.RuntimeException(
"capture() function expects a callable as "
"its argument (i.e. capture(func, *args, **kwargs))"
Expand Down Expand Up @@ -885,7 +886,7 @@ def _render(template, callable_, args, data, as_unicode=False):


def _kwargs_for_callable(callable_, data):
argspec = compat.inspect_func_args(callable_)
argspec = compat.inspect_getargspec(callable_)
# for normal pages, **pageargs is usually present
if argspec[2]:
return data
Expand All @@ -900,7 +901,7 @@ def _kwargs_for_callable(callable_, data):


def _kwargs_for_include(callable_, data, **kwargs):
argspec = compat.inspect_func_args(callable_)
argspec = compat.inspect_getargspec(callable_)
namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
for arg in namedargs:
if arg != "context" and arg in data and arg not in kwargs:
Expand Down
3 changes: 2 additions & 1 deletion mako/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""Provides the Template class, a facade for parsing, generating and executing
template strings, as well as template runtime operations."""

import json
import os
import re
import shutil
Expand Down Expand Up @@ -659,7 +660,7 @@ def get_module_source_metadata(cls, module_source, full_line_map=False):
source_map = re.search(
r"__M_BEGIN_METADATA(.+?)__M_END_METADATA", module_source, re.S
).group(1)
source_map = compat.json.loads(source_map)
source_map = json.loads(source_map)
source_map["line_map"] = dict(
(int(k), int(v)) for k, v in source_map["line_map"].items()
)
Expand Down
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ tag_build = dev


[tool:pytest]
addopts= --tb native -v -r fxX
addopts= --tb native -v -r fxX -W error
python_files=test/*test_*.py


Expand All @@ -13,6 +13,7 @@ sign = 1
identity = C4DAFEE1

[flake8]
show-source = true
enable-extensions = G
# E203 is due to https://github.com/PyCQA/pycodestyle/issues/373
ignore =
Expand Down
25 changes: 5 additions & 20 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,9 @@
)
v.close()

readme = open(os.path.join(os.path.dirname(__file__), "README.rst")).read()
readme = os.path.join(os.path.dirname(__file__), "README.rst")

if sys.version_info < (2, 6):
raise Exception("Mako requires Python 2.6 or higher.")

markupsafe_installs = (
sys.version_info >= (2, 6) and sys.version_info < (3, 0)
) or sys.version_info >= (3, 3)

install_requires = []

if markupsafe_installs:
install_requires.append("MarkupSafe>=0.9.2")

try:
import argparse # noqa
except ImportError:
install_requires.append("argparse")
install_requires = ["MarkupSafe>=0.9.2"]


class PyTest(TestCommand):
Expand Down Expand Up @@ -59,7 +44,8 @@ def run_tests(self):
version=VERSION,
description="A super-fast templating language that borrows the \
best ideas from the existing templating languages.",
long_description=readme,
long_description=open(readme).read(),
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
classifiers=[
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: MIT License",
Expand All @@ -77,14 +63,13 @@ def run_tests(self):
url="https://www.makotemplates.org/",
project_urls={
"Documentation": "https://docs.makotemplates.org",
"Issue Tracker": "https://github.com/sqlalchemy/mako"
"Issue Tracker": "https://github.com/sqlalchemy/mako",
},
license="MIT",
packages=find_packages(".", exclude=["examples*", "test*"]),
tests_require=["pytest", "mock"],
cmdclass={"test": PyTest},
zip_safe=False,
python_requires=">=2.6",
install_requires=install_requires,
extras_require={},
entry_points="""
Expand Down
3 changes: 1 addition & 2 deletions test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from mako import compat
from mako.cache import CacheImpl
from mako.cache import register_plugin
from mako.compat import py33
from mako.compat import py3k
from mako.template import Template
from mako.util import update_wrapper
Expand Down Expand Up @@ -106,7 +105,7 @@ def teardown():
shutil.rmtree(module_base, True)


if py33:
if py3k:
from unittest import mock # noqa
else:
import mock # noqa
Expand Down
Loading

0 comments on commit 338cad6

Please sign in to comment.