<commit_before># Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
from six.moves import range
import json, os
from semantic_version import Version
import frappe
import requests
import subprocess # nosec
from frappe.utils import cstr
from frappe.utils.gitutils import get_app_branch
from frappe import _, safe_decode

def get_change_log(user=None):
	if not user: user = frappe.session.user

	last_known_versions = frappe._dict(json.loads(frappe.db.get_value("User",
		user, "last_known_versions") or "{}"))
	current_versions = get_versions()

	if not last_known_versions:
		update_last_known_versions()
		return []

	change_log = []
	def set_in_change_log(app, opts, change_log):
		from_version = last_known_versions.get(app, {}).get("version") or "0.0.1"
		to_version = opts["version"]

		if from_version != to_version:
			app_change_log = get_change_log_for_app(app, from_version=from_version, to_version=to_version)

			if app_change_log:
				change_log.append({
					"title": opts["title"],
					"description": opts["description"],
					"version": to_version,
					"change_log": app_change_log
				})

	for app, opts in current_versions.items():
		if app != "frappe":
			set_in_change_log(app, opts, change_log)

	if "frappe" in current_versions:
		set_in_change_log("frappe", current_versions["frappe"], change_log)

	return change_log

def get_change_log_for_app(app, from_version, to_version):
	change_log_folder = os.path.join(frappe.get_app_path(app), "change_log")
	if not os.path.exists(change_log_folder):
		return

	from_version = Version(from_version)
	to_version = Version(to_version)
	# remove pre-release part
	to_version.prerelease = None

	major_version_folders = ["v{0}".format(i) for i in range(from_version.major, to_version.major + 1)]
	app_change_log = []

	for folder in os.listdir(change_log_folder):
		if folder in major_version_folders:
			for file in os.listdir(os.path.join(change_log_folder, folder)):
				version = Version(os.path.splitext(file)[0][1:].replace("_", "."))

				if from_version < version <= to_version:
					file_path = os.path.join(change_log_folder, folder, file)
					content = frappe.read_file(file_path)
					app_change_log.append([version, content])

	app_change_log = sorted(app_change_log, key=lambda d: d[0], reverse=True)

	# convert version to string and send
	return [[cstr(d[0]), d[1]] for d in app_change_log]

@frappe.whitelist()
def update_last_known_versions():
	frappe.db.set_value("User", frappe.session.user, "last_known_versions",
		json.dumps(get_versions()), update_modified=False)

@frappe.whitelist()
def get_versions():
	"""Get versions of all installed apps.

	Example:

		{
			"frappe": {
				"title": "Frappe Framework",
				"version": "5.0.0"
			}
		}"""
	versions = {}
	for app in frappe.get_installed_apps(sort=True):
		app_hooks = frappe.get_hooks(app_name=app)
		versions[app] = {
			"title": app_hooks.get("app_title")[0],
			"description": app_hooks.get("app_description")[0],
			"branch": get_app_branch(app)
		}

		if versions[app]['branch'] != 'master':
			branch_version = app_hooks.get('{0}_version'.format(versions[app]['branch']))
			if branch_version:
				versions[app]['branch_version'] = branch_version[0] + ' ({0})'.format(get_app_last_commit_ref(app))

		try:
			versions[app]["version"] = frappe.get_attr(app + ".__version__")
		except AttributeError:
			versions[app]["version"] = '0.0.1'

	return versions

def get_app_branch(app):
	'''Returns branch of an app'''
	try:
		result = subprocess.check_output('cd ../apps/{0} && git rev-parse --abbrev-ref HEAD'.format(app),
			shell=True)
		result = safe_decode(result)
		result = result.strip()
		return result
	except Exception:
		return ''

def get_app_last_commit_ref(app):
	try:
		result = subprocess.check_output('cd ../apps/{0} && git rev-parse HEAD --short 7'.format(app),
			shell=True)
		result = safe_decode(result)
		result = result.strip()
		return result
	except Exception:
		return ''

def check_for_update():
	updates = frappe._dict(major=[], minor=[], patch=[])
	apps = get_versions()

	for app in apps:
		app_details = check_release_on_github(app)
		if not app_details: continue

		github_version, org_name = app_details
		# Get local instance's current version or the app

		branch_version = apps[app]['branch_version'].split(' ')[0] if apps[app].get('branch_version', '') else ''
		instance_version = Version(branch_version or apps[app].get('version'))
		# Compare and popup update message
		for update_type in updates:
			if github_version.__dict__[update_type] > instance_version.__dict__[update_type]:
				updates[update_type].append(frappe._dict(
					current_version   = str(instance_version),
					available_version = str(github_version),
					org_name          = org_name,
					app_name          = app,
					title             = apps[app]['title'],
				))
				break
			if github_version.__dict__[update_type] < instance_version.__dict__[update_type]: break

	add_message_to_redis(updates)

def parse_latest_non_beta_release(response):
	"""
	Pasrses the response JSON for all the releases and returns the latest non prerelease

	Parameters
	response (list): response object returned by github

	Returns
	json   : json object pertaining to the latest non-beta release
	"""
	for release in response:
		if release['prerelease'] == True: continue
		return release

def check_release_on_github(app):
	# Check if repo remote is on github
	from subprocess import CalledProcessError
	try:
		remote_url = subprocess.check_output("cd ../apps/{} && git ls-remote --get-url".format(app), shell=True).decode()
	except CalledProcessError:
		# Passing this since some apps may not have git initializaed in them
		return None

	if isinstance(remote_url, bytes):
		remote_url = remote_url.decode()

	if "github.com" not in remote_url:
		return None

	# Get latest version from github
	if 'https' not in remote_url:
		return None

	org_name = remote_url.split('/')[3]
	r = requests.get('https://api.github.com/repos/{}/{}/releases'.format(org_name, app))
	if r.status_code == 200 and r.json():
		lastest_non_beta_release = parse_latest_non_beta_release(r.json())
		return Version(lastest_non_beta_release['tag_name'].strip('v')), org_name
	else:
		# In case of an improper response or if there are no releases
		return None

def add_message_to_redis(update_json):
	# "update-message" will store the update message string
	# "update-user-set" will be a set of users
	cache = frappe.cache()
	cache.set_value("update-info", json.dumps(update_json))
	user_list = [x.name for x in frappe.get_all("User", filters={"enabled": True})]
	system_managers = [user for user in user_list if 'System Manager' in frappe.get_roles(user)]
	cache.sadd("update-user-set", *system_managers)

@frappe.whitelist()
def show_update_popup():
	cache = frappe.cache()
	user  = frappe.session.user

	update_info = cache.get_value("update-info")
	if not update_info:
		return

	updates = json.loads(update_info)

	# Check if user is int the set of users to send update message to
	update_message = ""
	if cache.sismember("update-user-set", user):
		for update_type in updates:
			release_links = ""
			for app in updates[update_type]:
				app = frappe._dict(app)
				release_links += "{title}: v{available_version}
".format(
					available_version = app.available_version,
					org_name          = app.org_name,
					app_name          = app.app_name,
					title             = app.title
				)
			if release_links:
				update_message += _("New {} releases for the following apps are available".format(update_type)) + ":

{}".format(release_links)

	if update_message:
		frappe.msgprint(update_message, title=_("New updates are available"), indicator='green')
		cache.srem("update-user-set", user)
<commit_msg>fix: compare and sort release list to get latest release<commit_after># Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
from six.moves import range
import json, os
from semantic_version import Version
import frappe
import requests
import subprocess # nosec
from frappe.utils import cstr
from frappe.utils.gitutils import get_app_branch
from frappe import _, safe_decode

def get_change_log(user=None):
	if not user: user = frappe.session.user

	last_known_versions = frappe._dict(json.loads(frappe.db.get_value("User",
		user, "last_known_versions") or "{}"))
	current_versions = get_versions()

	if not last_known_versions:
		update_last_known_versions()
		return []

	change_log = []
	def set_in_change_log(app, opts, change_log):
		from_version = last_known_versions.get(app, {}).get("version") or "0.0.1"
		to_version = opts["version"]

		if from_version != to_version:
			app_change_log = get_change_log_for_app(app, from_version=from_version, to_version=to_version)

			if app_change_log:
				change_log.append({
					"title": opts["title"],
					"description": opts["description"],
					"version": to_version,
					"change_log": app_change_log
				})

	for app, opts in current_versions.items():
		if app != "frappe":
			set_in_change_log(app, opts, change_log)

	if "frappe" in current_versions:
		set_in_change_log("frappe", current_versions["frappe"], change_log)

	return change_log

def get_change_log_for_app(app, from_version, to_version):
	change_log_folder = os.path.join(frappe.get_app_path(app), "change_log")
	if not os.path.exists(change_log_folder):
		return

	from_version = Version(from_version)
	to_version = Version(to_version)
	# remove pre-release part
	to_version.prerelease = None

	major_version_folders = ["v{0}".format(i) for i in range(from_version.major, to_version.major + 1)]
	app_change_log = []

	for folder in os.listdir(change_log_folder):
		if folder in major_version_folders:
			for file in os.listdir(os.path.join(change_log_folder, folder)):
				version = Version(os.path.splitext(file)[0][1:].replace("_", "."))

				if from_version < version <= to_version:
					file_path = os.path.join(change_log_folder, folder, file)
					content = frappe.read_file(file_path)
					app_change_log.append([version, content])

	app_change_log = sorted(app_change_log, key=lambda d: d[0], reverse=True)

	# convert version to string and send
	return [[cstr(d[0]), d[1]] for d in app_change_log]

@frappe.whitelist()
def update_last_known_versions():
	frappe.db.set_value("User", frappe.session.user, "last_known_versions",
		json.dumps(get_versions()), update_modified=False)

@frappe.whitelist()
def get_versions():
	"""Get versions of all installed apps.

	Example:

		{
			"frappe": {
				"title": "Frappe Framework",
				"version": "5.0.0"
			}
		}"""
	versions = {}
	for app in frappe.get_installed_apps(sort=True):
		app_hooks = frappe.get_hooks(app_name=app)
		versions[app] = {
			"title": app_hooks.get("app_title")[0],
			"description": app_hooks.get("app_description")[0],
			"branch": get_app_branch(app)
		}

		if versions[app]['branch'] != 'master':
			branch_version = app_hooks.get('{0}_version'.format(versions[app]['branch']))
			if branch_version:
				versions[app]['branch_version'] = branch_version[0] + ' ({0})'.format(get_app_last_commit_ref(app))

		try:
			versions[app]["version"] = frappe.get_attr(app + ".__version__")
		except AttributeError:
			versions[app]["version"] = '0.0.1'

	return versions

def get_app_branch(app):
	'''Returns branch of an app'''
	try:
		result = subprocess.check_output('cd ../apps/{0} && git rev-parse --abbrev-ref HEAD'.format(app),
			shell=True)
		result = safe_decode(result)
		result = result.strip()
		return result
	except Exception:
		return ''

def get_app_last_commit_ref(app):
	try:
		result = subprocess.check_output('cd ../apps/{0} && git rev-parse HEAD --short 7'.format(app),
			shell=True)
		result = safe_decode(result)
		result = result.strip()
		return result
	except Exception:
		return ''

def check_for_update():
	updates = frappe._dict(major=[], minor=[], patch=[])
	apps = get_versions()

	for app in apps:
		app_details = check_release_on_github(app)
		if not app_details: continue

		github_version, org_name = app_details
		# Get local instance's current version or the app

		branch_version = apps[app]['branch_version'].split(' ')[0] if apps[app].get('branch_version', '') else ''
		instance_version = Version(branch_version or apps[app].get('version'))
		# Compare and popup update message
		for update_type in updates:
			if github_version.__dict__[update_type] > instance_version.__dict__[update_type]:
				updates[update_type].append(frappe._dict(
					current_version   = str(instance_version),
					available_version = str(github_version),
					org_name          = org_name,
					app_name          = app,
					title             = apps[app]['title'],
				))
				break
			if github_version.__dict__[update_type] < instance_version.__dict__[update_type]: break

	add_message_to_redis(updates)

def parse_latest_non_beta_release(response):
	"""
	Pasrses the response JSON for all the releases and returns the latest non prerelease

	Parameters
	response (list): response object returned by github

	Returns
	json   : json object pertaining to the latest non-beta release
	"""
	version_list = [release.get('tag_name').strip('v') for release in response if not release.get('prerelease')]

	if version_list:
		return sorted(version_list, key=Version, reverse=True)[0]

	return None

def check_release_on_github(app):
	# Check if repo remote is on github
	from subprocess import CalledProcessError
	try:
		remote_url = subprocess.check_output("cd ../apps/{} && git ls-remote --get-url".format(app), shell=True).decode()
	except CalledProcessError:
		# Passing this since some apps may not have git initializaed in them
		return None

	if isinstance(remote_url, bytes):
		remote_url = remote_url.decode()

	if "github.com" not in remote_url:
		return None

	# Get latest version from github
	if 'https' not in remote_url:
		return None

	org_name = remote_url.split('/')[3]
	r = requests.get('https://api.github.com/repos/{}/{}/releases'.format(org_name, app))
	if r.ok:
		lastest_non_beta_release = parse_latest_non_beta_release(r.json())
		return Version(lastest_non_beta_release), org_name
	# In case of an improper response or if there are no releases
	return None

def add_message_to_redis(update_json):
	# "update-message" will store the update message string
	# "update-user-set" will be a set of users
	cache = frappe.cache()
	cache.set_value("update-info", json.dumps(update_json))
	user_list = [x.name for x in frappe.get_all("User", filters={"enabled": True})]
	system_managers = [user for user in user_list if 'System Manager' in frappe.get_roles(user)]
	cache.sadd("update-user-set", *system_managers)

@frappe.whitelist()
def show_update_popup():
	cache = frappe.cache()
	user  = frappe.session.user

	update_info = cache.get_value("update-info")
	if not update_info:
		return

	updates = json.loads(update_info)

	# Check if user is int the set of users to send update message to
	update_message = ""
	if cache.sismember("update-user-set", user):
		for update_type in updates:
			release_links = ""
			for app in updates[update_type]:
				app = frappe._dict(app)
				release_links += "{title}: v{available_version}
".format(
					available_version = app.available_version,
					org_name          = app.org_name,
					app_name          = app.app_name,
					title             = app.title
				)
			if release_links:
				update_message += _("New {} releases for the following apps are available".format(update_type)) + ":

{}".format(release_links)

	if update_message:
		frappe.msgprint(update_message, title=_("New updates are available"), indicator='green')
		cache.srem("update-user-set", user)
<|endoftext|>


<commit_before>from frasco import (Feature, action, Blueprint, View, render_template,\
                    current_context, command, hook, current_app)
from frasco.utils import remove_yaml_frontmatter
from frasco.templating import FileLoader, get_template_source
import os
import json
import re

class AngularView(View):
    def __init__(self, template=None, layout=None, **kwargs):
        view_attrs = ('name', 'url', 'methods', 'url_rules')
        self.route_options = { k: kwargs.pop(k) for k in kwargs.keys() if k not in view_attrs}
        super(AngularView, self).__init__(**kwargs)
        self.template = template
        self.layout = layout

    def dispatch_request(self, *args, **kwargs):
        layout = self.layout or current_app.features.angular.options['views_layout']
        return render_template(layout, **current_context.vars)

_endmacro_re = re.compile(r"\{%-?\s*endmacro\s*%\}")
_ngdirective_re = re.compile(r"\{#\s*ngdirective:(.+)#\}")
_url_arg_re = re.compile(r"<([a-z]:)?([a-z0-9_]+)>")

def convert_url_args(url):
    return _url_arg_re.sub(r":\2", url)

class AngularFeature(Feature):
    name = "angular"
    requires = ["assets"]
    view_files = [("*.ng.html", AngularView)]
    ignore_attributes = ['assets']
    defaults = {"export_macros": [],
                "static_dir": None, # defaults to app.static_folder
                "static_url_path": None, # defaults to app.static_url_path
                "app_file": "app/app.js", # set to False to not generate an app.js
                "app_module": "app",
                "app_deps": [],
                "partials_dir": "app/partials",
                "directives_file": "app/directives/auto.js",
                "directives_module": "directives",
                "views_dir": "app/views",
                "routes_file": "app/routes.js",
                "routes_module": "routes",
                "views_layout": "angular_layout.html",
                "services_file": "app/services/auto.js",
                "services_module": "services",
                "disable_reloading_endpoints": False}

    def init_app(self, app):
        self.app = app
        self.built = False
        if not self.options["static_dir"]:
            self.options["static_dir"] = app.static_folder
        if not self.options["static_url_path"]:
            self.options["static_url_path"] = app.static_url_path

        app.features.assets.expose_package("frasco_angular", __name__)
        app.assets.register({
            "angular-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"],
            "angular-route-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-route.min.js"],
            "angular-resource-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-resource.min.js"],
            "angular-animate-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-animate.min.js"],
            "angular-cookies-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-cookies.min.js"],
            "angular-loader-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-loader.min.js"],
            "angular-sanitize-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-sanitize.min.js"],
            "angular-touch-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-touch.min.js"],
            "angular-frasco": [
                {"output": "angular-frasco.min.js", "filters": "jsmin",
                 "contents": ["frasco_angular/angular-frasco.js"]}]})

        app.jinja_env.loader.bottom_loaders.append(FileLoader(
            os.path.join(os.path.dirname(__file__), "layout.html"), "angular_layout.html"))

        if not self.options["disable_reloading_endpoints"]:
            # adding the url rule ensure that we don't need to reload the app to regenerate the
            # partial file. partial files are still generated when the app starts but will then
            # be served by this endpoint and be generated on the fly
            # note: we don't need to the same for views as a change triggers the reloader
            app.add_url_rule(self.options["static_url_path"] + "/" + self.options["partials_dir"] + "/<macro>.html",
                endpoint="angular_partial", view_func=self.extract_macro)

    @property
    def assets(self):
        if "angular-app" not in self.app.assets:
            self.app.assets.register("angular-app")
        return self.app.assets["angular-app"]

    @command()
    def build(self):
        files = []
        files.extend(self.build_directives())
        files.extend(self.build_routes())
        files.extend(self.build_services())
        files.extend(self.build_app())
        for filename, source in files:
            if not os.path.exists(os.path.dirname(filename)):
                os.makedirs(os.path.dirname(filename))
            with open(filename, 'w') as f:
                f.write(source)

    @command()
    def clean(self):
        files = []
        files.extend(self.build_directives())
        files.extend(self.build_routes())
        files.extend(self.build_services())
        files.extend(self.build_app())
        for filename, source in files:
            if os.path.exists(filename):
                os.unlink(filename)

    @hook()
    def before_request(self):
        if not self.built:
            self.build()
            self.built = True

    def build_routes(self):
        files = []
        views = []
        for name, bp in self.app.blueprints.iteritems():
            if isinstance(bp, Blueprint):
                for v in bp.views.itervalues():
                    if isinstance(v, AngularView):
                        views.append((bp.url_prefix, v))

        base_url = self.options["static_url_path"] + "/" + self.options["views_dir"] + "/"
        when_tpl = "$routeProvider.when('%s', %s);"
        routes = []
        for url_prefix, view in views:
            files.append(self.export_view(view.template))
            for url, options in view.url_rules:
                spec = dict(view.route_options, templateUrl=base_url + view.template)
                if url_prefix:
                    url = url_prefix + url
                url = convert_url_args(url)
                routes.append(when_tpl % (url, json.dumps(spec)))

        routes.append("$routeProvider.otherwise({redirectTo: function(params, path, search) { window.location.href = path; }});")
        module = ("/* This file is auto-generated by frasco-angular. DO NOT MODIFY. */\n'use strict';\n\nangular.module('%s',"
                  "['ngRoute']).config(['$routeProvider', '$locationProvider',\n"
                  "    function($routeProvider, $locationProvider) {\n        $locationProvider.html5Mode(true);\n"
                  "        %s\n    }\n]);\n") % (self.options["routes_module"], "\n        ".join(routes))
        filename = os.path.join(self.options["static_dir"], self.options["routes_file"])
        files.append((filename, module))
        self.assets.append("@angular-route-cdn", self.options["routes_file"])
        self.options["app_deps"].append(self.options["routes_module"])
        return files

    def export_view(self, filename):
        source = remove_yaml_frontmatter(get_template_source(self.app, filename))
        dest = os.path.join(self.options["static_dir"], self.options["views_dir"], filename)
        return (dest, source)

    def build_directives(self):
        files = []
        directives = {}
        for macro in self.options["export_macros"]:
            filename, source, directives[macro] = self.export_macro(macro)
            files.append((filename, source))

        module = ("/* This file is auto-generated by frasco-angular. DO NOT MODIFY. */\n'use strict';\n"
                  "\nvar directives = angular.module('%s', []);\n\n") % self.options["directives_module"]
        for name, options in directives.iteritems():
            name = options.pop("name", name)
            module += "directives.directive('%s', function() {\nreturn %s;\n});\n\n" % (name, json.dumps(options, indent=4))

        filename = os.path.join(self.options["static_dir"], self.options["directives_file"])
        files.append((filename, module))
        self.assets.append(self.options["directives_file"])
        self.options["app_deps"].append(self.options["directives_module"])
        return files

    def export_macro(self, macro):
        partial, options = self.extract_macro(macro, True)
        filename = os.path.join(self.options["static_dir"], self.options["partials_dir"], macro + ".html")
        url = self.options["static_url_path"] + "/" + self.options["partials_dir"] + "/" + macro + ".html"
        options["templateUrl"] = url
        return (filename, partial.strip(), options)

    def extract_macro(self, macro, with_options=False):
        template = self.app.jinja_env.macros.resolve_template(macro)
        if not template:
            raise Exception("Macro '%s' cannot be exported to angular because it does not exist" % macro)
        source = get_template_source(self.app, template)

        m = re.search(r"\{%\s*macro\s+" + re.escape(macro), source)
        if not m:
            raise Exception("Macro '%s' not found in template %s" % (macro, template))
        start = source.find("%}", m.start()) + 2
        end = _endmacro_re.search(source, start).start()
        partial = source[start:end]

        options = {}
        m = _ngdirective_re.search(partial)
        if m:
            options = json.loads(m.group(1))
            partial = partial.replace(m.group(0), "")
        if with_options:
            return (partial, options)
        return partial

    def build_app(self):
        if not self.options["app_file"]:
            return []
        module = ("/* This file is auto-generated by frasco-angular. DO NOT MODIFY. */\n'use strict';\n"
                  "\nangular.module('%s', [\n  '%s'\n]);\n") % (self.options["app_module"], "',\n  '".join(self.options["app_deps"]))
        self.assets.append(self.options["app_file"])
        return [(os.path.join(self.options["static_dir"], self.options["app_file"]), module)]

    def build_services(self):
        if not self.options["services_file"]:
            return []
        filename = os.path.join(self.options["static_dir"], self.options["services_file"])
        module = ("/* This file is auto-generated by frasco-angular. DO NOT MODIFY. */\n'use strict';\n"
                  "\nvar services = angular.module('%s', ['frasco']);\n") % self.options["services_module"]

        for name, srv in self.app.services.iteritems():
            endpoints = {}
            for view in srv.views:
                endpoints[view.name] = [convert_url_args(view.url_rules[0][0]), view.func.view_args]
            module += ("\nservices.factory('%s', ['frascoServiceFactory', function(frascoServiceFactory) {\n"
                       "return frascoServiceFactory.make('%s', [], %s);\n}]);\n") % \
                        (name, self.app.services_url_prefix, json.dumps(endpoints, indent=2))

        self.assets.append("@angular-frasco", self.options["services_file"])
        self.options["app_deps"].append(self.options["services_module"])
        return [(filename, module)]<commit_msg>added assets generation before global assets build stage<commit_after>from frasco import (Feature, action, Blueprint, View, render_template,\
                    current_context, command, hook, current_app, signal)
from frasco.utils import remove_yaml_frontmatter
from frasco.templating import FileLoader, get_template_source
import os
import json
import re

class AngularView(View):
    def __init__(self, template=None, layout=None, **kwargs):
        view_attrs = ('name', 'url', 'methods', 'url_rules')
        self.route_options = { k: kwargs.pop(k) for k in kwargs.keys() if k not in view_attrs}
        super(AngularView, self).__init__(**kwargs)
        self.template = template
        self.layout = layout

    def dispatch_request(self, *args, **kwargs):
        layout = self.layout or current_app.features.angular.options['views_layout']
        return render_template(layout, **current_context.vars)

_endmacro_re = re.compile(r"\{%-?\s*endmacro\s*%\}")
_ngdirective_re = re.compile(r"\{#\s*ngdirective:(.+)#\}")
_url_arg_re = re.compile(r"<([a-z]:)?([a-z0-9_]+)>")

def convert_url_args(url):
    return _url_arg_re.sub(r":\2", url)

class AngularFeature(Feature):
    name = "angular"
    requires = ["assets"]
    view_files = [("*.ng.html", AngularView)]
    ignore_attributes = ['assets']
    defaults = {"export_macros": [],
                "static_dir": None, # defaults to app.static_folder
                "static_url_path": None, # defaults to app.static_url_path
                "app_file": "app/app.js", # set to False to not generate an app.js
                "app_module": "app",
                "app_deps": [],
                "partials_dir": "app/partials",
                "directives_file": "app/directives/auto.js",
                "directives_module": "directives",
                "views_dir": "app/views",
                "routes_file": "app/routes.js",
                "routes_module": "routes",
                "views_layout": "angular_layout.html",
                "services_file": "app/services/auto.js",
                "services_module": "services",
                "disable_reloading_endpoints": False}

    def init_app(self, app):
        self.app = app
        self.built = False
        if not self.options["static_dir"]:
            self.options["static_dir"] = app.static_folder
        if not self.options["static_url_path"]:
            self.options["static_url_path"] = app.static_url_path

        app.features.assets.expose_package("frasco_angular", __name__)
        app.assets.register({
            "angular-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"],
            "angular-route-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-route.min.js"],
            "angular-resource-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-resource.min.js"],
            "angular-animate-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-animate.min.js"],
            "angular-cookies-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-cookies.min.js"],
            "angular-loader-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-loader.min.js"],
            "angular-sanitize-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-sanitize.min.js"],
            "angular-touch-cdn": [
                "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-touch.min.js"],
            "angular-frasco": [
                {"output": "angular-frasco.min.js", "filters": "jsmin",
                 "contents": ["frasco_angular/angular-frasco.js"]}]})

        app.jinja_env.loader.bottom_loaders.append(FileLoader(
            os.path.join(os.path.dirname(__file__), "layout.html"), "angular_layout.html"))

        signal('before_assets_build').connect(lambda *args: self.build(), weak=False)

        if not self.options["disable_reloading_endpoints"]:
            # adding the url rule ensure that we don't need to reload the app to regenerate the
            # partial file. partial files are still generated when the app starts but will then
            # be served by this endpoint and be generated on the fly
            # note: we don't need to the same for views as a change triggers the reloader
            app.add_url_rule(self.options["static_url_path"] + "/" + self.options["partials_dir"] + "/<macro>.html",
                endpoint="angular_partial", view_func=self.extract_macro)

    @property
    def assets(self):
        if "angular-app" not in self.app.assets:
            self.app.assets.register("angular-app")
        return self.app.assets["angular-app"]

    @command()
    def build(self):
        files = []
        files.extend(self.build_directives())
        files.extend(self.build_routes())
        files.extend(self.build_services())
        files.extend(self.build_app())
        for filename, source in files:
            if not os.path.exists(os.path.dirname(filename)):
                os.makedirs(os.path.dirname(filename))
            with open(filename, 'w') as f:
                f.write(source)

    @command()
    def clean(self):
        files = []
        files.extend(self.build_directives())
        files.extend(self.build_routes())
        files.extend(self.build_services())
        files.extend(self.build_app())
        for filename, source in files:
            if os.path.exists(filename):
                os.unlink(filename)

    @hook()
    def before_request(self):
        if not self.built:
            self.build()
            self.built = True

    def build_routes(self):
        files = []
        views = []
        for name, bp in self.app.blueprints.iteritems():
            if isinstance(bp, Blueprint):
                for v in bp.views.itervalues():
                    if isinstance(v, AngularView):
                        views.append((bp.url_prefix, v))

        base_url = self.options["static_url_path"] + "/" + self.options["views_dir"] + "/"
        when_tpl = "$routeProvider.when('%s', %s);"
        routes = []
        for url_prefix, view in views:
            files.append(self.export_view(view.template))
            for url, options in view.url_rules:
                spec = dict(view.route_options, templateUrl=base_url + view.template)
                if url_prefix:
                    url = url_prefix + url
                url = convert_url_args(url)
                routes.append(when_tpl % (url, json.dumps(spec)))

        routes.append("$routeProvider.otherwise({redirectTo: function(params, path, search) { window.location.href = path; }});")
        module = ("/* This file is auto-generated by frasco-angular. DO NOT MODIFY. */\n'use strict';\n\nangular.module('%s',"
                  "['ngRoute']).config(['$routeProvider', '$locationProvider',\n"
                  "    function($routeProvider, $locationProvider) {\n        $locationProvider.html5Mode(true);\n"
                  "        %s\n    }\n]);\n") % (self.options["routes_module"], "\n        ".join(routes))
        filename = os.path.join(self.options["static_dir"], self.options["routes_file"])
        files.append((filename, module))
        self.assets.append("@angular-route-cdn",
            {"filters": "jsmin", "contents": [self.options["routes_file"]]})
        self.options["app_deps"].append(self.options["routes_module"])
        return files

    def export_view(self, filename):
        source = remove_yaml_frontmatter(get_template_source(self.app, filename))
        dest = os.path.join(self.options["static_dir"], self.options["views_dir"], filename)
        return (dest, source)

    def build_directives(self):
        files = []
        directives = {}
        for macro in self.options["export_macros"]:
            filename, source, directives[macro] = self.export_macro(macro)
            files.append((filename, source))

        if not files:
            return files

        module = ("/* This file is auto-generated by frasco-angular. DO NOT MODIFY. */\n'use strict';\n"
                  "\n(function() {\n\nvar directives = angular.module('%s', []);\n\n") % self.options["directives_module"]
        for name, options in directives.iteritems():
            name = options.pop("name", name)
            module += "directives.directive('%s', function() {\nreturn %s;\n});\n\n" % (name, json.dumps(options, indent=4))

        module += "})();";
        filename = os.path.join(self.options["static_dir"], self.options["directives_file"])
        files.append((filename, module))
        self.assets.append({"filters": "jsmin", "contents": [self.options["directives_file"]]})
        self.options["app_deps"].append(self.options["directives_module"])
        return files

    def export_macro(self, macro):
        partial, options = self.extract_macro(macro, True)
        filename = os.path.join(self.options["static_dir"], self.options["partials_dir"], macro + ".html")
        url = self.options["static_url_path"] + "/" + self.options["partials_dir"] + "/" + macro + ".html"
        options["templateUrl"] = url
        return (filename, partial.strip(), options)

    def extract_macro(self, macro, with_options=False):
        template = self.app.jinja_env.macros.resolve_template(macro)
        if not template:
            raise Exception("Macro '%s' cannot be exported to angular because it does not exist" % macro)
        source = get_template_source(self.app, template)

        m = re.search(r"\{%\s*macro\s+" + re.escape(macro), source)
        if not m:
            raise Exception("Macro '%s' not found in template %s" % (macro, template))
        start = source.find("%}", m.start()) + 2
        end = _endmacro_re.search(source, start).start()
        partial = source[start:end]

        options = {}
        m = _ngdirective_re.search(partial)
        if m:
            options = json.loads(m.group(1))
            partial = partial.replace(m.group(0), "")
        if with_options:
            return (partial, options)
        return partial

    def build_app(self):
        if not self.options["app_file"]:
            return []
        module = ("/* This file is auto-generated by frasco-angular. DO NOT MODIFY. */\n'use strict';\n"
                  "\nangular.module('%s', [\n  '%s'\n]);\n") % (self.options["app_module"], "',\n  '".join(self.options["app_deps"]))
        self.assets.append({"filters": "jsmin", "contents": [self.options["app_file"]]})
        return [(os.path.join(self.options["static_dir"], self.options["app_file"]), module)]

    def build_services(self):
        if not self.options["services_file"]:
            return []
        filename = os.path.join(self.options["static_dir"], self.options["services_file"])
        module = ("/* This file is auto-generated by frasco-angular. DO NOT MODIFY. */\n'use strict';\n"
                  "\n(function() {\n\nvar services = angular.module('%s', ['frasco']);\n") % self.options["services_module"]

        for name, srv in self.app.services.iteritems():
            endpoints = {}
            for view in srv.views:
                endpoints[view.name] = [convert_url_args(view.url_rules[0][0]), view.func.view_args]
            module += ("\nservices.factory('%s', ['frascoServiceFactory', function(frascoServiceFactory) {\n"
                       "return frascoServiceFactory.make('%s', [], %s);\n}]);\n") % \
                        (name, self.app.services_url_prefix, json.dumps(endpoints, indent=2))

        module += "\n})();";
        self.assets.append("@angular-frasco",
            {"filters": "jsmin", "contents": [self.options["services_file"]]})
        self.options["app_deps"].append(self.options["services_module"])
        return [(filename, module)]<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
#    Project: freesas
#             https://github.com/kif/freesas
#
#    Copyright (C) 2017  European Synchrotron Radiation Facility, Grenoble, France
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

__authors__ = ["Martha Brennich"]
__license__ = "MIT"
__date__ = "25/07/2020"

import unittest
import logging
from sys import version_info
from unittest.mock import patch, mock_open
from numpy import array, allclose
from ..sasio import parse_ascii_data, load_scattering_data
logger = logging.getLogger(__name__)

#mock_open under 3.6 needs some patching up
# Code from https://github.com/python/cpython/blob/3.8/Lib/unittest/mock.py
if version_info.minor > 7:
    my_mock_open = mock_open
else:
    def my_mock_open(mock=None, read_data=''):
        import io

        def _to_stream(read_data):
            if isinstance(read_data, bytes):
                return io.BytesIO(read_data)
            else:
                return io.StringIO(read_data)
        _read_data = _to_stream(read_data)
        _state = [_read_data, None]
        basic_mock = mock_open(mock, read_data)
        handle = basic_mock.return_value

        def _iter_side_effect():
            if handle.readline.return_value is not None:
                while True:
                    yield handle.readline.return_value
            for line in _state[0]:
                yield line

        def _next_side_effect():
            if handle.readline.return_value is not None:
                return handle.readline.return_value
            return next(_state[0])

        handle.__iter__.side_effect = _iter_side_effect
        handle.__next__.side_effect = _next_side_effect

        return basic_mock

class TestSasIO(unittest.TestCase):

    def test_parse_3_ok(self):
        """
        Test for successful parsing of file with some invalid lines
        """
        file_content = ["Test data for",
                        "file parsing",
                        "1 1 1",
                        "2 a 2",
                        "3 3 3",
                        "some stuff at the end",
                        ]
        expected_result = array([[1.0, 1.0, 1.0], [3.0, 3.0, 3.0]])
        data = parse_ascii_data(file_content, number_of_columns=3)
        self.assertTrue(allclose(data, expected_result, 1e-7),
                        msg="3 column parse returns expected result")

    def test_parse_no_data(self):
        """
        Test that an empty input list raises a ValueError
        """
        file_content = []
        with self.assertRaises(ValueError, msg="Empty list cannot be parsed"):
            parse_ascii_data(file_content, number_of_columns=3)

    def test_parse_no_valid_data(self):
        """
        Test that an input list with no valid data raises a ValueError
        """
        file_content = ["a a a", "2 4", "3 4 5 6", "# 3 4 6"]
        with self.assertRaises(ValueError,
                               msg="File with no float float float data"
                                   " cannot be parsed"):
            parse_ascii_data(file_content, number_of_columns=3)

    def test_load_clean_data(self):
        """
        Test that clean float float float data is loaded correctly.
        """
        file_content = ["# Test data for"
                        "# file parsing",
                        "1 1 1",
                        "2.0 2.0 1.0",
                        "3 3 3",
                        "#REMARK some stuff at the end",
                        ]
        expected_result = array([[1.0, 1.0, 1.0],
                                 [2.0, 2.0, 1.0],
                                 [3.0, 3.0, 3.0]])
        file_data = "\n".join(file_content)
        mocked_open = my_mock_open(read_data=file_data)
        with patch('builtins.open', mocked_open):
            with patch('numpy.DataSource.open', mocked_open):
                data = load_scattering_data("test")
        self.assertTrue(allclose(data, expected_result, 1e-7),
                        msg="Sunny data loaded correctly")

    def test_load_data_with_unescaped_header(self):
        """
        Test that an unescaped header does not hinder loading.
        """
        file_content = ["1 1 1",
                        "2.0 2.0 1.0",
                        "3 3 3",
                        "REMARK some stuff at the end"
                        ]
        expected_result = array([[1.0, 1.0, 1.0],
                                 [2.0, 2.0, 1.0],
                                 [3.0, 3.0, 3.0]])
        file_data = "\n".join(file_content)
        mocked_open = my_mock_open(read_data=file_data)
        with patch('builtins.open', mocked_open):
            with patch('numpy.DataSource.open', mocked_open):
                data = load_scattering_data("test")
        self.assertTrue(allclose(data, expected_result, 1e-7),
                        msg="Sunny data loaded correctly")

    def test_load_data_with_unescaped_footer(self):
        """
        Test that an unescaped footer does not hinder loading.
        """
        file_content = ["Test data for"
                        "file parsing",
                        "1 1 1",
                        "2.0 2.0 1.0",
                        "3 3 3",
                        ]
        expected_result = array([[1.0, 1.0, 1.0],
                                 [2.0, 2.0, 1.0],
                                 [3.0, 3.0, 3.0]])
        file_data = "\n".join(file_content)
        mocked_open = my_mock_open(read_data=file_data)
        with patch('builtins.open', mocked_open):
            with patch('numpy.DataSource.open', mocked_open):
                data = load_scattering_data("test")
        self.assertTrue(allclose(data, expected_result, 1e-7),
                        msg="Sunny data loaded correctly")

    def test_load_invalid_data(self):
        """
        Test that invalid data raises a ValueError.
        """
        file_content = ["a a a", "2 4", "3 4 5 6", "# 3 4 6"]
        file_data = "\n".join(file_content)
        mocked_open = my_mock_open(read_data=file_data)

        with patch('builtins.open', mocked_open):
            with patch('numpy.DataSource.open', mocked_open):
                with self.assertRaises(ValueError,
                                       msg="File with no float float float "
                                           "data cannot be loaded"):
                    load_scattering_data("test")

def suite():
    test_suite = unittest.TestSuite()
    test_suite.addTest(TestSasIO("test_parse_3_ok"))
    test_suite.addTest(TestSasIO("test_parse_no_data"))
    test_suite.addTest(TestSasIO("test_parse_no_valid_data"))
    test_suite.addTest(TestSasIO("test_load_clean_data"))
    test_suite.addTest(TestSasIO("test_load_data_with_unescaped_header"))
    test_suite.addTest(TestSasIO("test_load_data_with_unescaped_footer"))
    test_suite.addTest(TestSasIO("test_load_invalid_data"))
    return test_suite

if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite())
<commit_msg>Lazy attempt for mock_open: Copy code from python 3.8 into project<commit_after># -*- coding: utf-8 -*-
#
#    Project: freesas
#             https://github.com/kif/freesas
#
#    Copyright (C) 2017  European Synchrotron Radiation Facility, Grenoble, France
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

__authors__ = ["Martha Brennich"]
__license__ = "MIT"
__date__ = "25/07/2020"

import unittest
import logging
from sys import version_info
from numpy import array, allclose
from ..sasio import parse_ascii_data, load_scattering_data
if version_info.minor > 6:
    from unittest.mock import mock_open, patch
else:
    from .mock_open_38 import mock_open
    from unittest.mock import patch
logger = logging.getLogger(__name__)

class TestSasIO(unittest.TestCase):

    def test_parse_3_ok(self):
        """
        Test for successful parsing of file with some invalid lines
        """
        file_content = ["Test data for",
                        "file parsing",
                        "1 1 1",
                        "2 a 2",
                        "3 3 3",
                        "some stuff at the end",
                        ]
        expected_result = array([[1.0, 1.0, 1.0], [3.0, 3.0, 3.0]])
        data = parse_ascii_data(file_content, number_of_columns=3)
        self.assertTrue(allclose(data, expected_result, 1e-7),
                        msg="3 column parse returns expected result")

    def test_parse_no_data(self):
        """
        Test that an empty input list raises a ValueError
        """
        file_content = []
        with self.assertRaises(ValueError, msg="Empty list cannot be parsed"):
            parse_ascii_data(file_content, number_of_columns=3)

    def test_parse_no_valid_data(self):
        """
        Test that an input list with no valid data raises a ValueError
        """
        file_content = ["a a a", "2 4", "3 4 5 6", "# 3 4 6"]
        with self.assertRaises(ValueError,
                               msg="File with no float float float data"
                                   " cannot be parsed"):
            parse_ascii_data(file_content, number_of_columns=3)

    def test_load_clean_data(self):
        """
        Test that clean float float float data is loaded correctly.
        """
        file_content = ["# Test data for"
                        "# file parsing",
                        "1 1 1",
                        "2.0 2.0 1.0",
                        "3 3 3",
                        "#REMARK some stuff at the end",
                        ]
        expected_result = array([[1.0, 1.0, 1.0],
                                 [2.0, 2.0, 1.0],
                                 [3.0, 3.0, 3.0]])
        file_data = "\n".join(file_content)
        mocked_open = mock_open(read_data=file_data)
        with patch('builtins.open', mocked_open):
            with patch('numpy.DataSource.open', mocked_open):
                data = load_scattering_data("test")
        self.assertTrue(allclose(data, expected_result, 1e-7),
                        msg="Sunny data loaded correctly")

    def test_load_data_with_unescaped_header(self):
        """
        Test that an unescaped header does not hinder loading.
        """
        file_content = ["1 1 1",
                        "2.0 2.0 1.0",
                        "3 3 3",
                        "REMARK some stuff at the end"
                        ]
        expected_result = array([[1.0, 1.0, 1.0],
                                 [2.0, 2.0, 1.0],
                                 [3.0, 3.0, 3.0]])
        file_data = "\n".join(file_content)
        mocked_open = mock_open(read_data=file_data)
        with patch('builtins.open', mocked_open):
            with patch('numpy.DataSource.open', mocked_open):
                data = load_scattering_data("test")
        self.assertTrue(allclose(data, expected_result, 1e-7),
                        msg="Sunny data loaded correctly")

    def test_load_data_with_unescaped_footer(self):
        """
        Test that an unescaped footer does not hinder loading.
        """
        file_content = ["Test data for"
                        "file parsing",
                        "1 1 1",
                        "2.0 2.0 1.0",
                        "3 3 3",
                        ]
        expected_result = array([[1.0, 1.0, 1.0],
                                 [2.0, 2.0, 1.0],
                                 [3.0, 3.0, 3.0]])
        file_data = "\n".join(file_content)
        mocked_open = mock_open(read_data=file_data)
        with patch('builtins.open', mocked_open):
            with patch('numpy.DataSource.open', mocked_open):
                data = load_scattering_data("test")
        self.assertTrue(allclose(data, expected_result, 1e-7),
                        msg="Sunny data loaded correctly")

    def test_load_invalid_data(self):
        """
        Test that invalid data raises a ValueError.
        """
        file_content = ["a a a", "2 4", "3 4 5 6", "# 3 4 6"]
        file_data = "\n".join(file_content)
        mocked_open = mock_open(read_data=file_data)

        with patch('builtins.open', mocked_open):
            with patch('numpy.DataSource.open', mocked_open):
                with self.assertRaises(ValueError,
                                       msg="File with no float float float "
                                           "data cannot be loaded"):
                    load_scattering_data("test")

def suite():
    test_suite = unittest.TestSuite()
    test_suite.addTest(TestSasIO("test_parse_3_ok"))
    test_suite.addTest(TestSasIO("test_parse_no_data"))
    test_suite.addTest(TestSasIO("test_parse_no_valid_data"))
    test_suite.addTest(TestSasIO("test_load_clean_data"))
    test_suite.addTest(TestSasIO("test_load_data_with_unescaped_header"))
    test_suite.addTest(TestSasIO("test_load_data_with_unescaped_footer"))
    test_suite.addTest(TestSasIO("test_load_invalid_data"))
    return test_suite

if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite())
<|endoftext|>


<commit_before># -*- coding: UTF-8 -*-
# Copyright 2008-2017 Luc Saffre
# License: BSD (see file COPYING for details)

from __future__ import unicode_literals
from builtins import str
from builtins import object

import logging
logger = logging.getLogger(__name__)

from django.db import models
from django.conf import settings

from lino.api import dd
from lino import mixins
from django.utils.translation import ugettext_lazy as _
from lino.modlib.plausibility.choicelists import Checker
from lino_xl.lib.contacts.roles import ContactsUser, ContactsStaff

from .choicelists import PlaceTypes, CountryDrivers

FREQUENT_COUNTRIES = ['BE', 'NL', 'DE', 'FR', 'LU']
"""A list of frequent countries used by some demo fixtures."""

class Country(mixins.BabelNamed):

    class Meta(object):
        verbose_name = _("Country")
        verbose_name_plural = _("Countries")
        abstract = dd.is_abstract_model(__name__, 'Country')

    isocode = models.CharField(
        max_length=4, primary_key=True,
        verbose_name=_("ISO code"),
        help_text=_("""\
        The two-letter code for this country as defined by ISO 3166-1.
        For countries that no longer exist it may be a 4-letter code."""))
    #~ name = models.CharField(max_length=200)
    #~ name = d.BabelCharField(max_length=200,verbose_name=_("Designation"))

    short_code = models.CharField(
        max_length=4, blank=True,
        verbose_name=_("Short code"),
        help_text=_("""A short abbreviation for regional usage. Obsolete."""))

    iso3 = models.CharField(
        max_length=3, blank=True,
        verbose_name=_("ISO-3 code"),
        help_text=_("The three-letter code for this country "
                    "as defined by ISO 3166-1."))

    def allowed_city_types(self):
        cd = getattr(CountryDrivers, self.isocode, None)
        if cd is not None:
            return cd.region_types + cd.city_types
        return list(PlaceTypes.items())

    @classmethod
    def get_actual_countries(cls):
        return cls.objects.all()

Country.set_widget_options('short_code', width=10)
Country.set_widget_options('isocode', width=10)

class Countries(dd.Table):
    """The table of all countries."""

    #~ label = _("Countries")
    model = 'countries.Country'
    required_roles = dd.login_required(ContactsStaff)
    order_by = ["name", "isocode"]
    column_names = "name isocode *"
    detail_layout = """
    isocode name short_code
    countries.PlacesByCountry
    """
    insert_layout = """
    isocode short_code
    name
    """

from lino.mixins import Hierarchical

class Place(Hierarchical, mixins.BabelNamed):
    class Meta(object):
        verbose_name = _("Place")
        verbose_name_plural = _("Places")
        abstract = dd.is_abstract_model(__name__, 'Place')

        if not settings.SITE.allow_duplicate_cities:
            unique_together = (
                'country', 'parent', 'name', 'type', 'zip_code')

    country = models.ForeignKey('countries.Country')
    zip_code = models.CharField(max_length=8, blank=True)
    type = PlaceTypes.field(blank=True)
    show_type = models.BooleanField(_("Show type"), default=False)

    # parent = models.ForeignKey(
    #     'self',
    #     blank=True, null=True,
    #     verbose_name=_("Part of"),
    #     help_text=_("The superordinate geographic place "
    #                 "of which this place is a part."))

    # def get_parents(self, *grandparents):
    #     if self.parent_id:
    #         return self.parent.get_parents(self, *grandparents)
    #     return [self] + list(grandparents)

    @dd.chooser()
    def type_choices(cls, country):
        if country is not None:
            allowed = country.allowed_city_types()
            return [(i, t) for i, t in PlaceTypes.choices if i in allowed]
        return PlaceTypes.choices

    def get_choices_text(self, request, actor, field):
        """
        Extends the default behaviour (which would simply diplay this
        city in the current language) by also adding the name in other
        languages and the type between parentheses.
        """
        names = [self.name]
        for lng in settings.SITE.BABEL_LANGS:
            n = getattr(self, 'name' + lng.suffix)
            if n and n not in names:
                names.append(n)
                #~ s += ' / ' + n
        if len(names) == 1:
            s = names[0]
        else:
            s = ' / '.join(names)
            # s = "%s (%s)" % (names[0], ', '.join(names[1:]))
        if self.show_type:
            s += " (%s)" % str(self.type)
        return s

    @classmethod
    def get_cities(cls, country):
        if country is None:
            cd = None
            flt = models.Q()
        else:
            cd = getattr(CountryDrivers, country.isocode, None)
            flt = models.Q(country=country)

        #~ types = [PlaceTypes.blank_item] 20120829
        types = [None]
        if cd:
            types += cd.city_types
            #~ flt = flt & models.Q(type__in=cd.city_types)
        else:
            types += [v for v in list(PlaceTypes.items()) if v.value >= '50']
            #~ flt = flt & models.Q(type__gte=PlaceTypes.get_by_value('50'))
        flt = flt & models.Q(type__in=types)
        #~ flt = flt | models.Q(type=PlaceTypes.blank_item)
        return cls.objects.filter(flt).order_by('name')

        #~ if country is not None:
            #~ cd = getattr(CountryDrivers,country.isocode,None)
            #~ if cd:
                #~ return Place.objects.filter(
                    #~ country=country,
                    #~ type__in=cd.city_types).order_by('name')
            #~ return country.place_set.order_by('name')
        #~ return cls.city.field.rel.model.objects.order_by('name')

dd.update_field(
    Place, 'parent', verbose_name=_("Part of"),
    help_text=_("The superordinate geographic place "
                "of which this place is a part."))

class Places(dd.Table):
    help_text = _("""
    The table of known geographical places.
    A geographical place can be a city, a town, a suburb,
    a province, a lake... any named geographic entity,
    except for countries because these have their own table.
    """)

    model = 'countries.Place'
    required_roles = dd.login_required(ContactsStaff)
    order_by = "country name".split()
    column_names = "country name type zip_code parent *"
    detail_layout = """
    name country
    type parent zip_code id
    PlacesByPlace
    """

class PlacesByPlace(Places):
    label = _("Subdivisions")
    master_key = 'parent'
    column_names = "overview type zip_code *"

class PlacesByCountry(Places):
    master_key = 'country'
    column_names = "name type zip_code *"
    required_roles = dd.login_required()
    details_of_master_template = _("%(details)s in %(master)s")

class PlaceChecker(Checker):
    """The name of a geographical place
    (:attr:`lino_xl.lib.countries.models.Place.name`) should not
    consist of only digits.

    """
    model = 'countries.Place'
    verbose_name = _("Check plausibility of geographical places.")

    def get_plausibility_problems(self, obj, fix=False):
        if obj.name.isdigit():
            yield (False, _("Name contains only digits."))

PlaceChecker.activate()
<commit_msg>http://luc.lino-framework.org/blog/2017/0913.html<commit_after># -*- coding: UTF-8 -*-
# Copyright 2008-2017 Luc Saffre
# License: BSD (see file COPYING for details)

from __future__ import unicode_literals
from builtins import str
from builtins import object

import logging
logger = logging.getLogger(__name__)

from django.db import models
from django.conf import settings

from lino.api import dd
from lino import mixins
from django.utils.translation import ugettext_lazy as _
from lino.modlib.plausibility.choicelists import Checker
from lino_xl.lib.contacts.roles import ContactsUser, ContactsStaff

from .choicelists import PlaceTypes, CountryDrivers

FREQUENT_COUNTRIES = ['BE', 'NL', 'DE', 'FR', 'LU']
"""A list of frequent countries used by some demo fixtures."""

class Country(mixins.BabelNamed):

    class Meta(object):
        verbose_name = _("Country")
        verbose_name_plural = _("Countries")
        abstract = dd.is_abstract_model(__name__, 'Country')

    isocode = models.CharField(
        max_length=4, primary_key=True,
        verbose_name=_("ISO code"),
        help_text=_("""\
        The two-letter code for this country as defined by ISO 3166-1.
        For countries that no longer exist it may be a 4-letter code."""))
    #~ name = models.CharField(max_length=200)
    #~ name = d.BabelCharField(max_length=200,verbose_name=_("Designation"))

    short_code = models.CharField(
        max_length=4, blank=True,
        verbose_name=_("Short code"),
        help_text=_("""A short abbreviation for regional usage. Obsolete."""))

    iso3 = models.CharField(
        max_length=3, blank=True,
        verbose_name=_("ISO-3 code"),
        help_text=_("The three-letter code for this country "
                    "as defined by ISO 3166-1."))

    def allowed_city_types(self):
        cd = getattr(CountryDrivers, self.isocode, None)
        if cd is not None:
            return cd.region_types + cd.city_types
        return list(PlaceTypes.items())

    @classmethod
    def get_actual_countries(cls):
        return cls.objects.all()

Country.set_widget_options('short_code', width=10)
Country.set_widget_options('isocode', width=10)

class Countries(dd.Table):
    """The table of all countries."""

    #~ label = _("Countries")
    model = 'countries.Country'
    required_roles = dd.login_required(ContactsStaff)
    order_by = ["name", "isocode"]
    column_names = "name isocode *"
    detail_layout = """
    isocode name short_code
    countries.PlacesByCountry
    """
    insert_layout = """
    isocode short_code
    name
    """

from lino.mixins import Hierarchical

# @dd.python_2_unicode_compatible
class Place(Hierarchical, mixins.BabelNamed):
    class Meta(object):
        verbose_name = _("Place")
        verbose_name_plural = _("Places")
        abstract = dd.is_abstract_model(__name__, 'Place')

        if not settings.SITE.allow_duplicate_cities:
            unique_together = (
                'country', 'parent', 'name', 'type', 'zip_code')

    country = models.ForeignKey('countries.Country')
    zip_code = models.CharField(max_length=8, blank=True)
    type = PlaceTypes.field(blank=True)
    show_type = models.BooleanField(_("Show type"), default=False)

    # parent = models.ForeignKey(
    #     'self',
    #     blank=True, null=True,
    #     verbose_name=_("Part of"),
    #     help_text=_("The superordinate geographic place "
    #                 "of which this place is a part."))

    # def get_parents(self, *grandparents):
    #     if self.parent_id:
    #         return self.parent.get_parents(self, *grandparents)
    #     return [self] + list(grandparents)

    # def __str__(self):
    #     if self.zip_code:
    #         return "{} {}".format(
    #             dd.babelattr(self, 'name'), self.zip_code)
    #     return dd.babelattr(self, 'name')

    @dd.chooser()
    def type_choices(cls, country):
        if country is not None:
            allowed = country.allowed_city_types()
            return [(i, t) for i, t in PlaceTypes.choices if i in allowed]
        return PlaceTypes.choices

    def get_choices_text(self, request, actor, field):
        """
        Extends the default behaviour (which would simply diplay this
        city in the current language) by also adding the name in other
        languages and the type between parentheses.
        """
        names = [self.name]
        for lng in settings.SITE.BABEL_LANGS:
            n = getattr(self, 'name' + lng.suffix)
            if n and n not in names:
                names.append(n)
                #~ s += ' / ' + n
        if len(names) == 1:
            s = names[0]
        else:
            s = ' / '.join(names)
            # s = "%s (%s)" % (names[0], ', '.join(names[1:]))
        if self.show_type:
            s += " (%s)" % str(self.type)
        if self.zip_code:
            s += " (%s)" % self.zip_code
        return s

    @classmethod
    def get_cities(cls, country):
        if country is None:
            cd = None
            flt = models.Q()
        else:
            cd = getattr(CountryDrivers, country.isocode, None)
            flt = models.Q(country=country)

        #~ types = [PlaceTypes.blank_item] 20120829
        types = [None]
        if cd:
            types += cd.city_types
            #~ flt = flt & models.Q(type__in=cd.city_types)
        else:
            types += [v for v in list(PlaceTypes.items()) if v.value >= '50']
            #~ flt = flt & models.Q(type__gte=PlaceTypes.get_by_value('50'))
        flt = flt & models.Q(type__in=types)
        #~ flt = flt | models.Q(type=PlaceTypes.blank_item)
        return cls.objects.filter(flt).order_by('name')

        #~ if country is not None:
            #~ cd = getattr(CountryDrivers,country.isocode,None)
            #~ if cd:
                #~ return Place.objects.filter(
                    #~ country=country,
                    #~ type__in=cd.city_types).order_by('name')
            #~ return country.place_set.order_by('name')
        #~ return cls.city.field.rel.model.objects.order_by('name')

dd.update_field(
    Place, 'parent', verbose_name=_("Part of"),
    help_text=_("The superordinate geographic place "
                "of which this place is a part."))

class Places(dd.Table):
    help_text = _("""
    The table of known geographical places.
    A geographical place can be a city, a town, a suburb,
    a province, a lake... any named geographic entity,
    except for countries because these have their own table.
    """)

    model = 'countries.Place'
    required_roles = dd.login_required(ContactsStaff)
    order_by = "country name".split()
    column_names = "country name type zip_code parent *"
    detail_layout = """
    name country
    type parent zip_code id
    PlacesByPlace
    """

class PlacesByPlace(Places):
    label = _("Subdivisions")
    master_key = 'parent'
    column_names = "overview type zip_code *"

class PlacesByCountry(Places):
    master_key = 'country'
    column_names = "name type zip_code *"
    required_roles = dd.login_required()
    details_of_master_template = _("%(details)s in %(master)s")

class PlaceChecker(Checker):
    """The name of a geographical place
    (:attr:`lino_xl.lib.countries.models.Place.name`) should not
    consist of only digits.

    """
    model = 'countries.Place'
    verbose_name = _("Check plausibility of geographical places.")

    def get_plausibility_problems(self, obj, fix=False):
        if obj.name.isdigit():
            yield (False, _("Name contains only digits."))

PlaceChecker.activate()
<|endoftext|>


<commit_before>#!/usr/bin/python
import os
import numpy as np
import multiprocessing as mp
import subprocessing as sub
import shlex

#Make sure a directory path contains a trailing /#
def fixDirName(dirpath):
	if dirpath[-1] != '/':
		dirpath += '/'
	return dirpath

#Check if a directory exists, make it if needed#
def makeDir(dirpath):
	if not os.path.exists(dirpath):
		os.mkdir(dirpath)
	return 0

#Import sample names from a text file, if specifying a subset to process#
def importSampleList(infile):
	if os.path.exists(infile):
		files = []
		with open(infile, 'r') as IN:
			for x in IN:
				if len(x.rstrip().split('\t')) > 1:
					files.append(x.rstrip().split('\t')[0])
				else:
					files.append(x.rstrip())
	else:
		errorText = '\nERROR: the specified sample name file does not exist, please fix\n\t' + infile + '\n'
		print(errorText)
		raise SystemExit

	return files

#Get a list of samples to run processing for a specific step of the pipeline on#
def getSampleList(folder, sampleArg, extension):
	#to process all samples in the input folder#
	fileList = [ x for x in os.listdir(folder) if extension in x.split('.') ]

	#to process a specific subset of samples#
	if sampleArg:
		sampleList = importSampleList(sampleArg)
		fileList = [ x for x in fileList if any(y in x for y in sampleList) ]

		if len(sampleList) != len(fileList):
			errorText = '\nERROR: ' + str(len(fileList)) + ' samples exist for processing, but '
			errorText += str(len(sampleList)) + ' were specified in the sample list file, please fix any discrepancies\n'
			print(errorText)
			raise SystemExit

	fileList = [folder + x for x in fileList]
	return fileList

#Import information about samples from a reference .txt file#
def importInfoFile(infoFile, columns, useFunction, skiprows=0):
	functionDict =	{
					'normalize': {'names': ('name', 'method', 'cells'), 'formats': ('S50', 'S50', 'int')},
					'normref': {'names': ('chrom', 'abspos', 'gc'), 'formats': ('S10', int', 'float')}
					}

	if not infoFile:
		return functionDict[useFunction]

	if skiprows == 0:
		data = np.loadtxt(infoFile, usecols=columns, dtype=functionDict[useFunction])
	else:
		data = np.loadtxt(infoFile, usecols=columns, dtype=functionDict[useFunction], skiprows=skiprows)

	return data

###daemon to run multiprocessing and parallelize tasks###
def daemon(target, argList, name, cpuPerProcess=1):
	print( str( '\t' + str(len(argList)) + ' processes to run to ' + name ) )
	numCPU = mp.cpu_count()
	numWorkers = min( [int(numCPU / cpuPerProcess), len(argList)] )

	pool = mp.Pool(numWorkers)
	processes = [pool.apply_async(target, args=x) for x in argList]
	pool.close()

	for i,j in enumerate(processes):
		j.wait()

		if not j.successful():
			pool.terminate()

			print '\n\n\nprocessing failed, getting traceback now...'

			p = mp.Process(target=target, args=argList[i])
			p.start()
			p.join()
	#	else:
	#		print( str( '\t\t' + str(i+1) + ' of ' + str(len(argList)) + ' processes complete' ) )

	print( str( '\tAll processing to ' + name + ' complete\n' ) )

def zipping(filepath, gunzip=True):
	if filepath.split('.')[-1] != 'gz' and gunzip:
		return filepath
	elif filepath.split('.')[-1] == 'gz' and not gunzip:
		return filepath

	if gunzip:
		cmd = 'gunzip ' + filepath
		fixname = filepath[:-3]
	else:
		cmd = 'gzip ' + filepath
		fixname = filepath + '.gz'

	cmd = shlex.split(cmd)
	p = sub.Popen(cmd)
	p.wait()

	return fixname

<commit_msg>Update common.py<commit_after>#!/usr/bin/python
import os
import numpy as np
import multiprocessing as mp
import subprocessing as sub
import shlex

#Make sure a directory path contains a trailing /#
def fixDirName(dirpath):
	if dirpath[-1] != '/':
		dirpath += '/'
	return dirpath

#Check if a directory exists, make it if needed#
def makeDir(dirpath):
	if not os.path.exists(dirpath):
		os.mkdir(dirpath)
	return 0

#Import sample names from a text file, if specifying a subset to process#
def importSampleList(infile):
	if os.path.exists(infile):
		files = []
		with open(infile, 'r') as IN:
			for x in IN:
				if len(x.rstrip().split('\t')) > 1:
					files.append(x.rstrip().split('\t')[0])
				else:
					files.append(x.rstrip())
	else:
		errorText = '\nERROR: the specified sample name file does not exist, please fix\n\t' + infile + '\n'
		print(errorText)
		raise SystemExit

	return files

#Get a list of samples to run processing for a specific step of the pipeline on#
def getSampleList(folder, sampleArg, extension):
	#to process all samples in the input folder#
	fileList = [ x for x in os.listdir(folder) if extension in x.split('.') ]

	#to process a specific subset of samples#
	if sampleArg:
		sampleList = importSampleList(sampleArg)
		fileList = [ x for x in fileList if any(y in x for y in sampleList) ]

		if len(sampleList) != len(fileList):
			errorText = '\nERROR: ' + str(len(fileList)) + ' samples exist for processing, but '
			errorText += str(len(sampleList)) + ' were specified in the sample list file, please fix any discrepancies\n'
			print(errorText)
			raise SystemExit

	fileList = [folder + x for x in fileList]
	return fileList

#Import information about samples from a reference .txt file#
def importInfoFile(infoFile, columns, useFunction, skiprows=0):
	functionDict =	{
					'normalize': {'names': ('name', 'method', 'cells'), 'formats': ('S50', 'S50', 'int')},
					'normref': {'names': ('chrom', 'abspos', 'gc'), 'formats': ('S10', int', 'float')},
					'interpret': {'names': ('name', 'cells', 'group'), 'formats': ('S50', 'int', 'S50')}
					}

	if not infoFile:
		return functionDict[useFunction]

	if skiprows == 0:
		data = np.loadtxt(infoFile, usecols=columns, dtype=functionDict[useFunction])
	else:
		data = np.loadtxt(infoFile, usecols=columns, dtype=functionDict[useFunction], skiprows=skiprows)

	return data

###daemon to run multiprocessing and parallelize tasks###
def daemon(target, argList, name, cpuPerProcess=1):
	print( str( '\t' + str(len(argList)) + ' processes to run to ' + name ) )
	numCPU = mp.cpu_count()
	numWorkers = min( [int(numCPU / cpuPerProcess), len(argList)] )

	pool = mp.Pool(numWorkers)
	processes = [pool.apply_async(target, args=x) for x in argList]
	pool.close()

	for i,j in enumerate(processes):
		j.wait()

		if not j.successful():
			pool.terminate()

			print '\n\n\nprocessing failed, getting traceback now...'

			p = mp.Process(target=target, args=argList[i])
			p.start()
			p.join()
	#	else:
	#		print( str( '\t\t' + str(i+1) + ' of ' + str(len(argList)) + ' processes complete' ) )

	print( str( '\tAll processing to ' + name + ' complete\n' ) )

def zipping(filepath, gunzip=True):
	if filepath.split('.')[-1] != 'gz' and gunzip:
		return filepath
	elif filepath.split('.')[-1] == 'gz' and not gunzip:
		return filepath

	if gunzip:
		cmd = 'gunzip ' + filepath
		fixname = filepath[:-3]
	else:
		cmd = 'gzip ' + filepath
		fixname = filepath + '.gz'

	cmd = shlex.split(cmd)
	p = sub.Popen(cmd)
	p.wait()

	return fixname

<|endoftext|>


<commit_before>#! /usr/bin/env python2.5
# -*- coding: utf-8 -*-
"""General configuration module"""

from __future__ import with_statement

import os
import optparse
import logging
import ConfigParser

import vmcheckerpaths

DATE_FORMAT = '%Y.%m.%d %H:%M:%S'

cmdline = optparse.OptionParser()
options, args = None, None

config = ConfigParser.RawConfigParser()

def parse_arguments():
    """Parses command-line arguments"""
    global options, args
    options, args = cmdline.parse_args()

def _basic_config():
    """Common configuration"""

    # sets root path
    assert 'VMCHECKER_ROOT' in os.environ, (
            'Environment variable $VMCHECKER_ROOT is not defined')
    vmcheckerpaths.root = os.path.abspath(os.environ['VMCHECKER_ROOT'])

    # sets logging
    logging.basicConfig(level=logging.INFO)

    # parse command-line arguments
    parse_arguments()

def config_storer():
    """Configures storer"""
    _basic_config()

    with open(vmcheckerpaths.storer_config_file()) as handle:
        config.readfp(handle)

    # sets repository path
    vmcheckerpaths.repository = path('DEFAULT', 'Repository')

def config_tester():
    """Configures tester"""
    _basic_config()
    with open(vmcheckerpaths.tester_config_file()) as handle:
        config.readfp(handle)

def get(*args):
    """A convenient wrapper for config.get(), .options() and .sections()"""
    if len(args) == 0:
        return config.sections()
    if len(args) == 1:
        return config.options(args[0])
    if len(args) == 2:
        return config.get(args[0], args[1])
    assert False

def path(section, option):
    """Returns an absolute path derived from an option"""
    return vmcheckerpaths.abspath(config.get(section, option))

def _set_logging_level(option, opt_str, value, parser):
    """Sets the logging level throu command-line arguments"""
    setattr(parser.values, option.dest, True)

    if opt_str == 'verbose':
        logging.getLogger().setLevel(logging.DEBUG)
    if opt_str == 'quiet':
        logging.getLogger().setLevel(logging.WARN)

cmdline.add_option('-v', '--verbose', action='callback', nargs=0,
                   dest='verbose', default=False, callback=_set_logging_level,
                   help='Prints more stuff')
cmdline.add_option('-q', '--quiet', action='callback', nargs=0,
                   dest='quiet', default=False, callback=_set_logging_level,
                   help='Prints less stuff')
<commit_msg>added a list of assigments<commit_after>#! /usr/bin/env python2.5
# -*- coding: utf-8 -*-
"""General configuration module"""

from __future__ import with_statement

import os
import optparse
import logging
import ConfigParser

import vmcheckerpaths

DATE_FORMAT = '%Y.%m.%d %H:%M:%S'

cmdline = optparse.OptionParser()
options, args = None, None

config = ConfigParser.RawConfigParser()

def parse_arguments():
    """Parses command-line arguments"""
    global options, args
    options, args = cmdline.parse_args()

def _basic_config():
    """Common configuration"""

    # sets root path
    assert 'VMCHECKER_ROOT' in os.environ, (
            'Environment variable $VMCHECKER_ROOT is not defined')
    vmcheckerpaths.root = os.path.abspath(os.environ['VMCHECKER_ROOT'])

    # sets logging
    logging.basicConfig(level=logging.INFO)

    # parse command-line arguments
    parse_arguments()

def config_storer():
    """Configures storer"""
    _basic_config()

    with open(vmcheckerpaths.storer_config_file()) as handle:
        config.readfp(handle)

    # sets repository path
    vmcheckerpaths.repository = path('DEFAULT', 'Repository')

def config_tester():
    """Configures tester"""
    _basic_config()
    with open(vmcheckerpaths.tester_config_file()) as handle:
        config.readfp(handle)

def get(*args):
    """A convenient wrapper for config.get(), .options() and .sections()"""
    if len(args) == 0:
        return config.sections()
    if len(args) == 1:
        return config.options(args[0])
    if len(args) == 2:
        return config.get(args[0], args[1])
    assert False

def path(section, option):
    """Returns an absolute path derived from an option"""
    return vmcheckerpaths.abspath(config.get(section, option))

def _set_logging_level(option, opt_str, value, parser):
    """Sets the logging level throu command-line arguments"""
    setattr(parser.values, option.dest, True)

    if opt_str == 'verbose':
        logging.getLogger().setLevel(logging.DEBUG)
    if opt_str == 'quiet':
        logging.getLogger().setLevel(logging.WARN)

def assigments():
    """Returns a list of assigments"""
    return list(config.sections())

cmdline.add_option('-v', '--verbose', action='callback', nargs=0,
                   dest='verbose', default=False, callback=_set_logging_level,
                   help='Prints more stuff')
cmdline.add_option('-q', '--quiet', action='callback', nargs=0,
                   dest='quiet', default=False, callback=_set_logging_level,
                   help='Prints less stuff')
<|endoftext|>