# -*- coding: utf-8 -*-
"""
Location module containing ObjectLocation definition
"""
import inspect

from django.conf import settings as django_settings


class ObjectLocation(object):
    """
    Class for storing information about object location
    """
    def __init__(self, name, with_number):
        """
        Gets values from source code stack frames (file name, function names)
        and passed name to differentiate between different objects

        :param name: string indicating a type or name for a located object
        :param with_number: whether line number should be considered or not
        """
        self.source = self.get_source()
        if self.source:
            self.file = self.get_file()
            self.scope = self.get_scope()
            self.name = self.get_name(name)
            self.number = self.get_number() if with_number else None

    def __str__(self):
        """
        Joins all fields retrieved in __init__()

        :return: string representation, uniqueness wrt filename, execution scope and passed name
        """
        if self.source:
            format_str = '{file}::{name}::{number}' if self.number else '{file}/{scope}/{name}'
            return format_str.format(**self.__dict__)
        else:
            return ''

    def __bool__(self):
        """
        Tells whether object has any reasonable location in project source code

        :return: True if there are any source code stack frames
        """
        return bool(self.source)

    @staticmethod
    def get_source():
        """
        Gets full stack, then ignores frames executing libraries' code and frames executing code
        from a file different to last source code frame

        :return: list of frame objects that execute latest file of source code existing on traceback
        """
        try:
            latest_file_name = [s[1] for s in inspect.stack() if django_settings.BASE_DIR in s[1]][0]
            return [s for s in inspect.stack() if s[1] == latest_file_name]
        except IndexError:
            return []

    def get_file(self):
        _, filename, _, _, _, _ = self.source[0]
        return filename.replace(django_settings.BASE_DIR + '/', '')

    def get_scope(self):
        _, filename, _, _, _, _ = self.source[0]
        return '.'.join(reversed([str(s[3]) for s in self.source if s[1] == filename]))

    def get_number(self):
        _, _, lineno, _, _, _ = self.source[0]
        return str(lineno)

    @staticmethod
    def get_name(name):
        return str(name).lower()

# -*- coding: utf-8 -*-
"""
Location module containing ObjectLocation definition
"""
import inspect

from django.conf import settings as django_settings


class ObjectLocation(object):
    """
    Class for storing information about object location
    """
    def __init__(self, name, with_number):
        """
        Gets values from source code stack frames (file name, function names)
        and passed name to differentiate between different objects

        :param name: string indicating a type or name for a located object
        :param with_number: whether line number should be considered or not
        """
        self.source = self.get_source()
        if self.source:
            self.file = self.get_file()
            self.scope = self.get_scope()
            self.name = self.get_name(name)
            self.number = self.get_number() if with_number else None

    def __str__(self):
        """
        Joins all fields retrieved in __init__()

        :return: string representation, uniqueness wrt filename, execution scope and passed name
        """
        if self.source:
            format_str = '{file}::{name}::{number}' if self.number else '{file}/{scope}/{name}'
            return format_str.format(**self.__dict__)
        else:
            return ''

    def __bool__(self):
        """
        Tells whether object has any reasonable location in project source code

        :return: True if there are any source code stack frames
        """
        return bool(self.source)

    @staticmethod
    def get_source():
        """
        Gets full stack, then ignores frames executing libraries' code and frames executing code
        from a file different to last source code frame

        :return: list of frame objects that execute latest file of source code existing on traceback
        """
        try:
            latest_file_name = [s[1] for s in inspect.stack() if django_settings.BASE_DIR in s[1]][0]
            return [s for s in inspect.stack() if s[1] == latest_file_name]
        except IndexError:
            return []

    def get_file(self):
        _, filename, _, _, _, _ = self.source[0]
        return filename.replace(django_settings.BASE_DIR + '/', '')

    def get_scope(self):
        _, filename, _, _, _, _ = self.source[0]
        return '.'.join(reversed([str(s[3]) for s in self.source if s[1] == filename]))

    def get_number(self):
        _, _, lineno, _, _, _ = self.source[0]
        return str(lineno)

    @staticmethod
    def get_name(name):
        return str(name).lower()

# -*- coding: utf-8 -*- Location module containing ObjectLocation definition Class for storing information about object location Gets values from source code stack frames (file name, function names)         and passed name to differentiate between different objects          :param name: string indicating a type or name for a located object         :param with_number: whether line number should be considered or not Joins all fields retrieved in __init__()          :return: string representation, uniqueness wrt filename, execution scope and passed name Tells whether object has any reasonable location in project source code          :return: True if there are any source code stack frames Gets full stack, then ignores frames executing libraries' code and frames executing code         from a file different to last source code frame          :return: list of frame objects that execute latest file of source code existing on traceback