<commit_before># -*- coding: utf-8 -*-:
"""
This module contains the basic API for splinter drivers and elemnts.
"""

from splinter.element_list import ElementList
from splinter.meta import InheritedDocs
from splinter.request_handler.request_handler import RequestHandler

class DriverAPI(RequestHandler):
    """
    Basic driver API class.
    """
    __metaclass__ = InheritedDocs
    driver_name = None

    @property
    def title(self):
        """
        Title of current page.
        """
        raise NotImplementedError

    @property
    def html(self):
        """
        Source of current page.
        """
        raise NotImplementedError

    @property
    def url(self):
        """
        URL of current page.
        """
        raise NotImplementedError

    def visit(self, url):
        """
        Visits a given URL.

        The ``url`` parameter is a string.
        """
        raise NotImplementedError

    def back(self):
        """
        Back to the last URL in the browsing history.

        If there is no URL to back, this method does nothing.
        """
        raise NotImplementedError

    def forward(self):
        """
        Forward to the next URL in the browsing history.

        If there is no URL to forward, this method does nothing.
        """
        raise NotImplementedError

    def reload(self):
        """
        Revisits the current URL
        """
        raise NotImplementedError

    def get_alert(self):
        """
        Changes the context for working with alerts and prompts.

        For more details, check the :doc:`docs about iframes, alerts and prompts </iframes-and-alerts>`
        """
        raise NotImplementedError

    def get_iframe(self, id):
        """
        Changes the context for working with iframes.

        For more details, check the :doc:`docs about iframes, alerts and prompts </iframes-and-alerts>`
        """
        raise NotImplementedError("%s does not support frames" % self.driver_name)

    def execute_script(self, script):
        """
        Executes a given JavaScript in the browser.

        e.g.: ::
            >>> browser.execute_script('document.getElementById("body").innerHTML = "
Hello world!
"')
        """
        raise NotImplementedError

    def evaluate_script(self, script):
        """
        Similar to :meth:`execute_script <DriverAPI.execute_script>` method.

        Executes javascript in the browser and returns the value of the expression.

        e.g.: ::
            >>> assert 4 == browser.evaluate_script('2 + 2')
        """
        raise NotImplementedError

    def find_by_css(self, css_selector):
        """
        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`, using a CSS selector to query the
        current page content.
        """
        raise NotImplementedError

    def find_by_xpath(self, xpath):
        """
        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`, using a xpath selector to query the
        current page content.
        """
        raise NotImplementedError

    def find_by_name(self, name):
        """
        Finds elements in current page by them name.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`.
        """
        raise NotImplementedError

    def find_by_id(self, id):
        """
        Finds an element in current page by its id.

        Even when only one element is find, this method returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_by_value(self, value):
        """
        Finds elements in current page by them value.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_by_tag(self, tag):
        """
        Find all elements of a given tag in current page.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_link_by_href(self, href):
        """
        Find all elements of a given tag in current page.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_link_by_partial_href(self, partial_href):
        """
        Find links by looking for a partial ``str`` in them href attribute.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_link_by_text(self, text):
        """
        Find links querying for they text.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_link_by_partial_text(self, partial_text):
        """
        Find links by looking for a partial ``str`` in them text.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_option_by_value(self, value):
        """
        Finds ``<option>`` elements by them value.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_option_by_text(self, text):
        """
        Finds ``<option>`` elements by them text.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def is_text_present(self, text, wait_time=None):
        """
        Searchs for ``text`` in the browser and wait the seconds specified in ``wait_time``.

        Returns True if finds a match for the ``text`` and False if not.
        """
        raise NotImplementedError

    def type(self, name, value, slowly=False):
        """
        Types the ``value`` in the field identified by ``name``.

        It's useful to test javascript events like keyPress, keyUp, keyDown, etc.
        """
        raise NotImplementedError

    def fill(self, name, value):
        """
        Fill the field identified by ``name`` with the content specified by ``value``.
        """
        raise NotImplementedError

    def fill_form(self, field_values):
        """
        Fill the fields identified by ``name`` with the content specified by ``value`` in a dict.
        """
        raise NotImplementedError

    def choose(self, name, value):
        """
        Chooses a value in a radio buttons group.

        Suppose you have the two radio buttons in a page, with the name ``gender`` and values 'F' and 'M'.
        If you use the ``choose`` method the following way:

            >>> browser.choose('gender', 'F')

        Then you're choosing the female gender.
        """
        raise NotImplementedError

    def check(self, name):
        """
        Checks a checkbox by its name.

        Example:

            >>> browser.check("agree-with-terms")

        If you call ``browser.check`` n times, the checkbox keeps checked, it never get unchecked.

        To unckech a checkbox, take a look in the :meth:`uncheck <DriverAPI.uncheck>` method.
        """
        raise NotImplementedError

    def uncheck(self, name):
        """
        Unchecks a checkbox by its name.

        Example:

            >>> browser.uncheck("send-me-emails")

        If you call ``brower.uncheck`` n times, the checkbox keeps unchecked, it never get checked.

        To check a checkbox, take a look in the :meth:`check <DriverAPI.check>` method.
        """
        raise NotImplementedError

    def select(self, name, value):
        """
        Selects an ``<option>`` element in an ``<select>`` element using the ``name`` of the ``<select>`` and
        the ``value`` of the ``<option>``.

        Example:

            >>> browser.select("state", "NY")
        """
        raise NotImplementedError

    def click_link_by_href(self, href):
        """
        Clicks in a link by its ``href`` attribute.
        """
        return self.find_link_by_href(href).first.click()

    def click_link_by_partial_href(self, partial_href):
        """
        Clicks in a link by looking for partial content of ``href`` attribute.
        """
        return self.find_link_by_partial_href(partial_href).first.click()

    def click_link_by_text(self, text):
        """
        Clicks in a link by its ``text``.
        """
        return self.find_link_by_text(text).first.click()

    def click_link_by_partial_text(self, partial_text):
        """
        Clicks in a link by partial content of its text.
        """
        return self.find_link_by_partial_text(partial_text).first.click()

    def within(self, context):
        return ElementList([], context, self)

    def quit(self):
        """
        Quits the browser, closing its windows (if it has one).

        After quit the browser, you can't use it anymore.
        """
        raise NotImplementedError

    def is_element_present_by_css(self, css_selector, wait_time=None):
        """
        Verify if the element is present in the current page by css, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_css(self, css_selector, wait_time=None):
        """
        Verify if the element is not present in the current page by css, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    def is_element_present_by_xpath(self, xpath, wait_time=None):
        """
        Verify if the element is present in the current page by xpath, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_xpath(self, xpath, wait_time=None):
        """
        Verify if the element is not present in the current page by xpath, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    def is_element_present_by_tag(self, tag, wait_time=None):
        """
        Verify if the element is present in the current page by tag, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_tag(self, tag, wait_time=None):
        """
        Verify if the element is not present in the current page by tag, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    def is_element_present_by_name(self, name, wait_time=None):
        """
        Verify if the element is present in the current page by name, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_name(self, name, wait_time=None):
        """
        Verify if the element is not present in the current page by name, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    def is_element_present_by_value(self, value, wait_time=None):
        """
        Verify if the element is present in the current page by value, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_value(self, value, wait_time=None):
        """
        Verify if the element is not present in the current page by value, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    def is_element_present_by_id(self, id, wait_time=None):
        """
        Verify if the element is present in the current page by id, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_id(self, id, wait_time=None):
        """
        Verify if the element is present in the current page by id, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    @property
    def cookies(self):
        """
        A :class:`CookieManager <splinter.cookie_manager.CookieManagerAPI>` instance.

        For more details, check the :doc:`cookies manipulation section </cookies>`.
        """
        raise NotImplementedError

class ElementAPI(object):
    """
    Basic element API class.

    Any element in the page can be represented as an instance of ``ElementAPI``.

    Once you have an instance, you can easily access its attributes like a ``dict``:

        >>> element = browser.find_by_id("link-logo").first
        >>> assert element['href'] == 'http://splinter.cobrateam.info'

    You can also interact with the instance using the methods and properties listed below.
    """
    __metaclass__ = InheritedDocs

    def _get_value(self):
        raise NotImplementedError

    def _set_value(self, value):
        raise NotImplementedError

    #: Value of the element, usually a form element
    value = property(_get_value, _set_value)

    def click(self):
        """
        Clicks in the element.
        """
        raise NotImplementedError

    def check(self):
        """
        Checks the element, if it's "checkable" (e.g.: a checkbox).

        If the element is already checked, this method does nothing. For unchecking
        elements, take a loot in the :meth:`uncheck <ElementAPI.uncheck>` method.
        """
        raise NotImplementedError

    def uncheck(self):
        """
        Unchecks the element, if it's "checkable" (e.g.: a checkbox).

        If the element is already unchecked, this method does nothing. For checking
        elements, take a loot in the :meth:`check <ElementAPI.check>` method.
        """
        raise NotImplementedError

    @property
    def checked(self):
        """
        Boolean property that says if the element is checked or not.

        Example:

            >>> element.check()
            >>> assert element.checked
            >>> element.uncheck()
            >>> assert not element.checked
        """
        raise NotImplementedError

    @property
    def visible(self):
        """
        Boolean property that says if the element is visible or hidden in the current page.
        """
        raise NotImplementedError

    def mouse_over(self):
        """
        Puts the mouse over the element.
        """
        raise NotImplementedError

    def mouse_out(self):
        """
        Moves the mouse away from the element.
        """
        raise NotImplementedError

    def fill(self, value):
        """
        Fill the field with the content specified by ``value``.
        """
        raise NotImplementedError

    def type(self, value, slowly=False):
        """
        Types the ``value`` in the field.

        It's useful to test javascript events like keyPress, keyUp, keyDown, etc.
        """
        raise NotImplementedError

    def __getitem__(self, attribute):
        raise NotImplementedError
<commit_msg>Amended: change doc, get_iframe id to name<commit_after># -*- coding: utf-8 -*-:
"""
This module contains the basic API for splinter drivers and elemnts.
"""

from splinter.element_list import ElementList
from splinter.meta import InheritedDocs
from splinter.request_handler.request_handler import RequestHandler

class DriverAPI(RequestHandler):
    """
    Basic driver API class.
    """
    __metaclass__ = InheritedDocs
    driver_name = None

    @property
    def title(self):
        """
        Title of current page.
        """
        raise NotImplementedError

    @property
    def html(self):
        """
        Source of current page.
        """
        raise NotImplementedError

    @property
    def url(self):
        """
        URL of current page.
        """
        raise NotImplementedError

    def visit(self, url):
        """
        Visits a given URL.

        The ``url`` parameter is a string.
        """
        raise NotImplementedError

    def back(self):
        """
        Back to the last URL in the browsing history.

        If there is no URL to back, this method does nothing.
        """
        raise NotImplementedError

    def forward(self):
        """
        Forward to the next URL in the browsing history.

        If there is no URL to forward, this method does nothing.
        """
        raise NotImplementedError

    def reload(self):
        """
        Revisits the current URL
        """
        raise NotImplementedError

    def get_alert(self):
        """
        Changes the context for working with alerts and prompts.

        For more details, check the :doc:`docs about iframes, alerts and prompts </iframes-and-alerts>`
        """
        raise NotImplementedError

    def get_iframe(self, name):
        """
        Changes the context for working with iframes.

        For more details, check the :doc:`docs about iframes, alerts and prompts </iframes-and-alerts>`
        """
        raise NotImplementedError("%s does not support frames" % self.driver_name)

    def execute_script(self, script):
        """
        Executes a given JavaScript in the browser.

        e.g.: ::
            >>> browser.execute_script('document.getElementById("body").innerHTML = "
Hello world!
"')
        """
        raise NotImplementedError

    def evaluate_script(self, script):
        """
        Similar to :meth:`execute_script <DriverAPI.execute_script>` method.

        Executes javascript in the browser and returns the value of the expression.

        e.g.: ::
            >>> assert 4 == browser.evaluate_script('2 + 2')
        """
        raise NotImplementedError

    def find_by_css(self, css_selector):
        """
        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`, using a CSS selector to query the
        current page content.
        """
        raise NotImplementedError

    def find_by_xpath(self, xpath):
        """
        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`, using a xpath selector to query the
        current page content.
        """
        raise NotImplementedError

    def find_by_name(self, name):
        """
        Finds elements in current page by them name.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`.
        """
        raise NotImplementedError

    def find_by_id(self, id):
        """
        Finds an element in current page by its id.

        Even when only one element is find, this method returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_by_value(self, value):
        """
        Finds elements in current page by them value.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_by_tag(self, tag):
        """
        Find all elements of a given tag in current page.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_link_by_href(self, href):
        """
        Find all elements of a given tag in current page.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_link_by_partial_href(self, partial_href):
        """
        Find links by looking for a partial ``str`` in them href attribute.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_link_by_text(self, text):
        """
        Find links querying for they text.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_link_by_partial_text(self, partial_text):
        """
        Find links by looking for a partial ``str`` in them text.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_option_by_value(self, value):
        """
        Finds ``<option>`` elements by them value.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def find_option_by_text(self, text):
        """
        Finds ``<option>`` elements by them text.

        Returns an instance of :class:`ElementList <splinter.element_list.ElementList>`
        """
        raise NotImplementedError

    def is_text_present(self, text, wait_time=None):
        """
        Searchs for ``text`` in the browser and wait the seconds specified in ``wait_time``.

        Returns True if finds a match for the ``text`` and False if not.
        """
        raise NotImplementedError

    def type(self, name, value, slowly=False):
        """
        Types the ``value`` in the field identified by ``name``.

        It's useful to test javascript events like keyPress, keyUp, keyDown, etc.
        """
        raise NotImplementedError

    def fill(self, name, value):
        """
        Fill the field identified by ``name`` with the content specified by ``value``.
        """
        raise NotImplementedError

    def fill_form(self, field_values):
        """
        Fill the fields identified by ``name`` with the content specified by ``value`` in a dict.
        """
        raise NotImplementedError

    def choose(self, name, value):
        """
        Chooses a value in a radio buttons group.

        Suppose you have the two radio buttons in a page, with the name ``gender`` and values 'F' and 'M'.
        If you use the ``choose`` method the following way:

            >>> browser.choose('gender', 'F')

        Then you're choosing the female gender.
        """
        raise NotImplementedError

    def check(self, name):
        """
        Checks a checkbox by its name.

        Example:

            >>> browser.check("agree-with-terms")

        If you call ``browser.check`` n times, the checkbox keeps checked, it never get unchecked.

        To unckech a checkbox, take a look in the :meth:`uncheck <DriverAPI.uncheck>` method.
        """
        raise NotImplementedError

    def uncheck(self, name):
        """
        Unchecks a checkbox by its name.

        Example:

            >>> browser.uncheck("send-me-emails")

        If you call ``brower.uncheck`` n times, the checkbox keeps unchecked, it never get checked.

        To check a checkbox, take a look in the :meth:`check <DriverAPI.check>` method.
        """
        raise NotImplementedError

    def select(self, name, value):
        """
        Selects an ``<option>`` element in an ``<select>`` element using the ``name`` of the ``<select>`` and
        the ``value`` of the ``<option>``.

        Example:

            >>> browser.select("state", "NY")
        """
        raise NotImplementedError

    def click_link_by_href(self, href):
        """
        Clicks in a link by its ``href`` attribute.
        """
        return self.find_link_by_href(href).first.click()

    def click_link_by_partial_href(self, partial_href):
        """
        Clicks in a link by looking for partial content of ``href`` attribute.
        """
        return self.find_link_by_partial_href(partial_href).first.click()

    def click_link_by_text(self, text):
        """
        Clicks in a link by its ``text``.
        """
        return self.find_link_by_text(text).first.click()

    def click_link_by_partial_text(self, partial_text):
        """
        Clicks in a link by partial content of its text.
        """
        return self.find_link_by_partial_text(partial_text).first.click()

    def within(self, context):
        return ElementList([], context, self)

    def quit(self):
        """
        Quits the browser, closing its windows (if it has one).

        After quit the browser, you can't use it anymore.
        """
        raise NotImplementedError

    def is_element_present_by_css(self, css_selector, wait_time=None):
        """
        Verify if the element is present in the current page by css, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_css(self, css_selector, wait_time=None):
        """
        Verify if the element is not present in the current page by css, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    def is_element_present_by_xpath(self, xpath, wait_time=None):
        """
        Verify if the element is present in the current page by xpath, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_xpath(self, xpath, wait_time=None):
        """
        Verify if the element is not present in the current page by xpath, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    def is_element_present_by_tag(self, tag, wait_time=None):
        """
        Verify if the element is present in the current page by tag, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_tag(self, tag, wait_time=None):
        """
        Verify if the element is not present in the current page by tag, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    def is_element_present_by_name(self, name, wait_time=None):
        """
        Verify if the element is present in the current page by name, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_name(self, name, wait_time=None):
        """
        Verify if the element is not present in the current page by name, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    def is_element_present_by_value(self, value, wait_time=None):
        """
        Verify if the element is present in the current page by value, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_value(self, value, wait_time=None):
        """
        Verify if the element is not present in the current page by value, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    def is_element_present_by_id(self, id, wait_time=None):
        """
        Verify if the element is present in the current page by id, and wait the specified time in ``wait_time``.

        Returns True if the element is present and False if is not present.
        """
        raise NotImplementedError

    def is_element_not_present_by_id(self, id, wait_time=None):
        """
        Verify if the element is present in the current page by id, and wait the specified time in ``wait_time``.

        Returns True if the element is not present and False if is present.
        """
        raise NotImplementedError

    @property
    def cookies(self):
        """
        A :class:`CookieManager <splinter.cookie_manager.CookieManagerAPI>` instance.

        For more details, check the :doc:`cookies manipulation section </cookies>`.
        """
        raise NotImplementedError

class ElementAPI(object):
    """
    Basic element API class.

    Any element in the page can be represented as an instance of ``ElementAPI``.

    Once you have an instance, you can easily access its attributes like a ``dict``:

        >>> element = browser.find_by_id("link-logo").first
        >>> assert element['href'] == 'http://splinter.cobrateam.info'

    You can also interact with the instance using the methods and properties listed below.
    """
    __metaclass__ = InheritedDocs

    def _get_value(self):
        raise NotImplementedError

    def _set_value(self, value):
        raise NotImplementedError

    #: Value of the element, usually a form element
    value = property(_get_value, _set_value)

    def click(self):
        """
        Clicks in the element.
        """
        raise NotImplementedError

    def check(self):
        """
        Checks the element, if it's "checkable" (e.g.: a checkbox).

        If the element is already checked, this method does nothing. For unchecking
        elements, take a loot in the :meth:`uncheck <ElementAPI.uncheck>` method.
        """
        raise NotImplementedError

    def uncheck(self):
        """
        Unchecks the element, if it's "checkable" (e.g.: a checkbox).

        If the element is already unchecked, this method does nothing. For checking
        elements, take a loot in the :meth:`check <ElementAPI.check>` method.
        """
        raise NotImplementedError

    @property
    def checked(self):
        """
        Boolean property that says if the element is checked or not.

        Example:

            >>> element.check()
            >>> assert element.checked
            >>> element.uncheck()
            >>> assert not element.checked
        """
        raise NotImplementedError

    @property
    def visible(self):
        """
        Boolean property that says if the element is visible or hidden in the current page.
        """
        raise NotImplementedError

    def mouse_over(self):
        """
        Puts the mouse over the element.
        """
        raise NotImplementedError

    def mouse_out(self):
        """
        Moves the mouse away from the element.
        """
        raise NotImplementedError

    def fill(self, value):
        """
        Fill the field with the content specified by ``value``.
        """
        raise NotImplementedError

    def type(self, value, slowly=False):
        """
        Types the ``value`` in the field.

        It's useful to test javascript events like keyPress, keyUp, keyDown, etc.
        """
        raise NotImplementedError

    def __getitem__(self, attribute):
        raise NotImplementedError
<|endoftext|>


<commit_before>from django.db import models
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import fields
from django_extensions.db.fields import (ModificationDateTimeField,
                                         CreationDateTimeField)
from django.utils.text import Truncator
from django.utils.translation import ugettext_lazy as _

from polymorphic.models import PolymorphicModel

from .managers import ReactionManager, WallpostManager

WALLPOST_TEXT_MAX_LENGTH = getattr(settings, 'WALLPOST_TEXT_MAX_LENGTH', 300)
WALLPOST_REACTION_MAX_LENGTH = getattr(settings, 'WALLPOST_REACTION_MAX_LENGTH',
                                       300)

GROUP_PERMS = {
    'Staff': {
        'perms': (
            'add_reaction', 'change_reaction', 'delete_reaction',
            'add_wallpost', 'change_wallpost', 'delete_wallpost',
            'add_mediawallpost', 'change_mediawallpost', 'delete_mediawallpost',
            'add_textwallpost', 'change_textwallpost', 'delete_textwallpost',
            'add_systemwallpost', 'change_systemwallpost',
            'delete_systemwallpost',
            'add_mediawallpostphoto', 'change_mediawallpostphoto',
            'delete_mediawallpostphoto',
        )
    }
}

class Wallpost(PolymorphicModel):
    """
    The Wallpost base class. This class will never be used directly because the
    content of a Wallpost is always defined
    in the child classes.

    Implementation Note: Normally this would be an abstract class but it's not
    possible to make this an abstract class
    and have the polymorphic behaviour of sorting on the common fields.
    """

    @property
    def wallpost_type(self):
        return 'unknown'

    # The user who wrote the wall post. This can be empty to support wallposts
    # without users (e.g. anonymous
    # TextWallposts, system Wallposts for donations etc.)
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               verbose_name=_('author'),
                               related_name="%(class)s_wallpost", blank=True,
                               null=True)
    editor = models.ForeignKey(
        settings.AUTH_USER_MODEL, verbose_name=_('editor'), blank=True,
        null=True, help_text=_("The last user to edit this wallpost."))

    # The metadata for the wall post.
    created = CreationDateTimeField(_('created'))
    updated = ModificationDateTimeField(_('updated'))
    deleted = models.DateTimeField(_('deleted'), blank=True, null=True)
    ip_address = models.GenericIPAddressField(_('IP address'), blank=True, null=True,
                                       default=None)

    # Generic foreign key so we can connect it to any object.
    content_type = models.ForeignKey(
        ContentType, verbose_name=_('content type'),
        related_name="content_type_set_for_%(class)s")
    object_id = models.PositiveIntegerField(_('object ID'))
    content_object = fields.GenericForeignKey('content_type', 'object_id')

    share_with_facebook = models.BooleanField(default=False)
    share_with_twitter = models.BooleanField(default=False)
    share_with_linkedin = models.BooleanField(default=False)
    email_followers = models.BooleanField(default=True)

    donation = models.ForeignKey('donations.Donation',
                                 verbose_name=_("Donation"),
                                 related_name='donation',
                                 null=True, blank=True)

    # Manager
    objects = WallpostManager()
    objects_with_deleted = models.Manager()

    class Analytics:
        type = 'wallpost'
        tags = {}
        fields = {
            'id': 'id',
            'user_id': 'author.id'
        }

        def skip(self, obj, created):
            return True if obj.wallpost_type == 'system' else False

    class Meta:
        ordering = ('created',)

    def __unicode__(self):
        return str(self.id)

class MediaWallpost(Wallpost):
    # The content of the wall post.

    @property
    def wallpost_type(self):
        return 'media'

    title = models.CharField(max_length=60)
    text = models.TextField(max_length=WALLPOST_REACTION_MAX_LENGTH, blank=True,
                            default='')
    video_url = models.URLField(max_length=100, blank=True, default='')

    def __unicode__(self):
        return Truncator(self.text).words(10)

        # FIXME: See how we can re-enable this
        # def save(self, *args, **kwargs):
        #     super(MediaWallpost, self).save(*args, **kwargs)
        #
        #     # Mark the photos as deleted when the MediaWallpost is deleted.
        #     if self.deleted:
        #         for photo in self.photos.all():
        #             if not photo.deleted:
        #                 photo.deleted = self.deleted
        #                 photo.save()

class MediaWallpostPhoto(models.Model):
    mediawallpost = models.ForeignKey(MediaWallpost, related_name='photos',
                                      null=True, blank=True)
    photo = models.ImageField(upload_to='mediawallpostphotos')
    deleted = models.DateTimeField(_('deleted'), blank=True, null=True)
    ip_address = models.GenericIPAddressField(_('IP address'), blank=True, null=True,
                                       default=None)
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               verbose_name=_('author'),
                               related_name="%(class)s_wallpost_photo",
                               blank=True, null=True)
    editor = models.ForeignKey(settings.AUTH_USER_MODEL,
                               verbose_name=_('editor'), blank=True, null=True,
                               help_text=_(
                                   "The last user to edit this wallpost photo."))

class TextWallpost(Wallpost):
    # The content of the wall post.
    @property
    def wallpost_type(self):
        return 'text'

    text = models.TextField(max_length=WALLPOST_REACTION_MAX_LENGTH)

    def __unicode__(self):
        return Truncator(self.text).words(10)

class SystemWallpost(Wallpost):
    # The content of the wall post.
    @property
    def wallpost_type(self):
        return 'system'

    text = models.TextField(max_length=WALLPOST_REACTION_MAX_LENGTH, blank=True)

    # Generic foreign key so we can connect any object to it.
    related_type = models.ForeignKey(ContentType,
                                     verbose_name=_('related type'))
    related_id = models.PositiveIntegerField(_('related ID'))
    related_object = fields.GenericForeignKey('related_type', 'related_id')

    def __unicode__(self):
        return Truncator(self.text).words(10)

class Reaction(models.Model):
    """
    A user reaction or comment to a Wallpost. This model is based on
    the Comments model from django.contrib.comments.
    """

    # Who posted this reaction. User will need to be logged in to
    # make a reaction.
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               verbose_name=_('author'),
                               related_name='wallpost_reactions')
    editor = models.ForeignKey(
        settings.AUTH_USER_MODEL, verbose_name=_('editor'), blank=True,
        null=True, related_name='+',
        help_text=_("The last user to edit this reaction."))

    # The reaction text and the wallpost it's a reaction to.
    text = models.TextField(_('reaction text'),
                            max_length=WALLPOST_REACTION_MAX_LENGTH)
    wallpost = models.ForeignKey(Wallpost, related_name='reactions')

    # Metadata for the reaction.
    created = CreationDateTimeField(_('created'))
    updated = ModificationDateTimeField(_('updated'))
    deleted = models.DateTimeField(_('deleted'), blank=True, null=True)
    ip_address = models.GenericIPAddressField(_('IP address'), blank=True, null=True,
                                       default=None)

    # Manager
    objects = ReactionManager()
    objects_with_deleted = models.Manager()

    class Analytics:
        type = 'wallpost'
        tags = {}
        fields = {
            'id': 'id',
            'user_id': 'author.id'
        }

        def extra_tags(self, instance, created):
            return {'sub_type': 'reaction'}

        def skip(self, obj, created):
            return True if obj.wallpost_type == 'system' else False

    class Meta:
        ordering = ('created',)
        verbose_name = _('Reaction')
        verbose_name_plural = _('Reactions')

    def __unicode__(self):
        s = self.text
        return Truncator(s).words(10)

import mails
import bluebottle.wallposts.signals
<commit_msg>Remove unnessecary skip method<commit_after>from django.db import models
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import fields
from django_extensions.db.fields import (ModificationDateTimeField,
                                         CreationDateTimeField)
from django.utils.text import Truncator
from django.utils.translation import ugettext_lazy as _

from polymorphic.models import PolymorphicModel

from .managers import ReactionManager, WallpostManager

WALLPOST_TEXT_MAX_LENGTH = getattr(settings, 'WALLPOST_TEXT_MAX_LENGTH', 300)
WALLPOST_REACTION_MAX_LENGTH = getattr(settings, 'WALLPOST_REACTION_MAX_LENGTH',
                                       300)

GROUP_PERMS = {
    'Staff': {
        'perms': (
            'add_reaction', 'change_reaction', 'delete_reaction',
            'add_wallpost', 'change_wallpost', 'delete_wallpost',
            'add_mediawallpost', 'change_mediawallpost', 'delete_mediawallpost',
            'add_textwallpost', 'change_textwallpost', 'delete_textwallpost',
            'add_systemwallpost', 'change_systemwallpost',
            'delete_systemwallpost',
            'add_mediawallpostphoto', 'change_mediawallpostphoto',
            'delete_mediawallpostphoto',
        )
    }
}

class Wallpost(PolymorphicModel):
    """
    The Wallpost base class. This class will never be used directly because the
    content of a Wallpost is always defined
    in the child classes.

    Implementation Note: Normally this would be an abstract class but it's not
    possible to make this an abstract class
    and have the polymorphic behaviour of sorting on the common fields.
    """

    @property
    def wallpost_type(self):
        return 'unknown'

    # The user who wrote the wall post. This can be empty to support wallposts
    # without users (e.g. anonymous
    # TextWallposts, system Wallposts for donations etc.)
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               verbose_name=_('author'),
                               related_name="%(class)s_wallpost", blank=True,
                               null=True)
    editor = models.ForeignKey(
        settings.AUTH_USER_MODEL, verbose_name=_('editor'), blank=True,
        null=True, help_text=_("The last user to edit this wallpost."))

    # The metadata for the wall post.
    created = CreationDateTimeField(_('created'))
    updated = ModificationDateTimeField(_('updated'))
    deleted = models.DateTimeField(_('deleted'), blank=True, null=True)
    ip_address = models.GenericIPAddressField(_('IP address'), blank=True, null=True,
                                       default=None)

    # Generic foreign key so we can connect it to any object.
    content_type = models.ForeignKey(
        ContentType, verbose_name=_('content type'),
        related_name="content_type_set_for_%(class)s")
    object_id = models.PositiveIntegerField(_('object ID'))
    content_object = fields.GenericForeignKey('content_type', 'object_id')

    share_with_facebook = models.BooleanField(default=False)
    share_with_twitter = models.BooleanField(default=False)
    share_with_linkedin = models.BooleanField(default=False)
    email_followers = models.BooleanField(default=True)

    donation = models.ForeignKey('donations.Donation',
                                 verbose_name=_("Donation"),
                                 related_name='donation',
                                 null=True, blank=True)

    # Manager
    objects = WallpostManager()
    objects_with_deleted = models.Manager()

    class Analytics:
        type = 'wallpost'
        tags = {}
        fields = {
            'id': 'id',
            'user_id': 'author.id'
        }

        def skip(self, obj, created):
            return True if obj.wallpost_type == 'system' else False

    class Meta:
        ordering = ('created',)

    def __unicode__(self):
        return str(self.id)

class MediaWallpost(Wallpost):
    # The content of the wall post.

    @property
    def wallpost_type(self):
        return 'media'

    title = models.CharField(max_length=60)
    text = models.TextField(max_length=WALLPOST_REACTION_MAX_LENGTH, blank=True,
                            default='')
    video_url = models.URLField(max_length=100, blank=True, default='')

    def __unicode__(self):
        return Truncator(self.text).words(10)

        # FIXME: See how we can re-enable this
        # def save(self, *args, **kwargs):
        #     super(MediaWallpost, self).save(*args, **kwargs)
        #
        #     # Mark the photos as deleted when the MediaWallpost is deleted.
        #     if self.deleted:
        #         for photo in self.photos.all():
        #             if not photo.deleted:
        #                 photo.deleted = self.deleted
        #                 photo.save()

class MediaWallpostPhoto(models.Model):
    mediawallpost = models.ForeignKey(MediaWallpost, related_name='photos',
                                      null=True, blank=True)
    photo = models.ImageField(upload_to='mediawallpostphotos')
    deleted = models.DateTimeField(_('deleted'), blank=True, null=True)
    ip_address = models.GenericIPAddressField(_('IP address'), blank=True, null=True,
                                       default=None)
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               verbose_name=_('author'),
                               related_name="%(class)s_wallpost_photo",
                               blank=True, null=True)
    editor = models.ForeignKey(settings.AUTH_USER_MODEL,
                               verbose_name=_('editor'), blank=True, null=True,
                               help_text=_(
                                   "The last user to edit this wallpost photo."))

class TextWallpost(Wallpost):
    # The content of the wall post.
    @property
    def wallpost_type(self):
        return 'text'

    text = models.TextField(max_length=WALLPOST_REACTION_MAX_LENGTH)

    def __unicode__(self):
        return Truncator(self.text).words(10)

class SystemWallpost(Wallpost):
    # The content of the wall post.
    @property
    def wallpost_type(self):
        return 'system'

    text = models.TextField(max_length=WALLPOST_REACTION_MAX_LENGTH, blank=True)

    # Generic foreign key so we can connect any object to it.
    related_type = models.ForeignKey(ContentType,
                                     verbose_name=_('related type'))
    related_id = models.PositiveIntegerField(_('related ID'))
    related_object = fields.GenericForeignKey('related_type', 'related_id')

    def __unicode__(self):
        return Truncator(self.text).words(10)

class Reaction(models.Model):
    """
    A user reaction or comment to a Wallpost. This model is based on
    the Comments model from django.contrib.comments.
    """

    # Who posted this reaction. User will need to be logged in to
    # make a reaction.
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               verbose_name=_('author'),
                               related_name='wallpost_reactions')
    editor = models.ForeignKey(
        settings.AUTH_USER_MODEL, verbose_name=_('editor'), blank=True,
        null=True, related_name='+',
        help_text=_("The last user to edit this reaction."))

    # The reaction text and the wallpost it's a reaction to.
    text = models.TextField(_('reaction text'),
                            max_length=WALLPOST_REACTION_MAX_LENGTH)
    wallpost = models.ForeignKey(Wallpost, related_name='reactions')

    # Metadata for the reaction.
    created = CreationDateTimeField(_('created'))
    updated = ModificationDateTimeField(_('updated'))
    deleted = models.DateTimeField(_('deleted'), blank=True, null=True)
    ip_address = models.GenericIPAddressField(_('IP address'), blank=True, null=True,
                                       default=None)

    # Manager
    objects = ReactionManager()
    objects_with_deleted = models.Manager()

    class Analytics:
        type = 'wallpost'
        tags = {}

        fields = {
            'id': 'id',
            'user_id': 'author.id'
        }

        def extra_tags(self, instance, created):
            return {'sub_type': 'reaction'}

    class Meta:
        ordering = ('created',)
        verbose_name = _('Reaction')
        verbose_name_plural = _('Reactions')

    def __unicode__(self):
        s = self.text
        return Truncator(s).words(10)

import mails
import bluebottle.wallposts.signals
<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
Anything related to deploying your project modules, media, and data
"""
import os, shutil, sys

from django.core.servers.basehttp import AdminMediaHandler
from django.template.loader import render_to_string

from fabric.state import env
from fabric.operations import local, run, put, sudo
from fabric.decorators import runs_once
from fabric.contrib.files import exists
from fabric.contrib.console import confirm
#Required for a bug in 0.9
from fabric.version import get_version

from woven.deployment import deploy_files, run_once_per_host_version
from woven.environment import deployment_root, _root_domain

@runs_once
def _make_local_sitesettings(overwrite=False):
    local_settings_dir = os.path.join(os.getcwd(),env.project_name,'sitesettings')
    if not os.path.exists(local_settings_dir) or overwrite:
        if overwrite:
            shutil.rmtree(local_settings_dir,ignore_errors=True)
        os.mkdir(local_settings_dir)
        f = open(os.path.join(local_settings_dir,'__init__.py'),"w")
        f.close()

    settings_file_path = os.path.join(local_settings_dir,'settings.py')
    if not os.path.exists(settings_file_path):
        root_domain = _root_domain()
        u_domain = root_domain.replace('.','_')
        output = render_to_string('woven/sitesettings.txt',
                {"deployment_root":deployment_root(),
                "site_id":"1",
                "project_name": env.project_name,
                "project_fullname": env.project_fullname,
                "u_domain":u_domain,
                "domain":root_domain,
                "user":env.user},
            )

        f = open(settings_file_path,"w+")
        f.writelines(output)
        f.close()

        #create a convenience settings file link for the first site
        settings_file_path = os.path.join(local_settings_dir,''.join([u_domain,'.py']))
        if not os.path.exists(settings_file_path):
            f = open(settings_file_path, "w+")
            f.write("from %s.sitesettings.settings import *"% env.project_name)
            f.write("\nSITE_ID=1\n")
            f.close()
            #copy manage.py into that directory
            manage_path = os.path.join(os.getcwd(),env.project_name,'manage.py')
            dest_manage_path = os.path.join(os.getcwd(),env.project_name,'sitesettings','manage.py')
            shutil.copy(manage_path, dest_manage_path)
    return

@run_once_per_host_version
def deploy_project():
    """
    Deploy to the project directory in the virtualenv
    """

    project_root = '/'.join([deployment_root(),'env',env.project_fullname,'project'])
    local_dir = os.getcwd()

    if env.verbosity:
        print env.host,"DEPLOYING project", env.project_fullname
    #Exclude a few things that we don't want deployed as part of the project folder
    rsync_exclude = ['*.pyc','*.log','.*','/build','/dist','/media*','/static*','/www','/public','/templates']

    #make site local settings if they don't already exist
    _make_local_sitesettings()
    created = deploy_files(local_dir, project_root, rsync_exclude=rsync_exclude)
    if not env.patch:
        #hook the project into sys.path - #TODO make the python version not fixed
        link_name = '/'.join([deployment_root(),'env',env.project_fullname,'lib/python2.6/site-packages',env.project_name])
        target = '/'.join([project_root,env.project_name])
        run(' '.join(['ln -s',target,link_name]))

    return created

def deploy_sitesettings():
    """
    Deploy to the project directory in the virtualenv
    """

    sitesettings = '/'.join([deployment_root(),'env',env.project_fullname,'project',env.project_name,'sitesettings'])
    local_dir = os.path.join(os.getcwd(),env.project_name,'sitesettings')

    created = deploy_files(local_dir, sitesettings)
    if env.verbosity and created:
        print env.host,"DEPLOYING sitesettings"
        for path in created:
            tail = path.split('/')[-1]
            print ' * uploaded',tail

@run_once_per_host_version
def deploy_templates():
    """
    Deploy any templates from your shortest TEMPLATE_DIRS setting
    """

    deployed = None
    if not hasattr(env, 'project_template_dir'):
        #the normal pattern would mean the shortest path is the main one.
        #its probably the last listed
        length = 1000
        for dir in env.TEMPLATE_DIRS:
            if dir:
                len_dir = len(dir)
                if len_dir < length:
                    length = len_dir
                    env.project_template_dir = dir

    if hasattr(env,'project_template_dir'):
        remote_dir = '/'.join([deployment_root(),'env',env.project_fullname,'templates'])
        if env.verbosity:
            print env.host,"DEPLOYING templates", remote_dir
        deployed = deploy_files(env.project_template_dir,remote_dir)
    return deployed

@run_once_per_host_version
def deploy_static():
    """
    Deploy static (application) versioned media
    """
    if (not env.STATIC_ROOT and not env.ADMIN_MEDIA_PREFIX) or 'http://' in env.STATIC_URL: return

    remote_dir = '/'.join([deployment_root(),'env',env.project_fullname,'static'])

    #if app media is not handled by django-staticfiles we can install admin media by default
    if 'django.contrib.admin' in env.INSTALLED_APPS and not env.STATIC_ROOT:
        if env.MEDIA_URL in env.ADMIN_MEDIA_PREFIX:
            print "ERROR: Your ADMIN_MEDIA_PREFIX must not be on the same path as your MEDIA_URL"
            print "for example you cannot use MEDIA_URL = /media/ and ADMIN_MEDIA_PREFIX = /media/admin/"
            sys.exit(1)
        env.STATIC_URL = env.ADMIN_MEDIA_PREFIX
        admin = AdminMediaHandler('DummyApp')
        local_dir = admin.media_dir
        remote_dir =  ''.join([remote_dir,env.ADMIN_MEDIA_PREFIX])
    else:
        if env.MEDIA_URL in env.STATIC_URL:
            print "ERROR: Your STATIC_URL must not be on the same path as your MEDIA_URL"
            print "for example you cannot use MEDIA_URL = /media/ and STATIC_URL = /media/static/"
            sys.exit(1)
        elif env.STATIC_ROOT:
            local_dir = env.STATIC_ROOT
            static_url = env.STATIC_URL[1:]
            if static_url:
                remote_dir = '/'.join([remote_dir,static_url])
        else: return
    if env.verbosity:
        print env.host,"DEPLOYING static",remote_dir
    return deploy_files(local_dir,remote_dir)

@run_once_per_host_version
def deploy_public():
    """
    Deploy MEDIA_ROOT unversioned on host
    """
    if not env.MEDIA_ROOT or 'http://' in env.MEDIA_URL: return
    local_dir = env.MEDIA_ROOT

    remote_dir = '/'.join([deployment_root(),'public'])
    media_url = env.MEDIA_URL[1:]
    if media_url:
        remote_dir = '/'.join([remote_dir,media_url])
    if env.verbosity:
        print env.host,"DEPLOYING public",remote_dir
    deployed = deploy_files(local_dir,remote_dir)

    #make writable for www-data for file uploads
    sudo("chown -R www-data:sudo %s" % remote_dir)
    sudo("chmod -R ug+w %s"% remote_dir)
    return deployed

@runs_once
def deploy_db(rollback=False):
    """
    Deploy a sqlite database from development
    """
    db_name = ''.join([env.project_name,'.db'])
    db_dir = '/'.join([deployment_root(),'database'])
    db_path = '/'.join([db_dir,db_name])
    if not rollback:
        if env.DEFAULT_DATABASE_ENGINE=='django.db.backends.sqlite3' and not exists(db_path):
            if env.verbosity:
                print env.host,"DEPLOYING DEFAULT SQLITE DATABASE",db_path
            if not os.path.exists(env.DEFAULT_DATABASE_NAME) or not env.DEFAULT_DATABASE_NAME:
                print "ERROR: the database does not exist. Run python manage.py syncdb to create your database first."
                sys.exit(1)
            run('mkdir -p '+db_dir)
            put(env.DEFAULT_DATABASE_NAME,db_path)
            #directory and file must be writable by webserver
            sudo("chown -R %s:www-data %s"% (env.user,db_dir))
            sudo("chmod -R ug+w %s"% db_dir)
    elif rollback and env.DEFAULT_DATABASE_ENGINE=='django.db.backends.sqlite3':
        if env.INTERACTIVE:
            delete = confirm('DELETE the database on the host?',default=False)
            if delete:
                run('rm -f '+db_name)
    return
<commit_msg>fix up issue with database naming for sqlite. fix up issue with hosting application media externally<commit_after>#!/usr/bin/env python
"""
Anything related to deploying your project modules, media, and data
"""
import os, shutil, sys

from django.core.servers.basehttp import AdminMediaHandler
from django.template.loader import render_to_string

from fabric.state import env
from fabric.operations import local, run, put, sudo
from fabric.decorators import runs_once
from fabric.contrib.files import exists
from fabric.contrib.console import confirm
#Required for a bug in 0.9
from fabric.version import get_version

from woven.deployment import deploy_files, run_once_per_host_version
from woven.environment import deployment_root, _root_domain

@runs_once
def _make_local_sitesettings(overwrite=False):
    local_settings_dir = os.path.join(os.getcwd(),env.project_name,'sitesettings')
    if not os.path.exists(local_settings_dir) or overwrite:
        if overwrite:
            shutil.rmtree(local_settings_dir,ignore_errors=True)
        os.mkdir(local_settings_dir)
        f = open(os.path.join(local_settings_dir,'__init__.py'),"w")
        f.close()

    settings_file_path = os.path.join(local_settings_dir,'settings.py')
    if not os.path.exists(settings_file_path):
        root_domain = _root_domain()
        u_domain = root_domain.replace('.','_')
        output = render_to_string('woven/sitesettings.txt',
                {"deployment_root":deployment_root(),
                "site_id":"1",
                "project_name": env.project_name,
                "project_fullname": env.project_fullname,
                "u_domain":u_domain,
                "domain":root_domain,
                "user":env.user},
            )

        f = open(settings_file_path,"w+")
        f.writelines(output)
        f.close()

        #create a convenience settings file link for the first site
        settings_file_path = os.path.join(local_settings_dir,''.join([u_domain,'.py']))
        if not os.path.exists(settings_file_path):
            f = open(settings_file_path, "w+")
            f.write("from %s.sitesettings.settings import *"% env.project_name)
            f.write("\nSITE_ID=1\n")
            f.close()
            #copy manage.py into that directory
            manage_path = os.path.join(os.getcwd(),env.project_name,'manage.py')
            dest_manage_path = os.path.join(os.getcwd(),env.project_name,'sitesettings','manage.py')
            shutil.copy(manage_path, dest_manage_path)
    return

@run_once_per_host_version
def deploy_project():
    """
    Deploy to the project directory in the virtualenv
    """

    project_root = '/'.join([deployment_root(),'env',env.project_fullname,'project'])
    local_dir = os.getcwd()

    if env.verbosity:
        print env.host,"DEPLOYING project", env.project_fullname
    #Exclude a few things that we don't want deployed as part of the project folder
    rsync_exclude = ['*.pyc','*.log','.*','/build','/dist','/media*','/static*','/www','/public','/templates']

    #make site local settings if they don't already exist
    _make_local_sitesettings()
    created = deploy_files(local_dir, project_root, rsync_exclude=rsync_exclude)
    if not env.patch:
        #hook the project into sys.path - #TODO make the python version not fixed
        link_name = '/'.join([deployment_root(),'env',env.project_fullname,'lib/python2.6/site-packages',env.project_name])
        target = '/'.join([project_root,env.project_name])
        run(' '.join(['ln -s',target,link_name]))

    return created

def deploy_sitesettings():
    """
    Deploy to the project directory in the virtualenv
    """

    sitesettings = '/'.join([deployment_root(),'env',env.project_fullname,'project',env.project_name,'sitesettings'])
    local_dir = os.path.join(os.getcwd(),env.project_name,'sitesettings')

    created = deploy_files(local_dir, sitesettings)
    if env.verbosity and created:
        print env.host,"DEPLOYING sitesettings"
        for path in created:
            tail = path.split('/')[-1]
            print ' * uploaded',tail

@run_once_per_host_version
def deploy_templates():
    """
    Deploy any templates from your shortest TEMPLATE_DIRS setting
    """

    deployed = None
    if not hasattr(env, 'project_template_dir'):
        #the normal pattern would mean the shortest path is the main one.
        #its probably the last listed
        length = 1000
        for dir in env.TEMPLATE_DIRS:
            if dir:
                len_dir = len(dir)
                if len_dir < length:
                    length = len_dir
                    env.project_template_dir = dir

    if hasattr(env,'project_template_dir'):
        remote_dir = '/'.join([deployment_root(),'env',env.project_fullname,'templates'])
        if env.verbosity:
            print env.host,"DEPLOYING templates", remote_dir
        deployed = deploy_files(env.project_template_dir,remote_dir)
    return deployed

@run_once_per_host_version
def deploy_static():
    """
    Deploy static (application) versioned media
    """
    if (not env.STATIC_ROOT and not env.ADMIN_MEDIA_PREFIX) or 'http://' in env.STATIC_URL: return
    elif 'http://' in env.ADMIN_MEDIA_PREFIX: return

    remote_dir = '/'.join([deployment_root(),'env',env.project_fullname,'static'])

    #if app media is not handled by django-staticfiles we can install admin media by default
    if 'django.contrib.admin' in env.INSTALLED_APPS and not env.STATIC_ROOT:
        if env.MEDIA_URL in env.ADMIN_MEDIA_PREFIX:
            print "ERROR: Your ADMIN_MEDIA_PREFIX (Application media) must not be on the same path as your MEDIA_URL (User media)"
            sys.exit(1)
        env.STATIC_URL = env.ADMIN_MEDIA_PREFIX
        admin = AdminMediaHandler('DummyApp')
        local_dir = admin.media_dir
        remote_dir =  ''.join([remote_dir,env.ADMIN_MEDIA_PREFIX])
    else:
        if env.MEDIA_URL in env.STATIC_URL:
            print "ERROR: Your STATIC_URL (Application media) must not be on the same path as your MEDIA_URL (User media)"
            sys.exit(1)
        elif env.STATIC_ROOT:
            local_dir = env.STATIC_ROOT
            static_url = env.STATIC_URL[1:]
            if static_url:
                remote_dir = '/'.join([remote_dir,static_url])
        else: return
    if env.verbosity:
        print env.host,"DEPLOYING static",remote_dir
    return deploy_files(local_dir,remote_dir)

@run_once_per_host_version
def deploy_public():
    """
    Deploy MEDIA_ROOT unversioned on host
    """
    if not env.MEDIA_ROOT or 'http://' in env.MEDIA_URL: return
    local_dir = env.MEDIA_ROOT

    remote_dir = '/'.join([deployment_root(),'public'])
    media_url = env.MEDIA_URL[1:]
    if media_url:
        remote_dir = '/'.join([remote_dir,media_url])
    if env.verbosity:
        print env.host,"DEPLOYING public",remote_dir
    deployed = deploy_files(local_dir,remote_dir)

    #make writable for www-data for file uploads
    sudo("chown -R www-data:sudo %s" % remote_dir)
    sudo("chmod -R ug+w %s"% remote_dir)
    return deployed

@runs_once
def deploy_db(rollback=False):
    """
    Deploy a sqlite database from development
    """
    if not rollback:

        if env.DEFAULT_DATABASE_ENGINE=='django.db.backends.sqlite3':
            if env.verbosity:
                print env.host,"DEPLOYING DEFAULT SQLITE DATABASE"
            if not env.DEFAULT_DATABASE_NAME:
                print "ERROR: A database engine has not been defined in your Django settings file"
                sys.exit(1)
            elif env.DEFAULT_DATABASE_ENGINE=='django.db.backends.':
                print "ERROR: The default database engine has not been defined in your Django settings file"
                sys.exit(1)
            if env.DEFAULT_DATABASE_NAME[0] not in [os.path.sep,'.']: #relative path
                db_path = os.path.join(os.getcwd(),env.project_name,env.DEFAULT_DATABASE_NAME)
                print db_path
            elif env.DEFAULT_DATABASE_NAME[:2] == '..':
                print "ERROR: Use a full expanded path to the database in your Django settings"
                sys.exit(1)
            else:
                db_path = env.DEFAULT_DATABASE_NAME

            if not db_path or not os.path.exists(db_path):
                print "ERROR: the database %s does not exist. \nRun python manage.py syncdb to create your database locally first, or check your settings."% db_path
                sys.exit(1)
            db_dir = '/'.join([deployment_root(),'database'])
            db_name = os.path.split(db_path)[1]
            dest_db_path = '/'.join([db_dir,env.project_name+'.db'])

            run('mkdir -p '+db_dir)
            put(db_path,dest_db_path)
            #directory and file must be writable by webserver
            sudo("chown -R %s:www-data %s"% (env.user,db_dir))
            sudo("chmod -R ug+w %s"% db_dir)
    elif rollback and env.DEFAULT_DATABASE_ENGINE=='django.db.backends.sqlite3':
        if env.INTERACTIVE:
            delete = confirm('DELETE the database on the host?',default=False)
            if delete:
                run('rm -f '+db_name)
    return
<|endoftext|>


<commit_before># Copyright 2019 Extreme Networks, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import
import os
import sys
import unittest

import mock
from oslo_config import cfg

from st2common.constants.pack import SYSTEM_PACK_NAMES
from st2common.util.sandboxing import get_sandbox_path
from st2common.util.sandboxing import get_sandbox_python_path
from st2common.util.sandboxing import get_sandbox_python_path_for_python_action
from st2common.util.sandboxing import get_sandbox_python_binary_path
from st2common.util.sandboxing import is_pack_virtualenv_using_python3

import st2tests.config as tests_config

__all__ = [
    'SandboxingUtilsTestCase'
]

class SandboxingUtilsTestCase(unittest.TestCase):
    def setUp(self):
        super(SandboxingUtilsTestCase, self).setUp()

        # Restore PATH and other variables before each test case
        os.environ['PATH'] = self.old_path
        os.environ['PYTHONPATH'] = self.old_python_path
        sys.real_prefix = self.old_real_prefix

    @classmethod
    def setUpClass(cls):
        tests_config.parse_args()

        # Store original values so we can restore them in setUp
        cls.old_path = os.environ.get('PATH', '')
        cls.old_python_path = os.environ.get('PYTHONPATH', '')
        cls.old_real_prefix = sys.real_prefix

    @classmethod
    def tearDownClass(cls):
        os.environ['PATH'] = cls.old_path
        os.environ['PYTHONPATH'] = cls.old_python_path
        sys.real_prefix = cls.old_real_prefix

    def test_get_sandbox_python_binary_path(self):
        # Non-system content pack, should use pack specific virtualenv binary
        result = get_sandbox_python_binary_path(pack='mapack')
        expected = os.path.join(cfg.CONF.system.base_path, 'virtualenvs/mapack/bin/python')
        self.assertEqual(result, expected)

        # System content pack, should use current process (system) python binary
        result = get_sandbox_python_binary_path(pack=SYSTEM_PACK_NAMES[0])
        self.assertEqual(result, sys.executable)

    def test_get_sandbox_path(self):
        # Mock the current PATH value
        os.environ['PATH'] = '/home/path1:/home/path2:/home/path3:'

        virtualenv_path = '/home/venv/test'
        result = get_sandbox_path(virtualenv_path=virtualenv_path)
        self.assertEqual(result, '/home/venv/test/bin/:/home/path1:/home/path2:/home/path3')

    @mock.patch('st2common.util.sandboxing.get_python_lib')
    def test_get_sandbox_python_path(self, mock_get_python_lib):
        # No inheritance
        python_path = get_sandbox_python_path(inherit_from_parent=False,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':')

        # Inherit python path from current process
        # Mock the current process python path
        os.environ['PYTHONPATH'] = ':/data/test1:/data/test2'

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (not running inside virtualenv)
        del sys.real_prefix

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (running inside virtualenv)
        sys.real_prefix = '/usr'
        mock_get_python_lib.return_value = sys.prefix + '/virtualenvtest'
        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=True)
        self.assertEqual(python_path, ':/data/test1:/data/test2:%s/virtualenvtest' %
                         (sys.prefix))

    @mock.patch('os.path.isdir', mock.Mock(return_value=True))
    @mock.patch('os.listdir', mock.Mock(return_value=['python2.7']))
    @mock.patch('st2common.util.sandboxing.get_python_lib')
    def test_get_sandbox_python_path_for_python_action_python2_used_for_venv(self,
            mock_get_python_lib):
        self.assertFalse(is_pack_virtualenv_using_python3(pack='dummy_pack')[0])

        # No inheritance
        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=False,
                                                                inherit_parent_virtualenv=False)

        self.assertEqual(python_path, ':')

        # Inherit python path from current process
        # Mock the current process python path
        os.environ['PYTHONPATH'] = ':/data/test1:/data/test2'

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (not running inside virtualenv)
        del sys.real_prefix

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (running inside virtualenv)
        sys.real_prefix = '/usr'
        mock_get_python_lib.return_value = sys.prefix + '/virtualenvtest'
        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=True)
        self.assertEqual(python_path, ':/data/test1:/data/test2:%s/virtualenvtest' %
                         (sys.prefix))

    @mock.patch('os.path.exists', mock.Mock(return_value=True))
    @mock.patch('os.path.isdir', mock.Mock(return_value=True))
    @mock.patch('os.listdir', mock.Mock(return_value=['python3.6']))
    @mock.patch('st2common.util.sandboxing.get_python_lib')
    @mock.patch('st2common.util.sandboxing.get_pack_base_path',
                mock.Mock(return_value='/tmp/packs/dummy_pack'))
    @mock.patch('st2common.util.sandboxing.get_sandbox_virtualenv_path',
                mock.Mock(return_value='/tmp/virtualenvs/dummy_pack'))
    def test_get_sandbox_python_path_for_python_action_python3_used_for_venv(self,
            mock_get_python_lib):
        self.assertTrue(is_pack_virtualenv_using_python3(pack='dummy_pack')[0])

        # No inheritance
        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=False,
                                                                inherit_parent_virtualenv=False)

        split = python_path.strip(':').split(':')
        self.assertEqual(len(split), 3)

        # First entry should be lib/python3 dir from venv
        self.assertTrue('virtualenvs/dummy_pack/lib/python3.6' in split[0])

        # Second entry should be python3 site-packages dir from venv
        self.assertTrue('virtualenvs/dummy_pack/lib/python3.6/site-packages' in split[1])

        # Third entry should be actions/lib dir from pack root directory
        self.assertTrue('packs/dummy_pack/actions/lib/' in split[2])

        # Inherit python path from current process
        # Mock the current process python path
        os.environ['PYTHONPATH'] = ':/data/test1:/data/test2'

        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=True,
                                                                inherit_parent_virtualenv=False)
        expected = ('/tmp/virtualenvs/dummy_pack/lib/python3.6:'
                    '/tmp/virtualenvs/dummy_pack/lib/python3.6/site-packages:'
                    '/tmp/packs/dummy_pack/actions/lib/::/data/test1:/data/test2')
        self.assertEqual(python_path, expected)

        # Inherit from current process and from virtualenv (not running inside virtualenv)
        del sys.real_prefix

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (running inside virtualenv)
        sys.real_prefix = '/usr'
        mock_get_python_lib.return_value = sys.prefix + '/virtualenvtest'
        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=True,
                                                                inherit_parent_virtualenv=True)

        expected = ('/tmp/virtualenvs/dummy_pack/lib/python3.6:'
                    '/tmp/virtualenvs/dummy_pack/lib/python3.6/site-packages:'
                    '/tmp/packs/dummy_pack/actions/lib/::/data/test1:/data/test2:'
                    '%s/virtualenvtest' % (sys.prefix))
        self.assertEqual(python_path, expected)
<commit_msg>Add unit tests for it.<commit_after># Copyright 2019 Extreme Networks, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import
import os
import sys
import unittest

import mock
from oslo_config import cfg

from st2common.constants.pack import SYSTEM_PACK_NAMES
from st2common.util.sandboxing import get_sandbox_path
from st2common.util.sandboxing import get_sandbox_python_path
from st2common.util.sandboxing import get_sandbox_python_path_for_python_action
from st2common.util.sandboxing import get_sandbox_python_binary_path
from st2common.util.sandboxing import is_pack_virtualenv_using_python3

import st2tests.config as tests_config

__all__ = [
    'SandboxingUtilsTestCase'
]

class SandboxingUtilsTestCase(unittest.TestCase):
    def setUp(self):
        super(SandboxingUtilsTestCase, self).setUp()

        # Restore PATH and other variables before each test case
        os.environ['PATH'] = self.old_path
        os.environ['PYTHONPATH'] = self.old_python_path
        sys.real_prefix = self.old_real_prefix

    @classmethod
    def setUpClass(cls):
        tests_config.parse_args()

        # Store original values so we can restore them in setUp
        cls.old_path = os.environ.get('PATH', '')
        cls.old_python_path = os.environ.get('PYTHONPATH', '')
        cls.old_real_prefix = sys.real_prefix

    @classmethod
    def tearDownClass(cls):
        os.environ['PATH'] = cls.old_path
        os.environ['PYTHONPATH'] = cls.old_python_path
        sys.real_prefix = cls.old_real_prefix

    def test_get_sandbox_python_binary_path(self):
        # Non-system content pack, should use pack specific virtualenv binary
        result = get_sandbox_python_binary_path(pack='mapack')
        expected = os.path.join(cfg.CONF.system.base_path, 'virtualenvs/mapack/bin/python')
        self.assertEqual(result, expected)

        # System content pack, should use current process (system) python binary
        result = get_sandbox_python_binary_path(pack=SYSTEM_PACK_NAMES[0])
        self.assertEqual(result, sys.executable)

    def test_get_sandbox_path(self):
        # Mock the current PATH value
        os.environ['PATH'] = '/home/path1:/home/path2:/home/path3:'

        virtualenv_path = '/home/venv/test'
        result = get_sandbox_path(virtualenv_path=virtualenv_path)
        self.assertEqual(result, '/home/venv/test/bin/:/home/path1:/home/path2:/home/path3')

    @mock.patch('st2common.util.sandboxing.get_python_lib')
    def test_get_sandbox_python_path(self, mock_get_python_lib):
        # No inheritance
        python_path = get_sandbox_python_path(inherit_from_parent=False,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':')

        # Inherit python path from current process
        # Mock the current process python path
        os.environ['PYTHONPATH'] = ':/data/test1:/data/test2'

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (not running inside virtualenv)
        del sys.real_prefix

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (running inside virtualenv)
        sys.real_prefix = '/usr'
        mock_get_python_lib.return_value = sys.prefix + '/virtualenvtest'
        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=True)
        self.assertEqual(python_path, ':/data/test1:/data/test2:%s/virtualenvtest' %
                         (sys.prefix))

    @mock.patch('os.path.isdir', mock.Mock(return_value=True))
    @mock.patch('os.listdir', mock.Mock(return_value=['python2.7']))
    @mock.patch('st2common.util.sandboxing.get_python_lib')
    def test_get_sandbox_python_path_for_python_action_python2_used_for_venv(self,
            mock_get_python_lib):
        self.assertFalse(is_pack_virtualenv_using_python3(pack='dummy_pack')[0])

        # No inheritance
        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=False,
                                                                inherit_parent_virtualenv=False)

        self.assertEqual(python_path, ':')

        # Inherit python path from current process
        # Mock the current process python path
        os.environ['PYTHONPATH'] = ':/data/test1:/data/test2'

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (not running inside virtualenv)
        del sys.real_prefix

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (running inside virtualenv)
        sys.real_prefix = '/usr'
        mock_get_python_lib.return_value = sys.prefix + '/virtualenvtest'
        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=True)
        self.assertEqual(python_path, ':/data/test1:/data/test2:%s/virtualenvtest' %
                         (sys.prefix))

    @mock.patch('os.path.exists', mock.Mock(return_value=True))
    @mock.patch('os.path.isdir', mock.Mock(return_value=True))
    @mock.patch('os.listdir', mock.Mock(return_value=['python3.6']))
    @mock.patch('os.path.realpath', mock.Mock(return_value='/usr/lib/python3.6/abc.py'))
    @mock.patch('st2common.util.sandboxing.get_python_lib')
    @mock.patch('st2common.util.sandboxing.get_pack_base_path',
                mock.Mock(return_value='/tmp/packs/dummy_pack'))
    @mock.patch('st2common.util.sandboxing.get_sandbox_virtualenv_path',
                mock.Mock(return_value='/tmp/virtualenvs/dummy_pack'))
    def test_get_sandbox_python_path_for_python_action_python3_used_for_venv(self,
            mock_get_python_lib):
        self.assertTrue(is_pack_virtualenv_using_python3(pack='dummy_pack')[0])

        # No inheritance
        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=False,
                                                                inherit_parent_virtualenv=False)

        split = python_path.strip(':').split(':')
        self.assertEqual(len(split), 4)

        # First entry should be system lib/python3 dir
        # Second entry should be lib/python3 dir from venv
        self.assertTrue('virtualenvs/dummy_pack/lib/python3.6' in split[1])

        # Third entry should be python3 site-packages dir from venv
        self.assertTrue('virtualenvs/dummy_pack/lib/python3.6/site-packages' in split[2])

        # Fourth entry should be actions/lib dir from pack root directory
        self.assertTrue('packs/dummy_pack/actions/lib/' in split[3])

        # Inherit python path from current process
        # Mock the current process python path
        os.environ['PYTHONPATH'] = ':/data/test1:/data/test2'

        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=True,
                                                                inherit_parent_virtualenv=False)
        expected = ('/usr/lib/python3.6:'
                    '/tmp/virtualenvs/dummy_pack/lib/python3.6:'
                    '/tmp/virtualenvs/dummy_pack/lib/python3.6/site-packages:'
                    '/tmp/packs/dummy_pack/actions/lib/::/data/test1:/data/test2')
        self.assertEqual(python_path, expected)

        # Inherit from current process and from virtualenv (not running inside virtualenv)
        del sys.real_prefix

        python_path = get_sandbox_python_path(inherit_from_parent=True,
                                              inherit_parent_virtualenv=False)
        self.assertEqual(python_path, ':/data/test1:/data/test2')

        # Inherit from current process and from virtualenv (running inside virtualenv)
        sys.real_prefix = '/usr'
        mock_get_python_lib.return_value = sys.prefix + '/virtualenvtest'
        python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
                                                                inherit_from_parent=True,
                                                                inherit_parent_virtualenv=True)

        expected = ('/usr/lib/python3.6:'
                    '/tmp/virtualenvs/dummy_pack/lib/python3.6:'
                    '/tmp/virtualenvs/dummy_pack/lib/python3.6/site-packages:'
                    '/tmp/packs/dummy_pack/actions/lib/::/data/test1:/data/test2:'
                    '%s/virtualenvtest' % (sys.prefix))
        self.assertEqual(python_path, expected)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
# =============================================================================
#      FileName: spichi.py
#          Desc:
#        Author: ifkite
#         Email: holahello@163.com
#      HomePage: http://github.com/ifkite
#    LastChange: 2017-07-14 08:42:53
# =============================================================================
'''
from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule
import json

from session import SessionHandler
from utils import UploadHanderFactory
from database import DataBasefactory
from excepts import ExceptHandler, handle_except

class Spichi(object):

    url_map = Map([])
    view_func = {}
    pre_handler = [SessionHandler]
    post_hander = [SessionHandler]

    # sample
    databases = {'mysql': DataBasefactory('sql').build('mysql+mysqldb://root:@localhost/ydop')}
    UploadHandlerClass = UploadHanderFactory('local').get_backend()

    def __init__(self, *args, **kwargs):
        pass

    def route(self, rule, endpoint):
        def decorator(func):
            self.add_url(rule, endpoint, func)
        return decorator

    def route_class(self, rule, endpoint, *cls_args, **cls_kwargs):
        def decorator(cls):
            obj = cls(*cls_args, **cls_kwargs)
            self.add_url(rule, endpoint, obj)
            return cls
        return decorator

    def add_url(self, rule, endpoint, func):
        self.url_map.add(Rule(rule, endpoint=endpoint))
        self.view_func.update({endpoint: func})

    def pre_handle(self, request):
        for handler in self.pre_handler:
            handler().pre_process(request)

    def post_handle(self, request, response):
        for handler in self.post_hander:
            handler().post_process(request, response)

    def response_wrapper(self, endpoints, request, values):
        results = self.view_func[endpoints](request, **values) or []
        if isinstance(results, Response):
            return results
        return Response(json.dumps({'error_code': 200, 'error_msg': '', 'error_detail': '', 'results': results}), mimetype='application/json')

    def dispatch_response(self, request):
        adapter = self.url_map.bind_to_environ(request.environ)
        try:
            endpoints, values = adapter.match()
            return self.response_wrapper(endpoints=endpoints, request=request, values=values)
        except Exception as e:
            return handle_except(e, ExceptHandler)

    def wsgi_app(self, environ, start_response):
        request = Request(environ)
        self.pre_handle(request)
        response = self.dispatch_response(request)
        self.post_handle(request, response)
        return response(environ, start_response)

    def __call__(self, environ, start_response):
        return self.wsgi_app(environ, start_response)

def create_app(*args, **kwargs):
    return Spichi(*args, **kwargs)
<commit_msg>读 数据库以及上传文件类 的配置<commit_after># -*- coding: utf-8 -*-
'''
# =============================================================================
#      FileName: spichi.py
#          Desc:
#        Author: ifkite
#         Email: holahello@163.com
#      HomePage: http://github.com/ifkite
#    LastChange: 2017-07-14 08:42:53
# =============================================================================
'''
from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule
from config import Config
import os
import re
import json

from session import SessionHandler
from utils import UploadHanderFactory
from database import DataBasefactory
from excepts import ExceptHandler, handle_except

class Spichi(object):

    url_map = Map([])
    view_func = {}
    pre_handler = [SessionHandler]
    post_hander = [SessionHandler]

    def set_databases(self):
        self.databases = {
                db_name: DataBasefactory(db_value['DB_TYPE']).build(db_value['DB_CONF'])
                for db_name, db_value in self.conf['DATABASES'].iteritems()
                }

    def set_upload_handler_class(self):
        self.UploadHandlerClass = UploadHanderFactory(self.conf['UPLOAD_CLASS']).get_backend()

    def set_config(self, *args, **kwargs):
        default_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        default_path = os.path.join(default_dir, 'spichi')
        conf_filepath = kwargs.get('path', default_path)
        conf_filename = kwargs.get('conf', 'develop.json')
        self.conf = Config(conf_filepath)

        if re.search('\.py', conf_filename):
            self.conf.from_pyfile(conf_filename)
        else:
            self.conf.from_json(conf_filename)

    def __init__(self, *args, **kwargs):
        self.set_config(*args, **kwargs)
        self.set_databases()
        self.set_upload_handler_class()

    def route(self, rule, endpoint):
        def decorator(func):
            self.add_url(rule, endpoint, func)
        return decorator

    def route_class(self, rule, endpoint, *cls_args, **cls_kwargs):
        def decorator(cls):
            obj = cls(*cls_args, **cls_kwargs)
            self.add_url(rule, endpoint, obj)
            return cls
        return decorator

    def add_url(self, rule, endpoint, func):
        self.url_map.add(Rule(rule, endpoint=endpoint))
        self.view_func.update({endpoint: func})

    def pre_handle(self, request):
        for handler in self.pre_handler:
            handler().pre_process(request)

    def post_handle(self, request, response):
        for handler in self.post_hander:
            handler().post_process(request, response)

    def response_wrapper(self, endpoints, request, values):
        results = self.view_func[endpoints](request, **values) or []
        if isinstance(results, Response):
            return results
        return Response(json.dumps({'error_code': 200, 'error_msg': '', 'error_detail': '', 'results': results}), mimetype='application/json')

    def dispatch_response(self, request):
        adapter = self.url_map.bind_to_environ(request.environ)
        try:
            endpoints, values = adapter.match()
            return self.response_wrapper(endpoints=endpoints, request=request, values=values)
        except Exception as e:
            return handle_except(e, ExceptHandler)

    def wsgi_app(self, environ, start_response):
        request = Request(environ)
        self.pre_handle(request)
        response = self.dispatch_response(request)
        self.post_handle(request, response)
        return response(environ, start_response)

    def __call__(self, environ, start_response):
        return self.wsgi_app(environ, start_response)

def create_app(*args, **kwargs):
    return Spichi(*args, **kwargs)
<|endoftext|>