<commit_before>import unittest

import mock
import numpy

import chainer
from chainer import cuda
from chainer import functions
from chainer import gradient_check
from chainer import testing
from chainer.testing import attr
from chainer.testing import condition

@testing.parameterize(*testing.product({
    'shape_axis':
        [{'shape': None, 'axis': 1}, ] +
        testing.product({'shape': ((3, 4),), 'axis': (0, 1)}) +
        testing.product({'shape': ((3, 4, 5),), 'axis': (0, 1, 2)}) +
        testing.product({'shape': ((3, 4, 5, 6),), 'axis': (0, 1, 2, 3)}),
    'dtype': [numpy.float16, numpy.float32, numpy.float64],
}))
class TestSoftmax(unittest.TestCase):

    def setUp(self):
        self.shape = self.shape_axis['shape']
        self.axis = self.shape_axis['axis']
        if self.shape is None:
            # For checking numerical stability
            value = -5 if self.dtype == numpy.float16 else -1000
            self.x = numpy.array([[value, 1]], dtype=self.dtype)
        else:
            self.x = numpy.random.uniform(-1, 1, self.shape).astype(self.dtype)
        self.gy = numpy.random.uniform(-1, 1, self.x.shape).astype(self.dtype)
        self.ggx = numpy.random.uniform(-1, 1, self.x.shape).astype(self.dtype)

        self.check_forward_options = {}
        self.check_backward_options = {'dtype': numpy.float64}
        if self.dtype == numpy.float16:
            self.check_forward_options = {'atol': 1e-3, 'rtol': 1e-2}
            self.check_backward_options = {
                'dtype': numpy.float64, 'atol': 5e-4, 'rtol': 5e-3}

    def check_forward(self, x_data, use_cudnn='always'):
        x = chainer.Variable(x_data)
        with chainer.using_config('use_cudnn', use_cudnn):
            y = functions.softmax(x, axis=self.axis)
        self.assertEqual(y.data.dtype, self.dtype)

        y_expect = numpy.exp(self.x)
        y_roll = numpy.rollaxis(y_expect, self.axis, y_expect.ndim)
        for i in numpy.ndindex(y_roll.shape[:-1]):
            y_roll[i] /= y_roll[i].sum()

        testing.assert_allclose(
            y_expect, y.data, **self.check_forward_options)

    @condition.retry(3)
    def test_forward_cpu(self):
        self.check_forward(self.x)

    @attr.gpu
    @condition.retry(3)
    def test_forward_gpu(self):
        self.check_forward(cuda.to_gpu(self.x))

    @attr.gpu
    @condition.retry(3)
    def test_forward_gpu_non_contiguous(self):
        self.check_forward(
            cuda.cupy.asfortranarray(cuda.to_gpu(self.x)))

    @attr.gpu
    @condition.retry(3)
    def test_forward_gpu_no_cudnn(self):
        self.check_forward(cuda.to_gpu(self.x), 'never')

    def check_backward(self, x_data, gy_data, use_cudnn='always'):
        def f(x):
            return functions.softmax(x, axis=self.axis)

        with chainer.using_config('use_cudnn', use_cudnn):
            gradient_check.check_backward(
                f, x_data, gy_data, **self.check_backward_options)

    @condition.retry(10)
    def test_backward_cpu(self):
        self.check_backward(self.x, self.gy)

    @attr.gpu
    @condition.retry(10)
    def test_backward_gpu(self):
        self.check_backward(cuda.to_gpu(self.x), cuda.to_gpu(self.gy))

    @attr.gpu
    @condition.retry(10)
    def test_backward_gpu_non_contiguous(self):
        self.check_backward(
            cuda.cupy.asfortranarray(cuda.to_gpu(self.x)),
            cuda.cupy.asfortranarray(cuda.to_gpu(self.gy)))

    @attr.gpu
    @condition.retry(10)
    def test_backward_gpu_no_cudnn(self):
        self.check_backward(cuda.to_gpu(self.x), cuda.to_gpu(self.gy), 'never')

    def check_double_backward(self, x_data, gy_data, ggx_data):
        def f(x):
            return functions.softmax(x, axis=self.axis)

        gradient_check.check_double_backward(
            f, (x_data,), (gy_data,), (ggx_data),
            **self.check_backward_options)

    @condition.retry(10)
    def test_double_backward_cpu(self):
        self.check_double_backward(self.x, self.gy, self.ggx)

    @attr.gpu
    @condition.retry(10)
    def test_double_backward_gpu(self):
        self.check_double_backward(cuda.to_gpu(self.x),
                                   cuda.to_gpu(self.gy),
                                   cuda.to_gpu(self.ggx))

@testing.parameterize(*testing.product({
    'axis': [0, 1],
    'use_cudnn': ['always', 'auto', 'never'],
    'dtype': [numpy.float16, numpy.float32, numpy.float64],
}))
@attr.cudnn
class TestSoftmaxCudnnCall(unittest.TestCase):

    def setUp(self):
        self.x = cuda.cupy.random.uniform(-1, 1, (2, 3)).astype(self.dtype)
        self.gy = cuda.cupy.random.uniform(-1, 1, (2, 3)).astype(self.dtype)
        with chainer.using_config('use_cudnn', self.use_cudnn):
            self.expect = chainer.should_use_cudnn('>=auto')

    def forward(self):
        x = chainer.Variable(self.x)
        return functions.softmax(x, axis=self.axis)

    def test_call_cudnn_forward(self):
        with chainer.using_config('use_cudnn', self.use_cudnn):
            with mock.patch('cupy.cudnn.cudnn.softmaxForward') as func:
                self.forward()
                self.assertEqual(func.called, self.expect)

    def test_call_cudnn_backward(self):
        with chainer.using_config('use_cudnn', self.use_cudnn):
            y = self.forward()
            y.grad = self.gy
            with mock.patch('cupy.cudnn.cudnn.softmaxBackward') as func:
                y.backward()
                self.assertEqual(func.called, self.expect)

testing.run_module(__name__, __file__)
<commit_msg>Add no cudnn test.<commit_after>import unittest

import mock
import numpy

import chainer
from chainer import cuda
from chainer import functions
from chainer import gradient_check
from chainer import testing
from chainer.testing import attr
from chainer.testing import condition

@testing.parameterize(*testing.product({
    'shape_axis':
        [{'shape': None, 'axis': 1}, ] +
        testing.product({'shape': ((3, 4),), 'axis': (0, 1)}) +
        testing.product({'shape': ((3, 4, 5),), 'axis': (0, 1, 2)}) +
        testing.product({'shape': ((3, 4, 5, 6),), 'axis': (0, 1, 2, 3)}),
    'dtype': [numpy.float16, numpy.float32, numpy.float64],
}))
class TestSoftmax(unittest.TestCase):

    def setUp(self):
        self.shape = self.shape_axis['shape']
        self.axis = self.shape_axis['axis']
        if self.shape is None:
            # For checking numerical stability
            value = -5 if self.dtype == numpy.float16 else -1000
            self.x = numpy.array([[value, 1]], dtype=self.dtype)
        else:
            self.x = numpy.random.uniform(-1, 1, self.shape).astype(self.dtype)
        self.gy = numpy.random.uniform(-1, 1, self.x.shape).astype(self.dtype)
        self.ggx = numpy.random.uniform(-1, 1, self.x.shape).astype(self.dtype)

        self.check_forward_options = {}
        self.check_backward_options = {'dtype': numpy.float64}
        if self.dtype == numpy.float16:
            self.check_forward_options = {'atol': 1e-3, 'rtol': 1e-2}
            self.check_backward_options = {
                'dtype': numpy.float64, 'atol': 5e-4, 'rtol': 5e-3}

    def check_forward(self, x_data, use_cudnn='always'):
        x = chainer.Variable(x_data)
        with chainer.using_config('use_cudnn', use_cudnn):
            y = functions.softmax(x, axis=self.axis)
        self.assertEqual(y.data.dtype, self.dtype)

        y_expect = numpy.exp(self.x)
        y_roll = numpy.rollaxis(y_expect, self.axis, y_expect.ndim)
        for i in numpy.ndindex(y_roll.shape[:-1]):
            y_roll[i] /= y_roll[i].sum()

        testing.assert_allclose(
            y_expect, y.data, **self.check_forward_options)

    @condition.retry(3)
    def test_forward_cpu(self):
        self.check_forward(self.x)

    @attr.gpu
    @condition.retry(3)
    def test_forward_gpu(self):
        self.check_forward(cuda.to_gpu(self.x))

    @attr.gpu
    @condition.retry(3)
    def test_forward_gpu_non_contiguous(self):
        self.check_forward(
            cuda.cupy.asfortranarray(cuda.to_gpu(self.x)))

    @attr.gpu
    @condition.retry(3)
    def test_forward_gpu_no_cudnn(self):
        self.check_forward(cuda.to_gpu(self.x), 'never')

    def check_backward(self, x_data, gy_data, use_cudnn='always'):
        def f(x):
            return functions.softmax(x, axis=self.axis)

        with chainer.using_config('use_cudnn', use_cudnn):
            gradient_check.check_backward(
                f, x_data, gy_data, **self.check_backward_options)

    @condition.retry(10)
    def test_backward_cpu(self):
        self.check_backward(self.x, self.gy)

    @attr.gpu
    @condition.retry(10)
    def test_backward_gpu(self):
        self.check_backward(cuda.to_gpu(self.x), cuda.to_gpu(self.gy))

    @attr.gpu
    @condition.retry(10)
    def test_backward_gpu_non_contiguous(self):
        self.check_backward(
            cuda.cupy.asfortranarray(cuda.to_gpu(self.x)),
            cuda.cupy.asfortranarray(cuda.to_gpu(self.gy)))

    @attr.gpu
    @condition.retry(10)
    def test_backward_gpu_no_cudnn(self):
        self.check_backward(cuda.to_gpu(self.x), cuda.to_gpu(self.gy), 'never')

    def check_double_backward(self, x_data, gy_data, ggx_data,
                              use_cudnn='always'):
        def f(x):
            return functions.softmax(x, axis=self.axis)

        with chainer.using_config('use_cudnn', use_cudnn):
            gradient_check.check_double_backward(
                f, (x_data,), (gy_data,), (ggx_data),
                **self.check_backward_options)

    @condition.retry(10)
    def test_double_backward_cpu(self):
        self.check_double_backward(self.x, self.gy, self.ggx)

    @attr.gpu
    @condition.retry(10)
    def test_double_backward_gpu(self):
        self.check_double_backward(cuda.to_gpu(self.x),
                                   cuda.to_gpu(self.gy),
                                   cuda.to_gpu(self.ggx))

    @attr.gpu
    @condition.retry(10)
    def test_double_backward_gpu_no_cudnn(self):
        self.check_double_backward(cuda.to_gpu(self.x),
                                   cuda.to_gpu(self.gy),
                                   cuda.to_gpu(self.ggx),
                                   'never')

@testing.parameterize(*testing.product({
    'axis': [0, 1],
    'use_cudnn': ['always', 'auto', 'never'],
    'dtype': [numpy.float16, numpy.float32, numpy.float64],
}))
@attr.cudnn
class TestSoftmaxCudnnCall(unittest.TestCase):

    def setUp(self):
        self.x = cuda.cupy.random.uniform(-1, 1, (2, 3)).astype(self.dtype)
        self.gy = cuda.cupy.random.uniform(-1, 1, (2, 3)).astype(self.dtype)
        with chainer.using_config('use_cudnn', self.use_cudnn):
            self.expect = chainer.should_use_cudnn('>=auto')

    def forward(self):
        x = chainer.Variable(self.x)
        return functions.softmax(x, axis=self.axis)

    def test_call_cudnn_forward(self):
        with chainer.using_config('use_cudnn', self.use_cudnn):
            with mock.patch('cupy.cudnn.cudnn.softmaxForward') as func:
                self.forward()
                self.assertEqual(func.called, self.expect)

    def test_call_cudnn_backward(self):
        with chainer.using_config('use_cudnn', self.use_cudnn):
            y = self.forward()
            y.grad = self.gy
            with mock.patch('cupy.cudnn.cudnn.softmaxBackward') as func:
                y.backward()
                self.assertEqual(func.called, self.expect)

testing.run_module(__name__, __file__)
<|endoftext|>


<commit_before>import cgi
import discord
from discord.ext import commands
from bs4 import BeautifulSoup
from urllib.parse import quote_plus
from urllib.parse import urlparse

class Google:
    def __init__(self, bot):
        self.bot = bot
        self.aiohttp_session = bot.aiohttp_session
        self.url = 'https://google.com/search'
        self.headers = {
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR '
                          '2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MS-RTC LM 8; '
                          'InfoPath.3; .NET4.0C; .NET4.0E) chromeframe/8.0.552.224',
            'Accept-Language': 'en-us',
            'Cache-Control': 'no-cache'
            }

    @commands.command()
    async def google(self, ctx, query: str=None):
        """Search Google for a query"""

        await ctx.message.delete()

        # Handle no query being provided
        if query is None:
            return await ctx.invoke(self.bot.get_command('error'), delete_after=2.0, err='Please provide a query!')

        # 'google_embed' is dependent on a test that checks whether google has embedded any external data on the page
        # 'result_nums' is the no. of results to display when there is no embedded data
        google_embed = False
        params = {'q': quote_plus(query), 'source': 'hp'}
        results_num = 3

        # Tries its best to imitate a real browser visit, an old user-agent is used to make scraping easier
        async with self.aiohttp_session.get(self.url, params=params, headers=self.headers) as r:
            html = await r.text()

        # Beautiful soup
        soup = BeautifulSoup(html, 'lxml')

        # Get links and their brief descriptions, only upto 4 are taken at a time, it should've been three, but
        # if you read the code, it tries to work around an extra entry that is just 'Images for '.
        # URLs on google search are redirected through 'google.com/url?url=xxxxx' , this uses cgi and urlparse to
        # grab only the 'url' URL parameter and get rid of the other parameters google passes for logging etc to
        # 'google.com/url'
        result_links = [cgi.parse_qs(urlparse(x.attrs['href'])[4])['url'][0] for x in soup.select('div.g h3.r a')[:4] if
                        '/search' not in x.attrs['href'] and not x.text == '']
        result_desc = [x.text for x in soup.select('div#ires div.g div.s span.st')[:4] if
                       'Images for' not in x.text and not x.text == '']

        # 'hp-xpdbox' is the class for google's embedded data, if this exists, google_embed is changed to True
        # and results are changed to 2
        if soup.select('div.hp-xpdbox'):
            google_embed = True
            embed_title = [a.text for a in soup.select('div._B5d')][0]
            embed_type = [a.text for a in soup.select('div._Pxg')][0]
            embed_details = [a.text for a in soup.select('div._tXc span')][0]
            results_num -= 1

            # Embedded data might not always have an image, this works around that
            img = None
            try:
                img = [img.attrs.get('src') for img in soup.select('div._i8d img')][0]
            except IndexError:
                pass

        # Create embed if google_embed is true
        if google_embed:
            em = discord.Embed(title=embed_title, description=embed_type,color=self.bot.user_color)
            em.add_field(name="Info", value=embed_details)
            if img:
                em.set_thumbnail(url=img)

        results = "\n\n".join([f'{link}\n{desc}' for link, desc in list(zip(result_links, result_desc))[:results_num]])

        if google_embed:
            await ctx.send(embed=em, content=f"\n**Also see:**\n{results}")
        else:
            await ctx.send(embed=em, content=results)

def setup(bot):
    bot.add_cog(Google(bot))
<commit_msg>Google is now better, embed test fixed<commit_after>import cgi
import discord
from discord.ext import commands
from bs4 import BeautifulSoup
from urllib.parse import quote_plus
from urllib.parse import urlparse

class Google:
    def __init__(self, bot):
        self.bot = bot
        self.aiohttp_session = bot.aiohttp_session
        self.url = 'https://google.com/search'
        self.headers = {
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR '
                          '2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MS-RTC LM 8; '
                          'InfoPath.3; .NET4.0C; .NET4.0E) chromeframe/8.0.552.224',
            'Accept-Language': 'en-us',
            'Cache-Control': 'no-cache'
            }

    @commands.command()
    async def google(self, ctx, *, query: str=None):
        """Search Google for a query"""

        await ctx.message.delete()

        # Handle no query being provided
        if query is None:
            return await ctx.invoke(self.bot.get_command('error'), delete_after=2.0, err='Please provide a query!')

        # 'google_embed' is dependent on a test that checks whether google has embedded any external data on the page
        # 'result_nums' is the no. of results to display when there is no embedded data
        google_embed = False
        params = {'q': quote_plus(query), 'source': 'hp'}
        results_num = 3

        # Tries its best to imitate a real browser visit, an old user-agent is used to make scraping easier
        async with self.aiohttp_session.get(self.url, params=params, headers=self.headers) as r:
            html = await r.text()

        # Beautiful soup
        soup = BeautifulSoup(html, 'lxml')

        # Get links and their brief descriptions, only upto 4 are taken at a time, it should've been three, but
        # if you read the code, it tries to work around an extra entry that is just 'Images for '.
        # URLs on google search are redirected through 'google.com/url?url=xxxxx' , this uses cgi and urlparse to
        # grab only the 'url' URL parameter and get rid of the other parameters google passes for logging etc to
        # 'google.com/url'
        result_links = [cgi.parse_qs(urlparse(x.attrs['href'])[4])['url'][0] for x in soup.select('div.g h3.r a')[:4] if
                        '/search' not in x.attrs['href'] and not x.text == '']
        result_desc = [x.text for x in soup.select('div#ires div.g div.s span.st')[:4] if
                       '/search' not in x.text and not x.text == '']

        # 'hp-xpdbox' is the class for google's embedded data, if this exists, google_embed is changed to True
        # and results are changed to 2
        if soup.select('div.hp-xpdbox div._tXc'):
            google_embed = True
            embed_title = [a.text for a in soup.select('div._B5d')][0]
            embed_type = [a.text for a in soup.select('div._Pxg')][0]
            embed_details = [a.text for a in soup.select('div._tXc span')][0]
            results_num -= 1

            # Embedded data might not always have an image, this works around that
            img = None
            try:
                img = [img.attrs.get('src') for img in soup.select('div._i8d img')][0]
            except IndexError:
                pass

        # Create embed if google_embed is true
        if google_embed:
            em = discord.Embed(title=embed_title, description=embed_type,color=self.bot.user_color)
            em.add_field(name="Info", value=embed_details)
            if img:
                em.set_thumbnail(url=img)

        results = "\n\n".join([f'<{link}>\n{desc}' for link, desc in list(zip(result_links, result_desc))[:results_num]])

        if google_embed:
            await ctx.send(embed=em, content=f"\n**Results for {query}:**\n{results}")
        else:
            await ctx.send(f"\n**Results for {query}:**\n{results}")

def setup(bot):
    bot.add_cog(Google(bot))
<|endoftext|>


<commit_before># Copyright 2019 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for tensorflow.python.framework.composite_tensor_utils."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np

from tensorflow.python.framework import composite_tensor_utils
from tensorflow.python.framework import ops
from tensorflow.python.framework import sparse_tensor
from tensorflow.python.framework import test_util
from tensorflow.python.ops.ragged import ragged_tensor
from tensorflow.python.ops.ragged import ragged_tensor_value
from tensorflow.python.platform import googletest

class CompositeTensorTest(test_util.TensorFlowTestCase):

  def test_is_composite(self):
    # Validate that all composite tensor and value types return true.
    self.assertTrue(
        composite_tensor_utils.is_composite_or_composite_value(
            sparse_tensor.SparseTensor([[0, 0]], [1], [1, 1])))
    self.assertTrue(
        composite_tensor_utils.is_composite_or_composite_value(
            sparse_tensor.SparseTensorValue([[0, 0]], [1], [1, 1])))
    self.assertTrue(
        composite_tensor_utils.is_composite_or_composite_value(
            ragged_tensor.RaggedTensor.from_row_splits([0, 1, 2], [0, 1, 3])))
    self.assertTrue(
        composite_tensor_utils.is_composite_or_composite_value(
            ragged_tensor_value.RaggedTensorValue(
                np.array([0, 1, 2]), np.array([0, 1, 3]))))

    # Test that numpy arrays and tensors return false.
    self.assertFalse(
        composite_tensor_utils.is_composite_or_composite_value(
            np.ndarray([0, 1])))
    self.assertFalse(
        composite_tensor_utils.is_composite_or_composite_value(
            ops.convert_to_tensor([3, 1])))

  def test_sparse_concatenation(self):
    tensor_1 = sparse_tensor.SparseTensor([[0, 0]], [1], [1, 1])
    tensor_2 = sparse_tensor.SparseTensor([[0, 0]], [2], [1, 1])
    concatenated_tensor = composite_tensor_utils.append_composite_tensor(
        tensor_1, tensor_2)
    evaluated_tensor = self.evaluate(concatenated_tensor)
    self.assertAllEqual(evaluated_tensor.indices, [[0, 0], [1, 0]])
    self.assertAllEqual(evaluated_tensor.values, [1, 2])
    self.assertAllEqual(evaluated_tensor.dense_shape, [2, 1])

  def test_sparse_value_concatenation(self):
    tensor_1 = sparse_tensor.SparseTensorValue([[0, 0]], [1], [1, 1])
    tensor_2 = sparse_tensor.SparseTensorValue([[0, 0]], [2], [1, 1])
    concatenated_tensor = composite_tensor_utils.append_composite_tensor(
        tensor_1, tensor_2)
    self.assertAllEqual(concatenated_tensor.indices, [[0, 0], [1, 0]])
    self.assertAllEqual(concatenated_tensor.values, [1, 2])
    self.assertAllEqual(concatenated_tensor.dense_shape, [2, 1])

  def test_ragged_concatenation(self):
    tensor_1 = ragged_tensor.RaggedTensor.from_row_splits(
        np.array([0, 1, 2]), np.array([0, 1, 3]))
    tensor_2 = ragged_tensor.RaggedTensor.from_row_splits(
        np.array([3, 4, 5]), np.array([0, 2, 3]))
    concatenated_tensor = composite_tensor_utils.append_composite_tensor(
        tensor_1, tensor_2)
    evaluated_tensor = self.evaluate(concatenated_tensor)

    self.assertAllEqual(evaluated_tensor.values, [0, 1, 2, 3, 4, 5])
    self.assertAllEqual(evaluated_tensor.row_splits, [0, 1, 3, 5, 6])

  def test_ragged_value_concatenation(self):
    tensor_1 = ragged_tensor_value.RaggedTensorValue(
        np.array([0, 1, 2]), np.array([0, 1, 3]))
    tensor_2 = ragged_tensor_value.RaggedTensorValue(
        np.array([3, 4, 5]), np.array([0, 2, 3]))
    concatenated_tensor = composite_tensor_utils.append_composite_tensor(
        tensor_1, tensor_2)

    self.assertAllEqual(concatenated_tensor.values, [0, 1, 2, 3, 4, 5])
    self.assertAllEqual(concatenated_tensor.row_splits, [0, 1, 3, 5, 6])

if __name__ == '__main__':
  googletest.main()
<commit_msg>Explicitly use int64 data type for row splits when creating RaggedTensorValues.<commit_after># Copyright 2019 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for tensorflow.python.framework.composite_tensor_utils."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np

from tensorflow.python.framework import composite_tensor_utils
from tensorflow.python.framework import ops
from tensorflow.python.framework import sparse_tensor
from tensorflow.python.framework import test_util
from tensorflow.python.ops.ragged import ragged_tensor
from tensorflow.python.ops.ragged import ragged_tensor_value
from tensorflow.python.platform import googletest

class CompositeTensorTest(test_util.TensorFlowTestCase):

  def test_is_composite(self):
    # Validate that all composite tensor and value types return true.
    self.assertTrue(
        composite_tensor_utils.is_composite_or_composite_value(
            sparse_tensor.SparseTensor([[0, 0]], [1], [1, 1])))
    self.assertTrue(
        composite_tensor_utils.is_composite_or_composite_value(
            sparse_tensor.SparseTensorValue([[0, 0]], [1], [1, 1])))
    self.assertTrue(
        composite_tensor_utils.is_composite_or_composite_value(
            ragged_tensor.RaggedTensor.from_row_splits(
                np.array([0, 1, 2]), np.array([0, 1, 3], dtype=np.int64))))
    self.assertTrue(
        composite_tensor_utils.is_composite_or_composite_value(
            ragged_tensor_value.RaggedTensorValue(
                np.array([0, 1, 2]), np.array([0, 1, 3], dtype=np.int64))))

    # Test that numpy arrays and tensors return false.
    self.assertFalse(
        composite_tensor_utils.is_composite_or_composite_value(
            np.ndarray([0, 1])))
    self.assertFalse(
        composite_tensor_utils.is_composite_or_composite_value(
            ops.convert_to_tensor([3, 1])))

  def test_sparse_concatenation(self):
    tensor_1 = sparse_tensor.SparseTensor([[0, 0]], [1], [1, 1])
    tensor_2 = sparse_tensor.SparseTensor([[0, 0]], [2], [1, 1])
    concatenated_tensor = composite_tensor_utils.append_composite_tensor(
        tensor_1, tensor_2)
    evaluated_tensor = self.evaluate(concatenated_tensor)
    self.assertAllEqual(evaluated_tensor.indices, [[0, 0], [1, 0]])
    self.assertAllEqual(evaluated_tensor.values, [1, 2])
    self.assertAllEqual(evaluated_tensor.dense_shape, [2, 1])

  def test_sparse_value_concatenation(self):
    tensor_1 = sparse_tensor.SparseTensorValue([[0, 0]], [1], [1, 1])
    tensor_2 = sparse_tensor.SparseTensorValue([[0, 0]], [2], [1, 1])
    concatenated_tensor = composite_tensor_utils.append_composite_tensor(
        tensor_1, tensor_2)
    self.assertAllEqual(concatenated_tensor.indices, [[0, 0], [1, 0]])
    self.assertAllEqual(concatenated_tensor.values, [1, 2])
    self.assertAllEqual(concatenated_tensor.dense_shape, [2, 1])

  def test_ragged_concatenation(self):
    tensor_1 = ragged_tensor.RaggedTensor.from_row_splits(
        np.array([0, 1, 2]), np.array([0, 1, 3], dtype=np.int64))
    tensor_2 = ragged_tensor.RaggedTensor.from_row_splits(
        np.array([3, 4, 5]), np.array([0, 2, 3], dtype=np.int64))
    concatenated_tensor = composite_tensor_utils.append_composite_tensor(
        tensor_1, tensor_2)
    evaluated_tensor = self.evaluate(concatenated_tensor)

    self.assertAllEqual(evaluated_tensor.values, [0, 1, 2, 3, 4, 5])
    self.assertAllEqual(evaluated_tensor.row_splits, [0, 1, 3, 5, 6])

  def test_ragged_value_concatenation(self):
    tensor_1 = ragged_tensor_value.RaggedTensorValue(
        np.array([0, 1, 2]), np.array([0, 1, 3], dtype=np.int64))
    tensor_2 = ragged_tensor_value.RaggedTensorValue(
        np.array([3, 4, 5]), np.array([0, 2, 3], dtype=np.int64))
    concatenated_tensor = composite_tensor_utils.append_composite_tensor(
        tensor_1, tensor_2)

    self.assertAllEqual(concatenated_tensor.values, [0, 1, 2, 3, 4, 5])
    self.assertAllEqual(concatenated_tensor.row_splits, [0, 1, 3, 5, 6])

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


<commit_before>import datetime

from discord.ext import commands
import discord
import asyncpg

from utils.checks import need_db
from utils.errors import NotFound
from utils.utils import between, integer
from cogs.base import BaseCog

FACTS = 'https://catfact.ninja/facts?limit={count}'

def make_xkcd_url(num='', api=True):
    url = 'http://xkcd.com/'
    if num:
        url += str(num) + '/'
    if api:
        url += 'info.0.json'
    return url

def xkcd_date(data):
    if 'date' in data:  # data is an asyncpg record
        date = data['date']
    else:  # data is a dict from xkcd api
        date = datetime.date(*map(int, (data['year'], data['month'], data['day'])))
    return date

class Images(BaseCog):
    """Commands to fetch images from various sources."""
    async def fetch_xkcd(self, ctx, num=''):
        if num:
            if num in {'r', 'rand', 'random'}:
                url = 'https://c.xkcd.com/random/comic/'
                try:
                    async with self.bot.http_.get(url, timeout=10) as resp:
                        num = resp.url.parts[1]
                except TimeoutError:
                    raise NotFound('Could not get comic.')
            try:
                rec = await ctx.con.fetchrow('''
                    SELECT * FROM xkcd WHERE num = $1
                    ''', int(num))
            except TypeError:
                raise NotFound('Could not get comic.')
            if rec:
                return rec
        else:
            rec = await ctx.con.fetchrow('''
                SELECT * FROM xkcd WHERE date = 'today'
                ''')
            if rec:
                return rec
        url = make_xkcd_url(num)
        try:
            status, data = await self.bot.request(url)
        except asyncio.TimeoutError:
            status, data = None, None
        if status != 200:
            raise NotFound('Could not get comic.')
        else:
            return data

    async def xkcd_insert(self, ctx, data):
        try:
            async with ctx.con.transaction():
                return await ctx.con.execute('''
                    INSERT INTO xkcd VALUES ($1, $2, $3, $4, $5)
                    ''', data['num'], data['safe_title'],
                    data['alt'], data['img'], xkcd_date(data))
        except asyncpg.UniqueViolationError:
            # got yesterday's comic
            pass

    @need_db
    @commands.command()
    async def xkcd(self, ctx, comic=''):
        """Get xkcd comics.

        [comic] can be the number of a comic or "r"/"rand"/"random"
        """
        data = None
        with ctx.typing():
            try:
                data = await self.fetch_xkcd(ctx, comic)
                if isinstance(data, dict):
                    await self.xkcd_insert(ctx, data)
            except NotFound as e:
                return await ctx.send(e)

            description = f'**Date:** {xkcd_date(data):%m/%d/%Y}\n{data["alt"]}'
            embed = discord.Embed(title=f'{data["num"]}: {data["safe_title"]}',
                                  url=make_xkcd_url(data['num'], api=False),
                                  description=description)
            embed.set_image(url=data['img'])
        await ctx.send(embed=embed)

    async def fetch_facts(self, count):
        status, data = await self.bot.request(FACTS.format(count=count))
        if status != 200:
            raise NotFound('No cat fact available.')
        return [d['fact'] for d in data['data']]

    async def fetch_cat(self):
        status, data = await self.bot.request('http://random.cat/meow')
        if status != 200:
            raise NotFound('Could not get cat.')
        return data['file']

    @commands.group(invoke_without_command=True)
    async def cat(self, ctx):
        """Get a random cat image."""
        with ctx.typing():
            try:
                image_url = await self.fetch_cat()
            except NotFound as e:
                return await ctx.send(e)

            try:
                fact = (await self.fetch_facts(1))[0]
            except NotFound as e:
                fact = ''

            embed = discord.Embed(description=fact or None)
            embed.set_image(url=image_url)
        try:
            await ctx.send(embed=embed)
        except discord.HTTPException:
            embed = discord.Embed(description=fact or None)
            embed.set_footer(text='Failed getting a cat image.')
            await ctx.send(embed=embed)

    @cat.command(name='facts', aliases=['fact'])
    async def cat_facts(self, ctx, count: integer = 1):
        """Get cat facts.

        1 <= [count] <= 20
        """
        count = between(count, 1, 20)
        partial = count - int(count)
        count = int(count)
        if partial:
            count += 1
        elif count == 0:
            return

        try:
            facts = await self.fetch_facts(count)
        except NotFound as e:
            facts = [str(e)]
        else:
            if partial:
                end_ind = int(len(facts[-1]) * partial)
                facts[-1] = facts[-1][:end_ind] or facts[-1][0]

        if len(facts) > 1:
            msg = commands.Paginator(prefix='', suffix='')
            for ind, fact in enumerate(facts):
                msg.add_line(f'{ind + 1}. {fact}')
            for page in msg.pages:
                await ctx.send(page)
        else:
            await ctx.send(facts[0])

    @cat_facts.error
    async def cat_facts_error(self, ctx, exc):
        if isinstance(exc, commands.BadArgument):
            pass
        else:
            ctx.command = ctx.command.name

def setup(bot):
    bot.add_cog(Images(bot))
<commit_msg>get latest comic (mon/wed/fri) if available<commit_after>import datetime

from discord.ext import commands
import discord
import asyncpg

from utils.checks import need_db
from utils.errors import NotFound
from utils.utils import between, integer
from cogs.base import BaseCog

FACTS = 'https://catfact.ninja/facts?limit={count}'

def make_xkcd_url(num='', api=True):
    url = 'http://xkcd.com/'
    if num:
        url += str(num) + '/'
    if api:
        url += 'info.0.json'
    return url

def xkcd_date(data):
    if 'date' in data:  # data is an asyncpg record
        date = data['date']
    else:  # data is a dict from xkcd api
        date = datetime.date(*map(int, (data['year'], data['month'], data['day'])))
    return date

class Images(BaseCog):
    """Commands to fetch images from various sources."""
    async def fetch_xkcd(self, ctx, num=''):
        if num:
            if num in {'r', 'rand', 'random'}:
                url = 'https://c.xkcd.com/random/comic/'
                try:
                    async with self.bot.http_.get(url, timeout=10) as resp:
                        num = resp.url.parts[1]
                except TimeoutError:
                    raise NotFound('Could not get comic.')
            try:
                rec = await ctx.con.fetchrow('''
                    SELECT * FROM xkcd WHERE num = $1
                    ''', int(num))
            except TypeError:
                raise NotFound('Could not get comic.')
            if rec:
                return rec
        else:
            last_date = datetime.date.today()
            for _ in range(3):
                if last_date.weekday() in (0, 2, 4):
                    break
                last_date = last_date - datetime.timedelta(days=1)
            rec = await ctx.con.fetchrow('''
                SELECT * FROM xkcd WHERE date = $1
                ''', last_date)
            if rec:
                return rec
        url = make_xkcd_url(num)
        try:
            status, data = await self.bot.request(url)
        except asyncio.TimeoutError:
            status, data = None, None
        if status != 200:
            raise NotFound('Could not get comic.')
        else:
            return data

    async def xkcd_insert(self, ctx, data):
        try:
            async with ctx.con.transaction():
                return await ctx.con.execute('''
                    INSERT INTO xkcd VALUES ($1, $2, $3, $4, $5)
                    ''', data['num'], data['safe_title'],
                    data['alt'], data['img'], xkcd_date(data))
        except asyncpg.UniqueViolationError:
            # got yesterday's comic
            pass

    @need_db
    @commands.command()
    async def xkcd(self, ctx, comic=''):
        """Get xkcd comics.

        [comic] can be the number of a comic or "r"/"rand"/"random"
        """
        data = None
        with ctx.typing():
            try:
                data = await self.fetch_xkcd(ctx, comic)
                if isinstance(data, dict):
                    await self.xkcd_insert(ctx, data)
            except NotFound as e:
                return await ctx.send(e)

            description = f'**Date:** {xkcd_date(data):%m/%d/%Y}\n{data["alt"]}'
            embed = discord.Embed(title=f'{data["num"]}: {data["safe_title"]}',
                                  url=make_xkcd_url(data['num'], api=False),
                                  description=description)
            embed.set_image(url=data['img'])
        await ctx.send(embed=embed)

    async def fetch_facts(self, count):
        status, data = await self.bot.request(FACTS.format(count=count))
        if status != 200:
            raise NotFound('No cat fact available.')
        return [d['fact'] for d in data['data']]

    async def fetch_cat(self):
        status, data = await self.bot.request('http://random.cat/meow')
        if status != 200:
            raise NotFound('Could not get cat.')
        return data['file']

    @commands.group(invoke_without_command=True)
    async def cat(self, ctx):
        """Get a random cat image."""
        with ctx.typing():
            try:
                image_url = await self.fetch_cat()
            except NotFound as e:
                return await ctx.send(e)

            try:
                fact = (await self.fetch_facts(1))[0]
            except NotFound as e:
                fact = ''

            embed = discord.Embed(description=fact or None)
            embed.set_image(url=image_url)
        try:
            await ctx.send(embed=embed)
        except discord.HTTPException:
            embed = discord.Embed(description=fact or None)
            embed.set_footer(text='Failed getting a cat image.')
            await ctx.send(embed=embed)

    @cat.command(name='facts', aliases=['fact'])
    async def cat_facts(self, ctx, count: integer = 1):
        """Get cat facts.

        1 <= [count] <= 20
        """
        count = between(count, 1, 20)
        partial = count - int(count)
        count = int(count)
        if partial:
            count += 1
        elif count == 0:
            return

        try:
            facts = await self.fetch_facts(count)
        except NotFound as e:
            facts = [str(e)]
        else:
            if partial:
                end_ind = int(len(facts[-1]) * partial)
                facts[-1] = facts[-1][:end_ind] or facts[-1][0]

        if len(facts) > 1:
            msg = commands.Paginator(prefix='', suffix='')
            for ind, fact in enumerate(facts):
                msg.add_line(f'{ind + 1}. {fact}')
            for page in msg.pages:
                await ctx.send(page)
        else:
            await ctx.send(facts[0])

    @cat_facts.error
    async def cat_facts_error(self, ctx, exc):
        if isinstance(exc, commands.BadArgument):
            pass
        else:
            ctx.command = ctx.command.name

def setup(bot):
    bot.add_cog(Images(bot))
<|endoftext|>


<commit_before>import numpy as np
import openpnm as op
from openpnm.phases import mixtures
from numpy.testing import assert_allclose

class TransientMultiphysicsNernstPlanckSolverTest:

    def setup_class(self):
        # network
        np.random.seed(0)
        self.net = op.network.Cubic(shape=[6, 6, 1], spacing=1e-6)
        prs = (
            self.net['pore.back'] * self.net['pore.right']
            + self.net['pore.back'] * self.net['pore.left']
            + self.net['pore.front'] * self.net['pore.right']
            + self.net['pore.front'] * self.net['pore.left']
        )
        prs = self.net.Ps[prs]
        thrts = self.net['throat.surface']
        thrts = self.net.Ts[thrts]
        op.topotools.trim(network=self.net, pores=prs, throats=thrts)
        np.random.seed(0)
        op.topotools.reduce_coordination(self.net, 3)

        # geometry
        np.random.seed(0)
        self.geo = op.geometry.StickAndBall(network=self.net,
                                            pores=self.net.Ps,
                                            throats=self.net.Ts)

        # phase
        self.sw = mixtures.SalineWater(network=self.net)
        # Retrieve handles to each species for use below
        self.Na = self.sw.components['Na_' + self.sw.name]
        self.Cl = self.sw.components['Cl_' + self.sw.name]
        self.H2O = self.sw.components['H2O_' + self.sw.name]

        # physics
        self.phys = op.physics.GenericPhysics(network=self.net,
                                              phase=self.sw,
                                              geometry=self.geo)
        modphys = op.models.physics
        self.flow = modphys.hydraulic_conductance.hagen_poiseuille
        self.phys.add_model(propname='throat.hydraulic_conductance',
                            pore_viscosity='pore.viscosity',
                            throat_viscosity='throat.viscosity',
                            model=self.flow, regen_mode='normal')
        self.current = modphys.ionic_conductance.electroneutrality
        self.phys.add_model(propname='throat.ionic_conductance',
                            ions=[self.Na.name, self.Cl.name],
                            model=self.current, regen_mode='normal')
        self.eA_dif = modphys.diffusive_conductance.ordinary_diffusion
        self.phys.add_model(propname=('throat.diffusive_conductance.' + self.Na.name),
                            pore_diffusivity=('pore.diffusivity.' + self.Na.name),
                            throat_diffusivity=('throat.diffusivity.' + self.Na.name),
                            model=self.eA_dif, regen_mode='normal')
        self.eB_dif = modphys.diffusive_conductance.ordinary_diffusion
        self.phys.add_model(propname=('throat.diffusive_conductance.' + self.Cl.name),
                            pore_diffusivity=('pore.diffusivity.' + self.Cl.name),
                            throat_diffusivity=('throat.diffusivity.' + self.Cl.name),
                            model=self.eB_dif, regen_mode='normal')

        scheme = 'powerlaw'
        self.ad_dif_mig_Na = modphys.ad_dif_mig_conductance.ad_dif_mig
        self.phys.add_model(propname=('throat.ad_dif_mig_conductance.' + self.Na.name),
                            pore_pressure='pore.pressure',
                            model=self.ad_dif_mig_Na, ion=self.Na.name,
                            s_scheme=scheme)

        self.ad_dif_mig_Cl = modphys.ad_dif_mig_conductance.ad_dif_mig
        self.phys.add_model(propname=('throat.ad_dif_mig_conductance.' + self.Cl.name),
                            pore_pressure='pore.pressure',
                            model=self.ad_dif_mig_Cl, ion=self.Cl.name,
                            s_scheme=scheme)

        # settings for algorithms
        setts1 = {'solver_max_iter': 5, 'solver_tol': 1e-08,
                  'solver_rtol': 1e-08, 'nlin_max_iter': 10,
                  'cache_A': False, 'cache_b': False}
        setts2 = {'g_tol': 1e-4, 'g_max_iter': 100, 't_output': 1000,
                  't_step': 500, 't_final': 20000, 't_scheme': 'implicit'}

        # algorithms
        self.sf = op.algorithms.StokesFlow(network=self.net, phase=self.sw,
                                           settings=setts1)
        self.sf.set_value_BC(pores=self.net.pores('right'), values=11)
        self.sf.set_value_BC(pores=self.net.pores('left'), values=10)

        self.p = op.algorithms.TransientIonicConduction(network=self.net,
                                                        phase=self.sw,
                                                        settings=setts1)
        self.p.set_value_BC(pores=self.net.pores('back'), values=0.02)
        self.p.set_value_BC(pores=self.net.pores('front'), values=0.01)
        self.p.settings['charge_conservation'] = 'electroneutrality'

        self.eA = op.algorithms.TransientNernstPlanck(network=self.net,
                                                      phase=self.sw,
                                                      ion=self.Na.name,
                                                      settings=setts1)
        self.eA.set_value_BC(pores=self.net.pores('right'), values=20)
        self.eA.set_value_BC(pores=self.net.pores('left'), values=10)

        self.eB = op.algorithms.TransientNernstPlanck(network=self.net,
                                                      phase=self.sw,
                                                      ion=self.Cl.name,
                                                      settings=setts1)
        self.eB.set_value_BC(pores=self.net.pores('right'), values=20)
        self.eB.set_value_BC(pores=self.net.pores('left'), values=10)

        mnp = op.algorithms.TransientNernstPlanckMultiphysicsSolver
        self.mnp = mnp(network=self.net, phase=self.sw, settings=setts2)
        self.mnp.setup(potential_field=self.p.name,
                       ions=[self.eA.name, self.eB.name])

    def test_run_algs(self):
        self.sf.run()
        self.sw.update(self.sf.results())
        self.mnp.run()
        self.sw.update(self.p.results())
        self.sw.update(self.eA.results())
        self.sw.update(self.eB.results())

    def test_concentration_Na(self):
        x = [10.,         10.,         10.,         10.,         10.53517114,
             11.08046064, 11.71018632, 11.96714113, 11.72777708, 12.86695077,
             11.58746158, 12.65040345, 13.25574649, 13.47731388, 14.06090075,
             15.27217686, 13.05944438, 14.69280374, 14.62286844, 15.10186986,
             16.15146162, 17.35993123, 14.90573687, 16.25298948, 16.74426472,
             16.63951847, 17.98769641, 19.21709326, 20.,         20.,
             20.,         20.]
        x = np.around(x, decimals=5)
        y = np.around(self.sw['pore.concentration.Na_mix_01'], decimals=5)
        assert_allclose(actual=y, desired=x)

    def test_concentration_Cl(self):
        x = [10.,         10.,         10.,         10.,         13.06578514,
             12.42279423, 11.58371717, 11.40980409, 10.79147327,  9.83605168,
             15.77521525, 14.44971313, 13.47980971, 12.80209187, 12.07204557,
             11.11458021, 17.92765688, 15.93468763, 14.72209168, 13.95745968,
             13.35854227, 12.42861968, 19.45846835, 17.84550525, 17.00086559,
             15.76790954, 15.91290826, 14.89489377, 20.,         20.,
             20.,         20.]
        x = np.around(x, decimals=5)
        y = np.around(self.sw['pore.concentration.Cl_mix_01'], decimals=5)
        assert_allclose(actual=y, desired=x)

    def test_potential(self):
        x = [0.01870404, 0.01418691, 0.01324578, 0.01238089, 0.02,
             0.01870404, 0.01418691, 0.01324578, 0.01238089, 0.01,
             0.02,       0.01774593, 0.01519198, 0.0137006,  0.01212227,
             0.01,       0.02,       0.01697308, 0.01525899, 0.01349426,
             0.01185306, 0.01,       0.02,       0.01777765, 0.01560814,
             0.0135155,  0.01169786, 0.01,       0.01777765, 0.01560814,
             0.0135155,  0.01169786]
        x = np.around(x, decimals=5)
        y = np.around(self.sw['pore.potential'], decimals=5)
        assert_allclose(actual=y, desired=x)

    def test_times(self):
        times = [
            "pore.concentration.Na_mix_01@1000",
            "pore.concentration.Cl_mix_01@1000",
            "pore.potential@1000",
            "pore.concentration.Na_mix_01@2000",
            "pore.concentration.Cl_mix_01@2000",
            "pore.potential@2000",
            "pore.concentration.Na_mix_01@3000",
            "pore.concentration.Cl_mix_01@3000",
            "pore.potential@3000",
            "pore.concentration.Na_mix_01@3500",
            "pore.concentration.Cl_mix_01@3500",
            "pore.potential@3500",
        ]
        assert set(times).issubset(set(self.sw.keys()))

    def teardown_class(self):
        ws = op.Workspace()
        ws.clear()

if __name__ == '__main__':
    t = TransientMultiphysicsNernstPlanckSolverTest()
    t.setup_class()
    self = t
    for item in t.__dir__():
        if item.startswith('test'):
            print('running test: '+item)
            t.__getattribute__(item)()
<commit_msg>Testing laplace in TransientMultiphysicsNernstPlanckSolverTest<commit_after>import numpy as np
import openpnm as op
from openpnm.phases import mixtures
from numpy.testing import assert_allclose

class TransientMultiphysicsNernstPlanckSolverTest:

    def setup_class(self):
        # network
        np.random.seed(0)
        self.net = op.network.Cubic(shape=[6, 6, 1], spacing=1e-6)
        prs = (
            self.net['pore.back'] * self.net['pore.right']
            + self.net['pore.back'] * self.net['pore.left']
            + self.net['pore.front'] * self.net['pore.right']
            + self.net['pore.front'] * self.net['pore.left']
        )
        prs = self.net.Ps[prs]
        thrts = self.net['throat.surface']
        thrts = self.net.Ts[thrts]
        op.topotools.trim(network=self.net, pores=prs, throats=thrts)
        np.random.seed(0)
        op.topotools.reduce_coordination(self.net, 3)

        # geometry
        np.random.seed(0)
        self.geo = op.geometry.StickAndBall(network=self.net,
                                            pores=self.net.Ps,
                                            throats=self.net.Ts)

        # phase
        self.sw = mixtures.SalineWater(network=self.net)
        # Retrieve handles to each species for use below
        self.Na = self.sw.components['Na_' + self.sw.name]
        self.Cl = self.sw.components['Cl_' + self.sw.name]
        self.H2O = self.sw.components['H2O_' + self.sw.name]

        # physics
        self.phys = op.physics.GenericPhysics(network=self.net,
                                              phase=self.sw,
                                              geometry=self.geo)
        modphys = op.models.physics
        self.flow = modphys.hydraulic_conductance.hagen_poiseuille
        self.phys.add_model(propname='throat.hydraulic_conductance',
                            pore_viscosity='pore.viscosity',
                            throat_viscosity='throat.viscosity',
                            model=self.flow, regen_mode='normal')
        self.current = modphys.ionic_conductance.electroneutrality
        self.phys.add_model(propname='throat.ionic_conductance',
                            ions=[self.Na.name, self.Cl.name],
                            model=self.current, regen_mode='normal')
        self.eA_dif = modphys.diffusive_conductance.ordinary_diffusion
        self.phys.add_model(propname=('throat.diffusive_conductance.' + self.Na.name),
                            pore_diffusivity=('pore.diffusivity.' + self.Na.name),
                            throat_diffusivity=('throat.diffusivity.' + self.Na.name),
                            model=self.eA_dif, regen_mode='normal')
        self.eB_dif = modphys.diffusive_conductance.ordinary_diffusion
        self.phys.add_model(propname=('throat.diffusive_conductance.' + self.Cl.name),
                            pore_diffusivity=('pore.diffusivity.' + self.Cl.name),
                            throat_diffusivity=('throat.diffusivity.' + self.Cl.name),
                            model=self.eB_dif, regen_mode='normal')

        scheme = 'powerlaw'
        self.ad_dif_mig_Na = modphys.ad_dif_mig_conductance.ad_dif_mig
        self.phys.add_model(propname=('throat.ad_dif_mig_conductance.' + self.Na.name),
                            pore_pressure='pore.pressure',
                            model=self.ad_dif_mig_Na, ion=self.Na.name,
                            s_scheme=scheme)

        self.ad_dif_mig_Cl = modphys.ad_dif_mig_conductance.ad_dif_mig
        self.phys.add_model(propname=('throat.ad_dif_mig_conductance.' + self.Cl.name),
                            pore_pressure='pore.pressure',
                            model=self.ad_dif_mig_Cl, ion=self.Cl.name,
                            s_scheme=scheme)

        # settings for algorithms
        setts1 = {'solver_max_iter': 5, 'solver_tol': 1e-08,
                  'solver_rtol': 1e-08, 'nlin_max_iter': 10,
                  'cache_A': False, 'cache_b': False}
        setts2 = {'g_tol': 1e-4, 'g_max_iter': 100, 't_output': 1000,
                  't_step': 500, 't_final': 20000, 't_scheme': 'implicit'}

        # algorithms
        self.sf = op.algorithms.StokesFlow(network=self.net, phase=self.sw,
                                           settings=setts1)
        self.sf.set_value_BC(pores=self.net.pores('right'), values=11)
        self.sf.set_value_BC(pores=self.net.pores('left'), values=10)

        self.p = op.algorithms.TransientIonicConduction(network=self.net,
                                                        phase=self.sw,
                                                        settings=setts1)
        self.p.set_value_BC(pores=self.net.pores('back'), values=0.02)
        self.p.set_value_BC(pores=self.net.pores('front'), values=0.01)
        self.p.settings['charge_conservation'] = 'laplace'

        self.eA = op.algorithms.TransientNernstPlanck(network=self.net,
                                                      phase=self.sw,
                                                      ion=self.Na.name,
                                                      settings=setts1)
        self.eA.set_value_BC(pores=self.net.pores('right'), values=20)
        self.eA.set_value_BC(pores=self.net.pores('left'), values=10)

        self.eB = op.algorithms.TransientNernstPlanck(network=self.net,
                                                      phase=self.sw,
                                                      ion=self.Cl.name,
                                                      settings=setts1)
        self.eB.set_value_BC(pores=self.net.pores('right'), values=20)
        self.eB.set_value_BC(pores=self.net.pores('left'), values=10)

        mnp = op.algorithms.TransientNernstPlanckMultiphysicsSolver
        self.mnp = mnp(network=self.net, phase=self.sw, settings=setts2)
        self.mnp.setup(potential_field=self.p.name,
                       ions=[self.eA.name, self.eB.name])

    def test_run_algs(self):
        self.sf.run()
        self.sw.update(self.sf.results())
        self.mnp.run()
        self.sw.update(self.p.results())
        self.sw.update(self.eA.results())
        self.sw.update(self.eB.results())

    def test_concentration_Na(self):
        x = [10.,         10.,         10.,         10.,         10.53517114,
             11.08046064, 11.71018632, 11.96714113, 11.72777708, 12.86695077,
             11.58746158, 12.65040345, 13.25574649, 13.47731388, 14.06090075,
             15.27217686, 13.05944438, 14.69280374, 14.62286844, 15.10186986,
             16.15146162, 17.35993123, 14.90573687, 16.25298948, 16.74426472,
             16.63951847, 17.98769641, 19.21709326, 20.,         20.,
             20.,         20.]
        x = np.around(x, decimals=5)
        y = np.around(self.sw['pore.concentration.Na_mix_01'], decimals=5)
        assert_allclose(actual=y, desired=x)

    def test_concentration_Cl(self):
        x = [10.,         10.,         10.,         10.,         13.06578514,
             12.42279423, 11.58371717, 11.40980409, 10.79147327,  9.83605168,
             15.77521525, 14.44971313, 13.47980971, 12.80209187, 12.07204557,
             11.11458021, 17.92765688, 15.93468763, 14.72209168, 13.95745968,
             13.35854227, 12.42861968, 19.45846835, 17.84550525, 17.00086559,
             15.76790954, 15.91290826, 14.89489377, 20.,         20.,
             20.,         20.]
        x = np.around(x, decimals=5)
        y = np.around(self.sw['pore.concentration.Cl_mix_01'], decimals=5)
        assert_allclose(actual=y, desired=x)

    def test_potential(self):
        x = [0.01870404, 0.01418691, 0.01324578, 0.01238089, 0.02,
             0.01870404, 0.01418691, 0.01324578, 0.01238089, 0.01,
             0.02,       0.01774593, 0.01519198, 0.0137006,  0.01212227,
             0.01,       0.02,       0.01697308, 0.01525899, 0.01349426,
             0.01185306, 0.01,       0.02,       0.01777765, 0.01560814,
             0.0135155,  0.01169786, 0.01,       0.01777765, 0.01560814,
             0.0135155,  0.01169786]
        x = np.around(x, decimals=5)
        y = np.around(self.sw['pore.potential'], decimals=5)
        assert_allclose(actual=y, desired=x)

    def test_times(self):
        times = [
            "pore.concentration.Na_mix_01@1000",
            "pore.concentration.Cl_mix_01@1000",
            "pore.potential@1000",
            "pore.concentration.Na_mix_01@2000",
            "pore.concentration.Cl_mix_01@2000",
            "pore.potential@2000",
            "pore.concentration.Na_mix_01@3000",
            "pore.concentration.Cl_mix_01@3000",
            "pore.potential@3000",
            "pore.concentration.Na_mix_01@3500",
            "pore.concentration.Cl_mix_01@3500",
            "pore.potential@3500",
        ]
        assert set(times).issubset(set(self.sw.keys()))

    def teardown_class(self):
        ws = op.Workspace()
        ws.clear()

if __name__ == '__main__':
    t = TransientMultiphysicsNernstPlanckSolverTest()
    t.setup_class()
    self = t
    for item in t.__dir__():
        if item.startswith('test'):
            print('running test: '+item)
            t.__getattribute__(item)()
<|endoftext|>


<commit_before>import asyncio
from datetime import datetime
from typing import Any, Iterable, Optional

import discord
from asyncqlio.db import DatabaseInterface
from discord import AllowedMentions, Embed, TextChannel
from discord.ext import commands, menus
from discord.ext.commands import Cog
from discord.ext.menus import MenuKeysetPages, PageDirection, PageSpecifier

from bot import BeattieBot
from context import BContext
from schema.remind import Reminder, Table
from utils.checks import is_owner_or
from utils.converters import Time
from utils.etc import reverse_insort_by_key

class ReminderSource(menus.KeysetPageSource):
    def __init__(self, db: DatabaseInterface, user_id: int, guild_id: int):
        self.db = db
        self.user_id = user_id
        self.guild_id = guild_id

    def is_paginating(self) -> bool:
        return True

    async def get_page(self, specifier: PageSpecifier) -> list[Reminder]:
        async with self.db.get_session() as s:
            query = (
                s.select(Reminder)
                .where(
                    (Reminder.user_id == self.user_id)
                    & (Reminder.guild_id == self.guild_id)
                )
                .limit(10)
            )

            if specifier.reference is not None:
                if specifier.direction is PageDirection.after:
                    query = query.where(Reminder.id > specifier.reference[-1]["id"])
                else:
                    query = query.where(Reminder.id < specifier.reference[0]["id"])

            sort_order = "asc" if specifier.direction is PageDirection.after else "desc"
            query = query.order_by(Reminder.id, sort_order=sort_order)

            results = [reminder async for reminder in await query.all()]

        if not results:
            raise ValueError
        if specifier.direction is PageDirection.before:
            results.reverse()

        return results

    async def format_page(self, _: Any, page: Iterable[Reminder]) -> Embed:
        return Embed(
            description="\n".join(
                f'ID {row.id}: "{row.topic}" at {row.time}' for row in page
            )
        )

class Remind(Cog):
    def __init__(self, bot: BeattieBot):
        self.queue: list[Reminder] = []
        self.loop = bot.loop
        self.db = bot.db
        self.bot = bot
        self.db.bind_tables(Table)
        self.timer: asyncio.Task = self.loop.create_task(asyncio.sleep(0))
        self.loop.create_task(self.__init())

    def cog_check(self, ctx: BContext) -> bool:
        return ctx.guild is not None

    def cog_unload(self) -> None:
        self.timer.cancel()

    async def __init(self) -> None:
        await self.bot.wait_until_ready()
        await Reminder.create(if_not_exists=True)
        async with self.db.get_session() as s:
            query = s.select(Reminder).order_by(Reminder.time, sort_order="desc")
            self.queue = [reminder async for reminder in await query.all()]
        await self.start_timer()

    @commands.group(invoke_without_command=True, usage="")
    async def remind(
        self,
        ctx: BContext,
        time: Time,
        *,
        topic: Optional[commands.clean_content] = None,
    ) -> None:
        """Commands for setting and managing reminders."""
        await self.set_reminder(ctx, time, topic=topic)

    @remind.error
    async def remind_error(self, ctx: BContext, e: Exception) -> None:
        if ctx.invoked_subcommand is None:
            await self.set_reminder_error(ctx, e)

    @remind.command(name="set", aliases=["me"])
    async def set_reminder(
        self,
        ctx: BContext,
        time: Time,
        *,
        topic: Optional[str] = None,
    ) -> None:
        """Have the bot remind you about something.
        First put time (in quotes if there are spaces), then topic"""
        await self.schedule_reminder(ctx, time, topic)
        await ctx.send("Okay, I'll remind you.")

    @set_reminder.error
    async def set_reminder_error(self, ctx: BContext, e: Exception) -> None:
        if isinstance(e, (commands.BadArgument, commands.ConversionError)):
            await ctx.send(
                "Bad input. Valid input examples:\n"
                "remind 10m pizza\n"
                'remind "two days" check progress'
            )
        else:
            await ctx.bot.handle_error(ctx, e)

    @remind.command(name="list")
    async def list_reminders(self, ctx: BContext) -> None:
        """List all reminders active for you in this server."""
        assert ctx.guild is not None
        pages = MenuKeysetPages(
            source=ReminderSource(ctx.bot.db, ctx.author.id, ctx.guild.id),
            clear_reactions_after=True,
        )
        try:
            await pages.start(ctx)
        except ValueError:
            await ctx.send("No reminders to show.")

    @remind.command(name="delete", aliases=["remove", "del", "cancel"])
    async def delete_reminder(self, ctx: BContext, reminder_id: int) -> None:
        """Delete a specific reminder. Use `list` to get IDs."""
        async with ctx.bot.db.get_session() as s:
            query = s.select(Reminder).where(Reminder.id == reminder_id)
            reminder = await query.first()
            if reminder is None:
                await ctx.send("No such reminder.")
                return
            if reminder.user_id != ctx.author.id:
                await ctx.send("That reminder belongs to someone else.")
                return
            await s.remove(reminder)

        if self.queue[-1] == reminder:
            self.timer.cancel()
            self.queue.pop()
            await self.start_timer()
        else:
            self.queue.remove(reminder)

        await ctx.send("Reminder deleted.")

    @remind.command(name="channel")
    @is_owner_or(manage_guild=True)
    async def set_channel(
        self, ctx: BContext, channel: Optional[TextChannel] = None
    ) -> None:
        """Set the channel reminders will appear in. Invoke with no input to reset."""
        assert ctx.guild is not None
        await ctx.bot.config.set_guild(
            ctx.guild.id, reminder_channel=channel and channel.id
        )
        if channel is None:
            destination = "the channel they were invoked in"
        else:
            destination = channel.mention
        await ctx.send(f"All reminders will be sent to {destination} from now on.")

    async def schedule_reminder(
        self, ctx: BContext, time: Time, topic: Optional[str]
    ) -> None:
        assert ctx.guild is not None
        async with self.db.get_session() as s:
            reminder = await s.add(
                Reminder(
                    guild_id=ctx.guild.id,
                    channel_id=ctx.channel.id,
                    message_id=ctx.message.id,
                    user_id=ctx.author.id,
                    time=time,
                    topic=topic,
                )
            )
        if not self.queue or reminder.time < self.queue[-1].time:
            self.queue.append(reminder)
            self.timer.cancel()
            await self.start_timer()
        else:
            reverse_insort_by_key(
                self.queue, reminder, key=lambda r: r.time, hi=len(self.queue) - 1
            )

    async def send_reminder(self, reminder: Reminder) -> None:
        if (
            (guild := self.bot.get_guild(reminder.guild_id))
            and (member := guild.get_member(reminder.user_id))
            and (
                channel := guild.get_channel(
                    (await self.bot.config.get_guild(guild.id)).get("reminder_channel")
                    or reminder.channel_id
                )
            )
        ):
            assert isinstance(channel, TextChannel)
            topic = reminder.topic or "something"
            message = f"You asked to be reminded about {topic}."
            reference = None
            if message_id := reminder.message_id:
                reference = discord.MessageReference(
                    message_id=message_id,
                    channel_id=reminder.channel_id,
                    guild_id=reminder.guild_id,
                )
            try:
                await channel.send(
                    message,
                    reference=reference,
                )
            except (discord.NotFound, discord.Forbidden):
                pass
            except Exception as e:
                message = (
                    "An error occured in sending a reminder to "
                    f"{channel.guild.name}#{channel.name}"
                )
                self.bot.logger.exception(
                    message, exc_info=(type(e), e, e.__traceback__)
                )
        async with self.db.get_session() as s:
            await s.remove(reminder)

    async def start_timer(self) -> None:
        self.timer = self.loop.create_task(self.sleep())

    async def sleep(self) -> None:
        try:
            while self.queue:
                delta = (self.queue[-1].time - datetime.now()).total_seconds()
                if delta <= 0:
                    await self.send_reminder(self.queue.pop())
                else:
                    await asyncio.sleep(min(delta, 3_000_000))
        except Exception as e:
            import traceback

            traceback.print_exception(type(e), e, e.__traceback__)

def setup(bot: BeattieBot) -> None:
    bot.add_cog(Remind(bot))
<commit_msg>Re-sanitize mentions for reminders (lol)<commit_after>import asyncio
from datetime import datetime
from typing import Any, Iterable, Optional

import discord
from asyncqlio.db import DatabaseInterface
from discord import AllowedMentions, Embed, TextChannel
from discord.ext import commands, menus
from discord.ext.commands import Cog
from discord.ext.menus import MenuKeysetPages, PageDirection, PageSpecifier

from bot import BeattieBot
from context import BContext
from schema.remind import Reminder, Table
from utils.checks import is_owner_or
from utils.converters import Time
from utils.etc import reverse_insort_by_key

class ReminderSource(menus.KeysetPageSource):
    def __init__(self, db: DatabaseInterface, user_id: int, guild_id: int):
        self.db = db
        self.user_id = user_id
        self.guild_id = guild_id

    def is_paginating(self) -> bool:
        return True

    async def get_page(self, specifier: PageSpecifier) -> list[Reminder]:
        async with self.db.get_session() as s:
            query = (
                s.select(Reminder)
                .where(
                    (Reminder.user_id == self.user_id)
                    & (Reminder.guild_id == self.guild_id)
                )
                .limit(10)
            )

            if specifier.reference is not None:
                if specifier.direction is PageDirection.after:
                    query = query.where(Reminder.id > specifier.reference[-1]["id"])
                else:
                    query = query.where(Reminder.id < specifier.reference[0]["id"])

            sort_order = "asc" if specifier.direction is PageDirection.after else "desc"
            query = query.order_by(Reminder.id, sort_order=sort_order)

            results = [reminder async for reminder in await query.all()]

        if not results:
            raise ValueError
        if specifier.direction is PageDirection.before:
            results.reverse()

        return results

    async def format_page(self, _: Any, page: Iterable[Reminder]) -> Embed:
        return Embed(
            description="\n".join(
                f'ID {row.id}: "{row.topic}" at {row.time}' for row in page
            )
        )

class Remind(Cog):
    def __init__(self, bot: BeattieBot):
        self.queue: list[Reminder] = []
        self.loop = bot.loop
        self.db = bot.db
        self.bot = bot
        self.db.bind_tables(Table)
        self.timer: asyncio.Task = self.loop.create_task(asyncio.sleep(0))
        self.loop.create_task(self.__init())

    def cog_check(self, ctx: BContext) -> bool:
        return ctx.guild is not None

    def cog_unload(self) -> None:
        self.timer.cancel()

    async def __init(self) -> None:
        await self.bot.wait_until_ready()
        await Reminder.create(if_not_exists=True)
        async with self.db.get_session() as s:
            query = s.select(Reminder).order_by(Reminder.time, sort_order="desc")
            self.queue = [reminder async for reminder in await query.all()]
        await self.start_timer()

    @commands.group(invoke_without_command=True, usage="")
    async def remind(
        self,
        ctx: BContext,
        time: Time,
        *,
        topic: Optional[commands.clean_content] = None,
    ) -> None:
        """Commands for setting and managing reminders."""
        await self.set_reminder(ctx, time, topic=topic)

    @remind.error
    async def remind_error(self, ctx: BContext, e: Exception) -> None:
        if ctx.invoked_subcommand is None:
            await self.set_reminder_error(ctx, e)

    @remind.command(name="set", aliases=["me"])
    async def set_reminder(
        self,
        ctx: BContext,
        time: Time,
        *,
        topic: Optional[str] = None,
    ) -> None:
        """Have the bot remind you about something.
        First put time (in quotes if there are spaces), then topic"""
        await self.schedule_reminder(ctx, time, topic)
        await ctx.send("Okay, I'll remind you.")

    @set_reminder.error
    async def set_reminder_error(self, ctx: BContext, e: Exception) -> None:
        if isinstance(e, (commands.BadArgument, commands.ConversionError)):
            await ctx.send(
                "Bad input. Valid input examples:\n"
                "remind 10m pizza\n"
                'remind "two days" check progress'
            )
        else:
            await ctx.bot.handle_error(ctx, e)

    @remind.command(name="list")
    async def list_reminders(self, ctx: BContext) -> None:
        """List all reminders active for you in this server."""
        assert ctx.guild is not None
        pages = MenuKeysetPages(
            source=ReminderSource(ctx.bot.db, ctx.author.id, ctx.guild.id),
            clear_reactions_after=True,
        )
        try:
            await pages.start(ctx)
        except ValueError:
            await ctx.send("No reminders to show.")

    @remind.command(name="delete", aliases=["remove", "del", "cancel"])
    async def delete_reminder(self, ctx: BContext, reminder_id: int) -> None:
        """Delete a specific reminder. Use `list` to get IDs."""
        async with ctx.bot.db.get_session() as s:
            query = s.select(Reminder).where(Reminder.id == reminder_id)
            reminder = await query.first()
            if reminder is None:
                await ctx.send("No such reminder.")
                return
            if reminder.user_id != ctx.author.id:
                await ctx.send("That reminder belongs to someone else.")
                return
            await s.remove(reminder)

        if self.queue[-1] == reminder:
            self.timer.cancel()
            self.queue.pop()
            await self.start_timer()
        else:
            self.queue.remove(reminder)

        await ctx.send("Reminder deleted.")

    @remind.command(name="channel")
    @is_owner_or(manage_guild=True)
    async def set_channel(
        self, ctx: BContext, channel: Optional[TextChannel] = None
    ) -> None:
        """Set the channel reminders will appear in. Invoke with no input to reset."""
        assert ctx.guild is not None
        await ctx.bot.config.set_guild(
            ctx.guild.id, reminder_channel=channel and channel.id
        )
        if channel is None:
            destination = "the channel they were invoked in"
        else:
            destination = channel.mention
        await ctx.send(f"All reminders will be sent to {destination} from now on.")

    async def schedule_reminder(
        self, ctx: BContext, time: Time, topic: Optional[str]
    ) -> None:
        assert ctx.guild is not None
        async with self.db.get_session() as s:
            reminder = await s.add(
                Reminder(
                    guild_id=ctx.guild.id,
                    channel_id=ctx.channel.id,
                    message_id=ctx.message.id,
                    user_id=ctx.author.id,
                    time=time,
                    topic=topic,
                )
            )
        if not self.queue or reminder.time < self.queue[-1].time:
            self.queue.append(reminder)
            self.timer.cancel()
            await self.start_timer()
        else:
            reverse_insort_by_key(
                self.queue, reminder, key=lambda r: r.time, hi=len(self.queue) - 1
            )

    async def send_reminder(self, reminder: Reminder) -> None:
        if (
            (guild := self.bot.get_guild(reminder.guild_id))
            and (member := guild.get_member(reminder.user_id))
            and (
                channel := guild.get_channel(
                    (await self.bot.config.get_guild(guild.id)).get("reminder_channel")
                    or reminder.channel_id
                )
            )
        ):
            assert isinstance(channel, TextChannel)
            topic = reminder.topic or "something"
            message = f"You asked to be reminded about {topic}."
            reference = None
            if message_id := reminder.message_id:
                reference = discord.MessageReference(
                    message_id=message_id,
                    channel_id=reminder.channel_id,
                    guild_id=reminder.guild_id,
                )
            try:
                await channel.send(
                    message,
                    allowed_mentions=AllowedMentions(
                        everyone=False, users=[member], roles=False
                    ),
                    reference=reference,
                )
            except (discord.NotFound, discord.Forbidden):
                pass
            except Exception as e:
                message = (
                    "An error occured in sending a reminder to "
                    f"{channel.guild.name}#{channel.name}"
                )
                self.bot.logger.exception(
                    message, exc_info=(type(e), e, e.__traceback__)
                )
        async with self.db.get_session() as s:
            await s.remove(reminder)

    async def start_timer(self) -> None:
        self.timer = self.loop.create_task(self.sleep())

    async def sleep(self) -> None:
        try:
            while self.queue:
                delta = (self.queue[-1].time - datetime.now()).total_seconds()
                if delta <= 0:
                    await self.send_reminder(self.queue.pop())
                else:
                    await asyncio.sleep(min(delta, 3_000_000))
        except Exception as e:
            import traceback

            traceback.print_exception(type(e), e, e.__traceback__)

def setup(bot: BeattieBot) -> None:
    bot.add_cog(Remind(bot))
<|endoftext|>


<commit_before>from discord.ext.commands import bot
import discord
from main import blacklisted
from cogs.Admin import owner
from config.config import Config

class Twitch():
    def __init__(self, bot):
        self.bot = bot
        self.con = Config(bot)

    async def on_member_update(self, member_b, member_a):
        # Twitch Shilling Part
        if blacklisted(member_b):
            return
        if member_a.game:
            if member_a.game.type and not member_b.game.type:
                ts_enabled = self.con.serverconfig[member_a.server.id]["twitch"]["enabled"]
                ts_whitelist = self.con.serverconfig[member_a.server.id]["twitch"]["whitelist"]["enabled"]
                if ts_enabled:
                    if not ts_whitelist or member_a.id in \
                            self.con.serverconfig[member_a.server.id]["twitch"]["whitelist"]["list"]:
                        channel = discord.Object(self.con.serverconfig[member_a.server.id]["twitch"]["twitch-channel"])
                        return await self.bot.send_message(channel,
                                                           content=":video_game:** {} is live!** :video_game:\n {}\n{}".format(
                                                               member_a.name, member_a.game.name, member_a.game.url))

    @bot.command(pass_context=True, hidden=True)
    async def ts_enablewhitelist(self, ctx):
        if not owner(ctx):
            return await self.bot.reply("You do not have permission to do this command.", delete_after=20)
        else:
            self.con.serverconfig = self.con.load_config()
            if not self.con.serverconfig[ctx.server.id]["twitch"]["whitelist"]["enabled"]:
                self.con.serverconfig[ctx.server.id]["twitch"]["whitelist"]["enabled"] = 1
                self.con.updateconfig()
                return await self.bot.reply("Whitelist for Twitch shilling has been enabled.")
            else:
                self.con.serverconfig[ctx.server.id]["twitch"]["whitelist"]["enabled"] = 0
                self.con.updateconfig()
                return await self.bot.reply("Whitelist for Twitch shilling has been disabled.")

    @bot.command(pass_context=True, hidden=True)
    async def ts_whitelist(self, ctx, option, *mentions):
        if not owner(ctx):
            return await self.bot.reply("You do not have permission to do this command.", delete_after=20)

        whitelist_count = 0

        if not ctx.message.mentions and option != 'list':
            return await self.bot.reply("You haven't mentioned anyone to whitelist.")

        if option not in ['+', '-', 'add', 'remove', 'list']:
            return await self.bot.say('Invalid option "%s" specified, use +, -, add, or remove' % option, expire_in=20)

        if option in ['+', 'add']:
            self.con.serverconfig = self.con.load_config()
            for user in ctx.message.mentions:
                self.con.serverconfig[ctx.message.server.id]["twitch"]["whitelist"]["list"].append(user.id)
                self.con.updateconfig()
                whitelist_count += 1
            return await self.bot.say('{} user(s) have been added to the whitelist'.format(whitelist_count))

        elif option in ['-', 'remove']:
            self.con.serverconfig = self.con.load_config()
            for user in ctx.message.mentions:
                if user.id in self.con.serverconfig[ctx.message.server.id]["twitch"]["whitelist"]["list"]:
                    self.con.serverconfig[ctx.message.server.id]["twitch"]["whitelist"]["list"].remove(user.id)
                    self.con.updateconfig()
                    whitelist_count += 1
            return await self.bot.say('{} user(s) have been removed to the whitelist'.format(whitelist_count))

        elif option == 'list':
            return await self.bot.say(
                self.con.serverconfig[ctx.message.server.id]["twitch"]["whitelist"]["list"])

def setup(bot):
    bot.add_cog(Twitch(bot))
<commit_msg>never fixed that space issue grrr<commit_after>from discord.ext.commands import bot
import discord
from main import blacklisted
from cogs.Admin import owner
from config.config import Config

class Twitch():
    def __init__(self, bot):
        self.bot = bot
        self.con = Config(bot)

    async def on_member_update(self, member_b, member_a):
        # Twitch Shilling Part
        if blacklisted(member_b):
            return
        if member_a.game:
            if member_a.game.type and not member_b.game.type:
                ts_enabled = self.con.serverconfig[member_a.server.id]["twitch"]["enabled"]
                ts_whitelist = self.con.serverconfig[member_a.server.id]["twitch"]["whitelist"]["enabled"]
                if ts_enabled:
                    if not ts_whitelist or member_a.id in \
                            self.con.serverconfig[member_a.server.id]["twitch"]["whitelist"]["list"]:
                        channel = discord.Object(self.con.serverconfig[member_a.server.id]["twitch"]["twitch-channel"])
                        return await self.bot.send_message(channel,
                                                           content=":video_game:** {} is live!** :video_game:\n{}\n{}".format(
                                                               member_a.name, member_a.game.name, member_a.game.url))

    @bot.command(pass_context=True, hidden=True)
    async def ts_enablewhitelist(self, ctx):
        if not owner(ctx):
            return await self.bot.reply("You do not have permission to do this command.", delete_after=20)
        else:
            self.con.serverconfig = self.con.load_config()
            if not self.con.serverconfig[ctx.server.id]["twitch"]["whitelist"]["enabled"]:
                self.con.serverconfig[ctx.server.id]["twitch"]["whitelist"]["enabled"] = 1
                self.con.updateconfig()
                return await self.bot.reply("Whitelist for Twitch shilling has been enabled.")
            else:
                self.con.serverconfig[ctx.server.id]["twitch"]["whitelist"]["enabled"] = 0
                self.con.updateconfig()
                return await self.bot.reply("Whitelist for Twitch shilling has been disabled.")

    @bot.command(pass_context=True, hidden=True)
    async def ts_whitelist(self, ctx, option, *mentions):
        if not owner(ctx):
            return await self.bot.reply("You do not have permission to do this command.", delete_after=20)

        whitelist_count = 0

        if not ctx.message.mentions and option != 'list':
            return await self.bot.reply("You haven't mentioned anyone to whitelist.")

        if option not in ['+', '-', 'add', 'remove', 'list']:
            return await self.bot.say('Invalid option "%s" specified, use +, -, add, or remove' % option, expire_in=20)

        if option in ['+', 'add']:
            self.con.serverconfig = self.con.load_config()
            for user in ctx.message.mentions:
                self.con.serverconfig[ctx.message.server.id]["twitch"]["whitelist"]["list"].append(user.id)
                self.con.updateconfig()
                whitelist_count += 1
            return await self.bot.say('{} user(s) have been added to the whitelist'.format(whitelist_count))

        elif option in ['-', 'remove']:
            self.con.serverconfig = self.con.load_config()
            for user in ctx.message.mentions:
                if user.id in self.con.serverconfig[ctx.message.server.id]["twitch"]["whitelist"]["list"]:
                    self.con.serverconfig[ctx.message.server.id]["twitch"]["whitelist"]["list"].remove(user.id)
                    self.con.updateconfig()
                    whitelist_count += 1
            return await self.bot.say('{} user(s) have been removed to the whitelist'.format(whitelist_count))

        elif option == 'list':
            return await self.bot.say(
                self.con.serverconfig[ctx.message.server.id]["twitch"]["whitelist"]["list"])

def setup(bot):
    bot.add_cog(Twitch(bot))
<|endoftext|>


<commit_before>"""
MIT License

Copyright (c) 2017 s0hvaperuna

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

import logging
from collections import deque

from aiohttp import ClientSession
from discord.ext.commands import cooldown

from bot.bot import command
from utils.utilities import send_paged_message

logger = logging.getLogger('debug')

class SearchItem:
    def __init__(self, **kwargs):
        self.url = kwargs.pop('link', 'None')
        self.title = kwargs.pop('title', 'Untitled')

    def __str__(self):
        return '{0.url}'.format(self)

class Search:
    def __init__(self, bot, client: ClientSession):
        self.bot = bot
        self.client = client
        self.last_search = deque()
        self.key = bot.config.google_api_key
        self.cx = self.bot.config.custom_search

    @command()
    @cooldown(2, 5)
    async def image(self, ctx, *, query):
        """Google search an image"""
        #logger.debug('Image search query: {}'.format(query))
        return await self._search(ctx, query, True, safe='off' if ctx.channel.nsfw else 'high')

    @command()
    @cooldown(2, 5)
    async def google(self, ctx, *, query):
        #logger.debug('Web search query: {}'.format(query))
        return await self._search(ctx, query, safe='off' if ctx.channel.nsfw else 'medium')

    async def _search(self, ctx, query, image=False, safe='off'):
        params = {'key': self.key,
                  'cx': self.cx,
                  'q': query,
                  'safe': safe}

        if image:
            params['searchType'] = 'image'

        async with self.client.get('https://www.googleapis.com/customsearch/v1', params=params) as r:
            if r.status == 200:
                json = await r.json()
                if 'error' in json:
                    reason = json['error'].get('message', 'Unknown reason')
                    return await ctx.send('Failed to search because of an error\n```{}```'.format(reason))

                #logger.debug('Search result: {}'.format(json))

                total_results = json['searchInformation']['totalResults']
                if int(total_results) == 0:
                    return await ctx.send('No results with the keywords "{}"'.format(query))

                if 'items' in json:
                    items = []
                    for item in json['items']:
                        items.append(SearchItem(**item))

                    return await send_paged_message(ctx, items,
                                                    page_method=lambda p,
                                                                       i: str(
                                                        p))
            else:
                return await ctx.send('Http error {}'.format(r.status))

def setup(bot):
    bot.add_cog(Search(bot, bot.aiohttp_client))
<commit_msg>add image aliases<commit_after>"""
MIT License

Copyright (c) 2017 s0hvaperuna

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

import logging
from collections import deque

from aiohttp import ClientSession
from discord.ext.commands import cooldown

from bot.bot import command
from utils.utilities import send_paged_message

logger = logging.getLogger('debug')

class SearchItem:
    def __init__(self, **kwargs):
        self.url = kwargs.pop('link', 'None')
        self.title = kwargs.pop('title', 'Untitled')

    def __str__(self):
        return '{0.url}'.format(self)

class Search:
    def __init__(self, bot, client: ClientSession):
        self.bot = bot
        self.client = client
        self.last_search = deque()
        self.key = bot.config.google_api_key
        self.cx = self.bot.config.custom_search

    @command(aliases=['im', 'img'])
    @cooldown(2, 5)
    async def image(self, ctx, *, query):
        """Google search an image"""
        #logger.debug('Image search query: {}'.format(query))
        return await self._search(ctx, query, True, safe='off' if ctx.channel.nsfw else 'high')

    @command()
    @cooldown(2, 5)
    async def google(self, ctx, *, query):
        #logger.debug('Web search query: {}'.format(query))
        return await self._search(ctx, query, safe='off' if ctx.channel.nsfw else 'medium')

    async def _search(self, ctx, query, image=False, safe='off'):
        params = {'key': self.key,
                  'cx': self.cx,
                  'q': query,
                  'safe': safe}

        if image:
            params['searchType'] = 'image'

        async with self.client.get('https://www.googleapis.com/customsearch/v1', params=params) as r:
            if r.status == 200:
                json = await r.json()
                if 'error' in json:
                    reason = json['error'].get('message', 'Unknown reason')
                    return await ctx.send('Failed to search because of an error\n```{}```'.format(reason))

                #logger.debug('Search result: {}'.format(json))

                total_results = json['searchInformation']['totalResults']
                if int(total_results) == 0:
                    return await ctx.send('No results with the keywords "{}"'.format(query))

                if 'items' in json:
                    items = []
                    for item in json['items']:
                        items.append(SearchItem(**item))

                    return await send_paged_message(ctx, items,
                                                    page_method=lambda p,
                                                                       i: str(
                                                        p))
            else:
                return await ctx.send('Http error {}'.format(r.status))

def setup(bot):
    bot.add_cog(Search(bot, bot.aiohttp_client))
<|endoftext|>