<commit_before>#!/usr/bin/env python3

import json
import requests
import os
import sys
import re
import shutil
from os.path import basename
from jinja2 import Template
from subprocess import call
from trello import TrelloClient
from zipfile import ZipFile

AUTH_CONFIG = "auth-config.json"
TRELLO_TEMPLATE = "TEMPLATE: PP workflow"

PGDP_URL = "https://www.pgdp.net"

GITHUB_REMOTE = "origin"
GITHUB_BRANCH = "main"

# Set true to assume we'll use ppgen; false otherwise
PPGEN = True

class MakeProject():

    def __init__(self):
        self.dp_base = os.environ["HOME"] + "/dp"
        self.projects_base = self.dp_base + "/pp"
        self.template_dir = self.dp_base + "/util/templates"
        self.params = {}

        self.trello_template = TRELLO_TEMPLATE

        with open(self.dp_base + "/util/" + AUTH_CONFIG) as file:
            self.auth = json.loads(file.read())

    def get_param(self, param_name, prompt_text):
        param_answer = input(prompt_text + ": ")

        if param_name == "project_id":
            param_answer = param_answer.replace("projectID", "")

        self.params[param_name] = param_answer

    def get_params(self):
        self.get_param("project_name", 'Project name, e.g. "missfairfax"')
        self.get_param("project_id", 'Project ID, e.g. "projectID5351bd1e5eca9"')
        self.project_dir = "{}/{}".format(
            self.projects_base, self.params["project_name"])
        #self.params["kindlegen_dir"] = self.dp_base + "/kindlegen"

    def pgdp_login(self):
        payload = {
            "destination": "/c/",
            "userNM": self.auth["pgdp"]["username"],
            "userPW": self.auth["pgdp"]["password"],
        }

        r = requests.post(PGDP_URL + "/c/accounts/login.php", data=payload)
        if r.status_code != 200:
            print("Error: unable to log into DP site")
            sys.exit(1)

        self.dp_cookie = r.headers["Set-Cookie"].split(";")[0]

    def scrape_project_info(self):
        r = requests.post(
            "{0}/c/project.php?id=projectID{1}".format(
                PGDP_URL,
                self.params["project_id"]
            ),
            headers={"Cookie": self.dp_cookie}
        )
        if r.status_code != 200:
            print("Error: unable to retrieve DP project info")
            sys.exit(1)

        html_doc = re.sub(r"\n", "", r.text)

        self.params["title"] = re.sub(
            #
            # This version broke on cavalry. Changing " to <, see if it works
            # r'.*]+>Title	]+>([^"]+)	.*',
            #
            # This version broke on irishjournal, the site updated
            # to use th instead of tr... updating to match site.
            #r'.*]+>Title	]+>([^<]+)	.*',
            #
            r'.*Title	\s*]+>([^<]+)	.*',
            r"\1",
            html_doc
        )

        self.params["author"] = re.sub(
            # This version broke on irishjournal, the site updated
            # to use th instead of tr... updating to match site.
            #r'.*]+>Author	]+>([^<]+)	.*',
            #
            r'.*Author	\s*]+>([^<]+)	.*',
            r"\1",
            html_doc
        )

        #
Forum	Discuss this project (19 replies)

        self.params["forum_link"] = re.sub(
            # This version broke on irishjournal, the site updated
            # to use th instead of tr... updating to match site.
            #r".*]+>Forum	]+>.*",
            #
            #
            r".*Forum	\s*]+>\s*<a href='([^']+)'.*",
            r"\1",
            html_doc
        )

    def create_directories(self):
        os.mkdir(self.project_dir, mode=0o755)
        os.chdir(self.project_dir)
        os.mkdir("images", mode=0o755)
        os.mkdir("illustrations", mode=0o755)
        os.mkdir("pngs", mode=0o755)

    def create_git_repository(self):
        call(["git", "init"])
        call(["git", "add", "."])
        call(["git", "commit", "-m", "Initial import from DP"])
        call(["git", "remote", "add", GITHUB_REMOTE, self.git_remote_url])
        call(["git", "push", "-u", GITHUB_REMOTE, GITHUB_BRANCH])

    def process_template(self, src_filename, dst_filename=None):
        if not dst_filename:
            dst_filename = src_filename
        with open(self.template_dir + "/" + src_filename) as file:
            template = Template(file.read())
        with open(self.project_dir + "/" + dst_filename, "w") as file:
            file.write(template.render(self.params))

    def utf8_conversion(self):
        project_id = self.params["project_id"]
        project_name = self.params["project_name"]
        project_dir = self.project_dir

        input_file = "{}/projectID{}.txt".format(project_dir, project_id)
        output_file = "{}/{}-utf8.txt".format(project_dir, project_name)

        with open(input_file, encoding="latin-1") as file:
            contents = file.read()

        with open(output_file, "w", encoding="utf-8") as file:
            file.write("[** UTF8 preservation hack: Phœnix]\n")
            file.write(contents)

    def copy_text_file(self):
        project_id = self.params["project_id"]
        project_name = self.params["project_name"]
        project_dir = self.project_dir

        input_file = "{}/projectID{}.txt".format(project_dir, project_id)
        if PPGEN:
            output_file = "{}/{}-src.txt".format(project_dir, project_name)
        else:
            output_file = "{}/{}-utf8.txt".format(project_dir, project_name)

        shutil.copyfile(input_file, output_file)

    def make_github_repo(self):
        headers = {
            "Accept": "application/vnd.github.v3+json",
            "Content-Type": "application/json",
        }

        payload = {
            "name": "DP_{}".format(self.params["project_name"]),
            "description": 'DP PP project "{}" ID {}'.format(
                self.params["title"], self.params["project_id"],
            ),
            "private": False,
            "has_issues": False,
            "has_wiki": False,
            "has_downloads": False,
            "auto_init": False,
        }

        auth_data = (
            self.auth["github"]["username"],
            self.auth["github"]["password"],
        )

        r = requests.post("https://api.github.com/user/repos",
                          auth=auth_data, headers=headers,
                          data=json.dumps(payload))
        if r.status_code == 201:
            print("Created GitHub repository")
            json_response = json.loads(r.text)
            self.git_remote_url = json_response["ssh_url"]
        else:
            print("ERROR: GitHub response code {} unexpected.".format(
                r.status_code
            ))

    def make_gitlab_repo(self):
        headers = {
            "Content-Type": "application/json",
            "PRIVATE-TOKEN": self.auth["gitlab"],
        }

        payload = {
            "name": "DP_{}".format(self.params["project_name"]),
            "description": 'DP PP project "{}" ID {}'.format(
                self.params["title"], self.params["project_id"],
            ),
            "visibility": "private",
            "issues_enabled": False,
            "merge_requests_enabled": False,
            "jobs_enabled": False,
            "wiki_enabled": False,
            "snippets_enabled": False,
            "container_registry_enabled": False,
            "shared_runners_enabled": False,
            "lfs_enabled": False,
            "request_access_enabled": False,
        }

        r = requests.post("https://gitlab.com/api/v4/projects",
                          headers=headers,
                          data=json.dumps(payload))
        if r.status_code == 201:
            print("Created Gitlab repository")
            json_response = json.loads(r.text)
            self.git_remote_url = json_response["ssh_url_to_repo"]
        else:
            print("ERROR: Gitlab response code {} unexpected.".format(
                r.status_code
            ))
            print(r.text)

    def make_online_repo(self):
        if self.auth["git_site"] == "github":
            project.make_github_repo()
        elif self.auth["git_site"] == "gitlab":
            project.make_gitlab_repo()

    def make_trello_board(self):
        client = TrelloClient(
            api_key=self.auth["trello"]["api_key"],
            api_secret=self.auth["trello"]["api_secret"],
            token=self.auth["trello"]["token"],
            token_secret=self.auth["trello"]["token_secret"],
        )

        boards = client.list_boards()
        template = None

        for board in boards:
            if board.name == self.trello_template:
                template = board

        new_board = client.add_board(
            "DP: " + self.params["title"],
            source_board=template,
            permission_level="public"
        )
        self.params["trello_url"] = new_board.url
        print("Created Trello board - " + new_board.url)

    def download_text(self):
        print("Downloading text from DP ...", end="", flush=True)
        zipfile = "projectID{}.zip".format(self.params["project_id"])
        url = "{0}/projects/projectID{1}/projectID{1}.zip"
        r = requests.get(url.format(PGDP_URL, self.params["project_id"]),
                         headers={"Cookie": self.dp_cookie})
        with open(zipfile, "wb") as file:
            file.write(r.content)
        self.unzip_file(zipfile, self.project_dir)
        print(" done.")

    def download_images(self):
        print("Downloading images from DP ...", end="", flush=True)
        zipfile = "projectID{}images.zip".format(self.params["project_id"])
        url = "{0}/c/tools/download_images.php?projectid=projectID{1}"
        r = requests.get(url.format(PGDP_URL, self.params["project_id"]),
                         headers={"Cookie": self.dp_cookie})
        with open(zipfile, "wb") as file:
            file.write(r.content)
        self.unzip_file(zipfile, self.project_dir + "/pngs")
        print(" done.")

    def unzip_file(self, filename, path):
        with ZipFile(filename, "r") as zip_ref:
            zip_ref.extractall(path)
        os.remove(filename)

if __name__ == "__main__":

    # By default, create remote resources like Trello & GitHub.
    CREATE_REMOTE = True

    # Process arguments, if any
    if len(sys.argv) >= 2:
        if sys.argv[1] == "-h" or sys.argv[1] == "--help":
            print(f"Usage: {sys.argv[0]} [<option(s)>]")
            print("    -h, --help: print this help")
            print("    -l, --local: only create local resources (for debug)")
            sys.exit(1)
        elif sys.argv[1] == "-l" or sys.argv[1] == "--local":
            CREATE_REMOTE = False

    project = MakeProject()
    project.get_params()
    project.pgdp_login()
    project.scrape_project_info()
    project.create_directories()
    project.download_text()
    project.download_images()

    # No longer needed - UTF8 is now the default
    #project.utf8_conversion()

    # Make a copy of the text to work on
    project.copy_text_file()

    if CREATE_REMOTE:
        project.make_online_repo()
        project.make_trello_board()

    project.process_template("Makefile")
    project.process_template("README.md")
    project.process_template("pp-gitignore", ".gitignore")

    if CREATE_REMOTE:
        # This is only done if remote, because it will try to push.
        project.create_git_repository()
<commit_msg>Use new ppgen Trello board as template<commit_after>#!/usr/bin/env python3

import json
import requests
import os
import sys
import re
import shutil
from os.path import basename
from jinja2 import Template
from subprocess import call
from trello import TrelloClient
from zipfile import ZipFile

AUTH_CONFIG = "auth-config.json"
TRELLO_TEMPLATE = "TEMPLATE: PPgen workflow"

PGDP_URL = "https://www.pgdp.net"

GITHUB_REMOTE = "origin"
GITHUB_BRANCH = "main"

# Set true to assume we'll use ppgen; false otherwise
PPGEN = True

class MakeProject():

    def __init__(self):
        self.dp_base = os.environ["HOME"] + "/dp"
        self.projects_base = self.dp_base + "/pp"
        self.template_dir = self.dp_base + "/util/templates"
        self.params = {}

        self.trello_template = TRELLO_TEMPLATE

        with open(self.dp_base + "/util/" + AUTH_CONFIG) as file:
            self.auth = json.loads(file.read())

    def get_param(self, param_name, prompt_text):
        param_answer = input(prompt_text + ": ")

        if param_name == "project_id":
            param_answer = param_answer.replace("projectID", "")

        self.params[param_name] = param_answer

    def get_params(self):
        self.get_param("project_name", 'Project name, e.g. "missfairfax"')
        self.get_param("project_id", 'Project ID, e.g. "projectID5351bd1e5eca9"')
        self.project_dir = "{}/{}".format(
            self.projects_base, self.params["project_name"])
        #self.params["kindlegen_dir"] = self.dp_base + "/kindlegen"

    def pgdp_login(self):
        payload = {
            "destination": "/c/",
            "userNM": self.auth["pgdp"]["username"],
            "userPW": self.auth["pgdp"]["password"],
        }

        r = requests.post(PGDP_URL + "/c/accounts/login.php", data=payload)
        if r.status_code != 200:
            print("Error: unable to log into DP site")
            sys.exit(1)

        self.dp_cookie = r.headers["Set-Cookie"].split(";")[0]

    def scrape_project_info(self):
        r = requests.post(
            "{0}/c/project.php?id=projectID{1}".format(
                PGDP_URL,
                self.params["project_id"]
            ),
            headers={"Cookie": self.dp_cookie}
        )
        if r.status_code != 200:
            print("Error: unable to retrieve DP project info")
            sys.exit(1)

        html_doc = re.sub(r"\n", "", r.text)

        self.params["title"] = re.sub(
            #
            # This version broke on cavalry. Changing " to <, see if it works
            # r'.*]+>Title	]+>([^"]+)	.*',
            #
            # This version broke on irishjournal, the site updated
            # to use th instead of tr... updating to match site.
            #r'.*]+>Title	]+>([^<]+)	.*',
            #
            r'.*Title	\s*]+>([^<]+)	.*',
            r"\1",
            html_doc
        )

        self.params["author"] = re.sub(
            # This version broke on irishjournal, the site updated
            # to use th instead of tr... updating to match site.
            #r'.*]+>Author	]+>([^<]+)	.*',
            #
            r'.*Author	\s*]+>([^<]+)	.*',
            r"\1",
            html_doc
        )

        #
Forum	Discuss this project (19 replies)

        self.params["forum_link"] = re.sub(
            # This version broke on irishjournal, the site updated
            # to use th instead of tr... updating to match site.
            #r".*]+>Forum	]+>.*",
            #
            #
            r".*Forum	\s*]+>\s*<a href='([^']+)'.*",
            r"\1",
            html_doc
        )

    def create_directories(self):
        os.mkdir(self.project_dir, mode=0o755)
        os.chdir(self.project_dir)
        os.mkdir("images", mode=0o755)
        os.mkdir("illustrations", mode=0o755)
        os.mkdir("pngs", mode=0o755)

    def create_git_repository(self):
        call(["git", "init"])
        call(["git", "add", "."])
        call(["git", "commit", "-m", "Initial import from DP"])
        call(["git", "remote", "add", GITHUB_REMOTE, self.git_remote_url])
        call(["git", "push", "-u", GITHUB_REMOTE, GITHUB_BRANCH])

    def process_template(self, src_filename, dst_filename=None):
        if not dst_filename:
            dst_filename = src_filename
        with open(self.template_dir + "/" + src_filename) as file:
            template = Template(file.read())
        with open(self.project_dir + "/" + dst_filename, "w") as file:
            file.write(template.render(self.params))

    def utf8_conversion(self):
        project_id = self.params["project_id"]
        project_name = self.params["project_name"]
        project_dir = self.project_dir

        input_file = "{}/projectID{}.txt".format(project_dir, project_id)
        output_file = "{}/{}-utf8.txt".format(project_dir, project_name)

        with open(input_file, encoding="latin-1") as file:
            contents = file.read()

        with open(output_file, "w", encoding="utf-8") as file:
            file.write("[** UTF8 preservation hack: Phœnix]\n")
            file.write(contents)

    def copy_text_file(self):
        project_id = self.params["project_id"]
        project_name = self.params["project_name"]
        project_dir = self.project_dir

        input_file = "{}/projectID{}.txt".format(project_dir, project_id)
        if PPGEN:
            output_file = "{}/{}-src.txt".format(project_dir, project_name)
        else:
            output_file = "{}/{}-utf8.txt".format(project_dir, project_name)

        shutil.copyfile(input_file, output_file)

    def make_github_repo(self):
        headers = {
            "Accept": "application/vnd.github.v3+json",
            "Content-Type": "application/json",
        }

        payload = {
            "name": "DP_{}".format(self.params["project_name"]),
            "description": 'DP PP project "{}" ID {}'.format(
                self.params["title"], self.params["project_id"],
            ),
            "private": False,
            "has_issues": False,
            "has_wiki": False,
            "has_downloads": False,
            "auto_init": False,
        }

        auth_data = (
            self.auth["github"]["username"],
            self.auth["github"]["password"],
        )

        r = requests.post("https://api.github.com/user/repos",
                          auth=auth_data, headers=headers,
                          data=json.dumps(payload))
        if r.status_code == 201:
            print("Created GitHub repository")
            json_response = json.loads(r.text)
            self.git_remote_url = json_response["ssh_url"]
        else:
            print("ERROR: GitHub response code {} unexpected.".format(
                r.status_code
            ))

    def make_gitlab_repo(self):
        headers = {
            "Content-Type": "application/json",
            "PRIVATE-TOKEN": self.auth["gitlab"],
        }

        payload = {
            "name": "DP_{}".format(self.params["project_name"]),
            "description": 'DP PP project "{}" ID {}'.format(
                self.params["title"], self.params["project_id"],
            ),
            "visibility": "private",
            "issues_enabled": False,
            "merge_requests_enabled": False,
            "jobs_enabled": False,
            "wiki_enabled": False,
            "snippets_enabled": False,
            "container_registry_enabled": False,
            "shared_runners_enabled": False,
            "lfs_enabled": False,
            "request_access_enabled": False,
        }

        r = requests.post("https://gitlab.com/api/v4/projects",
                          headers=headers,
                          data=json.dumps(payload))
        if r.status_code == 201:
            print("Created Gitlab repository")
            json_response = json.loads(r.text)
            self.git_remote_url = json_response["ssh_url_to_repo"]
        else:
            print("ERROR: Gitlab response code {} unexpected.".format(
                r.status_code
            ))
            print(r.text)

    def make_online_repo(self):
        if self.auth["git_site"] == "github":
            project.make_github_repo()
        elif self.auth["git_site"] == "gitlab":
            project.make_gitlab_repo()

    def make_trello_board(self):
        client = TrelloClient(
            api_key=self.auth["trello"]["api_key"],
            api_secret=self.auth["trello"]["api_secret"],
            token=self.auth["trello"]["token"],
            token_secret=self.auth["trello"]["token_secret"],
        )

        boards = client.list_boards()
        template = None

        for board in boards:
            if board.name == self.trello_template:
                template = board

        new_board = client.add_board(
            "DP: " + self.params["title"],
            source_board=template,
            permission_level="public"
        )
        self.params["trello_url"] = new_board.url
        print("Created Trello board - " + new_board.url)

    def download_text(self):
        print("Downloading text from DP ...", end="", flush=True)
        zipfile = "projectID{}.zip".format(self.params["project_id"])
        url = "{0}/projects/projectID{1}/projectID{1}.zip"
        r = requests.get(url.format(PGDP_URL, self.params["project_id"]),
                         headers={"Cookie": self.dp_cookie})
        with open(zipfile, "wb") as file:
            file.write(r.content)
        self.unzip_file(zipfile, self.project_dir)
        print(" done.")

    def download_images(self):
        print("Downloading images from DP ...", end="", flush=True)
        zipfile = "projectID{}images.zip".format(self.params["project_id"])
        url = "{0}/c/tools/download_images.php?projectid=projectID{1}"
        r = requests.get(url.format(PGDP_URL, self.params["project_id"]),
                         headers={"Cookie": self.dp_cookie})
        with open(zipfile, "wb") as file:
            file.write(r.content)
        self.unzip_file(zipfile, self.project_dir + "/pngs")
        print(" done.")

    def unzip_file(self, filename, path):
        with ZipFile(filename, "r") as zip_ref:
            zip_ref.extractall(path)
        os.remove(filename)

if __name__ == "__main__":

    # By default, create remote resources like Trello & GitHub.
    CREATE_REMOTE = True

    # Process arguments, if any
    if len(sys.argv) >= 2:
        if sys.argv[1] == "-h" or sys.argv[1] == "--help":
            print(f"Usage: {sys.argv[0]} [<option(s)>]")
            print("    -h, --help: print this help")
            print("    -l, --local: only create local resources (for debug)")
            sys.exit(1)
        elif sys.argv[1] == "-l" or sys.argv[1] == "--local":
            CREATE_REMOTE = False

    project = MakeProject()
    project.get_params()
    project.pgdp_login()
    project.scrape_project_info()
    project.create_directories()
    project.download_text()
    project.download_images()

    # No longer needed - UTF8 is now the default
    #project.utf8_conversion()

    # Make a copy of the text to work on
    project.copy_text_file()

    if CREATE_REMOTE:
        project.make_online_repo()
        project.make_trello_board()

    project.process_template("Makefile")
    project.process_template("README.md")
    project.process_template("pp-gitignore", ".gitignore")

    if CREATE_REMOTE:
        # This is only done if remote, because it will try to push.
        project.create_git_repository()
<|endoftext|>


<commit_before>from django.contrib.sessions.backends.db import SessionStore
from django.contrib.sessions.models import Session
from django.conf import settings

def change_server_time(time):

    #Create a new session
    s = SessionStore(session_key='')
    s.save()
    old_s = Session.objects.get(session_key=s.session_key)

    #Copy it to a column with an id fixed
    new_session = Session(session_key=settings.SESSION_ID_SIMU, session_data=old_s.session_data,
                          expire_date=old_s.expire_date)
    new_session.save()

    #Change the current date
    session_dictionary = SessionStore(session_key=settings.SESSION_ID_SIMU)
    session_dictionary['current_date'] = time
    session_dictionary.save()<commit_msg>Correction du temps de simulation<commit_after>from django.contrib.sessions.backends.db import SessionStore
from django.contrib.sessions.models import Session
from django.conf import settings

class SimulationTime:

    session = None

    @staticmethod
    def change_server_time(time):

        if SimulationTime.session is None:
            #Create a new session
            s = SessionStore(session_key='')
            s.save()
            old_s = Session.objects.get(session_key=s.session_key)

            #Copy it to a column with an id fixed
            new_session = Session(session_key=settings.SESSION_ID_SIMU, session_data=old_s.session_data,
                                  expire_date=old_s.expire_date)
            new_session.save()
            #Change the current date
            session_dictionary = SessionStore(session_key=settings.SESSION_ID_SIMU)
            SimulationTime.session = session_dictionary

        SimulationTime.session['current_date'] = time
        SimulationTime.session.save()<|endoftext|>


<commit_before># -*- coding: UTF8 -*-
# ***** BEGIN LICENSE BLOCK *****
# Sconspiracy - Copyright (C) IRCAD, 2004-2010.
# Distributed under the terms of the BSD Licence as
# published by the Open Source Initiative.
# ****** END LICENSE BLOCK ******

import exceptions
import os
import re

from os.path import join, isfile, normpath

#------------------------------------------------------------------------------
def get_re_from_extensions(extensions):
    """ Return a compiled regex from a list of extensions or a regex

    Example : for ['cpp','hxx','c'] the returned regex is '.*\\.(cpp|hxx|c)$'
    and matches strings that ends with '.cpp', '.hxx' or '.c'
    """
    if not extensions:
        reg = '.*'
    elif isinstance(extensions, list):
        reg = '.*\.({0})$'.format('|'.join(extensions))
    else:
        reg = extensions
    return re.compile(reg)

#------------------------------------------------------------------------------
def remove_vcs_dirs(dirs):
    """ Remove vcs dirs from a list """
    import racy.renv.constants as constants
    for dir in constants.VCS_DIRS:
        if dir in dirs:
            dirs.remove(dir)

#------------------------------------------------------------------------------
def _match_any(v, values):
    """Returns True if v is a value in values. If values contains strings,
    then the strings has to be in lowercase.
    """
    if isinstance(v, basestring): v = v.lower()
    return v in values

#------------------------------------------------------------------------------
def is_false(v):
    """Returns True if v is a value in ['no', 'false', 'off', 0, False, None]"""
    return _match_any(v, ['no', 'false', 'off', 0, False, None])

#------------------------------------------------------------------------------
def is_true(v):
    """Returns True if v is a value in ['yes', 'true', 'on', 1, True]"""
    return _match_any(v, ['yes', 'true', 'on', 1, True])

#------------------------------------------------------------------------------
def DeepGlob(extensions, src_dir= '.', replace_dir = '', return_orig = False,
        invert_matches = False, filter = lambda x:True):
    """ Do a deep Glob, lookin up for file matching extensions, in
    src_dir (default '.'), replacing srd_dir by replace_dir if given.

    if invert_matches is True, DeepGlob will return files that doesn't
    match with extensions

    Accept regex as extensions (don't use '^')
    if extensions is None, match all files
    """
    if is_iterable(src_dir):
        kwargs = {
        'extensions'     : extensions,
        'src_dir'        : None,
        'replace_dir'    : None,
        'return_orig'    : return_orig,
        'invert_matches' : invert_matches,
        'filter'         : filter
        }
        result = []
        if not is_iterable(replace_dir):
            replace_dir = [replace_dir] * len(src_dir)

        for dir, replace in zip(src_dir, replace_dir):
            kwargs['src_dir']     = dir
            kwargs['replace_dir'] = replace
            result += DeepGlob(**kwargs)
        if return_orig:
            cat = lambda a,b: (a[0]+b[0], a[1]+b[1])
            if len(result)>1:
                result = reduce(cat, result)

    else:
        replace_dir = normpath(replace_dir)
        src_dir     = normpath(src_dir)
        regex       = get_re_from_extensions(extensions)
        file_match  = regex.match # cache the function
        result      = []

        if invert_matches:
            file_match = lambda x: not file_match(x)

        for root, dirs, files in os.walk(src_dir, topdown=True):
            #don't walk in vcs dirs
            remove_vcs_dirs(dirs)
            result += [ join(root, name) for name in files if file_match(name) ]
            result = [res for res in result if filter(res)]

        if replace_dir:
            result_orig = result
            norm = lambda f:normpath(f).replace(src_dir, replace_dir, 1)
            result = map(norm, result)

        if return_orig and replace_dir:
            result = result_orig, result

    return result

#------------------------------------------------------------------------------
def copy (src, dst, preserve_links=True, preserve_relative_links_only = True):
    #never true if symlinks not supported
    import shutil
    import os
    action = None

    if preserve_links and os.path.islink(src):
        linktarget = os.readlink( src )

        if preserve_relative_links_only and os.path.isabs(linktarget):
            action = shutil.copy
        else:
            src = linktarget
            action = os.symlink

        if os.path.exists(dst):
            os.unlink(dst)

        #hack to manage some symlinks errors
        try:
            action(src, dst)
        except exceptions.OSError, e:
            if not e.strerror == 'File exists':
                raise e
    else:
        shutil.copy(src, dst)

#------------------------------------------------------------------------------
def get_first_existing_file(files):
    """Returns first existing file from files. If an item of files is a list,
    the list items are first joined."""
    for file in files:
        if hasattr(file,'__iter__'):
            file = join(*file)
        if isfile(file):
            return file

#------------------------------------------------------------------------------
def tupleize(iterable):
    """Recursively <tupleize> an iterable to obtain a hashable object"""
    if hasattr(iterable, "__iter__"):
        if isinstance(iterable, dict):
            iterable = iterable.items()
        return tuple( tupleize(el) for el in iterable )
    return iterable

#------------------------------------------------------------------------------
def memoize(f, cache={}):
    """Memoization decorator. Store the computed values in 'cache'. If cache is
    not specified, every results will be store in the same dict (the one in the
    decorator's defautls value)
    *WARNING* : If tuple is used instead of tupleize, a parameter in args or
    kwargs or is unhashable, the decorated function will raise a TypeError
    """
    def g(*args, **kwargs):
        key = ( f, tupleize(args), tupleize(kwargs.items()) )
        if key not in cache:
            cache[key] = f(*args, **kwargs)
        return cache[key]
    g.__name__ = "@memoize({0})".format(f.__name__)
    return g

def cached_property(f):
    """Returns a cached property that is computed by function f. Be carefull
    with setter and deleter uses (they shouldn't be used with a
    cached_property).
    """
    def func(self):
        prefix = '__racy_internal__cached_property'
        fullname = "_".join([prefix, f.__name__])
        if hasattr(self, fullname):
            return getattr(self, fullname)
        res = f(self)
        setattr(self, fullname, res)
        return res

    func.__name__ = f.__name__
    #p = property(memoize(f))
    # do not memoized anymore for property -> optimized
    p = property(func)
    return p

def run_once(f):
    """This decorator ensure that an instance method is executed once
    and return ever the same result, without any regards on arguments
    """
    def func(self, *a, **k):
        prefix = '__racy_internal__used'
        fullname = "_".join([prefix, f.__name__])
        used = getattr(self, fullname, 0)
        res = None
        if used < 1:
            res = f(self, *a, **k)
        setattr(self, fullname, used+1)
        return res
    return func

#------------------------------------------------------------------------------
def time_it(func):
    """Internal use, class method timing decorator"""
    import time
    func.__tot  = 0.
    func.__call = 0
    def _inner(*args, **kw):
        func.__call += 1
        start = time.time()
        res = func(*args, **kw)
        timed = time.time() - start
        func.__tot += timed

        msg = '{0:20}: {1:15}  avg: {2:15}  tot: {3:15}  calls: {4:6}'
        msg = msg.format(func.__name__, timed,
                func.__tot/func.__call, func.__tot, func.__call)
        print msg
        return res
    return _inner

def merge_lists_of_dict(dict_dest, dict_src):
    """Merge two dict of list in dict_dest"""
    for el, val in dict_src.items():
        dict_dest[el] += val

#------------------------------------------------------------------------------
def is_iterable(obj):
    return hasattr(obj, "__iter__")
def iterize(obj):
    return obj if is_iterable(obj) else [obj]

#------------------------------------------------------------------------------
def put_file_content(filename, content):
    with open(filename, 'w') as f:
        f.write(content)

#------------------------------------------------------------------------------
def get_file_content(filename):
    read_data = None
    with open(filename, 'r') as f:
        read_data = f.read()
    return read_data

#------------------------------------------------------------------------------
class ListFromStr(list):
    """Build a list from a string if it contain a list. Examples :
       '[foo,bar,6]' gives ['foo','bar','6']
       'foo,bar,6' gives []
    """
    def __init__(self, s):
        super(ListFromStr, self).__init__()
        if s.startswith('[') and s.endswith(']'):
            self[:] = s[1:-1].split(',')

    @staticmethod
    def get_list(s):
       """Return a list from a string. the string must contain [ and ] to
       define a list, else the string will be returned as is.
       """
       lst = ListFromStr(s)
       if not lst:
           lst = s
       return lst

#------------------------------------------------------------------------------
def uniq(iterable):
    """Return a list from iterable without duplicates, keep the order of
    appearance of the iterable elements"""
    seen = set()
    add  = seen.add
    return [x for x in iterable if not (x in seen or add(x))]

#------------------------------------------------------------------------------

class Version(str):
    """This class provide a way to compare/normalize versions strings.
    Version format is [name]v1<sep>v2<sep>...<sep>vn where :
      - v1 ... vn are components of version (ex: 5 and 4 for 5.4)
      - <sep> is a separating char from [-_.]
      - [name] is an optionnal name composed with [a-zA-Z-_.]

    [name] is ignore for comparison.

    examples of True assertions:
     - Version('gcc4.3') < Version('gcc4.4')
     - Version('0.9') < Version('1')
     - Version('1.9') < Version('1.10')
    """

    separator = re.compile('[-_.]')

    @property
    def dotted (self):
        return self.separator.sub('.', self)

    @property
    def dashed (self):
        return self.separator.sub('-', self)

    @property
    def underscored (self):
        return self.separator.sub('_', self)

    @property
    def normalized (self):
        return self.dashed

    @property
    def to_tuple(self):
        filtered = re.sub('^[a-zA-Z-_.]+','',self)
        splited = self.separator.split(filtered)
        return tuple( int(el) for el in splited )

    def __str__(self):
        return self.normalized

    def __repr__(self):
        return self.normalized.join(["'", "'"])

    def __lt__(self, other):
        if isinstance(other, Version):
            return self.to_tuple < other.to_tuple
        str.__lt__(self, other)

    def __le__(self, other):
        if isinstance(other, Version):
            return self.to_tuple <= other.to_tuple
        str.__le__(self, other)

    def __eq__(self, other):
        if isinstance(other, Version):
            return self.to_tuple == other.to_tuple
        str.__eq__(self, other)

    def __ne__(self, other):
        if isinstance(other, Version):
            return self.to_tuple != other.to_tuple
        str.__ne__(self, other)

    def __gt__(self, other):
        if isinstance(other, Version):
            return self.to_tuple > other.to_tuple
        str.__gt__(self, other)

    def __ge__(self, other):
        if isinstance(other, Version):
            return self.to_tuple >= other.to_tuple
        str.__ge__(self, other)

<commit_msg>Added <decorator> decorator<commit_after># -*- coding: UTF8 -*-
# ***** BEGIN LICENSE BLOCK *****
# Sconspiracy - Copyright (C) IRCAD, 2004-2010.
# Distributed under the terms of the BSD Licence as
# published by the Open Source Initiative.
# ****** END LICENSE BLOCK ******

import exceptions
import os
import re

from os.path import join, isfile, normpath

#------------------------------------------------------------------------------

def decorator(_decorator):
    """This decorator can be used to turn simple functions
    into well-behaved decorators, so long as the decorators
    are fairly simple. If a decorator expects a function and
    returns a function (no descriptors), and if it doesn't
    modify function attributes or docstring, then it is
    eligible to use this. Simply apply @simple_decorator to
    your decorator and it will automatically preserve the
    docstring and function attributes of functions to which
    it is applied."""

    def copy_attributes(src, dst):
        if not isinstance(dst, property):
            dst.__name__ = src.__name__
            dst.__doc__  = src.__doc__
            dst.__dict__.update(src.__dict__)

    def new_decorator(f):
        g = _decorator(f)
        copy_attributes(f,g)
        return g

    copy_attributes(_decorator ,new_decorator)
    return new_decorator

#------------------------------------------------------------------------------
def get_re_from_extensions(extensions):
    """ Return a compiled regex from a list of extensions or a regex

    Example : for ['cpp','hxx','c'] the returned regex is '.*\\.(cpp|hxx|c)$'
    and matches strings that ends with '.cpp', '.hxx' or '.c'
    """
    if not extensions:
        reg = '.*'
    elif isinstance(extensions, list):
        reg = '.*\.({0})$'.format('|'.join(extensions))
    else:
        reg = extensions
    return re.compile(reg)

#------------------------------------------------------------------------------
def remove_vcs_dirs(dirs):
    """ Remove vcs dirs from a list """
    import racy.renv.constants as constants
    for dir in constants.VCS_DIRS:
        if dir in dirs:
            dirs.remove(dir)

#------------------------------------------------------------------------------
def _match_any(v, values):
    """Returns True if v is a value in values. If values contains strings,
    then the strings has to be in lowercase.
    """
    if isinstance(v, basestring): v = v.lower()
    return v in values

#------------------------------------------------------------------------------
def is_false(v):
    """Returns True if v is a value in ['no', 'false', 'off', 0, False, None]"""
    return _match_any(v, ['no', 'false', 'off', 0, False, None])

#------------------------------------------------------------------------------
def is_true(v):
    """Returns True if v is a value in ['yes', 'true', 'on', 1, True]"""
    return _match_any(v, ['yes', 'true', 'on', 1, True])

#------------------------------------------------------------------------------
def DeepGlob(extensions, src_dir= '.', replace_dir = '', return_orig = False,
        invert_matches = False, filter = lambda x:True):
    """ Do a deep Glob, lookin up for file matching extensions, in
    src_dir (default '.'), replacing srd_dir by replace_dir if given.

    if invert_matches is True, DeepGlob will return files that doesn't
    match with extensions

    Accept regex as extensions (don't use '^')
    if extensions is None, match all files
    """
    if is_iterable(src_dir):
        kwargs = {
        'extensions'     : extensions,
        'src_dir'        : None,
        'replace_dir'    : None,
        'return_orig'    : return_orig,
        'invert_matches' : invert_matches,
        'filter'         : filter
        }
        result = []
        if not is_iterable(replace_dir):
            replace_dir = [replace_dir] * len(src_dir)

        for dir, replace in zip(src_dir, replace_dir):
            kwargs['src_dir']     = dir
            kwargs['replace_dir'] = replace
            result += DeepGlob(**kwargs)
        if return_orig:
            cat = lambda a,b: (a[0]+b[0], a[1]+b[1])
            if len(result)>1:
                result = reduce(cat, result)

    else:
        replace_dir = normpath(replace_dir)
        src_dir     = normpath(src_dir)
        regex       = get_re_from_extensions(extensions)
        file_match  = regex.match # cache the function
        result      = []

        if invert_matches:
            file_match = lambda x: not file_match(x)

        for root, dirs, files in os.walk(src_dir, topdown=True):
            #don't walk in vcs dirs
            remove_vcs_dirs(dirs)
            result += [ join(root, name) for name in files if file_match(name) ]
            result = [res for res in result if filter(res)]

        if replace_dir:
            result_orig = result
            norm = lambda f:normpath(f).replace(src_dir, replace_dir, 1)
            result = map(norm, result)

        if return_orig and replace_dir:
            result = result_orig, result

    return result

#------------------------------------------------------------------------------
def copy (src, dst, preserve_links=True, preserve_relative_links_only = True):
    #never true if symlinks not supported
    import shutil
    import os
    action = None

    if preserve_links and os.path.islink(src):
        linktarget = os.readlink( src )

        if preserve_relative_links_only and os.path.isabs(linktarget):
            action = shutil.copy
        else:
            src = linktarget
            action = os.symlink

        if os.path.exists(dst):
            os.unlink(dst)

        #hack to manage some symlinks errors
        try:
            action(src, dst)
        except exceptions.OSError, e:
            if not e.strerror == 'File exists':
                raise e
    else:
        shutil.copy(src, dst)

#------------------------------------------------------------------------------
def get_first_existing_file(files):
    """Returns first existing file from files. If an item of files is a list,
    the list items are first joined."""
    for file in files:
        if hasattr(file,'__iter__'):
            file = join(*file)
        if isfile(file):
            return file

#------------------------------------------------------------------------------
def tupleize(iterable):
    """Recursively <tupleize> an iterable to obtain a hashable object"""
    if hasattr(iterable, "__iter__"):
        if isinstance(iterable, dict):
            iterable = iterable.items()
        return tuple( tupleize(el) for el in iterable )
    return iterable

#------------------------------------------------------------------------------
@decorator
def memoize(f, cache={}):
    """Memoization decorator. Store the computed values in 'cache'. If cache is
    not specified, every results will be store in the same dict (the one in the
    decorator's defautls value)
    *WARNING* : If tuple is used instead of tupleize, a parameter in args or
    kwargs or is unhashable, the decorated function will raise a TypeError
    """
    def g(*args, **kwargs):
        key = ( f, tupleize(args), tupleize(kwargs.items()) )
        if key not in cache:
            cache[key] = f(*args, **kwargs)
        return cache[key]
    return g

@decorator
def cached_property(f):
    """Returns a cached property that is computed by function f. Be carefull
    with setter and deleter uses (they shouldn't be used with a
    cached_property).
    """
    def func(self):
        prefix = '__racy_internal__cached_property'
        fullname = "_".join([prefix, f.__name__])
        if hasattr(self, fullname):
            return getattr(self, fullname)
        res = f(self)
        setattr(self, fullname, res)
        return res

    func.__name__ = f.__name__
    #p = property(memoize(f))
    # not memoized anymore for property -> optimized
    p = property(func)
    return p

@decorator
def run_once(f):
    """This decorator ensure that an instance method is executed once
    and return ever the same result, without any regards on arguments
    """
    def func(self, *a, **k):
        prefix = '__racy_internal__used'
        fullname = "_".join([prefix, f.__name__])
        used = getattr(self, fullname, 0)
        res = None
        if used < 1:
            res = f(self, *a, **k)
        setattr(self, fullname, used+1)
        return res
    return func

#------------------------------------------------------------------------------
@decorator
def time_it(func):
    """Internal use, class method timing decorator"""
    import time
    func.__tot  = 0.
    func.__call = 0
    def _inner(*args, **kw):
        func.__call += 1
        start = time.time()
        res = func(*args, **kw)
        timed = time.time() - start
        func.__tot += timed

        msg = '{0:20}: {1:15}  avg: {2:15}  tot: {3:15}  calls: {4:6}'
        msg = msg.format(func.__name__, timed,
                func.__tot/func.__call, func.__tot, func.__call)
        print msg
        return res
    return _inner

def merge_lists_of_dict(dict_dest, dict_src):
    """Merge two dict of list in dict_dest"""
    for el, val in dict_src.items():
        dict_dest[el] += val

#------------------------------------------------------------------------------
def is_iterable(obj):
    return hasattr(obj, "__iter__")
def iterize(obj):
    return obj if is_iterable(obj) else [obj]

#------------------------------------------------------------------------------
def put_file_content(filename, content):
    with open(filename, 'w') as f:
        f.write(content)

#------------------------------------------------------------------------------
def get_file_content(filename):
    read_data = None
    with open(filename, 'r') as f:
        read_data = f.read()
    return read_data

#------------------------------------------------------------------------------
class ListFromStr(list):
    """Build a list from a string if it contain a list. Examples :
       '[foo,bar,6]' gives ['foo','bar','6']
       'foo,bar,6' gives []
    """
    def __init__(self, s):
        super(ListFromStr, self).__init__()
        if s.startswith('[') and s.endswith(']'):
            self[:] = s[1:-1].split(',')

    @staticmethod
    def get_list(s):
       """Return a list from a string. the string must contain [ and ] to
       define a list, else the string will be returned as is.
       """
       lst = ListFromStr(s)
       if not lst:
           lst = s
       return lst

#------------------------------------------------------------------------------
def uniq(iterable):
    """Return a list from iterable without duplicates, keep the order of
    appearance of the iterable elements"""
    seen = set()
    add  = seen.add
    return [x for x in iterable if not (x in seen or add(x))]

#------------------------------------------------------------------------------

class Version(str):
    """This class provide a way to compare/normalize versions strings.
    Version format is [name]v1<sep>v2<sep>...<sep>vn where :
      - v1 ... vn are components of version (ex: 5 and 4 for 5.4)
      - <sep> is a separating char from [-_.]
      - [name] is an optionnal name composed with [a-zA-Z-_.]

    [name] is ignore for comparison.

    examples of True assertions:
     - Version('gcc4.3') < Version('gcc4.4')
     - Version('0.9') < Version('1')
     - Version('1.9') < Version('1.10')
    """

    separator = re.compile('[-_.]')

    @property
    def dotted (self):
        return self.separator.sub('.', self)

    @property
    def dashed (self):
        return self.separator.sub('-', self)

    @property
    def underscored (self):
        return self.separator.sub('_', self)

    @property
    def normalized (self):
        return self.dashed

    @property
    def to_tuple(self):
        filtered = re.sub('^[a-zA-Z-_.]+','',self)
        splited = self.separator.split(filtered)
        return tuple( int(el) for el in splited )

    def __str__(self):
        return self.normalized

    def __repr__(self):
        return self.normalized.join(["'", "'"])

    def __lt__(self, other):
        if isinstance(other, Version):
            return self.to_tuple < other.to_tuple
        str.__lt__(self, other)

    def __le__(self, other):
        if isinstance(other, Version):
            return self.to_tuple <= other.to_tuple
        str.__le__(self, other)

    def __eq__(self, other):
        if isinstance(other, Version):
            return self.to_tuple == other.to_tuple
        str.__eq__(self, other)

    def __ne__(self, other):
        if isinstance(other, Version):
            return self.to_tuple != other.to_tuple
        str.__ne__(self, other)

    def __gt__(self, other):
        if isinstance(other, Version):
            return self.to_tuple > other.to_tuple
        str.__gt__(self, other)

    def __ge__(self, other):
        if isinstance(other, Version):
            return self.to_tuple >= other.to_tuple
        str.__ge__(self, other)

<|endoftext|>


<commit_before>import asyncio
from enum import Enum, unique
from logging import getLogger
from typing import Optional

from pika.channel import Channel
from .common import BaseChannel, FutureStore
from .message import Message
from .tools import create_future

log = getLogger(__name__)

@unique
class ExchangeType(Enum):
    FANOUT = 'fanout'
    DIRECT = 'direct'
    TOPIC = 'topic'
    HEADERS = 'headers'
    X_DELAYED_MESSAGE = 'x-delayed-message'

class Exchange(BaseChannel):
    """ Exchange abstraction """

    __slots__ = (
        'name', '__type', '__publish_method', 'arguments', 'durable',
        'auto_delete', 'internal', 'passive', '_channel'
    )

    def __init__(self, channel: Channel, publish_method, name: str,
                 type: ExchangeType=ExchangeType.DIRECT, *, auto_delete: Optional[bool],
                 durable: Optional[bool], internal: Optional[bool], passive: Optional[bool],
                 arguments: dict=None, loop: asyncio.AbstractEventLoop,
                 future_store: FutureStore):

        super().__init__(loop, future_store)

        if not arguments:
            arguments = {}

        self._channel = channel
        self.__publish_method = publish_method
        self.__type = type.value
        self.name = name
        self.auto_delete = auto_delete
        self.durable = durable
        self.internal = internal
        self.passive = passive
        self.arguments = arguments

    def __str__(self):
        return self.name

    def __repr__(self):
        return "<Exchange(%s): auto_delete=%s, durable=%s, arguments=%r)>" % (
            self, self.auto_delete, self.durable, self.arguments
        )

    @BaseChannel._ensure_channel_is_open
    def declare(self, timeout: int=None):
        future = self._create_future(timeout=timeout)

        self._channel.exchange_declare(
            future.set_result,
            self.name,
            self.__type,
            durable=self.durable,
            auto_delete=self.auto_delete,
            internal=self.internal,
            passive=self.passive,
            arguments=self.arguments,
        )

        return future

    @BaseChannel._ensure_channel_is_open
    def bind(self, exchange,
             routing_key: str='', *, arguments=None, timeout: int = None) -> asyncio.Future:

        """ A binding can also be a relationship between two exchanges. This can be
        simply read as: this exchange is interested in messages from another exchange.

        Bindings can take an extra routing_key parameter. To avoid the confusion
        with a basic_publish parameter we're going to call it a binding key.

        .. code-block:: python

            client = await connect()

            routing_key = 'simple_routing_key'
            src_exchange_name = "source_exchange"
            dest_exchange_name = "destination_exchange"

            channel = await client.channel()
            src_exchange = await channel.declare_exchange(src_exchange_name, auto_delete=True)
            dest_exchange = await channel.declare_exchange(dest_exchange_name, auto_delete=True)
            queue = await channel.declare_queue(auto_delete=True)

            await queue.bind(dest_exchange, routing_key)
            await dest_exchange.bind(src_exchange, routing_key)

        :param exchange: :class:`aio_pika.exchange.Exchange` instance
        :param routing_key: routing key
        :param arguments: additional arguments (will be passed to `pika`)
        :param timeout: execution timeout
        :return: :class:`None`
        """

        log.debug(
            "Binding exchange %r to exchange %r, routing_key=%r, arguments=%r",
            self, exchange, routing_key, arguments
        )

        f = self._create_future(timeout)

        self._channel.exchange_bind(
            f.set_result,
            self.name,
            exchange.name,
            routing_key=routing_key,
            arguments=arguments
        )

        return f

    @BaseChannel._ensure_channel_is_open
    def unbind(self, exchange, routing_key: str = '',
               arguments: dict = None, timeout: int = None) -> asyncio.Future:

        """ Remove exchange-to-exchange binding for this :class:`Exchange` instance

        :param exchange: :class:`aio_pika.exchange.Exchange` instance
        :param routing_key: routing key
        :param arguments: additional arguments (will be passed to `pika`)
        :param timeout: execution timeout
        :return: :class:`None`
        """

        log.debug(
            "Unbinding exchange %r from exchange %r, routing_key=%r, arguments=%r",
            self, exchange, routing_key, arguments
        )

        f = self._create_future(timeout)

        self._channel.exchange_unbind(
            f.set_result,
            self.name,
            exchange.name,
            routing_key=routing_key,
            arguments=arguments
        )

        return f

    @BaseChannel._ensure_channel_is_open
    @asyncio.coroutine
    def publish(self, message: Message, routing_key, *, mandatory=True, immediate=False):
        """ Publish the message to the queue. `aio_pika` use `publisher confirms`_
        extension for message delivery.

        .. _publisher confirms: https://www.rabbitmq.com/confirms.html

        """

        log.debug("Publishing message via exchange %s: %r", self, message)
        if self.internal:
            # Caught on the client side to prevent channel closure
            raise ValueError("cannot publish to internal exchange: '%s'!" % self.name)

        return (
            yield from self.__publish_method(
                self.name,
                routing_key,
                message.body,
                properties=message.properties,
                mandatory=mandatory,
                immediate=immediate
            )
        )

    @BaseChannel._ensure_channel_is_open
    def delete(self, if_unused=False) -> asyncio.Future:
        """ Delete the queue

        :param if_unused: perform deletion when queue has no bindings.
        """
        log.info("Deleting %r", self)
        self._futures.reject_all(RuntimeError("Exchange was deleted"))
        future = create_future(loop=self.loop)
        self._channel.exchange_delete(future.set_result, self.name, if_unused=if_unused)
        return future

__all__ = ('Exchange',)
<commit_msg>add the x-consistent-hash exchange type<commit_after>import asyncio
from enum import Enum, unique
from logging import getLogger
from typing import Optional

from pika.channel import Channel
from .common import BaseChannel, FutureStore
from .message import Message
from .tools import create_future

log = getLogger(__name__)

@unique
class ExchangeType(Enum):
    FANOUT = 'fanout'
    DIRECT = 'direct'
    TOPIC = 'topic'
    HEADERS = 'headers'
    X_DELAYED_MESSAGE = 'x-delayed-message'
    X_CONSISTENT_HASH = 'x-consistent-hash'

class Exchange(BaseChannel):
    """ Exchange abstraction """

    __slots__ = (
        'name', '__type', '__publish_method', 'arguments', 'durable',
        'auto_delete', 'internal', 'passive', '_channel'
    )

    def __init__(self, channel: Channel, publish_method, name: str,
                 type: ExchangeType=ExchangeType.DIRECT, *, auto_delete: Optional[bool],
                 durable: Optional[bool], internal: Optional[bool], passive: Optional[bool],
                 arguments: dict=None, loop: asyncio.AbstractEventLoop,
                 future_store: FutureStore):

        super().__init__(loop, future_store)

        if not arguments:
            arguments = {}

        self._channel = channel
        self.__publish_method = publish_method
        self.__type = type.value
        self.name = name
        self.auto_delete = auto_delete
        self.durable = durable
        self.internal = internal
        self.passive = passive
        self.arguments = arguments

    def __str__(self):
        return self.name

    def __repr__(self):
        return "<Exchange(%s): auto_delete=%s, durable=%s, arguments=%r)>" % (
            self, self.auto_delete, self.durable, self.arguments
        )

    @BaseChannel._ensure_channel_is_open
    def declare(self, timeout: int=None):
        future = self._create_future(timeout=timeout)

        self._channel.exchange_declare(
            future.set_result,
            self.name,
            self.__type,
            durable=self.durable,
            auto_delete=self.auto_delete,
            internal=self.internal,
            passive=self.passive,
            arguments=self.arguments,
        )

        return future

    @BaseChannel._ensure_channel_is_open
    def bind(self, exchange,
             routing_key: str='', *, arguments=None, timeout: int = None) -> asyncio.Future:

        """ A binding can also be a relationship between two exchanges. This can be
        simply read as: this exchange is interested in messages from another exchange.

        Bindings can take an extra routing_key parameter. To avoid the confusion
        with a basic_publish parameter we're going to call it a binding key.

        .. code-block:: python

            client = await connect()

            routing_key = 'simple_routing_key'
            src_exchange_name = "source_exchange"
            dest_exchange_name = "destination_exchange"

            channel = await client.channel()
            src_exchange = await channel.declare_exchange(src_exchange_name, auto_delete=True)
            dest_exchange = await channel.declare_exchange(dest_exchange_name, auto_delete=True)
            queue = await channel.declare_queue(auto_delete=True)

            await queue.bind(dest_exchange, routing_key)
            await dest_exchange.bind(src_exchange, routing_key)

        :param exchange: :class:`aio_pika.exchange.Exchange` instance
        :param routing_key: routing key
        :param arguments: additional arguments (will be passed to `pika`)
        :param timeout: execution timeout
        :return: :class:`None`
        """

        log.debug(
            "Binding exchange %r to exchange %r, routing_key=%r, arguments=%r",
            self, exchange, routing_key, arguments
        )

        f = self._create_future(timeout)

        self._channel.exchange_bind(
            f.set_result,
            self.name,
            exchange.name,
            routing_key=routing_key,
            arguments=arguments
        )

        return f

    @BaseChannel._ensure_channel_is_open
    def unbind(self, exchange, routing_key: str = '',
               arguments: dict = None, timeout: int = None) -> asyncio.Future:

        """ Remove exchange-to-exchange binding for this :class:`Exchange` instance

        :param exchange: :class:`aio_pika.exchange.Exchange` instance
        :param routing_key: routing key
        :param arguments: additional arguments (will be passed to `pika`)
        :param timeout: execution timeout
        :return: :class:`None`
        """

        log.debug(
            "Unbinding exchange %r from exchange %r, routing_key=%r, arguments=%r",
            self, exchange, routing_key, arguments
        )

        f = self._create_future(timeout)

        self._channel.exchange_unbind(
            f.set_result,
            self.name,
            exchange.name,
            routing_key=routing_key,
            arguments=arguments
        )

        return f

    @BaseChannel._ensure_channel_is_open
    @asyncio.coroutine
    def publish(self, message: Message, routing_key, *, mandatory=True, immediate=False):
        """ Publish the message to the queue. `aio_pika` use `publisher confirms`_
        extension for message delivery.

        .. _publisher confirms: https://www.rabbitmq.com/confirms.html

        """

        log.debug("Publishing message via exchange %s: %r", self, message)
        if self.internal:
            # Caught on the client side to prevent channel closure
            raise ValueError("cannot publish to internal exchange: '%s'!" % self.name)

        return (
            yield from self.__publish_method(
                self.name,
                routing_key,
                message.body,
                properties=message.properties,
                mandatory=mandatory,
                immediate=immediate
            )
        )

    @BaseChannel._ensure_channel_is_open
    def delete(self, if_unused=False) -> asyncio.Future:
        """ Delete the queue

        :param if_unused: perform deletion when queue has no bindings.
        """
        log.info("Deleting %r", self)
        self._futures.reject_all(RuntimeError("Exchange was deleted"))
        future = create_future(loop=self.loop)
        self._channel.exchange_delete(future.set_result, self.name, if_unused=if_unused)
        return future

__all__ = ('Exchange',)
<|endoftext|>


<commit_before>from __future__ import absolute_import, unicode_literals

import os

import logging
import tornado.web
import tornado.gen
import tornado.httpclient
import requests
from mopidy import httpclient
from mopidy_subidy import subsonic_api
import mopidy_subidy

logger = logging.getLogger(__name__)

class CoverartRequestHandler(tornado.web.RequestHandler):
    def initialize(self, config, subsonic_api):
        self.proxy_formatted = httpclient.format_proxy(config['proxy'])
        self.subsonic_api = subsonic_api

    def get(self):
        a_id = self.get_argument('id')
        proxies = dict(http=self.proxy_formatted, https=self.proxy_formatted)
        useragent = httpclient.format_user_agent('{name}/{ver}'.format(name=mopidy_subidy.SubidyExtension.dist_name, ver=mopidy_subidy.__version__))
        censored_url = self.subsonic_api.get_censored_coverart_image_uri(a_id)
        logger.debug("Loading cover art from subsonic with url: '%s'" % censored_url)
        url = self.subsonic_api.get_coverart_image_uri(a_id)
        try:
            fetched = requests.get(url, headers={'user-agent': useragent}, proxies=proxies, stream=True)
            self.set_header('Content-Type', fetched.headers.get('content-type', 'application/octet-stream'))
            for chunk in response.iter_content(chunk_size=8192):
                self.write(chunk)
        except Exception as e:
            logger.warning('Connecting to subsonic failed when loading cover art image.')

def factory(config, core):
    subsonic_api = subsonic_api.get_subsonic_api_with_config(config)
    return (
        ('/cover_art', CoverartRequestHandler, dict(config=config, subsonic_api=subsonic_api)),
    )
<commit_msg>B"H rm unneeded import<commit_after>from __future__ import absolute_import, unicode_literals

import os

import logging
import tornado.web
import tornado.gen
import requests
from mopidy import httpclient
from mopidy_subidy import subsonic_api
import mopidy_subidy

logger = logging.getLogger(__name__)

class CoverartRequestHandler(tornado.web.RequestHandler):
    def initialize(self, config, subsonic_api):
        self.proxy_formatted = httpclient.format_proxy(config['proxy'])
        self.subsonic_api = subsonic_api

    def get(self):
        a_id = self.get_argument('id')
        proxies = dict(http=self.proxy_formatted, https=self.proxy_formatted)
        useragent = httpclient.format_user_agent('{name}/{ver}'.format(name=mopidy_subidy.SubidyExtension.dist_name, ver=mopidy_subidy.__version__))
        censored_url = self.subsonic_api.get_censored_coverart_image_uri(a_id)
        logger.debug("Loading cover art from subsonic with url: '%s'" % censored_url)
        url = self.subsonic_api.get_coverart_image_uri(a_id)
        try:
            fetched = requests.get(url, headers={'user-agent': useragent}, proxies=proxies, stream=True)
            self.set_header('Content-Type', fetched.headers.get('content-type', 'application/octet-stream'))
            for chunk in response.iter_content(chunk_size=8192):
                self.write(chunk)
        except Exception as e:
            logger.warning('Connecting to subsonic failed when loading cover art image.')

def factory(config, core):
    subsonic_api = subsonic_api.get_subsonic_api_with_config(config)
    return (
        ('/cover_art', CoverartRequestHandler, dict(config=config, subsonic_api=subsonic_api)),
    )
<|endoftext|>


<commit_before>#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import itertools
import os
import os.path

import sys
import argparse
import logging

def cartesian_product(dicts):
    return (dict(zip(dicts, x)) for x in itertools.product(*dicts.values()))

def summary(configuration):
    kvs = sorted([(k, v) for k, v in configuration.items()], key=lambda e: e[0])
    return '_'.join([('%s=%s' % (k, v)) for (k, v) in kvs])

def to_cmd(c, _path=None):
    if _path is None:
        _path = '/home/pminervi/workspace/inferbeddings/'
    command = 'python3 {}/bin/adv-cli.py' \
              ' --train {}/data/wn18/wordnet-mlj12-train.txt' \
              ' --valid {}/data/wn18/wordnet-mlj12-valid.txt' \
              ' --test {}/data/wn18/wordnet-mlj12-test.txt' \
              ' --clauses {}/data/wn18/clauses/clauses_0.9.pl' \
              ' --nb-epochs {}' \
              ' --lr {}' \
              ' --nb-batches {}' \
              ' --model {}' \
              ' --similarity {}' \
              ' --margin {}' \
              ' --embedding-size {}' \
              ' --subsample-size {}' \
              ' --loss {}' \
              ' --adv-lr {} --adv-init-ground --adversary-epochs {}' \
              ' --discriminator-epochs {} --adv-weight {} --adv-batch-size {}' \
              ''.format(_path, _path, _path, _path, _path,
                        c['epochs'], c['lr'], c['batches'],
                        c['model'], c['similarity'],
                        c['margin'], c['embedding_size'],
                        c['subsample_size'],
                        c['loss'],
                        c['adv_lr'], c['adv_epochs'],
                        c['disc_epochs'], c['adv_weight'], c['adv_batch_size'])
    return command

def to_logfile(c, path):
    outfile = "%s/ucl_wn18_adv_xshot_v1.%s.log" % (path, summary(c))
    return outfile

def main(argv):
    def formatter(prog):
        return argparse.HelpFormatter(prog, max_help_position=100, width=200)

    argparser = argparse.ArgumentParser('Generating experiments for the UCL cluster', formatter_class=formatter)
    argparser.add_argument('--debug', '-D', action='store_true', help='Debug flag')
    argparser.add_argument('--path', '-p', action='store', type=str, default=None, help='Path')

    args = argparser.parse_args(argv)

    hyperparameters_space_transe = dict(
        epochs=[100],
        optimizer=['adagrad'],
        lr=[.1],
        batches=[10],
        model=['TransE'],
        similarity=['l1', 'l2'],
        margin=[1],  # margin=[1, 2, 5, 10],
        embedding_size=[20, 50, 100, 150, 200],
        loss=['hinge'],
        subsample_size=[.1, .2, .3, .4, .5, .6, .7, 1],
        adv_lr=[.1],
        adv_epochs=[0, 10],
        disc_epochs=[10],
        adv_weight=[0, 1, 100, 10000, 1000000],
        adv_batch_size=[1, 10, 100]
    )

    hyperparameters_space_distmult_complex = dict(
        epochs=[100],
        optimizer=['adagrad'],
        lr=[.1],
        batches=[10],
        model=['DistMult', 'ComplEx'],
        similarity=['dot'],
        margin=[1],  # margin=[1, 2, 5, 10],
        embedding_size=[20, 50, 100, 150, 200],
        loss=['hinge'],
        subsample_size=[.1, .2, .3, .4, .5, .6, .7, 1],
        adv_lr=[.1],
        adv_epochs=[0, 10],
        disc_epochs=[10],
        adv_weight=[0, 1, 100, 10000, 1000000],
        adv_batch_size=[1, 10, 100]
    )

    configurations_transe = cartesian_product(hyperparameters_space_transe)
    configurations_distmult_complex = cartesian_product(hyperparameters_space_distmult_complex)

    path = '/home/pminervi/workspace/inferbeddings/logs/ucl_wn18_adv_xshot_v1/'
    if not os.path.exists(path):
        os.makedirs(path)

    configurations = list(configurations_transe) + list(configurations_distmult_complex)

    for job_id, cfg in enumerate(configurations):
        logfile = to_logfile(cfg, path)

        completed = False
        if os.path.isfile(logfile):
            with open(logfile, 'r', encoding='utf-8', errors='ignore') as f:
                content = f.read()
                completed = '### MICRO (test filtered)' in content

        if not completed:
            line = '{} >> {} 2>&1'.format(to_cmd(cfg, _path=args.path), logfile)

            if args.debug:
                print(line)
            else:
                file_name = 'ucl_wn18_adv_xshot_v1_{}.job'.format(job_id)
                alias = ''
                job_script = '#$ -S /bin/bash\n' \
                             '#$ -wd /tmp/\n' \
                             '#$ -l h_vmem=4G,tmem=4G\n' \
                             '#$ -l h_rt=24:00:00\n' \
                             '{}\n{}\n'.format(alias, line)

                with open(file_name, 'w') as f:
                    f.write(job_script)

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)
    main(sys.argv[1:])
<commit_msg>larger grid<commit_after>#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import itertools
import os
import os.path

import sys
import argparse
import logging

def cartesian_product(dicts):
    return (dict(zip(dicts, x)) for x in itertools.product(*dicts.values()))

def summary(configuration):
    kvs = sorted([(k, v) for k, v in configuration.items()], key=lambda e: e[0])
    return '_'.join([('%s=%s' % (k, v)) for (k, v) in kvs])

def to_cmd(c, _path=None):
    if _path is None:
        _path = '/home/pminervi/workspace/inferbeddings/'
    command = 'python3 {}/bin/adv-cli.py' \
              ' --train {}/data/wn18/wordnet-mlj12-train.txt' \
              ' --valid {}/data/wn18/wordnet-mlj12-valid.txt' \
              ' --test {}/data/wn18/wordnet-mlj12-test.txt' \
              ' --clauses {}/data/wn18/clauses/clauses_0.9.pl' \
              ' --nb-epochs {}' \
              ' --lr {}' \
              ' --nb-batches {}' \
              ' --model {}' \
              ' --similarity {}' \
              ' --margin {}' \
              ' --embedding-size {}' \
              ' --subsample-size {}' \
              ' --loss {}' \
              ' --adv-lr {} --adv-init-ground --adversary-epochs {}' \
              ' --discriminator-epochs {} --adv-weight {} --adv-batch-size {}' \
              ''.format(_path, _path, _path, _path, _path,
                        c['epochs'], c['lr'], c['batches'],
                        c['model'], c['similarity'],
                        c['margin'], c['embedding_size'],
                        c['subsample_size'],
                        c['loss'],
                        c['adv_lr'], c['adv_epochs'],
                        c['disc_epochs'], c['adv_weight'], c['adv_batch_size'])
    return command

def to_logfile(c, path):
    outfile = "%s/ucl_wn18_adv_xshot_v1.%s.log" % (path, summary(c))
    return outfile

def main(argv):
    def formatter(prog):
        return argparse.HelpFormatter(prog, max_help_position=100, width=200)

    argparser = argparse.ArgumentParser('Generating experiments for the UCL cluster', formatter_class=formatter)
    argparser.add_argument('--debug', '-D', action='store_true', help='Debug flag')
    argparser.add_argument('--path', '-p', action='store', type=str, default=None, help='Path')

    args = argparser.parse_args(argv)

    hyperparameters_space_transe = dict(
        epochs=[100],
        optimizer=['adagrad'],
        lr=[.1],
        batches=[10],
        model=['TransE'],
        similarity=['l1', 'l2', 'dot'],
        margin=[1],  # margin=[1, 2, 5, 10],
        embedding_size=[20, 50, 100, 150, 200],
        loss=['hinge'],
        subsample_size=[.1, .2, .3, .4, .5, .6, .7, .8, .9, 1],
        adv_lr=[.1],
        adv_epochs=[0, 10],
        disc_epochs=[10],
        adv_weight=[0, 1, 100, 10000, 1000000],
        adv_batch_size=[1, 10, 100]
    )

    hyperparameters_space_distmult_complex = dict(
        epochs=[100],
        optimizer=['adagrad'],
        lr=[.1],
        batches=[10],
        model=['DistMult', 'ComplEx'],
        similarity=['dot'],
        margin=[1],  # margin=[1, 2, 5, 10],
        embedding_size=[20, 50, 100, 150, 200],
        loss=['hinge'],
        subsample_size=[.1, .2, .3, .4, .5, .6, .7, .8, .9, 1],
        adv_lr=[.1],
        adv_epochs=[0, 10],
        disc_epochs=[10],
        adv_weight=[0, 1, 100, 10000, 1000000],
        adv_batch_size=[1, 10, 100]
    )

    configurations_transe = cartesian_product(hyperparameters_space_transe)
    configurations_distmult_complex = cartesian_product(hyperparameters_space_distmult_complex)

    path = '/home/pminervi/workspace/inferbeddings/logs/ucl_wn18_adv_xshot_v1/'
    if not os.path.exists(path):
        os.makedirs(path)

    configurations = list(configurations_transe) + list(configurations_distmult_complex)

    for job_id, cfg in enumerate(configurations):
        logfile = to_logfile(cfg, path)

        completed = False
        if os.path.isfile(logfile):
            with open(logfile, 'r', encoding='utf-8', errors='ignore') as f:
                content = f.read()
                completed = '### MICRO (test filtered)' in content

        if not completed:
            line = '{} >> {} 2>&1'.format(to_cmd(cfg, _path=args.path), logfile)

            if args.debug:
                print(line)
            else:
                file_name = 'ucl_wn18_adv_xshot_v1_{}.job'.format(job_id)
                alias = ''
                job_script = '#$ -S /bin/bash\n' \
                             '#$ -wd /tmp/\n' \
                             '#$ -l h_vmem=4G,tmem=4G\n' \
                             '#$ -l h_rt=24:00:00\n' \
                             '{}\n{}\n'.format(alias, line)

                with open(file_name, 'w') as f:
                    f.write(job_script)

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)
    main(sys.argv[1:])
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
import builds.version_slug
import taggit.managers

class Migration(migrations.Migration):

    dependencies = [
        ('projects', '0001_initial'),
        ('taggit', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='Build',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('type', models.CharField(default=b'html', max_length=55, verbose_name='Type', choices=[(b'html', 'HTML'), (b'pdf', 'PDF'), (b'epub', 'Epub'), (b'man', 'Manpage'), (b'dash', 'Dash')])),
                ('state', models.CharField(default=b'finished', max_length=55, verbose_name='State', choices=[(b'triggered', 'Triggered'), (b'cloning', 'Cloning'), (b'installing', 'Installing'), (b'building', 'Building'), (b'finished', 'Finished')])),
                ('date', models.DateTimeField(auto_now_add=True, verbose_name='Date')),
                ('success', models.BooleanField(default=True, verbose_name='Success')),
                ('setup', models.TextField(null=True, verbose_name='Setup', blank=True)),
                ('setup_error', models.TextField(null=True, verbose_name='Setup error', blank=True)),
                ('output', models.TextField(default=b'', verbose_name='Output', blank=True)),
                ('error', models.TextField(default=b'', verbose_name='Error', blank=True)),
                ('exit_code', models.IntegerField(null=True, verbose_name='Exit code', blank=True)),
                ('commit', models.CharField(max_length=255, null=True, verbose_name='Commit', blank=True)),
                ('length', models.IntegerField(null=True, verbose_name='Build Length', blank=True)),
                ('builder', models.CharField(max_length=255, null=True, verbose_name='Builder', blank=True)),
                ('project', models.ForeignKey(related_name='builds', verbose_name='Project', to='projects.Project')),
            ],
            options={
                'ordering': ['-date'],
                'get_latest_by': 'date',
            },
        ),
        migrations.CreateModel(
            name='Version',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('type', models.CharField(default=b'unknown', max_length=20, verbose_name='Type', choices=[(b'branch', 'Branch'), (b'tag', 'Tag'), (b'unknown', 'Unknown')])),
                ('identifier', models.CharField(max_length=255, verbose_name='Identifier')),
                ('verbose_name', models.CharField(max_length=255, verbose_name='Verbose Name')),
                ('slug', builds.version_slug.VersionSlugField(populate_from=b'verbose_name', max_length=255, verbose_name='Slug', db_index=True)),
                ('supported', models.BooleanField(default=True, verbose_name='Supported')),
                ('active', models.BooleanField(default=False, verbose_name='Active')),
                ('built', models.BooleanField(default=False, verbose_name='Built')),
                ('uploaded', models.BooleanField(default=False, verbose_name='Uploaded')),
                ('privacy_level', models.CharField(default=b'public', help_text='Level of privacy for this Version.', max_length=20, verbose_name='Privacy Level', choices=[(b'public', 'Public'), (b'protected', 'Protected'), (b'private', 'Private')])),
                ('machine', models.BooleanField(default=False, verbose_name='Machine Created')),
                ('project', models.ForeignKey(related_name='versions', verbose_name='Project', to='projects.Project')),
                ('tags', taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', blank=True, help_text='A comma-separated list of tags.', verbose_name='Tags')),
            ],
            options={
                'ordering': ['-verbose_name'],
                'permissions': (('view_version', 'View Version'),),
            },
        ),
        migrations.CreateModel(
            name='VersionAlias',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('from_slug', models.CharField(default=b'', max_length=255, verbose_name='From slug')),
                ('to_slug', models.CharField(default=b'', max_length=255, verbose_name='To slug', blank=True)),
                ('largest', models.BooleanField(default=False, verbose_name='Largest')),
                ('project', models.ForeignKey(related_name='aliases', verbose_name='Project', to='projects.Project')),
            ],
        ),
        migrations.AddField(
            model_name='build',
            name='version',
            field=models.ForeignKey(related_name='builds', verbose_name='Version', to='builds.Version', null=True),
        ),
        migrations.AlterUniqueTogether(
            name='version',
            unique_together=set([('project', 'slug')]),
        ),
        migrations.AlterIndexTogether(
            name='build',
            index_together=set([('version', 'state', 'type')]),
        ),
    ]
<commit_msg>Fix 1-time migration issue<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
import readthedocs.builds.version_slug
import taggit.managers

class Migration(migrations.Migration):

    dependencies = [
        ('projects', '0001_initial'),
        ('taggit', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='Build',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('type', models.CharField(default=b'html', max_length=55, verbose_name='Type', choices=[(b'html', 'HTML'), (b'pdf', 'PDF'), (b'epub', 'Epub'), (b'man', 'Manpage'), (b'dash', 'Dash')])),
                ('state', models.CharField(default=b'finished', max_length=55, verbose_name='State', choices=[(b'triggered', 'Triggered'), (b'cloning', 'Cloning'), (b'installing', 'Installing'), (b'building', 'Building'), (b'finished', 'Finished')])),
                ('date', models.DateTimeField(auto_now_add=True, verbose_name='Date')),
                ('success', models.BooleanField(default=True, verbose_name='Success')),
                ('setup', models.TextField(null=True, verbose_name='Setup', blank=True)),
                ('setup_error', models.TextField(null=True, verbose_name='Setup error', blank=True)),
                ('output', models.TextField(default=b'', verbose_name='Output', blank=True)),
                ('error', models.TextField(default=b'', verbose_name='Error', blank=True)),
                ('exit_code', models.IntegerField(null=True, verbose_name='Exit code', blank=True)),
                ('commit', models.CharField(max_length=255, null=True, verbose_name='Commit', blank=True)),
                ('length', models.IntegerField(null=True, verbose_name='Build Length', blank=True)),
                ('builder', models.CharField(max_length=255, null=True, verbose_name='Builder', blank=True)),
                ('project', models.ForeignKey(related_name='builds', verbose_name='Project', to='projects.Project')),
            ],
            options={
                'ordering': ['-date'],
                'get_latest_by': 'date',
            },
        ),
        migrations.CreateModel(
            name='Version',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('type', models.CharField(default=b'unknown', max_length=20, verbose_name='Type', choices=[(b'branch', 'Branch'), (b'tag', 'Tag'), (b'unknown', 'Unknown')])),
                ('identifier', models.CharField(max_length=255, verbose_name='Identifier')),
                ('verbose_name', models.CharField(max_length=255, verbose_name='Verbose Name')),
                ('slug', readthedocs.builds.version_slug.VersionSlugField(populate_from=b'verbose_name', max_length=255, verbose_name='Slug', db_index=True)),
                ('supported', models.BooleanField(default=True, verbose_name='Supported')),
                ('active', models.BooleanField(default=False, verbose_name='Active')),
                ('built', models.BooleanField(default=False, verbose_name='Built')),
                ('uploaded', models.BooleanField(default=False, verbose_name='Uploaded')),
                ('privacy_level', models.CharField(default=b'public', help_text='Level of privacy for this Version.', max_length=20, verbose_name='Privacy Level', choices=[(b'public', 'Public'), (b'protected', 'Protected'), (b'private', 'Private')])),
                ('machine', models.BooleanField(default=False, verbose_name='Machine Created')),
                ('project', models.ForeignKey(related_name='versions', verbose_name='Project', to='projects.Project')),
                ('tags', taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', blank=True, help_text='A comma-separated list of tags.', verbose_name='Tags')),
            ],
            options={
                'ordering': ['-verbose_name'],
                'permissions': (('view_version', 'View Version'),),
            },
        ),
        migrations.CreateModel(
            name='VersionAlias',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('from_slug', models.CharField(default=b'', max_length=255, verbose_name='From slug')),
                ('to_slug', models.CharField(default=b'', max_length=255, verbose_name='To slug', blank=True)),
                ('largest', models.BooleanField(default=False, verbose_name='Largest')),
                ('project', models.ForeignKey(related_name='aliases', verbose_name='Project', to='projects.Project')),
            ],
        ),
        migrations.AddField(
            model_name='build',
            name='version',
            field=models.ForeignKey(related_name='builds', verbose_name='Version', to='builds.Version', null=True),
        ),
        migrations.AlterUniqueTogether(
            name='version',
            unique_together=set([('project', 'slug')]),
        ),
        migrations.AlterIndexTogether(
            name='build',
            index_together=set([('version', 'state', 'type')]),
        ),
    ]
<|endoftext|>