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

"""
Run REDbot as a systemd service.
"""

from configparser import ConfigParser, SectionProxy
import locale
import os
import sys
from urllib.parse import urlsplit

import thor
from thor.events import EventEmitter
from thor.loop import _loop

from redbot import __version__
from redbot.type import RawHeaderListType
from redbot.webui import RedWebUi

_loop.precision = .1

def standalone_main(config: SectionProxy) -> None:
    """Run REDbot as a standalone Web server."""

    # load static files
    static_types = {
        b'.js': b'text/javascript',
        b'.css': b'text/css',
        b'.png': b'image/png',
    }
    static_files = {}
    for root, dirs, files in os.walk(config['static_dir']):
        for name in files:
            try:
                path = os.path.join(root, name)
                uri = os.path.relpath(path, config['static_dir'])
                static_files[b"/static/%s" % uri.encode('utf-8')] = open(path, 'rb').read()
            except IOError:
                sys.stderr.write("* Problem loading %s\n" % path)

    def red_handler(x: EventEmitter) -> None:
        @thor.events.on(x)
        def request_start(method: bytes, uri: bytes, req_hdrs: RawHeaderListType) -> None:
            p_uri = urlsplit(uri)
            if p_uri.path in static_files:
                headers = []
                file_ext = os.path.splitext(p_uri.path)[1].lower()
                content_encoding = static_types.get(file_ext, b'application/octet-stream')
                headers.append((b'Content-Encoding', content_encoding))
                headers.append((b'Cache-Control', b'max-age=300'))
                x.response_start(b"200", b"OK", headers)
                x.response_body(static_files[p_uri.path])
                x.response_done([])
            elif p_uri.path == b"/":
                try:
                    RedWebUi(config, method.decode(config['charset']), p_uri.query,
                             x.response_start, x.response_body, x.response_done)
                except Exception:
                    sys.stderr.write("""

*** FATAL ERROR
REDbot has encountered a fatal error which it really, really can't recover from
in standalone server mode. Details follow.

""")
                    import traceback
                    traceback.print_exc()
                    thor.stop()
                    sys.exit(1)
            else:
                x.response_start(b"404", b"Not Found", [])
                x.response_done([])

    server = thor.http.HttpServer(config.get('host', ''), int(config['port']))
    server.on('exchange', red_handler)

    try:
        thor.run()
    except KeyboardInterrupt:
        sys.stderr.write("Stopping...\n")
        thor.stop()

if __name__ == "__main__":

    from optparse import OptionParser
    usage = "Usage: %prog configfile"
    version = "REDbot version %s" % __version__
    option_parser = OptionParser(usage=usage, version=version)
    (options, args) = option_parser.parse_args()
    if len(args) < 1:
        option_parser.error("Please specify a config file.")

    conf = ConfigParser()
    conf.read(args[0])
    redconf = conf['redbot']

    try:
        locale.setlocale(locale.LC_ALL, locale.normalize(redconf['lang']))
    except ValueError:
        locale.setlocale(locale.LC_ALL, '')

    sys.stderr.write(
        "Starting on PID %s...\n" % os.getpid() + \
        "http://%s:%s/\n" % (redconf['host'], redconf['port']))

    standalone_main(redconf)
<commit_msg>Clean up daemon a bit.<commit_after>#!/usr/bin/env python3

"""
Run REDbot as a daemon.
"""

from configparser import ConfigParser, SectionProxy
import locale
import os
import sys
from urllib.parse import urlsplit

import thor
from thor.events import EventEmitter
from thor.loop import _loop

from redbot import __version__
from redbot.type import RawHeaderListType
from redbot.webui import RedWebUi

_loop.precision = .1

def standalone_main(config: SectionProxy) -> None:
    """Run REDbot as a standalone Web server."""

    # load static files
    static_types = {
        b'.js': b'text/javascript',
        b'.css': b'text/css',
        b'.png': b'image/png',
    }
    static_files = {}
    for root, dirs, files in os.walk(config['static_dir']):
        for name in files:
            try:
                path = os.path.join(root, name)
                uri = os.path.relpath(path, config['static_dir'])
                static_files[b"/static/%s" % uri.encode('utf-8')] = open(path, 'rb').read()
            except IOError:
                sys.stderr.write("* Problem loading %s\n" % path)

    def red_handler(x: EventEmitter) -> None:
        @thor.events.on(x)
        def request_start(method: bytes, uri: bytes, req_hdrs: RawHeaderListType) -> None:
            p_uri = urlsplit(uri)
            if p_uri.path in static_files:
                headers = []
                file_ext = os.path.splitext(p_uri.path)[1].lower()
                content_encoding = static_types.get(file_ext, b'application/octet-stream')
                headers.append((b'Content-Encoding', content_encoding))
                headers.append((b'Cache-Control', b'max-age=300'))
                x.response_start(b"200", b"OK", headers)
                x.response_body(static_files[p_uri.path])
                x.response_done([])
            elif p_uri.path == b"/":
                try:
                    RedWebUi(config, method.decode(config['charset']), p_uri.query,
                             x.response_start, x.response_body, x.response_done)
                except Exception:
                    sys.stderr.write("""

*** FATAL ERROR
REDbot has encountered a fatal error which it really, really can't recover from
in standalone server mode. Details follow.

""")
                    import traceback
                    traceback.print_exc()
                    thor.stop()
                    sys.exit(1)
            else:
                x.response_start(b"404", b"Not Found", [])
                x.response_done([])

    server = thor.http.HttpServer(config.get('host', ''), int(config['port']))
    server.on('exchange', red_handler)

    try:
        thor.run()
    except KeyboardInterrupt:
        sys.stderr.write("Stopping...\n")
        thor.stop()

if __name__ == "__main__":

    from optparse import OptionParser
    usage = "Usage: %prog configfile"
    version = "REDbot version %s" % __version__
    option_parser = OptionParser(usage=usage, version=version)
    (options, args) = option_parser.parse_args()
    if len(args) < 1:
        option_parser.error("Please specify a config file.")

    conf = ConfigParser()
    conf.read(args[0])
    redconf = conf['redbot']

    try:
        locale.setlocale(locale.LC_ALL, locale.normalize(redconf['lang']))
    except ValueError:
        locale.setlocale(locale.LC_ALL, '')

    sys.stderr.write(
        "Starting on PID %s...\n" % os.getpid() + \
        "http://%s:%s/\n" % (redconf.get('host', ''), redconf['port']))

    standalone_main(redconf)
<|endoftext|>


<commit_before>import json
import importlib
import os
import sys

import h5py
import numpy as np
from tensorflow import get_default_session, get_default_graph, keras

from astroNN.config import custom_model_path_reader
from astroNN.nn.losses import losses_lookup
from astroNN.nn.utilities import Normalizer
from astroNN.models.apogee_models import ApogeeBCNN, ApogeeCVAE, ApogeeCNN, ApogeeBCNNCensored, ApogeeDR14GaiaDR2BCNN, \
    StarNet2017
from astroNN.models.misc_models import Cifar10CNN, MNIST_BCNN, SimplePolyNN

__all__ = [
    'load_folder',
    'ApogeeBCNN',
    'ApogeeCVAE',
    'ApogeeCNN',
    'ApogeeBCNNCensored',
    'ApogeeDR14GaiaDR2BCNN',
    'StarNet2017',
    'Cifar10CNN',
    'MNIST_BCNN',
    'SimplePolyNN']

optimizers = keras.optimizers
Sequential = keras.models.Sequential

_GRAPH_COUTNER = 0  # keep track of the indices used in list storage below
_GRAPH_STORAGE = []  # store all the graph used by multiple models
_SESSION_STORAGE = []  # store all the graph used by multiple models

def Galaxy10CNN():
    """
    NAME:
        Galaxy10CNN
    PURPOSE:
        setup Galaxy10CNN from Cifar10CNN with Galaxy10 parameter
    INPUT:
    OUTPUT:
        (instance): a callable instances from Cifar10_CNN with Galaxy10 parameter
    HISTORY:
        2018-Feb-09 - Written - Henry Leung (University of Toronto)
        2018-Apr-02 - Update - Henry Leung (University of Toronto)
    """
    from astroNN.datasets.galaxy10 import galaxy10cls_lookup
    from astroNN.models.misc_models import Cifar10CNN
    galaxy10_net = Cifar10CNN()
    galaxy10_net._model_identifier = 'Galaxy10CNN'
    targetname = []
    for i in range(10):
        targetname.extend([galaxy10cls_lookup(i)])

    galaxy10_net.targetname = targetname
    return galaxy10_net

def convert_custom_objects(obj):
    """Handles custom object lookup.

    Based on Keras Source Code

    # Arguments
        obj: object, dict, or list.

    # Returns
        The same structure, where occurrences
            of a custom object name have been replaced
            with the custom object.
    """
    if isinstance(obj, list):
        deserialized = []
        for value in obj:
            deserialized.append(convert_custom_objects(value))
        return deserialized
    if isinstance(obj, dict):
        deserialized = {}
        for key, value in obj.items():
            deserialized[key] = convert_custom_objects(value)
        return deserialized
    return obj

def load_folder(folder=None):
    """
    To load astroNN model object from folder

    :param folder: [optional] you should provide folder name if outside folder, do not specific when you are inside the folder
    :type folder: str
    :return: astroNN Neural Network instance
    :rtype: astroNN.nn.NeuralNetMaster.NeuralNetMaster
    :History: 2017-Dec-29 - Written - Henry Leung (University of Toronto)
    """
    currentdir = os.getcwd()

    if folder is not None:
        fullfilepath = os.path.join(currentdir, folder)
    else:
        fullfilepath = currentdir

    astronn_model_obj = None

    if folder is not None and os.path.isfile(os.path.join(folder, 'astroNN_model_parameter.json')) is True:
        with open(os.path.join(folder, 'astroNN_model_parameter.json')) as f:
            parameter = json.load(f)
            f.close()
    elif os.path.isfile('astroNN_model_parameter.json') is True:
        with open('astroNN_model_parameter.json') as f:
            parameter = json.load(f)
            f.close()
    elif folder is not None and not os.path.exists(folder):
        raise IOError('Folder not exists: ' + str(currentdir + os.sep + folder))
    else:
        raise FileNotFoundError('Are you sure this is an astroNN generated folder?')

    identifier = parameter['id']
    unknown_model_message = f'Unknown model identifier -> {identifier}!'

    # need to point to the actual neural network if non-travial location
    if identifier == 'Galaxy10CNN':
        astronn_model_obj = Galaxy10CNN()
    else:
        # else try to import it from standard way
        try:
            astronn_model_obj = getattr(importlib.import_module(f"astroNN.models"), identifier)()
        except ImportError:
            # try to load custom model from CUSTOM_MODEL_PATH if none are working
            CUSTOM_MODEL_PATH = custom_model_path_reader()
            # try the current folder and see if there is any .py on top of CUSTOM_MODEL_PATH
            list_py_files = [os.path.join(fullfilepath, f) for f in os.listdir(fullfilepath) if f.endswith(".py")]
            if CUSTOM_MODEL_PATH is None and list_py_files is None:
                print("\n")
                raise TypeError(unknown_model_message)
            else:
                for path_list in (path_list for path_list in [CUSTOM_MODEL_PATH, list_py_files] if path_list is not None):
                    for path in path_list:
                        head, tail = os.path.split(path)
                        sys.path.insert(0, head)
                        try:
                            model = getattr(importlib.import_module(tail.strip('.py')), str(identifier))
                            astronn_model_obj = model()
                        except AttributeError:
                            pass

        if astronn_model_obj is None:
            print("\n")
            raise TypeError(unknown_model_message)

    astronn_model_obj.currentdir = currentdir
    astronn_model_obj.fullfilepath = fullfilepath
    astronn_model_obj.folder_name = folder if folder is not None else os.path.basename(os.path.normpath(currentdir))

    # Must have parameter
    astronn_model_obj._input_shape = parameter['input']
    astronn_model_obj._labels_shape = parameter['labels']
    astronn_model_obj.num_hidden = parameter['hidden']
    astronn_model_obj.input_norm_mode = parameter['input_norm_mode']
    astronn_model_obj.labels_norm_mode = parameter['labels_norm_mode']
    astronn_model_obj.input_mean = np.array(parameter['input_mean'])
    astronn_model_obj.labels_mean = np.array(parameter['labels_mean'])
    astronn_model_obj.input_std = np.array(parameter['input_std'])
    astronn_model_obj.labels_std = np.array(parameter['labels_std'])
    astronn_model_obj.batch_size = parameter['batch_size']
    astronn_model_obj.targetname = parameter['targetname']
    astronn_model_obj.val_size = parameter['valsize']

    # create normalizer and set correct mean and std
    astronn_model_obj.input_normalizer = Normalizer(mode=astronn_model_obj.input_norm_mode)
    astronn_model_obj.labels_normalizer = Normalizer(mode=astronn_model_obj.labels_norm_mode)
    astronn_model_obj.input_normalizer.mean_labels = astronn_model_obj.input_mean
    astronn_model_obj.input_normalizer.std_labels = astronn_model_obj.input_std
    astronn_model_obj.labels_normalizer.mean_labels = astronn_model_obj.labels_mean
    astronn_model_obj.labels_normalizer.std_labels = astronn_model_obj.labels_std

    # Conditional parameter depends on neural net architecture
    try:
        astronn_model_obj.num_filters = parameter['filternum']
    except KeyError:
        pass
    try:
        astronn_model_obj.filter_len = parameter['filterlen']
    except KeyError:
        pass
    try:
        pool_length = parameter['pool_length']
        if pool_length is not None:
            if isinstance(pool_length, int):  # multi-dimensional case
                astronn_model_obj.pool_length = parameter['pool_length']
            else:
                astronn_model_obj.pool_length = list(parameter['pool_length'])
    except KeyError or TypeError:
        pass
    try:
        # need to convert to int because of keras do not want array or list
        astronn_model_obj.latent_dim = int(parameter['latent'])
    except KeyError:
        pass
    try:
        astronn_model_obj.task = parameter['task']
    except KeyError:
        pass
    try:
        astronn_model_obj.dropout_rate = parameter['dropout_rate']
    except KeyError:
        pass
    try:
        # if inverse model precision exists, so does length_scale
        astronn_model_obj.inv_model_precision = parameter['inv_tau']
        astronn_model_obj.length_scale = parameter['length_scale']
    except KeyError:
        pass
    try:
        astronn_model_obj.l1 = parameter['l1']
    except KeyError:
        pass
    try:
        astronn_model_obj.l2 = parameter['l2']
    except KeyError:
        pass
    try:
        astronn_model_obj.maxnorm = parameter['maxnorm']
    except KeyError:
        pass
    try:
        astronn_model_obj._last_layer_activation = parameter['last_layer_activation']
    except KeyError:
        pass
    try:
        astronn_model_obj.activation = parameter['activation']
    except KeyError:
        pass
    global _GRAPH_COUTNER
    global _GRAPH_STORAGE
    global _SESSION_STORAGE
    _GRAPH_COUTNER += 1
    _GRAPH_STORAGE.append(get_default_graph())

    with _GRAPH_STORAGE[_GRAPH_COUTNER - 1].as_default():
        _SESSION_STORAGE.append(get_default_session())
        with _SESSION_STORAGE[_GRAPH_COUTNER - 1].as_default():
            with h5py.File(os.path.join(astronn_model_obj.fullfilepath, 'model_weights.h5'), mode='r') as f:
                training_config = f.attrs.get('training_config')
                training_config = json.loads(training_config.decode('utf-8'))
                optimizer_config = training_config['optimizer_config']
                optimizer = optimizers.deserialize(optimizer_config)

                # Recover loss functions and metrics.
                losses = convert_custom_objects(training_config['loss'])
                try:
                    try:
                        [losses_lookup(losses[loss]) for loss in losses]
                    except TypeError:
                        losses_lookup(losses)
                except:
                    pass

                metrics = convert_custom_objects(training_config['metrics'])
                # its weird that keras needs -> metrics[metric][0] instead of metrics[metric] likes losses, need attention
                try:
                    try:
                        [losses_lookup(metrics[metric][0]) for metric in metrics]
                    except TypeError:
                        losses_lookup(metrics[0])
                except:
                    pass

                sample_weight_mode = training_config['sample_weight_mode']
                loss_weights = training_config['loss_weights']

                # compile the model
                astronn_model_obj.compile(optimizer=optimizer)

                # set weights
                astronn_model_obj.keras_model.load_weights(
                    os.path.join(astronn_model_obj.fullfilepath, 'model_weights.h5'))

                # Build train function (to get weight updates), need to consider Sequential model too
                astronn_model_obj.keras_model._make_train_function()
                optimizer_weights_group = f['optimizer_weights']
                optimizer_weight_names = [n.decode('utf8') for n in optimizer_weights_group.attrs['weight_names']]
                optimizer_weight_values = [optimizer_weights_group[n] for n in optimizer_weight_names]
                astronn_model_obj.keras_model.optimizer.set_weights(optimizer_weight_values)

        astronn_model_obj.graph = _GRAPH_STORAGE[_GRAPH_COUTNER - 1]  # the graph associated with the model
        astronn_model_obj.session = _SESSION_STORAGE[_GRAPH_COUTNER - 1]  # the model associated with the model

    print("========================================================")
    print(f"Loaded astroNN model, model type: {astronn_model_obj.name} -> {identifier}")
    print("========================================================")
    return astronn_model_obj
<commit_msg>get session if no default session<commit_after>import importlib
import json
import os
import sys

import h5py
import numpy as np
from tensorflow import get_default_session, get_default_graph, keras, Session

from astroNN.config import custom_model_path_reader
from astroNN.models.apogee_models import ApogeeBCNN, ApogeeCVAE, ApogeeCNN, ApogeeBCNNCensored, ApogeeDR14GaiaDR2BCNN, \
    StarNet2017
from astroNN.models.misc_models import Cifar10CNN, MNIST_BCNN, SimplePolyNN
from astroNN.nn.losses import losses_lookup
from astroNN.nn.utilities import Normalizer

__all__ = [
    'load_folder',
    'ApogeeBCNN',
    'ApogeeCVAE',
    'ApogeeCNN',
    'ApogeeBCNNCensored',
    'ApogeeDR14GaiaDR2BCNN',
    'StarNet2017',
    'Cifar10CNN',
    'MNIST_BCNN',
    'SimplePolyNN']

optimizers = keras.optimizers
Sequential = keras.models.Sequential

_GRAPH_COUTNER = 0  # keep track of the indices used in list storage below
_GRAPH_STORAGE = []  # store all the graph used by multiple models
_SESSION_STORAGE = []  # store all the graph used by multiple models

def Galaxy10CNN():
    """
    NAME:
        Galaxy10CNN
    PURPOSE:
        setup Galaxy10CNN from Cifar10CNN with Galaxy10 parameter
    INPUT:
    OUTPUT:
        (instance): a callable instances from Cifar10_CNN with Galaxy10 parameter
    HISTORY:
        2018-Feb-09 - Written - Henry Leung (University of Toronto)
        2018-Apr-02 - Update - Henry Leung (University of Toronto)
    """
    from astroNN.datasets.galaxy10 import galaxy10cls_lookup
    from astroNN.models.misc_models import Cifar10CNN
    galaxy10_net = Cifar10CNN()
    galaxy10_net._model_identifier = 'Galaxy10CNN'
    targetname = []
    for i in range(10):
        targetname.extend([galaxy10cls_lookup(i)])

    galaxy10_net.targetname = targetname
    return galaxy10_net

def convert_custom_objects(obj):
    """Handles custom object lookup.

    Based on Keras Source Code

    # Arguments
        obj: object, dict, or list.

    # Returns
        The same structure, where occurrences
            of a custom object name have been replaced
            with the custom object.
    """
    if isinstance(obj, list):
        deserialized = []
        for value in obj:
            deserialized.append(convert_custom_objects(value))
        return deserialized
    if isinstance(obj, dict):
        deserialized = {}
        for key, value in obj.items():
            deserialized[key] = convert_custom_objects(value)
        return deserialized
    return obj

def load_folder(folder=None):
    """
    To load astroNN model object from folder

    :param folder: [optional] you should provide folder name if outside folder, do not specific when you are inside the folder
    :type folder: str
    :return: astroNN Neural Network instance
    :rtype: astroNN.nn.NeuralNetMaster.NeuralNetMaster
    :History: 2017-Dec-29 - Written - Henry Leung (University of Toronto)
    """
    currentdir = os.getcwd()

    if folder is not None:
        fullfilepath = os.path.join(currentdir, folder)
    else:
        fullfilepath = currentdir

    astronn_model_obj = None

    if folder is not None and os.path.isfile(os.path.join(folder, 'astroNN_model_parameter.json')) is True:
        with open(os.path.join(folder, 'astroNN_model_parameter.json')) as f:
            parameter = json.load(f)
            f.close()
    elif os.path.isfile('astroNN_model_parameter.json') is True:
        with open('astroNN_model_parameter.json') as f:
            parameter = json.load(f)
            f.close()
    elif folder is not None and not os.path.exists(folder):
        raise IOError('Folder not exists: ' + str(currentdir + os.sep + folder))
    else:
        raise FileNotFoundError('Are you sure this is an astroNN generated folder?')

    identifier = parameter['id']
    unknown_model_message = f'Unknown model identifier -> {identifier}!'

    # need to point to the actual neural network if non-travial location
    if identifier == 'Galaxy10CNN':
        astronn_model_obj = Galaxy10CNN()
    else:
        # else try to import it from standard way
        try:
            astronn_model_obj = getattr(importlib.import_module(f"astroNN.models"), identifier)()
        except ImportError:
            # try to load custom model from CUSTOM_MODEL_PATH if none are working
            CUSTOM_MODEL_PATH = custom_model_path_reader()
            # try the current folder and see if there is any .py on top of CUSTOM_MODEL_PATH
            list_py_files = [os.path.join(fullfilepath, f) for f in os.listdir(fullfilepath) if f.endswith(".py")]
            if CUSTOM_MODEL_PATH is None and list_py_files is None:
                print("\n")
                raise TypeError(unknown_model_message)
            else:
                for path_list in (path_list for path_list in [CUSTOM_MODEL_PATH, list_py_files] if path_list is not None):
                    for path in path_list:
                        head, tail = os.path.split(path)
                        sys.path.insert(0, head)
                        try:
                            model = getattr(importlib.import_module(tail.strip('.py')), str(identifier))
                            astronn_model_obj = model()
                        except AttributeError:
                            pass

        if astronn_model_obj is None:
            print("\n")
            raise TypeError(unknown_model_message)

    astronn_model_obj.currentdir = currentdir
    astronn_model_obj.fullfilepath = fullfilepath
    astronn_model_obj.folder_name = folder if folder is not None else os.path.basename(os.path.normpath(currentdir))

    # Must have parameter
    astronn_model_obj._input_shape = parameter['input']
    astronn_model_obj._labels_shape = parameter['labels']
    astronn_model_obj.num_hidden = parameter['hidden']
    astronn_model_obj.input_norm_mode = parameter['input_norm_mode']
    astronn_model_obj.labels_norm_mode = parameter['labels_norm_mode']
    astronn_model_obj.input_mean = np.array(parameter['input_mean'])
    astronn_model_obj.labels_mean = np.array(parameter['labels_mean'])
    astronn_model_obj.input_std = np.array(parameter['input_std'])
    astronn_model_obj.labels_std = np.array(parameter['labels_std'])
    astronn_model_obj.batch_size = parameter['batch_size']
    astronn_model_obj.targetname = parameter['targetname']
    astronn_model_obj.val_size = parameter['valsize']

    # create normalizer and set correct mean and std
    astronn_model_obj.input_normalizer = Normalizer(mode=astronn_model_obj.input_norm_mode)
    astronn_model_obj.labels_normalizer = Normalizer(mode=astronn_model_obj.labels_norm_mode)
    astronn_model_obj.input_normalizer.mean_labels = astronn_model_obj.input_mean
    astronn_model_obj.input_normalizer.std_labels = astronn_model_obj.input_std
    astronn_model_obj.labels_normalizer.mean_labels = astronn_model_obj.labels_mean
    astronn_model_obj.labels_normalizer.std_labels = astronn_model_obj.labels_std

    # Conditional parameter depends on neural net architecture
    try:
        astronn_model_obj.num_filters = parameter['filternum']
    except KeyError:
        pass
    try:
        astronn_model_obj.filter_len = parameter['filterlen']
    except KeyError:
        pass
    try:
        pool_length = parameter['pool_length']
        if pool_length is not None:
            if isinstance(pool_length, int):  # multi-dimensional case
                astronn_model_obj.pool_length = parameter['pool_length']
            else:
                astronn_model_obj.pool_length = list(parameter['pool_length'])
    except KeyError or TypeError:
        pass
    try:
        # need to convert to int because of keras do not want array or list
        astronn_model_obj.latent_dim = int(parameter['latent'])
    except KeyError:
        pass
    try:
        astronn_model_obj.task = parameter['task']
    except KeyError:
        pass
    try:
        astronn_model_obj.dropout_rate = parameter['dropout_rate']
    except KeyError:
        pass
    try:
        # if inverse model precision exists, so does length_scale
        astronn_model_obj.inv_model_precision = parameter['inv_tau']
        astronn_model_obj.length_scale = parameter['length_scale']
    except KeyError:
        pass
    try:
        astronn_model_obj.l1 = parameter['l1']
    except KeyError:
        pass
    try:
        astronn_model_obj.l2 = parameter['l2']
    except KeyError:
        pass
    try:
        astronn_model_obj.maxnorm = parameter['maxnorm']
    except KeyError:
        pass
    try:
        astronn_model_obj._last_layer_activation = parameter['last_layer_activation']
    except KeyError:
        pass
    try:
        astronn_model_obj.activation = parameter['activation']
    except KeyError:
        pass
    global _GRAPH_COUTNER
    global _GRAPH_STORAGE
    global _SESSION_STORAGE
    _GRAPH_COUTNER += 1
    _GRAPH_STORAGE.append(get_default_graph())

    with _GRAPH_STORAGE[_GRAPH_COUTNER - 1].as_default():
        if not get_default_session():  # in case gpu management flag is False so nothing is being set
            _SESSION_STORAGE.append(Session())
        else:
            _SESSION_STORAGE.append(get_default_session())
        with _SESSION_STORAGE[_GRAPH_COUTNER - 1].as_default():
            with h5py.File(os.path.join(astronn_model_obj.fullfilepath, 'model_weights.h5'), mode='r') as f:
                training_config = f.attrs.get('training_config')
                training_config = json.loads(training_config.decode('utf-8'))
                optimizer_config = training_config['optimizer_config']
                optimizer = optimizers.deserialize(optimizer_config)

                # Recover loss functions and metrics.
                losses = convert_custom_objects(training_config['loss'])
                try:
                    try:
                        [losses_lookup(losses[loss]) for loss in losses]
                    except TypeError:
                        losses_lookup(losses)
                except:
                    pass

                metrics = convert_custom_objects(training_config['metrics'])
                # its weird that keras needs -> metrics[metric][0] instead of metrics[metric] likes losses, need attention
                try:
                    try:
                        [losses_lookup(metrics[metric][0]) for metric in metrics]
                    except TypeError:
                        losses_lookup(metrics[0])
                except:
                    pass

                sample_weight_mode = training_config['sample_weight_mode']
                loss_weights = training_config['loss_weights']

                # compile the model
                astronn_model_obj.compile(optimizer=optimizer)

                # set weights
                astronn_model_obj.keras_model.load_weights(
                    os.path.join(astronn_model_obj.fullfilepath, 'model_weights.h5'))

                # Build train function (to get weight updates), need to consider Sequential model too
                astronn_model_obj.keras_model._make_train_function()
                optimizer_weights_group = f['optimizer_weights']
                optimizer_weight_names = [n.decode('utf8') for n in optimizer_weights_group.attrs['weight_names']]
                optimizer_weight_values = [optimizer_weights_group[n] for n in optimizer_weight_names]
                astronn_model_obj.keras_model.optimizer.set_weights(optimizer_weight_values)

        astronn_model_obj.graph = _GRAPH_STORAGE[_GRAPH_COUTNER - 1]  # the graph associated with the model
        astronn_model_obj.session = _SESSION_STORAGE[_GRAPH_COUTNER - 1]  # the model associated with the model

    print("========================================================")
    print(f"Loaded astroNN model, model type: {astronn_model_obj.name} -> {identifier}")
    print("========================================================")
    return astronn_model_obj
<|endoftext|>


<commit_before>#!/usr/bin/env python
'''checkplotlist.py - Waqas Bhatti (wbhatti@astro.princeton.edu) - Dec 2016
License: MIT. See LICENSE for full text.

DESCRIPTION
===========

This makes a checkplot file list for use with the checkplot-viewer.html or the
checkplotserver.py webapps. Checkplots are quick-views of object info, finder
charts, light curves, phased light curves, and periodograms used to examine
their stellar variability. These are produced by several functions in the
astrobase.checkplot module:

checkplot.checkplot_png: makes a checkplot PNG for a single period-finding
                         method

checkplot.twolsp_checkplot_png: does the same for two independent period-finding
                                methods

checkplot.checkplot_pickle: makes a checkplot .pkl.gz for any number of
                            independent period-finding methods

USAGE
=====

If you made checkplots in the PNG format (checkplot-*.png)
----------------------------------------------------------

Copy checkplot-viewer.html and checkplot-viewer.js to the
base directory from where you intend to serve your checkplot images from. Then
invoke this command from that directory:

$ checkplotlist png subdir/containing/the/checkplots 'optional-glob*.png'

This will generate a checkplot-filelist.json file containing the file paths to
the checkplots.

You can then run a temporary Python web server from this base directory to
browse through all the checkplots:

$ python -m SimpleHTTPServer # Python 2
$ python3 -m http.server     # Python 3

then browse to http://localhost:8000/checkplot-viewer.html.

If this directory is already in a path served by a web server, then you can just
browse to the checkplot-viewer.html file normally. Note that a file:/// URL
provided to the browser won't necessarily work in some browsers (especially
Google Chrome) because of security precautions.

If you made checkplots in the pickle format (checkplot-*.pkl)
-------------------------------------------------------------

Invoke this command from that directory like so:

$ checkplotlist pkl subdir/containing/the/checkplots 'optional-glob*.pkl'

Then, from that directory, invoke the checkplotserver webapp (make sure the
astrobase virtualenv is active, so the command below is in your path):

$ checkplotserver [list of options, use --help to see these]

The webapp will start up a Tornado web server running on your computer and
listening on a local address (default: http://localhost:5225). This webapp will
read the checkplot-filelist.json file to find the checkplots.

Browse to http://localhost:5225 (or whatever port you set in checkplotserver
options) to look through or update all your checkplots. Any changes will be
written back to the checkplot .pkl files, making this method of browsing more
suited to more serious variability searches on large numbers of checkplots.

TL;DR
=====

This makes a checkplot file list for use with the checkplot-viewer.html (for
checkplot PNGs) or the checkplotserver.py (for checkplot pickles) webapps.

checkplotlist <pkl|png> <subdir/containing/checkplots/> '[optional checkplot file glob]' '[optional sort specification]'

If you have checkplots that don't have 'checkplot' somewhere in their file name,
use the optional checkplot file glob argument to checkplotlist to provide
this. Make sure to use the quotes around this argument, otherwise the shell will
expand it, e.g.:

$ checkplot png my-project/awesome-objects '*awesome-objects*'

For checkplot pickles only: If you want to sort the checkplot pickles in some
special way, e.g. by their existing Stetson J indices in descending order, use
something like:

$ checkplot pkl my-project/awesome-objects '*awesome-objects*' 'varinfo.varfeatures.stetsonj-desc'

This requires an arg on the commandline of the form: '<sortkey>-<asc|desc>'

where sortkey is some key in the checkplot pickle: this can be a simple key:
e.g. objectid or it can be a composite key: e.g. varinfo.varfeatures.stetsonj
and sortorder is either 'asc' or desc' for ascending/descending sort.

'''

import os
import os.path
import sys
import glob
import json

try:
    from tqdm import tqdm
    TQDM = True
else:
    TQDM = False

# to turn a list of keys into a dict address
# from https://stackoverflow.com/a/14692747
# used to walk a checkplotdict for a specific key in the structure
from functools import reduce  # forward compatibility for Python 3
import operator

def dict_get(datadict, keylist):
    return reduce(operator.getitem, keylist, datadict)

def main(args=None):

    if not args:
        args = sys.argv

    if len(args) < 3:
        docstring = __doc__
        if docstring:
            print(docstring)
        else:
            print("Usage: %s <pkl|png> <subdir/containing/the/checkplots/> "
                  "'[file glob to use] [checkplot pickle sort key-sort order]'"
                  % args[0])
        sys.exit(2)

    checkplotbasedir = args[2]

    if len(args) == 5:
        sortkey, sortorder = args[4].split('-')
    else:
        sortkey, sortorder = None, None

    if len(args) == 4:
        fileglob = args[3]
    else:
        fileglob = '*checkplot*'

    if args[1] == 'pkl':
        checkplotext = 'pkl'
    elif args[1] == 'png':
        checkplotext = 'png'
    else:
        print("unknown format for checkplots: %s! can't continue!"
              % args[1])
        sys.exit(1)

    currdir = os.getcwd()

    checkplotglob = os.path.join(checkplotbasedir,
                                 '%s.%s' % (fileglob, checkplotext))

    print('searching for checkplots: %s' % checkplotglob)

    searchresults = glob.glob(checkplotglob)

    if searchresults:

        print('found %s checkplot files in %s, '
              'making checkplot-filelist.json...' %
              (len(searchresults), checkplotbasedir))

        outjson = os.path.abspath(
            os.path.join(currdir,'checkplot-filelist.json')
        )

        # see if we should sort the searchresults in some special order
        # this requires an arg on the commandline of the form:
        # '<sortkey>-<asc|desc>'
        # where sortkey is some key in the checkplot pickle:
        #   this can be a simple key: e.g. objectid
        #   or it can be a composite key: e.g. varinfo.varfeatures.stetsonj
        # and sortorder is either 'asc' or desc' for ascending/descending sort
        if sortkey and sortorder:

            LOGINFO('sorting checkplot pickles by %s in order: %s...' %
                    (sortkey, sortorder))

            from astrobase import checkplot
            import numpy as np

            # dereference the sort key
            sortkeys = sortkey.split('.')

            sorttargets = []

            # we need to run through the pickles and get their sort keys

            # if tqdm is present
            if TQDM:
                listiterator = tqdm(searchresults)
            else:
                listiterator = searchresults

            for pkl in listerator:

                cpd = checkplot._read_checkplot_pickle(pkl)
                sorttargets.append(dict_get(cpd, sortkeys))

            sorttargets = np.array(sorttargets)
            sortind = np.argsort(sorttargets)
            if sortorder == 'desc':
                sortind = sortind[::-1]
            searchresults = np.array(searchresults)
            searchresults = searchresults[sortind].tolist()

        # if there's no special sort order defined, use the usual sort order
        else:
            LOGWARNING('no special sort key and order specified, '
                       'sorting checkplot pickles '
                       'using usual alphanumeric sort...')
            searchresults = sorted(searchresults)

        # ask if the checkplot list JSON should be updated
        if os.path.exists(outjson):

            answer = input('There is an existing '
                           'checkplot list file in this '
                           'directory:\n    %s\nDo you want to '
                           'overwrite it? (default: no) [y/n] ' % outjson)

            # if it's OK to overwrite, then do so
            if answer and answer == 'y':

                with open(outjson,'w') as outfd:
                    print('overwriting existing checkplot list')
                    outdict = {'checkplots':searchresults,
                               'nfiles':len(searchresults)}
                    json.dump(outdict,outfd)

            # if it's not OK to overwrite, then
            else:

                # read in the outjson, and add stuff to it for objects that
                # don't have an entry
                print('updating existing checkplot list file')

                with open(outjson,'r') as infd:
                    indict = json.load(infd)

                # update the checkplot list only
                indict['checkplots'] = searchresults
                indict['nfiles'] = len(searchresults)
                # write the updated to back to the file
                with open(outjson,'w') as outfd:
                    json.dump(indict, outfd)

        # if this is a new output file
        else:

            with open(outjson,'w') as outfd:
                outdict = {'checkplots':searchresults,
                           'nfiles':len(searchresults)}
                json.dump(outdict,outfd)

        if os.path.exists(outjson):
            print('checkplot file list written to %s' % outjson)
        else:
            print('ERR! writing the checkplot file list failed!')

    else:

        print('ERR! no checkplots found in %s' % checkplotbasedir)

if __name__ == '__main__':

    args = sys.argv
    main(args=args)
<commit_msg>typo fix<commit_after>#!/usr/bin/env python
'''checkplotlist.py - Waqas Bhatti (wbhatti@astro.princeton.edu) - Dec 2016
License: MIT. See LICENSE for full text.

DESCRIPTION
===========

This makes a checkplot file list for use with the checkplot-viewer.html or the
checkplotserver.py webapps. Checkplots are quick-views of object info, finder
charts, light curves, phased light curves, and periodograms used to examine
their stellar variability. These are produced by several functions in the
astrobase.checkplot module:

checkplot.checkplot_png: makes a checkplot PNG for a single period-finding
                         method

checkplot.twolsp_checkplot_png: does the same for two independent period-finding
                                methods

checkplot.checkplot_pickle: makes a checkplot .pkl.gz for any number of
                            independent period-finding methods

USAGE
=====

If you made checkplots in the PNG format (checkplot-*.png)
----------------------------------------------------------

Copy checkplot-viewer.html and checkplot-viewer.js to the
base directory from where you intend to serve your checkplot images from. Then
invoke this command from that directory:

$ checkplotlist png subdir/containing/the/checkplots 'optional-glob*.png'

This will generate a checkplot-filelist.json file containing the file paths to
the checkplots.

You can then run a temporary Python web server from this base directory to
browse through all the checkplots:

$ python -m SimpleHTTPServer # Python 2
$ python3 -m http.server     # Python 3

then browse to http://localhost:8000/checkplot-viewer.html.

If this directory is already in a path served by a web server, then you can just
browse to the checkplot-viewer.html file normally. Note that a file:/// URL
provided to the browser won't necessarily work in some browsers (especially
Google Chrome) because of security precautions.

If you made checkplots in the pickle format (checkplot-*.pkl)
-------------------------------------------------------------

Invoke this command from that directory like so:

$ checkplotlist pkl subdir/containing/the/checkplots 'optional-glob*.pkl'

Then, from that directory, invoke the checkplotserver webapp (make sure the
astrobase virtualenv is active, so the command below is in your path):

$ checkplotserver [list of options, use --help to see these]

The webapp will start up a Tornado web server running on your computer and
listening on a local address (default: http://localhost:5225). This webapp will
read the checkplot-filelist.json file to find the checkplots.

Browse to http://localhost:5225 (or whatever port you set in checkplotserver
options) to look through or update all your checkplots. Any changes will be
written back to the checkplot .pkl files, making this method of browsing more
suited to more serious variability searches on large numbers of checkplots.

TL;DR
=====

This makes a checkplot file list for use with the checkplot-viewer.html (for
checkplot PNGs) or the checkplotserver.py (for checkplot pickles) webapps.

checkplotlist <pkl|png> <subdir/containing/checkplots/> '[optional checkplot file glob]' '[optional sort specification]'

If you have checkplots that don't have 'checkplot' somewhere in their file name,
use the optional checkplot file glob argument to checkplotlist to provide
this. Make sure to use the quotes around this argument, otherwise the shell will
expand it, e.g.:

$ checkplot png my-project/awesome-objects '*awesome-objects*'

For checkplot pickles only: If you want to sort the checkplot pickles in some
special way, e.g. by their existing Stetson J indices in descending order, use
something like:

$ checkplot pkl my-project/awesome-objects '*awesome-objects*' 'varinfo.varfeatures.stetsonj-desc'

This requires an arg on the commandline of the form: '<sortkey>-<asc|desc>'

where sortkey is some key in the checkplot pickle: this can be a simple key:
e.g. objectid or it can be a composite key: e.g. varinfo.varfeatures.stetsonj
and sortorder is either 'asc' or desc' for ascending/descending sort.

'''

import os
import os.path
import sys
import glob
import json

try:
    from tqdm import tqdm
    TQDM = True
except:
    TQDM = False

# to turn a list of keys into a dict address
# from https://stackoverflow.com/a/14692747
# used to walk a checkplotdict for a specific key in the structure
from functools import reduce  # forward compatibility for Python 3
import operator

def dict_get(datadict, keylist):
    return reduce(operator.getitem, keylist, datadict)

def main(args=None):

    if not args:
        args = sys.argv

    if len(args) < 3:
        docstring = __doc__
        if docstring:
            print(docstring)
        else:
            print("Usage: %s <pkl|png> <subdir/containing/the/checkplots/> "
                  "'[file glob to use] [checkplot pickle sort key-sort order]'"
                  % args[0])
        sys.exit(2)

    checkplotbasedir = args[2]

    if len(args) == 5:
        sortkey, sortorder = args[4].split('-')
    else:
        sortkey, sortorder = None, None

    if len(args) == 4:
        fileglob = args[3]
    else:
        fileglob = '*checkplot*'

    if args[1] == 'pkl':
        checkplotext = 'pkl'
    elif args[1] == 'png':
        checkplotext = 'png'
    else:
        print("unknown format for checkplots: %s! can't continue!"
              % args[1])
        sys.exit(1)

    currdir = os.getcwd()

    checkplotglob = os.path.join(checkplotbasedir,
                                 '%s.%s' % (fileglob, checkplotext))

    print('searching for checkplots: %s' % checkplotglob)

    searchresults = glob.glob(checkplotglob)

    if searchresults:

        print('found %s checkplot files in %s, '
              'making checkplot-filelist.json...' %
              (len(searchresults), checkplotbasedir))

        outjson = os.path.abspath(
            os.path.join(currdir,'checkplot-filelist.json')
        )

        # see if we should sort the searchresults in some special order
        # this requires an arg on the commandline of the form:
        # '<sortkey>-<asc|desc>'
        # where sortkey is some key in the checkplot pickle:
        #   this can be a simple key: e.g. objectid
        #   or it can be a composite key: e.g. varinfo.varfeatures.stetsonj
        # and sortorder is either 'asc' or desc' for ascending/descending sort
        if sortkey and sortorder:

            LOGINFO('sorting checkplot pickles by %s in order: %s...' %
                    (sortkey, sortorder))

            from astrobase import checkplot
            import numpy as np

            # dereference the sort key
            sortkeys = sortkey.split('.')

            sorttargets = []

            # we need to run through the pickles and get their sort keys

            # if tqdm is present
            if TQDM:
                listiterator = tqdm(searchresults)
            else:
                listiterator = searchresults

            for pkl in listerator:

                cpd = checkplot._read_checkplot_pickle(pkl)
                sorttargets.append(dict_get(cpd, sortkeys))

            sorttargets = np.array(sorttargets)
            sortind = np.argsort(sorttargets)
            if sortorder == 'desc':
                sortind = sortind[::-1]
            searchresults = np.array(searchresults)
            searchresults = searchresults[sortind].tolist()

        # if there's no special sort order defined, use the usual sort order
        else:
            LOGWARNING('no special sort key and order specified, '
                       'sorting checkplot pickles '
                       'using usual alphanumeric sort...')
            searchresults = sorted(searchresults)

        # ask if the checkplot list JSON should be updated
        if os.path.exists(outjson):

            answer = input('There is an existing '
                           'checkplot list file in this '
                           'directory:\n    %s\nDo you want to '
                           'overwrite it? (default: no) [y/n] ' % outjson)

            # if it's OK to overwrite, then do so
            if answer and answer == 'y':

                with open(outjson,'w') as outfd:
                    print('overwriting existing checkplot list')
                    outdict = {'checkplots':searchresults,
                               'nfiles':len(searchresults)}
                    json.dump(outdict,outfd)

            # if it's not OK to overwrite, then
            else:

                # read in the outjson, and add stuff to it for objects that
                # don't have an entry
                print('updating existing checkplot list file')

                with open(outjson,'r') as infd:
                    indict = json.load(infd)

                # update the checkplot list only
                indict['checkplots'] = searchresults
                indict['nfiles'] = len(searchresults)
                # write the updated to back to the file
                with open(outjson,'w') as outfd:
                    json.dump(indict, outfd)

        # if this is a new output file
        else:

            with open(outjson,'w') as outfd:
                outdict = {'checkplots':searchresults,
                           'nfiles':len(searchresults)}
                json.dump(outdict,outfd)

        if os.path.exists(outjson):
            print('checkplot file list written to %s' % outjson)
        else:
            print('ERR! writing the checkplot file list failed!')

    else:

        print('ERR! no checkplots found in %s' % checkplotbasedir)

if __name__ == '__main__':

    args = sys.argv
    main(args=args)
<|endoftext|>


<commit_before>#!/usr/bin/env python
from blessed import Terminal
import sys

#    _keymap
#    _keycodes

def main():
    """
    Displays all known key capabilities that may match the terminal.
    As each key is pressed on input, it is lit up and points are scored.
    """
    term = Terminal()
    score = level = hit_highbit = hit_unicode = 0
    dirty = True

    def refresh(term, board, level, score, inp):
        sys.stdout.write(term.home + term.clear)
        level_color = level % 7
        if level_color == 0:
            level_color = 4
        bottom = 0
        for keycode, attr in board.items():
            sys.stdout.write(u''.join((
                term.move(attr['row'], attr['column']),
                term.color(level_color),
                (term.reverse if attr['hit'] else term.bold),
                keycode,
                term.normal)))
            bottom = max(bottom, attr['row'])
        sys.stdout.write(term.move(term.height, 0)
                         + 'level: %s score: %s' % (level, score,))
        sys.stdout.flush()
        if bottom >= (term.height - 5):
            sys.stderr.write(
                '\n' * (term.height / 2) +
                term.center(term.red_underline('cheater!')) + '\n')
            sys.stderr.write(
                term.center("(use a larger screen)") +
                '\n' * (term.height / 2))
            sys.exit(1)
        for row, inp in enumerate(inps[(term.height - (bottom + 2)) * -1:]):
            sys.stdout.write(term.move(bottom + row+1))
            sys.stdout.write('%r, %s, %s' % (inp.__str__() if inp.is_sequence
                                             else inp, inp.code, inp.name, ))
            sys.stdout.flush()

    def build_gameboard(term):
        column, row = 0, 0
        board = dict()
        spacing = 2
        for keycode in sorted(term._keycodes.values()):
            if (keycode.startswith('KEY_F')
                    and keycode[-1].isdigit()
                    and int(keycode[len('KEY_F'):]) > 24):
                continue
            if column + len(keycode) + (spacing * 2) >= term.width:
                column = 0
                row += 1
            board[keycode] = {'column': column,
                              'row': row,
                              'hit': 0,
                              }
            column += len(keycode) + (spacing * 2)
        return board

    def add_score(score, pts, level):
        lvl_multiplier = 10
        score += pts
        if 0 == (score % (pts * lvl_multiplier)):
            level += 1
        return score, level

    gb = build_gameboard(term)
    inps = []

    with term.cbreak():
        inp = term.inkey(timeout=0)
        while inp.upper() != 'Q':
            if dirty:
                refresh(term, gb, level, score, inps)
                dirty = False
            inp = term.inkey(timeout=5.0)
            dirty = True
            if (inp.is_sequence and
                    inp.name in gb and
                    0 == gb[inp.name]['hit']):
                gb[inp.name]['hit'] = 1
                score, level = add_score(score, 100, level)
            elif inp and not inp.is_sequence and 128 <= ord(inp) <= 255:
                hit_highbit += 1
                if hit_highbit < 5:
                    score, level = add_score(score, 100, level)
            elif inp and not inp.is_sequence and ord(inp) > 256:
                hit_unicode += 1
                if hit_unicode < 5:
                    score, level = add_score(score, 100, level)
            inps.append(inp)

        sys.stdout.write(u''.join((
            term.move(term.height),
            term.clear_eol,
            u'Your final score was %s' % (score,),
            u' at level %s' % (level,),
            term.clear_eol,
            u'\n',
            term.clear_eol,
            u'You hit %s' % (hit_highbit,),
            u' 8-bit (extended ascii) characters',
            term.clear_eol,
            u'\n',
            term.clear_eol,
            u'You hit %s' % (hit_unicode,),
            u' unicode characters.',
            term.clear_eol,
            u'\n',
            term.clear_eol,
            u'press any key',
            term.clear_eol,))
        )
        term.inkey()

if __name__ == '__main__':
    main()
<commit_msg>switch test_keyboard.py for @raw<commit_after>#!/usr/bin/env python
from blessed import Terminal
import sys

def main():
    """
    Displays all known key capabilities that may match the terminal.
    As each key is pressed on input, it is lit up and points are scored.
    """
    term = Terminal()
    score = level = hit_highbit = hit_unicode = 0
    dirty = True

    def refresh(term, board, level, score, inp):
        sys.stdout.write(term.home + term.clear)
        level_color = level % 7
        if level_color == 0:
            level_color = 4
        bottom = 0
        for keycode, attr in board.items():
            sys.stdout.write(u''.join((
                term.move(attr['row'], attr['column']),
                term.color(level_color),
                (term.reverse if attr['hit'] else term.bold),
                keycode,
                term.normal)))
            bottom = max(bottom, attr['row'])
        sys.stdout.write(term.move(term.height, 0)
                         + 'level: %s score: %s' % (level, score,))
        sys.stdout.flush()
        if bottom >= (term.height - 5):
            sys.stderr.write(
                '\n' * (term.height / 2) +
                term.center(term.red_underline('cheater!')) + '\n')
            sys.stderr.write(
                term.center("(use a larger screen)") +
                '\n' * (term.height / 2))
            sys.exit(1)
        for row, inp in enumerate(inps[(term.height - (bottom + 2)) * -1:]):
            sys.stdout.write(term.move(bottom + row+1))
            sys.stdout.write('%r, %s, %s' % (inp.__str__() if inp.is_sequence
                                             else inp, inp.code, inp.name, ))
            sys.stdout.flush()

    def build_gameboard(term):
        column, row = 0, 0
        board = dict()
        spacing = 2
        for keycode in sorted(term._keycodes.values()):
            if (keycode.startswith('KEY_F')
                    and keycode[-1].isdigit()
                    and int(keycode[len('KEY_F'):]) > 24):
                continue
            if column + len(keycode) + (spacing * 2) >= term.width:
                column = 0
                row += 1
            board[keycode] = {'column': column,
                              'row': row,
                              'hit': 0,
                              }
            column += len(keycode) + (spacing * 2)
        return board

    def add_score(score, pts, level):
        lvl_multiplier = 10
        score += pts
        if 0 == (score % (pts * lvl_multiplier)):
            level += 1
        return score, level

    gb = build_gameboard(term)
    inps = []

    with term.raw():
        inp = term.inkey(timeout=0)
        while inp.upper() != 'Q':
            if dirty:
                refresh(term, gb, level, score, inps)
                dirty = False
            inp = term.inkey(timeout=5.0)
            dirty = True
            if (inp.is_sequence and
                    inp.name in gb and
                    0 == gb[inp.name]['hit']):
                gb[inp.name]['hit'] = 1
                score, level = add_score(score, 100, level)
            elif inp and not inp.is_sequence and 128 <= ord(inp) <= 255:
                hit_highbit += 1
                if hit_highbit < 5:
                    score, level = add_score(score, 100, level)
            elif inp and not inp.is_sequence and ord(inp) > 256:
                hit_unicode += 1
                if hit_unicode < 5:
                    score, level = add_score(score, 100, level)
            inps.append(inp)

    with term.cbreak():
        sys.stdout.write(u''.join((
            term.move(term.height),
            term.clear_eol,
            u'Your final score was %s' % (score,),
            u' at level %s' % (level,),
            term.clear_eol,
            u'\n',
            term.clear_eol,
            u'You hit %s' % (hit_highbit,),
            u' 8-bit (extended ascii) characters',
            term.clear_eol,
            u'\n',
            term.clear_eol,
            u'You hit %s' % (hit_unicode,),
            u' unicode characters.',
            term.clear_eol,
            u'\n',
            term.clear_eol,
            u'press any key',
            term.clear_eol,))
        )
        term.inkey()

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>from rest_framework import serializers as ser

from api.base.utils import get_object_or_404
from website.models import Node, User
from framework.auth.core import Auth
from rest_framework import exceptions
from api.base.serializers import JSONAPISerializer, LinksField, Link, WaterbutlerLink

class NodeSerializer(JSONAPISerializer):
    # TODO: If we have to redo this implementation in any of the other serializers, subclass ChoiceField and make it
    # handle blank choices properly. Currently DRF ChoiceFields ignore blank options, which is incorrect in this
    # instance
    category_choices = Node.CATEGORY_MAP.keys()
    category_choices_string = ', '.join(["'{}'".format(choice) for choice in category_choices])
    filterable_fields = frozenset(['title', 'description', 'public'])

    id = ser.CharField(read_only=True, source='_id')
    title = ser.CharField(required=True)
    description = ser.CharField(required=False, allow_blank=True, allow_null=True)
    category = ser.ChoiceField(choices=category_choices, help_text="Choices: " + category_choices_string)
    date_created = ser.DateTimeField(read_only=True)
    date_modified = ser.DateTimeField(read_only=True)
    tags = ser.SerializerMethodField(help_text='A dictionary that contains two lists of tags: '
                                               'user and system. Any tag that a user will define in the UI will be '
                                               'a user tag')

    links = LinksField({
        'html': 'get_absolute_url',
        'children': {
            'related': Link('nodes:node-children', kwargs={'node_id': '<pk>'}),
            'count': 'get_node_count',
        },
        'contributors': {
            'related': Link('nodes:node-contributors', kwargs={'node_id': '<pk>'}),
            'count': 'get_contrib_count',
        },
        'pointers': {
            'related': Link('nodes:node-pointers', kwargs={'node_id': '<pk>'}),
            'count': 'get_pointers_count',
        },
        'registrations': {
            'related': Link('nodes:node-registrations', kwargs={'node_id': '<pk>'}),
            'count': 'get_registration_count',
        },
        'files': {
            'related': Link('nodes:node-files', kwargs={'node_id': '<pk>'})
        },
        'parent': {
            'self': Link('nodes:node-detail', kwargs={'node_id': '<parent_id>'})
        }
    })
    properties = ser.SerializerMethodField(help_text='A dictionary of read-only booleans: registration, collection,'
                                                     'and dashboard. Collections are special nodes used by the Project '
                                                     'Organizer to, as you would imagine, organize projects. '
                                                     'A dashboard is a collection node that serves as the root of '
                                                     'Project Organizer collections. Every user will always have '
                                                     'one Dashboard')
    # TODO: When we have 'admin' permissions, make this writable for admins
    public = ser.BooleanField(source='is_public', read_only=True,
                              help_text='Nodes that are made public will give read-only access '
                                                            'to everyone. Private nodes require explicit read '
                                                            'permission. Write and admin access are the same for '
                                                            'public and private nodes. Administrators on a parent '
                                                            'node have implicit read permissions for all child nodes',
                              )
    # TODO: finish me

    class Meta:
        type_ = 'nodes'

    def get_absolute_url(self, obj):
        return obj.absolute_url

    # TODO: See if we can get the count filters into the filter rather than the serializer.

    def get_user_auth(self, request):
        user = request.user
        if user.is_anonymous():
            auth = Auth(None)
        else:
            auth = Auth(user)
        return auth

    def get_node_count(self, obj):
        auth = self.get_user_auth(self.context['request'])
        nodes = [node for node in obj.nodes if node.can_view(auth) and node.primary]
        return len(nodes)

    def get_contrib_count(self, obj):
        return len(obj.contributors)

    def get_registration_count(self, obj):
        auth = self.get_user_auth(self.context['request'])
        registrations = [node for node in obj.node__registrations if node.can_view(auth)]
        return len(registrations)

    def get_pointers_count(self, obj):
        return len(obj.nodes_pointer)

    @staticmethod
    def get_properties(obj):
        ret = {
            'registration': obj.is_registration,
            'collection': obj.is_folder,
            'dashboard': obj.is_dashboard,
        }
        return ret

    @staticmethod
    def get_tags(obj):
        ret = {
            'system': [tag._id for tag in obj.system_tags],
            'user': [tag._id for tag in obj.tags],
        }
        return ret

    def create(self, validated_data):
        node = Node(**validated_data)
        node.save()
        return node

    def update(self, instance, validated_data):
        """Update instance with the validated data. Requires
        the request to be in the serializer context.
        """
        assert isinstance(instance, Node), 'instance must be a Node'
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        return instance

class NodeContributorsSerializer(JSONAPISerializer):
    """ Separate from UserSerializer due to necessity to override almost every field as read only
    """
    filterable_fields = frozenset([
        'fullname',
        'given_name',
        'middle_name',
        'family_name',
        'id',
        'bibliographic',
        'permissions'
    ])
    id = ser.CharField(source='_id')
    fullname = ser.CharField(read_only=True, help_text='Display name used in the general user interface')
    given_name = ser.CharField(read_only=True, help_text='For bibliographic citations')
    middle_name = ser.CharField(read_only=True, source='middle_names', help_text='For bibliographic citations')
    family_name = ser.CharField(read_only=True, help_text='For bibliographic citations')
    suffix = ser.CharField(read_only=True, help_text='For bibliographic citations')
    date_registered = ser.DateTimeField(read_only=True)
    gravatar_url = ser.CharField(read_only=True, help_text='URL for the icon used to identify the user. '
                                                           'Relies on http://gravatar.com ')
    employment_institutions = ser.ListField(read_only=True, source='jobs', help_text='An array of dictionaries '
                                                                                'representing the places the '
                                                                                'user has worked')
    educational_institutions = ser.ListField(read_only=True, source='schools',
                                             help_text='An array of dictionaries representing the places the '
                                                       'user has attended school')
    social_accounts = ser.DictField(read_only=True, source='social',
                                    help_text='A dictionary of various social media account dentifiers including '
                                              'an array of user-defined URLs')
    bibliographic = ser.BooleanField(help_text='Whether the user will be included in citations for this node or not.  '
                                               'Required due to issues with field defaulting to false.')

    permission = ser.ChoiceField(choices=['read', 'write', 'admin'], allow_blank=True, required=False,
                                 help_text='Highest permission the user has.  Blank input defaults write permission if '
                                           'user is being added and to current permission if user is being edited.')
    links = LinksField({
        'html': 'absolute_url',
        'nodes': {
            'relation': Link('users:user-nodes', kwargs={'user_id': '<pk>'})
        },
        'detail': Link('nodes:node-contributor-detail',
                       kwargs={'node_id': '<node_id>', 'user_id': '<pk>'})
    })

    class Meta:
        type_ = 'users'

    def absolute_url(self, obj):
        return obj.absolute_url

    def create(self, validated_data):
        auth = Auth(self.context['request'].user)
        node = self.context['view'].get_node()
        user = get_object_or_404(User, validated_data['_id'])
        # Node object checks for contributor existence but can still change permissions anyway
        if user in node.contributors:
            raise exceptions.ValidationError('{} is already a validated contributor'.format(user.username))

        bibliographic = validated_data['bibliographic']
        permissions = self.get_permissions_list(validated_data['permission']) \
            if 'permission' in validated_data else ['read', 'write']
        node.add_contributor(contributor=user, auth=auth, visible=bibliographic, permissions=permissions, save=True)
        node.reload()
        user.permission = node.get_permissions(user)[-1]
        user.bibliographic = node.get_visible(user)
        user.node_id = node._id
        return user

    @staticmethod
    def get_permissions_list(permission):
        if permission == 'admin':
            return ['read', 'write', 'admin']
        elif permission == 'write':
            return ['read', 'write']
        elif permission == 'read':
            return ['read']

class NodeContributorDetailSerializer(NodeContributorsSerializer):
    """ Overrides node contributor serializer to make id read only and add addtional methods
    """
    id = ser.CharField(read_only=True, source='_id')

    def update(self, instance, validated_data):
        pass

class NodePointersSerializer(JSONAPISerializer):

    id = ser.CharField(read_only=True, source='_id')
    target_node_id = ser.CharField(source='node._id', help_text='The ID of the node that this pointer points to')
    title = ser.CharField(read_only=True, source='node.title', help_text='The title of the node that this pointer '
                                                                         'points to')

    class Meta:
        type_ = 'pointers'

    links = LinksField({
        'html': 'get_absolute_url',
    })

    def get_absolute_url(self, obj):
        pointer_node = Node.load(obj.node._id)
        return pointer_node.absolute_url

    def create(self, validated_data):
        request = self.context['request']
        user = request.user
        auth = Auth(user)
        node = self.context['view'].get_node()
        pointer_node = Node.load(validated_data['node']['_id'])
        if not pointer_node:
            raise exceptions.NotFound('Node not found.')
        try:
            pointer = node.add_pointer(pointer_node, auth, save=True)
            return pointer
        except ValueError:
            raise exceptions.ValidationError('Pointer to node {} already in list'.format(pointer_node._id))

    def update(self, instance, validated_data):
        pass

class NodeFilesSerializer(JSONAPISerializer):

    id = ser.CharField(read_only=True, source='_id')
    provider = ser.CharField(read_only=True)
    path = ser.CharField(read_only=True)
    item_type = ser.CharField(read_only=True)
    name = ser.CharField(read_only=True)
    metadata = ser.DictField(read_only=True)

    class Meta:
        type_ = 'files'

    links = LinksField({
        'self': WaterbutlerLink(kwargs={'node_id': '<node_id>'}),
        'self_methods': 'valid_self_link_methods',
        'related': Link('nodes:node-files', kwargs={'node_id': '<node_id>'},
                        query_kwargs={'path': '<path>', 'provider': '<provider>'}),
    })

    @staticmethod
    def valid_self_link_methods(obj):
        return obj['valid_self_link_methods']

    def create(self, validated_data):
        # TODO
        pass

    def update(self, instance, validated_data):
        # TODO
        pass
<commit_msg>Created update method<commit_after>from rest_framework import serializers as ser

from api.base.utils import get_object_or_404
from website.models import Node, User
from framework.auth.core import Auth
from rest_framework import exceptions
from api.base.serializers import JSONAPISerializer, LinksField, Link, WaterbutlerLink

class NodeSerializer(JSONAPISerializer):
    # TODO: If we have to redo this implementation in any of the other serializers, subclass ChoiceField and make it
    # handle blank choices properly. Currently DRF ChoiceFields ignore blank options, which is incorrect in this
    # instance
    category_choices = Node.CATEGORY_MAP.keys()
    category_choices_string = ', '.join(["'{}'".format(choice) for choice in category_choices])
    filterable_fields = frozenset(['title', 'description', 'public'])

    id = ser.CharField(read_only=True, source='_id')
    title = ser.CharField(required=True)
    description = ser.CharField(required=False, allow_blank=True, allow_null=True)
    category = ser.ChoiceField(choices=category_choices, help_text="Choices: " + category_choices_string)
    date_created = ser.DateTimeField(read_only=True)
    date_modified = ser.DateTimeField(read_only=True)
    tags = ser.SerializerMethodField(help_text='A dictionary that contains two lists of tags: '
                                               'user and system. Any tag that a user will define in the UI will be '
                                               'a user tag')

    links = LinksField({
        'html': 'get_absolute_url',
        'children': {
            'related': Link('nodes:node-children', kwargs={'node_id': '<pk>'}),
            'count': 'get_node_count',
        },
        'contributors': {
            'related': Link('nodes:node-contributors', kwargs={'node_id': '<pk>'}),
            'count': 'get_contrib_count',
        },
        'pointers': {
            'related': Link('nodes:node-pointers', kwargs={'node_id': '<pk>'}),
            'count': 'get_pointers_count',
        },
        'registrations': {
            'related': Link('nodes:node-registrations', kwargs={'node_id': '<pk>'}),
            'count': 'get_registration_count',
        },
        'files': {
            'related': Link('nodes:node-files', kwargs={'node_id': '<pk>'})
        },
        'parent': {
            'self': Link('nodes:node-detail', kwargs={'node_id': '<parent_id>'})
        }
    })
    properties = ser.SerializerMethodField(help_text='A dictionary of read-only booleans: registration, collection,'
                                                     'and dashboard. Collections are special nodes used by the Project '
                                                     'Organizer to, as you would imagine, organize projects. '
                                                     'A dashboard is a collection node that serves as the root of '
                                                     'Project Organizer collections. Every user will always have '
                                                     'one Dashboard')
    # TODO: When we have 'admin' permissions, make this writable for admins
    public = ser.BooleanField(source='is_public', read_only=True,
                              help_text='Nodes that are made public will give read-only access '
                                                            'to everyone. Private nodes require explicit read '
                                                            'permission. Write and admin access are the same for '
                                                            'public and private nodes. Administrators on a parent '
                                                            'node have implicit read permissions for all child nodes',
                              )
    # TODO: finish me

    class Meta:
        type_ = 'nodes'

    def get_absolute_url(self, obj):
        return obj.absolute_url

    # TODO: See if we can get the count filters into the filter rather than the serializer.

    def get_user_auth(self, request):
        user = request.user
        if user.is_anonymous():
            auth = Auth(None)
        else:
            auth = Auth(user)
        return auth

    def get_node_count(self, obj):
        auth = self.get_user_auth(self.context['request'])
        nodes = [node for node in obj.nodes if node.can_view(auth) and node.primary]
        return len(nodes)

    def get_contrib_count(self, obj):
        return len(obj.contributors)

    def get_registration_count(self, obj):
        auth = self.get_user_auth(self.context['request'])
        registrations = [node for node in obj.node__registrations if node.can_view(auth)]
        return len(registrations)

    def get_pointers_count(self, obj):
        return len(obj.nodes_pointer)

    @staticmethod
    def get_properties(obj):
        ret = {
            'registration': obj.is_registration,
            'collection': obj.is_folder,
            'dashboard': obj.is_dashboard,
        }
        return ret

    @staticmethod
    def get_tags(obj):
        ret = {
            'system': [tag._id for tag in obj.system_tags],
            'user': [tag._id for tag in obj.tags],
        }
        return ret

    def create(self, validated_data):
        node = Node(**validated_data)
        node.save()
        return node

    def update(self, instance, validated_data):
        """Update instance with the validated data. Requires
        the request to be in the serializer context.
        """
        assert isinstance(instance, Node), 'instance must be a Node'
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        return instance

class NodeContributorsSerializer(JSONAPISerializer):
    """ Separate from UserSerializer due to necessity to override almost every field as read only
    """
    filterable_fields = frozenset([
        'fullname',
        'given_name',
        'middle_name',
        'family_name',
        'id',
        'bibliographic',
        'permissions'
    ])
    id = ser.CharField(source='_id')
    fullname = ser.CharField(read_only=True, help_text='Display name used in the general user interface')
    given_name = ser.CharField(read_only=True, help_text='For bibliographic citations')
    middle_name = ser.CharField(read_only=True, source='middle_names', help_text='For bibliographic citations')
    family_name = ser.CharField(read_only=True, help_text='For bibliographic citations')
    suffix = ser.CharField(read_only=True, help_text='For bibliographic citations')
    date_registered = ser.DateTimeField(read_only=True)
    gravatar_url = ser.CharField(read_only=True, help_text='URL for the icon used to identify the user. '
                                                           'Relies on http://gravatar.com ')
    employment_institutions = ser.ListField(read_only=True, source='jobs', help_text='An array of dictionaries '
                                                                                'representing the places the '
                                                                                'user has worked')
    educational_institutions = ser.ListField(read_only=True, source='schools',
                                             help_text='An array of dictionaries representing the places the '
                                                       'user has attended school')
    social_accounts = ser.DictField(read_only=True, source='social',
                                    help_text='A dictionary of various social media account dentifiers including '
                                              'an array of user-defined URLs')
    bibliographic = ser.BooleanField(help_text='Whether the user will be included in citations for this node or not.  '
                                               'Required due to issues with field defaulting to false.')

    permission = ser.ChoiceField(choices=['read', 'write', 'admin'], allow_blank=True, required=False,
                                 help_text='Highest permission the user has.  Blank input defaults write permission if '
                                           'user is being added and to current permission if user is being edited.')
    links = LinksField({
        'html': 'absolute_url',
        'nodes': {
            'relation': Link('users:user-nodes', kwargs={'user_id': '<pk>'})
        },
        'detail': Link('nodes:node-contributor-detail',
                       kwargs={'node_id': '<node_id>', 'user_id': '<pk>'})
    })

    class Meta:
        type_ = 'users'

    def absolute_url(self, obj):
        return obj.absolute_url

    def create(self, validated_data):
        auth = Auth(self.context['request'].user)
        node = self.context['view'].get_node()
        user = get_object_or_404(User, validated_data['_id'])
        # Node object checks for contributor existence but can still change permissions anyway
        if user in node.contributors:
            raise exceptions.ValidationError('{} is already a validated contributor'.format(user.username))

        bibliographic = validated_data['bibliographic']
        permissions = self.get_permissions_list(validated_data['permission']) \
            if 'permission' in validated_data else ['read', 'write']
        node.add_contributor(contributor=user, auth=auth, visible=bibliographic, permissions=permissions, save=True)
        node.reload()
        user.permission = node.get_permissions(user)[-1]
        user.bibliographic = node.get_visible(user)
        user.node_id = node._id
        return user

    @staticmethod
    def get_permissions_list(permission):
        if permission == 'admin':
            return ['read', 'write', 'admin']
        elif permission == 'write':
            return ['read', 'write']
        elif permission == 'read':
            return ['read']

class NodeContributorDetailSerializer(NodeContributorsSerializer):
    """ Overrides node contributor serializer to make id read only and add addtional methods
    """
    id = ser.CharField(read_only=True, source='_id')

    def update(self, instance, validated_data):
        auth = Auth(self.context['request'].user)
        node = self.context['view'].get_node()
        if 'permission' in validated_data:
            self.set_contributor_permissions(node, validated_data['permission'], instance, auth)
        try:
            node.set_visible(instance, validated_data['bibliographic'], auth=auth, save=True)
        except ValueError as e:
            raise exceptions.ValidationError(e)

    # checks to make sure unique admin is removing own admin privilege
    def set_contributor_permissions(self, node, permission, contributor, auth):
        permissions = self.get_permissions_list(permission)
        if self.has_multiple_admins(node) and contributor is not auth.user:
            node.set_permissions(contributor, permissions=permissions, auth=auth, save=True)
        if permission == 'admin':
            node.set_permissions(contributor, permissions=permissions, auth=auth, save=True)
        else:
            raise exceptions.ValidationError('{} is the only admin.'.format(contributor.username))

    def has_multiple_admins(self, node):
        has_admin = False
        for contributor in node.contributors:
            if node.has_permission(contributor, 'admin'):
                if has_admin:
                    return True
                has_admin = True
        return False

class NodePointersSerializer(JSONAPISerializer):

    id = ser.CharField(read_only=True, source='_id')
    target_node_id = ser.CharField(source='node._id', help_text='The ID of the node that this pointer points to')
    title = ser.CharField(read_only=True, source='node.title', help_text='The title of the node that this pointer '
                                                                         'points to')

    class Meta:
        type_ = 'pointers'

    links = LinksField({
        'html': 'get_absolute_url',
    })

    def get_absolute_url(self, obj):
        pointer_node = Node.load(obj.node._id)
        return pointer_node.absolute_url

    def create(self, validated_data):
        request = self.context['request']
        user = request.user
        auth = Auth(user)
        node = self.context['view'].get_node()
        pointer_node = Node.load(validated_data['node']['_id'])
        if not pointer_node:
            raise exceptions.NotFound('Node not found.')
        try:
            pointer = node.add_pointer(pointer_node, auth, save=True)
            return pointer
        except ValueError:
            raise exceptions.ValidationError('Pointer to node {} already in list'.format(pointer_node._id))

    def update(self, instance, validated_data):
        pass

class NodeFilesSerializer(JSONAPISerializer):

    id = ser.CharField(read_only=True, source='_id')
    provider = ser.CharField(read_only=True)
    path = ser.CharField(read_only=True)
    item_type = ser.CharField(read_only=True)
    name = ser.CharField(read_only=True)
    metadata = ser.DictField(read_only=True)

    class Meta:
        type_ = 'files'

    links = LinksField({
        'self': WaterbutlerLink(kwargs={'node_id': '<node_id>'}),
        'self_methods': 'valid_self_link_methods',
        'related': Link('nodes:node-files', kwargs={'node_id': '<node_id>'},
                        query_kwargs={'path': '<path>', 'provider': '<provider>'}),
    })

    @staticmethod
    def valid_self_link_methods(obj):
        return obj['valid_self_link_methods']

    def create(self, validated_data):
        # TODO
        pass

    def update(self, instance, validated_data):
        # TODO
        pass
<|endoftext|>


<commit_before>from rest_framework import serializers as ser

from api.base.serializers import JSONAPISerializer
from website.models import Node
from framework.auth.core import Auth

class NodeSerializer(JSONAPISerializer):

    id = ser.CharField(read_only=True, source='_id')
    title = ser.CharField(required=True)
    description = ser.CharField(required=False, allow_blank=True)
    is_public = ser.BooleanField()
    is_registration = ser.BooleanField()
    # TODO: finish me

    class Meta:
        type_ = 'nodes'

    def get_links(self, obj):
        return {
            'html': obj.absolute_url,
        }

    def create(self, validated_data):
        node = Node(**validated_data)
        node.save()
        return node

    def update(self, instance, validated_data):
        """Update instance with the validated data. Requires
        the request to be in the serializer context.
        """
        assert isinstance(instance, Node), 'instance must be a Node'
        is_public = validated_data.pop('is_public')
        for attr, value in validated_data.items():
            setattr(instance, attr, value)

        request = self.context['request']
        user = request.user
        auth = Auth(user)
        if is_public != instance.is_public:
            privacy = 'public' if is_public else 'private'
            instance.set_privacy(privacy, auth)
        instance.save()
        return instance
<commit_msg>is_registration should be read_only<commit_after>from rest_framework import serializers as ser

from api.base.serializers import JSONAPISerializer
from website.models import Node
from framework.auth.core import Auth

class NodeSerializer(JSONAPISerializer):

    id = ser.CharField(read_only=True, source='_id')
    title = ser.CharField(required=True)
    description = ser.CharField(required=False, allow_blank=True)
    is_public = ser.BooleanField()
    is_registration = ser.BooleanField(read_only=True)
    # TODO: finish me

    class Meta:
        type_ = 'nodes'

    def get_links(self, obj):
        return {
            'html': obj.absolute_url,
        }

    def create(self, validated_data):
        node = Node(**validated_data)
        node.save()
        return node

    def update(self, instance, validated_data):
        """Update instance with the validated data. Requires
        the request to be in the serializer context.
        """
        assert isinstance(instance, Node), 'instance must be a Node'
        is_public = validated_data.pop('is_public')
        for attr, value in validated_data.items():
            setattr(instance, attr, value)

        request = self.context['request']
        user = request.user
        auth = Auth(user)
        if is_public != instance.is_public:
            privacy = 'public' if is_public else 'private'
            instance.set_privacy(privacy, auth)
        instance.save()
        return instance
<|endoftext|>


<commit_before>#!python3
# -*- coding: utf-8 -*-
# works on windows XP, 7, 8 and 10
import os
import sys
import time
import subprocess

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))  # not required after 'pip install uiautomation'
import uiautomation as automation

def Calc(window, btns, expression):
    expression = ''.join(expression.split())
    if not expression.endswith('='):
        expression += '='
    for char in expression:
        automation.Logger.Write(char, writeToFile = False)
        btns[char].Click(waitTime = 0.05)
    window.SendKeys('{Ctrl}c', waitTime = 0)
    result = automation.GetClipboardText()
    automation.Logger.WriteLine(result, automation.ConsoleColor.Cyan, writeToFile = False)
    time.sleep(1)

def CalcOnXP():
    chars = '0123456789.+-*/=()'
    calcWindow = automation.WindowControl(searchDepth = 1, ClassName = 'SciCalc')
    if not calcWindow.Exists(0, 0):
        subprocess.Popen('calc')
    calcWindow.SetActive()
    calcWindow.SendKeys('{Alt}vs', 0.5)
    clearBtn = calcWindow.ButtonControl(Name = 'CE')
    clearBtn.Click()
    char2Button = {}
    for key in chars:
        char2Button[key] = calcWindow.ButtonControl(Name = key)
    Calc(calcWindow, char2Button, '1234 * (4 + 5 + 6) - 78 / 90')
    Calc(calcWindow, char2Button, '2*3.14159*10')

def CalcOnWindows7And8():
    char2Id = {
        '0' : '130',
        '1' : '131',
        '2' : '132',
        '3' : '133',
        '4' : '134',
        '5' : '135',
        '6' : '136',
        '7' : '137',
        '8' : '138',
        '9' : '139',
        '.' : '84',
        '+' : '93',
        '-' : '94',
        '*' : '92',
        '/' : '91',
        '=' : '121',
        '(' : '128',
        ')' : '129',
    }
    calcWindow = automation.WindowControl(searchDepth = 1, ClassName = 'CalcFrame')
    if not calcWindow.Exists(0, 0):
        subprocess.Popen('calc')
    calcWindow.SetActive()
    calcWindow.SendKeys('{Alt}2')
    clearBtn = calcWindow.ButtonControl(foundIndex= 8, Depth = 3)  #test foundIndex and Depth, the 8th button is clear
    if clearBtn.AutomationId == '82':
        clearBtn.Click()
    char2Button = {}
    for key in char2Id:
        char2Button[key] = calcWindow.ButtonControl(AutomationId = char2Id[key])
    Calc(calcWindow, char2Button, '1234 * (4 + 5 + 6) - 78 / 90')
    Calc(calcWindow, char2Button, '2*3.14159*10')

def CalcOnWindows10():
    char2Id = {
        '0' : 'num0Button',
        '1' : 'num1Button',
        '2' : 'num2Button',
        '3' : 'num3Button',
        '4' : 'num4Button',
        '5' : 'num5Button',
        '6' : 'num6Button',
        '7' : 'num7Button',
        '8' : 'num8Button',
        '9' : 'num9Button',
        '.' : 'decimalSeparatorButton',
        '+' : 'plusButton',
        '-' : 'minusButton',
        '*' : 'multiplyButton',
        '/' : 'divideButton',
        '=' : 'equalButton',
        '(' : 'openParanthesisButton',
        ')' : 'closeParanthesisButton',
    }
    calcWindow = automation.WindowControl(searchDepth = 1, ClassName = 'ApplicationFrameWindow', Name = 'Calculator')
    if not calcWindow.Exists(0, 0):
        subprocess.Popen('calc')
    calcWindow.SetActive()
    calcWindow.ButtonControl(AutomationId = 'NavButton').Click()
    calcWindow.ListItemControl(Name = 'Scientific Calculator').Click()
    calcWindow.ButtonControl(AutomationId = 'clearButton').Click()
    char2Button = {}
    for key in char2Id:
        char2Button[key] = calcWindow.ButtonControl(AutomationId = char2Id[key])
    Calc(calcWindow, char2Button, '1234 * (4 + 5 + 6) - 78 / 90')
    Calc(calcWindow, char2Button, '2*3.14159*10')
    calcWindow.CaptureToImage('calc.png', 7, 0, -14, -7)  # on windows 10, 7 pixels of windows border are transparent

if __name__ == '__main__':
    import platform
    osVersion = int(platform.version().split('.')[0])
    if osVersion < 6:
        CalcOnXP()
    elif osVersion == 6:
        CalcOnWindows7And8()
    elif osVersion >= 10:
        CalcOnWindows10()
<commit_msg>modify demo<commit_after>#!python3
# -*- coding: utf-8 -*-
# works on windows XP, 7, 8 and 10
import os
import sys
import time
import subprocess

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))  # not required after 'pip install uiautomation'
import uiautomation as automation

def Calc(window, btns, expression):
    expression = ''.join(expression.split())
    if not expression.endswith('='):
        expression += '='
    for char in expression:
        automation.Logger.Write(char, writeToFile = False)
        btns[char].Click(waitTime = 0.05)
    window.SendKeys('{Ctrl}c', waitTime = 0.05)
    result = automation.GetClipboardText()
    automation.Logger.WriteLine(result, automation.ConsoleColor.Cyan, writeToFile = False)
    time.sleep(1)

def CalcOnXP():
    chars = '0123456789.+-*/=()'
    calcWindow = automation.WindowControl(searchDepth = 1, ClassName = 'SciCalc')
    if not calcWindow.Exists(0, 0):
        subprocess.Popen('calc')
    calcWindow.SetActive()
    calcWindow.SendKeys('{Alt}vs', 0.5)
    clearBtn = calcWindow.ButtonControl(Name = 'CE')
    clearBtn.Click()
    char2Button = {key: calcWindow.ButtonControl(Name = key) for key in chars}
    Calc(calcWindow, char2Button, '1234 * (4 + 5 + 6) - 78 / 90')
    Calc(calcWindow, char2Button, '2*3.14159*10')

def CalcOnWindows7And8():
    char2Id = {
        '0' : '130',
        '1' : '131',
        '2' : '132',
        '3' : '133',
        '4' : '134',
        '5' : '135',
        '6' : '136',
        '7' : '137',
        '8' : '138',
        '9' : '139',
        '.' : '84',
        '+' : '93',
        '-' : '94',
        '*' : '92',
        '/' : '91',
        '=' : '121',
        '(' : '128',
        ')' : '129',
    }
    calcWindow = automation.WindowControl(searchDepth = 1, ClassName = 'CalcFrame')
    if not calcWindow.Exists(0, 0):
        subprocess.Popen('calc')
    calcWindow.SetActive()
    calcWindow.SendKeys('{Alt}2')
    clearBtn = calcWindow.ButtonControl(foundIndex= 8, Depth = 3)  #test foundIndex and Depth, the 8th button is clear
    if clearBtn.AutomationId == '82':
        clearBtn.Click()
    char2Button = {key: calcWindow.ButtonControl(AutomationId = char2Id[key]) for key in char2Id}
    Calc(calcWindow, char2Button, '1234 * (4 + 5 + 6) - 78 / 90')
    Calc(calcWindow, char2Button, '2*3.14159*10')

def CalcOnWindows10():
    char2Id = {
        '0' : 'num0Button',
        '1' : 'num1Button',
        '2' : 'num2Button',
        '3' : 'num3Button',
        '4' : 'num4Button',
        '5' : 'num5Button',
        '6' : 'num6Button',
        '7' : 'num7Button',
        '8' : 'num8Button',
        '9' : 'num9Button',
        '.' : 'decimalSeparatorButton',
        '+' : 'plusButton',
        '-' : 'minusButton',
        '*' : 'multiplyButton',
        '/' : 'divideButton',
        '=' : 'equalButton',
        '(' : 'openParanthesisButton',
        ')' : 'closeParanthesisButton',
    }
    calcWindow = automation.WindowControl(searchDepth = 1, ClassName = 'ApplicationFrameWindow', Name = 'Calculator')
    if not calcWindow.Exists(0, 0):
        subprocess.Popen('calc')
    calcWindow.SetActive()
    calcWindow.ButtonControl(AutomationId = 'NavButton').Click()
    calcWindow.ListItemControl(Name = 'Scientific Calculator').Click()
    calcWindow.ButtonControl(AutomationId = 'clearButton').Click()
    char2Button = {key: calcWindow.ButtonControl(AutomationId = char2Id[key]) for key in char2Id}
    Calc(calcWindow, char2Button, '1234 * (4 + 5 + 6) - 78 / 90')
    Calc(calcWindow, char2Button, '2*3.14159*10')
    calcWindow.CaptureToImage('calc.png', 7, 0, -14, -7)  # on windows 10, 7 pixels of windows border are transparent

if __name__ == '__main__':
    import platform
    osVersion = int(platform.version().split('.')[0])
    if osVersion < 6:
        CalcOnXP()
    elif osVersion == 6:
        CalcOnWindows7And8()
    elif osVersion >= 10:
        CalcOnWindows10()
<|endoftext|>