import datetime
import os
import shutil
import tempfile
from unittest import mock

import pytest
import pytz

from testifycompat import assert_equal
from testifycompat import assert_in
from testifycompat import run
from testifycompat import setup
from testifycompat import teardown
from testifycompat import TestCase
from tests.assertions import assert_raises
from tron.config import config_parse
from tron.config import config_utils
from tron.config import ConfigError
from tron.config import schedule_parse
from tron.config import schema
from tron.config.config_parse import build_format_string_validator
from tron.config.config_parse import CLEANUP_ACTION_NAME
from tron.config.config_parse import valid_cleanup_action_name
from tron.config.config_parse import valid_config
from tron.config.config_parse import valid_job
from tron.config.config_parse import valid_node_pool
from tron.config.config_parse import valid_output_stream_dir
from tron.config.config_parse import validate_fragment
from tron.config.config_utils import NullConfigContext
from tron.config.schedule_parse import ConfigDailyScheduler
from tron.config.schema import ConfigNodeAffinity
from tron.config.schema import MASTER_NAMESPACE

BASE_CONFIG = dict(
    ssh_options=dict(agent=False, identities=["tests/test_id_rsa"]),
    time_zone="EST",
    output_stream_dir="/tmp",
    nodes=[dict(name="node0", hostname="node0"), dict(name="node1", hostname="node1"),],
    node_pools=[dict(name="NodePool", nodes=["node0", "node1"])],
)

def make_ssh_options():
    return schema.ConfigSSHOptions(
        agent=False,
        identities=("tests/test_id_rsa",),
        known_hosts_file=None,
        connect_timeout=30,
        idle_connection_timeout=3600,
        jitter_min_load=4,
        jitter_max_delay=20,
        jitter_load_factor=1,
    )

def make_mock_schedule():
    return ConfigDailyScheduler(days=set(), hour=0, minute=0, second=0, original="00:00:00 ", jitter=None,)

def make_command_context():
    return {
        "python": "/usr/bin/python",
        "batch_dir": "/tron/batch/test/foo",
    }

def make_nodes():
    return {
        "node0": schema.ConfigNode(name="node0", username="foo", hostname="node0", port=22,),
        "node1": schema.ConfigNode(name="node1", username="foo", hostname="node1", port=22,),
    }

def make_node_pools():
    return {
        "NodePool": schema.ConfigNodePool(nodes=("node0", "node1"), name="NodePool",),
    }

def make_mesos_options():
    return schema.ConfigMesos(
        master_address=None,
        master_port=5050,
        secret_file=None,
        role="*",
        principal="tron",
        enabled=False,
        default_volumes=(),
        dockercfg_location=None,
        offer_timeout=300,
    )

def make_k8s_options():
    return schema.ConfigKubernetes(enabled=False, default_volumes=())

def make_action(**kwargs):
    kwargs.setdefault("name", "action"),
    kwargs.setdefault("command", "command")
    kwargs.setdefault("executor", schema.ExecutorTypes.ssh.value)
    kwargs.setdefault("requires", ())
    kwargs.setdefault("expected_runtime", datetime.timedelta(1))
    return schema.ConfigAction(**kwargs)

def make_cleanup_action(**kwargs):
    kwargs.setdefault("name", "cleanup"),
    kwargs.setdefault("command", "command")
    kwargs.setdefault("executor", schema.ExecutorTypes.ssh.value)
    kwargs.setdefault("expected_runtime", datetime.timedelta(1))
    return schema.ConfigCleanupAction(**kwargs)

def make_job(**kwargs):
    kwargs.setdefault("namespace", "MASTER")
    kwargs.setdefault("name", f"{kwargs['namespace']}.job_name")
    kwargs.setdefault("node", "node0")
    kwargs.setdefault("enabled", True)
    kwargs.setdefault("monitoring", {})
    kwargs.setdefault(
        "schedule",
        schedule_parse.ConfigDailyScheduler(
            days=set(), hour=16, minute=30, second=0, original="16:30:00 ", jitter=None,
        ),
    )
    kwargs.setdefault("actions", {"action": make_action()})
    kwargs.setdefault("queueing", True)
    kwargs.setdefault("run_limit", 50)
    kwargs.setdefault("all_nodes", False)
    kwargs.setdefault("cleanup_action", make_cleanup_action())
    kwargs.setdefault("max_runtime")
    kwargs.setdefault("allow_overlap", False)
    kwargs.setdefault("time_zone", None)
    kwargs.setdefault("expected_runtime", datetime.timedelta(0, 3600))
    kwargs.setdefault("use_k8s", False)
    return schema.ConfigJob(**kwargs)

def make_master_jobs():
    return {
        "MASTER.test_job0": make_job(
            name="MASTER.test_job0", schedule=make_mock_schedule(), expected_runtime=datetime.timedelta(1),
        ),
        "MASTER.test_job1": make_job(
            name="MASTER.test_job1",
            schedule=schedule_parse.ConfigDailyScheduler(
                days={1, 3, 5}, hour=0, minute=30, second=0, original="00:30:00 MWF", jitter=None,
            ),
            actions={
                "action": make_action(requires=("action1",), expected_runtime=datetime.timedelta(0, 7200),),
                "action1": make_action(name="action1", expected_runtime=datetime.timedelta(0, 7200),),
            },
            time_zone=pytz.timezone("Pacific/Auckland"),
            expected_runtime=datetime.timedelta(1),
            cleanup_action=None,
            allow_overlap=True,
        ),
        "MASTER.test_job2": make_job(
            name="MASTER.test_job2",
            node="node1",
            actions={"action2_0": make_action(name="action2_0", command="test_command2.0",),},
            time_zone=pytz.timezone("Pacific/Auckland"),
            expected_runtime=datetime.timedelta(1),
            cleanup_action=None,
        ),
        "MASTER.test_job_actions_dict": make_job(
            name="MASTER.test_job_actions_dict",
            node="node1",
            schedule=make_mock_schedule(),
            actions={
                "action": make_action(),
                "action1": make_action(name="action1"),
                "action2": make_action(name="action2", requires=("action", "action1"), node="node0",),
            },
            cleanup_action=None,
            expected_runtime=datetime.timedelta(1),
        ),
        "MASTER.test_job4": make_job(
            name="MASTER.test_job4",
            node="NodePool",
            schedule=schedule_parse.ConfigDailyScheduler(
                original="00:00:00 ", hour=0, minute=0, second=0, days=set(), jitter=None,
            ),
            all_nodes=True,
            enabled=False,
            cleanup_action=None,
            expected_runtime=datetime.timedelta(1),
        ),
        "MASTER.test_job_mesos": make_job(
            name="MASTER.test_job_mesos",
            node="NodePool",
            schedule=schedule_parse.ConfigDailyScheduler(
                original="00:00:00 ", hour=0, minute=0, second=0, days=set(), jitter=None,
            ),
            actions={
                "action_mesos": make_action(
                    name="action_mesos",
                    command="test_command_mesos",
                    executor=schema.ExecutorTypes.mesos.value,
                    cpus=0.1,
                    mem=100,
                    disk=600,
                    docker_image="container:latest",
                ),
            },
            cleanup_action=None,
            expected_runtime=datetime.timedelta(1),
        ),
        "MASTER.test_job_k8s": make_job(
            name="MASTER.test_job_k8s",
            node="NodePool",
            schedule=schedule_parse.ConfigDailyScheduler(
                original="00:00:00 ", hour=0, minute=0, second=0, days=set(), jitter=None,
            ),
            actions={
                "action_k8s": make_action(
                    name="action_k8s",
                    command="test_command_k8s",
                    executor=schema.ExecutorTypes.kubernetes.value,
                    cpus=0.1,
                    mem=100,
                    disk=600,
                    cap_add=["KILL"],
                    cap_drop=["CHOWN", "KILL"],
                    docker_image="container:latest",
                    secret_env=dict(
                        TEST_SECRET=schema.ConfigSecretSource(secret_name="tron-secret-test-secret--1", key="secret_1")
                    ),
                    secret_volumes=(
                        schema.ConfigSecretVolume(
                            secret_volume_name="abc",
                            secret_name="secret1",
                            container_path="/b/c",
                            default_mode="0644",
                            items=(schema.ConfigSecretVolumeItem(key="secret1", path="abcd", mode="777"),),
                        ),
                    ),
                    node_selectors={"yelp.com/pool": "default"},
                    node_affinities=(ConfigNodeAffinity(key="instance_type", operator="In", value=("a1.1xlarge",),),),
                ),
            },
            cleanup_action=None,
            expected_runtime=datetime.timedelta(1),
        ),
    }

def make_tron_config(
    action_runner=None,
    output_stream_dir="/tmp",
    command_context=None,
    ssh_options=None,
    time_zone=pytz.timezone("EST"),
    state_persistence=config_parse.DEFAULT_STATE_PERSISTENCE,
    nodes=None,
    node_pools=None,
    jobs=None,
    mesos_options=None,
    k8s_options=None,
):
    return schema.TronConfig(
        action_runner=action_runner or {},
        output_stream_dir=output_stream_dir,
        command_context=command_context or dict(batch_dir="/tron/batch/test/foo", python="/usr/bin/python"),
        ssh_options=ssh_options or make_ssh_options(),
        time_zone=time_zone,
        state_persistence=state_persistence,
        nodes=nodes or make_nodes(),
        node_pools=node_pools or make_node_pools(),
        jobs=jobs or make_master_jobs(),
        mesos_options=mesos_options or make_mesos_options(),
        k8s_options=k8s_options or make_k8s_options(),
    )

def make_named_tron_config(jobs=None):
    return schema.NamedTronConfig(jobs=jobs or make_master_jobs())

class ConfigTestCase(TestCase):
    JOBS_CONFIG = dict(
        jobs=[
            dict(
                name="test_job0",
                node="node0",
                schedule="daily 00:00:00",
                actions=[dict(name="action", command="command")],
                cleanup_action=dict(command="command"),
            ),
            dict(
                name="test_job1",
                node="node0",
                schedule="daily 00:30:00 MWF",
                allow_overlap=True,
                time_zone="Pacific/Auckland",
                actions=[
                    dict(name="action", command="command", requires=["action1"], expected_runtime="2h",),
                    dict(name="action1", command="command", expected_runtime="2h",),
                ],
            ),
            dict(
                name="test_job2",
                node="node1",
                schedule="daily 16:30:00",
                expected_runtime="1d",
                time_zone="Pacific/Auckland",
                actions=[dict(name="action2_0", command="test_command2.0")],
            ),
            dict(
                name="test_job_actions_dict",
                node="node1",
                schedule="daily 00:00:00 ",
                actions=dict(
                    action=dict(command="command"),
                    action1=dict(command="command"),
                    action2=dict(node="node0", command="command", requires=["action", "action1"],),
                ),
            ),
            dict(
                name="test_job4",
                node="NodePool",
                all_nodes=True,
                schedule="daily",
                enabled=False,
                actions=[dict(name="action", command="command")],
            ),
            dict(
                name="test_job_mesos",
                node="NodePool",
                schedule="daily",
                actions=[
                    dict(
                        name="action_mesos",
                        executor="mesos",
                        command="test_command_mesos",
                        cpus=0.1,
                        mem=100,
                        disk=600,
                        docker_image="container:latest",
                    ),
                ],
            ),
            dict(
                name="test_job_k8s",
                node="NodePool",
                schedule="daily",
                actions=[
                    dict(
                        name="action_k8s",
                        executor="kubernetes",
                        command="test_command_k8s",
                        cpus=0.1,
                        mem=100,
                        disk=600,
                        docker_image="container:latest",
                        secret_env=dict(TEST_SECRET=dict(secret_name="tron-secret-test-secret--1", key="secret_1")),
                        secret_volumes=[
                            dict(
                                secret_volume_name="abc",
                                secret_name="secret1",
                                container_path="/b/c",
                                default_mode="0644",
                                items=[dict(key="secret1", path="abcd", mode="777"),],
                            ),
                        ],
                        cap_add=["KILL"],
                        cap_drop=["CHOWN", "KILL"],
                        node_selectors={"yelp.com/pool": "default"},
                        node_affinities=[{"key": "instance_type", "operator": "In", "value": ["a1.1xlarge"]}],
                    ),
                ],
            ),
        ],
    )

    config = dict(
        command_context=dict(batch_dir="/tron/batch/test/foo", python="/usr/bin/python",), **BASE_CONFIG, **JOBS_CONFIG,
    )

    @mock.patch.dict("tron.config.config_parse.ValidateNode.defaults")
    def test_attributes(self):
        config_parse.ValidateNode.defaults["username"] = "foo"
        expected = make_tron_config()

        test_config = valid_config(self.config)

        assert test_config.command_context == expected.command_context
        assert test_config.ssh_options == expected.ssh_options
        assert test_config.mesos_options == expected.mesos_options
        assert test_config.time_zone == expected.time_zone
        assert test_config.nodes == expected.nodes
        assert test_config.node_pools == expected.node_pools
        assert test_config.k8s_options == expected.k8s_options
        for key in ["0", "1", "2", "_actions_dict", "4", "_mesos"]:
            job_name = f"MASTER.test_job{key}"
            assert job_name in test_config.jobs, f"{job_name} in test_config.jobs"
            assert job_name in expected.jobs, f"{job_name} in test_config.jobs"
            assert test_config.jobs[job_name] == expected.jobs[job_name]
        assert test_config == expected

    def test_empty_node_test(self):
        valid_config(dict(nodes=None))

class TestNamedConfig(TestCase):
    config = ConfigTestCase.JOBS_CONFIG

    def test_attributes(self):
        expected = make_named_tron_config(
            jobs={
                "test_job": make_job(
                    name="test_job",
                    namespace="test_namespace",
                    schedule=make_mock_schedule(),
                    expected_runtime=datetime.timedelta(1),
                ),
            },
        )
        test_config = validate_fragment(
            "test_namespace",
            dict(
                jobs=[
                    dict(
                        name="test_job",
                        namespace="test_namespace",
                        node="node0",
                        schedule="daily 00:00:00 ",
                        actions=[dict(name="action", command="command")],
                        cleanup_action=dict(command="command"),
                    ),
                ],
            ),
        )
        assert_equal(test_config, expected)

    def test_attributes_with_master_context(self):
        expected = make_named_tron_config(
            jobs={
                "test_namespace.test_job": make_job(
                    name="test_namespace.test_job",
                    namespace="test_namespace",
                    schedule=make_mock_schedule(),
                    expected_runtime=datetime.timedelta(1),
                ),
            },
        )
        master_config = dict(
            nodes=[dict(name="node0", hostname="node0",),], node_pools=[dict(name="nodepool0", nodes=["node0"],),],
        )
        test_config = validate_fragment(
            "test_namespace",
            dict(
                jobs=[
                    dict(
                        name="test_job",
                        namespace="test_namespace",
                        node="node0",
                        schedule="daily 00:00:00",
                        actions=[dict(name="action", command="command")],
                        cleanup_action=dict(command="command"),
                    ),
                ],
            ),
            master_config=master_config,
        )
        assert_equal(test_config, expected)

    def test_invalid_job_node_with_master_context(self):
        master_config = dict(nodes=[dict(name="node0", hostname="node0",),],)
        test_config = dict(
            jobs=[
                dict(
                    name="test_job",
                    namespace="test_namespace",
                    node="node1",
                    schedule="daily 00:30:00 ",
                    actions=[dict(name="action", command="command")],
                    cleanup_action=dict(command="command"),
                ),
            ],
        )
        expected_message = "Unknown node name node1 at test_namespace.NamedConfigFragment.jobs.Job.test_job.node"
        exception = assert_raises(ConfigError, validate_fragment, "test_namespace", test_config, master_config,)
        assert_in(expected_message, str(exception))

    def test_invalid_action_node_with_master_context(self):
        master_config = dict(
            nodes=[dict(name="node0", hostname="node0",),], node_pools=[dict(name="nodepool0", nodes=["node0"],),],
        )
        test_config = dict(
            jobs=[
                dict(
                    name="test_job",
                    namespace="test_namespace",
                    node="node0",
                    schedule="daily 00:30:00 ",
                    actions=[dict(name="action", node="nodepool1", command="command")],
                    cleanup_action=dict(command="command"),
                ),
            ],
        )
        expected_message = "Unknown node name nodepool1 at test_namespace.NamedConfigFragment.jobs.Job.test_job.actions.Action.action.node"

        exception = assert_raises(ConfigError, validate_fragment, "test_namespace", test_config, master_config,)
        assert_in(expected_message, str(exception))

class TestJobConfig(TestCase):
    def test_no_actions(self):
        test_config = dict(jobs=[dict(name="test_job0", node="node0", schedule="daily 00:30:00 "),], **BASE_CONFIG,)

        expected_message = "Job test_job0 is missing options: actions"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_in(expected_message, str(exception))

    def test_empty_actions(self):
        test_config = dict(
            jobs=[dict(name="test_job0", node="node0", schedule="daily 00:30:00 ", actions=None,),], **BASE_CONFIG,
        )

        expected_message = "Value at config.jobs.Job.test_job0.actions"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_in(expected_message, str(exception))

    def test_dupe_names(self):
        test_config = dict(
            jobs=[
                dict(
                    name="test_job0",
                    node="node0",
                    schedule="daily 00:30:00",
                    actions=[dict(name="action", command="cmd"), dict(name="action", command="cmd"),],
                ),
            ],
            **BASE_CONFIG,
        )

        expected = "Duplicate name action at config.jobs.Job.test_job0.actions"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_in(expected, str(exception))

    def test_bad_requires(self):
        test_config = dict(
            jobs=[
                dict(
                    name="test_job0",
                    node="node0",
                    schedule="daily 00:30:00",
                    actions=[dict(name="action", command="cmd")],
                ),
                dict(
                    name="test_job1",
                    node="node0",
                    schedule="daily 00:30:00",
                    actions=[dict(name="action1", command="cmd", requires=["action"],),],
                ),
            ],
            **BASE_CONFIG,
        )

        expected_message = "jobs.MASTER.test_job1.action1 has a dependency " '"action" that is not in the same job!'
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_in(expected_message, str(exception))

    def test_circular_dependency(self):
        test_config = dict(
            jobs=[
                dict(
                    name="test_job0",
                    node="node0",
                    schedule="daily 00:30:00",
                    actions=[
                        dict(name="action1", command="cmd", requires=["action2"],),
                        dict(name="action2", command="cmd", requires=["action1"],),
                    ],
                ),
            ],
            **BASE_CONFIG,
        )

        expect = "Circular dependency in job.MASTER.test_job0: action1 -> action2"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_in(expect, str(exception))

    def test_circular_dependency_multiaction(self):
        test_config = dict(
            jobs=[
                dict(
                    name="test_job0",
                    node="node0",
                    schedule="daily 00:30:00",
                    actions=[
                        dict(name="action1", command="cmd", requires=["action2"],),
                        dict(name="action2", command="cmd", requires=["action3"],),
                        dict(name="action3", command="cmd", requires=["action4"],),
                        dict(name="action4", command="cmd", requires=["action5"],),
                        dict(name="action5", command="cmd", requires=["action3"],),
                    ],
                ),
            ],
            **BASE_CONFIG,
        )

        expect = "Circular dependency in job.MASTER.test_job0: action3 -> action4 -> action5"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_in(expect, str(exception))

    def test_config_cleanup_name_collision(self):
        test_config = dict(
            jobs=[
                dict(
                    name="test_job0",
                    node="node0",
                    schedule="daily 00:30:00",
                    actions=[dict(name=CLEANUP_ACTION_NAME, command="cmd"),],
                ),
            ],
            **BASE_CONFIG,
        )
        expected_message = "config.jobs.Job.test_job0.actions.Action.cleanup.name"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_in(expected_message, str(exception))

    def test_config_cleanup_action_name(self):
        test_config = dict(
            jobs=[
                dict(
                    name="test_job0",
                    node="node0",
                    schedule="daily 00:30:00",
                    actions=[dict(name="action", command="cmd"),],
                    cleanup_action=dict(name="gerald", command="cmd"),
                ),
            ],
            **BASE_CONFIG,
        )

        expected_msg = "Cleanup actions cannot have custom names"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_in(expected_msg, str(exception))

    def test_config_cleanup_requires(self):
        test_config = dict(
            jobs=[
                dict(
                    name="test_job0",
                    node="node0",
                    schedule="daily 00:30:00",
                    actions=[dict(name="action", command="cmd"),],
                    cleanup_action=dict(command="cmd", requires=["action"]),
                ),
            ],
            **BASE_CONFIG,
        )

        expected_msg = "Unknown keys in CleanupAction : requires"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_equal(expected_msg, str(exception))

    def test_validate_job_no_actions(self):
        job_config = dict(name="job_name", node="localhost", schedule="daily 00:30:00", actions=[],)
        config_context = config_utils.ConfigContext("config", ["localhost"], None, None,)
        expected_msg = "Required non-empty list at config.Job.job_name.actions"
        exception = assert_raises(ConfigError, valid_job, job_config, config_context,)
        assert_in(expected_msg, str(exception))

class TestValidSecretSource(TestCase):
    def test_missing_secret_name(self):
        secret_env = dict(key="no_secret_name")

        with pytest.raises(ConfigError) as missing_exc:
            config_parse.valid_secret_source(secret_env, NullConfigContext)

        assert "missing options: secret" in str(missing_exc.value)

    def test_validate_job_extra_secret_env(self):
        secret_env = dict(
            secret_name="tron-secret-k8s-name-no--secret--name", key="no_secret_name", extra_key="unknown",
        )
        with pytest.raises(ConfigError) as missing_exc:
            config_parse.valid_secret_source(secret_env, NullConfigContext)

        assert "Unknown keys in SecretSource : extra_key" in str(missing_exc.value)

    def test_valid_job_secret_env_success(self):
        secret_env = dict(secret_name="tron-secret-k8s-name-no--secret--name", key="no_secret_name",)

        expected_env = schema.ConfigSecretSource(**secret_env)

        built_env = config_parse.valid_secret_source(secret_env, NullConfigContext)
        assert built_env == expected_env

class TestNodeConfig(TestCase):
    def test_validate_node_pool(self):
        config_node_pool = valid_node_pool(dict(name="theName", nodes=["node1", "node2"]),)
        assert_equal(config_node_pool.name, "theName")
        assert_equal(len(config_node_pool.nodes), 2)

    def test_overlap_node_and_node_pools(self):
        tron_config = dict(
            nodes=[dict(name="sameName", hostname="localhost"),],
            node_pools=[dict(name="sameName", nodes=["sameNode"]),],
        )
        expected_msg = "Node and NodePool names must be unique sameName"
        exception = assert_raises(ConfigError, valid_config, tron_config)
        assert_in(expected_msg, str(exception))

    def test_invalid_node_name(self):
        test_config = dict(
            jobs=[
                dict(
                    name="test_job0",
                    node="unknown_node",
                    schedule="daily 00:30:00",
                    actions=[dict(name="action", command="cmd")],
                ),
            ],
            **BASE_CONFIG,
        )

        expected_msg = "Unknown node name unknown_node at config.jobs.Job.test_job0.node"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_equal(expected_msg, str(exception))

    def test_invalid_nested_node_pools(self):
        test_config = dict(
            nodes=[dict(name="node0", hostname="node0"), dict(name="node1", hostname="node1"),],
            node_pools=[dict(name="pool0", nodes=["node1"]), dict(name="pool1", nodes=["node0", "pool0"]),],
            jobs=[
                dict(
                    name="test_job0",
                    node="pool1",
                    schedule="daily 00:30:00",
                    actions=[dict(name="action", command="cmd")],
                ),
            ],
        )

        expected_msg = "NodePool pool1 contains other NodePools: pool0"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_in(expected_msg, str(exception))

    def test_invalid_node_pool_config(self):
        test_config = dict(
            nodes=[dict(name="node0", hostname="node0"), dict(name="node1", hostname="node1"),],
            node_pools=[dict(name="pool0", hostname=["node1"]), dict(name="pool1", nodes=["node0", "pool0"]),],
            jobs=[
                dict(
                    name="test_job0",
                    node="pool1",
                    schedule="daily 00:30:00",
                    actions=[dict(name="action", command="cmd")],
                ),
            ],
        )

        expected_msg = "NodePool pool0 is missing options"
        exception = assert_raises(ConfigError, valid_config, test_config,)
        assert_in(expected_msg, str(exception))

    def test_invalid_named_update(self):
        test_config = dict(bozray=None)
        expected_message = "Unknown keys in NamedConfigFragment : bozray"
        exception = assert_raises(ConfigError, validate_fragment, "foo", test_config,)
        assert_in(expected_message, str(exception))

class TestValidateJobs(TestCase):
    def test_valid_jobs_success(self):
        test_config = dict(
            jobs=[
                dict(
                    name="test_job0",
                    node="node0",
                    schedule="daily",
                    expected_runtime="20m",
                    actions=[
                        dict(name="action", command="command", expected_runtime="20m",),
                        dict(
                            name="action_mesos",
                            command="command",
                            executor="mesos",
                            cpus=4,
                            mem=300,
                            disk=600,
                            constraints=[dict(attribute="pool", operator="LIKE", value="default",),],
                            docker_image="my_container:latest",
                            docker_parameters=[dict(key="label", value="labelA"), dict(key="label", value="labelB"),],
                            env=dict(USER="batch"),
                            extra_volumes=[dict(container_path="/tmp", host_path="/home/tmp", mode="RO",),],
                        ),
                        dict(
                            name="test_trigger_attrs",
                            command="foo",
                            triggered_by=["foo.bar"],
                            trigger_downstreams=True,
                        ),
                    ],
                    cleanup_action=dict(command="command"),
                ),
            ],
            **BASE_CONFIG,
        )

        expected_jobs = {
            "MASTER.test_job0": make_job(
                name="MASTER.test_job0",
                schedule=make_mock_schedule(),
                actions={
                    "action": make_action(expected_runtime=datetime.timedelta(0, 1200),),
                    "action_mesos": make_action(
                        name="action_mesos",
                        executor=schema.ExecutorTypes.mesos.value,
                        cpus=4.0,
                        mem=300.0,
                        disk=600.0,
                        constraints=(schema.ConfigConstraint(attribute="pool", operator="LIKE", value="default",),),
                        docker_image="my_container:latest",
                        docker_parameters=(
                            schema.ConfigParameter(key="label", value="labelA",),
                            schema.ConfigParameter(key="label", value="labelB",),
                        ),
                        env={"USER": "batch"},
                        extra_volumes=(
                            schema.ConfigVolume(
                                container_path="/tmp", host_path="/home/tmp", mode=schema.VolumeModes.RO.value,
                            ),
                        ),
                        expected_runtime=datetime.timedelta(hours=24),
                    ),
                    "test_trigger_attrs": make_action(
                        name="test_trigger_attrs", command="foo", triggered_by=("foo.bar",), trigger_downstreams=True,
                    ),
                },
                expected_runtime=datetime.timedelta(0, 1200),
            ),
        }

        context = config_utils.ConfigContext("config", ["node0"], None, MASTER_NAMESPACE,)
        config_parse.validate_jobs(test_config, context)
        assert expected_jobs == test_config["jobs"]

class TestValidMesosAction(TestCase):
    def test_missing_docker_image(self):
        config = dict(name="test_missing", command="echo hello", executor="mesos", cpus=0.2, mem=150, disk=450,)
        with pytest.raises(ConfigError):
            config_parse.valid_action(config, NullConfigContext)

    def test_cleanup_missing_docker_image(self):
        config = dict(command="echo hello", executor="mesos", cpus=0.2, mem=150, disk=450,)
        with pytest.raises(ConfigError):
            config_parse.valid_action(config, NullConfigContext)

class TestValidCleanupActionName(TestCase):
    def test_valid_cleanup_action_name_pass(self):
        name = valid_cleanup_action_name(CLEANUP_ACTION_NAME, None)
        assert_equal(CLEANUP_ACTION_NAME, name)

    def test_valid_cleanup_action_name_fail(self):
        assert_raises(
            ConfigError, valid_cleanup_action_name, "other", NullConfigContext,
        )

class TestValidOutputStreamDir(TestCase):
    @setup
    def setup_dir(self):
        self.dir = tempfile.mkdtemp()

    @teardown
    def teardown_dir(self):
        shutil.rmtree(self.dir)

    def test_valid_dir(self):
        path = valid_output_stream_dir(self.dir, NullConfigContext)
        assert_equal(self.dir, path)

    def test_missing_dir(self):
        exception = assert_raises(ConfigError, valid_output_stream_dir, "bogus-dir", NullConfigContext,)
        assert_in("is not a directory", str(exception))

    # TODO: docker tests run as root so everything is writeable
    # def test_no_ro_dir(self):
    #     os.chmod(self.dir, stat.S_IRUSR)
    #     exception = assert_raises(
    #         ConfigError,
    #         valid_output_stream_dir, self.dir, NullConfigContext,
    #     )
    #     assert_in("is not writable", str(exception))

    def test_missing_with_partial_context(self):
        dir = "/bogus/path/does/not/exist"
        context = config_utils.PartialConfigContext("path", "MASTER")
        path = config_parse.valid_output_stream_dir(dir, context)
        assert_equal(path, dir)

class TestBuildFormatStringValidator(TestCase):
    @setup
    def setup_keys(self):
        self.context = dict.fromkeys(["one", "seven", "stars"])
        self.validator = build_format_string_validator(self.context)

    def test_validator_passes(self):
        template = "The {one} thing I {seven} is {stars}"
        assert self.validator(template, NullConfigContext)

    def test_validator_unknown_variable_error(self):
        template = "The {one} thing I {seven} is {unknown}"
        exception = assert_raises(ConfigError, self.validator, template, NullConfigContext,)
        assert_in("Unknown context variable", str(exception))

    def test_validator_passes_with_context(self):
        template = "The {one} thing I {seven} is {mars}"
        context = config_utils.ConfigContext(None, None, {"mars": "ok"}, None,)
        assert self.validator(template, context) == template

    def test_validator_valid_string_without_no_percent_escape(self):
        template = "The {one} {seven} thing is {mars} --year %Y"
        context = config_utils.ConfigContext(path=None, nodes=None, command_context={"mars": "ok"}, namespace=None,)
        assert self.validator(template, context)

class TestValidateConfigMapping(TestCase):
    config = dict(**BASE_CONFIG, command_context=dict(some_var="The string"))

    def test_validate_config_mapping_missing_master(self):
        config_mapping = {"other": mock.Mock()}
        seq = config_parse.validate_config_mapping(config_mapping)
        exception = assert_raises(ConfigError, list, seq)
        assert_in("requires a MASTER namespace", str(exception))

    def test_validate_config_mapping(self):
        master_config = self.config
        other_config = TestNamedConfig.config
        config_mapping = {
            "other": other_config,
            MASTER_NAMESPACE: master_config,
        }
        result = list(config_parse.validate_config_mapping(config_mapping))
        assert_equal(len(result), 2)
        assert_equal(result[0][0], MASTER_NAMESPACE)
        assert_equal(result[1][0], "other")

class TestConfigContainer(TestCase):
    config = BASE_CONFIG

    @setup
    def setup_container(self):
        other_config = TestNamedConfig.config
        self.config_mapping = {
            MASTER_NAMESPACE: valid_config(self.config),
            "other": validate_fragment("other", other_config),
        }
        self.container = config_parse.ConfigContainer(self.config_mapping)

    def test_create(self):
        config_mapping = {
            MASTER_NAMESPACE: self.config,
            "other": TestNamedConfig.config,
        }

        container = config_parse.ConfigContainer.create(config_mapping)
        assert_equal(set(container.configs.keys()), {"MASTER", "other"})

    def test_create_missing_master(self):
        config_mapping = {"other": mock.Mock()}
        assert_raises(
            ConfigError, config_parse.ConfigContainer.create, config_mapping,
        )

    def test_get_job_names(self):
        job_names = self.container.get_job_names()
        expected = [
            "test_job1",
            "test_job0",
            "test_job_actions_dict",
            "test_job2",
            "test_job4",
            "test_job_mesos",
            "test_job_k8s",
        ]
        assert_equal(set(job_names), set(expected))

    def test_get_jobs(self):
        expected = [
            "test_job1",
            "test_job0",
            "test_job_actions_dict",
            "test_job2",
            "test_job4",
            "test_job_mesos",
            "test_job_k8s",
        ]
        assert_equal(set(expected), set(self.container.get_jobs().keys()))

    def test_get_node_names(self):
        node_names = self.container.get_node_names()
        expected = {"node0", "node1", "NodePool"}
        assert_equal(node_names, expected)

class TestValidateSSHOptions(TestCase):
    @setup
    def setup_context(self):
        self.context = config_utils.NullConfigContext
        self.config = {"agent": True, "identities": []}

    @mock.patch.dict("tron.config.config_parse.os.environ")
    def test_post_validation_failed(self):
        if "SSH_AUTH_SOCK" in os.environ:
            del os.environ["SSH_AUTH_SOCK"]
        assert_raises(
            ConfigError, config_parse.valid_ssh_options.validate, self.config, self.context,
        )

    @mock.patch.dict("tron.config.config_parse.os.environ")
    def test_post_validation_success(self):
        os.environ["SSH_AUTH_SOCK"] = "something"
        config = config_parse.valid_ssh_options.validate(self.config, self.context,)
        assert_equal(config.agent, True)

class TestValidateIdentityFile(TestCase):
    @setup
    def setup_context(self):
        self.context = config_utils.NullConfigContext
        self.private_file = tempfile.NamedTemporaryFile()

    def test_valid_identity_file_missing_private_key(self):
        exception = assert_raises(ConfigError, config_parse.valid_identity_file, "/file/not/exist", self.context,)
        assert_in("Private key file", str(exception))

    def test_valid_identity_files_missing_public_key(self):
        filename = self.private_file.name
        exception = assert_raises(ConfigError, config_parse.valid_identity_file, filename, self.context,)
        assert_in("Public key file", str(exception))

    def test_valid_identity_files_valid(self):
        filename = self.private_file.name
        fh_private = open(filename + ".pub", "w")
        try:
            config = config_parse.valid_identity_file(filename, self.context)
        finally:
            fh_private.close()
            os.unlink(fh_private.name)
        assert_equal(config, filename)

    def test_valid_identity_files_missing_with_partial_context(self):
        path = "/bogus/file/does/not/exist"
        context = config_utils.PartialConfigContext("path", "MASTER")
        file_path = config_parse.valid_identity_file(path, context)
        assert_equal(path, file_path)

class TestValidKnownHostsFile(TestCase):
    @setup
    def setup_context(self):
        self.context = config_utils.NullConfigContext
        self.known_hosts_file = tempfile.NamedTemporaryFile()

    def test_valid_known_hosts_file_exists(self):
        filename = config_parse.valid_known_hosts_file(self.known_hosts_file.name, self.context,)
        assert_equal(filename, self.known_hosts_file.name)

    def test_valid_known_hosts_file_missing(self):
        exception = assert_raises(ConfigError, config_parse.valid_known_hosts_file, "/bogus/path", self.context,)
        assert_in("Known hosts file /bogus/path", str(exception))

    def test_valid_known_hosts_file_missing_partial_context(self):
        context = config_utils.PartialConfigContext
        expected = "/bogus/does/not/exist"
        filename = config_parse.valid_known_hosts_file(expected, context,)
        assert_equal(filename, expected)

class TestValidateVolume(TestCase):
    @setup
    def setup_context(self):
        self.context = config_utils.NullConfigContext

    def test_missing_container_path(self):
        config = {
            "container_path_typo": "/nail/srv",
            "host_path": "/tmp",
            "mode": "RO",
        }
        assert_raises(
            ConfigError, config_parse.valid_volume.validate, config, self.context,
        )

    def test_missing_host_path(self):
        config = {
            "container_path": "/nail/srv",
            "hostPath": "/tmp",
            "mode": "RO",
        }
        assert_raises(
            ConfigError, config_parse.valid_volume.validate, config, self.context,
        )

    def test_invalid_mode(self):
        config = {
            "container_path": "/nail/srv",
            "host_path": "/tmp",
            "mode": "RA",
        }
        assert_raises(
            ConfigError, config_parse.valid_volume.validate, config, self.context,
        )

    def test_valid(self):
        config = {
            "container_path": "/nail/srv",
            "host_path": "/tmp",
            "mode": schema.VolumeModes.RO.value,
        }
        assert_equal(
            schema.ConfigVolume(**config), config_parse.valid_volume.validate(config, self.context),
        )

    def test_mesos_default_volumes(self):
        mesos_options = {"master_address": "mesos_master"}
        mesos_options["default_volumes"] = [
            {"container_path": "/nail/srv", "host_path": "/tmp", "mode": "RO",},
            {"container_path": "/nail/srv", "host_path": "/tmp", "mode": "invalid",},
        ]

        with pytest.raises(ConfigError):
            config_parse.valid_mesos_options.validate(mesos_options, self.context)

        # After we fix the error, expect error to go away.
        mesos_options["default_volumes"][1]["mode"] = "RW"
        assert config_parse.valid_mesos_options.validate(mesos_options, self.context,)

    def test_k8s_default_volumes(self):
        k8s_options = {"kubeconfig_path": "some_path"}
        k8s_options["default_volumes"] = [
            {"container_path": "/nail/srv", "host_path": "/tmp", "mode": "RO",},
            {"container_path": "/nail/srv", "host_path": "/tmp", "mode": "invalid",},
        ]

        with pytest.raises(ConfigError):
            config_parse.valid_kubernetes_options.validate(k8s_options, self.context)

        # After we fix the error, expect error to go away.
        k8s_options["default_volumes"][1]["mode"] = "RW"
        assert config_parse.valid_kubernetes_options.validate(k8s_options, self.context,)

class TestValidPermissionMode:
    @pytest.mark.parametrize(
        ("permission", "normalized"),
        [("777", "777"), ("0", "0"), ("0000", "0000"), ("0123", "0123"), (0, "0"), (7777, "7777")],
    )
    def test_valid_permissions(self, permission, normalized):
        result = config_parse.valid_permission_mode(permission, NullConfigContext)
        assert result == normalized

    @pytest.mark.parametrize("permission", ["778", "é", -1, "", {}, [], ()])
    def test_invalid_permissions(self, permission):
        with pytest.raises(ConfigError):
            config_parse.valid_permission_mode(permission, NullConfigContext)

class TestValidSecretVolumeItem:
    @pytest.mark.parametrize(
        "config",
        [
            {"path": "abc"},
            {"key": "abc",},
            {"key": "abc", "path": "abc", "extra_key": None,},
            {"key": "abc", "path": "abc", "mode": "a"},
        ],
    )
    def test_invalid(self, config):
        with pytest.raises(ConfigError):
            config_parse.valid_secret_volume_item(config, NullConfigContext)

    @pytest.mark.parametrize(
        "config", [{"key": "abc", "path": "abc"}, {"key": "abc", "path": "abc", "mode": "777"}],
    )
    def test_valid_job_secret_volume_success(self, config):
        config_parse.valid_secret_volume_item(config, NullConfigContext)

class TestValidSecretVolume:
    @pytest.mark.parametrize(
        "config",
        [
            dict(
                secret_volume_name="abc",
                secret_name="secret1",
                container_path="/b/c",
                default_mode="0644",
                items=[dict(key="secret1", path="abcd", mode="7778"),],
            ),
            dict(
                secret_volume_name="abc",
                container_path="/b/c",
                default_mode="0644",
                items=[dict(key="secret1", path="abcd", mode="7777"),],
            ),
            dict(secret_volume_name="abc", secret_name="secret1", container_path=123,),
            dict(
                secret_volume_name="abc",
                secret_name="secret1",
                container_path="/b/c",
                items=[dict(key="secret1", path="abcd", mode="7777"), dict(key="secret1", path="abcde", mode="7777")],
            ),
        ],
    )
    def test_invalid(self, config):
        with pytest.raises(ConfigError):
            config_parse.valid_secret_volume(config, NullConfigContext)

    def test_wrong_item_key(self):
        config = dict(
            secret_volume_name="abc",
            secret_name="secret1",
            container_path="/b/c",
            items=[dict(key="secret2", path="abc"),],
        )
        with pytest.raises(ConfigError):
            config_parse.valid_secret_volume(config, NullConfigContext)

    @pytest.mark.parametrize(
        "config",
        [
            dict(
                secret_volume_name="abc",
                secret_name="secret1",
                container_path="/b/c",
                default_mode="0644",
                items=[dict(key="secret1", path="abc"),],
            ),
            dict(secret_volume_name="abc", secret_name="secret1", container_path="/b/c", items=[],),
            dict(secret_volume_name="abc", secret_name="secret1", container_path="/b/c",),
        ],
    )
    def test_valid(self, config):
        config_parse.valid_secret_volume(config, NullConfigContext)

class TestValidMasterAddress:
    @pytest.fixture
    def context(self):
        return config_utils.NullConfigContext

    @pytest.mark.parametrize(
        "url", ["http://blah.com", "http://blah.com/", "blah.com", "blah.com/",],
    )
    def test_valid(self, url, context):
        normalized = "http://blah.com"
        result = config_parse.valid_master_address(url, context)
        assert result == normalized

    @pytest.mark.parametrize(
        "url", ["https://blah.com", "http://blah.com/something", "blah.com/other", "http://", "blah.com?a=1",],
    )
    def test_invalid(self, url, context):
        with pytest.raises(ConfigError):
            config_parse.valid_master_address(url, context)

if __name__ == "__main__":
    run()


import warnings
from inspect import getmembers, isfunction

from . import metrics

metric_fn_dict = dict(getmembers(metrics, predicate=isfunction))

class Evaluator:
    def __init__(self, module, *,
                 valid_loader, test_loader,
                 valid_metrics=None,
                 test_metrics=None,
                 metric_kwargs=None):
        self.module = module
        self.valid_loader = valid_loader
        self.test_loader = test_loader
        self.valid_metrics = valid_metrics or {}
        self.test_metrics = test_metrics or valid_metrics
        self.valid_cache = {}
        self.test_cache = {}
        self.metric_kwargs = metric_kwargs or {}

    def evaluate(self, dataloader, metric, cache=None):
        assert metric in metric_fn_dict, f"Metric name {metric} not present in `metrics.py`"

        metric_fn = metric_fn_dict[metric]
        metric_fn_kwargs = self.metric_kwargs.get(metric) or {}

        self.module.eval()
        return metric_fn(self.module, dataloader, cache=cache, **metric_fn_kwargs)

    def validate(self):
        print(f"Validating {self.valid_metrics} for {self.module.model_type}")
        return self._create_metrics_dict(self.valid_metrics, self.valid_loader, self.valid_cache)

    def test(self):
        print(f"Testing {self.test_metrics} for {self.module.model_type}")
        return self._create_metrics_dict(self.test_metrics, self.test_loader, self.test_cache)

    def _create_metrics_dict(self, metrics, loader, cache):
        metrics_dict = {}
        for metric in metrics:
            try:
                metric_result = self.evaluate(loader, metric, cache=cache)
            except NotImplementedError:
                warnings.warn(f"Metric {metric} not implemented for provided model. Skipping.")
                continue
            if isinstance(metric_result, dict):
                metrics_dict.update(metric_result)
            else:
                metrics_dict[metric] = metric_result
        return metrics_dict

class NullEvaluator(Evaluator):
    def __init__(self, module, *, valid_loader, test_loader):
        super().__init__(
            module, valid_loader=valid_loader, test_loader=test_loader,
            valid_metrics={"null_metric"},
        )

class AutoencodingEvaluator(Evaluator):
    def __init__(self, module, *, valid_loader, test_loader):
        super().__init__(
            module, valid_loader=valid_loader, test_loader=test_loader,
            valid_metrics={"l2_reconstruction_error"},
        )

class ImageEvaluator(Evaluator):
    def __init__(self, module, *, train_loader, valid_loader, test_loader):
        super().__init__(
            module, valid_loader=valid_loader, test_loader=test_loader,
            valid_metrics={"l2_reconstruction_error"},
            test_metrics={"l2_reconstruction_error", "fid"},
            metric_kwargs={
                "fid": {
                    "train_loader": train_loader,
                }
            }
        )

class ImageFIDEvaluator(Evaluator):
    def __init__(self, module, *, train_loader, valid_loader, test_loader):
        super().__init__(
            module, valid_loader=valid_loader, test_loader=test_loader,
            valid_metrics={"l2_reconstruction_error", "fid"},
            test_metrics={"l2_reconstruction_error", "fid"},
            metric_kwargs={
                "fid": {
                    "train_loader": train_loader,
                }
            }
        )

class OODEvaluator(Evaluator):
    def __init__(
            self,
            module,
            *,
            is_test_loader,
            oos_test_loader,
            is_train_loader,
            oos_train_loader,
            savedir,
            low_dim
        ):
        super().__init__(
            module, valid_loader=None, test_loader=is_test_loader,
            valid_metrics=None,
            test_metrics={"likelihood_ood_acc"},
            metric_kwargs={
                "likelihood_ood_acc": {
                    "oos_test_loader": oos_test_loader,
                    "is_train_loader": is_train_loader,
                    "oos_train_loader": oos_train_loader,
                    "savedir": savedir,
                    "low_dim": low_dim
                }
            }
        )


from board import SCL, SDA
import busio
import time

from adafruit_pca9685 import PCA9685

from adafruit_motor import servo

i2c = busio.I2C(SCL,SDA)

pca = PCA9685(i2c)
pca.frequency = 50

servo4 = servo.Servo(pca.channels[4])
servo1 = servo.Servo(pca.channels[0])

for i in range(180):
    servo4.angle = i
    servo1.angle = i
    #time.sleep(0.1)
time.sleep(5)
for i in range(180):
    servo4.angle = 180 - i
    servo1.angle = 180 - i
pca.deinit()

Sensor Specific Code/PCA9685 Servo-LED controller/servotest1.py


def sol(arr, n):
    pro = 1
    flag = 0
    i = 0
    memory = 0
    for i in range(n):
        if arr[i] == 0:
            pro *= 1
        else:
            pro *= arr[i]
    ans = []
    for i in range(n):
        if arr[i] == 0:
            flag = 1
            memory = i
            break
        else:
            ans.append(pro // arr[i])

    if flag == 1:
        for k in range(i + 1, n):
            if arr[k] == 0:
                tem1 = [0] * n
                return tem1

        temp = [0] * n
        temp[memory] = pro
        print(pro)
        return temp
    else:
        return ans

if __name__ == '__main__':
    # arr=[10, 3, 5, 6, 2]
    # arr=[12,0,3]
    arr=[1,0]
    # arr=[0, 8, 6, 2, 4, 7, 9, 3, 9, 2, 8, 3, 0, 1, 7, 8, 9, 1, 5, 4, 9, 2, 5, 7, 4, 9, 9, 4]
    n=len(arr)

    print(sol(arr,n))


import argparse
import pickle
import gzip
import warnings
import json
from sklearn.preprocessing import LabelEncoder
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.feature_extraction.text import CountVectorizer
warnings.simplefilter("ignore")

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--model", dest="model", help="Output file for pickled model")
    parser.add_argument("--scores", dest="scores", help="Output file for scores")
    parser.add_argument("--input", dest="input", help="Input file")
    parser.add_argument("--vectorizer", dest="vectorizer", help="Output file for vectorizer")
#   parser.add_argument("--output", dest="output", help="Output file")
    args, rest = parser.parse_known_args()

#Creating content, label and title lists
X = []
y = []
titles = []
with gzip.open(args.input, "rt") as ifd:
    for line in ifd:
        data = json.loads(line)
        y.append(data['label'])
        X.append(data['content'])
        ht_meta = data['ht_meta']
        titles.append((ht_meta['title']))

le = LabelEncoder()
y = le.fit_transform(y)
y = list(zip(y, titles))

#Minimal preprocessing by lowercasing the content
data_list = []
for text in X:
    text = text.lower()
    data_list.append(text)

cv = CountVectorizer(ngram_range=(1, 4), token_pattern = r"(?u)\b\w+\b", analyzer='char')
X = cv.fit_transform(data_list).toarray()

#train test splitting
x_train, x_test, y_train_tuples, y_test_tuples = train_test_split(X, y, random_state=1, test_size = 0.20)

#model creation and prediction
y_train =[label for label, title in y_train_tuples]
y_test = [label for label, title in y_test_tuples]
title_test = [title for lable, title in y_test_tuples]

model = MultinomialNB()
model.fit(x_train, y_train)

# prediction
y_pred = model.predict(x_test)

# model evaluation
metrics  = {
    "ac":  accuracy_score(y_test, y_pred),
#   cm: confusion_matrix(y_test, y_pred)
    "fscore" : f1_score(y_test, y_pred)
    }
#saving the model
with gzip.open(args.model, "wb") as ofd:
    ofd.write(pickle.dumps(model))

#saving the scores
with open(args.scores, "wb") as ofd:
   ofd.write(pickle.dumps(metrics))

#saving the vectorizer
with gzip.open(args.vectorizer, "wb") as ofd:
    ofd.write(pickle.dumps(cv))

"""
def split_text(text, max_length):
    while len(text) > max_length:
        yield text[:max_length]
        text = text[max_length:]
    if len(text) > 0:
        yield text

if __name__ == "__main__":

    parser = argparse.ArgumentParser()
    parser.add_argument("--data", dest="data", help="Data input file")
    parser.add_argument("--train", dest="train", help="Train input file (list of line-numbers in the data file)")
    parser.add_argument("--dev", dest="dev", help="Dev input file (list of line-numbers in the data file)")
    parser.add_argument("--model", dest="model", help="Output file for pickled model")
    parser.add_argument("--scores", dest="scores", help="Output file for dev scores")
    parser.add_argument("--n", dest="n", default=3, type=int, help="Value of 'n', as in 'n-gram'")
    parser.add_argument("--max_length", dest="max_length", default=0, type=int, help="Max length of texts to evaluate on")
    args, rest = parser.parse_known_args()

    # Get lists of train/dev item-numbers
    train = []
    dev = []

    with gzip.open(args.train, "rt") as ifd:
        for line in ifd:
            train.append(json.loads(line))

    with gzip.open(args.dev, "rt") as ifd:
        for line in ifd:
            dev.append(json.loads(line))

    models = {}

    # Train model and get dev instances
    devs = []
    with gzip.open(args.data, "rt") as ifd:
        for i, line in enumerate(ifd):
           j = json.loads(line)
           if i in train:
               label = j["label"]
               # Initialize model for this label if one doesn't exist yet
               # models[label] = models.get(label, None)

               # Add counts from j["contents"] to the model[label]
               # ...
               pass
           elif i in dev:
               devs.append(j)

    # Apply models to (chunks of) dev
    guesses = []
    golds = []
    for j in devs:
        gold = j["label"]
        # Apply models to j["content"], whichever is more likely is the "guess"
        #
        for chunk in (j["content"] if args.max_length == 0 else split_text(j["content"], args.max_length)):
            # guesses.append(guess)
            golds.append(gold)
            pass

    # compute scores
    scores = {
        # "fscore" : sklearn.metrics.f_measure(...)
    }

    # save model
    with gzip.open(args.model, "wb") as ofd:
        ofd.write(pickle.dumps(models))

    # save scores
    with gzip.open(args.scores, "wb") as ofd:
        ofd.write(pickle.dumps(scores))
"""


import sys
from antlr4 import *
from Python3Lexer import Python3Lexer
from Python3Parser import Python3Parser
from antlr4.tree.Trees import Trees

def print_tree(tree, lev):
    print (" " * lev) + "` " + str(tree)
    for c in tree.getChildren():
        print_tree(c, lev + 1)

def main(argv):
    input_stream = FileStream(argv[1])
    lexer = Python3Lexer(input_stream)
    stream = CommonTokenStream(lexer)
    parser = Python3Parser(stream)
    tree = parser.file_input()
    print(tree.toStringTree(recog=parser))

if __name__ == '__main__':
    main(sys.argv)