from __future__ import absolute_import, print_function, unicode_literals

__metaclass__ = type

import json

from testtools.matchers import MatchesStructure
import transaction
from zope.security.management import endInteraction
from zope.security.proxy import removeSecurityProxy

from lp.app.enums import InformationType
from lp.blueprints.enums import SpecificationDefinitionStatus
from lp.registry.enums import SpecificationSharingPolicy
from lp.services.webapp.interaction import ANONYMOUS
from lp.services.webapp.interfaces import OAuthPermission
from lp.testing import (
    admin_logged_in,
    api_url,
    launchpadlib_for,
    person_logged_in,
    TestCaseWithFactory,
    ws_object,
    )
from lp.testing.layers import (
    AppServerLayer,
    DatabaseFunctionalLayer,
    )
from lp.testing.pages import (
    LaunchpadWebServiceCaller,
    webservice_for_person,
    )

class SpecificationWebserviceTestCase(TestCaseWithFactory):

    def getLaunchpadlib(self):
        user = self.factory.makePerson()
        return launchpadlib_for("testing", user, version='devel')

    def getSpecOnWebservice(self, spec_object):
        launchpadlib = self.getLaunchpadlib()
        # Ensure that there is an interaction so that the security
        # checks for spec_object work.
        with person_logged_in(ANONYMOUS):
            url = '/%s/+spec/%s' % (spec_object.target.name, spec_object.name)
        result = launchpadlib.load(url)
        return result

    def getPillarOnWebservice(self, pillar_obj):
        pillar_name = pillar_obj.name
        launchpadlib = self.getLaunchpadlib()
        return launchpadlib.load(pillar_name)

class SpecificationWebserviceTests(SpecificationWebserviceTestCase):
    """Test accessing specification top-level webservice."""
    layer = AppServerLayer

    def test_collection(self):
        # `ISpecificationSet` is exposed as a webservice via /specs
        # and is represented by an empty collection.
        user = self.factory.makePerson()
        webservice = webservice_for_person(user)
        response = webservice.get('/specs')
        self.assertEqual(200, response.status)
        self.assertEqual(
            ['entries', 'resource_type_link', 'start', 'total_size'],
            sorted(response.jsonBody().keys()))
        self.assertEqual(0, response.jsonBody()['total_size'])

    def test_creation_for_products(self):
        # `ISpecificationSet.createSpecification` is exposed and
        # allows specification creation for products.
        user = self.factory.makePerson()
        product = self.factory.makeProduct()
        product_url = api_url(product)
        webservice = webservice_for_person(
            user, permission=OAuthPermission.WRITE_PUBLIC)
        response = webservice.named_post(
            '/specs', 'createSpecification',
            name='test-prod', title='Product', specurl='http://test.com',
            definition_status='Approved', summary='A summary',
            target=product_url,
            api_version='devel')
        self.assertEqual(201, response.status)

    def test_creation_honor_product_sharing_policy(self):
        # `ISpecificationSet.createSpecification` respect product
        # specification_sharing_policy.
        user = self.factory.makePerson()
        product = self.factory.makeProduct(
            owner=user,
            specification_sharing_policy=(
                SpecificationSharingPolicy.PROPRIETARY))
        product_url = api_url(product)
        webservice = webservice_for_person(
            user, permission=OAuthPermission.WRITE_PRIVATE)
        spec_name = 'test-prop'
        response = webservice.named_post(
            '/specs', 'createSpecification',
            name=spec_name, title='Proprietary', specurl='http://test.com',
            definition_status='Approved', summary='A summary',
            target=product_url,
            api_version='devel')
        self.assertEqual(201, response.status)
        # The new specification was created as PROPROETARY.
        response = webservice.get('%s/+spec/%s' % (product_url, spec_name))
        self.assertEqual(200, response.status)
        self.assertEqual(
            'Proprietary', response.jsonBody()['information_type'])

    def test_creation_for_distribution(self):
        # `ISpecificationSet.createSpecification` also allows
        # specification creation for distributions.
        user = self.factory.makePerson()
        distribution = self.factory.makeDistribution()
        distribution_url = api_url(distribution)
        webservice = webservice_for_person(
            user, permission=OAuthPermission.WRITE_PUBLIC)
        response = webservice.named_post(
            '/specs', 'createSpecification',
            name='test-distro', title='Distro', specurl='http://test.com',
            definition_status='Approved', summary='A summary',
            target=distribution_url,
            api_version='devel')
        self.assertEqual(201, response.status)

class SpecificationAttributeWebserviceTests(SpecificationWebserviceTestCase):
    """Test accessing specification attributes over the webservice."""
    layer = AppServerLayer

    def test_representation_is_empty_on_1_dot_0(self):
        # ISpecification is exposed on the 1.0 version so that they can be
        # linked against branches, but none of its fields is exposed on that
        # version as we expect it to undergo significant refactorings before
        # it's ready for prime time.
        spec = self.factory.makeSpecification()
        user = self.factory.makePerson()
        url = '/%s/+spec/%s' % (spec.product.name, spec.name)
        webservice = webservice_for_person(user)
        response = webservice.get(url)
        expected_keys = ['self_link', 'http_etag', 'resource_type_link',
                         'web_link', 'information_type']
        self.assertEqual(response.status, 200)
        self.assertContentEqual(expected_keys, response.jsonBody().keys())

    def test_representation_basics(self):
        spec = self.factory.makeSpecification()
        spec_webservice = self.getSpecOnWebservice(spec)
        with person_logged_in(ANONYMOUS):
            self.assertThat(
                spec_webservice,
                MatchesStructure.byEquality(
                    name=spec.name,
                    title=spec.title,
                    specification_url=spec.specurl,
                    summary=spec.summary,
                    implementation_status=spec.implementation_status.title,
                    definition_status=spec.definition_status.title,
                    priority=spec.priority.title,
                    date_created=spec.datecreated,
                    whiteboard=spec.whiteboard,
                    workitems_text=spec.workitems_text))

    def test_representation_contains_target(self):
        spec = self.factory.makeSpecification(
            product=self.factory.makeProduct())
        spec_target_name = spec.target.name
        spec_webservice = self.getSpecOnWebservice(spec)
        self.assertEqual(spec_target_name, spec_webservice.target.name)

    def test_representation_contains_assignee(self):
        # Hard-code the person's name or else we'd need to set up a zope
        # interaction as IPerson.name is protected.
        spec = self.factory.makeSpecification(
            assignee=self.factory.makePerson(name='test-person'))
        spec_webservice = self.getSpecOnWebservice(spec)
        self.assertEqual('test-person', spec_webservice.assignee.name)

    def test_representation_contains_drafter(self):
        spec = self.factory.makeSpecification(
            drafter=self.factory.makePerson(name='test-person'))
        spec_webservice = self.getSpecOnWebservice(spec)
        self.assertEqual('test-person', spec_webservice.drafter.name)

    def test_representation_contains_approver(self):
        spec = self.factory.makeSpecification(
            approver=self.factory.makePerson(name='test-person'))
        spec_webservice = self.getSpecOnWebservice(spec)
        self.assertEqual('test-person', spec_webservice.approver.name)

    def test_representation_contains_owner(self):
        spec = self.factory.makeSpecification(
            owner=self.factory.makePerson(name='test-person'))
        spec_webservice = self.getSpecOnWebservice(spec)
        self.assertEqual('test-person', spec_webservice.owner.name)

    def test_representation_contains_milestone(self):
        product = self.factory.makeProduct()
        productseries = self.factory.makeProductSeries(product=product)
        milestone = self.factory.makeMilestone(
            name="1.0", product=product, productseries=productseries)
        spec_object = self.factory.makeSpecification(
            product=product, goal=productseries, milestone=milestone)
        spec = self.getSpecOnWebservice(spec_object)
        self.assertEqual("1.0", spec.milestone.name)

    def test_representation_contains_dependencies(self):
        spec = self.factory.makeSpecification()
        spec2 = self.factory.makeSpecification()
        spec2_name = spec2.name
        spec.createDependency(spec2)
        spec_webservice = self.getSpecOnWebservice(spec)
        self.assertEqual(1, spec_webservice.dependencies.total_size)
        self.assertEqual(spec2_name, spec_webservice.dependencies[0].name)

    def test_representation_contains_linked_branches(self):
        spec = self.factory.makeSpecification()
        branch = self.factory.makeBranch()
        person = self.factory.makePerson()
        spec.linkBranch(branch, person)
        spec_webservice = self.getSpecOnWebservice(spec)
        self.assertEqual(1, spec_webservice.linked_branches.total_size)

    def test_representation_contains_bug_links(self):
        spec = self.factory.makeSpecification()
        bug = self.factory.makeBug()
        person = self.factory.makePerson()
        with person_logged_in(person):
            spec.linkBug(bug)
        spec_webservice = self.getSpecOnWebservice(spec)
        self.assertEqual(1, spec_webservice.bugs.total_size)
        self.assertEqual(bug.id, spec_webservice.bugs[0].id)

class SpecificationMutationTests(TestCaseWithFactory):

    layer = DatabaseFunctionalLayer

    def test_set_information_type(self):
        product = self.factory.makeProduct(
            specification_sharing_policy=(
                SpecificationSharingPolicy.PUBLIC_OR_PROPRIETARY))
        spec = self.factory.makeSpecification(product=product)
        self.assertEqual(InformationType.PUBLIC, spec.information_type)
        spec_url = api_url(spec)
        webservice = webservice_for_person(
            product.owner, permission=OAuthPermission.WRITE_PRIVATE)
        response = webservice.patch(
            spec_url, "application/json",
            json.dumps(dict(information_type='Proprietary')),
            api_version='devel')
        self.assertEqual(209, response.status)
        with admin_logged_in():
            self.assertEqual(
                InformationType.PROPRIETARY, spec.information_type)

    def test_set_target(self):
        old_target = self.factory.makeProduct()
        spec = self.factory.makeSpecification(product=old_target, name='foo')
        new_target = self.factory.makeProduct(displayname='Fooix')
        spec_url = api_url(spec)
        new_target_url = api_url(new_target)
        webservice = webservice_for_person(
            old_target.owner, permission=OAuthPermission.WRITE_PRIVATE)
        response = webservice.patch(
            spec_url, "application/json",
            json.dumps(dict(target_link=new_target_url)), api_version='devel')
        self.assertEqual(301, response.status)
        with admin_logged_in():
            self.assertEqual(new_target, spec.target)

            # Moving another spec with the same name fails.
            other_spec = self.factory.makeSpecification(
                product=old_target, name='foo')
            other_spec_url = api_url(other_spec)
        response = webservice.patch(
            other_spec_url, "application/json",
            json.dumps(dict(target_link=new_target_url)), api_version='devel')
        self.assertEqual(400, response.status)
        self.assertEqual(
            "There is already a blueprint named foo for Fooix.", response.body)

class SpecificationTargetTests(SpecificationWebserviceTestCase):
    """Tests for accessing specifications via their targets."""
    layer = AppServerLayer

    def test_get_specification_on_product(self):
        product = self.factory.makeProduct(name="fooix")
        self.factory.makeSpecification(
            product=product, name="some-spec")
        product_on_webservice = self.getPillarOnWebservice(product)
        spec = product_on_webservice.getSpecification(name="some-spec")
        self.assertEqual("some-spec", spec.name)
        self.assertEqual("fooix", spec.target.name)

    def test_get_specification_on_distribution(self):
        distribution = self.factory.makeDistribution(name="foobuntu")
        self.factory.makeSpecification(
            distribution=distribution, name="some-spec")
        distro_on_webservice = self.getPillarOnWebservice(distribution)
        spec = distro_on_webservice.getSpecification(name="some-spec")
        self.assertEqual("some-spec", spec.name)
        self.assertEqual("foobuntu", spec.target.name)

    def test_get_specification_on_productseries(self):
        product = self.factory.makeProduct(name="fooix")
        productseries = self.factory.makeProductSeries(
            product=product, name="fooix-dev")
        self.factory.makeSpecification(
            product=product, name="some-spec", goal=productseries)
        product_on_webservice = self.getPillarOnWebservice(product)
        productseries_on_webservice = product_on_webservice.getSeries(
            name="fooix-dev")
        spec = productseries_on_webservice.getSpecification(name="some-spec")
        self.assertEqual("some-spec", spec.name)
        self.assertEqual("fooix", spec.target.name)

    def test_get_specification_on_distroseries(self):
        distribution = self.factory.makeDistribution(name="foobuntu")
        distroseries = self.factory.makeDistroSeries(
            distribution=distribution, name="maudlin")
        self.factory.makeSpecification(
            distribution=distribution, name="some-spec",
            goal=distroseries)
        distro_on_webservice = self.getPillarOnWebservice(distribution)
        distroseries_on_webservice = distro_on_webservice.getSeries(
            name_or_version="maudlin")
        spec = distroseries_on_webservice.getSpecification(name="some-spec")
        self.assertEqual("some-spec", spec.name)
        self.assertEqual("foobuntu", spec.target.name)

    def test_get_specification_not_found(self):
        product = self.factory.makeProduct()
        product_on_webservice = self.getPillarOnWebservice(product)
        spec = product_on_webservice.getSpecification(name="nonexistant")
        self.assertEqual(None, spec)

class IHasSpecificationsTests(SpecificationWebserviceTestCase):
    """Tests for accessing IHasSpecifications methods over the webservice."""
    layer = DatabaseFunctionalLayer

    def assertNamesOfSpecificationsAre(self, expected_names, specifications):
        names = [s.name for s in specifications]
        self.assertContentEqual(expected_names, names)

    def test_anonymous_access_to_collection(self):
        product = self.factory.makeProduct()
        self.factory.makeSpecification(product=product, name="spec1")
        self.factory.makeSpecification(product=product, name="spec2")
        # Need to endInteraction() because launchpadlib_for_anonymous() will
        # setup a new one.
        endInteraction()
        lplib = launchpadlib_for('lplib-test', person=None, version='devel')
        ws_product = ws_object(lplib, removeSecurityProxy(product))
        self.assertNamesOfSpecificationsAre(
            ["spec1", "spec2"], ws_product.all_specifications)

    def test_product_all_specifications(self):
        product = self.factory.makeProduct()
        self.factory.makeSpecification(product=product, name="spec1")
        self.factory.makeSpecification(product=product, name="spec2")
        product_on_webservice = self.getPillarOnWebservice(product)
        self.assertNamesOfSpecificationsAre(
            ["spec1", "spec2"], product_on_webservice.all_specifications)

    def test_distribution_valid_specifications(self):
        distribution = self.factory.makeDistribution()
        self.factory.makeSpecification(
            distribution=distribution, name="spec1")
        self.factory.makeSpecification(
            distribution=distribution, name="spec2",
            status=SpecificationDefinitionStatus.OBSOLETE)
        distro_on_webservice = self.getPillarOnWebservice(distribution)
        self.assertNamesOfSpecificationsAre(
            ["spec1"], distro_on_webservice.valid_specifications)

class TestSpecificationSubscription(SpecificationWebserviceTestCase):

    layer = AppServerLayer

    def test_subscribe(self):
        # Test subscribe() API.
        with person_logged_in(ANONYMOUS):
            db_spec = self.factory.makeSpecification()
            db_person = self.factory.makePerson()
            launchpad = self.factory.makeLaunchpadService()

        spec = ws_object(launchpad, db_spec)
        person = ws_object(launchpad, db_person)
        spec.subscribe(person=person, essential=True)
        transaction.commit()

        # Check the results.
        sub = db_spec.subscription(db_person)
        self.assertIsNot(None, sub)
        self.assertTrue(sub.essential)

    def test_unsubscribe(self):
        # Test unsubscribe() API.
        with person_logged_in(ANONYMOUS):
            db_spec = self.factory.makeBlueprint()
            db_person = self.factory.makePerson()
            db_spec.subscribe(person=db_person)
            launchpad = self.factory.makeLaunchpadService(person=db_person)

        spec = ws_object(launchpad, db_spec)
        person = ws_object(launchpad, db_person)
        spec.unsubscribe(person=person)
        transaction.commit()

        # Check the results.
        self.assertFalse(db_spec.isSubscribed(db_person))

    def test_canBeUnsubscribedByUser(self):
        # Test canBeUnsubscribedByUser() API.
        webservice = LaunchpadWebServiceCaller(
            'launchpad-library', 'salgado-change-anything',
            domain='api.launchpad.dev:8085')

        with person_logged_in(ANONYMOUS):
            db_spec = self.factory.makeSpecification()
            db_person = self.factory.makePerson()
            launchpad = self.factory.makeLaunchpadService()

            spec = ws_object(launchpad, db_spec)
            person = ws_object(launchpad, db_person)
            subscription = spec.subscribe(person=person, essential=True)
            transaction.commit()

        result = webservice.named_get(
            subscription['self_link'], 'canBeUnsubscribedByUser').jsonBody()
        self.assertTrue(result)

class TestSpecificationBugLinks(SpecificationWebserviceTestCase):

    layer = AppServerLayer

    def test_bug_linking(self):
        # Set up a spec, person, and bug.
        with person_logged_in(ANONYMOUS):
            db_spec = self.factory.makeSpecification()
            db_person = self.factory.makePerson()
            db_bug = self.factory.makeBug()
            launchpad = self.factory.makeLaunchpadService()

        # Link the bug to the spec via the web service.
        with person_logged_in(db_person):
            spec = ws_object(launchpad, db_spec)
            bug = ws_object(launchpad, db_bug)
            # There are no bugs associated with the spec/blueprint yet.
            self.assertEqual(0, spec.bugs.total_size)
            spec.linkBug(bug=bug)
            transaction.commit()

        # The spec now has one bug associated with it and that bug is the one
        # we linked.
        self.assertEqual(1, spec.bugs.total_size)
        self.assertEqual(bug.id, spec.bugs[0].id)

    def test_bug_unlinking(self):
        # Set up a spec, person, and bug, then link the bug to the spec.
        with person_logged_in(ANONYMOUS):
            db_spec = self.factory.makeBlueprint()
            db_person = self.factory.makePerson()
            db_bug = self.factory.makeBug()
            launchpad = self.factory.makeLaunchpadService(person=db_person)

        spec = ws_object(launchpad, db_spec)
        bug = ws_object(launchpad, db_bug)
        spec.linkBug(bug=bug)

        # There is only one bug linked at the moment.
        self.assertEqual(1, spec.bugs.total_size)

        spec.unlinkBug(bug=bug)
        transaction.commit()

        # Now that we've unlinked the bug, there are no linked bugs at all.
        self.assertEqual(0, spec.bugs.total_size)

class TestSpecificationGoalHandling(SpecificationWebserviceTestCase):

    layer = AppServerLayer

    def setUp(self):
        super(TestSpecificationGoalHandling, self).setUp()
        self.driver = self.factory.makePerson()
        self.proposer = self.factory.makePerson()
        self.product = self.factory.makeProduct(driver=self.driver)
        self.series = self.factory.makeProductSeries(product=self.product)

    def test_goal_propose_and_accept(self):
        # Webservice clients can propose and accept spec series goals.
        db_spec = self.factory.makeBlueprint(product=self.product,
                                             owner=self.proposer)
        # Propose for series goal
        with person_logged_in(self.proposer):
            launchpad = self.factory.makeLaunchpadService(person=self.proposer)
            spec = ws_object(launchpad, db_spec)
            series = ws_object(launchpad, self.series)
            spec.proposeGoal(goal=series)
            transaction.commit()
            self.assertEqual(db_spec.goal, self.series)
            self.assertFalse(spec.has_accepted_goal)

        # Accept series goal
        with person_logged_in(self.driver):
            launchpad = self.factory.makeLaunchpadService(person=self.driver)
            spec = ws_object(launchpad, db_spec)
            spec.acceptGoal()
            transaction.commit()
            self.assertTrue(spec.has_accepted_goal)

    def test_goal_propose_decline_and_clear(self):
        # Webservice clients can decline and clear spec series goals.
        db_spec = self.factory.makeBlueprint(product=self.product,
                                             owner=self.proposer)
        # Propose for series goal
        with person_logged_in(self.proposer):
            launchpad = self.factory.makeLaunchpadService(person=self.proposer)
            spec = ws_object(launchpad, db_spec)
            series = ws_object(launchpad, self.series)
            spec.proposeGoal(goal=series)
            transaction.commit()
            self.assertEqual(db_spec.goal, self.series)
            self.assertFalse(spec.has_accepted_goal)

        with person_logged_in(self.driver):
            # Decline series goal
            launchpad = self.factory.makeLaunchpadService(person=self.driver)
            spec = ws_object(launchpad, db_spec)
            spec.declineGoal()
            transaction.commit()
            self.assertFalse(spec.has_accepted_goal)
            self.assertEqual(db_spec.goal, self.series)

            # Clear series goal as a driver
            spec.proposeGoal(goal=None)
            transaction.commit()
            self.assertIsNone(db_spec.goal)


import sys
import copy
import logging
import warnings
from pathlib import Path

import numpy as np
import yaml

from functools import partial
from multiprocessing.pool import Pool

from immuneML.data_model.encoded_data.EncodedData import EncodedData
from immuneML.environment.Label import Label
from immuneML.ml_methods.classifiers.MLMethod import MLMethod
from immuneML.ml_methods.util.Util import Util
from immuneML.ml_metrics.ClassificationMetric import ClassificationMetric
from immuneML.ml_metrics.MetricUtil import MetricUtil
from immuneML.util.PathBuilder import PathBuilder

class BinaryFeatureClassifier(MLMethod):
    """
    A simple classifier that takes in encoded data containing features with only 1/0 or True/False values.

    This classifier gives a positive prediction if any of the binary features for an example are 'true'.
    Optionally, the classifier can select an optimal subset of these features. In this case, the given data is split
    into a training and validation set, a minimal set of features is learned through greedy forward selection,
    and the validation set is used to determine when to stop growing the set of features (earlystopping).
    Earlystopping is reached when the optimization metric on the validation set no longer improves for a given number of features (patience).
    The optimization metric is the same metric as the one used for optimization in the :py:obj:`~immuneML.workflows.instructions.TrainMLModelInstruction`.

    Currently, this classifier can be used in combination with two encoders:

    - The classifier can be used in combination with the :py:obj:`~immuneML.encodings.motif_encoding.MotifEncoder.MotifEncoder`,
    such that sequences containing any of the positive class-associated motifs are classified as positive.
    A reduced subset of binding-associated motifs can be learned (when keep_all is false).
    This results in a set of complementary motifs, minimizing the redundant predictions made by different motifs.

    - Alternatively, this classifier can be combined with the :py:obj:`~immuneML.encodings.motif_encoding.SimilarToPositiveSequenceEncoder.SimilarToPositiveSequenceEncoder`
    such that any sequence that falls within a given hamming distance from any of the positive class sequences in the training set
    are classified as positive. Parameter keep_all should be set to true, since this encoder creates only 1 feature.

    Arguments:

        training_percentage (float): What percentage of data to use for training (the rest will be used for validation); values between 0 and 1

        keep_all (bool): Whether to keep all the input features (true) or learn a reduced subset (false). By default, keep_all is false.

        random_seed (int): Random seed for splitting the data into training and validation sets when learning a minimal subset of features. This is only used when keep_all is false.

        max_features (int): The maximum number of features to allow in the reduced subset. When this number is reached, no more features are added even if the earlystopping criterion is not reached yet.
        This is only used when keep_all is false. By default, max_features is 100.

        patience (int): The patience for earlystopping. When earlystopping is reached, <patience> more features are added to the reduced set to test whether the optimization metric on the validation set improves again. By default, patience is 5.

        min_delta (float): The delta value used to test if there was improvement between the previous set of features and the new set of features (+1). By default, min_delta is 0, meaning the new set of features does not need to yield a higher optimization metric score on the validation set, but it needs to be at least equally high as the previous set.

    YAML specification:

    .. indent with spaces
    .. code-block:: yaml

        my_motif_classifier:
            MotifClassifier:
                training_percentage: 0.7
                max_features: 100
                patience: 5
                min_delta: 0
                keep_all: false

    """

    def __init__(self, training_percentage: float = None,
                 random_seed: int = None, max_features: int = None, patience: int = None,
                 min_delta: float = None, keep_all: bool = None,
                 result_path: Path = None):
        super().__init__()
        self.training_percentage = training_percentage
        self.random_seed = random_seed
        self.max_features = max_features
        self.patience = patience
        self.min_delta = min_delta
        self.keep_all = keep_all

        self.train_indices = None
        self.val_indices = None
        self.feature_names = None
        self.rule_tree_indices = None
        self.rule_tree_features = None
        self.label = None
        self.optimization_metric = None
        self.class_mapping = None

        self.result_path = result_path

    def predict(self, encoded_data: EncodedData, label: Label):
        self._check_features(encoded_data.feature_names)

        return {self.label.name: self._get_rule_tree_predictions_class(encoded_data, self.rule_tree_indices)}

    def predict_proba(self, encoded_data: EncodedData, label: Label):
        warnings.warn(f"{BinaryFeatureClassifier.__name__}: cannot predict probabilities.")
        return None

    def fit(self, encoded_data: EncodedData, label: Label, optimization_metric: str, cores_for_training: int = 2):
        self.feature_names = encoded_data.feature_names
        self.label = label
        self.class_mapping = Util.make_binary_class_mapping(encoded_data.labels[self.label.name])
        self.optimization_metric = optimization_metric

        self.rule_tree_indices = self._build_rule_tree(encoded_data, cores_for_training)
        self.rule_tree_features = self._get_rule_tree_features_from_indices(self.rule_tree_indices, self.feature_names)
        self._export_selected_features(self.result_path, self.rule_tree_features)

        logging.info(f"{BinaryFeatureClassifier.__name__}: finished training.")

    def _get_optimization_scoring_fn(self):
        return MetricUtil.get_metric_fn(ClassificationMetric[self.optimization_metric.upper()])

    def _build_rule_tree(self, encoded_data, cores_for_training):
        if self.keep_all:
            rules = list(range(len(self.feature_names)))
            logging.info(f"{BinaryFeatureClassifier.__name__}: all {len(rules)} rules kept.")
        else:
            encoded_train_data, encoded_val_data = self._prepare_and_split_data(encoded_data)
            if self.max_features is None:
                self.max_features = encoded_train_data.examples.shape[1]

            rules = self._start_recursive_search(encoded_train_data, encoded_val_data, cores_for_training)

            logging.info(f"{BinaryFeatureClassifier.__name__}: selected {len(rules)} out of {len(self.feature_names)} rules.")

        return rules

    def _start_recursive_search(self, encoded_train_data, encoded_val_data, cores_for_training):
        old_recursion_limit = sys.getrecursionlimit()
        new_recursion_limit = old_recursion_limit + encoded_train_data.examples.shape[1]
        sys.setrecursionlimit(new_recursion_limit)

        rules = self._recursively_select_rules(encoded_train_data=encoded_train_data,
                                               encoded_val_data=encoded_val_data,
                                               index_candidates=list(range(encoded_train_data.examples.shape[1])),
                                               prev_rule_indices=[],
                                               prev_train_predictions=np.array([False] * encoded_train_data.examples.shape[0]),
                                               prev_val_predictions=np.array([False] * encoded_val_data.examples.shape[0]),
                                               prev_val_scores=[],
                                               cores_for_training=cores_for_training)

        sys.setrecursionlimit(old_recursion_limit)

        return rules

    def _get_rule_tree_features_from_indices(self, rule_tree_indices, feature_names):
        return [feature_names[idx] for idx in rule_tree_indices]

    def _recursively_select_rules(self, encoded_train_data, encoded_val_data, index_candidates, prev_rule_indices, prev_train_predictions, prev_val_predictions, prev_val_scores, cores_for_training):
        new_rule_indices, new_train_predictions, new_index_candidates = self._add_next_best_rule(encoded_train_data, prev_rule_indices, prev_train_predictions, index_candidates, cores_for_training)

        if new_rule_indices == prev_rule_indices:
            logging.info(f"{BinaryFeatureClassifier.__name__}: no improvement on training set")
            return self._get_optimal_indices(prev_rule_indices, self._test_is_improvement(prev_val_scores, self.min_delta))

        logging.info(f"{BinaryFeatureClassifier.__name__}: added rule {len(new_rule_indices)}/{min(self.max_features, encoded_train_data.examples.shape[1])} ({len(new_index_candidates)} candidates left)")

        new_val_predictions = np.logical_or(prev_val_predictions, encoded_val_data.examples[:, new_rule_indices[-1]])
        new_val_scores = prev_val_scores + [self._test_performance_predictions(encoded_val_data, pred=new_val_predictions)]
        is_improvement = self._test_is_improvement(new_val_scores, self.min_delta)

        if len(new_rule_indices) >= self.max_features:
            logging.info(f"{BinaryFeatureClassifier.__name__}: max features reached")
            return self._get_optimal_indices(new_rule_indices, is_improvement)

        if self._test_earlystopping(is_improvement):
            logging.info(f"{BinaryFeatureClassifier.__name__}: earlystopping criterion reached")
            return self._get_optimal_indices(new_rule_indices, is_improvement)

        return self._recursively_select_rules(encoded_train_data, encoded_val_data,
                                              prev_rule_indices=new_rule_indices,
                                              index_candidates=new_index_candidates,
                                              prev_train_predictions=new_train_predictions,
                                              prev_val_predictions=new_val_predictions,
                                              prev_val_scores=new_val_scores,
                                              cores_for_training=cores_for_training)

    def _test_earlystopping(self, is_improvement):
        # patience has not reached yet, continue training
        if len(is_improvement) < self.patience:
            return False

        # last few trees did not improve, stop training
        if not any(is_improvement[-self.patience:]):
            return True

        return False

    def _test_is_improvement(self, scores, min_delta):
        if len(scores) == 0:
            return []

        best = scores[0]
        is_improvement = [True]

        for score in scores[1:]:
            if score > best + min_delta:
                best = score
                is_improvement.append(True)
            else:
                is_improvement.append(False)

        return is_improvement

    def _get_optimal_indices(self, rule_indices, is_improvement):
        if len(rule_indices) == 0:
            return []

        optimal_tree_idx = max([i if is_improvement[i] else -1 for i in range(len(is_improvement))])

        return rule_indices[:optimal_tree_idx + 1]

    def _add_next_best_rule(self, encoded_train_data, prev_rule_indices, prev_predictions, index_candidates, cores_for_training):
        if len(index_candidates) == 0:
            return prev_rule_indices, prev_predictions, []

        prev_train_performance = self._test_performance_predictions(encoded_train_data, pred=prev_predictions)
        new_training_performances = self._test_new_train_performances(encoded_train_data, prev_predictions,
                                                                      index_candidates, prev_train_performance, cores_for_training)

        best_new_performance = max(new_training_performances)
        best_new_index = index_candidates[new_training_performances.index(best_new_performance)]
        new_index_candidates = [index_candidates[i] for i, new_performance in enumerate(new_training_performances) if new_performance > prev_train_performance]

        if best_new_performance > prev_train_performance:
            new_rule_indices = prev_rule_indices + [best_new_index]
            new_predictions = np.logical_or(prev_predictions, encoded_train_data.examples[:, best_new_index])

            return new_rule_indices, new_predictions, new_index_candidates
        else:
            return prev_rule_indices, prev_predictions, new_index_candidates

    def _test_new_train_performances(self, encoded_train_data, prev_predictions, index_candidates,
                                     prev_train_performance, cores_for_training):
        y_true_train = Util.map_to_new_class_values(encoded_train_data.labels[self.label.name], self.class_mapping)

        example_weights = encoded_train_data.example_weights

        with Pool(cores_for_training) as pool:
            partial_func = partial(self._apply_optimization_fn_to_new_rule_combo, y_true_train=y_true_train,
                                   example_weights=example_weights, prev_predictions=prev_predictions,
                                   prev_train_performance=prev_train_performance)
            scores = pool.map(partial_func, encoded_train_data.examples[:, index_candidates].T)
        return scores

    def _apply_optimization_fn_to_new_rule_combo(self, new_rule_predictions,
                                                 y_true_train, example_weights,
                                                 prev_predictions, prev_train_performance):
        new_predictions = np.logical_or(prev_predictions, new_rule_predictions)

        if np.array_equal(new_predictions, prev_predictions):
            return prev_train_performance
        else:
            optimization_scoring_fn = self._get_optimization_scoring_fn()
            return optimization_scoring_fn(y_true=y_true_train,
                                           y_pred=new_predictions,
                                           sample_weight=example_weights)

    # def _apply_optimization_fn_to_new_rule_combo(self, optimization_scoring_fn, examples, y_true_train,
    #                                              example_weights, prev_predictions, new_rule_idx):
    #     return optimization_scoring_fn(y_true=y_true_train,
    #                                    y_pred=np.logical_or(prev_predictions, examples[:, new_rule_idx]),
    #                                    sample_weight=example_weights)
    #

    def _get_unused_rule_indices(self, encoded_train_data, rule_indices):
        return [idx for idx in range(encoded_train_data.examples.shape[1]) if idx not in rule_indices]

    def _test_performance_predictions(self, encoded_data, pred):
        y_true = Util.map_to_new_class_values(encoded_data.labels[self.label.name], self.class_mapping)
        optimization_scoring_fn = self._get_optimization_scoring_fn()

        return optimization_scoring_fn(y_true=y_true, y_pred=pred, sample_weight=encoded_data.example_weights)

    def _get_new_performances(self, encoded_data, prev_predictions, new_indices_to_test):
        return [self._test_performance_predictions(encoded_data=encoded_data,
                                                   pred=np.logical_or(prev_predictions, encoded_data.examples[:, idx]))
                for idx in new_indices_to_test]

    def _test_performance_rule_tree(self, encoded_data, rule_indices):
        pred = self._get_rule_tree_predictions_bool(encoded_data, rule_indices)
        return self._test_performance_predictions(encoded_data, pred=pred)

    def _get_rule_tree_predictions_bool(self, encoded_data, rule_indices):
        return np.logical_or.reduce([encoded_data.examples[:, i] for i in rule_indices])

    def _get_rule_tree_predictions_class(self, encoded_data, rule_indices):
        y = self._get_rule_tree_predictions_bool(encoded_data, rule_indices).astype(int)
        return Util.map_to_old_class_values(y, self.class_mapping)

    def _check_features(self, encoded_data_features):
        if self.feature_names != encoded_data_features:
            mssg = f"{BinaryFeatureClassifier.__name__}: features during evaluation did not match the features set during fitting."

            logging.info(mssg + f"\n\nEvaluation features: {encoded_data_features}\nFitting features: {self.feature_names}")
            raise ValueError(mssg + " See the log file for more info.")

    def _export_selected_features(self, path, rule_tree_features):
        if path is not None:
            PathBuilder.build(path)
            with open(path / "selected_features.txt", "w") as file:
                file.writelines([f"{feature}\n" for feature in rule_tree_features])

    def fit_by_cross_validation(self, encoded_data: EncodedData, label: Label = None, optimization_metric: str = None,
                                number_of_splits: int = 5, cores_for_training: int = -1):
        logging.warning(f"{BinaryFeatureClassifier.__name__}: cross_validation is not implemented for this method. Using standard fitting instead...")
        self.fit(encoded_data=encoded_data, label=label)

    def _prepare_and_split_data(self, encoded_data: EncodedData):
        train_indices, val_indices = Util.get_train_val_indices(len(encoded_data.example_ids), self.training_percentage, random_seed=self.random_seed)

        self.train_indices = train_indices
        self.val_indices = val_indices

        train_data = Util.subset_encoded_data(encoded_data, train_indices)
        val_data = Util.subset_encoded_data(encoded_data, val_indices)

        return train_data, val_data

    def store(self, path: Path, feature_names=None, details_path: Path = None):
        PathBuilder.build(path)

        custom_vars = copy.deepcopy(vars(self))
        del custom_vars["result_path"]

        if self.label:
            custom_vars["label"] = {key.lstrip("_"): value for key, value in vars(self.label).items()}

        params_path = path / "custom_params.yaml"
        with params_path.open('w') as file:
            yaml.dump(custom_vars, file)

    def load(self, path):
        params_path = path / "custom_params.yaml"
        with params_path.open("r") as file:
            custom_params = yaml.load(file, Loader=yaml.SafeLoader)

        for param, value in custom_params.items():
            if hasattr(self, param):
                if param == "label":
                    setattr(self, "label", Label(**value))
                else:
                    setattr(self, param, value)

    def check_if_exists(self, path):
        return self.rule_tree_indices is not None

    def get_params(self):
        params = copy.deepcopy(vars(self))
        return params

    def get_label_name(self):
        return self.label.name

    def get_package_info(self) -> str:
        return Util.get_immuneML_version()

    def get_feature_names(self) -> list:
        return self.feature_names

    def can_predict_proba(self) -> bool:
        return False

    def get_class_mapping(self) -> dict:
        return self.class_mapping

    def get_compatible_encoders(self):
        from immuneML.encodings.motif_encoding.MotifEncoder import MotifEncoder
        from immuneML.encodings.motif_encoding.SimilarToPositiveSequenceEncoder import SimilarToPositiveSequenceEncoder
        return [MotifEncoder, SimilarToPositiveSequenceEncoder]


from django.urls import path, include
from rest_framework import routers
from . import views
from .views import PizzaViewSet

app_name = 'fastfood'
router = routers.SimpleRouter()
router.register(r'', PizzaViewSet)

urlpatterns = [
    path('pizza', views.pizza, name='pizza'),
    path('burgers', views.burgers, name='burgers'),
    path('order', views.order, name='order'),
    path('success', views.success, name='success'),
    path('login', views.logIn, name='login'),
    path('logout', views.logOut, name='logout'),
    path('', include(router.urls,)),
]


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Roman Moser, 1/12/19

"""
Quora Insincere Questions - prepare data with word2vec
run with: python3 main.py
"""

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from gensim.models import Word2Vec
import os
os.chdir('/home/roman/Documents/Projects/Quora/data')

def main():
    # load data:
    data = pd.read_csv('train.csv')
    X_train, X_val, y_train, y_val = train_test_split(data['question_text'], \
        data['target'], test_size=0.1, random_state=123)
    y_train_np = np.array(y_train)
    y_val_np = np.array(y_val)
    np.save('y_train', y_train_np)
    np.save('y_val', y_val_np)
    # Prepare data with Word2Vec embedding:
    # load w2v model
    os.chdir('../models')
    size = 150
    filename = 'w2v_w5_s150'
    model = Word2Vec.load(filename + '.model')
    w2v = dict(zip(model.wv.index2word, model.wv.syn0))

    X_train_texts = [[word for word in document.lower().split()] for document in X_train]
    X_val_texts = [[word for word in document.lower().split()] for document in X_val]

    X_train_texts_w2v_mean = np.array([np.mean([w2v[word] if word in w2v else \
            np.zeros(size) for word in text], axis=0) for text in X_train_texts])
    X_val_texts_w2v_mean = np.array([np.mean([w2v[word] if word in w2v else \
            np.zeros(size) for word in text], axis=0) for text in X_val_texts])
    os.chdir('../data')
    np.save('X_train_' + filename, X_train_texts_w2v_mean)
    np.save('X_val_' + filename, X_val_texts_w2v_mean)

if __name__ == '__main__':
        main()


import wx.grid

class MyGrid(wx.grid.Grid):
    def __init__(self, parent):
        super(MyGrid, self).__init__(parent=parent)

    def set_cell_value(self, row, col, value):
        if isinstance(value, (int, float)):
            value = str(value)
        self.SetCellValue(row, col, value)

    def get_selected_rows(self):
        if self.GetSelectedRows():
            return self.GetSelectedRows()
        if self.GetSelectedCells():
            return [row[0] for row in self.GetSelectedCells()]
        if self.GetSelectionBlockTopLeft():
            top_row = self.GetSelectionBlockTopLeft()[0][0]
            bottom_row = self.GetSelectionBlockBottomRight()[0][0]
            return list(range(top_row, bottom_row+1))
        return [self.GetGridCursorRow()]


from PySimpleGUI import PySimpleGUI as program
import requests
#layout and window
#set theme
program.theme('Dark')
#set layout
layout = [
    [program.Text('INFO'),program.Input(key='info')],
    [program.Button('check')]
]

window = program.Window('info check', layout)

#events
while True:
    event, checkValors = window.read()
    content = checkValors['info']

    if event == program.WIN_CLOSED:
        break
    if event == 'check':
        try:
            int(content)
            data = requests.get('https://cep.awesomeapi.com.br/json/{}'.format(content))
            data = data.json()
            cep = data['cep']
            street = data['address_name']
            state = data['state']
            district = data['district']
            lat = data['lat']
            lng = data['lng']
            city = data['city']
            ibge = data['city_ibge']
            ddd = data['ddd']
            print(cep, street, state, district, lat, lng, city, ibge, ddd)
            window.hide()

        except:
           pass


import boto3
import os
import sys
import awswrangler as wr
from awsglue.utils import getResolvedOptions

class RawProcessing():
    def __init__(self) -> None:
        args = getResolvedOptions(
            sys.argv,
            ['aws_bucket_source',
            'aws_bucket_target',
            'database',
            'table'])
        self.s3_resource = boto3.resource('s3')
        self.glue_client = boto3.client('glue')
        self.aws_bucket_source = args['aws_bucket_source']
        self.aws_bucket_target = args['aws_bucket_target']
        self.boto_session = boto3.session.Session(region_name='us-east-1')
        self.db = args['database']
        self.tb = args['table']

    def df_to_parquet(self, dataframe, partition_cols, aws_bucket, db, tb):
        """
        Save a pandas dataframe data in S3 with
        Parquet format whit snappy compression.
        Catalog data into Glue table
        Inputs:
            dataframe: data to save in pandas dataframe
            partition_cols: list of columns to create a partition data
            aws_bucket: bucket where information is storage
            db: database where data is cataloged
            tb: table where data is putting

        """
        wr.s3.to_parquet(
            df=dataframe,
            path=f's3://{aws_bucket}',
            index=False,
            compression='snappy',
            boto3_session=self.boto_session,
            dataset=True,
            partition_cols=partition_cols,
            concurrent_partitioning=True,
            catalog_versioning=True,
            mode='overwrite_partitions',
            database=db,
            table=tb
            )

    def read_csv_s3(self, aws_bucket, filename, sep=','):
        '''
        Read a comma-separated values (csv) file into DataFrame and save it into S3
        Input:
            aws_bucket: s3 bucket where information is storage
            filename: file name in format csv who has the information
            sep: file separator
        Output:
            df: Conversion csv file into dataframe.
        '''
        df = wr.s3.read_csv(
            path=f's3://{aws_bucket}/{filename}',
            sep=sep,
            header=0,
            index_col=False
            )
        return df

    def processing_data(self):
        """
        Orchestration process
        Cleaning and transform data
        """
        for obj in self.s3_resource.Bucket(self.aws_bucket_source).objects.all():
            file_name = obj.key
            name = os.path.splitext(file_name)[:-1][0]
            partition_city = name.split('-')[1]

            #Read csv into dataframe
            df = self.read_csv_s3(self.aws_bucket_source, file_name)
            df['city'] = partition_city

            # Identify day, month and year for star range date
            date_range = df['Date Range'].unique()
            for date in date_range:
                month, day, year = date.split('-')[0].split('/')
                df.loc[df['Date Range'] == date, 'month'] = month
                df.loc[df['Date Range'] == date, 'day'] = day
                df.loc[df['Date Range'] == date, 'year'] = year

            #Change data types
            df['Origin Movement ID'] = df['Origin Movement ID'].astype('object')
            df['Destination Movement ID'] = df['Destination Movement ID'].astype('object')
            df['Mean Travel Time (Seconds)'] = df['Mean Travel Time (Seconds)'].astype('float')
            df['Range - Lower Bound Travel Time (Seconds)'] = df['Range - Lower Bound Travel Time (Seconds)'].astype('float')
            df['Range - Upper Bound Travel Time (Seconds)'] = df['Range - Upper Bound Travel Time (Seconds)'].astype('float')
            partition_cols = ['city', 'month', 'day', 'year']

            self.df_to_parquet(df, partition_cols, self.aws_bucket_target, self.db, self.tb)

if __name__ == '__main__':
    process = RawProcessing()
    process.processing_data()


"""
snowball.py: A snowball cog that implements a version of Discord's 2021 Snowball Bot game.

References
----------
Rules and code inspiration.
https://web.archive.org/web/20220103003050/https://support.discord.com/hc/en-us/articles/4414111886359-Snowsgiving-2021-Snowball-Bot-FAQ
https://github.com/0xMukesh/snowball-bot
"""

from __future__ import annotations

import json
import logging
import pathlib
import random
from itertools import cycle, islice
from typing import Any

import asyncpg
import discord
from discord import app_commands
from discord.ext import commands

import core
from core.utils import EMOJI_STOCK, StatsEmbed

from .utils import (
    GuildSnowballSettings,
    SnowballSettingsView,
    UserSnowballUpdate,
    collect_cooldown,
    steal_cooldown,
    transfer_cooldown,
)

LOGGER = logging.getLogger(__name__)

LEADERBOARD_MAX = 10  # Number of people shown on one leaderboard at a time.

class SnowballCog(commands.Cog, name="Snowball"):
    """A cog that implements all snowball fight-related commands, like Discord's 2021 Snowball bot game.

    Parameters
    ----------
    bot : :class:`Beira`
        The main Discord bot this cog is a part of.

    Attributes
    ----------
    embed_data : :class:`dict`
        A dictionary with strings that embeds will use in this cog, depending on the state and functions. It's loaded in
        from a json file before the bot connects to the Discord Gateway.
    """

    def __init__(self, bot: core.Beira) -> None:
        self.bot = bot
        self.embed_data: dict[str, Any] = {}

    @property
    def cog_emoji(self) -> discord.PartialEmoji:
        """:class:`discord.PartialEmoji`: A partial emoji representing this cog."""

        return discord.PartialEmoji(name="snowflake", animated=True, id=1077980648867901531)

    async def cog_load(self) -> None:
        """Load the embed data for various snowball commands before the bot connects to the Discord Gateway."""

        with pathlib.Path("data/snowball_embed_data.json").open(encoding="utf-8") as data_file:
            self.embed_data = json.load(data_file)

    async def cog_command_error(self, ctx: core.Context, error: Exception) -> None:  # type: ignore # Narrowing
        """Handles errors that occur within this cog.

        For example, when using prefix commands, this will tell users if they are missing arguments. Other error cases
        will be added as needed.

        Parameters
        ----------
        ctx : :class:`core.Context`
            The invocation context where the error happened.
        error : :class:`Exception`
            The error that happened.
        """

        assert ctx.command is not None

        # Extract the original error.
        error = getattr(error, "original", error)
        if ctx.interaction:
            error = getattr(error, "original", error)

        embed = discord.Embed(color=0x5E9A40)

        if isinstance(error, commands.MissingRequiredArgument):
            embed.title = "Missing Parameter!"
            embed.description = "This command needs a target."
            ctx.command.reset_cooldown(ctx)
        elif isinstance(error, commands.CommandOnCooldown):
            embed.title = "Command on Cooldown!"
            embed.description = f"Please wait {error.retry_after:.2f} seconds before trying this command again."
        elif isinstance(error, core.CannotTargetSelf):
            embed.title = "No Targeting Yourself!"
            embed.description = (
                "Are you a masochist or do you just like the taste of snow? Regardless, no hitting yourself in the "
                "face."
            )
        else:
            embed.title = f"{ctx.command.name}: Unknown Command Error"
            embed.description = (
                "Maybe the snowballs are revolting. Maybe you hit a beehive. Regardless, there's some kind of error. "
                "Please try again in a minute or two."
            )
            LOGGER.exception("", exc_info=error)

        await ctx.send(embed=embed, ephemeral=True)

    @commands.hybrid_group()
    async def snow(self, ctx: core.Context) -> None:
        """A group of snowball-related commands."""

        await ctx.send_help(ctx.command)

    @snow.command()
    @commands.guild_only()
    async def settings(self, ctx: core.GuildContext) -> None:
        """Show what the settings are for the snowballs in this server."""

        # Get the settings for the guild and make an embed display.
        guild_settings = await GuildSnowballSettings.from_database(ctx.db, ctx.guild.id)
        view = SnowballSettingsView(ctx.guild.name, guild_settings)

        send_kwargs: dict[str, Any] = {"embed": view.format_embed()}

        # Only send the view with the embed if invoker has certain perms.
        if ctx.author.id == self.bot.owner_id or await core.is_admin().predicate(ctx):
            send_kwargs["view"] = view

        message = await ctx.send(**send_kwargs)

        if "view" in send_kwargs:
            send_kwargs["view"].message = message

    @snow.command()
    @commands.guild_only()
    @commands.dynamic_cooldown(collect_cooldown, commands.cooldowns.BucketType.user)  # type: ignore
    async def collect(self, ctx: core.GuildContext) -> None:
        """Collects a snowball."""

        # Get the snowball settings for this particular guild.
        guild_snow_settings = getattr(ctx, "guild_snow_settings", GuildSnowballSettings(ctx.guild.id))
        base_stock_cap = guild_snow_settings.stock_cap

        # Only special people get the higher snowball limit.
        privilege_check = bool(ctx.author.id == self.bot.owner_id or self.bot.is_ali(ctx.author))
        stock_limit = base_stock_cap * 2 if privilege_check else base_stock_cap

        record = await UserSnowballUpdate(ctx.author, stock=1).upsert_record(ctx.db)

        embed = discord.Embed(color=0x5E62D3)
        if record:
            if record["stock"] < stock_limit:
                embed.description = (
                    f"Slapping on your warmest pair of gloves, you gathered some snow and started shaping"
                    f"some snowballs. You now have {record['stock']} of them—let 'em fly!"
                )
                embed.set_image(url=random.choice(self.embed_data["collects"]["image_success"]))

            else:
                embed.description = (
                    f"You've filled your armory to the brim with about {stock_limit} snowballs! Release "
                    f"some of your stores to make space for more."
                )
                embed.set_image(url=self.embed_data["collects"]["image_failure"])

            await ctx.send(embed=embed, ephemeral=True, delete_after=60.0)

    @snow.command()
    @commands.guild_only()
    @app_commands.describe(target="Who do you want to throw a snowball at?")
    async def throw(self, ctx: core.GuildContext, *, target: discord.Member) -> None:
        """Start a snowball fight with another server member.

        Parameters
        ----------
        ctx : :class:`core.GuildContext`
            The invocation context.
        target : :class:`discord.Member`
            The user to hit with a snowball.
        """

        if target == ctx.author:
            msg = "You cannot target yourself with this argument."
            raise core.CannotTargetSelf(msg)

        # Get the snowball settings for this particular guild.
        guild_snow_settings = getattr(ctx, "guild_snow_settings", GuildSnowballSettings(ctx.guild.id))
        base_hit_odds = guild_snow_settings.hit_odds

        message = ""
        embed = discord.Embed(color=0x60FF60)
        ephemeral = False

        query = "SELECT hits, misses, kos, stock FROM snowball_stats WHERE guild_id = $1 AND user_id = $2"
        record = await ctx.db.fetchrow(query, ctx.guild.id, ctx.author.id)

        # The user has to be in the database and have collected at least one snowball before they can throw one.
        if (record is not None) and (record["stock"] > 0):
            roll = random.random()

            # Update the database records and prepare the response message and embed based on the outcome.
            if roll < base_hit_odds:
                async with ctx.db.acquire() as conn, conn.transaction():
                    await UserSnowballUpdate(ctx.author, hits=1, stock=-1).upsert_record(conn)  # type: ignore
                    await UserSnowballUpdate(target, kos=1).upsert_record(conn)  # type: ignore

                embed.description = random.choice(self.embed_data["hits"]["notes"]).format(target.mention)
                embed.set_image(url=random.choice(self.embed_data["hits"]["gifs"]))
                message = target.mention

            else:
                await UserSnowballUpdate(ctx.author, misses=1).upsert_record(ctx.db)

                misses_text = random.choice(self.embed_data["misses"]["notes"])
                embed.colour = 0xFFA600
                embed.description = misses_text.format(target.mention) if "{}" in misses_text else misses_text
                embed.set_image(url=random.choice(self.embed_data["misses"]["gifs"]))

        else:
            embed.colour = 0x000000
            embed.description = "Oops! You don't have any snowballs. Use the /collect command to stock up!"
            embed.set_image(url="https://media.tenor.com/wNdxxIIt1zEAAAAC/polar-vortex-winter-break.gif")
            ephemeral = True

        await ctx.send(content=message, embed=embed, ephemeral=ephemeral)

    @snow.command()
    @commands.guild_only()
    @commands.dynamic_cooldown(transfer_cooldown, commands.cooldowns.BucketType.user)  # type: ignore
    @app_commands.describe(receiver="Who do you want to give some balls? You can't transfer more than 10 at a time.")
    async def transfer(self, ctx: core.GuildContext, amount: int, *, receiver: discord.Member) -> None:
        """Give another server member some of your snowballs, though no more than 10 at a time.

        Parameters
        ----------
        ctx : :class:`core.GuildContext`
            The invocation context.
        amount : :class:`int`
            The number of snowballs to transfer. If is greater than 10, pushes the receiver's snowball stock past the
            stock cap, or brings the giver's balance below zero, the transfer fails.
        receiver : :class:`discord.Member`
            The user to bestow snowballs upon.
        """

        if receiver == ctx.author:
            msg = "You cannot target yourself with this argument."
            raise core.CannotTargetSelf(msg)

        # Get the snowball settings for this particular guild.
        guild_snow_settings = getattr(ctx, "guild_snow_settings", GuildSnowballSettings(ctx.guild.id))
        base_transfer_cap = guild_snow_settings.transfer_cap
        base_stock_cap = guild_snow_settings.stock_cap

        # Only special people get the higher snowball limit.
        privilege_check = bool(ctx.author.id == self.bot.owner_id or self.bot.is_ali(ctx.author))
        stock_limit = base_stock_cap * 2 if privilege_check else base_stock_cap

        # Build on an embed.
        def_embed = discord.Embed(color=0x69FF69)

        # Set a limit on how many snowballs can be transferred at a time.
        if amount > base_transfer_cap:
            def_embed.description = "10 snowballs at once is the bulk giving limit."
            await ctx.send(embed=def_embed, ephemeral=True)
            return

        query = "SELECT hits, misses, kos, stock FROM snowball_stats WHERE guild_id = $1 AND user_id = $2"
        async with ctx.db.acquire() as conn, conn.transaction():
            giver_record = await conn.fetchrow(query, ctx.guild.id, ctx.author.id)
            receiver_record = await conn.fetchrow(query, ctx.guild.id, receiver.id)

        # In case of failed transfer, send one of these messages.
        if (giver_record is not None) and (giver_record["stock"] - amount < 0):
            def_embed.description = (
                "You don't have that many snowballs to give. Find a few more with /collect and you might "
                "be able give that many soon!"
            )
            await ctx.send(embed=def_embed, ephemeral=True)
            return

        if (receiver_record is not None) and (receiver_record["stock"] + amount > stock_limit):
            def_embed.description = (
                f"Your friend has enough snowballs; this transfer would push them past the stock cap of "
                f"{stock_limit}. If you think about it, with that many in hand, do they need yours too?"
            )
            await ctx.send(embed=def_embed, ephemeral=True)
            return

        # Update the giver and receiver's records.
        async with ctx.db.acquire() as conn, conn.transaction():
            await UserSnowballUpdate(ctx.author, stock=-amount).upsert_record(conn)  # type: ignore
            await UserSnowballUpdate(receiver, stock=amount).upsert_record(conn)  # type: ignore

        # Send notification message of successful transfer.
        def_embed.description = f"Transfer successful! You've given {receiver.mention} {amount} of your snowballs!"
        message = f"{ctx.author.mention}, {receiver.mention}"
        await ctx.send(content=message, embed=def_embed, ephemeral=False)

    @snow.command()
    @commands.guild_only()
    @core.is_owner_or_friend()
    @commands.dynamic_cooldown(steal_cooldown, commands.cooldowns.BucketType.user)  # type: ignore
    @app_commands.describe(
        amount="How much do you want to steal? (No more than 10 at a time)",
        victim="Who do you want to pilfer some balls from?",
    )
    async def steal(self, ctx: core.GuildContext, amount: int, *, victim: discord.Member) -> None:
        """Steal snowballs from another server member, though no more than 10 at a time.

        Parameters
        ----------
        ctx : :class:`core.GuildContext`
            The invocation context.
        amount : :class:`int`
            The number of snowballs to steal. If is greater than 10, pushes the receiver's snowball stock past the
            stock cap, or brings the giver's balance below zero, then the steal fails.
        victim : :class:`discord.Member`
            The user to steal snowballs from.
        """

        if victim == ctx.author:
            msg = "You cannot target yourself with this argument."
            raise core.CannotTargetSelf(msg)

        # Get the snowball settings for this particular guild.
        guild_snow_settings = getattr(ctx, "guild_snow_settings", GuildSnowballSettings(ctx.guild.id))
        base_transfer_cap = guild_snow_settings.transfer_cap
        base_stock_cap = guild_snow_settings.stock_cap

        # Only special people get the higher snowball limit.
        privilege_check = bool(ctx.author.id == self.bot.owner_id or self.bot.is_ali(ctx.author))
        stock_limit = base_stock_cap * 2 if privilege_check else base_stock_cap

        # Build on an embed.
        def_embed = discord.Embed(color=0x69FF69)

        # Set a limit on how many snowballs can be stolen at a time.
        if (amount > base_transfer_cap) and (ctx.author.id not in self.bot.special_friends.values()):
            def_embed.description = "10 snowballs at once is the bulk stealing limit."
            await ctx.send(embed=def_embed, ephemeral=True)
            return

        query = "SELECT hits, misses, kos, stock FROM snowball_stats WHERE guild_id = $1 AND user_id = $2"
        async with ctx.db.acquire() as conn, conn.transaction():
            thief_record = await conn.fetchrow(query, ctx.guild.id, ctx.author.id)
            victim_record = await conn.fetchrow(query, ctx.guild.id, victim.id)

        # In case of failed steal, send one of these messages.
        if (
            (victim_record is not None)
            and (victim_record["stock"] - amount < 0)
            and ctx.author.id not in self.bot.special_friends.values()
        ):
            def_embed.description = (
                "They don't have that much to steal. Wait for them to collect a few more, or "
                "pilfer a smaller number."
            )
            await ctx.send(embed=def_embed, ephemeral=True)
            return

        if (thief_record is not None) and (thief_record["stock"] + amount > stock_limit):
            def_embed.description = (
                f"You enough snowballs; this transfer would push you past the stock cap of "
                f"{stock_limit}. Use some of your balls before you decide to rob some hapless soul."
            )
            await ctx.send(embed=def_embed, ephemeral=True)
            return

        # Update the giver and receiver's records.
        async with ctx.db.acquire() as conn, conn.transaction():
            assert victim_record is not None
            amount_to_steal = min(victim_record["stock"], amount)
            await UserSnowballUpdate(ctx.author, stock=amount_to_steal).upsert_record(conn)  # type: ignore
            await UserSnowballUpdate(victim, stock=-amount_to_steal).upsert_record(conn)  # type: ignore

        # Send notification message of successful theft.
        def_embed.description = f"Thievery successful! You've stolen {amount_to_steal} snowballs from {victim.mention}!"
        message = f"{ctx.author.mention}, {victim.mention}"
        await ctx.send(content=message, embed=def_embed, ephemeral=False)

    @snow.group(fallback="get")
    @commands.guild_only()
    @app_commands.describe(target="Look up a particular Snowball Sparrer's stats.")
    async def stats(self, ctx: core.GuildContext, *, target: discord.User = commands.Author) -> None:
        """See who's the best at shooting snow spheres.

        Parameters
        ----------
        ctx : :class:`core.GuildContext`
            The invocation context.
        target : :class:`discord.User`, default=:class:`commands.Author`
            The user whose stats are to be displayed. If none, defaults to the caller. Their stats are specifically from
            all their interactions within the guild in context.
        """

        query = """
            SELECT guild_rank, hits, misses, kos, stock
            FROM(
                SELECT user_id, hits, kos, misses, stock,
                    DENSE_RANK() over (ORDER BY hits DESC, kos, misses, stock DESC, user_id DESC) AS guild_rank
                FROM snowball_stats
                WHERE guild_id = $1
                ORDER BY guild_rank
            ) as t
            WHERE user_id = $2;
        """
        record = await ctx.db.fetchrow(query, ctx.guild.id, target.id)

        # Create and send the stats embed only if the user has a record.
        if record is not None:
            title = f"**Player Statistics for {target}**"
            headers = ["Rank", "Direct Hits", "Total Misses", "KOs", "Total Snowballs Collected"]
            emojis = [EMOJI_STOCK["snowsgive_phi"] or ""]

            embed = (
                StatsEmbed(title=title)
                .add_stat_fields(stat_names=headers, stat_emojis=emojis, stat_values=record)
                .set_thumbnail(url=target.display_avatar.url)
            )

            await ctx.send(embed=embed, ephemeral=True)

        else:
            person = "You don't" if target.id == ctx.author.id else "That player doesn't"
            await ctx.send(
                f"{person} have any stats yet. *Maybe you could change that.* "
                f"{EMOJI_STOCK['snowball1']}{EMOJI_STOCK['snowball2']}",
                ephemeral=True,
            )

    @stats.command(name="global")
    @app_commands.describe(target="Look up a a player's stats as a summation across all servers.")
    async def stats_global(self, ctx: core.Context, *, target: discord.User = commands.Author) -> None:
        """See who's the best across all Beira servers.

        Parameters
        ----------
        ctx : :class:`core.Context`
            The invocation context.
        target : :class:`discord.User`, default=:class:`commands.Author`
            The user whose stats are to be displayed. If none, defaults to the caller. Their global stats are a
            summation of all their guild-specific stats.
        """

        query = "SELECT rank, hits, misses, kos, stock FROM global_rank_view WHERE user_id = $1;"
        record = await ctx.db.fetchrow(query, target.id)

        # Create and send the stats embed only if the user has a record.
        if record is not None:
            title = f"**Global Player Statistics for {target}**"  # Formerly 0x2f3171
            headers = ["*Overall* Rank", "*All* Direct Hits", "*All* Misses", "*All* KOs", "*All* Snowballs Collected"]
            emojis = [EMOJI_STOCK["snowsgive_phi"]]

            embed = (
                StatsEmbed(title=title)
                .add_stat_fields(stat_names=headers, stat_emojis=emojis, stat_values=record)
                .set_thumbnail(url=target.display_avatar.url)
            )

            await ctx.send(embed=embed, ephemeral=True)

        else:
            snow1, snow2 = EMOJI_STOCK["snowball1"], EMOJI_STOCK["snowball2"]
            person = "You don't" if target.id == ctx.author.id else "That player doesn't"
            await ctx.send(
                f"{person} have any stats yet. *Maybe you could change that.* {snow1}{snow2}",
                ephemeral=True,
            )

    @snow.group(fallback="get")
    @commands.guild_only()
    async def leaderboard(self, ctx: core.GuildContext) -> None:
        """See who's dominating the Snowball Bot leaderboard in your server.

        Parameters
        ----------
        ctx : :class:`core.GuildContext`
            The invocation context.
        """

        query = """
            SELECT user_id, hits, kos, misses, stock,
                DENSE_RANK() over (ORDER BY hits DESC, kos, misses, stock DESC, user_id DESC) AS rank
            FROM snowball_stats
            WHERE guild_id = $1
            ORDER BY rank
            LIMIT $2;
        """
        guild_ldbd = await ctx.db.fetch(query, ctx.guild.id, LEADERBOARD_MAX)

        embed = StatsEmbed(
            color=0x2F3136,
            title=f"**Snowball Champions in {ctx.guild.name}**",
            description="(Hits / Misses / KOs)\n——————————————",
        )

        if ctx.guild.icon:
            embed.set_thumbnail(url=ctx.guild.icon.url)

        if guild_ldbd:
            await self._make_leaderboard_fields(embed, guild_ldbd)
        else:
            embed.description = embed.description or ""
            embed.description += "\n**There are no scores at this time, as no users have interacted with the bot yet!**"

        await ctx.send(embed=embed, ephemeral=False)

    @leaderboard.command(name="global")
    async def leaderboard_global(self, ctx: core.Context) -> None:
        """See who's dominating the Global Snowball Bot leaderboard across all the servers.

        Parameters
        ----------
        ctx : :class:`core.Context`
            The invocation context.
        """
        assert self.bot.user  # Known to exist during runtime.

        query = "SELECT * FROM global_rank_view LIMIT $1;"
        global_ldbd = await ctx.db.fetch(query, LEADERBOARD_MAX)

        embed = StatsEmbed(
            color=0x2F3136,
            title="**Global Snowball Champions**",
            description="(Total Hits / Total Misses / Total KOs)\n——————————————",
        ).set_thumbnail(url=self.bot.user.display_avatar.url)

        if global_ldbd:
            await self._make_leaderboard_fields(embed, global_ldbd)
        else:
            embed.description = embed.description or ""
            embed.description += "\n**There was an issue connecting to the database. Please try again later.**"

        await ctx.send(embed=embed, ephemeral=False)

    @leaderboard.command(name="guilds")
    async def leaderboard_guilds(self, ctx: core.Context) -> None:
        """See which guild is dominating the Snowball Bot leaderboard.

        Parameters
        ----------
        ctx : :class:`core.Context`
            The invocation context.
        """
        assert self.bot.user  # Known to exist during runtime.

        query = "SELECT * FROM guilds_only_rank_view LIMIT $1;"
        guilds_only_ldbd = await ctx.db.fetch(query, LEADERBOARD_MAX)

        embed = StatsEmbed(
            color=0x2F3136,
            title="**Guild-Level Snowball Champions**",
            description="(Total Hits / Total Misses / Total KOs)\n——————————————",
        ).set_thumbnail(url=self.bot.user.display_avatar.url)

        if guilds_only_ldbd:
            await self._make_leaderboard_fields(embed, guilds_only_ldbd)
        else:
            embed.description = embed.description or ""
            embed.description += "\n**There was an issue connecting to the database. Please try again later.**"

        await ctx.send(embed=embed, ephemeral=False)

    @snow.command()
    async def sources(self, ctx: core.Context) -> None:
        """Gives links and credit to the Snowsgiving 2021 Help Center article and to reference code.

        Parameters
        ----------
        ctx : :class:`core.Context`
            The invocation context.
        """

        code_value = self.embed_data["inspo"]["note"].format(self.embed_data["inspo"]["url"])
        inspo_value = self.embed_data["code"]["note"].format(self.embed_data["code"]["url"])

        embed = (
            discord.Embed(color=0xDD8B42, title="**Sources of Inspiration and Code**")
            .add_field(name="Inspiration", value=code_value, inline=False)
            .add_field(name="Code", value=inspo_value, inline=False)
        )
        await ctx.send(embed=embed, ephemeral=True)

    @collect.before_invoke
    @throw.before_invoke
    @transfer.before_invoke
    @steal.before_invoke
    async def snow_before(self, ctx: core.GuildContext) -> None:
        """Load the snowball settings from the db for the current guild before certain commands are executed.

        This allows the use of guild-specific limits stored in the db and now temporarily in the context.
        """

        guild_snow_settings = await GuildSnowballSettings.from_database(ctx.db, ctx.guild.id)
        ctx.guild_snow_settings = guild_snow_settings  # type: ignore # Runtime attribute assignment.

    @collect.after_invoke
    @throw.after_invoke
    @transfer.after_invoke
    @steal.after_invoke
    async def snow_after(self, ctx: core.GuildContext) -> None:
        """Remove the snowball settings from the context. Probably not necessary."""

        delattr(ctx, "guild_snow_settings")

    async def _make_leaderboard_fields(self, embed: StatsEmbed, records: list[asyncpg.Record]) -> None:
        """Edits a leaderboard embed by adding information about its members through fields.

        This can handle ranks of either guilds or users, but not a mix of both.
        """

        def _get_entity_from_record(record: asyncpg.Record) -> discord.Guild | discord.User | None:
            if "guild_id" in record:
                entity = self.bot.get_guild(record["guild_id"])
            elif "user_id" in record:
                entity = self.bot.get_user(record["user_id"])
            else:
                entity = None
            return entity

        # Create temporary, more concise references for a few emojis.
        special_stars = (EMOJI_STOCK[name] for name in ("orange_star", "blue_star", "pink_star"))

        # Create a list of emojis to accompany the leaderboard members.
        ldbd_places_emojis = (
            "\N{GLOWING STAR}",
            "\N{WHITE MEDIUM STAR}",
            *tuple(emoji for emoji in islice(cycle(special_stars), 8)),
        )

        # Assemble each entry's data.
        snow_data = [(_get_entity_from_record(row), row["hits"], row["misses"], row["kos"]) for row in records]

        # Create the leaderboard.
        embed.add_leaderboard_fields(ldbd_content=snow_data, ldbd_emojis=ldbd_places_emojis, value_format="({}/{}/{})")


__author__ = 'woody'
import unittest
from interfaceTest import app
import datetime as date
from interfaceTest.Methods.BeopTools import *
#项目ID,点名,项目名,dtu名称,引擎名称,是否判断掉线时间,持续时间

url = "http://%s/get_history_data_padded_reduce" % app.config['SERVERIP']
projectId = 179
pointName = "Ch001_ChPower_prs"

class Calc017(unittest.TestCase):
    testCaseID = 'Calc017'
    projectName = "嘉民"
    buzName = 'm5,h1,d1历史数据最后一条是否相等'
    start = 0.0
    now = ""
    startTime = ""
    errors = []

    def setUp(self):
        self.start = date.datetime.now()
        self.startTime = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
        self.logger = BeopTools.init_log(r'%s\log\%s.txt' % (sys.path[0], self.testCaseID))

    def Test(self):
        self.errors = []
        timeShaft_m5 = self.getM5Time
        timeShaft_h1 = self.getH1Time
        timeShaft_d1 = self.getD1Time
        timeShaft_M1 = self.getMonthTime
        timeOrig = self.getLastHistoryData(timeShaft_m5[0], timeShaft_m5[1], 'm5', projectId, 'Ch002_ChEnterCondTemp')
        if timeOrig is not None:
            print('现场数据没掉线!')
            m5_get_data_time = BeopTools.getTime()
            m5_last_data = self.getLastHistoryData(timeShaft_m5[0], timeShaft_m5[1], 'm5')
            h1_get_data_time = BeopTools.getTime()
            h1_last_data = self.getLastHistoryData(timeShaft_h1[0], timeShaft_h1[1], 'h1')
            d1_get_data_time = BeopTools.getTime()
            d1_last_data = self.getLastHistoryData(timeShaft_d1[0], timeShaft_d1[1], 'd1')
            M1_get_data_time = BeopTools.getTime()
            M1_last_data = self.getLastHistoryData(timeShaft_M1[0], timeShaft_M1[1], 'M1')
            if m5_last_data == h1_last_data == m5_last_data == d1_last_data == M1_last_data:
                print("[%s]%s---%s项目 %s点 m5,h1,d1,M1表中最后存储的历史数据一致!   \nm5数据读取时间: %s m5时间段 :[%s~%s] ,返回点值数组最后一个数据: %s   \nh1数据读取时间: %s h1时间段 :[%s~%s] ,返回点值数组最后一个数据: %s   \nd1数据读取时间: %s d1时间段 :[%s~%s] ,返回点值数组最后一个数据: %s   \nM1数据读取时间: %s M1时间段 :[%s~%s] ,返回点值数组最后一个数据: %s"

                                   % (BeopTools.getTime(), self.testCaseID, self.projectName, pointName, m5_get_data_time, timeShaft_m5[0], timeShaft_m5[1], m5_last_data, h1_get_data_time, timeShaft_h1[0], timeShaft_h1[1], h1_last_data, d1_get_data_time, timeShaft_d1[0], timeShaft_d1[1], d1_last_data,  M1_get_data_time, timeShaft_M1[0], timeShaft_M1[1], M1_last_data))
            else:
                BeopTools.writeLogError(self.logger, "错误信息[%s]%s---%s项目 %s点 m5,h1,d1,M1表中最后存储的历史数据不一致!   m5时间:%s,点值:%s   h1时间:%s,点值:%s   d1时间:%s,点值:%s   M1时间:%s,点值:%s  " % (BeopTools.getTime(), self.testCaseID, self.projectName, pointName, timeShaft_m5[1], m5_last_data, timeShaft_h1[1], h1_last_data, timeShaft_d1[1], d1_last_data, timeShaft_M1[1], M1_last_data))
                self.errors.append("错误信息[%s]%s---%s项目 %s点 m5,h1,d1,M1表中最后存储的历史数据不一致!   \nm5数据读取时间: %s m5时间段 :[%s~%s] ,返回点值数组最后一个数据: %s   \nh1数据读取时间: %s h1时间段 :[%s~%s] ,返回点值数组最后一个数据: %s   \nd1数据读取时间: %s d1时间段 :[%s~%s] ,返回点值数组最后一个数据: %s   \nM1数据读取时间: %s M1时间段 :[%s~%s] ,返回点值数组最后一个数据: %s"

                                   % (BeopTools.getTime(), self.testCaseID, self.projectName, pointName, m5_get_data_time, timeShaft_m5[0], timeShaft_m5[1], m5_last_data, h1_get_data_time, timeShaft_h1[0], timeShaft_h1[1], h1_last_data, d1_get_data_time, timeShaft_d1[0], timeShaft_d1[1], d1_last_data,  M1_get_data_time, timeShaft_M1[0], timeShaft_M1[1], M1_last_data))
        else:
            self.errors.append('错误信息[%s]%s---%s项目现场数据未更新，不检测其m5,h1,d1,M1表中最后存储的历史数据是否一致!' % (BeopTools.getTime(), self.testCaseID, self.projectName))
        BeopTools.raiseError(self.errors, self.testCaseID)

    @property
    def getH1Time(self):
        timeNowStr = time.strftime("%Y-%m-%d %H:00:00", time.localtime())
        timeNowStamp = date.datetime.strptime(timeNowStr, "%Y-%m-%d %H:%M:%S")
        timeStart = timeNowStamp - date.timedelta(seconds=3600)
        timeStartStr = date.datetime.strftime(timeStart, "%Y-%m-%d %H:%M:%S")
        #timeStart = date.datetime.now() - date.timedelta(seconds=600)
        return (timeStartStr, timeNowStr)

    @property
    def getM5Time(self):
        timeNowStr = time.strftime("%Y-%m-%d %H:%M:00", time.localtime())
        minute = timeNowStr[:-3]
        m5_min = minute[-1]
        if 0 < int(m5_min) < 5:
            m5_end = minute[:-1] + "0:00"
        elif 5 < int(m5_min) < 10:
            m5_end = minute[:-1] + "5:00"
        else:
            m5_end = minute + ":00"

        timeNowStamp = date.datetime.strptime(m5_end, "%Y-%m-%d %H:%M:%S")
        timeStart = timeNowStamp - date.timedelta(seconds=900)
        timeStartStr = date.datetime.strftime(timeStart, "%Y-%m-%d %H:%M:%S")
        #timeStart = date.datetime.now() - date.timedelta(seconds=600)
        return (timeStartStr, m5_end)

    @property
    def getD1Time(self):
        timeNowStr = time.strftime("%Y-%m-%d 00:00:00", time.localtime())
        timeNowStamp = date.datetime.strptime(timeNowStr, "%Y-%m-%d %H:%M:%S")
        timeStart = timeNowStamp - date.timedelta(days=1)
        timeStartStr = date.datetime.strftime(timeStart, "%Y-%m-%d %H:%M:%S")
        #timeStart = date.datetime.now() - date.timedelta(seconds=600)
        return (timeStartStr, timeNowStr)

    @property
    def getMonthTime(self):
        timeNowStr = time.strftime("%Y-%m-01 00:00:00", time.localtime())
        year = int(timeNowStr[0:4])
        month = int(timeNowStr[5:7])
        if month == 1:
            year -= 1
            month = 12
            timeStart = "%s-12-01 00:00:00" % str(year)
        elif 1 < month <= 10:
            month = month - 1
            timeStart = "%s-0%s-01 00:00:00" % (str(year), str(month))
        else:
            timeStart = "%s-%s-01 00:00:00" % (str(year), str(month))

        return (timeStart, timeNowStr)

    def getLastHistoryData(self, timeStart, timeEnd, timeFormat, projId=projectId, ptName=pointName):
        data = {
                "projectId":projId, "pointList":[ptName],
                "timeStart":timeStart,
                "timeEnd":timeEnd,
                "timeFormat":timeFormat
                }
        rt = []
        a = BeopTools()
        try:
            rt = a.postJsonToken(url=url, data=data, t=10)
        except Exception as e:
            print(e.__str__())
            a.writeLogError(self.logger, e.__str__())
            self.errors.append("错误信息[%s]%s---发送json数据:%s 访问接口:%s失败!" % (a.getTime(), self.testCaseID, json.dumps(data), url))

        values_dict = rt.get('data',{})
        values = values_dict.get(ptName, [])

        if isinstance(values, list) and values:
            return values[-1]
        else:
            self.errors.append("错误信息[%s]%s---发送json数据:%s 访问接口:%s返回的值为%s!" % (a.getTime(), self.testCaseID, json.dumps(data), url, json.dumps(rt)))
            return None

    def tearDown(self):
        use1 = str((date.datetime.now() - self.start).seconds)
        use = use1 + "s"
        print("本次用例执行时间为%s" % use)
        self.now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        ##info.append([self.testCaseID, use, now])

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(Calc017('Test'))
    runner = unittest.TextTestRunner()
    result = runner.run(suite)
    #unittest.main()


# Question 1
from datetime import date

def numSundaysOnFirstOfMonth(start, end):
    numSundays = 0
    for year in range(start, end+1):
        for month in range(1, 13):
            # weekday() returns Sunday as int 6
            if date(year, month, 1).weekday() == 6:
                numSundays += 1
    return numSundays

if __name__ == '__main__':
    print(numSundaysOnFirstOfMonth(1901,2000))


from typing import Optional

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:

        dummy = ListNode(val=0, next=head)
        tail = dummy

        while tail.next:
            if tail.next.val == val:
                tail.next = tail.next.next
            else:
                tail = tail.next

        return dummy.next


"""自定义频率限制"""
import time
from rest_framework.throttling import BaseThrottle

# 访问频率限制次数
LIMIT_NUM = 3

class IPThrottle(BaseThrottle):
    # 定义成类属性,所有对象用的都是这个
    VISIT_DIC = {}

    def __init__(self):
        self.history_list = []

    def allow_request(self, request, view):
        """
        #（1）取出访问者ip
        #（2）如果当前ip不在访问字典里，添加进去，并且直接返回True,表示第一次访问，存在字典里，继续往下走
        #（3）循环判断当前ip的列表，有值，并且当前时间减去列表的最后一个时间大于60s，把这种数据pop掉，这样列表中只有60s以内的访问时间，
        #（4）判断，当列表小于3，说明一分钟以内访问不足三次，把当前时间插入到列表第一个位置，返回True，顺利通过
        #（5）当大于等于3，说明一分钟内访问超过三次，返回False验证失败
        """
        current_ip = request.META.get('REMOTE_ADDR')
        current_time = time.time()
        if current_ip not in self.VISIT_DIC:
            self.VISIT_DIC[current_ip] = [current_time]
            return True
        self.history_list = self.VISIT_DIC[current_ip]
        while True:
            if current_time - self.history_list[-1] > 60:
                self.history_list.pop(-1)
            else:
                break
        if len(self.history_list) < LIMIT_NUM:
            self.history_list.insert(0, current_time)
            return True
        else:
            return False

    def wait(self):
        """
        :return: 返回限制的剩余的秒数
        """
        last_time = self.history_list[-1]
        return 60 - (time.time() - last_time)


"""Grid convergence index (GCI)"""
from math import pow, log, fabs
from typing import Union, List

import numpy as np
import pyGCS

class GCISolution:
    """Interface for GCI solution"""

    def __init__(self, gci: pyGCS.GCI):
        self._gci = gci

    def __repr__(self):
        """TODO: use tabulate to print a nice table"""
        return f'GCI: {self.gci}'

    @property
    def gci(self):
        """Grid convergence index"""
        return self._gci.get('gci')

    @property
    def refinement_ratio(self):
        """Refinement ratio"""
        return self._gci.get('refinement_ratio')

    @property
    def apparent_order(self):
        """Apparent order"""
        return self._gci.get('apparent_order')

    @property
    def asymptotic_gci(self):
        """Asymptotic GCI"""
        return self._gci.get('asymptotic_gci')

class GCI:
    """Grid convergence index (GCI) interface class"""

    def __init__(self, cells, simulation_order, volume, dimension: int):
        """Grid convergence index (GCI)

        Parameters
        ----------
        cells : List[float] or np.ndarray
            Number of cells in each mesh
        simulation_order : float
            Order of the convergence
        volume: float
            Volume of the simulation domain
        dimension : int
            Dimension of the simulation. 2D or 3D.
        """
        self.cells = cells
        if dimension not in (2, 3):
            raise ValueError("Simulation dimension must be 2 or 3")
        self.dim = dimension
        self.volume = volume
        self.simulation_order = simulation_order

    def compute(self, solution: Union[List[float], np.ndarray]):
        """compute the GCI for given quantity
        Parameters
        ----------
        solution : List[float] or np.ndarray
            Solution for each mesh. Order must be corresponding to the order when initializing the class.
        """
        return GCISolution(pyGCS.GCI(dimension=self.dim,
                                     simulation_order=self.simulation_order,
                                     volume=self.volume,
                                     cells=self.cells,
                                     solution=solution))

    @staticmethod
    def compute_order(initial_order, e21, e32, r21, r32):
        """
        Compute the formal order of accuracy `p`.

        taken from
        https://github.com/tomrobin-teschner/pyGCS/blob/d3803f8bdd08d1dff703b4a5f2480bdadc862154/src/pyGCS/GCI.py#L109
        """
        eps = 1
        iteration = 1
        max_iteration = 100
        norm = 1
        p = initial_order
        while eps > 1e-6:
            p_old = p

            s = np.sign(e32 / e21)
            q = log((pow(r21, p) - s) / (pow(r32, p) - s))
            p = (1.0 / log(r21)) * fabs(log(fabs(e32 / e21)) + q)

            residual = p - p_old
            if iteration == 1:
                norm = residual
            iteration += 1
            eps = residual / norm
            if iteration == max_iteration:
                print('WARNING: max number of iterations (' + str(max_iteration) +
                      ') reached for calculating apparent order p ...')
                break
        return p

def main():
    cells = [18000, 8000, 4500]
    solutions = [6.063, 5.972, 5.863]

    gci = GCI(cells=cells,
              simulation_order=2, volume=76, dimension=2)
    print(gci.compute(solutions).gci)
    print(gci.compute(solutions).apparent_order)
    print(gci.compute(solutions).asymptotic_gci)
    print(gci.compute(solutions))

    from pyGCS import GCI as GCI2
    gci = GCI2(dimension=2,
               simulation_order=2,
               volume=76,
               cells=cells,
               solution=solutions)
    print(gci.get('gci'))

    gci.set('solution', [1, 2, 3])
    print(gci.get('gci'))

    gci.set('solution', solutions)
    print(gci.get('gci'))

if __name__ == "__main__":
    main()


import requests, json, string
import urllib.request as request
import time
import Message
import Location
import Marketstack

def GetCovidData(text):
    """ Get Covid Data from Country """
    url = 'https://covid-api.mmediagroup.fr/v1/cases?country=' + text
    with request.urlopen(url) as response:
       source = response.read()
       data = json.loads(source)["All"]

       return data

def CreateMessage(access_token, room_id, data):
    """ Send Message to WebEx Room """
    country = data["country"]
    message = "%s | Confirmed : %d\tRecovered : %d\tDeaths : %d"%(country, data["confirmed"], data["recovered"], data["deaths"])
    url = 'https://webexapis.com/v1/messages'
    headers = {
        'Authorization': 'Bearer {}'.format(access_token),
        'Content-Type': 'application/json'
    }
    params = {'roomId': room_id[1], 'markdown': message}
    requests.post(url, headers=headers, json=params)

    print("Message : \"%s\""%message)

def CheckText(text, access_token, room_id):
    """ Check Message from WebEx Room """
    while True:
        text = Message.GetMessage(access_token, room_id)
        if text == "None" or text.lower() == "covid":
            continue
        elif text.lower() == "end":
            print("...................................Leave Covid-19 Mode")
            break
        # Location Mode
        elif text.lower() == "location":
            print("...................................Leave Covid-19 Mode")
            print(".........................................Location Mode")
            url = 'https://webexapis.com/v1/messages'
            headers = {
                'Authorization': 'Bearer {}'.format(access_token),
                'Content-Type': 'application/json'
            }
            params = {'roomId': room_id[1], 'markdown': "Please Enter Location..."}
            requests.post(url, headers=headers, json=params)
            Location.CheckText(text, access_token, room_id)
        # Market Stack Mode
        elif text.lower() == "market":
            print("...................................Leave Covid-19 Mode")
            print(".....................................Market Stack Mode")
            url = 'https://webexapis.com/v1/messages'
            headers = {
                'Authorization': 'Bearer {}'.format(access_token),
                'Content-Type': 'application/json'
            }
            params = {'roomId': room_id[1], 'markdown': "Please Enter Symbol..."}
            requests.post(url, headers=headers, json=params)
            Marketstack.CheckText(text, access_token, room_id)
        elif text:
            data = GetCovidData(text)
            CreateMessage(access_token, room_id, data)
            print("Send message to " + room_id[0] + " success!")
        time.sleep(5)