#     Copyright 2016, Kay Hayen, mailto:kay.hayen@gmail.com
#
#     Python tests originally created or extracted from other peoples work. The
#     parts were too small to be protected.
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.
#

from __future__ import print_function

import inspect, types, sys, pprint

def displayDict(d, remove_keys = ()):
    if "__loader__" in d:
        d = dict(d)
        d["__loader__"] = "<__loader__ removed>"

    if "__file__" in d:
        d = dict(d)
        d["__file__"] = "<__file__ removed>"

    for remove_key in remove_keys:
        if remove_key in d:
            d = dict(d)
            del d[remove_key]

    return pprint.pformat(d)


def compiledFunction(a, b):
    pass

assert inspect.isfunction(compiledFunction) is True
assert isinstance(compiledFunction, types.FunctionType)
assert isinstance(compiledFunction, (int, types.FunctionType))

print("Compiled spec:", inspect.getargspec(compiledFunction))
print("Compiled args:", inspect.formatargspec(*inspect.getargspec(compiledFunction)))

# Even this works.
assert type(compiledFunction) == types.FunctionType

class CompiledClass:
    def __init__(self):
        pass

    def compiledMethod(self):
        pass

assert inspect.isfunction(CompiledClass) is False
assert isinstance(CompiledClass, types.FunctionType) is False

assert inspect.ismethod(compiledFunction) is False
assert inspect.ismethod(CompiledClass) is False

assert inspect.ismethod(CompiledClass.compiledMethod) == ( sys.version_info < (3,) )
assert inspect.ismethod(CompiledClass().compiledMethod) is True

assert bool(type(CompiledClass.compiledMethod) == types.MethodType) == ( sys.version_info < (3,) )


print("Compiled method:", inspect.getargspec(CompiledClass().compiledMethod))
print("Compiled class:", inspect.formatargspec(*inspect.getargspec(CompiledClass().compiledMethod)))


def compiledGenerator():
    yield 1

assert inspect.isfunction(compiledGenerator) is True
assert inspect.isgeneratorfunction(compiledGenerator) is True

assert isinstance(compiledGenerator(), types.GeneratorType) is True
assert type(compiledGenerator()) == types.GeneratorType
assert isinstance(compiledGenerator, types.GeneratorType) is False

assert inspect.ismethod(compiledGenerator()) is False
assert inspect.isfunction(compiledGenerator()) is False

assert inspect.isgenerator(compiledFunction) is False
assert inspect.isgenerator(compiledGenerator) is False
assert inspect.isgenerator(compiledGenerator()) is True

def someFunction(a):
    assert inspect.isframe(sys._getframe())
    # print("Running frame getframeinfo()", inspect.getframeinfo(sys._getframe()))

    # TODO: The locals of the frame are not updated.
    # print("Running frame arg values", inspect.getargvalues(sys._getframe()))

someFunction(2)

class C:
    print("Class locals", displayDict(sys._getframe().f_locals, remove_keys = ("__qualname__","__locals__")))
    print("Class flags", sys._getframe().f_code.co_flags)

def f():
    print("Func locals", sys._getframe().f_locals)
    print("Func flags", sys._getframe().f_code.co_flags)

f()

def g():
    yield("Generator object locals", sys._getframe().f_locals)
    yield("Generator object flags", sys._getframe().f_code.co_flags)

for line in g():
    print(*line)

print("Generator function flags", g.__code__.co_flags)

print("Module frame locals", displayDict(sys._getframe().f_locals))
print("Module flags", sys._getframe().f_code.co_flags)
print("Module code name", sys._getframe().f_code.co_name)

print("Module frame dir", dir(sys._getframe()))
