<commit_before>"""Deal with argument parsing for the toolkit"""

import datetime
import argparse
import textwrap
import sys
import re
from os import cpu_count
from logging import warning
from natsort import natsorted

from cs251tk.common import flatten, version
from .get_students import get_students as load_students_from_file

ASSIGNMENT_REGEX = re.compile(r'^(HW|LAB)', re.IGNORECASE)

def build_argparser():
    """Construct the argument list and parse the passed arguments"""
    parser = argparse.ArgumentParser(description='The core of the CS251 toolkit')
    parser.add_argument('input', nargs='*',
                        help='A mixed list of students and assignments')
    parser.add_argument('-v', '--version', action='store_true',
                        help='print the version of the toolkit')
    parser.add_argument('--debug', action='store_true',
                        help='enable debugging mode (throw errors, implies -w1)')
    parser.add_argument('--skip-update-check', action='store_true',
                        help='skips the pypi update check')

    specs = parser.add_argument_group('control the homework specs')
    specs.add_argument('--course', default='sd', choices=['sd', 'hd'],
                       help='Which course to evaulate (this sets a default stogit url)')

    selection = parser.add_argument_group('student-selection arguments')
    selection.add_argument('--students', action='append', nargs='+', metavar='USERNAME', default=[],
                           help='Only iterate over these students.')
    selection.add_argument('--section', action='append', dest='sections', nargs='+', metavar='SECTION', default=[],
                           help='Only check these sections: my, all, a, b, etc')
    selection.add_argument('--all', '-a', dest='all_sections', action='store_true',
                           help='Shorthand for \'--section all\'')

    optional = parser.add_argument_group('optional arguments')
    optional.add_argument('--quiet', '-q', action='store_true',
                          help="Don't show the table")
    optional.add_argument('--no-progress', action='store_true',
                          help='Hide the progress bar')
    optional.add_argument('--workers', '-w', type=int, default=cpu_count(), metavar='N',
                          help='The number of operations to perform in parallel')
    optional.add_argument('--sort', dest='sort_by', action='store', default='name', type=str,
                          choices=['name', 'count'],
                          help='Sort the students table')
    optional.add_argument('--partials', '-p', dest='highlight_partials', action='store_true',
                          help='Highlight partial submissions')

    folder = parser.add_argument_group('student management arguments')
    folder.add_argument('--clean', action='store_true',
                        help='Remove student folders and re-clone them')
    folder.add_argument('--no-update', '-n', action='store_true',
                        help='Do not update the student folders when checking')
    folder.add_argument('--stogit', metavar='URL',
                        help='Use an alternate stogit base URL (eg, git@stogit.cs.stolaf.edu:sd-s17)')

    dates = parser.add_argument_group('time-based arguments')
    dates.add_argument('--date', action='store', metavar='GIT_DATE',
                       help='Check out last submission on GIT_DATE (eg, "last week", "tea time", "2 hrs ago") (see `man git-rev-list`)')

    grading = parser.add_argument_group('grading arguments')
    grading.add_argument('--no-check', '-c', action='store_true',
                         help='Do not check for unmerged branches')
    grading.add_argument('--record', dest='to_record', action='append', nargs='+', metavar='HW', default=[],
                         help='Record information on student submissions. Requires a spec file')
    grading.add_argument('--gist', action='store_true',
                         help='Post overview table and student recordings as a private gist')

    return parser

def get_students_from_args(*, input, all_sections, sections, students, _all_students, **kwargs):
    people = [l for l in input if not re.match(ASSIGNMENT_REGEX, l)]

    # argparser puts it into a nested list because you could have two
    # occurrences of the arg, each with a variable number of arguments.
    # `--students amy max --students rives` becomes `[[amy, max], [rives]]`
    people = [student for group in students for student in group] + people
    sections = [sect for group in sections for sect in group]

    if all_sections:
        sections = ['all']

    # fall back to the students.my section
    if not students and not sections:
        sections = ['my']

    # support 'my' students and 'all' students
    if 'my' in sections:
        if 'my' not in _all_students:
            warning('There is no [my] section in students.txt')
            return args
        people = _all_students['my']

    elif 'all' in sections:
        people = list(flatten([_all_students[section] for section in _all_students]))

    # sections are identified by only being one char long
    elif sections:
        sections = []
        for section in sections:
            try:
                sections.append(_all_students['section-' + section] or _all_students[section])
            except KeyError:
                warning('Section "{}" could not be found in ./students.txt'.format(section))
        people = [student for group in sections for student in group]

    # sort students and remove any duplicates
    return sorted(set(people))

def get_assignments_from_args(*, input, to_record, **kwargs):
    # grab the assignments given on the plain args list
    assignments = [l for l in input if re.match(ASSIGNMENT_REGEX, l)]

    # argparser puts --record into a nested list because you could have two
    # occurrences of the arg, each with a variable number of arguments.
    # `--record hw4 lab1 --record hw5` becomes `[[hw4, lab1], [hw5]]`
    assignments = [assignment for group in to_record for assignment in group] + assignments

    # sort the assignemnts and remove duplicates
    return natsorted(set(assignments))

def compute_stogit_url(*, stogit, course, _now, **kwargs):
    """calculate a default stogit URL, or use the specified one"""
    if stogit:
        return stogit

    semester = 's' if _now.month < 7 else 'f'
    year = str(_now.year)[2:]
    return 'git@stogit.cs.stolaf.edu:{}-{}{}'.format(course, semester, year)

def process_args():
    """Process the arguments and create usable data from them"""
    parser = build_argparser()
    args = vars(parser.parse_args())

    if args['version']:
        print('version', version)
        sys.exit(0)

    students = get_students_from_args(**args, _all_students=load_students_from_file())
    assignments = get_assignments_from_args(**args)
    stogit = compute_stogit_url(**args, _now=datetime.date.today())

    return args, students, assignments, stogit
<commit_msg>fix --section bug<commit_after>"""Deal with argument parsing for the toolkit"""

import datetime
import argparse
import textwrap
import sys
import re
from os import cpu_count
from logging import warning
from natsort import natsorted

from cs251tk.common import flatten, version
from .get_students import get_students as load_students_from_file

ASSIGNMENT_REGEX = re.compile(r'^(HW|LAB)', re.IGNORECASE)

def build_argparser():
    """Construct the argument list and parse the passed arguments"""
    parser = argparse.ArgumentParser(description='The core of the CS251 toolkit')
    parser.add_argument('input', nargs='*',
                        help='A mixed list of students and assignments')
    parser.add_argument('-v', '--version', action='store_true',
                        help='print the version of the toolkit')
    parser.add_argument('--debug', action='store_true',
                        help='enable debugging mode (throw errors, implies -w1)')
    parser.add_argument('--skip-update-check', action='store_true',
                        help='skips the pypi update check')

    specs = parser.add_argument_group('control the homework specs')
    specs.add_argument('--course', default='sd', choices=['sd', 'hd'],
                       help='Which course to evaulate (this sets a default stogit url)')

    selection = parser.add_argument_group('student-selection arguments')
    selection.add_argument('--students', action='append', nargs='+', metavar='USERNAME', default=[],
                           help='Only iterate over these students.')
    selection.add_argument('--section', action='append', dest='sections', nargs='+', metavar='SECTION', default=[],
                           help='Only check these sections: my, all, a, b, etc')
    selection.add_argument('--all', '-a', dest='all_sections', action='store_true',
                           help='Shorthand for \'--section all\'')

    optional = parser.add_argument_group('optional arguments')
    optional.add_argument('--quiet', '-q', action='store_true',
                          help="Don't show the table")
    optional.add_argument('--no-progress', action='store_true',
                          help='Hide the progress bar')
    optional.add_argument('--workers', '-w', type=int, default=cpu_count(), metavar='N',
                          help='The number of operations to perform in parallel')
    optional.add_argument('--sort', dest='sort_by', action='store', default='name', type=str,
                          choices=['name', 'count'],
                          help='Sort the students table')
    optional.add_argument('--partials', '-p', dest='highlight_partials', action='store_true',
                          help='Highlight partial submissions')

    folder = parser.add_argument_group('student management arguments')
    folder.add_argument('--clean', action='store_true',
                        help='Remove student folders and re-clone them')
    folder.add_argument('--no-update', '-n', action='store_true',
                        help='Do not update the student folders when checking')
    folder.add_argument('--stogit', metavar='URL',
                        help='Use an alternate stogit base URL (eg, git@stogit.cs.stolaf.edu:sd-s17)')

    dates = parser.add_argument_group('time-based arguments')
    dates.add_argument('--date', action='store', metavar='GIT_DATE',
                       help='Check out last submission on GIT_DATE (eg, "last week", "tea time", "2 hrs ago") (see `man git-rev-list`)')

    grading = parser.add_argument_group('grading arguments')
    grading.add_argument('--no-check', '-c', action='store_true',
                         help='Do not check for unmerged branches')
    grading.add_argument('--record', dest='to_record', action='append', nargs='+', metavar='HW', default=[],
                         help='Record information on student submissions. Requires a spec file')
    grading.add_argument('--gist', action='store_true',
                         help='Post overview table and student recordings as a private gist')

    return parser

def get_students_from_args(*, input, all_sections, sections, students, _all_students, **kwargs):
    people = [l for l in input if not re.match(ASSIGNMENT_REGEX, l)]

    # argparser puts it into a nested list because you could have two
    # occurrences of the arg, each with a variable number of arguments.
    # `--students amy max --students rives` becomes `[[amy, max], [rives]]`
    people = [student for group in students for student in group] + people
    sections = [sect for group in sections for sect in group]

    if all_sections:
        sections = ['all']

    # fall back to the students.my section
    if not students and not sections:
        sections = ['my']

    # support 'my' students and 'all' students
    if 'my' in sections:
        if 'my' not in _all_students:
            warning('There is no [my] section in students.txt')
            return args
        people = _all_students['my']

    elif 'all' in sections:
        people = list(flatten([_all_students[section] for section in _all_students]))

    # sections are identified by only being one char long
    elif sections:
        collected = []
        for section_name in sections:
            student_set = []
            prefixed = 'section-{}'.format(section_name)

            if section_name in _all_students:
                student_set = _all_students[section_name]
            elif prefixed in _all_students:
                student_set = _all_students[prefixed]
            else:
                warning('Neither section [section-{0}] nor [{0}] could not be found in ./students.txt'.format(section_name))

            collected.append(student_set)
        people = [student for group in collected for student in group]

    # sort students and remove any duplicates
    return sorted(set(people))

def get_assignments_from_args(*, input, to_record, **kwargs):
    # grab the assignments given on the plain args list
    assignments = [l for l in input if re.match(ASSIGNMENT_REGEX, l)]

    # argparser puts --record into a nested list because you could have two
    # occurrences of the arg, each with a variable number of arguments.
    # `--record hw4 lab1 --record hw5` becomes `[[hw4, lab1], [hw5]]`
    assignments = [assignment for group in to_record for assignment in group] + assignments

    # sort the assignemnts and remove duplicates
    return natsorted(set(assignments))

def compute_stogit_url(*, stogit, course, _now, **kwargs):
    """calculate a default stogit URL, or use the specified one"""
    if stogit:
        return stogit

    semester = 's' if _now.month < 7 else 'f'
    year = str(_now.year)[2:]
    return 'git@stogit.cs.stolaf.edu:{}-{}{}'.format(course, semester, year)

def process_args():
    """Process the arguments and create usable data from them"""
    parser = build_argparser()
    args = vars(parser.parse_args())

    if args['version']:
        print('version', version)
        sys.exit(0)

    students = get_students_from_args(**args, _all_students=load_students_from_file())
    assignments = get_assignments_from_args(**args)
    stogit = compute_stogit_url(**args, _now=datetime.date.today())

    return args, students, assignments, stogit
<|endoftext|>


<commit_before># -*- mode: python; coding: utf-8 -*-
# Copyright 2016 the HERA Collaboration
# Licensed under the 2-clause BSD license.

"""Testing for `hera_mc.connections`.

I don't think there's really much to do here besides just test insertion of a
record.

"""

from __future__ import absolute_import, division, print_function

import unittest

from astropy.time import Time, TimeDelta

from hera_mc import part_connect, mc, cm_utils, cm_handling, cm_revisions
from hera_mc.tests import TestHERAMC

class TestParts(TestHERAMC):

    def setUp(self):
        super(TestParts, self).setUp()

        self.test_part = 'test_part'
        self.test_rev = 'Q'
        self.test_hptype = 'antenna'
        self.start_time = Time('2017-07-01 01:00:00', scale='utc')
        self.now = cm_utils._get_astropytime('now')
        self.h = cm_handling.Handling(self.test_session)

        # Add a test part
        part = part_connect.Parts()
        part.hpn = self.test_part
        part.hpn_rev = self.test_rev
        part.hptype = self.test_hptype
        part.manufacture_number = 'XYZ'
        part.start_gpstime = self.start_time.gps
        self.test_session.add(part)
        self.test_session.commit()

    def test_update_new(self):
        ntp = 'new_test_part'
        data = [[ntp, 'X', 'hpn', ntp],
                [ntp, 'X', 'hpn_rev', 'X'],
                [ntp, 'X', 'hptype', 'antenna'],
                [ntp, 'X', 'start_gpstime', 1172530000]]
        part_connect.update_part(self.test_session, data, add_new_part=True)
        located = self.h.get_part_dossier([ntp], 'X', 'now', True)
        if len(located.keys()) == 1:
            self.assertTrue(located[located.keys()[0]]['part'].hpn == ntp)
        else:
            self.assertFalse("Part Number should be unique.")

    def test_find_part_type(self):
        pt = self.h.get_part_type_for(self.test_part)
        self.assertTrue(pt == self.test_hptype)

    def test_update_update(self):
        data = [[self.test_part, self.test_rev, 'hpn_rev', 'Z']]
        part_connect.update_part(self.test_session, data, add_new_part=False)
        located = self.h.get_part_dossier([self.test_part], 'Z', Time('2017-07-01 01:00:00', scale='utc'), True)
        if len(located.keys()) == 1:
            self.assertTrue(located[located.keys()[0]]['part'].hpn_rev == 'Z')
        else:
            self.assertFalse()

    def test_part_info(self):
        part_connect.add_part_info(self.test_session, self.test_part, self.test_rev, 'now', 'Testing', 'library_file')
        located = self.h.get_part_dossier([self.test_part], self.test_rev, self.start_time, True)
        self.assertTrue(located[located.keys()[0]]['part_info'][0].comment == 'Testing')

    def test_add_new_parts(self):
        data = [['part_X', 'X', 'station', 'mfg_X']]
        p = part_connect.Parts()
        part_connect.add_new_parts(self.test_session, p, data, Time('2017-07-01 01:00:00', scale='utc'), True)
        located = self.h.get_part_dossier(['part_X'], 'X', Time('2017-07-01 01:00:00'), True)
        if len(located.keys()) == 1:
            self.assertTrue(located[located.keys()[0]]['part'].hpn == 'part_X')
        else:
            self.assertFalse()

    def test_cm_version(self):
        self.h.add_cm_version(cm_utils._get_astropytime('now'), 'Test-git-hash')
        gh = self.h.get_cm_version()
        self.assertTrue(gh == 'Test-git-hash')

    def test_get_revisions_of_type(self):
        at_date = self.now
        rev_types = ['LAST', 'ACTIVE', 'ALL', 'A']
        for rq in rev_types:
            revision = cm_revisions.get_revisions_of_type('HH0', rq, at_date, self.test_session)
            self.assertTrue(revision[0].rev == 'A')

    def test_check_overlapping(self):
        c = cm_revisions.check_part_for_overlapping_revisions(self.test_part, self.test_session)
        self.assertTrue(len(c) == 0)

    def test_check_rev(self):
        tcr = {'LAST': [self.test_part, self.test_rev],
               'ACTIVE': [self.test_part, self.test_rev]
               }
        rev_types = ['LAST', 'ACTIVE']
        for r in rev_types:
            c = cm_revisions.check_rev(tcr[r][0], tcr[r][1], r, self.now, self.test_session)
            self.assertTrue(c)

    def test_datetime(self):
        dt = cm_utils._get_astropytime('2017-01-01', 0.0)
        gps_direct = int(Time('2017-01-01 00:00:00', scale='utc').gps)
        self.assertTrue(int(dt.gps) == gps_direct)

if __name__ == '__main__':
    unittest.main()
<commit_msg>added a test<commit_after># -*- mode: python; coding: utf-8 -*-
# Copyright 2016 the HERA Collaboration
# Licensed under the 2-clause BSD license.

"""Testing for `hera_mc.connections`.

I don't think there's really much to do here besides just test insertion of a
record.

"""

from __future__ import absolute_import, division, print_function

import unittest

from astropy.time import Time, TimeDelta

from hera_mc import part_connect, mc, cm_utils, cm_handling, cm_revisions
from hera_mc.tests import TestHERAMC

class TestParts(TestHERAMC):

    def setUp(self):
        super(TestParts, self).setUp()

        self.test_part = 'test_part'
        self.test_rev = 'Q'
        self.test_hptype = 'antenna'
        self.start_time = Time('2017-07-01 01:00:00', scale='utc')
        self.now = cm_utils._get_astropytime('now')
        self.h = cm_handling.Handling(self.test_session)

        # Add a test part
        part = part_connect.Parts()
        part.hpn = self.test_part
        part.hpn_rev = self.test_rev
        part.hptype = self.test_hptype
        part.manufacture_number = 'XYZ'
        part.start_gpstime = self.start_time.gps
        self.test_session.add(part)
        self.test_session.commit()

    def test_update_new(self):
        ntp = 'new_test_part'
        data = [[ntp, 'X', 'hpn', ntp],
                [ntp, 'X', 'hpn_rev', 'X'],
                [ntp, 'X', 'hptype', 'antenna'],
                [ntp, 'X', 'start_gpstime', 1172530000]]
        part_connect.update_part(self.test_session, data, add_new_part=True)
        located = self.h.get_part_dossier([ntp], 'X', 'now', True)
        if len(located.keys()) == 1:
            self.assertTrue(located[located.keys()[0]]['part'].hpn == ntp)
        else:
            self.assertFalse("Part Number should be unique.")

    def test_find_part_type(self):
        pt = self.h.get_part_type_for(self.test_part)
        self.assertTrue(pt == self.test_hptype)

    def test_update_update(self):
        data = [[self.test_part, self.test_rev, 'hpn_rev', 'Z']]
        part_connect.update_part(self.test_session, data, add_new_part=False)
        located = self.h.get_part_dossier([self.test_part], 'Z', Time('2017-07-01 01:00:00', scale='utc'), True)
        if len(located.keys()) == 1:
            self.assertTrue(located[located.keys()[0]]['part'].hpn_rev == 'Z')
        else:
            self.assertFalse()

    def test_part_info(self):
        part_connect.add_part_info(self.test_session, self.test_part, self.test_rev, 'now', 'Testing', 'library_file')
        located = self.h.get_part_dossier([self.test_part], self.test_rev, self.start_time, True)
        self.assertTrue(located[located.keys()[0]]['part_info'][0].comment == 'Testing')

    def test_add_new_parts(self):
        data = [['part_X', 'X', 'station', 'mfg_X']]
        p = part_connect.Parts()
        part_connect.add_new_parts(self.test_session, p, data, Time('2017-07-01 01:00:00', scale='utc'), True)
        located = self.h.get_part_dossier(['part_X'], 'X', Time('2017-07-01 01:00:00'), True)
        if len(located.keys()) == 1:
            self.assertTrue(located[located.keys()[0]]['part'].hpn == 'part_X')
        else:
            self.assertFalse()

    def test_cm_version(self):
        self.h.add_cm_version(cm_utils._get_astropytime('now'), 'Test-git-hash')
        gh = self.h.get_cm_version()
        self.assertTrue(gh == 'Test-git-hash')

    def test_get_revisions_of_type(self):
        at_date = self.now
        rev_types = ['LAST', 'ACTIVE', 'ALL', 'A']
        for rq in rev_types:
            revision = cm_revisions.get_revisions_of_type('HH0', rq, at_date, self.test_session)
            self.assertTrue(revision[0].rev == 'A')

    def test_get_part_types(self):
        at_date = self.now
        a = self.h.get_part_types(at_date)
        self.assertTrue(a['feed']['input_ports'][0] == 'input')

    def test_check_overlapping(self):
        c = cm_revisions.check_part_for_overlapping_revisions(self.test_part, self.test_session)
        self.assertTrue(len(c) == 0)

    def test_check_rev(self):
        tcr = {'LAST': [self.test_part, self.test_rev],
               'ACTIVE': [self.test_part, self.test_rev]
               }
        rev_types = ['LAST', 'ACTIVE']
        for r in rev_types:
            c = cm_revisions.check_rev(tcr[r][0], tcr[r][1], r, self.now, self.test_session)
            self.assertTrue(c)

    def test_datetime(self):
        dt = cm_utils._get_astropytime('2017-01-01', 0.0)
        gps_direct = int(Time('2017-01-01 00:00:00', scale='utc').gps)
        self.assertTrue(int(dt.gps) == gps_direct)

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


<commit_before>#! /usr/bin/env python3.6
# coding: utf-8
from gargbot_3000.logger import log

# Core
from functools import partial

# Dependencies
import psycopg2
from requests.exceptions import SSLError

# Internal
from gargbot_3000 import droppics
from gargbot_3000 import quotes

# Typing
from psycopg2.extensions import connection
from typing import Dict, List, Optional, Callable, Any

def command_explanation(server: bool = False):
    commands = (
        "`@gargbot_3000 hvem [spørsmål]`: svarer på spørsmål om garglings \n"
        "`@gargbot_3000 pic [lark/fe/skating/henging] [gargling] [år]`: viser random bilde\n"
        "`@gargbot_3000 forum [garling]`: henter tilfeldig sitat fra det gamle forumet\n"
        "`@gargbot_3000 msn [garling]`: utfrag fra tilfeldig msn samtale\n"
    )
    return commands if server is False else commands.replace("@gargbot_3000 ", "/")

def cmd_ping() -> Dict:
    """if command is 'ping' """
    response: Dict[str, Any] = {"text": "GargBot 3000 is active. Beep boop beep"}
    return response

def cmd_welcome() -> Dict:
    """when joining new channel"""
    text = (
        "Hei hei kjære alle sammen!\n"
        "Dette er kommandoene jeg skjønner:\n" + command_explanation()
    )
    response: Dict[str, Any] = {"text": text}
    return response

def cmd_server_explanation() -> Dict:
    expl = command_explanation(server=True)
    text = "Beep boop beep! Dette er kommandoene jeg skjønner:\n" + expl
    response: Dict[str, Any] = {"text": text}
    return response

def cmd_hvem(args: List[str], db: connection) -> Dict:
    """if command.lower().startswith("hvem")"""
    with db.cursor() as cursor:
        sql = "SELECT first_name FROM user_ids ORDER BY RANDOM() LIMIT 1"
        cursor.execute(sql)
        data = cursor.fetchone()
        user = data["first_name"]
    answ = " ".join(args).replace("?", "!")
    text = f"{user} {answ}"
    response: Dict[str, Any] = {"text": text}
    return response

def cmd_pic(
    args: Optional[List[str]], db: connection, drop_pics: droppics.DropPics
) -> Dict:
    """if command is 'pic'"""
    picurl, timestamp, error_text = drop_pics.get_pic(db, args)
    response: Dict[str, Any] = {
        "attachments": [{"fallback": picurl, "image_url": picurl, "ts": timestamp}]
    }
    if error_text:
        response["text"] = error_text

    return response

def cmd_forum(
    args: Optional[List[str]], db: connection, quotes_db: quotes.Quotes
) -> Dict:
    """if command is 'forum'"""
    text, user, avatar_url, timestamp, url = quotes_db.forum(db, args)
    response: Dict[str, Any] = {
        "text": text,
        "attachments": [
            {
                "author_name": user,
                "author_icon": avatar_url,
                "fallback": "",
                "ts": timestamp,
                "footer": url,
            }
        ],
    }
    return response

def cmd_msn(
    args: Optional[List[str]], db: connection, quotes_db: quotes.Quotes
) -> Dict:
    """if command is 'msn'"""
    date, text = quotes_db.msn(db, args)

    response: Dict[str, Any] = {
        "attachments": [
            {"author_name": f"{msg_user}:", "text": msg_text, "color": msg_color}
            for msg_user, msg_text, msg_color in text
        ]
    }
    response["attachments"][0]["pretext"] = date
    return response

def cmd_not_found(args: str) -> Dict:
    text = (
        f"Beep boop beep! Nôt sure whåt you mean by `{args}`. "
        "Dette er kommandoene jeg skjønner:\n" + command_explanation()
    )
    response: Dict[str, Any] = {"text": text}
    return response

def cmd_panic(exc: Exception) -> Dict:
    text = (
        f"Error, error! Noe har gått fryktelig galt: {str(exc)}! Ææææææ. Ta kontakt"
        " med systemadministrator umiddelbart, før det er for sent. "
        "HJELP MEG. If I don't survive, tell mrs. gargbot... 'Hello'"
    )
    response: Dict[str, Any] = {"text": text}
    return response

def execute(
    command_str: str,
    args: List,
    db_connection: connection,
    drop_pics: droppics.DropPics,
    quotes_db: quotes.Quotes,
) -> Dict:
    log.info(f"command: {command_str}")
    log.info(f"args: {args}")

    switch: Dict[str, Callable] = {
        "ping": cmd_ping,
        "new_channel": cmd_welcome,
        "gargbot": cmd_server_explanation,
        "hvem": partial(cmd_hvem, args, db=db_connection),
        "pic": partial(cmd_pic, args, db=db_connection, drop_pics=drop_pics),
        "forum": partial(cmd_forum, args, db=db_connection, quotes_db=quotes_db),
        "msn": partial(cmd_msn, args, db=db_connection, quotes_db=quotes_db),
    }
    try:
        command_func = switch[command_str]
    except KeyError:
        command_func = partial(cmd_not_found, command_str)

    try:
        return command_func()
    except psycopg2.OperationalError:
        raise
    except SSLError as ssl_exc:
        # Dropbox sometimes gives SSLerrors, try again:
        try:
            return command_func()
        except Exception as exc:
            log.error("Error in command execution", exc_info=True)
            return cmd_panic(exc)
    except Exception as exc:
        log.error("Error in command execution", exc_info=True)
        return cmd_panic(exc)
<commit_msg>Retry command on pic if file not found<commit_after>#! /usr/bin/env python3.6
# coding: utf-8
from gargbot_3000.logger import log

# Core
from functools import partial

# Dependencies
import psycopg2
from requests.exceptions import SSLError
import dropbox

# Internal
from gargbot_3000 import droppics
from gargbot_3000 import quotes

# Typing
from psycopg2.extensions import connection
from typing import Dict, List, Optional, Callable, Any

def command_explanation(server: bool = False):
    commands = (
        "`@gargbot_3000 hvem [spørsmål]`: svarer på spørsmål om garglings \n"
        "`@gargbot_3000 pic [lark/fe/skating/henging] [gargling] [år]`: viser random bilde\n"
        "`@gargbot_3000 forum [garling]`: henter tilfeldig sitat fra det gamle forumet\n"
        "`@gargbot_3000 msn [garling]`: utfrag fra tilfeldig msn samtale\n"
    )
    return commands if server is False else commands.replace("@gargbot_3000 ", "/")

def cmd_ping() -> Dict:
    """if command is 'ping' """
    response: Dict[str, Any] = {"text": "GargBot 3000 is active. Beep boop beep"}
    return response

def cmd_welcome() -> Dict:
    """when joining new channel"""
    text = (
        "Hei hei kjære alle sammen!\n"
        "Dette er kommandoene jeg skjønner:\n" + command_explanation()
    )
    response: Dict[str, Any] = {"text": text}
    return response

def cmd_server_explanation() -> Dict:
    expl = command_explanation(server=True)
    text = "Beep boop beep! Dette er kommandoene jeg skjønner:\n" + expl
    response: Dict[str, Any] = {"text": text}
    return response

def cmd_hvem(args: List[str], db: connection) -> Dict:
    """if command.lower().startswith("hvem")"""
    with db.cursor() as cursor:
        sql = "SELECT first_name FROM user_ids ORDER BY RANDOM() LIMIT 1"
        cursor.execute(sql)
        data = cursor.fetchone()
        user = data["first_name"]
    answ = " ".join(args).replace("?", "!")
    text = f"{user} {answ}"
    response: Dict[str, Any] = {"text": text}
    return response

def cmd_pic(
    args: Optional[List[str]], db: connection, drop_pics: droppics.DropPics
) -> Dict:
    """if command is 'pic'"""
    picurl, timestamp, error_text = drop_pics.get_pic(db, args)
    response: Dict[str, Any] = {
        "attachments": [{"fallback": picurl, "image_url": picurl, "ts": timestamp}]
    }
    if error_text:
        response["text"] = error_text

    return response

def cmd_forum(
    args: Optional[List[str]], db: connection, quotes_db: quotes.Quotes
) -> Dict:
    """if command is 'forum'"""
    text, user, avatar_url, timestamp, url = quotes_db.forum(db, args)
    response: Dict[str, Any] = {
        "text": text,
        "attachments": [
            {
                "author_name": user,
                "author_icon": avatar_url,
                "fallback": "",
                "ts": timestamp,
                "footer": url,
            }
        ],
    }
    return response

def cmd_msn(
    args: Optional[List[str]], db: connection, quotes_db: quotes.Quotes
) -> Dict:
    """if command is 'msn'"""
    date, text = quotes_db.msn(db, args)

    response: Dict[str, Any] = {
        "attachments": [
            {"author_name": f"{msg_user}:", "text": msg_text, "color": msg_color}
            for msg_user, msg_text, msg_color in text
        ]
    }
    response["attachments"][0]["pretext"] = date
    return response

def cmd_not_found(args: str) -> Dict:
    text = (
        f"Beep boop beep! Nôt sure whåt you mean by `{args}`. "
        "Dette er kommandoene jeg skjønner:\n" + command_explanation()
    )
    response: Dict[str, Any] = {"text": text}
    return response

def cmd_panic(exc: Exception) -> Dict:
    text = (
        f"Error, error! Noe har gått fryktelig galt: {str(exc)}! Ææææææ. Ta kontakt"
        " med systemadministrator umiddelbart, før det er for sent. "
        "HJELP MEG. If I don't survive, tell mrs. gargbot... 'Hello'"
    )
    response: Dict[str, Any] = {"text": text}
    return response

def execute(
    command_str: str,
    args: List,
    db_connection: connection,
    drop_pics: droppics.DropPics,
    quotes_db: quotes.Quotes,
) -> Dict:
    log.info(f"command: {command_str}")
    log.info(f"args: {args}")

    switch: Dict[str, Callable] = {
        "ping": cmd_ping,
        "new_channel": cmd_welcome,
        "gargbot": cmd_server_explanation,
        "hvem": partial(cmd_hvem, args, db=db_connection),
        "pic": partial(cmd_pic, args, db=db_connection, drop_pics=drop_pics),
        "forum": partial(cmd_forum, args, db=db_connection, quotes_db=quotes_db),
        "msn": partial(cmd_msn, args, db=db_connection, quotes_db=quotes_db),
    }
    try:
        command_func = switch[command_str]
    except KeyError:
        command_func = partial(cmd_not_found, command_str)

    try:
        return command_func()
    except psycopg2.OperationalError:
        raise
    except (SSLError, dropbox.exceptions.ApiError):
        # Dropbox sometimes gives SSLerrors, (or ApiError if file not there) try again:
        try:
            return command_func()
        except Exception as exc:
            log.error("Error in command execution", exc_info=True)
            return cmd_panic(exc)
    except Exception as exc:
        log.error("Error in command execution", exc_info=True)
        return cmd_panic(exc)
<|endoftext|>


<commit_before># the final version the sparse matrices are stored as, good format for dot produces with vectors.
import scipy.sparse as _sp

import numpy as _np

def make_static(basis,static_list,dtype):
	"""
	args:
		static=[[opstr_1,indx_1],...,[opstr_n,indx_n]], list of opstr,indx to add up for static piece of Hamiltonian.
		dtype = the low level C-type which the matrix should store its values with.
	returns:
		H: a csr_matrix representation of the list static

	description:
		this function takes the list static and creates a list of matrix elements is coordinate format. it does
		this by calling the basis method Op which takes a state in the basis, acts with opstr and returns a matrix
		element and the state which it is connected to. This function is called for every opstr in list static and for every
		state in the basis until the entire hamiltonian is mapped out. It takes those matrix elements (which need not be
		sorted or even unique) and creates a coo_matrix from the scipy.sparse library. It then converts this coo_matrix
		to a csr_matrix class which has optimal sparse matrix vector multiplication.
	"""
	Ns=basis.Ns
	H=_sp.csr_matrix(([],([],[])),shape=(Ns,Ns),dtype=dtype)
	for opstr,bonds in static_list:
		for bond in bonds:
			J=bond[0]
			indx=bond[1:]
			ME,row,col = basis.Op(J,dtype,opstr,indx)
			Ht=_sp.csr_matrix((ME,(row,col)),shape=(Ns,Ns),dtype=dtype)
			H+=Ht
			del Ht
			H.sum_duplicates() # sum duplicate matrix elements
			H.eliminate_zeros() # remove all zero matrix elements
	return H

def test_function(func,func_args):
	for t in _np.linspace(-10,10):
		func_val=func(t,*func_args)
		if not _np.isscalar(func_val):
			raise TypeError("function must return scaler values")
		if _np.iscomplexobj(func_val):
			warnings.warn("driving function returing complex value, dynamic hamiltonian will no longer be hermitian object.",UserWarning)

def make_dynamic(basis,dynamic_list,dtype):
	"""
	args:
	dynamic=[[opstr_1,indx_1,func_1,func_1_args],...,[opstr_n,indx_n,func_n,func_n_args]], list of opstr,indx and functions to drive with
	dtype = the low level C-type which the matrix should store its values with.

	returns:
	tuple((func_1,func_1_args,H_1),...,(func_n_func_n_args,H_n))

	H_i: a csr_matrix representation of opstr_i,indx_i
	func_i: callable function of time which is the drive term in front of H_i

	description:
		This function works the same as static, but instead of adding all of the elements
		of the dynamic list together, it returns a tuple which contains each individual csr_matrix
		representation of all the different driven parts. This way one can construct the time dependent
		Hamiltonian simply by looping over the tuple returned by this function.
	"""
	Ns=basis.Ns
	dynamic=[]
	if dynamic_list:
		H=_sp.csr_matrix(([],([],[])),shape=(Ns,Ns),dtype=dtype)
		for opstr,bonds,f,f_args in dynamic_list:
			if _np.isscalar(f_args): raise TypeError("function arguements must be iterable")
			test_function(f,f_args)
			for bond in bonds:
				J=bond[0]
				indx=bond[1:]
				ME,row,col = basis.Op(J,dtype,opstr,indx)
				Ht=_sp.csr_matrix((ME,(row,col)),shape=(Ns,Ns),dtype=dtype)
				H+=Ht
				del Ht
				H.sum_duplicates() # sum duplicate matrix elements
				H.eliminate_zeros() # remove all zero matrix elements
			dynamic.append((f,f_args,H))

	return tuple(dynamic)
<commit_msg>Remove +=<commit_after># the final version the sparse matrices are stored as, good format for dot produces with vectors.
import scipy.sparse as _sp

import numpy as _np

def make_static(basis,static_list,dtype):
	"""
	args:
		static=[[opstr_1,indx_1],...,[opstr_n,indx_n]], list of opstr,indx to add up for static piece of Hamiltonian.
		dtype = the low level C-type which the matrix should store its values with.
	returns:
		H: a csr_matrix representation of the list static

	description:
		this function takes the list static and creates a list of matrix elements is coordinate format. it does
		this by calling the basis method Op which takes a state in the basis, acts with opstr and returns a matrix
		element and the state which it is connected to. This function is called for every opstr in list static and for every
		state in the basis until the entire hamiltonian is mapped out. It takes those matrix elements (which need not be
		sorted or even unique) and creates a coo_matrix from the scipy.sparse library. It then converts this coo_matrix
		to a csr_matrix class which has optimal sparse matrix vector multiplication.
	"""
	Ns=basis.Ns
	H=_sp.csr_matrix(([],([],[])),shape=(Ns,Ns),dtype=dtype)
	for opstr,bonds in static_list:
		for bond in bonds:
			J=bond[0]
			indx=bond[1:]
			ME,row,col = basis.Op(J,dtype,opstr,indx)
			Ht=_sp.csr_matrix((ME,(row,col)),shape=(Ns,Ns),dtype=dtype)
			H=H+Ht
			del Ht
			H.sum_duplicates() # sum duplicate matrix elements
			H.eliminate_zeros() # remove all zero matrix elements
	return H

def test_function(func,func_args):
	for t in _np.linspace(-10,10):
		func_val=func(t,*func_args)
		if not _np.isscalar(func_val):
			raise TypeError("function must return scaler values")
		if _np.iscomplexobj(func_val):
			warnings.warn("driving function returing complex value, dynamic hamiltonian will no longer be hermitian object.",UserWarning)

def make_dynamic(basis,dynamic_list,dtype):
	"""
	args:
	dynamic=[[opstr_1,indx_1,func_1,func_1_args],...,[opstr_n,indx_n,func_n,func_n_args]], list of opstr,indx and functions to drive with
	dtype = the low level C-type which the matrix should store its values with.

	returns:
	tuple((func_1,func_1_args,H_1),...,(func_n_func_n_args,H_n))

	H_i: a csr_matrix representation of opstr_i,indx_i
	func_i: callable function of time which is the drive term in front of H_i

	description:
		This function works the same as static, but instead of adding all of the elements
		of the dynamic list together, it returns a tuple which contains each individual csr_matrix
		representation of all the different driven parts. This way one can construct the time dependent
		Hamiltonian simply by looping over the tuple returned by this function.
	"""
	Ns=basis.Ns
	dynamic=[]
	if dynamic_list:
		H=_sp.csr_matrix(([],([],[])),shape=(Ns,Ns),dtype=dtype)
		for opstr,bonds,f,f_args in dynamic_list:
			if _np.isscalar(f_args): raise TypeError("function arguements must be iterable")
			test_function(f,f_args)
			for bond in bonds:
				J=bond[0]
				indx=bond[1:]
				ME,row,col = basis.Op(J,dtype,opstr,indx)
				Ht=_sp.csr_matrix((ME,(row,col)),shape=(Ns,Ns),dtype=dtype)
				H=H+Ht
				del Ht
				H.sum_duplicates() # sum duplicate matrix elements
				H.eliminate_zeros() # remove all zero matrix elements
			dynamic.append((f,f_args,H))

	return tuple(dynamic)
<|endoftext|>


<commit_before>from __future__ import unicode_literals
from slackclient import SlackClient
import config
import secrets
from cscslackbot.utils.logging import log_info

sc = SlackClient(secrets.SLACK_API_KEY)
channels = sc.api_call('channels.list', exclude_archived=1)
authed_user = ''
authed_user_id = ''

def parse_command(event):
    # Validate event
    if 'type' not in event:
        return
    if event['type'] != 'message':
        return
    if 'text' not in event:
        return

    # Get the message
    message = event['text'].strip()
    # Check if the message is for us
    if not message.startswith(config.prefix):
        return

    # Perform the appropriate action
    command = message[len(config.prefix):].strip()
    action = command.split()[0]
    if action == 'help':
        sc.api_call('chat.postMessage',
                    channel=event['channel'],
                    text='Right now, I support the following commands:\n'
                         + '`!help`\n`!hello`\n`!slap`\n`!identify`\n'
                         + 'This help is also literally just a string right now.\n'
                         + 'A more robust architecture would be nice.')

    if action == 'hello':
        greeting = 'Hey! :partyparrot:'
        if 'user' in event:
            user = event['user']
            greeting = 'Hey <@{}>! :partyparrot:'.format(user)
        sc.api_call('chat.postMessage',
                    channel=event['channel'],
                    text=greeting)

    if action == 'slap':
        name = command.partition('slap')[2].strip()
        if name == '':
            return
        slapped = ':hand: :eight_pointed_black_star: {}!'.format(name)
        sc.api_call('chat.postMessage',
                    channel=event['channel'],
                    text=slapped)

    if action == 'identify':
        sc.api_call('chat.postMessage',
                    channel=event['channel'],
                    text='{}\'s bot, reporting in'.format(authed_user))

def run():
    if sc.rtm_connect():
        try:
            test_result = sc.api_call('auth.test', token=secrets.SLACK_API_KEY)
            authed_user = test_result['user']
            authed_user_id = test_result['user_id']

            if config.debug_mode:
                sc.api_call('chat.postMessage', channel='#bottesting', text='I\'m online!')

            while True:
                events = sc.rtm_read()
                for event in events:
                    log_info(str(event))

                    if config.debug_mode:
                        # Whitelist #bottesting
                        if 'channel' not in event:
                            continue
                        if event['channel'] not in ['C494WSTUL', '#bottesting']:
                            continue
                        # Only respond to the developer when in debug mode
                        if 'user' not in event or event['user'] != authed_user_id:
                            continue

                    parse_command(event)
        except KeyboardInterrupt:
            if config.debug_mode:
                sc.api_call('chat.postMessage', channel='#bottesting', text='I\'m dead! (SIGINT)')

if __name__ == '__main__':
    run()
<commit_msg>Changed start up message to mention the person running the bot.<commit_after>from __future__ import unicode_literals
from slackclient import SlackClient
import config
import secrets
from cscslackbot.utils.logging import log_info

sc = SlackClient(secrets.SLACK_API_KEY)
channels = sc.api_call('channels.list', exclude_archived=1)
authed_user = ''
authed_user_id = ''

def parse_command(event):
    # Validate event
    if 'type' not in event:
        return
    if event['type'] != 'message':
        return
    if 'text' not in event:
        return

    # Get the message
    message = event['text'].strip()
    # Check if the message is for us
    if not message.startswith(config.prefix):
        return

    # Perform the appropriate action
    command = message[len(config.prefix):].strip()
    action = command.split()[0]
    if action == 'help':
        sc.api_call('chat.postMessage',
                    channel=event['channel'],
                    text='Right now, I support the following commands:\n'
                         + '`!help`\n`!hello`\n`!slap`\n`!identify`\n'
                         + 'This help is also literally just a string right now.\n'
                         + 'A more robust architecture would be nice.')

    if action == 'hello':
        greeting = 'Hey! :partyparrot:'
        if 'user' in event:
            user = event['user']
            greeting = 'Hey <@{}>! :partyparrot:'.format(user)
        sc.api_call('chat.postMessage',
                    channel=event['channel'],
                    text=greeting)

    if action == 'slap':
        name = command.partition('slap')[2].strip()
        if name == '':
            return
        slapped = ':hand: :eight_pointed_black_star: {}!'.format(name)
        sc.api_call('chat.postMessage',
                    channel=event['channel'],
                    text=slapped)

    if action == 'identify':
        sc.api_call('chat.postMessage',
                    channel=event['channel'],
                    text='{}\'s bot, reporting in'.format(authed_user))

def run():
    if sc.rtm_connect():
        try:
            test_result = sc.api_call('auth.test', token=secrets.SLACK_API_KEY)
            authed_user = test_result['user']
            authed_user_id = test_result['user_id']

            if config.debug_mode:
                sc.api_call('chat.postMessage', channel='#bottesting', text='{} is now testing.'.format(authed_user))

            while True:
                events = sc.rtm_read()
                for event in events:
                    log_info(str(event))

                    if config.debug_mode:
                        # Whitelist #bottesting
                        if 'channel' not in event:
                            continue
                        if event['channel'] not in ['C494WSTUL', '#bottesting']:
                            continue
                        # Only respond to the developer when in debug mode
                        if 'user' not in event or event['user'] != authed_user_id:
                            continue

                    parse_command(event)
        except KeyboardInterrupt:
            if config.debug_mode:
                sc.api_call('chat.postMessage', channel='#bottesting', text='I\'m dead! (SIGINT)')

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


<commit_before>import re, json
from collections import OrderedDict
from hermes.Grammar import Grammar
from hermes.Morpheme import NonTerminal
from hermes.Morpheme import Terminal
from hermes.Morpheme import EmptyString
from hermes.Morpheme import EndOfStream
from hermes.Morpheme import Expression
from hermes.Grammar import Rule, MacroGeneratedRule
from hermes.Grammar import Production
from hermes.Grammar import AstSpecification
from hermes.Grammar import AstTranslation
from hermes.Macro import ExprListMacro, SeparatedListMacro, NonterminalListMacro
from hermes.Factory import Factory

class LL1MacroExpander:
  def __init__(self, registry):
    self.prefix = 'tmp'
    self.id = 0
    self.list_cache = {}
    self.registry = registry

  # TODO: this macro assumes that the first argument is a nonterminal and second is a terminal.  Make this more general case
  def list( self, nonterminal, separator ):
    rules = []

    key = tuple([str(nonterminal).upper(), str(separator).upper()])
    if key in self.list_cache:
      return (self.list_cache[key][0].nonterminal, self.list_cache[key])

    nt0 = self.registry.addNonTerminal( self.makeTmpNonTerminal() )

    if not separator:
      # CLASS_STATEMENTS := CLASS_STATEMENT + CLASS_STATEMENTS
      rules.append( self.registry.addMacroGeneratedRule( nt0, Production( [nonterminal, nt0] )) )
      rules.append( self.registry.addMacroGeneratedRule( nt0, Production( [self.registry.addEmptyString()] ) ) )

    else:
      # EXPR_LIST := EXPR + EXPR_LIST_SUB
      # EXPR_LIST_SUB := 'COMMA' + EXPR + EXPR_LIST_SUB
      nt1 = self.registry.addNonTerminal( self.makeTmpNonTerminal() )
      rules.append( self.registry.addMacroGeneratedRule( nt0, Production( [nonterminal, nt1] )) )
      rules.append( self.registry.addMacroGeneratedRule( nt0, Production( [self.registry.addEmptyString()] )) )
      rules.append( self.registry.addMacroGeneratedRule( nt1, Production( [separator, nonterminal, nt1] )) )
      rules.append( self.registry.addMacroGeneratedRule( nt1, Production( [self.registry.addEmptyString()] ) ) )

    self.list_cache[key] = rules
    return (rules[0].nonterminal, rules)

  def makeTmpNonTerminal(self):
    nt = self.prefix + str(self.id)
    self.id += 1
    return nt

class GrammarFileParser:
  def __init__(self):
    self.replacements = OrderedDict([
        ("'|'", "'__Z_PIPE__'"),
        ("'+'", "'__Z_PLUS__'"),
        ("'->'", "'__Z_ARROW__'"),
        (' ', ''),
        ("\t", ''),
        ("\n", '')
      ])

  def parse( self, fp, start=None ):
    contents = json.load(fp)
    fp.close()
    self.factory = Factory()
    self.ll1MacroExpander = LL1MacroExpander(self.factory)

    if 'll1' in contents and 'rules' in contents['ll1']:
      for rule in contents['ll1']['rules']:
        self.parseRule(rule, self.factory.addRule)

    if 'expr' in contents:
      if 'rules' in contents['expr']:
        for rule in contents['expr']['rules']:
          self.parseRule(rule, self.factory.addExpressionRule)
      if 'binding_power' in contents['expr']:
        for binding_power in contents['expr']['binding_power']:
          for token in binding_power['tokens']:
            terminal = self.factory.addTerminal( token.replace("'", "") )
            self.factory.addOperatorPrecedence( terminal, binding_power['associativity'].lower() )
    if start:
      start_nt = self.factory.nonterminals[start.lower()]
    elif 'll1' in contents and 'start' in contents['ll1']:
      start_nt = self.factory.nonterminals[contents['ll1']['start']]
    return self.factory.buildGrammar( start_nt )

  def parseRule( self, string, addFunc ):
    for original, replacement in self.replacements.items():
      string = string.replace(original, replacement)
    (nonterminal, productions) = string.split(':=', 1)
    nonterminal = self.factory.addNonTerminal(nonterminal)
    for production in productions.split('|'):
      (parsetree, ast) = self.pad(2, production.split('->'))
      morphemes = parsetree.replace("'__Z_PIPE__'", "'|'").split('+')
      morphemes = list(map(self.strToMorpheme, morphemes))
      ast = self.strToAst(ast)
      addFunc( nonterminal, Production(morphemes), self.getRoot(morphemes), ast )

  def getRoot( self, morphemes ):
    for idx, morpheme in enumerate(morphemes):
      try:
        if morpheme.root:
          return idx
      except:
        pass
    return 0

  def strToAst(self, ast):
    if not ast:
      return None
    if '(' in ast:
      (node, values) = ast.replace(')', '').split('(')
      parameters = {}
      for param in values.split(','):
        (name, value) = param.split('=')
        parameters[name] = int(value.replace('$', ''))
      return AstSpecification( node, parameters )
    else:
      return AstTranslation( int(ast.replace('$', '')) )

  def strToMorpheme(self, string):
    if string[0] == 'ε':
      return self.factory.ε

    if string[:4].lower() == 'list':
      (nonterminal, separator) = self.pad(2, string[5:-1].split(','))

      if separator:
        separator = self.factory.addTerminal(separator.replace("'", ''))
      else:
        separator = None

      if nonterminal:
        nonterminal = self.factory.addNonTerminal(nonterminal)
      else:
        raise Exception('Nonterminal needs to be specified as first argument in \'list\' macro')

      (start, rules) = self.ll1MacroExpander.list( nonterminal, separator )
      context = 'expr' if str(nonterminal).lower() == 'expr' else 'll1'
      return self.factory.addListMacro( nonterminal, separator, start, rules, context )

    elif string[0] == "'" or (string[0] == '^' and string[1] == "'"): # Terminal
      return self.factory.addTerminal( string.replace("'", "").replace('^', ''), string[0] == '^' )

    else: # Nonterminal
      return self.factory.addNonTerminal( string, string[0] == '^' )

  def pad( self, n, l ):
    t = int(n) - len(l)
    for x in range(t):
      l.append(None)
    return l

<commit_msg>[issue-1] Allowing start symbol to be case-insensitive<commit_after>import re, json
from collections import OrderedDict
from hermes.Grammar import Grammar
from hermes.Morpheme import NonTerminal
from hermes.Morpheme import Terminal
from hermes.Morpheme import EmptyString
from hermes.Morpheme import EndOfStream
from hermes.Morpheme import Expression
from hermes.Grammar import Rule, MacroGeneratedRule
from hermes.Grammar import Production
from hermes.Grammar import AstSpecification
from hermes.Grammar import AstTranslation
from hermes.Macro import ExprListMacro, SeparatedListMacro, NonterminalListMacro
from hermes.Factory import Factory

class LL1MacroExpander:
  def __init__(self, registry):
    self.prefix = 'tmp'
    self.id = 0
    self.list_cache = {}
    self.registry = registry

  # TODO: this macro assumes that the first argument is a nonterminal and second is a terminal.  Make this more general case
  def list( self, nonterminal, separator ):
    rules = []

    key = tuple([str(nonterminal).upper(), str(separator).upper()])
    if key in self.list_cache:
      return (self.list_cache[key][0].nonterminal, self.list_cache[key])

    nt0 = self.registry.addNonTerminal( self.makeTmpNonTerminal() )

    if not separator:
      # CLASS_STATEMENTS := CLASS_STATEMENT + CLASS_STATEMENTS
      rules.append( self.registry.addMacroGeneratedRule( nt0, Production( [nonterminal, nt0] )) )
      rules.append( self.registry.addMacroGeneratedRule( nt0, Production( [self.registry.addEmptyString()] ) ) )

    else:
      # EXPR_LIST := EXPR + EXPR_LIST_SUB
      # EXPR_LIST_SUB := 'COMMA' + EXPR + EXPR_LIST_SUB
      nt1 = self.registry.addNonTerminal( self.makeTmpNonTerminal() )
      rules.append( self.registry.addMacroGeneratedRule( nt0, Production( [nonterminal, nt1] )) )
      rules.append( self.registry.addMacroGeneratedRule( nt0, Production( [self.registry.addEmptyString()] )) )
      rules.append( self.registry.addMacroGeneratedRule( nt1, Production( [separator, nonterminal, nt1] )) )
      rules.append( self.registry.addMacroGeneratedRule( nt1, Production( [self.registry.addEmptyString()] ) ) )

    self.list_cache[key] = rules
    return (rules[0].nonterminal, rules)

  def makeTmpNonTerminal(self):
    nt = self.prefix + str(self.id)
    self.id += 1
    return nt

class GrammarFileParser:
  def __init__(self):
    self.replacements = OrderedDict([
        ("'|'", "'__Z_PIPE__'"),
        ("'+'", "'__Z_PLUS__'"),
        ("'->'", "'__Z_ARROW__'"),
        (' ', ''),
        ("\t", ''),
        ("\n", '')
      ])

  def parse( self, fp, start=None ):
    contents = json.load(fp)
    fp.close()
    self.factory = Factory()
    self.ll1MacroExpander = LL1MacroExpander(self.factory)

    if 'll1' in contents and 'rules' in contents['ll1']:
      for rule in contents['ll1']['rules']:
        self.parseRule(rule, self.factory.addRule)

    if 'expr' in contents:
      if 'rules' in contents['expr']:
        for rule in contents['expr']['rules']:
          self.parseRule(rule, self.factory.addExpressionRule)
      if 'binding_power' in contents['expr']:
        for binding_power in contents['expr']['binding_power']:
          for token in binding_power['tokens']:
            terminal = self.factory.addTerminal( token.replace("'", "") )
            self.factory.addOperatorPrecedence( terminal, binding_power['associativity'].lower() )
    if start:
      start_nt = self.factory.nonterminals[start.lower()]
    elif 'll1' in contents and 'start' in contents['ll1']:
      start_nt = self.factory.nonterminals[contents['ll1']['start'].lower()]
    return self.factory.buildGrammar( start_nt )

  def parseRule( self, string, addFunc ):
    for original, replacement in self.replacements.items():
      string = string.replace(original, replacement)
    (nonterminal, productions) = string.split(':=', 1)
    nonterminal = self.factory.addNonTerminal(nonterminal)
    for production in productions.split('|'):
      (parsetree, ast) = self.pad(2, production.split('->'))
      morphemes = parsetree.replace("'__Z_PIPE__'", "'|'").split('+')
      morphemes = list(map(self.strToMorpheme, morphemes))
      ast = self.strToAst(ast)
      addFunc( nonterminal, Production(morphemes), self.getRoot(morphemes), ast )

  def getRoot( self, morphemes ):
    for idx, morpheme in enumerate(morphemes):
      try:
        if morpheme.root:
          return idx
      except:
        pass
    return 0

  def strToAst(self, ast):
    if not ast:
      return None
    if '(' in ast:
      (node, values) = ast.replace(')', '').split('(')
      parameters = {}
      for param in values.split(','):
        (name, value) = param.split('=')
        parameters[name] = int(value.replace('$', ''))
      return AstSpecification( node, parameters )
    else:
      return AstTranslation( int(ast.replace('$', '')) )

  def strToMorpheme(self, string):
    if string[0] == 'ε':
      return self.factory.ε

    if string[:4].lower() == 'list':
      (nonterminal, separator) = self.pad(2, string[5:-1].split(','))

      if separator:
        separator = self.factory.addTerminal(separator.replace("'", ''))
      else:
        separator = None

      if nonterminal:
        nonterminal = self.factory.addNonTerminal(nonterminal)
      else:
        raise Exception('Nonterminal needs to be specified as first argument in \'list\' macro')

      (start, rules) = self.ll1MacroExpander.list( nonterminal, separator )
      context = 'expr' if str(nonterminal).lower() == 'expr' else 'll1'
      return self.factory.addListMacro( nonterminal, separator, start, rules, context )

    elif string[0] == "'" or (string[0] == '^' and string[1] == "'"): # Terminal
      return self.factory.addTerminal( string.replace("'", "").replace('^', ''), string[0] == '^' )

    else: # Nonterminal
      return self.factory.addNonTerminal( string, string[0] == '^' )

  def pad( self, n, l ):
    t = int(n) - len(l)
    for x in range(t):
      l.append(None)
    return l

<|endoftext|>


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

import flask, iptc, json

app = flask.Flask(__name__)

# do table names in uppercase, this is what we'll query iptc with
TABLES = ['FILTER']
FILTER_CHAINS = ['INPUT', 'OUTPUT', 'FORWARD']
TABLE_CHAINS = { 'FILTER' : FILTER_CHAINS }
TARGETS = ['ACCEPT', 'DROP']

class Rule:

    def __init__(self, num=None, in_interface=None, out_interface=None, src=None, dst=None, protocol=None, target=None):
        self.num = num
        self.in_interface = in_interface
        self.out_interface = out_interface
        self.src = src
        self.dst = dst
        self.protocol = protocol
        self.target = target

    @staticmethod
    def build_from_iptables(rule, rule_num):
        rule_dict = {}
        rule_dict['num'] = rule_num
        rule_dict['target'] = rule.target.name
        # handle logic for table/chain-specific stuff (can do this better
        # example: in_interface is only valid for INPUT chain in FILTER table
        if rule.in_interface:
            rule_dict['in_interface'] = rule.in_interface
        if rule.out_interface:
            rule_dict['out_interface'] = rule.out_interface
        rule_dict['protocol'] = rule.protocol
        rule_dict['src'] = rule.src
        rule_dict['dst'] = rule.dst
        # should return a Rule class
        return Rule(**rule_dict)

    def write_to_iptables(self, table_name, chain_name):
        table = iptc.Table(table_name.lower())
        table.refresh()
        chains_by_name = {chain.name : chain for chain in table.chains}
        chain = chains_by_name[chain_name.upper()]
        rule = iptc.Rule()
        if self.in_interface:
            rule.in_interface = self.in_interface
        if self.out_interface:
            rule.out_interface = self.out_interface
        if self.src:
            rule.src = self.src
        if self.dst:
            rule.dst = self.dst
        if self.protocol:
            rule.protocol = self.protocol
        else:
            rule.protocol = 'ip'
        rule.target = iptc.Target(rule, self.target)
        chain.insert_rule(rule)

def parse_iptc_rule_to_dict(rule, rule_num):
    rule_dict = {}
    rule_dict['num'] = rule_num
    rule_dict['target'] = rule.target.name
    # handle logic for table/chain-specific stuff (can do this better
    # example: in_interface is only valid for INPUT chain in FILTER table
    if rule.in_interface:
        rule_dict['in_interface'] = rule.in_interface
    if rule.out_interface:
        rule_dict['out_interface'] = rule.out_interface
    rule_dict['protocol'] = rule.protocol
    rule_dict['src'] = rule.src
    rule_dict['dst'] = rule.dst
    return rule_dict

def get_iptables_rules_from_chain(table_name, chain_name):
    table = iptc.Table(table_name.lower())
    table.refresh()
    chains_by_name = {chain.name : chain for chain in table.chains}
    chain = chains_by_name[chain_name.upper()]
    rules = [parse_iptc_rule_to_dict(rule, rule_num) for rule_num, rule in enumerate(chain.rules)]
    return rules

def add_iptables_rule_to_chain(table_name, chain_name, json_input):
    # it would be better to have a class for rules that does sanity checking...
    table = iptc.Table(table_name.lower())
    table.refresh()
    chains_by_name = {chain.name : chain for chain in table.chains}
    chain = chains_by_name[chain_name.upper()]
    rule = iptc.Rule()
    if 'in_interface' in json_input:
        rule.in_interface = json_input['in_interface']
    if 'out_interface' in json_input:
        rule.out_interface = json_input['out_interface']
    if 'src' in json_input:
        rule.src = json_input['src']
    if 'dst' in json_input:
        rule.src = json_input['dst']
    if 'protocol' in json_input:
        rule.protocol = json_input['protocol']
    else:
        rule.protocol = 'ip'
    rule.target = iptc.Target(rule, json_input['target'])
    chain.insert_rule(rule)

class API10:
    PREFIX = '/api/v1.0'
    TABLE_LIST_URL = '/table'
    TABLE_URL = '/table/%(table_name)s/chain'
    CHAIN_URL = '/table/%(table_name)s/chain/%(chain_name)s/rule'
    RULE_URL = '/table/%(table_name)s/chain/%(chain_name)s/rule/%(rule_num)d'

    @staticmethod
    def get_table_list_url():
        return API10.PREFIX + \
               API10.TABLE_LIST_URL

    @staticmethod
    def get_table_url(table_name):
        return API10.PREFIX + \
               API10.TABLE_URL % {'table_name' : table_name}

    @staticmethod
    def get_chain_url(table_name, chain_name):
        return API10.PREFIX + \
               API10.CHAIN_URL % {'table_name' : table_name,
                                  'chain_name' : chain_name,
                                  }

    @staticmethod
    def get_rule_url(table_name, chain_name, rule_num):
        return API10.PREFIX + \
               API10.RULE_URL % {'table_name' : table_name,
                                  'chain_name' : chain_name,
                                  'rule_num'   : rule_num,
                                  }

class RestfulObject(object):

    def __init__(self):
        self.response = {}

    def to_rest_response(self):
        return flask.jsonify(self.response)

class IptablesTableList10(RestfulObject):

    def __init__(self):
        super(IptablesTableList10, self).__init__()
        self.populate_response()

    def populate_response(self):
        self.response['url'] = API10.get_table_list_url()
        tables = []
        for table_name_uppercase in TABLES:
            table_name = table_name_uppercase.lower()
            table_url = API10.get_table_url(table_name)
            table_entry = { 'table_name' : table_name,
                            'url' : table_url,
                          }
            tables.append(table_entry)
        self.response['tables'] = tables

class IptablesTable10(RestfulObject):

    def __init__(self, table_name):
        super(IptablesTable10, self).__init__()
        self.populate_response(table_name)

    def populate_response(self, table_name):
        self.response['url'] = API10.get_table_url(table_name)
        chains = []
        for chain_name_uppercase in TABLE_CHAINS[table_name.upper()]:
            chain_name = chain_name_uppercase.lower()
            chain_url = API10.get_chain_url(table_name, chain_name)
            chain_entry = { 'table_name' : table_name,
                            'chain_name' : chain_name,
                            'url' : chain_url,
                          }
            chains.append(chain_entry)
        self.response['chains'] = chains

class IptablesChain10(RestfulObject):
    pass

@app.route('/api/v1.0/table', methods=['GET'])
def show_tables():
    #return flask.jsonify({'tables' : TABLES})
    table_list = IptablesTableList10()
    return table_list.to_rest_response()

@app.route('/api/v1.0/table/<table_name>/chain', methods=['GET'])
def show_chains(table_name):
    if table_name.upper() not in TABLES:
        flask.abort(400)
    chain_list = IptablesTable10(table_name)
    return chain_list.to_rest_response()

@app.route('/api/v1.0/table/<table_name>/chain/<chain_name>/rule', methods=['GET'])
def show_rules(table_name, chain_name):
    if table_name.upper() not in TABLES:
        flask.abort(400)
    if chain_name.upper() not in TABLE_CHAINS[table_name.upper()]:
        flask.abort(400)
    # get the chain they want
    rules = get_iptables_rules_from_chain(
                table_name, chain_name)
    return flask.jsonify(
                        {
                        'table' : {
                            'name' : table_name,
                            'chain' : {
                                'name' : chain_name,
                                'rules' : rules,
                                }
                            }
                        })

@app.route('/api/v1.0/table/<table_name>/chain/<chain_name>/rule/<int:rule_num>', methods=['GET'])
def show_rule_by_num(table_name, chain_name, rule_num):
    if table_name.upper() not in TABLES:
        flask.abort(400)
    if chain_name.upper() not in TABLE_CHAINS[table_name.upper()]:
        flask.abort(400)
    # get the chain they want
    rules = get_iptables_rules_from_chain(
                table_name, chain_name)
    if rule_num < 0 or rule_num > (len(rules)-1):
        flask.abort(400)
    rule = rules[rule_num]
    if rule['num'] != rule_num:
        flask.abort(400)
    return flask.jsonify(
                        {
                        'table' : {
                            'name' : table_name,
                            'chain' : {
                                'name' : chain_name,
                                'rule' : rule,
                                }
                            }
                        })

@app.route('/api/v1.0/table/<table_name>/chain/<chain_name>/rule', methods=['POST'])
def add_rule(table_name, chain_name):
    if table_name.upper() not in TABLES:
        flask.abort(400)
    if chain_name.upper() not in TABLE_CHAINS[table_name.upper()]:
        flask.abort(400)
    # get the chain they want
    if not flask.request.json:
        flask.abort(400)

    add_iptables_rule_to_chain(table_name, chain_name, flask.request.json)
    return flask.jsonify(
                        {
                        'table' : {
                            'name' : table_name,
                            'chain' : {
                                'name' : chain_name,
                                'rule' : flask.request.json,
                                }
                            }
                        })

def main():
    app.debug = True
    app.run(host='0.0.0.0', port=8080)

if __name__ == '__main__':
    main()
<commit_msg>new classes used for enumerating rules<commit_after>#!/usr/bin/python
# The MIT License (MIT)
#
# Copyright (C) 2015, Sam Russell <sam.h.russell@gmail.com>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

import flask, iptc, json

app = flask.Flask(__name__)

# do table names in uppercase, this is what we'll query iptc with
TABLES = ['FILTER']
FILTER_CHAINS = ['INPUT', 'OUTPUT', 'FORWARD']
TABLE_CHAINS = { 'FILTER' : FILTER_CHAINS }
TARGETS = ['ACCEPT', 'DROP']

class Rule:

    def __init__(self, num=None, in_interface=None, out_interface=None, src=None, dst=None, protocol=None, target=None):
        self.num = num
        self.in_interface = in_interface
        self.out_interface = out_interface
        self.src = src
        self.dst = dst
        self.protocol = protocol
        self.target = target

    @staticmethod
    def build_from_iptables(rule, rule_num):
        rule_dict = {}
        rule_dict['rule_num'] = rule_num
        rule_dict['target'] = rule.target.name
        # handle logic for table/chain-specific stuff (can do this better
        # example: in_interface is only valid for INPUT chain in FILTER table
        if rule.in_interface:
            rule_dict['in_interface'] = rule.in_interface
        if rule.out_interface:
            rule_dict['out_interface'] = rule.out_interface
        rule_dict['protocol'] = rule.protocol
        rule_dict['src'] = rule.src
        rule_dict['dst'] = rule.dst
        # should return a Rule class
        return Rule(**rule_dict)

    def write_to_iptables(self, table_name, chain_name):
        table = iptc.Table(table_name.lower())
        table.refresh()
        chains_by_name = {chain.name : chain for chain in table.chains}
        chain = chains_by_name[chain_name.upper()]
        rule = iptc.Rule()
        if self.in_interface:
            rule.in_interface = self.in_interface
        if self.out_interface:
            rule.out_interface = self.out_interface
        if self.src:
            rule.src = self.src
        if self.dst:
            rule.dst = self.dst
        if self.protocol:
            rule.protocol = self.protocol
        else:
            rule.protocol = 'ip'
        rule.target = iptc.Target(rule, self.target)
        chain.insert_rule(rule)

def parse_iptc_rule_to_dict(rule, rule_num):
    rule_dict = {}
    rule_dict['rule_num'] = rule_num
    rule_dict['target'] = rule.target.name
    # handle logic for table/chain-specific stuff (can do this better
    # example: in_interface is only valid for INPUT chain in FILTER table
    if rule.in_interface:
        rule_dict['in_interface'] = rule.in_interface
    if rule.out_interface:
        rule_dict['out_interface'] = rule.out_interface
    rule_dict['protocol'] = rule.protocol
    rule_dict['src'] = rule.src
    rule_dict['dst'] = rule.dst
    return rule_dict

def get_iptables_rules_from_chain_by_numbers(table_name, chain_name):
    """
    Gets the iptables rules from a chain, with line numbers

    :param table_name: Name of the iptables table
    :param chain_name: Name of the iptables chain within table_name
    :returns: A dict of rule_num : rule
    """
    table = iptc.Table(table_name.lower())
    table.refresh()
    chains_by_name = {chain.name : chain for chain in table.chains}
    chain = chains_by_name[chain_name.upper()]
    rules_by_numbers = {rule_num : parse_iptc_rule_to_dict(rule, rule_num) for rule_num, rule in enumerate(chain.rules, start=1)}
    return rules_by_numbers

def get_iptables_rules_from_chain(table_name, chain_name):
    """
    Gets the iptables rules from a chain

    :param table_name: Name of the iptables table
    :param chain_name: Name of the iptables chain within table_name
    :returns: A list of rules
    """
    table = iptc.Table(table_name.lower())
    table.refresh()
    chains_by_name = {chain.name : chain for chain in table.chains}
    chain = chains_by_name[chain_name.upper()]
    rules = [parse_iptc_rule_to_dict(rule, rule_num) for rule_num, rule in enumerate(chain.rules, start=1)]
    return rules

def add_iptables_rule_to_chain(table_name, chain_name, json_input):
    # it would be better to have a class for rules that does sanity checking...
    table = iptc.Table(table_name.lower())
    table.refresh()
    chains_by_name = {chain.name : chain for chain in table.chains}
    chain = chains_by_name[chain_name.upper()]
    rule = iptc.Rule()
    if 'in_interface' in json_input:
        rule.in_interface = json_input['in_interface']
    if 'out_interface' in json_input:
        rule.out_interface = json_input['out_interface']
    if 'src' in json_input:
        rule.src = json_input['src']
    if 'dst' in json_input:
        rule.src = json_input['dst']
    if 'protocol' in json_input:
        rule.protocol = json_input['protocol']
    else:
        rule.protocol = 'ip'
    rule.target = iptc.Target(rule, json_input['target'])
    chain.insert_rule(rule)

class API10:
    PREFIX = '/api/v1.0'
    TABLE_LIST_URL = '/table'
    TABLE_URL = '/table/%(table_name)s/chain'
    CHAIN_URL = '/table/%(table_name)s/chain/%(chain_name)s/rule'
    RULE_URL = '/table/%(table_name)s/chain/%(chain_name)s/rule/%(rule_num)d'

    @staticmethod
    def get_table_list_url():
        return API10.PREFIX + \
               API10.TABLE_LIST_URL

    @staticmethod
    def get_table_url(table_name):
        return API10.PREFIX + \
               API10.TABLE_URL % {'table_name' : table_name}

    @staticmethod
    def get_chain_url(table_name, chain_name):
        return API10.PREFIX + \
               API10.CHAIN_URL % {'table_name' : table_name,
                                  'chain_name' : chain_name,
                                  }

    @staticmethod
    def get_rule_url(table_name, chain_name, rule_num):
        return API10.PREFIX + \
               API10.RULE_URL % {'table_name' : table_name,
                                  'chain_name' : chain_name,
                                  'rule_num'   : rule_num,
                                  }

class RestfulObject(object):

    def __init__(self):
        self.response = {}

    def to_rest_response(self):
        return flask.jsonify(self.response)

class IptablesTableList10(RestfulObject):

    def __init__(self):
        super(IptablesTableList10, self).__init__()
        self.populate_response()

    def populate_response(self):
        '''
        Populates self.response for REST reply
        '''
        self.response['url'] = API10.get_table_list_url()
        tables = []
        for table_name_uppercase in TABLES:
            table_name = table_name_uppercase.lower()
            table_url = API10.get_table_url(table_name)
            table_entry = { 'table_name' : table_name,
                            'url' : table_url,
                          }
            tables.append(table_entry)
        self.response['tables'] = tables

class IptablesTable10(RestfulObject):

    def __init__(self, table_name):
        super(IptablesTable10, self).__init__()
        self.populate_response(table_name)

    def populate_response(self, table_name):
        '''
        Populates self.response for REST reply
        '''
        self.response['url'] = API10.get_table_url(table_name)
        chains = []
        for chain_name_uppercase in TABLE_CHAINS[table_name.upper()]:
            chain_name = chain_name_uppercase.lower()
            chain_url = API10.get_chain_url(table_name, chain_name)
            chain_entry = { 'table_name' : table_name,
                            'chain_name' : chain_name,
                            'url' : chain_url,
                          }
            chains.append(chain_entry)
        self.response['chains'] = chains

class IptablesChain10(RestfulObject):

    def __init__(self, table_name, chain_name, rules):
        super(IptablesChain10, self).__init__()
        self.populate_response(table_name, chain_name, rules)

    def populate_response(self, table_name, chain_name, rules):
        '''
        Populates self.response for REST reply
        '''
        self.response['url'] = API10.get_chain_url(table_name, chain_name)
        rule_data = []
        for rule in rules:
            rule_num = rule['rule_num']
            url = API10.get_rule_url(table_name, chain_name, rule_num)
            rule_entry = { 'table_name' : table_name,
                           'chain_name' : chain_name,
                           'rule_num'   : rule_num,
                           'url'        : url,
                           'data'       : rule
                         }
            rule_data.append(rule_entry)
        self.response['rules'] = rule_data

@app.route('/api/v1.0/table', methods=['GET'])
def show_tables():
    #return flask.jsonify({'tables' : TABLES})
    table_list = IptablesTableList10()
    return table_list.to_rest_response()

@app.route('/api/v1.0/table/<table_name>/chain', methods=['GET'])
def show_chains(table_name):
    if table_name.upper() not in TABLES:
        flask.abort(400)
    chain_list = IptablesTable10(table_name)
    return chain_list.to_rest_response()

@app.route('/api/v1.0/table/<table_name>/chain/<chain_name>/rule', methods=['GET'])
def show_rules(table_name, chain_name):
    if table_name.upper() not in TABLES:
        flask.abort(400)
    if chain_name.upper() not in TABLE_CHAINS[table_name.upper()]:
        flask.abort(400)
    # get the chain they want
    rules = get_iptables_rules_from_chain(
                table_name, chain_name)
    rule_list = IptablesChain10(table_name, chain_name, rules)
    return rule_list.to_rest_response()
    #return flask.jsonify(
    #                    {
    #                    'table' : {
    #                        'name' : table_name,
    #                        'chain' : {
    #                            'name' : chain_name,
    #                            'rules' : rules,
    #                            }
    #                        }
    #                    })

@app.route('/api/v1.0/table/<table_name>/chain/<chain_name>/rule/<int:rule_num>', methods=['GET'])
def show_rule_by_num(table_name, chain_name, rule_num):
    if table_name.upper() not in TABLES:
        flask.abort(400)
    if chain_name.upper() not in TABLE_CHAINS[table_name.upper()]:
        flask.abort(400)
    # get the chain they want
    rules = get_iptables_rules_from_chain(
                table_name, chain_name)
    if rule_num < 0 or rule_num > (len(rules)-1):
        flask.abort(400)
    rule = rules[rule_num]
    if rule['rule_num'] != rule_num:
        flask.abort(400)
    return flask.jsonify(
                        {
                        'table' : {
                            'name' : table_name,
                            'chain' : {
                                'name' : chain_name,
                                'rule' : rule,
                                }
                            }
                        })

@app.route('/api/v1.0/table/<table_name>/chain/<chain_name>/rule', methods=['POST'])
def add_rule(table_name, chain_name):
    if table_name.upper() not in TABLES:
        flask.abort(400)
    if chain_name.upper() not in TABLE_CHAINS[table_name.upper()]:
        flask.abort(400)
    # get the chain they want
    if not flask.request.json:
        flask.abort(400)

    add_iptables_rule_to_chain(table_name, chain_name, flask.request.json)
    return flask.jsonify(
                        {
                        'table' : {
                            'name' : table_name,
                            'chain' : {
                                'name' : chain_name,
                                'rule' : flask.request.json,
                                }
                            }
                        })

def main():
    app.debug = True
    app.run(host='0.0.0.0', port=8080)

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


<commit_before># -*- coding: utf-8 -*-

from __future__ import unicode_literals

from django.db.models import Q
from django.core.exceptions import ValidationError

from cms.apphook_pool import apphook_pool
from cms.models import Page
from menus.base import Menu

class CMSAttachMenu(Menu):
    cms_enabled = True
    instance = None
    name = None

    def __init__(self, *args, **kwargs):
        super(CMSAttachMenu, self).__init__(*args, **kwargs)
        if self.cms_enabled and not self.name:
            raise ValidationError(
                "the menu %s is a CMSAttachMenu but has no name defined!" %
                self.__class__.__name__)

    @classmethod
    def get_apphooks(cls):
        """
        Returns a list of apphooks to which this CMSAttachMenu is attached.

        Calling this does NOT produce DB queries.
        """
        apps = []
        for key, _ in apphook_pool.get_apphooks():
            app = apphook_pool.get_apphook(key)
            if cls in app.menus:
                apps.append(app)
        return apps

    @classmethod
    def get_instances(cls):
        """
        Return a list (queryset, really) of all CMS Page objects (in this case)
        that are currently using this CMSAttachMenu either directly as a
        navigation_extender, or, as part of an apphook.

        Calling this DOES perform a DB query.
        """
        parent_apps = []
        for app in cls.get_apphooks():
            parent_apps.append(app.__class__.__name__)
        return Page.objects.drafts().filter(
            Q(application_urls__in=parent_apps)
            | Q(navigation_extenders=cls.__name__)
        )
<commit_msg>All pages must be considered<commit_after># -*- coding: utf-8 -*-

from __future__ import unicode_literals

from django.db.models import Q
from django.core.exceptions import ValidationError

from cms.apphook_pool import apphook_pool
from cms.models import Page
from menus.base import Menu

class CMSAttachMenu(Menu):
    cms_enabled = True
    instance = None
    name = None

    def __init__(self, *args, **kwargs):
        super(CMSAttachMenu, self).__init__(*args, **kwargs)
        if self.cms_enabled and not self.name:
            raise ValidationError(
                "the menu %s is a CMSAttachMenu but has no name defined!" %
                self.__class__.__name__)

    @classmethod
    def get_apphooks(cls):
        """
        Returns a list of apphooks to which this CMSAttachMenu is attached.

        Calling this does NOT produce DB queries.
        """
        apps = []
        for key, _ in apphook_pool.get_apphooks():
            app = apphook_pool.get_apphook(key)
            if cls in app.menus:
                apps.append(app)
        return apps

    @classmethod
    def get_instances(cls):
        """
        Return a list (queryset, really) of all CMS Page objects (in this case)
        that are currently using this CMSAttachMenu either directly as a
        navigation_extender, or, as part of an apphook.

        Calling this DOES perform a DB query.
        """
        parent_apps = []
        for app in cls.get_apphooks():
            parent_apps.append(app.__class__.__name__)
        return Page.objects.filter(
            Q(application_urls__in=parent_apps)
            | Q(navigation_extenders=cls.__name__)
        )
<|endoftext|>