<commit_before>__author__ = 'Fredrik A. Madsen-Malmo'

from flask import Flask, flash, render_template, g

import models
import forms

import os

DEBUG = True
PORT = port = int(os.environ.get('PORT', 33507))
HOST = '0.0.0.0'

app = Flask(__name__)
app.secret_key = os.environ.get('secret_key', 'error')

# Before and after request

@app.before_request
def before_request():
    """Connect to db before each req"""
    g.db = models.DATABASE
    g.db.connect()

@app.after_request
def after_request(response):
	"""Close the db connection after each req"""
	g.db.close()

	return response

# Other functions

@app.route('/online/<ip>', methods=['POST', 'GET'])
def is_online(ip):
    try:
        target = models.Entry.get(models.Entry.id == ip)
    except Exception:
        return False

    # 2 cycles and 0 bytes sent
    result = os.popen('ping -c 2 -s 0 {}'.format(ip))

    if not (result.contains('Unknown host') or result.conatins('timeout')):
        target.update(
            online=True
        ).execute()

        return True

# Routes

@app.route('/', methods=['POST', 'GET'])
def index():
    form = forms.EntryForm()
    stream = models.Entry.select()

    if form.validate_on_submit():
        try:
            models.Entry.create(
                name=form.name.data,
                ip=form.ip.data,
                port=form.port.data,
                online=is_online(form.ip.data))

        except Exception:
            pass

    return render_template('index.html', form=form, stream=stream)

# Start app

if __name__ == '__main__':
    models.initialize()

    try:
        models.Entry.get(models.Entry.ip == '93.184.204.215')
    except Exception:
        models.Entry.create(
        name='fotoply',
        ip='93.184.204.215',
        port='7077')

    app.run(debug=DEBUG, port=PORT, host=HOST)
<commit_msg>forgot to read from pipe<commit_after>__author__ = 'Fredrik A. Madsen-Malmo'

from flask import Flask, flash, render_template, g

import models
import forms

import os

DEBUG = True
PORT = port = int(os.environ.get('PORT', 33507))
HOST = '0.0.0.0'

app = Flask(__name__)
app.secret_key = os.environ.get('secret_key', 'error')

# Before and after request

@app.before_request
def before_request():
    """Connect to db before each req"""
    g.db = models.DATABASE
    g.db.connect()

@app.after_request
def after_request(response):
	"""Close the db connection after each req"""
	g.db.close()

	return response

# Other functions

@app.route('/online/<ip>', methods=['POST', 'GET'])
def is_online(ip):
    try:
        target = models.Entry.get(models.Entry.id == ip)
    except Exception:
        return False

    # 2 cycles and 0 bytes sent
    result = os.popen('ping -c 2 -s 0 {}'.format(ip)).read()

    if not (result.contains('Unknown host') or result.conatins('timeout')):
        target.update(
            online=True
        ).execute()

        return True

# Routes

@app.route('/', methods=['POST', 'GET'])
def index():
    form = forms.EntryForm()
    stream = models.Entry.select()

    if form.validate_on_submit():
        try:
            models.Entry.create(
                name=form.name.data,
                ip=form.ip.data,
                port=form.port.data,
                online=is_online(form.ip.data))

        except Exception:
            pass

    return render_template('index.html', form=form, stream=stream)

# Start app

if __name__ == '__main__':
    models.initialize()

    try:
        models.Entry.get(models.Entry.ip == '93.184.204.215')
    except Exception:
        models.Entry.create(
        name='fotoply',
        ip='93.184.204.215',
        port='7077')

    app.run(debug=DEBUG, port=PORT, host=HOST)
<|endoftext|>


<commit_before>from contextlib import contextmanager
from datetime import datetime
import os
import re
from sqlalchemy import Column, DateTime, String

script_re = re.compile(r'^\d{8}-\d\d-[a-z0-9-_]+\.(:?py|sql)$')

class AppliedChanges(object):
    __tablename__ = 'applied_changes'

    applied = Column(DateTime, nullable=False)
    name = Column(String, primary_key=True)

class Migrate(object):
    def __init__(self, app):
        # FIXME - Should not require `app` here. See
        # <http://flask.pocoo.org/docs/extensiondev/>.
        self.app = app
        self.init_app(app)

    def init_app(self, app):
        app.extensions['migrate'] = self

        # Register our commands.
        def migrate():
            self.migrate()
        app.extensions['script'].command(migrate)

        # Add our table to database.
        self.app.db.AppliedChanges = type('AppliedChanges',
                                          (AppliedChanges, self.app.db.Model),
                                          {})

    def all_scripts(self):
        modules = [('', self.app)]
        modules.extend((name + '/', bp)
                       for name, bp in self.app.blueprints.items())

        for prefix, module in modules:
            migrations = os.path.join(module.root_path, 'migrations')
            if not os.path.exists(migrations):
                continue

            for name in sorted(os.listdir(migrations)):
                if script_re.match(name):
                    yield prefix + name, os.path.join(migrations, name)

    def migrate(self):
        with context(self.app):
            Change = self.app.db.AppliedChanges
            Change.__table__.metadata.bind = self.app.db.session.bind
            Change.__table__.create(checkfirst=True)

            for name, path in self.all_scripts():
                if Change.query.filter_by(name=name).count():
                    continue

                self.app.db.session.add(Change(applied=datetime.utcnow(),
                                               name=name))
                print '%s . . .' % name
                self.apply_script(self.app.db, path)
                self.app.db.session.commit()

    def apply_script(self, db, path):
        with open(path) as file:
            if path.endswith('.sql'):
                cnx = db.session.connection()
                for statement in parse_sql_script(file):
                    cnx.execute(statement)

            elif path.endswith('.py'):
                code = compile(file.read(), path, 'exec')
                eval(code, {'db': db})

def parse_sql_script(f):
    return filter(None, [s.strip() for s in f.read().strip().split('\n\n')])

@contextmanager
def context(app):
    context = app.test_request_context()
    context.push()
    try:
        yield context
    finally:
        context.pop()
<commit_msg>Run migrations in date order.<commit_after>from contextlib import contextmanager
from datetime import datetime
import os
import re
from sqlalchemy import Column, DateTime, String

script_re = re.compile(r'^\d{8}-\d\d-[a-z0-9-_]+\.(:?py|sql)$')

class AppliedChanges(object):
    __tablename__ = 'applied_changes'

    applied = Column(DateTime, nullable=False)
    name = Column(String, primary_key=True)

class Migrate(object):
    def __init__(self, app):
        # FIXME - Should not require `app` here. See
        # <http://flask.pocoo.org/docs/extensiondev/>.
        self.app = app
        self.init_app(app)

    def init_app(self, app):
        app.extensions['migrate'] = self

        # Register our commands.
        def migrate():
            self.migrate()
        app.extensions['script'].command(migrate)

        # Add our table to database.
        self.app.db.AppliedChanges = type('AppliedChanges',
                                          (AppliedChanges, self.app.db.Model),
                                          {})

    def all_scripts(self):
        modules = [('', self.app)]
        modules.extend((name + '/', bp)
                       for name, bp in self.app.blueprints.items())

        for prefix, module in modules:
            migrations = os.path.join(module.root_path, 'migrations')
            if not os.path.exists(migrations):
                continue

            for name in os.listdir(migrations):
                if script_re.match(name):
                    yield prefix + name, os.path.join(migrations, name)

    def migrate(self):
        with context(self.app):
            Change = self.app.db.AppliedChanges
            Change.__table__.metadata.bind = self.app.db.session.bind
            Change.__table__.create(checkfirst=True)

            all = sorted(self.all_scripts(),
                         key=lambda (name, path): os.path.basename(path))
            for name, path in all:
                if Change.query.filter_by(name=name).count():
                    continue

                self.app.db.session.add(Change(applied=datetime.utcnow(),
                                               name=name))
                print '%s . . .' % name
                self.apply_script(self.app.db, path)
                self.app.db.session.commit()

    def apply_script(self, db, path):
        with open(path) as file:
            if path.endswith('.sql'):
                cnx = db.session.connection()
                for statement in parse_sql_script(file):
                    cnx.execute(statement)

            elif path.endswith('.py'):
                code = compile(file.read(), path, 'exec')
                eval(code, {'db': db})

def parse_sql_script(f):
    return filter(None, [s.strip() for s in f.read().strip().split('\n\n')])

@contextmanager
def context(app):
    context = app.test_request_context()
    context.push()
    try:
        yield context
    finally:
        context.pop()
<|endoftext|>


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

from dtf.module import Module

from dtf.adb import DtfAdb
from dtf.client import (DtfClient, RESP_OK, RESP_NO_READ, RESP_ERROR,
                        RESP_NO_WRITE, RESP_EXISTS, RESP_NO_EXIST,
                        ERR_SOCK)

import dtf.logging as log
import dtf.properties as prop
import dtf.core.utils as utils

from dtf.constants import DTF_CLIENT
from argparse import ArgumentParser

import os.path

DTF_CLIENT_PATH = ("%s/included/dtfClient/com.dtf.client-1.3-1.apk" %
                   utils.get_pydtf_dir())

DEFAULT_UPLOAD_PATH = '/data/data/com.dtf.client'

class client(Module):

    """Module class for dtf client"""

    adb = DtfAdb()
    client = DtfClient()

    @classmethod
    def usage(cls):

        """Display module usage"""

        print "dtf Client Manager"
        print "Subcommands:"
        print "    download   Download a file using dtfClient."
        print "    install    Install the dtf client on device."
        print "    status     Print the install status of the client."
        print "    remove     Uninstall the dtf client."
        print "    restart    Restart dtfClient's socket service."
        print "    upload     Upload file using dtfClient."
        print ""

        return 0

    def do_install(self):

        """Install the dtf client on device"""

        log.i(self.name, "Waiting for device to be connected...")
        self.adb.wait_for_device()

        log.i(self.name, "Removing old client if it exists...")
        self.adb.uninstall(DTF_CLIENT)

        log.i(self.name, "Installing dtf client...")

        self.adb.install(DTF_CLIENT_PATH)

        cmd = "am startservice -a com.dtf.action.name.INITIALIZE"
        self.adb.shell_command(cmd)

        busybox_path = "/data/data/%s/files/busybox" % DTF_CLIENT
        prop.set_prop('Info', 'busybox', busybox_path)

        log.i(self.name, "dtf client installed.")

        return 0

    def do_status(self):

        """Print the install status of the client"""

        if self.adb.is_installed(DTF_CLIENT):
            print "dtf Client Status: Installed"
            print ""

        else:
            print "dtf Client Status: Not Installed"
            print ""

    def do_remove(self):

        """Uninstall the dtf client"""

        log.i(self.name, "Waiting for device to be connected...")
        self.adb.wait_for_device()

        log.i(self.name, "Removing dtf client...")
        self.adb.uninstall(DTF_CLIENT)

        prop.del_prop('Info', 'busybox')

        log.i(self.name, "dtf client removed!")

        return 0

    def do_upload(self, args):

        """Upload file to dtf client directory"""

        parser = ArgumentParser(prog='client upload',
                                description='Upload file to device with dtfClient.')
        parser.add_argument('--path', dest='upload_path',
                            default=None, help="Specify a upload point.")
        parser.add_argument('file_name', type=str,
                            help='The file to upload.')

        args = parser.parse_args(args)

        file_name = args.file_name

        if args.upload_path is None:
            upload_file_name = os.path.basename(file_name)
            upload_path = "%s/%s" % (DEFAULT_UPLOAD_PATH, upload_file_name)
        else:
            upload_path = args.upload_path

        if not os.path.isfile(file_name):
            log.e(self.name, "File does not exist: %s" % file_name)
            return -1

        log.i(self.name, "Waiting for device to be connected...")
        self.adb.wait_for_device()
        log.i(self.name, "Device connected!")

        # Is client installed?
        if not self.adb.is_installed(DTF_CLIENT):
            log.e(self.name, "dtf Client is not installed!")
            return -1

        resp = self.client.upload_file(file_name, upload_path)

        if resp == RESP_OK:
            log.i(self.name, "File upload success!")
            return 0
        elif resp == RESP_ERROR:
            log.e(self.name, "General error!")
            return -1
        elif resp == RESP_EXISTS:
            log.e(self.name, "Remote file exist!")
            return -1
        elif resp == RESP_NO_WRITE:
            log.e(self.name, "No write permissions!")
            return -1
        elif resp == ERR_SOCK:
            log.e(self.name, "Socket error!")
            return -1
        else:
            log.e(self.name, "Unknown response, cannot proceed.")
            return -1

        return 0

    def do_download(self, args):

        """Download a file using the dtfClient API"""

        parser = ArgumentParser(prog='client download',
                                description='Download file from device with dtfClient.')
        parser.add_argument('--path', dest='download_path',
                            default=None, help="Specify local path.")
        parser.add_argument('file_name', type=str,
                            help='The file to download.')

        args = parser.parse_args(args)
        file_name = args.file_name

        if args.download_path is None:
            local_path = os.path.basename(file_name)
        else:
            local_path = args.download_path

        if os.path.isfile(local_path):
            log.e(self.name, "Local file '%s' already exists!" % local_path)
            return -1

        log.i(self.name, "Waiting for connected device...")
        self.adb.wait_for_device()
        log.i(self.name, "Device connected!")

        # Is client installed?
        if not self.adb.is_installed(DTF_CLIENT):
            log.e(self.name, "dtf Client is not installed!")
            return -1

        resp = self.client.download_file(file_name, local_path)

        if resp == RESP_OK:
            log.i(self.name, "File download success!")
            return 0
        elif resp == RESP_ERROR:
            log.e(self.name, "General error!")
            return -1
        elif resp == RESP_NO_EXIST:
            log.e(self.name, "Remote file doesnt exist!")
            return -1
        elif resp == RESP_NO_READ:
            log.e(self.name, "No read permissions!")
            return -1
        elif resp == ERR_SOCK:
            log.e(self.name, "Socket error!")
            return -1
        else:
            log.e(self.name, "Unknown response, cannot proceed.")
            return -1

    def do_restart(self):

        """Restart the socket service on the dtfClient"""

        log.i(self.name, "Waiting for device to be connected...")
        self.adb.wait_for_device()
        log.i(self.name, "Connected!")

        cmd = "am startservice -a com.dtf.action.name.RESTART_SOCKET"
        self.adb.shell_command(cmd)

        return 0

    def do_execute(self, args):

        """Execute a command using the dtfClient"""

        if len(args) != 1:
            print "Usage:"
            print "dtf client execute [command]"
            return -1

        command_string = args.pop()

        log.i(self.name, "Waiting for connected device...")
        self.adb.wait_for_device()
        log.i(self.name, "Device connected!")

        # Is client installed?
        if not self.adb.is_installed(DTF_CLIENT):
            log.e(self.name, "dtf Client is not installed!")
            return -1

        response, resp_code = self.client.execute_command(command_string)

        if resp_code == RESP_OK:
            print response
            return 0
        elif resp_code == ERR_SOCK:
            log.e(self.name, "Socket error!")
            return -1
        else:
            log.e(self.name, "Something went wrong with running the command: %d"
                  % resp_code)
            return -1

    def execute(self, args):

        """Main module executor"""

        self.name = self.__self__

        rtn = 0

        if len(args) < 1:
            return self.usage()

        sub_cmd = args.pop(0)

        if sub_cmd == 'install':
            rtn = self.do_install()

        elif sub_cmd == 'status':
            rtn = self.do_status()

        elif sub_cmd == 'remove':
            rtn = self.do_remove()

        elif sub_cmd == 'upload':
            rtn = self.do_upload(args)

        elif sub_cmd == 'download':
            rtn = self.do_download(args)

        elif sub_cmd == 'restart':
            rtn = self.do_restart()

        elif sub_cmd == 'execute':
            rtn = self.do_execute(args)

        else:
            print "Sub-command '%s' not found!" % sub_cmd
            rtn = self.usage()

        return rtn
<commit_msg>Switched %d to %s<commit_after># Android Device Testing Framework ("dtf")
# Copyright 2013-2015 Jake Valletta (@jake_valletta)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Built-in module for client on device """

from dtf.module import Module

from dtf.adb import DtfAdb
from dtf.client import (DtfClient, RESP_OK, RESP_NO_READ, RESP_ERROR,
                        RESP_NO_WRITE, RESP_EXISTS, RESP_NO_EXIST,
                        ERR_SOCK)

import dtf.logging as log
import dtf.properties as prop
import dtf.core.utils as utils

from dtf.constants import DTF_CLIENT
from argparse import ArgumentParser

import os.path

DTF_CLIENT_PATH = ("%s/included/dtfClient/com.dtf.client-1.3-1.apk" %
                   utils.get_pydtf_dir())

DEFAULT_UPLOAD_PATH = '/data/data/com.dtf.client'

class client(Module):

    """Module class for dtf client"""

    adb = DtfAdb()
    client = DtfClient()

    @classmethod
    def usage(cls):

        """Display module usage"""

        print "dtf Client Manager"
        print "Subcommands:"
        print "    download   Download a file using dtfClient."
        print "    install    Install the dtf client on device."
        print "    status     Print the install status of the client."
        print "    remove     Uninstall the dtf client."
        print "    restart    Restart dtfClient's socket service."
        print "    upload     Upload file using dtfClient."
        print ""

        return 0

    def do_install(self):

        """Install the dtf client on device"""

        log.i(self.name, "Waiting for device to be connected...")
        self.adb.wait_for_device()

        log.i(self.name, "Removing old client if it exists...")
        self.adb.uninstall(DTF_CLIENT)

        log.i(self.name, "Installing dtf client...")

        self.adb.install(DTF_CLIENT_PATH)

        cmd = "am startservice -a com.dtf.action.name.INITIALIZE"
        self.adb.shell_command(cmd)

        busybox_path = "/data/data/%s/files/busybox" % DTF_CLIENT
        prop.set_prop('Info', 'busybox', busybox_path)

        log.i(self.name, "dtf client installed.")

        return 0

    def do_status(self):

        """Print the install status of the client"""

        if self.adb.is_installed(DTF_CLIENT):
            print "dtf Client Status: Installed"
            print ""

        else:
            print "dtf Client Status: Not Installed"
            print ""

    def do_remove(self):

        """Uninstall the dtf client"""

        log.i(self.name, "Waiting for device to be connected...")
        self.adb.wait_for_device()

        log.i(self.name, "Removing dtf client...")
        self.adb.uninstall(DTF_CLIENT)

        prop.del_prop('Info', 'busybox')

        log.i(self.name, "dtf client removed!")

        return 0

    def do_upload(self, args):

        """Upload file to dtf client directory"""

        parser = ArgumentParser(prog='client upload',
                                description='Upload file to device with dtfClient.')
        parser.add_argument('--path', dest='upload_path',
                            default=None, help="Specify a upload point.")
        parser.add_argument('file_name', type=str,
                            help='The file to upload.')

        args = parser.parse_args(args)

        file_name = args.file_name

        if args.upload_path is None:
            upload_file_name = os.path.basename(file_name)
            upload_path = "%s/%s" % (DEFAULT_UPLOAD_PATH, upload_file_name)
        else:
            upload_path = args.upload_path

        if not os.path.isfile(file_name):
            log.e(self.name, "File does not exist: %s" % file_name)
            return -1

        log.i(self.name, "Waiting for device to be connected...")
        self.adb.wait_for_device()
        log.i(self.name, "Device connected!")

        # Is client installed?
        if not self.adb.is_installed(DTF_CLIENT):
            log.e(self.name, "dtf Client is not installed!")
            return -1

        resp = self.client.upload_file(file_name, upload_path)

        if resp == RESP_OK:
            log.i(self.name, "File upload success!")
            return 0
        elif resp == RESP_ERROR:
            log.e(self.name, "General error!")
            return -1
        elif resp == RESP_EXISTS:
            log.e(self.name, "Remote file exist!")
            return -1
        elif resp == RESP_NO_WRITE:
            log.e(self.name, "No write permissions!")
            return -1
        elif resp == ERR_SOCK:
            log.e(self.name, "Socket error!")
            return -1
        else:
            log.e(self.name, "Unknown response, cannot proceed.")
            return -1

        return 0

    def do_download(self, args):

        """Download a file using the dtfClient API"""

        parser = ArgumentParser(prog='client download',
                                description='Download file from device with dtfClient.')
        parser.add_argument('--path', dest='download_path',
                            default=None, help="Specify local path.")
        parser.add_argument('file_name', type=str,
                            help='The file to download.')

        args = parser.parse_args(args)
        file_name = args.file_name

        if args.download_path is None:
            local_path = os.path.basename(file_name)
        else:
            local_path = args.download_path

        if os.path.isfile(local_path):
            log.e(self.name, "Local file '%s' already exists!" % local_path)
            return -1

        log.i(self.name, "Waiting for connected device...")
        self.adb.wait_for_device()
        log.i(self.name, "Device connected!")

        # Is client installed?
        if not self.adb.is_installed(DTF_CLIENT):
            log.e(self.name, "dtf Client is not installed!")
            return -1

        resp = self.client.download_file(file_name, local_path)

        if resp == RESP_OK:
            log.i(self.name, "File download success!")
            return 0
        elif resp == RESP_ERROR:
            log.e(self.name, "General error!")
            return -1
        elif resp == RESP_NO_EXIST:
            log.e(self.name, "Remote file doesnt exist!")
            return -1
        elif resp == RESP_NO_READ:
            log.e(self.name, "No read permissions!")
            return -1
        elif resp == ERR_SOCK:
            log.e(self.name, "Socket error!")
            return -1
        else:
            log.e(self.name, "Unknown response, cannot proceed.")
            return -1

    def do_restart(self):

        """Restart the socket service on the dtfClient"""

        log.i(self.name, "Waiting for device to be connected...")
        self.adb.wait_for_device()
        log.i(self.name, "Connected!")

        cmd = "am startservice -a com.dtf.action.name.RESTART_SOCKET"
        self.adb.shell_command(cmd)

        return 0

    def do_execute(self, args):

        """Execute a command using the dtfClient"""

        if len(args) != 1:
            print "Usage:"
            print "dtf client execute [command]"
            return -1

        command_string = args.pop()

        log.i(self.name, "Waiting for connected device...")
        self.adb.wait_for_device()
        log.i(self.name, "Device connected!")

        # Is client installed?
        if not self.adb.is_installed(DTF_CLIENT):
            log.e(self.name, "dtf Client is not installed!")
            return -1

        response, resp_code = self.client.execute_command(command_string)

        if resp_code == RESP_OK:
            print response
            return 0
        elif resp_code == ERR_SOCK:
            log.e(self.name, "Socket error!")
            return -1
        else:
            log.e(self.name, "Something went wrong with running the command: %s"
                  % resp_code)
            return -1

    def execute(self, args):

        """Main module executor"""

        self.name = self.__self__

        rtn = 0

        if len(args) < 1:
            return self.usage()

        sub_cmd = args.pop(0)

        if sub_cmd == 'install':
            rtn = self.do_install()

        elif sub_cmd == 'status':
            rtn = self.do_status()

        elif sub_cmd == 'remove':
            rtn = self.do_remove()

        elif sub_cmd == 'upload':
            rtn = self.do_upload(args)

        elif sub_cmd == 'download':
            rtn = self.do_download(args)

        elif sub_cmd == 'restart':
            rtn = self.do_restart()

        elif sub_cmd == 'execute':
            rtn = self.do_execute(args)

        else:
            print "Sub-command '%s' not found!" % sub_cmd
            rtn = self.usage()

        return rtn
<|endoftext|>


<commit_before>"""Classes for binary search tree."""

class Node():
    """Node object for the binary search tree."""

    def __init__(self, value, left=None, right=None):
        """Instantiate a node object."""
        self.value = value
        self.left = left
        self.right = right

class BinarySearchTree():
    """Binary Search Tree.

    .insert(): Add a value to the BST
    """

    def __init__(self):
        """Initialize the BinarySearchTree Class."""
        self.size = 0
        self.depth = 0
        self.root = None

    def insert(self, value):
        """Insert a value in to the binary search tree."""
        self.size += 1
        if self.root is None:
            self.root = Node(value)
            return
        current_node = self.root
        while True:
            if value < current_node.value:
                if current_node.left:
                    current_node = current_node.left
                else:
                    current_node.left = Node(value)
                    break
            if value > current_node.value:
                if current_node.right:
                    current_node = current_node.right
                else:
                    current_node.right = Node(value)
                    break

    def search(self, value):
        """Search the Binary Search Tree for a value, return node or none."""
        current_node = self.root
        while True:
            if value == current_node.value:
                return current_node
            if value < current_node.value:
                if current_node.left:
                    current_node = current_node.left
                    continue
                else:
                    return None
            if value > current_node.value:
                if current_node.right:
                    current_node = current_node.right
                    continue
                else:
                    return None

<commit_msg>size function<commit_after>"""Classes for binary search tree."""

class Node():
    """Node object for the binary search tree."""

    def __init__(self, value, left=None, right=None):
        """Instantiate a node object."""
        self.value = value
        self.left = left
        self.right = right

class BinarySearchTree():
    """Binary Search Tree.

    .insert(): Add a value to the BST
    """

    def __init__(self):
        """Initialize the BinarySearchTree Class."""
        self.size = 0
        self.depth = 0
        self.root = None

    def insert(self, value):
        """Insert a value in to the binary search tree."""
        self.size += 1
        if self.root is None:
            self.root = Node(value)
            return
        current_node = self.root
        while True:
            if value < current_node.value:
                if current_node.left:
                    current_node = current_node.left
                else:
                    current_node.left = Node(value)
                    break
            if value > current_node.value:
                if current_node.right:
                    current_node = current_node.right
                else:
                    current_node.right = Node(value)
                    break

    def search(self, value):
        """Search the Binary Search Tree for a value, return node or none."""
        current_node = self.root
        while True:
            if value == current_node.value:
                return current_node
            if value < current_node.value:
                if current_node.left:
                    current_node = current_node.left
                    continue
                else:
                    return None
            if value > current_node.value:
                if current_node.right:
                    current_node = current_node.right
                    continue
                else:
                    return None

    def size(self):
        """Return the size of the BST."""
        return self.size

    <|endoftext|>


<commit_before>"""
Like south.modelsparser, but using introspection where possible
rather than direct inspection of models.py.
"""

import datetime

import modelsparser
from south.utils import get_attribute

from django.db import models
from django.contrib.localflavor import us
from django.db.models.base import ModelBase
from django.db.models.fields import NOT_PROVIDED
from django.conf import settings
from django.utils.functional import Promise
from django.contrib.contenttypes import generic
from django.utils.datastructures import SortedDict

NOISY = True

# Gives information about how to introspect certain fields.
# This is a list of triples; the first item is a list of fields it applies to,
# (note that isinstance is used, so superclasses are perfectly valid here)
# the second is a list of positional argument descriptors, and the third
# is a list of keyword argument descriptors.
# Descriptors are of the form:
#  [attrname, options]
# Where attrname is the attribute on the field to get the value from, and options
# is an optional dict.
#
# The introspector uses the combination of all matching entries, in order.
introspection_details = [
    (
        (models.Field, ),
        [],
        {
            "null": ["null", {"default": False}],
            "blank": ["blank", {"default": False, "ignore_if":"primary_key"}],
            "primary_key": ["primary_key", {"default": False}],
            "max_length": ["max_length", {"default": None}],
            "unique": ["_unique", {"default": False}],
            "db_index": ["db_index", {"default": False}],
            "default": ["default", {"default": NOT_PROVIDED}],
            "db_column": ["db_column", {"default": None}],
            "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_INDEX_TABLESPACE}],
        },
    ),
    (
        (models.ForeignKey, models.OneToOneField),
        [],
        {
            "to": ["rel.to", {}],
            "to_field": ["rel.field_name", {"default_attr": "rel.to._meta.pk.name"}],
            "related_name": ["rel.related_name", {"default": None}],
            "db_index": ["db_index", {"default": True}],
        },
    ),
    (
        (models.ManyToManyField,),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
        },
    ),
    (
        (models.DateField, models.TimeField),
        [],
        {
            "auto_now": ["auto_now", {"default": False}],
            "auto_now_add": ["auto_now_add", {"default": False}],
        },
    ),
    (
        (models.DecimalField, ),
        [],
        {
            "max_digits": ["max_digits", {"default": None}],
            "decimal_places": ["decimal_places", {"default": None}],
        },
    ),
    (
        (models.BooleanField, ),
        [],
        {
            "default": ["default", {"default": NOT_PROVIDED, "converter": bool}],
        },
    ),
    (
        (models.FilePathField, ),
        [],
        {
            "path": ["path", {"default": ''}],
            "match": ["match", {"default": None}],
            "recursive": ["recursive", {"default": False}],
        },
    ),
    (
        (generic.GenericRelation, ),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
            "object_id_field": ["object_id_field_name", {"default": "object_id"}],
            "content_type_field": ["content_type_field_name", {"default": "content_type"}],
            "blank": ["blank", {"default": True}],
        },
    ),
]

# Similar, but for Meta, so just the inner level (kwds).
meta_details = {
    "db_table": ["db_table", {"default_attr_concat": ["%s_%s", "app_label", "module_name"]}],
    "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_TABLESPACE}],
    "unique_together": ["unique_together", {"default": []}],
}

# 2.4 compatability
any = lambda x: reduce(lambda y, z: y or z, x, False)

def can_introspect(field):
    """
    Returns True if we are allowed to introspect this field, False otherwise.
    ('allowed' means 'in core'. Custom fields can declare they are introspectable
    by the default South rules by adding the attribute _south_introspects = True.)
    """
    # Check for special attribute
    if hasattr(field, "_south_introspects") and field._south_introspects:
        return True
    # Check it's a core field (one I've written for)
    module = field.__class__.__module__
    return module.startswith("django.db") or module.startswith("django.contrib.gis") or module.startswith("django.contrib.localflavor") or module.startswith("django.contrib.contenttypes.generic")

def matching_details(field):
    """
    Returns the union of all matching entries in introspection_details for the field.
    """
    our_args = []
    our_kwargs = {}
    for classes, args, kwargs in introspection_details:
        if any([isinstance(field, x) for x in classes]):
            our_args.extend(args)
            our_kwargs.update(kwargs)
    return our_args, our_kwargs

class IsDefault(Exception):
    """
    Exception for when a field contains its default value.
    """

def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    value = get_attribute(field, attrname)
    # Lazy-eval functions get eval'd.
    # Annoyingly, we can't do an isinstance() test
    if isinstance(value, Promise):
        value = unicode(value)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # If there's an ignore_if, use it
    if "ignore_if" in options:
        if get_attribute(field, options['ignore_if']):
            raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Models get their own special repr()
    if isinstance(value, ModelBase):
        # If it's a proxy model, follow it back to its non-proxy parent
        if getattr(value._meta, "proxy", False):
            value = value._meta.proxy_for_model
        return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
    # Callables get called.
    elif callable(value):
        # Datetime.datetime.now is special, as we can access it from the eval
        # context (and because it changes all the time; people will file bugs otherwise).
        if value == datetime.datetime.now:
            return "datetime.datetime.now"
        if value == datetime.date.today:
            return "datetime.date.today"
        # All other callables get called.
        value = value()
    # Now, apply the converter func if there is one
    if "converter" in options:
        value = options['converter'](value)
    # Return the final value
    return repr(value)

def introspector(field):
    """
    Given a field, introspects its definition triple.
    """
    arg_defs, kwarg_defs = matching_details(field)
    args = []
    kwargs = {}
    # For each argument, use the descriptor to get the real value.
    for defn in arg_defs:
        try:
            args.append(get_value(field, defn))
        except IsDefault:
            pass
    for kwd, defn in kwarg_defs.items():
        try:
            kwargs[kwd] = get_value(field, defn)
        except IsDefault:
            pass
    return args, kwargs

def get_model_fields(model, m2m=False):
    """
    Given a model class, returns a dict of {field_name: field_triple} defs.
    """

    field_defs = SortedDict()
    inherited_fields = {}

    # Go through all bases (that are themselves models, but not Model)
    for base in model.__bases__:
        if base != models.Model and issubclass(base, models.Model):
            if not base._meta.abstract:
                # Looks like we need their fields, Ma.
                inherited_fields.update(get_model_fields(base))

    # Now, ask the parser to have a look at this model too.
    try:
        parser_fields = modelsparser.get_model_fields(model, m2m) or {}
    except TypeError: # Almost certainly a not-real module
        parser_fields = {}

    # Now, go through all the fields and try to get their definition
    source = model._meta.local_fields[:]
    if m2m:
        source += model._meta.local_many_to_many

    for field in source:
        # Does it define a south_field_triple method?
        if hasattr(field, "south_field_triple"):
            if NOISY:
                print " ( Nativing field: %s" % field.name
            field_defs[field.name] = field.south_field_triple()
        # Can we introspect it?
        elif can_introspect(field):
            #if NOISY:
            #    print "Introspecting field: %s" % field.name
            # Get the full field class path.
            field_class = field.__class__.__module__ + "." + field.__class__.__name__
            # Run this field through the introspector
            args, kwargs = introspector(field)
            # That's our definition!
            field_defs[field.name] = (field_class, args, kwargs)
        # Hmph. Is it parseable?
        elif parser_fields.get(field.name, None):
            if NOISY:
                print " ( Parsing field: %s" % field.name
            field_defs[field.name] = parser_fields[field.name]
        # Shucks, no definition!
        else:
            if NOISY:
                print " ( Nodefing field: %s" % field.name
            field_defs[field.name] = None

    return field_defs

def get_model_meta(model):
    """
    Given a model class, will return the dict representing the Meta class.
    """

    # Get the introspected attributes
    meta_def = {}
    for kwd, defn in meta_details.items():
        try:
            meta_def[kwd] = get_value(model._meta, defn)
        except IsDefault:
            pass

    return meta_def
<commit_msg>Add introspection support for GeoDjango fields<commit_after>"""
Like south.modelsparser, but using introspection where possible
rather than direct inspection of models.py.
"""

import datetime

import modelsparser
from south.utils import get_attribute

from django.db import models
from django.contrib.localflavor import us
from django.db.models.base import ModelBase
from django.db.models.fields import NOT_PROVIDED
from django.conf import settings
from django.utils.functional import Promise
from django.contrib.contenttypes import generic
from django.utils.datastructures import SortedDict
from django.contrib.gis.db.models.fields import GeometryField

NOISY = True

# Gives information about how to introspect certain fields.
# This is a list of triples; the first item is a list of fields it applies to,
# (note that isinstance is used, so superclasses are perfectly valid here)
# the second is a list of positional argument descriptors, and the third
# is a list of keyword argument descriptors.
# Descriptors are of the form:
#  [attrname, options]
# Where attrname is the attribute on the field to get the value from, and options
# is an optional dict.
#
# The introspector uses the combination of all matching entries, in order.
introspection_details = [
    (
        (models.Field, ),
        [],
        {
            "null": ["null", {"default": False}],
            "blank": ["blank", {"default": False, "ignore_if":"primary_key"}],
            "primary_key": ["primary_key", {"default": False}],
            "max_length": ["max_length", {"default": None}],
            "unique": ["_unique", {"default": False}],
            "db_index": ["db_index", {"default": False}],
            "default": ["default", {"default": NOT_PROVIDED}],
            "db_column": ["db_column", {"default": None}],
            "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_INDEX_TABLESPACE}],
        },
    ),
    (
        (models.ForeignKey, models.OneToOneField),
        [],
        {
            "to": ["rel.to", {}],
            "to_field": ["rel.field_name", {"default_attr": "rel.to._meta.pk.name"}],
            "related_name": ["rel.related_name", {"default": None}],
            "db_index": ["db_index", {"default": True}],
        },
    ),
    (
        (models.ManyToManyField,),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
        },
    ),
    (
        (models.DateField, models.TimeField),
        [],
        {
            "auto_now": ["auto_now", {"default": False}],
            "auto_now_add": ["auto_now_add", {"default": False}],
        },
    ),
    (
        (models.DecimalField, ),
        [],
        {
            "max_digits": ["max_digits", {"default": None}],
            "decimal_places": ["decimal_places", {"default": None}],
        },
    ),
    (
        (models.BooleanField, ),
        [],
        {
            "default": ["default", {"default": NOT_PROVIDED, "converter": bool}],
        },
    ),
    (
        (models.FilePathField, ),
        [],
        {
            "path": ["path", {"default": ''}],
            "match": ["match", {"default": None}],
            "recursive": ["recursive", {"default": False}],
        },
    ),
    (
        (generic.GenericRelation, ),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
            "object_id_field": ["object_id_field_name", {"default": "object_id"}],
            "content_type_field": ["content_type_field_name", {"default": "content_type"}],
            "blank": ["blank", {"default": True}],
        },
    ),
    (
        (GeometryField, ),
        [],
        {
            "srid": ["srid", {"default": 4326}],
            "spatial_index": ["spatial_index", {"default": True}],
            "dim": ["dim", {"default": 2}],
        },
    ),
]

# Similar, but for Meta, so just the inner level (kwds).
meta_details = {
    "db_table": ["db_table", {"default_attr_concat": ["%s_%s", "app_label", "module_name"]}],
    "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_TABLESPACE}],
    "unique_together": ["unique_together", {"default": []}],
}

# 2.4 compatability
any = lambda x: reduce(lambda y, z: y or z, x, False)

def can_introspect(field):
    """
    Returns True if we are allowed to introspect this field, False otherwise.
    ('allowed' means 'in core'. Custom fields can declare they are introspectable
    by the default South rules by adding the attribute _south_introspects = True.)
    """
    # Check for special attribute
    if hasattr(field, "_south_introspects") and field._south_introspects:
        return True
    # Check it's a core field (one I've written for)
    module = field.__class__.__module__
    return module.startswith("django.db") or module.startswith("django.contrib.gis") or module.startswith("django.contrib.localflavor") or module.startswith("django.contrib.contenttypes.generic")

def matching_details(field):
    """
    Returns the union of all matching entries in introspection_details for the field.
    """
    our_args = []
    our_kwargs = {}
    for classes, args, kwargs in introspection_details:
        if any([isinstance(field, x) for x in classes]):
            our_args.extend(args)
            our_kwargs.update(kwargs)
    return our_args, our_kwargs

class IsDefault(Exception):
    """
    Exception for when a field contains its default value.
    """

def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    value = get_attribute(field, attrname)
    # Lazy-eval functions get eval'd.
    # Annoyingly, we can't do an isinstance() test
    if isinstance(value, Promise):
        value = unicode(value)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # If there's an ignore_if, use it
    if "ignore_if" in options:
        if get_attribute(field, options['ignore_if']):
            raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Models get their own special repr()
    if isinstance(value, ModelBase):
        # If it's a proxy model, follow it back to its non-proxy parent
        if getattr(value._meta, "proxy", False):
            value = value._meta.proxy_for_model
        return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
    # Callables get called.
    elif callable(value):
        # Datetime.datetime.now is special, as we can access it from the eval
        # context (and because it changes all the time; people will file bugs otherwise).
        if value == datetime.datetime.now:
            return "datetime.datetime.now"
        if value == datetime.date.today:
            return "datetime.date.today"
        # All other callables get called.
        value = value()
    # Now, apply the converter func if there is one
    if "converter" in options:
        value = options['converter'](value)
    # Return the final value
    return repr(value)

def introspector(field):
    """
    Given a field, introspects its definition triple.
    """
    arg_defs, kwarg_defs = matching_details(field)
    args = []
    kwargs = {}
    # For each argument, use the descriptor to get the real value.
    for defn in arg_defs:
        try:
            args.append(get_value(field, defn))
        except IsDefault:
            pass
    for kwd, defn in kwarg_defs.items():
        try:
            kwargs[kwd] = get_value(field, defn)
        except IsDefault:
            pass
    return args, kwargs

def get_model_fields(model, m2m=False):
    """
    Given a model class, returns a dict of {field_name: field_triple} defs.
    """

    field_defs = SortedDict()
    inherited_fields = {}

    # Go through all bases (that are themselves models, but not Model)
    for base in model.__bases__:
        if base != models.Model and issubclass(base, models.Model):
            if not base._meta.abstract:
                # Looks like we need their fields, Ma.
                inherited_fields.update(get_model_fields(base))

    # Now, ask the parser to have a look at this model too.
    try:
        parser_fields = modelsparser.get_model_fields(model, m2m) or {}
    except TypeError: # Almost certainly a not-real module
        parser_fields = {}

    # Now, go through all the fields and try to get their definition
    source = model._meta.local_fields[:]
    if m2m:
        source += model._meta.local_many_to_many

    for field in source:
        # Does it define a south_field_triple method?
        if hasattr(field, "south_field_triple"):
            if NOISY:
                print " ( Nativing field: %s" % field.name
            field_defs[field.name] = field.south_field_triple()
        # Can we introspect it?
        elif can_introspect(field):
            #if NOISY:
            #    print "Introspecting field: %s" % field.name
            # Get the full field class path.
            field_class = field.__class__.__module__ + "." + field.__class__.__name__
            # Run this field through the introspector
            args, kwargs = introspector(field)
            # That's our definition!
            field_defs[field.name] = (field_class, args, kwargs)
        # Hmph. Is it parseable?
        elif parser_fields.get(field.name, None):
            if NOISY:
                print " ( Parsing field: %s" % field.name
            field_defs[field.name] = parser_fields[field.name]
        # Shucks, no definition!
        else:
            if NOISY:
                print " ( Nodefing field: %s" % field.name
            field_defs[field.name] = None

    return field_defs

def get_model_meta(model):
    """
    Given a model class, will return the dict representing the Meta class.
    """

    # Get the introspected attributes
    meta_def = {}
    for kwd, defn in meta_details.items():
        try:
            meta_def[kwd] = get_value(model._meta, defn)
        except IsDefault:
            pass

    return meta_def
<|endoftext|>


<commit_before>"""
Like the old south.modelsparser, but using introspection where possible
rather than direct inspection of models.py.
"""

import datetime
import re
import decimal

from south.utils import get_attribute, auto_through

from django.db import models
from django.db.models.base import ModelBase, Model
from django.db.models.fields import NOT_PROVIDED
from django.conf import settings
from django.utils.functional import Promise
from django.contrib.contenttypes import generic
from django.utils.datastructures import SortedDict

NOISY = False

# Gives information about how to introspect certain fields.
# This is a list of triples; the first item is a list of fields it applies to,
# (note that isinstance is used, so superclasses are perfectly valid here)
# the second is a list of positional argument descriptors, and the third
# is a list of keyword argument descriptors.
# Descriptors are of the form:
#  [attrname, options]
# Where attrname is the attribute on the field to get the value from, and options
# is an optional dict.
#
# The introspector uses the combination of all matching entries, in order.
introspection_details = [
    (
        (models.Field, ),
        [],
        {
            "null": ["null", {"default": False}],
            "blank": ["blank", {"default": False, "ignore_if":"primary_key"}],
            "primary_key": ["primary_key", {"default": False}],
            "max_length": ["max_length", {"default": None}],
            "unique": ["_unique", {"default": False}],
            "db_index": ["db_index", {"default": False}],
            "default": ["default", {"default": NOT_PROVIDED, "ignore_dynamics": True}],
            "db_column": ["db_column", {"default": None}],
            "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_INDEX_TABLESPACE}],
        },
    ),
    (
        (models.ForeignKey, models.OneToOneField),
        [],
        {
            "to": ["rel.to", {}],
            "to_field": ["rel.field_name", {"default_attr": "rel.to._meta.pk.name"}],
            "related_name": ["rel.related_name", {"default": None}],
            "db_index": ["db_index", {"default": True}],
        },
    ),
    (
        (models.ManyToManyField,),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
            "related_name": ["rel.related_name", {"default": None}],
            "db_table": ["db_table", {"default": None}],
            # TODO: Kind of ugly to add this one-time-only option
            "through": ["rel.through", {"ignore_if_auto_through": True}],
        },
    ),
    (
        (models.DateField, models.TimeField),
        [],
        {
            "auto_now": ["auto_now", {"default": False}],
            "auto_now_add": ["auto_now_add", {"default": False}],
        },
    ),
    (
        (models.DecimalField, ),
        [],
        {
            "max_digits": ["max_digits", {"default": None}],
            "decimal_places": ["decimal_places", {"default": None}],
        },
    ),
    (
        (models.BooleanField, ),
        [],
        {
            "default": ["default", {"default": NOT_PROVIDED, "converter": bool}],
        },
    ),
    (
        (models.FilePathField, ),
        [],
        {
            "path": ["path", {"default": ''}],
            "match": ["match", {"default": None}],
            "recursive": ["recursive", {"default": False}],
        },
    ),
    (
        (generic.GenericRelation, ),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
            "object_id_field": ["object_id_field_name", {"default": "object_id"}],
            "content_type_field": ["content_type_field_name", {"default": "content_type"}],
            "blank": ["blank", {"default": True}],
        },
    ),
]

# Regexes of allowed field full paths
allowed_fields = [
    "^django\.db",
    "^django\.contrib\.contenttypes\.generic",
    "^django\.contrib\.localflavor",
]

# Regexes of ignored fields (custom fields which look like fields, but have no column behind them)
ignored_fields = [
    "^django\.contrib\.contenttypes\.generic\.GenericRelation",
    "^django\.contrib\.contenttypes\.generic\.GenericForeignKey",
]

# Similar, but for Meta, so just the inner level (kwds).
meta_details = {
    "db_table": ["db_table", {"default_attr_concat": ["%s_%s", "app_label", "module_name"]}],
    "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_TABLESPACE}],
    "unique_together": ["unique_together", {"default": []}],
}

# 2.4 compatability
any = lambda x: reduce(lambda y, z: y or z, x, False)

def add_introspection_rules(rules=[], patterns=[]):
    "Allows you to add some introspection rules at runtime, e.g. for 3rd party apps."
    assert isinstance(rules, (list, tuple))
    assert isinstance(patterns, (list, tuple))
    allowed_fields.extend(patterns)
    introspection_details.extend(rules)

def add_ignored_fields(patterns):
    "Allows you to add some ignore field patterns."
    assert isinstance(patterns, (list, tuple))
    ignored_fields.extend(patterns)

def can_ignore(field):
    """
    Returns True if we know for certain that we can ignore this field, False
    otherwise.
    """
    full_name = "%s.%s" % (field.__class__.__module__, field.__class__.__name__)
    for regex in ignored_fields:
        if re.match(regex, full_name):
            return True
    return False

def can_introspect(field):
    """
    Returns True if we are allowed to introspect this field, False otherwise.
    ('allowed' means 'in core'. Custom fields can declare they are introspectable
    by the default South rules by adding the attribute _south_introspects = True.)
    """
    # Check for special attribute
    if hasattr(field, "_south_introspects") and field._south_introspects:
        return True
    # Check it's an introspectable field
    full_name = "%s.%s" % (field.__class__.__module__, field.__class__.__name__)
    for regex in allowed_fields:
        if re.match(regex, full_name):
            return True
    return False

def matching_details(field):
    """
    Returns the union of all matching entries in introspection_details for the field.
    """
    our_args = []
    our_kwargs = {}
    for classes, args, kwargs in introspection_details:
        if any([isinstance(field, x) for x in classes]):
            our_args.extend(args)
            our_kwargs.update(kwargs)
    return our_args, our_kwargs

class IsDefault(Exception):
    """
    Exception for when a field contains its default value.
    """

def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    # If the options say it's not a attribute name but a real value, use that.
    if options.get('is_value', False):
        value = attrname
    else:
        value = get_attribute(field, attrname)
    # Lazy-eval functions get eval'd.
    if isinstance(value, Promise):
        value = unicode(value)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # If there's an ignore_if, use it
    if "ignore_if" in options:
        if get_attribute(field, options['ignore_if']):
            raise IsDefault
    # If there's an ignore_if_auto_through which is True, use it
    if options.get("ignore_if_auto_through", False):
        if auto_through(field):
            raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Callables get called.
    if callable(value) and not isinstance(value, ModelBase):
        # Datetime.datetime.now is special, as we can access it from the eval
        # context (and because it changes all the time; people will file bugs otherwise).
        if value == datetime.datetime.now:
            return "datetime.datetime.now"
        if value == datetime.datetime.utcnow:
            return "datetime.datetime.utcnow"
        if value == datetime.date.today:
            return "datetime.date.today"
        # All other callables get called.
        value = value()
    # Models get their own special repr()
    if isinstance(value, ModelBase):
        # If it's a proxy model, follow it back to its non-proxy parent
        if getattr(value._meta, "proxy", False):
            value = value._meta.proxy_for_model
        return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
    # As do model instances
    if isinstance(value, Model):
        if options.get("ignore_dynamics", False):
            raise IsDefault
        return "orm['%s.%s'].objects.get(pk=%r)" % (value.__class__._meta.app_label, value.__class__._meta.object_name, value.pk)
    # Make sure Decimal is converted down into a string
    if isinstance(value, decimal.Decimal):
        value = str(value)
    # Now, apply the converter func if there is one
    if "converter" in options:
        value = options['converter'](value)
    # Return the final value
    return repr(value)

def introspector(field):
    """
    Given a field, introspects its definition triple.
    """
    arg_defs, kwarg_defs = matching_details(field)
    args = []
    kwargs = {}
    # For each argument, use the descriptor to get the real value.
    for defn in arg_defs:
        try:
            args.append(get_value(field, defn))
        except IsDefault:
            pass
    for kwd, defn in kwarg_defs.items():
        try:
            kwargs[kwd] = get_value(field, defn)
        except IsDefault:
            pass
    return args, kwargs

def get_model_fields(model, m2m=False):
    """
    Given a model class, returns a dict of {field_name: field_triple} defs.
    """

    field_defs = SortedDict()
    inherited_fields = {}

    # Go through all bases (that are themselves models, but not Model)
    for base in model.__bases__:
        if base != models.Model and issubclass(base, models.Model):
            if not base._meta.abstract:
                # Looks like we need their fields, Ma.
                inherited_fields.update(get_model_fields(base))

    # Now, go through all the fields and try to get their definition
    source = model._meta.local_fields[:]
    if m2m:
        source += model._meta.local_many_to_many

    for field in source:
        # Can we ignore it completely?
        if can_ignore(field):
            continue
        # Does it define a south_field_triple method?
        if hasattr(field, "south_field_triple"):
            if NOISY:
                print " ( Nativing field: %s" % field.name
            field_defs[field.name] = field.south_field_triple()
        # Can we introspect it?
        elif can_introspect(field):
            # Get the full field class path.
            field_class = field.__class__.__module__ + "." + field.__class__.__name__
            # Run this field through the introspector
            args, kwargs = introspector(field)
            # That's our definition!
            field_defs[field.name] = (field_class, args, kwargs)
        # Shucks, no definition!
        else:
            if NOISY:
                print " ( Nodefing field: %s" % field.name
            field_defs[field.name] = None

    # If they've used the horrific hack that is order_with_respect_to, deal with
    # it.
    if model._meta.order_with_respect_to:
        field_defs['_order'] = ("django.db.models.fields.IntegerField", [], {"default": "0"})

    return field_defs

def get_model_meta(model):
    """
    Given a model class, will return the dict representing the Meta class.
    """

    # Get the introspected attributes
    meta_def = {}
    for kwd, defn in meta_details.items():
        try:
            meta_def[kwd] = get_value(model._meta, defn)
        except IsDefault:
            pass

    # Also, add on any non-abstract model base classes.
    # This is called _ormbases as the _bases variable was previously used
    # for a list of full class paths to bases, so we can't conflict.
    for base in model.__bases__:
        if base != models.Model and issubclass(base, models.Model):
            if not base._meta.abstract:
                # OK, that matches our terms.
                if "_ormbases" not in meta_def:
                    meta_def['_ormbases'] = []
                meta_def['_ormbases'].append("%s.%s" % (
                    base._meta.app_label,
                    base._meta.object_name,
                ))

    return meta_def

# Now, load the built-in South introspection plugins
import south.introspection_plugins
<commit_msg>Fix #483 (invalid freezing of safe_datetime)<commit_after>"""
Like the old south.modelsparser, but using introspection where possible
rather than direct inspection of models.py.
"""

import datetime
import re
import decimal

from south.utils import get_attribute, auto_through

from django.db import models
from django.db.models.base import ModelBase, Model
from django.db.models.fields import NOT_PROVIDED
from django.conf import settings
from django.utils.functional import Promise
from django.contrib.contenttypes import generic
from django.utils.datastructures import SortedDict
from django.utils import datetime_safe

NOISY = False

# Gives information about how to introspect certain fields.
# This is a list of triples; the first item is a list of fields it applies to,
# (note that isinstance is used, so superclasses are perfectly valid here)
# the second is a list of positional argument descriptors, and the third
# is a list of keyword argument descriptors.
# Descriptors are of the form:
#  [attrname, options]
# Where attrname is the attribute on the field to get the value from, and options
# is an optional dict.
#
# The introspector uses the combination of all matching entries, in order.
introspection_details = [
    (
        (models.Field, ),
        [],
        {
            "null": ["null", {"default": False}],
            "blank": ["blank", {"default": False, "ignore_if":"primary_key"}],
            "primary_key": ["primary_key", {"default": False}],
            "max_length": ["max_length", {"default": None}],
            "unique": ["_unique", {"default": False}],
            "db_index": ["db_index", {"default": False}],
            "default": ["default", {"default": NOT_PROVIDED, "ignore_dynamics": True}],
            "db_column": ["db_column", {"default": None}],
            "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_INDEX_TABLESPACE}],
        },
    ),
    (
        (models.ForeignKey, models.OneToOneField),
        [],
        {
            "to": ["rel.to", {}],
            "to_field": ["rel.field_name", {"default_attr": "rel.to._meta.pk.name"}],
            "related_name": ["rel.related_name", {"default": None}],
            "db_index": ["db_index", {"default": True}],
        },
    ),
    (
        (models.ManyToManyField,),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
            "related_name": ["rel.related_name", {"default": None}],
            "db_table": ["db_table", {"default": None}],
            # TODO: Kind of ugly to add this one-time-only option
            "through": ["rel.through", {"ignore_if_auto_through": True}],
        },
    ),
    (
        (models.DateField, models.TimeField),
        [],
        {
            "auto_now": ["auto_now", {"default": False}],
            "auto_now_add": ["auto_now_add", {"default": False}],
        },
    ),
    (
        (models.DecimalField, ),
        [],
        {
            "max_digits": ["max_digits", {"default": None}],
            "decimal_places": ["decimal_places", {"default": None}],
        },
    ),
    (
        (models.BooleanField, ),
        [],
        {
            "default": ["default", {"default": NOT_PROVIDED, "converter": bool}],
        },
    ),
    (
        (models.FilePathField, ),
        [],
        {
            "path": ["path", {"default": ''}],
            "match": ["match", {"default": None}],
            "recursive": ["recursive", {"default": False}],
        },
    ),
    (
        (generic.GenericRelation, ),
        [],
        {
            "to": ["rel.to", {}],
            "symmetrical": ["rel.symmetrical", {"default": True}],
            "object_id_field": ["object_id_field_name", {"default": "object_id"}],
            "content_type_field": ["content_type_field_name", {"default": "content_type"}],
            "blank": ["blank", {"default": True}],
        },
    ),
]

# Regexes of allowed field full paths
allowed_fields = [
    "^django\.db",
    "^django\.contrib\.contenttypes\.generic",
    "^django\.contrib\.localflavor",
]

# Regexes of ignored fields (custom fields which look like fields, but have no column behind them)
ignored_fields = [
    "^django\.contrib\.contenttypes\.generic\.GenericRelation",
    "^django\.contrib\.contenttypes\.generic\.GenericForeignKey",
]

# Similar, but for Meta, so just the inner level (kwds).
meta_details = {
    "db_table": ["db_table", {"default_attr_concat": ["%s_%s", "app_label", "module_name"]}],
    "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_TABLESPACE}],
    "unique_together": ["unique_together", {"default": []}],
}

# 2.4 compatability
any = lambda x: reduce(lambda y, z: y or z, x, False)

def add_introspection_rules(rules=[], patterns=[]):
    "Allows you to add some introspection rules at runtime, e.g. for 3rd party apps."
    assert isinstance(rules, (list, tuple))
    assert isinstance(patterns, (list, tuple))
    allowed_fields.extend(patterns)
    introspection_details.extend(rules)

def add_ignored_fields(patterns):
    "Allows you to add some ignore field patterns."
    assert isinstance(patterns, (list, tuple))
    ignored_fields.extend(patterns)

def can_ignore(field):
    """
    Returns True if we know for certain that we can ignore this field, False
    otherwise.
    """
    full_name = "%s.%s" % (field.__class__.__module__, field.__class__.__name__)
    for regex in ignored_fields:
        if re.match(regex, full_name):
            return True
    return False

def can_introspect(field):
    """
    Returns True if we are allowed to introspect this field, False otherwise.
    ('allowed' means 'in core'. Custom fields can declare they are introspectable
    by the default South rules by adding the attribute _south_introspects = True.)
    """
    # Check for special attribute
    if hasattr(field, "_south_introspects") and field._south_introspects:
        return True
    # Check it's an introspectable field
    full_name = "%s.%s" % (field.__class__.__module__, field.__class__.__name__)
    for regex in allowed_fields:
        if re.match(regex, full_name):
            return True
    return False

def matching_details(field):
    """
    Returns the union of all matching entries in introspection_details for the field.
    """
    our_args = []
    our_kwargs = {}
    for classes, args, kwargs in introspection_details:
        if any([isinstance(field, x) for x in classes]):
            our_args.extend(args)
            our_kwargs.update(kwargs)
    return our_args, our_kwargs

class IsDefault(Exception):
    """
    Exception for when a field contains its default value.
    """

def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    # If the options say it's not a attribute name but a real value, use that.
    if options.get('is_value', False):
        value = attrname
    else:
        value = get_attribute(field, attrname)
    # Lazy-eval functions get eval'd.
    if isinstance(value, Promise):
        value = unicode(value)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # If there's an ignore_if, use it
    if "ignore_if" in options:
        if get_attribute(field, options['ignore_if']):
            raise IsDefault
    # If there's an ignore_if_auto_through which is True, use it
    if options.get("ignore_if_auto_through", False):
        if auto_through(field):
            raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Callables get called.
    if callable(value) and not isinstance(value, ModelBase):
        # Datetime.datetime.now is special, as we can access it from the eval
        # context (and because it changes all the time; people will file bugs otherwise).
        if value == datetime.datetime.now:
            return "datetime.datetime.now"
        if value == datetime.datetime.utcnow:
            return "datetime.datetime.utcnow"
        if value == datetime.date.today:
            return "datetime.date.today"
        # All other callables get called.
        value = value()
    # Models get their own special repr()
    if isinstance(value, ModelBase):
        # If it's a proxy model, follow it back to its non-proxy parent
        if getattr(value._meta, "proxy", False):
            value = value._meta.proxy_for_model
        return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
    # As do model instances
    if isinstance(value, Model):
        if options.get("ignore_dynamics", False):
            raise IsDefault
        return "orm['%s.%s'].objects.get(pk=%r)" % (value.__class__._meta.app_label, value.__class__._meta.object_name, value.pk)
    # Make sure Decimal is converted down into a string
    if isinstance(value, decimal.Decimal):
        value = str(value)
    # datetime_safe has an improper repr value
    if isinstance(value, datetime_safe.datetime):
        value = datetime.datetime(*value.utctimetuple()[:7])
    if isinstance(value, datetime_safe.date):
        value = datetime.date(*value.timetuple()[:3])
    # Now, apply the converter func if there is one
    if "converter" in options:
        value = options['converter'](value)
    # Return the final value
    return repr(value)

def introspector(field):
    """
    Given a field, introspects its definition triple.
    """
    arg_defs, kwarg_defs = matching_details(field)
    args = []
    kwargs = {}
    # For each argument, use the descriptor to get the real value.
    for defn in arg_defs:
        try:
            args.append(get_value(field, defn))
        except IsDefault:
            pass
    for kwd, defn in kwarg_defs.items():
        try:
            kwargs[kwd] = get_value(field, defn)
        except IsDefault:
            pass
    return args, kwargs

def get_model_fields(model, m2m=False):
    """
    Given a model class, returns a dict of {field_name: field_triple} defs.
    """

    field_defs = SortedDict()
    inherited_fields = {}

    # Go through all bases (that are themselves models, but not Model)
    for base in model.__bases__:
        if base != models.Model and issubclass(base, models.Model):
            if not base._meta.abstract:
                # Looks like we need their fields, Ma.
                inherited_fields.update(get_model_fields(base))

    # Now, go through all the fields and try to get their definition
    source = model._meta.local_fields[:]
    if m2m:
        source += model._meta.local_many_to_many

    for field in source:
        # Can we ignore it completely?
        if can_ignore(field):
            continue
        # Does it define a south_field_triple method?
        if hasattr(field, "south_field_triple"):
            if NOISY:
                print " ( Nativing field: %s" % field.name
            field_defs[field.name] = field.south_field_triple()
        # Can we introspect it?
        elif can_introspect(field):
            # Get the full field class path.
            field_class = field.__class__.__module__ + "." + field.__class__.__name__
            # Run this field through the introspector
            args, kwargs = introspector(field)
            # That's our definition!
            field_defs[field.name] = (field_class, args, kwargs)
        # Shucks, no definition!
        else:
            if NOISY:
                print " ( Nodefing field: %s" % field.name
            field_defs[field.name] = None

    # If they've used the horrific hack that is order_with_respect_to, deal with
    # it.
    if model._meta.order_with_respect_to:
        field_defs['_order'] = ("django.db.models.fields.IntegerField", [], {"default": "0"})

    return field_defs

def get_model_meta(model):
    """
    Given a model class, will return the dict representing the Meta class.
    """

    # Get the introspected attributes
    meta_def = {}
    for kwd, defn in meta_details.items():
        try:
            meta_def[kwd] = get_value(model._meta, defn)
        except IsDefault:
            pass

    # Also, add on any non-abstract model base classes.
    # This is called _ormbases as the _bases variable was previously used
    # for a list of full class paths to bases, so we can't conflict.
    for base in model.__bases__:
        if base != models.Model and issubclass(base, models.Model):
            if not base._meta.abstract:
                # OK, that matches our terms.
                if "_ormbases" not in meta_def:
                    meta_def['_ormbases'] = []
                meta_def['_ormbases'].append("%s.%s" % (
                    base._meta.app_label,
                    base._meta.object_name,
                ))

    return meta_def

# Now, load the built-in South introspection plugins
import south.introspection_plugins
<|endoftext|>