<commit_before>from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import *
from belay_test_utils import *
from time import *
import random
import os

class BelayEnabledPage(object):
    """ Common utilities for belay enabled pages. """

    def __init__(self, driver):
        self.driver = driver
        self.window = driver.current_window_handle
        self.wait_for_ready()
        self.inject_js_error_detect()

    def inject_js_error_detect(self):
        self.driver.execute_script("""
            window.belaytest.jsErrors = [];
            window.addEventListener('error', function(evt) {
                window.belaytest.jsErrors.push({
                    msg: evt.message,
                    file: evt.filename,
                    lineNum: evt.lineno,
                });
            });
        """)

    def get_js_errors(self):
        exec_js = self.driver.execute_script
        num_errors = exec_js("return window.belaytest.jsErrors.length")
        print "Errors: %d" % num_errors
        errors = []
        for i in range(0,num_errors):
            errors.append(exec_js("return window.belaytest.jsErrors[%d]" % i))

        return errors

    def drag_from(self, source_jq_matcher):
        driver = self.driver
        driver.execute_script("""
            var fakeDragEvt = document.createEvent('UIEvents');
            fakeDragEvt.initEvent('dragstart', true, true);
            fakeDragEvt.dataTransfer = {
                setDragImage: function(x, y, z) {},
                setData: function(mime, data) {
                    belaytest.dropped_data = data;
                }
            };
            $('%s')[0].dispatchEvent(fakeDragEvt);
        """ % source_jq_matcher)
        data = driver.execute_script("return belaytest.dropped_data")
        driver.execute_script("delete belaytest.dropped_data")
        return data

    def drag_to(self, cap_data, target_jq_matcher):
        temp_source_id = "belaytest_ddsource_" + str(random.randint(0, 2 ** 64))
        self.driver.execute_script("""
            var fakeDropEvt = document.createEvent('UIEvents');
            fakeDropEvt.initEvent('drop', true, true);
            fakeDropEvt.dataTransfer = {
                getData: function(mime) {
                    return '%s';
                }
            };
            $('%s')[0].dispatchEvent(fakeDropEvt);
        """ % (cap_data, target_jq_matcher))

    def page_ready(self, driver=None):
        driver = self.driver if driver == None else driver
        return driver.execute_script("return window.belaytest && window.belaytest.ready")

    def wait_for(self, p, timeout=5):
        wait_for(self.driver, p, timeout)

    def wait_for_ready(self):
        self.wait_for(self.page_ready)

    def focus(self):
        self.driver.switch_to_window(self.window)
        self.driver.execute_script("window.focus()")

    def close(self):
        self.driver.switch_to_window(self.window)
        self.driver.close()

    def is_open(self):
        found = false
        for window in self.driver.window_handles:
            found = found and (window == self.window)
        return found

    def get_suggestions(self):
        self.driver.switch_to_frame("belay-frame")
        suggest_button_xpath = "//button[@class='suggestButton']"
        buttons = self.driver.find_elements_by_xpath(suggest_button_xpath)
        suggestions = [button.text for button in buttons]
        self.driver.switch_to_default_content()
        return suggestions

    def open_suggestion(self, suggestion):
        self.driver.switch_to_frame("belay-frame")
        suggest_button_xpath = "//button[@class='suggestButton']"
        buttons = self.driver.find_elements_by_xpath(suggest_button_xpath)

        for b in buttons:
            if b.text == suggestion:
                # this is horrible, but I can't find any way to figure out when an
                # item is both displayed and clickable when a CSS animation is
                # currently being applied. So, we must wait for the butter bar
                # CSS animation to complete before we can go ahead and click
                sleep(1)
                b.click()
                return

class BelayAdminPage(BelayEnabledPage):
    """ Representation of the contents of the belay-belay admin page. """

    def __init__(self, driver):
        super(BelayAdminPage,self).__init__(driver)

    def get_open_link(self):
        xpath = "//div[@id='open-button']//a"
        return self.driver.find_element_by_xpath(xpath)

    def get_create_open_link(self):
        xpath = "//div[@id='create-button']//a"
        return self.driver.find_element_by_xpath(xpath)

    def click_advanced_header(self):
        xpath = "//div[@id='advanced']/h2"
        self.driver.find_element_by_xpath(xpath).click()

    def get_advanced_content(self):
        xpath = "//div[@id='advanced']/div[@class='content']"
        return self.driver.find_element_by_xpath(xpath)

    def open_advanced_content(self):
        if not self.get_advanced_content().is_displayed():
            self.click_advanced_header()
            self.wait_for(lambda x: self.get_advanced_content().is_displayed())

    def close_advanced_content(self):
        if self.get_advanced_content().is_displayed():
            self.click_advanced_header()
            self.wait_for(lambda x: not self.get_advanced_content().is_displayed())

    def get_station_cap_field(self):
        return self.driver.find_element_by_id("station-cap")

    def get_station_cap_set_button(self):
        return self.driver.find_element_by_id("station-set")

    def get_station_cap_clear_button(self):
        return self.driver.find_element_by_id("station-clear")

    def get_current_station(self):
        return self.get_station_cap_field().get_attribute("value")

    def clear_station(self):
        self.get_station_cap_clear_button().click()
        self.wait_for(lambda x: self.get_current_station() == "")

    def generate_station_using_index(self, index):
        self.open_advanced_content()
        xpath = "//div[@class='gen'][" + str(index) + "]/button"
        self.driver.find_element_by_xpath(xpath).click()

    def get_custom_station_gen_field(self):
        xpath = "//div[@class='gen'][3]/input"
        return self.driver.find_element_by_xpath(xpath)

    def generate_new_public_station(self):
        self.generate_station_using_index(1)

    def generate_new_local_station(self):
        self.generate_station_using_index(2)

    def generate_new_custom_station(self, gen_url):
        field = self.get_custom_station_gen_field()
        field.clear()
        field.send_keys(gen_url)
        self.generate_station_using_index(3)

    def open_station(self):
        if self.get_current_station() == "":
            self.generate_new_local_station()

        def open_action():
            self.wait_for(lambda x: self.get_open_link().is_displayed())
            self.get_open_link().click()

        find_new_window(self.driver, open_action)
        return BelayStationPage(self.driver)

class BelayStationInstance(object):

    def __init__(self, section, instance_row):
        self.section = section
        self.row = instance_row

    def name(self):
        return self.row.find_element_by_xpath("td[@class='name']").text

    def open(self, driver):
        find_new_window(driver, lambda: self.row.find_element_by_tag_name("a").click())

    def delete(self):
        self.row.find_element_by_xpath("//span[@class='remove']").click()
        # wait for delete animation to complete
        sleep(1)

    def get_drag_source(self):
        return self.row

    def get_drag_source_jq_matcher(self):
        elements = self.section.elem.find_elements_by_xpath('table[@class="items"]//tr')
        print len(elements)
        index = 0
        my_name = self.name()
        for element in elements:
            if element.find_element_by_xpath("td[@class='name']").text == my_name:
                break
            index += 1

        return '.items tr:eq(%d)' % index

    def is_displayed(self):
        return self.row.is_displayed()

class BelayStationSection(object):

    def __init__(self, station, section_elem):
        self.station = station
        self.elem = section_elem

    def name(self):
        return self.elem.find_element_by_xpath("table[@class='header']//td[@class='name']").text

    def is_empty(self):
        """ determines whether any instances exist in the section. """
        return len(self.instances()) == 0

    def instances(self):
        rows = self.elem.find_elements_by_xpath("table[@class='items']//tr")
        return [BelayStationInstance(self, row) for row in rows]

    def get_drop_target(self):
        return self.elem

    def get_drop_target_jq_matcher(self):
        return "#section-" + self.name()

    def set_attributes(self, attrs):
        driver = self.station.driver
        self.open_attributes()

        attribute_rows = self.elem.find_elements_by_xpath("table//table//tr")
        for row in attribute_rows:
            attr_name = row.find_element_by_class_name("tag").text
            if attr_name in attrs:
                row.find_element_by_tag_name("input").click()
                select_group = row.find_element_by_tag_name("select")
                wait_for(driver, lambda drv: select_group.is_displayed())

                found = False
                selections = select_group.find_elements_by_tag_name("option")
                for selection in selections:
                    if selection.text == attrs[attr_name]:
                        found = True
                        selection.click()

                if not found:
                    raise ("Attribute value " +
                            attrs[attr_name] +
                            "not a valid option")

        self.save_attributes()

    def open_attributes(self):
        driver = self.station.driver
        cls_finder = self.elem.find_element_by_class_name

        if cls_finder("attributes").is_displayed():
            return

        settings_link = cls_finder("settings")
        settings_link.click()
        wait_for(driver, lambda drv: cls_finder("attributes").is_displayed())

    def save_attributes(self):
        self.elem.find_element_by_class_name("save").click()
        attributes = self.elem.find_element_by_class_name("attributes")
        wait_for(self.station.driver, lambda drv: not attributes.is_displayed())

    def cancel_attributes(self):
        self.elem.find_element_by_class_name("cancel").click()
        attributes = self.elem.find_element_by_class_name("attributes")
        wait_for(self.station.driver, lambda drv: not attributes.is_displayed())

class BelayStationPage(BelayEnabledPage):
    """ Representation of the contents of the belay-station page. """

    def __init__(self, driver):
        super(BelayStationPage,self).__init__(driver)

    def categories(self):
        belay_items = self.driver.find_element_by_id("belay-items")
        category_elems = belay_items.find_elements_by_class_name("section")
        categories = list()
        for elem in category_elems:
            categories.append(BelayStationSection(self, elem))

        return categories

    def category_for_name(self, name):
        for category in self.categories():
            if category.name() == name:
                return category

        return None

    def uncategorized(self):
        return self.categories()[0]

    def personal(self):
        return self.categories()[1]

    def is_empty(self):
        """ determines whether any instances exist in the station. """
        empty = True
        for category in self.categories():
            empty = empty and category.is_empty()
        return empty

    def find_instances_by_name(self, name):
        cats = self.categories()
        instances = list()
        for cat in cats:
            for inst in cat.instances():
                if inst.name() == name:
                    instances.append(inst)

        return instances

    def move_to_category(self, instance, category):
        drag_source = instance.get_drag_source_jq_matcher()
        drop_target = category.get_drop_target_jq_matcher()
        data = self.drag_from(drag_source)

        old_instance_count = category.instances()
        self.drag_to(data, drop_target)

        self.wait_for(lambda drv: category.instances() > old_instance_count)

class BuzzerLandingPage(BelayEnabledPage):
    def __init__(self, driver):
        super(BuzzerLandingPage,self).__init__(driver)

    def create_new_instance(self, title):
        self.get_title_field().send_keys(title)
        self.driver.find_element_by_xpath("//form//input[@type='submit']").submit()
        self.wait_for(lambda drv: drv.current_url == "http://localhost:9004/buzzer-belay.html")
        return BuzzerInstancePage(self.driver)

    def get_title_field(self):
        return self.driver.find_element_by_xpath("//form//input[@type='text']")

    def get_form(self):
        return self.driver.find_element_by_xpath("//form")

class BuzzerPost(object):
    def __init__(self, instance, post_div):
        self.instance = instance
        self.post_div = post_div

    def get_content(self):
        content_div = self.post_div.find_element_by_class_name("buzzer-body")
        return content_div.text

class BuzzerInstancePage(BelayEnabledPage):
    def __init__(self, driver):
        super(BuzzerInstancePage,self).__init__(driver)

    def post(self, postText):
        num_posts = len(self.get_posts())
        self.get_post_field().clear()
        self.get_post_field().send_keys(postText)
        self.get_post_button().click()
        self.wait_for(lambda drv: len(self.get_posts()) > num_posts)

    def get_name(self):
        return self.driver.find_element_by_id("buzzer-name").text

    def get_post_field(self):
        return self.driver.find_element_by_id("body")

    def get_post_button(self):
        return self.driver.find_element_by_tag_name("input")

    def get_posts(self):
        item_xpath = "//div[@class='buzzer-item']"
        items = self.driver.find_elements_by_xpath(item_xpath)
        return [ BuzzerPost(self, item) for item in items ]

    def get_last_post(self):
        return self.get_posts()[0]

    def get_read_only_cap(self):
        return self.drag_from('.buzzer-reader-chit')

    def get_post_cap(self):
        return self.drag_from('.buzzer-post-chit')

    def get_read_only_chit(self):
        return self.driver.find_element_by_class_name("buzzer-reader-chit")

    def get_poster_name_attribute(self):
        xpath_find = self.driver.find_elements_by_xpath
        name = xpath_find("//i[@class='poster-name']")
        if name:
            return name[0].text

        return None

    def get_poster_location_attribute(self):
        xpath_find = self.driver.find_elements_by_xpath
        location = xpath_find("//i[@class='poster-location']")
        if location:
            return location[0].text

        return None

    def is_read_only(self):
        # we can determine if this is a read-only view by the absence
        # of the input text area
        return len(self.driver.find_elements_by_id('body')) == 0

def open_belay_admin(driver):
    driver.get("http://localhost:9000")
    return BelayAdminPage(driver)
<commit_msg>disable jquery animations when testing<commit_after>from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import *
from belay_test_utils import *
from time import *
import random
import os

class BelayEnabledPage(object):
    """ Common utilities for belay enabled pages. """

    def __init__(self, driver):
        self.driver = driver
        self.window = driver.current_window_handle
        self.wait_for_ready()
        self.inject_js_error_detect()
        self.disable_jquery_animations()

    def inject_js_error_detect(self):
        self.driver.execute_script("""
            window.belaytest.jsErrors = [];
            window.addEventListener('error', function(evt) {
                window.belaytest.jsErrors.push({
                    msg: evt.message,
                    file: evt.filename,
                    lineNum: evt.lineno,
                });
            });
        """)

    def disable_jquery_animations(self):
        self.driver.execute_script('jQuery.fx.off = true;')

    def get_js_errors(self):
        exec_js = self.driver.execute_script
        num_errors = exec_js("return window.belaytest.jsErrors.length")
        print "Errors: %d" % num_errors
        errors = []
        for i in range(0,num_errors):
            errors.append(exec_js("return window.belaytest.jsErrors[%d]" % i))

        return errors

    def drag_from(self, source_jq_matcher):
        driver = self.driver
        driver.execute_script("""
            var fakeDragEvt = document.createEvent('UIEvents');
            fakeDragEvt.initEvent('dragstart', true, true);
            fakeDragEvt.dataTransfer = {
                setDragImage: function(x, y, z) {},
                setData: function(mime, data) {
                    belaytest.dropped_data = data;
                }
            };
            $('%s')[0].dispatchEvent(fakeDragEvt);
        """ % source_jq_matcher)
        data = driver.execute_script("return belaytest.dropped_data")
        driver.execute_script("delete belaytest.dropped_data")
        return data

    def drag_to(self, cap_data, target_jq_matcher):
        temp_source_id = "belaytest_ddsource_" + str(random.randint(0, 2 ** 64))
        self.driver.execute_script("""
            var fakeDropEvt = document.createEvent('UIEvents');
            fakeDropEvt.initEvent('drop', true, true);
            fakeDropEvt.dataTransfer = {
                getData: function(mime) {
                    return '%s';
                }
            };
            $('%s')[0].dispatchEvent(fakeDropEvt);
        """ % (cap_data, target_jq_matcher))

    def page_ready(self, driver=None):
        driver = self.driver if driver == None else driver
        return driver.execute_script("return window.belaytest && window.belaytest.ready")

    def wait_for(self, p, timeout=5):
        wait_for(self.driver, p, timeout)

    def wait_for_ready(self):
        self.wait_for(self.page_ready)

    def focus(self):
        self.driver.switch_to_window(self.window)
        self.driver.execute_script("window.focus()")

    def close(self):
        self.driver.switch_to_window(self.window)
        self.driver.close()

    def is_open(self):
        found = false
        for window in self.driver.window_handles:
            found = found and (window == self.window)
        return found

    def get_suggestions(self):
        self.driver.switch_to_frame("belay-frame")
        suggest_button_xpath = "//button[@class='suggestButton']"
        buttons = self.driver.find_elements_by_xpath(suggest_button_xpath)
        suggestions = [button.text for button in buttons]
        self.driver.switch_to_default_content()
        return suggestions

    def open_suggestion(self, suggestion):
        self.driver.switch_to_frame("belay-frame")
        suggest_button_xpath = "//button[@class='suggestButton']"
        buttons = self.driver.find_elements_by_xpath(suggest_button_xpath)

        for b in buttons:
            if b.text == suggestion:
                # this is horrible, but I can't find any way to figure out when an
                # item is both displayed and clickable when a CSS animation is
                # currently being applied. So, we must wait for the butter bar
                # CSS animation to complete before we can go ahead and click
                sleep(1)
                b.click()
                return

class BelayAdminPage(BelayEnabledPage):
    """ Representation of the contents of the belay-belay admin page. """

    def __init__(self, driver):
        super(BelayAdminPage,self).__init__(driver)

    def get_open_link(self):
        xpath = "//div[@id='open-button']//a"
        return self.driver.find_element_by_xpath(xpath)

    def get_create_open_link(self):
        xpath = "//div[@id='create-button']//a"
        return self.driver.find_element_by_xpath(xpath)

    def click_advanced_header(self):
        xpath = "//div[@id='advanced']/h2"
        self.driver.find_element_by_xpath(xpath).click()

    def get_advanced_content(self):
        xpath = "//div[@id='advanced']/div[@class='content']"
        return self.driver.find_element_by_xpath(xpath)

    def open_advanced_content(self):
        if not self.get_advanced_content().is_displayed():
            self.click_advanced_header()
            self.wait_for(lambda x: self.get_advanced_content().is_displayed())

    def close_advanced_content(self):
        if self.get_advanced_content().is_displayed():
            self.click_advanced_header()
            self.wait_for(lambda x: not self.get_advanced_content().is_displayed())

    def get_station_cap_field(self):
        return self.driver.find_element_by_id("station-cap")

    def get_station_cap_set_button(self):
        return self.driver.find_element_by_id("station-set")

    def get_station_cap_clear_button(self):
        return self.driver.find_element_by_id("station-clear")

    def get_current_station(self):
        return self.get_station_cap_field().get_attribute("value")

    def clear_station(self):
        self.get_station_cap_clear_button().click()
        self.wait_for(lambda x: self.get_current_station() == "")

    def generate_station_using_index(self, index):
        self.open_advanced_content()
        xpath = "//div[@class='gen'][" + str(index) + "]/button"
        self.driver.find_element_by_xpath(xpath).click()

    def get_custom_station_gen_field(self):
        xpath = "//div[@class='gen'][3]/input"
        return self.driver.find_element_by_xpath(xpath)

    def generate_new_public_station(self):
        self.generate_station_using_index(1)

    def generate_new_local_station(self):
        self.generate_station_using_index(2)

    def generate_new_custom_station(self, gen_url):
        field = self.get_custom_station_gen_field()
        field.clear()
        field.send_keys(gen_url)
        self.generate_station_using_index(3)

    def open_station(self):
        if self.get_current_station() == "":
            self.generate_new_local_station()

        def open_action():
            self.wait_for(lambda x: self.get_open_link().is_displayed())
            self.get_open_link().click()

        find_new_window(self.driver, open_action)
        return BelayStationPage(self.driver)

class BelayStationInstance(object):

    def __init__(self, section, instance_row):
        self.section = section
        self.row = instance_row

    def name(self):
        return self.row.find_element_by_xpath("td[@class='name']").text

    def open(self, driver):
        find_new_window(driver, lambda: self.row.find_element_by_tag_name("a").click())

    def delete(self):
        self.row.find_element_by_xpath("//span[@class='remove']").click()
        # wait for delete animation to complete
        sleep(1)

    def get_drag_source(self):
        return self.row

    def get_drag_source_jq_matcher(self):
        elements = self.section.elem.find_elements_by_xpath('table[@class="items"]//tr')
        print len(elements)
        index = 0
        my_name = self.name()
        for element in elements:
            if element.find_element_by_xpath("td[@class='name']").text == my_name:
                break
            index += 1

        return '.items tr:eq(%d)' % index

    def is_displayed(self):
        return self.row.is_displayed()

class BelayStationSection(object):

    def __init__(self, station, section_elem):
        self.station = station
        self.elem = section_elem

    def name(self):
        return self.elem.find_element_by_xpath("table[@class='header']//td[@class='name']").text

    def is_empty(self):
        """ determines whether any instances exist in the section. """
        return len(self.instances()) == 0

    def instances(self):
        rows = self.elem.find_elements_by_xpath("table[@class='items']//tr")
        return [BelayStationInstance(self, row) for row in rows]

    def get_drop_target(self):
        return self.elem

    def get_drop_target_jq_matcher(self):
        return "#section-" + self.name()

    def set_attributes(self, attrs):
        driver = self.station.driver
        self.open_attributes()

        attribute_rows = self.elem.find_elements_by_xpath("table//table//tr")
        for row in attribute_rows:
            attr_name = row.find_element_by_class_name("tag").text
            if attr_name in attrs:
                row.find_element_by_tag_name("input").click()
                select_group = row.find_element_by_tag_name("select")
                wait_for(driver, lambda drv: select_group.is_displayed())

                found = False
                selections = select_group.find_elements_by_tag_name("option")
                for selection in selections:
                    if selection.text == attrs[attr_name]:
                        found = True
                        selection.click()

                if not found:
                    raise ("Attribute value " +
                            attrs[attr_name] +
                            "not a valid option")

        self.save_attributes()

    def open_attributes(self):
        driver = self.station.driver
        cls_finder = self.elem.find_element_by_class_name

        if cls_finder("attributes").is_displayed():
            return

        settings_link = cls_finder("settings")
        settings_link.click()
        wait_for(driver, lambda drv: cls_finder("attributes").is_displayed())

    def save_attributes(self):
        self.elem.find_element_by_class_name("save").click()
        attributes = self.elem.find_element_by_class_name("attributes")
        wait_for(self.station.driver, lambda drv: not attributes.is_displayed())

    def cancel_attributes(self):
        self.elem.find_element_by_class_name("cancel").click()
        attributes = self.elem.find_element_by_class_name("attributes")
        wait_for(self.station.driver, lambda drv: not attributes.is_displayed())

class BelayStationPage(BelayEnabledPage):
    """ Representation of the contents of the belay-station page. """

    def __init__(self, driver):
        super(BelayStationPage,self).__init__(driver)

    def categories(self):
        belay_items = self.driver.find_element_by_id("belay-items")
        category_elems = belay_items.find_elements_by_class_name("section")
        categories = list()
        for elem in category_elems:
            categories.append(BelayStationSection(self, elem))

        return categories

    def category_for_name(self, name):
        for category in self.categories():
            if category.name() == name:
                return category

        return None

    def uncategorized(self):
        return self.categories()[0]

    def personal(self):
        return self.categories()[1]

    def is_empty(self):
        """ determines whether any instances exist in the station. """
        empty = True
        for category in self.categories():
            empty = empty and category.is_empty()
        return empty

    def find_instances_by_name(self, name):
        cats = self.categories()
        instances = list()
        for cat in cats:
            for inst in cat.instances():
                if inst.name() == name:
                    instances.append(inst)

        return instances

    def move_to_category(self, instance, category):
        drag_source = instance.get_drag_source_jq_matcher()
        drop_target = category.get_drop_target_jq_matcher()
        data = self.drag_from(drag_source)

        old_instance_count = category.instances()
        self.drag_to(data, drop_target)

        self.wait_for(lambda drv: category.instances() > old_instance_count)

class BuzzerLandingPage(BelayEnabledPage):
    def __init__(self, driver):
        super(BuzzerLandingPage,self).__init__(driver)

    def create_new_instance(self, title):
        self.get_title_field().send_keys(title)
        self.driver.find_element_by_xpath("//form//input[@type='submit']").submit()
        self.wait_for(lambda drv: drv.current_url == "http://localhost:9004/buzzer-belay.html")
        return BuzzerInstancePage(self.driver)

    def get_title_field(self):
        return self.driver.find_element_by_xpath("//form//input[@type='text']")

    def get_form(self):
        return self.driver.find_element_by_xpath("//form")

class BuzzerPost(object):
    def __init__(self, instance, post_div):
        self.instance = instance
        self.post_div = post_div

    def get_content(self):
        content_div = self.post_div.find_element_by_class_name("buzzer-body")
        return content_div.text

class BuzzerInstancePage(BelayEnabledPage):
    def __init__(self, driver):
        super(BuzzerInstancePage,self).__init__(driver)

    def post(self, postText):
        num_posts = len(self.get_posts())
        self.get_post_field().clear()
        self.get_post_field().send_keys(postText)
        self.get_post_button().click()
        self.wait_for(lambda drv: len(self.get_posts()) > num_posts)

    def get_name(self):
        return self.driver.find_element_by_id("buzzer-name").text

    def get_post_field(self):
        return self.driver.find_element_by_id("body")

    def get_post_button(self):
        return self.driver.find_element_by_tag_name("input")

    def get_posts(self):
        item_xpath = "//div[@class='buzzer-item']"
        items = self.driver.find_elements_by_xpath(item_xpath)
        return [ BuzzerPost(self, item) for item in items ]

    def get_last_post(self):
        return self.get_posts()[0]

    def get_read_only_cap(self):
        return self.drag_from('.buzzer-reader-chit')

    def get_post_cap(self):
        return self.drag_from('.buzzer-post-chit')

    def get_read_only_chit(self):
        return self.driver.find_element_by_class_name("buzzer-reader-chit")

    def get_poster_name_attribute(self):
        xpath_find = self.driver.find_elements_by_xpath
        name = xpath_find("//i[@class='poster-name']")
        if name:
            return name[0].text

        return None

    def get_poster_location_attribute(self):
        xpath_find = self.driver.find_elements_by_xpath
        location = xpath_find("//i[@class='poster-location']")
        if location:
            return location[0].text

        return None

    def is_read_only(self):
        # we can determine if this is a read-only view by the absence
        # of the input text area
        return len(self.driver.find_elements_by_id('body')) == 0

def open_belay_admin(driver):
    driver.get("http://localhost:9000")
    return BelayAdminPage(driver)
<|endoftext|>


<commit_before>#########
# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved
#
# 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 os
import shutil
import tempfile
import ast

import testtools
from testfixtures import log_capture

import cloudify.ctx_wrappers
from cloudify.exceptions import NonRecoverableError
from cloudify.exceptions import OperationRetry
from cloudify.workflows import local
from script_runner.tasks import ProcessException, IS_WINDOWS

BLUEPRINT_DIR = os.path.join(os.path.dirname(__file__), 'wrapper_blueprint')

class PythonWrapperTests(testtools.TestCase):

    @classmethod
    def setUpClass(cls):
        source = os.path.join(os.path.dirname(
            cloudify.ctx_wrappers.__file__), 'ctx-py.py')
        cls.tempdir = tempfile.mkdtemp()
        destination = os.path.join(cls.tempdir, 'ctxwrapper.py')
        shutil.copy(source, destination)

    @classmethod
    def tearDownClass(cls):
        try:
            shutil.rmtree(cls.tempdir)
        except:
            pass

    def setUp(self):
        super(PythonWrapperTests, self).setUp()
        self.script_path = tempfile.mktemp()
        self.addCleanup(self.cleanup)

    def cleanup(self):
        try:
            os.remove(self.script_path)
        except:
            pass

    def _prescript(self):
        return (
            '#!/usr/bin/env python\n'
            'from ctxwrapper import ctx\n'.format(self.tempdir)
        )

    def _create_script(self, script):
        script_path = tempfile.mktemp()
        with open(script_path, 'w') as f:
            f.write(self._prescript() + script)
        return script_path

    def _run(self, script,
             process=None,
             workflow_name='execute_operation',
             parameters=None,
             env_var='value',
             task_retries=0):

        self.script_path = self._create_script(script)
        process = process or {}
        env = process.setdefault('env', {})

        if 'PYTHONPATH' in env:
            env['PYTHONPATH'] += ':' + self.tempdir
        else:
            env['PYTHONPATH'] = self.tempdir

        if IS_WINDOWS:
            process['command_prefix'] = 'python'

        inputs = {
            'script_path': self.script_path,
            'process': process,
            'env_var': env_var
        }
        blueprint_path = os.path.join(BLUEPRINT_DIR, 'blueprint.yaml')
        self.env = local.init_env(blueprint_path,
                                  name=self._testMethodName,
                                  inputs=inputs)
        result = self.env.execute(workflow_name,
                                  parameters=parameters,
                                  task_retries=task_retries,
                                  task_retry_interval=0)
        if not result:
            result = self.env.storage.get_node_instances()[0][
                'runtime_properties']
        return result

    def test_direct_ctx_call(self):
        script = ('ctx("instance runtime-properties key value")')
        result = self._run(script)
        self.assertEqual(result['key'], 'value')

    def test_direct_bad_ctx_call(self):
        script = ('ctx("bad_call")')
        ex = self.assertRaises(ProcessException, self._run, script)
        self.assertIn(
            'RuntimeError: bad_call cannot be processed in',
            str(ex))

    def test_direct_ctx_call_missing_property(self):
        script = ('ctx("node properties missing_node_property")')
        ex = self.assertRaises(ProcessException, self._run, script)
        self.assertIn(
            'illegal path: missing_node_property',
            str(ex))

    @log_capture()
    def test_logger(self, capture):
        script = ('ctx.logger.debug("debug_message")\n'
                  'ctx.logger.info("info_message")\n'
                  'ctx.logger.warn("warning_message")\n'
                  'ctx.logger.error("error_message")')
        expected_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR']
        expected_msgs = [
            'debug_message',
            'info_message',
            'warning_message',
            'error_message'
        ]
        self._run(script)
        # first message is unrelated to the test
        capture.records.pop(0)
        for m in range(1, len(expected_levels)):
            self.assertEqual(
                '{0}: {1}'.format(
                    capture.records[m].levelname,
                    capture.records[m].msg),
                '{0}: {1}'.format(
                    expected_levels[m],
                    expected_msgs[m]))

    def test_get_node_properties(self):
        script = ('value = ctx.node.properties["key"]\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('value', result)

    def test_get_all_node_properties(self):
        script = ('value = ctx.node.properties.get_all()\n'
                  'ctx.returns(value)')
        result = self._run(script)
        res_dict = ast.literal_eval(result)
        self.assertIn('ip', res_dict.keys())
        self.assertEquals(res_dict['ip'], '1.1.1.1')
        self.assertIn('key', res_dict.keys())
        self.assertEquals(res_dict['key'], 'value')

    def test_get_node_properties_get_function(self):
        script = ('value = ctx.node.properties.get("key", "b")\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('value', result)

    def test_get_node_properties_get_function_missing_key_no_default(self):
        script = ('value = ctx.node.properties.get("key1")\n'
                  'ctx.returns(type(value))')
        result = self._run(script)
        self.assertEqual("<type 'NoneType'>", str(result))

    def test_get_node_properties_get_function_missing_key_with_default(self):
        script = ('value = ctx.node.properties.get("key1", "b")\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('b', result)

    def test_get_node_id(self):
        script = ('value = ctx.node.id\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('test_node', result)

    def test_get_node_name(self):
        script = ('value = ctx.node.name\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('test_node', result)

    def test_get_node_type(self):
        script = ('value = ctx.node.type\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('cloudify.nodes.Compute', result)

    def test_get_instance_id(self):
        script = ('value = ctx.instance.id\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertIn('test_node_', result)

    def test_get_instance_relationships(self):
        script = ('value = ctx.instance.relationships\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual([], eval(result))

    def test_set_get_instance_runtime_properties(self):
        script = ('ctx.instance.runtime_properties["key"] = "value"\n'
                  'value = ctx.instance.runtime_properties["key"]\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('value', result)

    def test_get_instance_runtime_properties_non_string(self):
        script = ('value = ctx.instance.runtime_properties["key"] = 1\n'
                  'ctx.returns(type(value))')
        result = self._run(script)
        self.assertEqual("<type 'int'>", result)

    def test_get_instance_runtime_properties_missing_key_no_default(self):
        script = ('value = ctx.instance.runtime_properties.get("key1")\n'
                  'ctx.returns(type(value))')
        result = self._run(script)
        self.assertEqual("<type 'NoneType'>", str(result))

    def test_get_instance_runtime_properties_missing_key_with_default(self):
        script = ('value = ctx.instance.runtime_properties.get("key1", "b")\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('b', result)

    def test_get_instance_host_ip(self):
        script = ('value = ctx.instance.host_ip\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual(result, '1.1.1.1')

    def _test_download_resource(self, script, expected_content):
        result = None
        try:
            result = self._run(script)
            self.assertTrue(result.startswith(tempfile.gettempdir()))
            self.assertTrue(result.endswith('-resource'))
            with open(result) as f:
                resulting_content = f.read()
            self.assertEqual(expected_content, resulting_content)
        finally:
            if result is not None:
                os.remove(result)

    def test_download_resource(self):
        script = ('path = ctx.download_resource("resource")\n'
                  'ctx.returns(path)')
        self._test_download_resource(
            script=script,
            expected_content='{{ ctx.node.name }}')

    def test_download_resource_with_destination(self):
        fd, temp_path = tempfile.mkstemp(suffix='-resource')
        os.close(fd)
        script = ('path = ctx.download_resource("resource", {0!r})\n'
                  'ctx.returns(path)'.format(temp_path))
        self._test_download_resource(
            script=script,
            expected_content='{{ ctx.node.name }}')

    def test_download_resource_and_render(self):
        script = ('path = ctx.download_resource_and_render("resource")\n'
                  'ctx.returns(path)')
        self._test_download_resource(
            script=script,
            expected_content='test_node')

    def test_download_resource_and_render_with_destination(self):
        fd, temp_path = tempfile.mkstemp(suffix='-resource')
        os.close(fd)
        script = ('path = ctx.download_resource_and_render("resource", {0!r})\n'  # NOQA
                  'ctx.returns(path)'.format(temp_path))
        self._test_download_resource(
            script=script,
            expected_content='test_node')

    def test_download_missing_resource(self):
        script = ('path = ctx.download_resource("missing_resource")\n'
                  'ctx.returns(path)')
        ex = self.assertRaises(ProcessException, self._run, script)
        self.assertIn(
            'IOError: [Errno 2] No such file or directory:',
            str(ex))

    def test_abort_operation(self):
        script = ('ctx.abort_operation("abort_message")')
        ex = self.assertRaises(NonRecoverableError, self._run, script)
        self.assertIn('abort_message', str(ex))

    def test_retry_operation(self):
        script = ('ctx.retry_operation("retry_message")')
        ex = self.assertRaises(OperationRetry, self._run, script)
        self.assertIn('retry_message', str(ex))
<commit_msg>CFY-5100 add ctx-py wrapper test for logger.warning<commit_after>#########
# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved
#
# 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 os
import shutil
import tempfile
import ast

import testtools
from testfixtures import log_capture

import cloudify.ctx_wrappers
from cloudify.exceptions import NonRecoverableError
from cloudify.exceptions import OperationRetry
from cloudify.workflows import local
from script_runner.tasks import ProcessException, IS_WINDOWS

BLUEPRINT_DIR = os.path.join(os.path.dirname(__file__), 'wrapper_blueprint')

class PythonWrapperTests(testtools.TestCase):

    @classmethod
    def setUpClass(cls):
        source = os.path.join(os.path.dirname(
            cloudify.ctx_wrappers.__file__), 'ctx-py.py')
        cls.tempdir = tempfile.mkdtemp()
        destination = os.path.join(cls.tempdir, 'ctxwrapper.py')
        shutil.copy(source, destination)

    @classmethod
    def tearDownClass(cls):
        try:
            shutil.rmtree(cls.tempdir)
        except:
            pass

    def setUp(self):
        super(PythonWrapperTests, self).setUp()
        self.script_path = tempfile.mktemp()
        self.addCleanup(self.cleanup)

    def cleanup(self):
        try:
            os.remove(self.script_path)
        except:
            pass

    def _prescript(self):
        return (
            '#!/usr/bin/env python\n'
            'from ctxwrapper import ctx\n'.format(self.tempdir)
        )

    def _create_script(self, script):
        script_path = tempfile.mktemp()
        with open(script_path, 'w') as f:
            f.write(self._prescript() + script)
        return script_path

    def _run(self, script,
             process=None,
             workflow_name='execute_operation',
             parameters=None,
             env_var='value',
             task_retries=0):

        self.script_path = self._create_script(script)
        process = process or {}
        env = process.setdefault('env', {})

        if 'PYTHONPATH' in env:
            env['PYTHONPATH'] += ':' + self.tempdir
        else:
            env['PYTHONPATH'] = self.tempdir

        if IS_WINDOWS:
            process['command_prefix'] = 'python'

        inputs = {
            'script_path': self.script_path,
            'process': process,
            'env_var': env_var
        }
        blueprint_path = os.path.join(BLUEPRINT_DIR, 'blueprint.yaml')
        self.env = local.init_env(blueprint_path,
                                  name=self._testMethodName,
                                  inputs=inputs)
        result = self.env.execute(workflow_name,
                                  parameters=parameters,
                                  task_retries=task_retries,
                                  task_retry_interval=0)
        if not result:
            result = self.env.storage.get_node_instances()[0][
                'runtime_properties']
        return result

    def test_direct_ctx_call(self):
        script = ('ctx("instance runtime-properties key value")')
        result = self._run(script)
        self.assertEqual(result['key'], 'value')

    def test_direct_bad_ctx_call(self):
        script = ('ctx("bad_call")')
        ex = self.assertRaises(ProcessException, self._run, script)
        self.assertIn(
            'RuntimeError: bad_call cannot be processed in',
            str(ex))

    def test_direct_ctx_call_missing_property(self):
        script = ('ctx("node properties missing_node_property")')
        ex = self.assertRaises(ProcessException, self._run, script)
        self.assertIn(
            'illegal path: missing_node_property',
            str(ex))

    @log_capture()
    def test_logger(self, capture):
        script = ('ctx.logger.debug("debug_message")\n'
                  'ctx.logger.info("info_message")\n'
                  'ctx.logger.warn("warning_message")\n'
                  'ctx.logger.warning("warning_message")\n'
                  'ctx.logger.error("error_message")')
        expected_levels = ['DEBUG', 'INFO', 'WARNING', 'WARNING', 'ERROR']
        expected_msgs = [
            'debug_message',
            'info_message',
            'warning_message',
            'warning_message',
            'error_message'
        ]
        self._run(script)
        # first message is unrelated to the test
        capture.records.pop(0)
        for m in range(1, len(expected_levels)):
            self.assertEqual(
                '{0}: {1}'.format(
                    capture.records[m].levelname,
                    capture.records[m].msg),
                '{0}: {1}'.format(
                    expected_levels[m],
                    expected_msgs[m]))

    def test_get_node_properties(self):
        script = ('value = ctx.node.properties["key"]\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('value', result)

    def test_get_all_node_properties(self):
        script = ('value = ctx.node.properties.get_all()\n'
                  'ctx.returns(value)')
        result = self._run(script)
        res_dict = ast.literal_eval(result)
        self.assertIn('ip', res_dict.keys())
        self.assertEquals(res_dict['ip'], '1.1.1.1')
        self.assertIn('key', res_dict.keys())
        self.assertEquals(res_dict['key'], 'value')

    def test_get_node_properties_get_function(self):
        script = ('value = ctx.node.properties.get("key", "b")\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('value', result)

    def test_get_node_properties_get_function_missing_key_no_default(self):
        script = ('value = ctx.node.properties.get("key1")\n'
                  'ctx.returns(type(value))')
        result = self._run(script)
        self.assertEqual("<type 'NoneType'>", str(result))

    def test_get_node_properties_get_function_missing_key_with_default(self):
        script = ('value = ctx.node.properties.get("key1", "b")\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('b', result)

    def test_get_node_id(self):
        script = ('value = ctx.node.id\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('test_node', result)

    def test_get_node_name(self):
        script = ('value = ctx.node.name\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('test_node', result)

    def test_get_node_type(self):
        script = ('value = ctx.node.type\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('cloudify.nodes.Compute', result)

    def test_get_instance_id(self):
        script = ('value = ctx.instance.id\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertIn('test_node_', result)

    def test_get_instance_relationships(self):
        script = ('value = ctx.instance.relationships\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual([], eval(result))

    def test_set_get_instance_runtime_properties(self):
        script = ('ctx.instance.runtime_properties["key"] = "value"\n'
                  'value = ctx.instance.runtime_properties["key"]\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('value', result)

    def test_get_instance_runtime_properties_non_string(self):
        script = ('value = ctx.instance.runtime_properties["key"] = 1\n'
                  'ctx.returns(type(value))')
        result = self._run(script)
        self.assertEqual("<type 'int'>", result)

    def test_get_instance_runtime_properties_missing_key_no_default(self):
        script = ('value = ctx.instance.runtime_properties.get("key1")\n'
                  'ctx.returns(type(value))')
        result = self._run(script)
        self.assertEqual("<type 'NoneType'>", str(result))

    def test_get_instance_runtime_properties_missing_key_with_default(self):
        script = ('value = ctx.instance.runtime_properties.get("key1", "b")\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual('b', result)

    def test_get_instance_host_ip(self):
        script = ('value = ctx.instance.host_ip\n'
                  'ctx.returns(value)')
        result = self._run(script)
        self.assertEqual(result, '1.1.1.1')

    def _test_download_resource(self, script, expected_content):
        result = None
        try:
            result = self._run(script)
            self.assertTrue(result.startswith(tempfile.gettempdir()))
            self.assertTrue(result.endswith('-resource'))
            with open(result) as f:
                resulting_content = f.read()
            self.assertEqual(expected_content, resulting_content)
        finally:
            if result is not None:
                os.remove(result)

    def test_download_resource(self):
        script = ('path = ctx.download_resource("resource")\n'
                  'ctx.returns(path)')
        self._test_download_resource(
            script=script,
            expected_content='{{ ctx.node.name }}')

    def test_download_resource_with_destination(self):
        fd, temp_path = tempfile.mkstemp(suffix='-resource')
        os.close(fd)
        script = ('path = ctx.download_resource("resource", {0!r})\n'
                  'ctx.returns(path)'.format(temp_path))
        self._test_download_resource(
            script=script,
            expected_content='{{ ctx.node.name }}')

    def test_download_resource_and_render(self):
        script = ('path = ctx.download_resource_and_render("resource")\n'
                  'ctx.returns(path)')
        self._test_download_resource(
            script=script,
            expected_content='test_node')

    def test_download_resource_and_render_with_destination(self):
        fd, temp_path = tempfile.mkstemp(suffix='-resource')
        os.close(fd)
        script = ('path = ctx.download_resource_and_render("resource", {0!r})\n'  # NOQA
                  'ctx.returns(path)'.format(temp_path))
        self._test_download_resource(
            script=script,
            expected_content='test_node')

    def test_download_missing_resource(self):
        script = ('path = ctx.download_resource("missing_resource")\n'
                  'ctx.returns(path)')
        ex = self.assertRaises(ProcessException, self._run, script)
        self.assertIn(
            'IOError: [Errno 2] No such file or directory:',
            str(ex))

    def test_abort_operation(self):
        script = ('ctx.abort_operation("abort_message")')
        ex = self.assertRaises(NonRecoverableError, self._run, script)
        self.assertIn('abort_message', str(ex))

    def test_retry_operation(self):
        script = ('ctx.retry_operation("retry_message")')
        ex = self.assertRaises(OperationRetry, self._run, script)
        self.assertIn('retry_message', str(ex))
<|endoftext|>


<commit_before>"""
Unofficial Python Lending Club API

Using this API user should be able to find necessary information of their
investor account as well as placing orders.
"""

__version__ = "0.3.0"
<commit_msg>Release 0.4.0<commit_after>"""
Unofficial Python Lending Club API

Using this API user should be able to find necessary information of their
investor account as well as placing orders.
"""

__version__ = "0.4.0"
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Copyright 2009-2019 Joshua Bronson. All Rights Reserved.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

"""Strategies for Hypothesis tests."""

import re
from collections import OrderedDict

from hypothesis import assume, strategies as st
from bidict import IGNORE, OVERWRITE, RAISE, OrderedBidictBase, namedbidict
from bidict.compat import PY2, izip

import _types as t

# pylint: disable=invalid-name

DATA = st.data()
RAND = st.randoms()
BIDICT_TYPES = st.sampled_from(t.BIDICT_TYPES)
MUTABLE_BIDICT_TYPES = st.sampled_from(t.MUTABLE_BIDICT_TYPES)
FROZEN_BIDICT_TYPES = st.sampled_from(t.FROZEN_BIDICT_TYPES)
ORDERED_BIDICT_TYPES = st.sampled_from(t.ORDERED_BIDICT_TYPES)
MAPPING_TYPES = st.sampled_from(t.MAPPING_TYPES)
NON_BIDICT_MAPPING_TYPES = st.sampled_from(t.NON_BIDICT_MAPPING_TYPES)
ORDERED_MAPPING_TYPES = st.sampled_from(t.ORDERED_MAPPING_TYPES)
HASHABLE_MAPPING_TYPES = st.sampled_from(t.HASHABLE_MAPPING_TYPES)
DUP_POLICIES = st.sampled_from((IGNORE, OVERWRITE, RAISE))
DUP_POLICIES_DICT = st.fixed_dictionaries(dict(
    on_dup_key=DUP_POLICIES,
    on_dup_val=DUP_POLICIES,
    on_dup_kv=DUP_POLICIES,
))

BOOLEANS = st.booleans()
FLOATS = st.floats(allow_nan=False)
INTS = st.integers()
TEXT = st.text()
NONE = st.none()
IMMUTABLES = BOOLEANS | TEXT | NONE | INTS | FLOATS

LISTS_MAX_SIZE = 10
LISTS_PAIRS = st.lists(st.tuples(IMMUTABLES, IMMUTABLES), max_size=LISTS_MAX_SIZE)

NON_MAPPINGS = IMMUTABLES | LISTS_PAIRS

IDENTIFIER_TYPE = TEXT
if PY2:
    IDENTIFIER_TYPE = IDENTIFIER_TYPE.map(lambda x: x.encode('utf-8'))

@st.composite
def _lists_pairs_with_duplication(draw):
    # pylint: disable=too-many-locals
    n = draw(st.integers(min_value=3, max_value=LISTS_MAX_SIZE))
    indexes = st.integers(min_value=0, max_value=n - 1)
    keys = draw(st.lists(IMMUTABLES, min_size=n, max_size=n))
    vals = draw(st.lists(IMMUTABLES, min_size=n, max_size=n))
    fwd = OrderedDict(izip(keys, vals))
    inv = OrderedDict(izip(vals, keys))
    which_to_dup = draw(RAND).choice((1, 2, 3))
    should_dup_key = which_to_dup in (1, 3)
    should_dup_val = which_to_dup in (2, 3)
    should_add_dup_key = should_dup_key and len(fwd) < n
    should_add_dup_val = should_dup_val and len(inv) < n
    if not should_add_dup_key and not should_add_dup_val:
        return list(izip(keys, vals))
    if should_add_dup_key:
        dup_key_idx = draw(indexes)
        added_key = keys[dup_key_idx]
    else:
        added_key = draw(IMMUTABLES)
        assume(added_key not in fwd)
    if should_add_dup_val:
        dup_val_idx = draw(indexes)
        if should_add_dup_key:
            assume(dup_val_idx != dup_key_idx)
        added_val = vals[dup_val_idx]
    else:
        added_val = draw(IMMUTABLES)
        assume(added_val not in inv)
    insert_idx = draw(indexes)
    keys.insert(insert_idx, added_key)
    vals.insert(insert_idx, added_val)
    return list(izip(keys, vals))

# pylint: disable=no-value-for-parameter
LISTS_PAIRS_DUP = _lists_pairs_with_duplication()

@st.composite
def lists_pairs_nodup(draw, elements=IMMUTABLES, min_size=0, max_size=LISTS_MAX_SIZE):
    """Generate a list of pairs from the given elements with no duplication."""
    n = draw(st.integers(min_value=min_size, max_value=max_size))
    size_n_sets = st.sets(elements, min_size=n, max_size=n)
    keys = draw(size_n_sets)
    vals = draw(size_n_sets)
    return list(izip(keys, vals))

LISTS_PAIRS_NODUP = lists_pairs_nodup()
LISTS_TEXT_PAIRS_NODUP = lists_pairs_nodup(elements=TEXT)

# pylint: disable=dangerous-default-value
@st.composite
def bidicts(draw, bi_types=BIDICT_TYPES, init_items=LISTS_PAIRS_NODUP):
    """Generate bidicts."""
    bi_cls = draw(bi_types)
    items = draw(init_items)
    bi = bi_cls(items)
    # Return the inverse bidict with 50% probability to increase coverage.
    return bi if draw(RAND).choice((True, False)) else bi.inv

BIDICTS = bidicts()
FROZEN_BIDICTS = bidicts(bi_types=FROZEN_BIDICT_TYPES)
MUTABLE_BIDICTS = bidicts(bi_types=MUTABLE_BIDICT_TYPES)
ORDERED_BIDICTS = bidicts(bi_types=ORDERED_BIDICT_TYPES)

NAMEDBIDICT_VALID_NAME_PAT = re.compile('[A-z][A-z0-9_]*$')
NAMEDBIDICT_NAMES = st.from_regex(NAMEDBIDICT_VALID_NAME_PAT, fullmatch=True)
NAMEDBIDICT_3_NAMES = st.tuples(
    NAMEDBIDICT_NAMES,
    NAMEDBIDICT_NAMES,
    NAMEDBIDICT_NAMES,
)

@st.composite
def _namedbidict_types(draw, names=NAMEDBIDICT_3_NAMES, base_types=BIDICT_TYPES):
    typename, keyname, valname = draw(names)
    assume(keyname != valname)
    base_type = draw(base_types)
    return namedbidict(typename, keyname, valname, base_type=base_type)

NAMEDBIDICT_TYPES = _namedbidict_types()

@st.composite
def _namedbidicts(draw, nb_types=NAMEDBIDICT_TYPES, init_items=LISTS_PAIRS_NODUP):
    nb_cls = draw(nb_types)
    items = draw(init_items)
    nb = nb_cls(items)
    # Return the inverse namedbidict with 50% probability to increase coverage.
    return nb if draw(RAND).choice((True, False)) else nb.inv

NAMEDBIDICTS = _namedbidicts()

_COMPARE_DICT_TYPE = object()
_SAME_AS_BI_ITEMS = object()
_SAME_AS_BI_ITEMS_DIFF_ORDER = object()

@st.composite
def _bidict_and_mapping_from_items(
        draw,
        bi_types=BIDICT_TYPES,
        map_types=MAPPING_TYPES,
        bi_items=LISTS_PAIRS_NODUP,
        map_items=_SAME_AS_BI_ITEMS,
):
    bi_cls = draw(bi_types)
    if map_types is _COMPARE_DICT_TYPE:
        map_cls = OrderedDict if issubclass(bi_cls, OrderedBidictBase) else dict
    else:
        map_cls = draw(map_types)
    bi_items_ = draw(bi_items)
    same_items = map_items in (_SAME_AS_BI_ITEMS, _SAME_AS_BI_ITEMS_DIFF_ORDER)
    if same_items:
        map_items_ = bi_items_[:]
        if map_items is _SAME_AS_BI_ITEMS_DIFF_ORDER:
            draw(RAND).shuffle(map_items_)
            assume(map_items_ != bi_items_)
    else:
        map_items_ = draw(map_items)
    b = bi_cls(bi_items_)
    m = map_cls(map_items_)
    if not same_items:
        assume(m.items() != b.items())
    return b, m

BIDICT_AND_MAPPING_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items()
BIDICT_AND_MAPPING_FROM_DIFFERENT_ITEMS = _bidict_and_mapping_from_items(
    map_items=LISTS_PAIRS_NODUP,
)
BIDICT_AND_COMPARE_DICT_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items(
    map_types=_COMPARE_DICT_TYPE,
)
ORDERED_BIDICT_AND_ORDERED_DICT_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items(
    bi_types=ORDERED_BIDICT_TYPES,
    map_types=_COMPARE_DICT_TYPE,
)
ORDERED_BIDICT_AND_ORDERED_MAPPING_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items(
    bi_types=ORDERED_BIDICT_TYPES,
    map_types=ORDERED_MAPPING_TYPES,
)
HASHABLE_BIDICT_AND_MAPPING_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items(
    bi_types=FROZEN_BIDICT_TYPES,
    map_types=HASHABLE_MAPPING_TYPES,
)
ORDERED_BIDICT_AND_ORDERED_MAPPING_FROM_SAME_ITEMS_DIFF_ORDER = _bidict_and_mapping_from_items(
    bi_types=ORDERED_BIDICT_TYPES,
    map_types=ORDERED_MAPPING_TYPES,
    map_items=_SAME_AS_BI_ITEMS_DIFF_ORDER,
)

NO_ARGS = st.just(())
IM_ARG = st.tuples(IMMUTABLES)
LP_ARG = st.tuples(LISTS_PAIRS)
TWO_IM_ARGS = st.tuples(IMMUTABLES, IMMUTABLES)

ARGS_BY_METHOD = st.fixed_dictionaries({
    # mutating
    # 0-arity
    (0, 'clear'): NO_ARGS,
    (0, 'popitem'): NO_ARGS,
    # 1-arity, an immutable atom
    (1, '__delitem__'): IM_ARG,
    (1, 'pop'): IM_ARG,
    (1, 'setdefault'): IM_ARG,
    (1, 'move_to_end'): IM_ARG,
    # 1-arity, a list of pairs
    (1, 'update'): LP_ARG,
    (1, 'forceupdate'): LP_ARG,
    # 2-arity
    (2, 'pop'): TWO_IM_ARGS,
    (2, 'setdefault'): TWO_IM_ARGS,
    (2, '__setitem__'): TWO_IM_ARGS,
    (2, 'put'): TWO_IM_ARGS,
    (2, 'forceput'): TWO_IM_ARGS,
    (2, 'move_to_end'): st.tuples(IMMUTABLES, BOOLEANS),
    # non-mutating
    # 0-arity
    (0, '__copy__'): NO_ARGS,
    (0, '__iter__'): NO_ARGS,
    (0, '__len__'): NO_ARGS,
    (0, 'copy'): NO_ARGS,
    (0, 'keys'): NO_ARGS,
    (0, 'items'): NO_ARGS,
    (0, 'values'): NO_ARGS,
    (0, 'iterkeys'): NO_ARGS,
    (0, 'iteritems'): NO_ARGS,
    (0, 'itervalues'): NO_ARGS,
    (0, 'viewkeys'): NO_ARGS,
    (0, 'viewitems'): NO_ARGS,
    (0, 'viewvalues'): NO_ARGS,
    # 1-arity
    (1, '__contains__'): IM_ARG,
    (1, '__getitem__'): IM_ARG,
    (1, 'get'): IM_ARG,
})
<commit_msg>Use ItemsView in _bidict_and_mapping_from_items when not same_items for portability.<commit_after># -*- coding: utf-8 -*-
# Copyright 2009-2019 Joshua Bronson. All Rights Reserved.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

"""Strategies for Hypothesis tests."""

import re
from collections import OrderedDict

from hypothesis import assume, strategies as st
from bidict import IGNORE, OVERWRITE, RAISE, OrderedBidictBase, namedbidict
from bidict.compat import ItemsView, PY2, izip

import _types as t

# pylint: disable=invalid-name

DATA = st.data()
RAND = st.randoms()
BIDICT_TYPES = st.sampled_from(t.BIDICT_TYPES)
MUTABLE_BIDICT_TYPES = st.sampled_from(t.MUTABLE_BIDICT_TYPES)
FROZEN_BIDICT_TYPES = st.sampled_from(t.FROZEN_BIDICT_TYPES)
ORDERED_BIDICT_TYPES = st.sampled_from(t.ORDERED_BIDICT_TYPES)
MAPPING_TYPES = st.sampled_from(t.MAPPING_TYPES)
NON_BIDICT_MAPPING_TYPES = st.sampled_from(t.NON_BIDICT_MAPPING_TYPES)
ORDERED_MAPPING_TYPES = st.sampled_from(t.ORDERED_MAPPING_TYPES)
HASHABLE_MAPPING_TYPES = st.sampled_from(t.HASHABLE_MAPPING_TYPES)
DUP_POLICIES = st.sampled_from((IGNORE, OVERWRITE, RAISE))
DUP_POLICIES_DICT = st.fixed_dictionaries(dict(
    on_dup_key=DUP_POLICIES,
    on_dup_val=DUP_POLICIES,
    on_dup_kv=DUP_POLICIES,
))

BOOLEANS = st.booleans()
FLOATS = st.floats(allow_nan=False)
INTS = st.integers()
TEXT = st.text()
NONE = st.none()
IMMUTABLES = BOOLEANS | TEXT | NONE | INTS | FLOATS

LISTS_MAX_SIZE = 10
LISTS_PAIRS = st.lists(st.tuples(IMMUTABLES, IMMUTABLES), max_size=LISTS_MAX_SIZE)

NON_MAPPINGS = IMMUTABLES | LISTS_PAIRS

IDENTIFIER_TYPE = TEXT
if PY2:
    IDENTIFIER_TYPE = IDENTIFIER_TYPE.map(lambda x: x.encode('utf-8'))

@st.composite
def _lists_pairs_with_duplication(draw):
    # pylint: disable=too-many-locals
    n = draw(st.integers(min_value=3, max_value=LISTS_MAX_SIZE))
    indexes = st.integers(min_value=0, max_value=n - 1)
    keys = draw(st.lists(IMMUTABLES, min_size=n, max_size=n))
    vals = draw(st.lists(IMMUTABLES, min_size=n, max_size=n))
    fwd = OrderedDict(izip(keys, vals))
    inv = OrderedDict(izip(vals, keys))
    which_to_dup = draw(RAND).choice((1, 2, 3))
    should_dup_key = which_to_dup in (1, 3)
    should_dup_val = which_to_dup in (2, 3)
    should_add_dup_key = should_dup_key and len(fwd) < n
    should_add_dup_val = should_dup_val and len(inv) < n
    if not should_add_dup_key and not should_add_dup_val:
        return list(izip(keys, vals))
    if should_add_dup_key:
        dup_key_idx = draw(indexes)
        added_key = keys[dup_key_idx]
    else:
        added_key = draw(IMMUTABLES)
        assume(added_key not in fwd)
    if should_add_dup_val:
        dup_val_idx = draw(indexes)
        if should_add_dup_key:
            assume(dup_val_idx != dup_key_idx)
        added_val = vals[dup_val_idx]
    else:
        added_val = draw(IMMUTABLES)
        assume(added_val not in inv)
    insert_idx = draw(indexes)
    keys.insert(insert_idx, added_key)
    vals.insert(insert_idx, added_val)
    return list(izip(keys, vals))

# pylint: disable=no-value-for-parameter
LISTS_PAIRS_DUP = _lists_pairs_with_duplication()

@st.composite
def lists_pairs_nodup(draw, elements=IMMUTABLES, min_size=0, max_size=LISTS_MAX_SIZE):
    """Generate a list of pairs from the given elements with no duplication."""
    n = draw(st.integers(min_value=min_size, max_value=max_size))
    size_n_sets = st.sets(elements, min_size=n, max_size=n)
    keys = draw(size_n_sets)
    vals = draw(size_n_sets)
    return list(izip(keys, vals))

LISTS_PAIRS_NODUP = lists_pairs_nodup()
LISTS_TEXT_PAIRS_NODUP = lists_pairs_nodup(elements=TEXT)

# pylint: disable=dangerous-default-value
@st.composite
def bidicts(draw, bi_types=BIDICT_TYPES, init_items=LISTS_PAIRS_NODUP):
    """Generate bidicts."""
    bi_cls = draw(bi_types)
    items = draw(init_items)
    bi = bi_cls(items)
    # Return the inverse bidict with 50% probability to increase coverage.
    return bi if draw(RAND).choice((True, False)) else bi.inv

BIDICTS = bidicts()
FROZEN_BIDICTS = bidicts(bi_types=FROZEN_BIDICT_TYPES)
MUTABLE_BIDICTS = bidicts(bi_types=MUTABLE_BIDICT_TYPES)
ORDERED_BIDICTS = bidicts(bi_types=ORDERED_BIDICT_TYPES)

NAMEDBIDICT_VALID_NAME_PAT = re.compile('[A-z][A-z0-9_]*$')
NAMEDBIDICT_NAMES = st.from_regex(NAMEDBIDICT_VALID_NAME_PAT, fullmatch=True)
NAMEDBIDICT_3_NAMES = st.tuples(
    NAMEDBIDICT_NAMES,
    NAMEDBIDICT_NAMES,
    NAMEDBIDICT_NAMES,
)

@st.composite
def _namedbidict_types(draw, names=NAMEDBIDICT_3_NAMES, base_types=BIDICT_TYPES):
    typename, keyname, valname = draw(names)
    assume(keyname != valname)
    base_type = draw(base_types)
    return namedbidict(typename, keyname, valname, base_type=base_type)

NAMEDBIDICT_TYPES = _namedbidict_types()

@st.composite
def _namedbidicts(draw, nb_types=NAMEDBIDICT_TYPES, init_items=LISTS_PAIRS_NODUP):
    nb_cls = draw(nb_types)
    items = draw(init_items)
    nb = nb_cls(items)
    # Return the inverse namedbidict with 50% probability to increase coverage.
    return nb if draw(RAND).choice((True, False)) else nb.inv

NAMEDBIDICTS = _namedbidicts()

_COMPARE_DICT_TYPE = object()
_SAME_AS_BI_ITEMS = object()
_SAME_AS_BI_ITEMS_DIFF_ORDER = object()

@st.composite
def _bidict_and_mapping_from_items(
        draw,
        bi_types=BIDICT_TYPES,
        map_types=MAPPING_TYPES,
        bi_items=LISTS_PAIRS_NODUP,
        map_items=_SAME_AS_BI_ITEMS,
):
    bi_cls = draw(bi_types)
    if map_types is _COMPARE_DICT_TYPE:
        map_cls = OrderedDict if issubclass(bi_cls, OrderedBidictBase) else dict
    else:
        map_cls = draw(map_types)
    bi_items_ = draw(bi_items)
    same_items = map_items in (_SAME_AS_BI_ITEMS, _SAME_AS_BI_ITEMS_DIFF_ORDER)
    if same_items:
        map_items_ = bi_items_[:]
        if map_items is _SAME_AS_BI_ITEMS_DIFF_ORDER:
            draw(RAND).shuffle(map_items_)
            assume(map_items_ != bi_items_)
    else:
        map_items_ = draw(map_items)
    b = bi_cls(bi_items_)
    m = map_cls(map_items_)
    if not same_items:
        assume(ItemsView(m) != ItemsView(b))
    return b, m

BIDICT_AND_MAPPING_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items()
BIDICT_AND_MAPPING_FROM_DIFFERENT_ITEMS = _bidict_and_mapping_from_items(
    map_items=LISTS_PAIRS_NODUP,
)
BIDICT_AND_COMPARE_DICT_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items(
    map_types=_COMPARE_DICT_TYPE,
)
ORDERED_BIDICT_AND_ORDERED_DICT_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items(
    bi_types=ORDERED_BIDICT_TYPES,
    map_types=_COMPARE_DICT_TYPE,
)
ORDERED_BIDICT_AND_ORDERED_MAPPING_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items(
    bi_types=ORDERED_BIDICT_TYPES,
    map_types=ORDERED_MAPPING_TYPES,
)
HASHABLE_BIDICT_AND_MAPPING_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items(
    bi_types=FROZEN_BIDICT_TYPES,
    map_types=HASHABLE_MAPPING_TYPES,
)
ORDERED_BIDICT_AND_ORDERED_MAPPING_FROM_SAME_ITEMS_DIFF_ORDER = _bidict_and_mapping_from_items(
    bi_types=ORDERED_BIDICT_TYPES,
    map_types=ORDERED_MAPPING_TYPES,
    map_items=_SAME_AS_BI_ITEMS_DIFF_ORDER,
)

NO_ARGS = st.just(())
IM_ARG = st.tuples(IMMUTABLES)
LP_ARG = st.tuples(LISTS_PAIRS)
TWO_IM_ARGS = st.tuples(IMMUTABLES, IMMUTABLES)

ARGS_BY_METHOD = st.fixed_dictionaries({
    # mutating
    # 0-arity
    (0, 'clear'): NO_ARGS,
    (0, 'popitem'): NO_ARGS,
    # 1-arity, an immutable atom
    (1, '__delitem__'): IM_ARG,
    (1, 'pop'): IM_ARG,
    (1, 'setdefault'): IM_ARG,
    (1, 'move_to_end'): IM_ARG,
    # 1-arity, a list of pairs
    (1, 'update'): LP_ARG,
    (1, 'forceupdate'): LP_ARG,
    # 2-arity
    (2, 'pop'): TWO_IM_ARGS,
    (2, 'setdefault'): TWO_IM_ARGS,
    (2, '__setitem__'): TWO_IM_ARGS,
    (2, 'put'): TWO_IM_ARGS,
    (2, 'forceput'): TWO_IM_ARGS,
    (2, 'move_to_end'): st.tuples(IMMUTABLES, BOOLEANS),
    # non-mutating
    # 0-arity
    (0, '__copy__'): NO_ARGS,
    (0, '__iter__'): NO_ARGS,
    (0, '__len__'): NO_ARGS,
    (0, 'copy'): NO_ARGS,
    (0, 'keys'): NO_ARGS,
    (0, 'items'): NO_ARGS,
    (0, 'values'): NO_ARGS,
    (0, 'iterkeys'): NO_ARGS,
    (0, 'iteritems'): NO_ARGS,
    (0, 'itervalues'): NO_ARGS,
    (0, 'viewkeys'): NO_ARGS,
    (0, 'viewitems'): NO_ARGS,
    (0, 'viewvalues'): NO_ARGS,
    # 1-arity
    (1, '__contains__'): IM_ARG,
    (1, '__getitem__'): IM_ARG,
    (1, 'get'): IM_ARG,
})
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import os
import sys
import json
import logging
from optparse import OptionParser

# add jedi too sys.path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

import jedi
from jedi.api import NotFoundError

# remove it. WHY?
sys.path.pop(0)

is_funcargs_complete_enabled = True
auto_complete_function_params = 'required'

class JsonFormatter(logging.Formatter):
    def format(self, record):
        output = logging.Formatter.format(self, record)
        data = {
            'logging': record.levelname.lower(),
            'content': output
        }
        record = json.dumps(data)
        return record

def getLogger():
    """ Build file logger """
    log = logging.getLogger('Sublime Jedi Daemon')
    log.setLevel(logging.DEBUG)
    formatter = JsonFormatter('%(asctime)s: %(levelname)-8s: %(message)s')
    hdlr = logging.StreamHandler(sys.stderr)
    hdlr.setFormatter(formatter)
    log.addHandler(hdlr)
    return log

logger = getLogger()

def write(data):
    """  Write data to STDOUT """
    if not isinstance(data, str):
        data = json.dumps(data)

    sys.stdout.write(data)

    if not data.endswith('\n'):
        sys.stdout.write('\n')

    try:
        sys.stdout.flush()
    except IOError:
        sys.exit()

def format_completion(complete):
    """ Returns a tuple of the string that would be visible in
    the completion dialogue and the completion word

    :type complete: jedi.api_classes.Completion
    :rtype: (str, str)
    """
    display, insert = complete.name + '\t' + complete.type, complete.name
    return display, insert

def get_function_parameters(callDef):
    """  Return list function parameters, prepared for sublime completion.
    Tuple contains parameter name and default value

    Parameters list excludes: self, *args and **kwargs parameters

    :type callDef: jedi.api_classes.CallDef
    :rtype: list of (str, str or None)
    """
    if not callDef:
        return []

    params = []
    for param in callDef.params:
        # logger.info("%s %s" % (param.name, param.description))
        cleaned_param = param.description.rstrip(',')
        if '*' in cleaned_param or cleaned_param in ['self', '...']:
            continue
        params.append([s.strip() for s in cleaned_param.split('=')])
    return params

class JediFacade:
    """
    Facade to call Jedi API

     Action       | Method
    ===============================
     autocomplete | get_autocomplete
    -------------------------------
     goto         | get_goto
    -------------------------------
     usages       | get_usages
    -------------------------------
     funcargs     | get_funcargs
    --------------------------------

    """
    def __init__(self, source, line, offset, filename='', encoding='utf-8'):
        filename = filename or None
        self.script = jedi.Script(
            source, int(line), int(offset), filename, encoding
        )

    def get(self, action):
        """ Action dispatcher """
        try:
            return getattr(self, 'get_' + action)()
        except:
            logger.exception('`JediFacade.get_{0}` failed'.format(action))

    def get_goto(self):
        """ Jedi "Go To Definition" """
        return self._goto()

    def get_usages(self):
        """ Jedi "Find Usage" """
        return self._usages()

    def get_funcargs(self):
        """ complete callable object parameters with Jedi """
        return self._complete_call_assigments()

    def get_autocomplete(self):
        """ Jedi "completion" """
        data = self._parameters_for_completion() or []
        data.extend(self._completion() or [])
        return data

    def get_docstring(self):
        return self._docstring()

    def get_signature(self):
        return self._docstring(signature=1)

    def _docstring(self, signature=0):
        """ Jedi show doctring or signature

        :rtype: str
        """
        defs = self.script.goto_definitions()
        assert isinstance(defs, list)

        if len(defs) > 0:
            if signature:
                calltip_signature = defs[0].docstring().split('\n\n')[0]
                return calltip_signature.replace('\n', ' ').replace(' = ', '=')
            else:
                return defs[0].docstring()

    def _parameters_for_completion(self):
        """ Get function / class' constructor parameters completions list

        :rtype: list of str
        """
        completions = []
        try:
            in_call = self.script.call_signatures()[0]
        except IndexError:
            in_call = None

        parameters = get_function_parameters(in_call)

        for parameter in parameters:
            try:
                name, value = parameter
            except ValueError:
                name = parameter[0]
                value = None

            if value is None:
                completions.append((name, '${1:%s}' % name))
            else:
                completions.append((name + '\t' + value,
                                   '%s=${1:%s}' % (name, value)))
        return completions

    def _completion(self):
        """ regular completions

        :rtype: list of (str, str)
        """
        completions = self.script.completions()
        return [format_completion(complete) for complete in completions]

    def _goto(self):
        """ Jedi "go to Definitions" functionality

        :rtype: list of (str, int, int) or None
        """
        try:
            definitions = self.script.goto_assignments()
            if all(d.type == 'import' for d in definitions):
                # check if it an import string and if it is get definition
                definitions = self.script.goto_definitions()
        except NotFoundError:
            return
        else:
            return [(i.module_path, i.line, i.column + 1)
                    for i in definitions if not i.in_builtin_module()]

    def _usages(self):
        """ Jedi "find usages" functionality

        :rtype: list of (str, int, int)
        """
        usages = self.script.usages()
        return [(i.module_path, i.line, i.column + 1)
                for i in usages if not i.in_builtin_module()]

    def _complete_call_assigments(self):
        """ Get function or class parameters and build Sublime Snippet string
        for completion

        :rtype: str
        """
        completions = []
        complete_all = auto_complete_function_params == 'all'

        try:
            call_definition = self.script.call_signatures()[0]
        except IndexError:
            call_definition = None

        parameters = get_function_parameters(call_definition)

        for index, parameter in enumerate(parameters):
            try:
                name, value = parameter
            except ValueError:
                name = parameter[0]
                value = None

            if value is None:
                completions.append('${%d:%s}' % (index + 1, name))
            elif complete_all:
                completions.append('%s=${%d:%s}' % (name, index + 1, value))

        return ", ".join(completions)

def process_line(line):
    data = json.loads(line.strip())
    action_type = data['type']

    script = JediFacade(
        source=data['source'],
        line=data['line'],
        offset=data['offset'],
        filename=data.get('filename', '')
    )

    out_data = {
        'uuid': data.get('uuid'),
        'type': action_type,
        action_type: script.get(action_type)
    }

    write(out_data)

if __name__ == '__main__':
    parser = OptionParser()
    parser.add_option(
        "-p", "--project",
        dest="project_name",
        default='',
        help="project name to store jedi's cache"
    )
    parser.add_option(
        "-e", "--extra_folder",
        dest="extra_folders",
        default=[],
        action="append",
        help="extra folders to add to sys.path"
    )
    parser.add_option(
        "-f", "--complete_function_params",
        dest="function_params",
        default='all',
        help='function parameters completion type: "all", "required", or ""'
    )

    options, args = parser.parse_args()

    is_funcargs_complete_enabled = bool(options.function_params)
    auto_complete_function_params = options.function_params

    logger.info(
        'Daemon started. '
        'extra folders - %s, '
        'complete_function_params - %s',
        options.extra_folders,
        options.function_params,
    )

    # append extra paths to sys.path
    for extra_folder in options.extra_folders:
        if extra_folder not in sys.path:
            sys.path.insert(0, extra_folder)

    # call the Jedi
    for line in iter(sys.stdin.readline, ''):
        if line:
            try:
                process_line(line)
            except Exception:
                logger.exception('failed to process line')
<commit_msg>fix issue #179. fix broken call signature processing<commit_after># -*- coding: utf-8 -*-
import os
import sys
import json
import logging
from optparse import OptionParser

# add jedi too sys.path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

import jedi
from jedi.api import NotFoundError

# remove it. WHY?
sys.path.pop(0)

is_funcargs_complete_enabled = True
auto_complete_function_params = 'required'

class JsonFormatter(logging.Formatter):
    def format(self, record):
        output = logging.Formatter.format(self, record)
        data = {
            'logging': record.levelname.lower(),
            'content': output
        }
        record = json.dumps(data)
        return record

def getLogger():
    """ Build file logger """
    log = logging.getLogger('Sublime Jedi Daemon')
    log.setLevel(logging.DEBUG)
    formatter = JsonFormatter('%(asctime)s: %(levelname)-8s: %(message)s')
    hdlr = logging.StreamHandler(sys.stderr)
    hdlr.setFormatter(formatter)
    log.addHandler(hdlr)
    return log

logger = getLogger()

def write(data):
    """  Write data to STDOUT """
    if not isinstance(data, str):
        data = json.dumps(data)

    sys.stdout.write(data)

    if not data.endswith('\n'):
        sys.stdout.write('\n')

    try:
        sys.stdout.flush()
    except IOError:
        sys.exit()

def format_completion(complete):
    """ Returns a tuple of the string that would be visible in
    the completion dialogue and the completion word

    :type complete: jedi.api_classes.Completion
    :rtype: (str, str)
    """
    display, insert = complete.name + '\t' + complete.type, complete.name
    return display, insert

def get_function_parameters(callDef):
    """  Return list function parameters, prepared for sublime completion.
    Tuple contains parameter name and default value

    Parameters list excludes: self, *args and **kwargs parameters

    :type callDef: jedi.api_classes.CallDef
    :rtype: list of (str, str or None)
    """
    if not callDef:
        return []

    params = []
    for param in callDef.params:
        # logger.info("%s %s" % (param.name, param.description))

        # when you writing a callable object
        # jedi tring to complete incompleted object
        # and returns "empty" calldefinition
        # in this case we have to skip it
        if not param.name:
            continue

        cleaned_param = param.description.rstrip(',')
        if '*' in cleaned_param or cleaned_param in ['self', '...']:
            continue
        params.append([s.strip() for s in cleaned_param.split('=')])
    return params

class JediFacade:
    """
    Facade to call Jedi API

     Action       | Method
    ===============================
     autocomplete | get_autocomplete
    -------------------------------
     goto         | get_goto
    -------------------------------
     usages       | get_usages
    -------------------------------
     funcargs     | get_funcargs
    --------------------------------

    """
    def __init__(self, source, line, offset, filename='', encoding='utf-8'):
        filename = filename or None
        self.script = jedi.Script(
            source, int(line), int(offset), filename, encoding
        )

    def get(self, action):
        """ Action dispatcher """
        try:
            return getattr(self, 'get_' + action)()
        except:
            logger.exception('`JediFacade.get_{0}` failed'.format(action))

    def get_goto(self):
        """ Jedi "Go To Definition" """
        return self._goto()

    def get_usages(self):
        """ Jedi "Find Usage" """
        return self._usages()

    def get_funcargs(self):
        """ complete callable object parameters with Jedi """
        return self._complete_call_assigments()

    def get_autocomplete(self):
        """ Jedi "completion" """
        data = []

        try:
            data.extend(self._parameters_for_completion())
        except:
            logger.info("params completion failed")

        try:
            data.extend(self._completion() or [])
        except:
            logger.info("general completion failed")

        return data

    def get_docstring(self):
        return self._docstring()

    def get_signature(self):
        return self._docstring(signature=1)

    def _docstring(self, signature=0):
        """ Jedi show doctring or signature

        :rtype: str
        """
        defs = self.script.goto_definitions()
        assert isinstance(defs, list)

        if len(defs) > 0:
            if signature:
                calltip_signature = defs[0].docstring().split('\n\n')[0]
                return calltip_signature.replace('\n', ' ').replace(' = ', '=')
            else:
                return defs[0].docstring()

    def _parameters_for_completion(self):
        """ Get function / class' constructor parameters completions list

        :rtype: list of str
        """
        completions = []
        try:
            in_call = self.script.call_signatures()[0]
        except IndexError:
            in_call = None

        parameters = get_function_parameters(in_call)

        for parameter in parameters:
            try:
                name, value = parameter
            except ValueError:
                name = parameter[0]
                value = None

            if value is None:
                completions.append((name, '${1:%s}' % name))
            else:
                completions.append((name + '\t' + value,
                                   '%s=${1:%s}' % (name, value)))
        return completions

    def _completion(self):
        """ regular completions

        :rtype: list of (str, str)
        """
        completions = self.script.completions()
        return [format_completion(complete) for complete in completions]

    def _goto(self):
        """ Jedi "go to Definitions" functionality

        :rtype: list of (str, int, int) or None
        """
        try:
            definitions = self.script.goto_assignments()
            if all(d.type == 'import' for d in definitions):
                # check if it an import string and if it is get definition
                definitions = self.script.goto_definitions()
        except NotFoundError:
            return
        else:
            return [(i.module_path, i.line, i.column + 1)
                    for i in definitions if not i.in_builtin_module()]

    def _usages(self):
        """ Jedi "find usages" functionality

        :rtype: list of (str, int, int)
        """
        usages = self.script.usages()
        return [(i.module_path, i.line, i.column + 1)
                for i in usages if not i.in_builtin_module()]

    def _complete_call_assigments(self):
        """ Get function or class parameters and build Sublime Snippet string
        for completion

        :rtype: str
        """
        completions = []
        complete_all = auto_complete_function_params == 'all'

        try:
            call_definition = self.script.call_signatures()[0]
        except IndexError:
            call_definition = None

        parameters = get_function_parameters(call_definition)

        for index, parameter in enumerate(parameters):
            try:
                name, value = parameter
            except ValueError:
                name = parameter[0]
                value = None

            if value is None:
                completions.append('${%d:%s}' % (index + 1, name))
            elif complete_all:
                completions.append('%s=${%d:%s}' % (name, index + 1, value))

        return ", ".join(completions)

def process_line(line):
    data = json.loads(line.strip())
    action_type = data['type']

    script = JediFacade(
        source=data['source'],
        line=data['line'],
        offset=data['offset'],
        filename=data.get('filename', '')
    )

    out_data = {
        'uuid': data.get('uuid'),
        'type': action_type,
        action_type: script.get(action_type)
    }

    write(out_data)

if __name__ == '__main__':
    parser = OptionParser()
    parser.add_option(
        "-p", "--project",
        dest="project_name",
        default='',
        help="project name to store jedi's cache"
    )
    parser.add_option(
        "-e", "--extra_folder",
        dest="extra_folders",
        default=[],
        action="append",
        help="extra folders to add to sys.path"
    )
    parser.add_option(
        "-f", "--complete_function_params",
        dest="function_params",
        default='all',
        help='function parameters completion type: "all", "required", or ""'
    )

    options, args = parser.parse_args()

    is_funcargs_complete_enabled = bool(options.function_params)
    auto_complete_function_params = options.function_params

    logger.info(
        'Daemon started. '
        'extra folders - %s, '
        'complete_function_params - %s',
        options.extra_folders,
        options.function_params,
    )

    # append extra paths to sys.path
    for extra_folder in options.extra_folders:
        if extra_folder not in sys.path:
            sys.path.insert(0, extra_folder)

    # call the Jedi
    for line in iter(sys.stdin.readline, ''):
        if line:
            try:
                process_line(line)
            except Exception:
                logger.exception('failed to process line')
<|endoftext|>