<commit_before>import os
import hmac
import json
import time
import asyncio
import hashlib
import functools

import furl

from waterbutler.core import utils
from waterbutler.core import streams
from waterbutler.core import provider
from waterbutler.core import exceptions
from waterbutler.core.path import WaterButlerPath

from waterbutler.providers.cloudfiles import settings
from waterbutler.providers.cloudfiles.metadata import CloudFilesFileMetadata
from waterbutler.providers.cloudfiles.metadata import CloudFilesFolderMetadata
from waterbutler.providers.cloudfiles.metadata import CloudFilesHeaderMetadata

def ensure_connection(func):
    """Runs ``_ensure_connection`` before continuing to the method
    """
    @functools.wraps(func)
    @asyncio.coroutine
    def wrapped(self, *args, **kwargs):
        yield from self._ensure_connection()
        return (yield from func(self, *args, **kwargs))
    return wrapped

class CloudFilesProvider(provider.BaseProvider):
    """Provider for Rackspace CloudFiles
    """
    NAME = 'cloudfiles'

    def __init__(self, auth, credentials, settings):
        super().__init__(auth, credentials, settings)
        self.token = None
        self.endpoint = None
        self.public_endpoint = None
        self.temp_url_key = credentials.get('temp_key', '').encode()
        self.region = self.credentials['region']
        self.og_token = self.credentials['token']
        self.username = self.credentials['username']
        self.container = self.settings['container']
        self.use_public = self.settings.get('use_public', True)

    @asyncio.coroutine
    def validate_path(self, path, **kwargs):
        return WaterButlerPath(path)

    @property
    def default_headers(self):
        return {
            'X-Auth-Token': self.token,
            'Accept': 'application/json',
        }

    @ensure_connection
    @asyncio.coroutine
    def intra_copy(self, dest_provider, source_path, dest_path):
        url = dest_provider.build_url(dest_path.path)
        exists = yield from dest_provider.exists(dest_path)

        yield from self.make_request(
            'PUT',
            url,
            headers={
                'X-Copy-From': os.path.join(self.container, source_path.path)
            },
            expects=(201, ),
            throws=exceptions.IntraCopyError,
        )
        return (yield from dest_provider.metadata(dest_path)), not exists

    @ensure_connection
    @asyncio.coroutine
    def download(self, path, accept_url=False, **kwargs):
        """Returns a ResponseStreamReader (Stream) for the specified path
        :param str path: Path to the object you want to download
        :param dict **kwargs: Additional arguments that are ignored
        :rtype str:
        :rtype ResponseStreamReader:
        :raises: exceptions.DownloadError
        """
        if accept_url:
            parsed_url = furl.furl(self.sign_url(path, endpoint=self.public_endpoint))
            parsed_url.args['filename'] = kwargs.get('displayName') or path.name
            return parsed_url.url

        resp = yield from self.make_request(
            'GET',
            self.sign_url(path),
            expects=(200, ),
            throws=exceptions.DownloadError,
        )
        return streams.ResponseStreamReader(resp)

    @ensure_connection
    @asyncio.coroutine
    def upload(self, stream, path, check_created=True, fetch_metadata=True, **kwargs):
        """Uploads the given stream to CloudFiles
        :param ResponseStreamReader stream: The stream to put to CloudFiles
        :param str path: The full path of the object to upload to/into
        :rtype ResponseStreamReader:
        """
        if check_created:
            created = yield from self.exists(path)
        else:
            created = None

        stream.add_writer('md5', streams.HashStreamWriter(hashlib.md5))
        url = self.sign_url(path, 'PUT')
        resp = yield from self.make_request(
            'PUT',
            url,
            data=stream,
            headers={'Content-Length': str(stream.size)},
            expects=(200, 201),
            throws=exceptions.UploadError,
        )
        # md5 is returned as ETag header as long as server side encryption is not used.
        # TODO: nice assertion error goes here
        assert resp.headers['ETag'].replace('"', '') == stream.writers['md5'].hexdigest

        if fetch_metadata:
            metadata = yield from self.metadata(path)
        else:
            metadata = None

        return metadata, created

    @ensure_connection
    @asyncio.coroutine
    def delete(self, path, **kwargs):
        """Deletes the key at the specified path
        :param str path: The path of the key to delete
        :rtype ResponseStreamReader:
        """
        if path.is_dir:
            metadata = yield from self.metadata(path, recursive=True)

            delete_files = [
                os.path.join('/', self.container, path.child(item['name']).path)
                for item in metadata
            ]

            delete_files.append(os.path.join('/', self.container, path.path))

            query = {'bulk-delete': ''}
            yield from self.make_request(
                'DELETE',
                self.build_url(**query),
                data='\n'.join(delete_files),
                expects=(200, ),
                throws=exceptions.DeleteError,
                headers={
                    'Content-Type': 'text/plain',
                },
            )
        else:
            yield from self.make_request(
                'DELETE',
                self.build_url(path.path),
                expects=(204, ),
                throws=exceptions.DeleteError,
            )

    @ensure_connection
    @asyncio.coroutine
    def metadata(self, path, recursive=False, **kwargs):
        """Get Metadata about the requested file or folder
        :param str path: The path to a key or folder
        :rtype dict:
        :rtype list:
        """
        if path.is_dir:
            return (yield from self._metadata_folder(path, recursive=recursive, **kwargs))
        else:
            return (yield from self._metadata_file(path, **kwargs))

    def build_url(self, *segments, _endpoint=None, **query):
        """Build the url for the specified object
        :param args segments: URI segments
        :param kwargs query: Query parameters
        :rtype str:
        """
        endpoint = _endpoint or self.endpoint
        return provider.build_url(endpoint, self.container, *segments, **query)

    def can_intra_copy(self, dest_provider, path=None):
        return type(self) == type(dest_provider) and not getattr(path, 'is_dir', False)

    def can_intra_move(self, dest_provider, path=None):
        return type(self) == type(dest_provider) and not getattr(path, 'is_dir', False)

    def sign_url(self, path, method='GET', endpoint=None, seconds=settings.TEMP_URL_SECS):
        """Sign a temp url for the specified stream
        :param str stream: The requested stream's path
        :param CloudFilesPath path: A path to a file/folder
        :param str method: The HTTP method used to access the returned url
        :param int seconds: Time for the url to live
        :rtype str:
        """
        method = method.upper()
        expires = str(int(time.time() + seconds))
        url = furl.furl(self.build_url(path.path, _endpoint=endpoint))

        body = '\n'.join([method, expires, str(url.path)]).encode()
        signature = hmac.new(self.temp_url_key, body, hashlib.sha1).hexdigest()

        url.args.update({
            'temp_url_sig': signature,
            'temp_url_expires': expires,
        })
        return url.url

    @asyncio.coroutine
    def _ensure_connection(self):
        """Defines token, endpoint and temp_url_key if they are not already defined
        :raises ProviderError: If no temp url key is available
        """
        # Must have a temp url key for download and upload
        # Currently You must have one for everything however
        if not self.token or not self.endpoint:
            data = yield from self._get_token()
            self.token = data['access']['token']['id']
            if self.use_public:
                self.public_endpoint, _ = self._extract_endpoints(data)
                self.endpoint = self.public_endpoint
            else:
                self.public_endpoint, self.endpoint = self._extract_endpoints(data)
        if not self.temp_url_key:
            resp = yield from self.make_request('HEAD', self.endpoint, expects=(204, ))
            try:
                self.temp_url_key = resp.headers['X-Account-Meta-Temp-URL-Key'].encode()
            except KeyError:
                raise exceptions.ProviderError('No temp url key is available', code=503)

    def _extract_endpoints(self, data):
        """Pulls both the public and internal cloudfiles urls,
        returned respectively, from the return of tokens
        Very optimized.
        :param dict data: The json response from the token endpoint
        :rtype (str, str):
        """
        for service in reversed(data['access']['serviceCatalog']):
            if service['name'].lower() == 'cloudfiles':
                for region in service['endpoints']:
                    if region['region'].lower() == self.region.lower():
                        return region['publicURL'], region['internalURL']

    @asyncio.coroutine
    def _get_token(self):
        """Fetches an access token from cloudfiles for actual api requests
        Returns the entire json response from the tokens endpoint
        Notably containing our token and proper endpoint to send requests to
        :rtype dict:
        """
        resp = yield from self.make_request(
            'POST',
            settings.AUTH_URL,
            data=json.dumps({
                'auth': {
                    'RAX-KSKEY:apiKeyCredentials': {
                        'username': self.username,
                        'apiKey': self.og_token,
                    }
                }
            }),
            headers={
                'Content-Type': 'application/json',
            },
            expects=(200, ),
        )
        data = yield from resp.json()
        return data

    def _metadata_file(self, path, is_folder=False, **kwargs):
        """Get Metadata about the requested file
        :param str path: The path to a key
        :rtype dict:
        :rtype list:
        """
        resp = yield from self.make_request(
            'HEAD',
            self.build_url(path.path),
            expects=(200, ),
            throws=exceptions.MetadataError,
        )

        if (resp.headers['Content-Type'] == 'application/directory' and not is_folder):
            raise exceptions.MetadataError(
                'Could not retrieve file \'{0}\''.format(str(path)),
                code=404,
            )

        return CloudFilesHeaderMetadata(resp.headers, path.path).serialized()

    def _metadata_folder(self, path, recursive=False, **kwargs):
        """Get Metadata about the requested folder
        :param str path: The path to a folder
        :rtype dict:
        :rtype list:
        """
        # prefix must be blank when searching the root of the container
        query = {'prefix': path.path}
        if not recursive:
            query.update({'delimiter': '/'})
        resp = yield from self.make_request(
            'GET',
            self.build_url('', **query),
            expects=(200, ),
            throws=exceptions.MetadataError,
        )
        data = yield from resp.json()

        # no data and the provider path is not root, we are left with either a file or a directory marker
        if not data and not path.is_root:
            # Convert the parent path into a directory marker (file) and check for an empty folder
            dir_marker = path.parent.child(path.name, folder=False)
            metadata = yield from self._metadata_file(dir_marker, is_folder=True, **kwargs)
            if not metadata:
                raise exceptions.MetadataError(
                    'Could not retrieve folder \'{0}\''.format(str(path)),
                    code=404,
                )

        # normalized metadata, remove extraneous directory markers
        for item in data:
            if 'subdir' in item:
                for marker in data:
                    if 'content_type' in marker and marker['content_type'] == 'application/directory':
                        subdir_path = item['subdir'].rstrip('/')
                        if marker['name'] == subdir_path:
                            data.remove(marker)
                            break

        return [
            self._serialize_folder_metadata(item)
            for item in data
        ]

    def _serialize_folder_metadata(self, data):
        if data.get('subdir'):
            return CloudFilesFolderMetadata(data).serialized()
        elif data['content_type'] == 'application/directory':
            return CloudFilesFolderMetadata({'subdir': data['name'] + '/'}).serialized()
        return CloudFilesFileMetadata(data).serialized()
<commit_msg>Poor naming leads to broken things<commit_after>import os
import hmac
import json
import time
import asyncio
import hashlib
import functools

import furl

from waterbutler.core import utils
from waterbutler.core import streams
from waterbutler.core import provider
from waterbutler.core import exceptions
from waterbutler.core.path import WaterButlerPath

from waterbutler.providers.cloudfiles import settings
from waterbutler.providers.cloudfiles.metadata import CloudFilesFileMetadata
from waterbutler.providers.cloudfiles.metadata import CloudFilesFolderMetadata
from waterbutler.providers.cloudfiles.metadata import CloudFilesHeaderMetadata

def ensure_connection(func):
    """Runs ``_ensure_connection`` before continuing to the method
    """
    @functools.wraps(func)
    @asyncio.coroutine
    def wrapped(self, *args, **kwargs):
        yield from self._ensure_connection()
        return (yield from func(self, *args, **kwargs))
    return wrapped

class CloudFilesProvider(provider.BaseProvider):
    """Provider for Rackspace CloudFiles
    """
    NAME = 'cloudfiles'

    def __init__(self, auth, credentials, settings):
        super().__init__(auth, credentials, settings)
        self.token = None
        self.endpoint = None
        self.public_endpoint = None
        self.temp_url_key = credentials.get('temp_key', '').encode()
        self.region = self.credentials['region']
        self.og_token = self.credentials['token']
        self.username = self.credentials['username']
        self.container = self.settings['container']
        self.use_public = self.settings.get('use_public', True)

    @asyncio.coroutine
    def validate_path(self, path, **kwargs):
        return WaterButlerPath(path)

    @property
    def default_headers(self):
        return {
            'X-Auth-Token': self.token,
            'Accept': 'application/json',
        }

    @ensure_connection
    @asyncio.coroutine
    def intra_copy(self, dest_provider, source_path, dest_path):
        url = dest_provider.build_url(dest_path.path)
        exists = yield from dest_provider.exists(dest_path)

        yield from self.make_request(
            'PUT',
            url,
            headers={
                'X-Copy-From': os.path.join(self.container, source_path.path)
            },
            expects=(201, ),
            throws=exceptions.IntraCopyError,
        )
        return (yield from dest_provider.metadata(dest_path)), not exists

    @ensure_connection
    @asyncio.coroutine
    def download(self, path, accept_url=False, **kwargs):
        """Returns a ResponseStreamReader (Stream) for the specified path
        :param str path: Path to the object you want to download
        :param dict **kwargs: Additional arguments that are ignored
        :rtype str:
        :rtype ResponseStreamReader:
        :raises: exceptions.DownloadError
        """
        if accept_url:
            parsed_url = furl.furl(self.sign_url(path, endpoint=self.public_endpoint))
            parsed_url.args['filename'] = kwargs.get('displayName') or path.name
            return parsed_url.url

        resp = yield from self.make_request(
            'GET',
            self.sign_url(path),
            expects=(200, ),
            throws=exceptions.DownloadError,
        )
        return streams.ResponseStreamReader(resp)

    @ensure_connection
    @asyncio.coroutine
    def upload(self, stream, path, check_created=True, fetch_metadata=True, **kwargs):
        """Uploads the given stream to CloudFiles
        :param ResponseStreamReader stream: The stream to put to CloudFiles
        :param str path: The full path of the object to upload to/into
        :rtype ResponseStreamReader:
        """
        if check_created:
            created = not (yield from self.exists(path))
        else:
            created = None

        stream.add_writer('md5', streams.HashStreamWriter(hashlib.md5))
        url = self.sign_url(path, 'PUT')
        resp = yield from self.make_request(
            'PUT',
            url,
            data=stream,
            headers={'Content-Length': str(stream.size)},
            expects=(200, 201),
            throws=exceptions.UploadError,
        )
        # md5 is returned as ETag header as long as server side encryption is not used.
        # TODO: nice assertion error goes here
        assert resp.headers['ETag'].replace('"', '') == stream.writers['md5'].hexdigest

        if fetch_metadata:
            metadata = yield from self.metadata(path)
        else:
            metadata = None

        return metadata, created

    @ensure_connection
    @asyncio.coroutine
    def delete(self, path, **kwargs):
        """Deletes the key at the specified path
        :param str path: The path of the key to delete
        :rtype ResponseStreamReader:
        """
        if path.is_dir:
            metadata = yield from self.metadata(path, recursive=True)

            delete_files = [
                os.path.join('/', self.container, path.child(item['name']).path)
                for item in metadata
            ]

            delete_files.append(os.path.join('/', self.container, path.path))

            query = {'bulk-delete': ''}
            yield from self.make_request(
                'DELETE',
                self.build_url(**query),
                data='\n'.join(delete_files),
                expects=(200, ),
                throws=exceptions.DeleteError,
                headers={
                    'Content-Type': 'text/plain',
                },
            )
        else:
            yield from self.make_request(
                'DELETE',
                self.build_url(path.path),
                expects=(204, ),
                throws=exceptions.DeleteError,
            )

    @ensure_connection
    @asyncio.coroutine
    def metadata(self, path, recursive=False, **kwargs):
        """Get Metadata about the requested file or folder
        :param str path: The path to a key or folder
        :rtype dict:
        :rtype list:
        """
        if path.is_dir:
            return (yield from self._metadata_folder(path, recursive=recursive, **kwargs))
        else:
            return (yield from self._metadata_file(path, **kwargs))

    def build_url(self, *segments, _endpoint=None, **query):
        """Build the url for the specified object
        :param args segments: URI segments
        :param kwargs query: Query parameters
        :rtype str:
        """
        endpoint = _endpoint or self.endpoint
        return provider.build_url(endpoint, self.container, *segments, **query)

    def can_intra_copy(self, dest_provider, path=None):
        return type(self) == type(dest_provider) and not getattr(path, 'is_dir', False)

    def can_intra_move(self, dest_provider, path=None):
        return type(self) == type(dest_provider) and not getattr(path, 'is_dir', False)

    def sign_url(self, path, method='GET', endpoint=None, seconds=settings.TEMP_URL_SECS):
        """Sign a temp url for the specified stream
        :param str stream: The requested stream's path
        :param CloudFilesPath path: A path to a file/folder
        :param str method: The HTTP method used to access the returned url
        :param int seconds: Time for the url to live
        :rtype str:
        """
        method = method.upper()
        expires = str(int(time.time() + seconds))
        url = furl.furl(self.build_url(path.path, _endpoint=endpoint))

        body = '\n'.join([method, expires, str(url.path)]).encode()
        signature = hmac.new(self.temp_url_key, body, hashlib.sha1).hexdigest()

        url.args.update({
            'temp_url_sig': signature,
            'temp_url_expires': expires,
        })
        return url.url

    @asyncio.coroutine
    def _ensure_connection(self):
        """Defines token, endpoint and temp_url_key if they are not already defined
        :raises ProviderError: If no temp url key is available
        """
        # Must have a temp url key for download and upload
        # Currently You must have one for everything however
        if not self.token or not self.endpoint:
            data = yield from self._get_token()
            self.token = data['access']['token']['id']
            if self.use_public:
                self.public_endpoint, _ = self._extract_endpoints(data)
                self.endpoint = self.public_endpoint
            else:
                self.public_endpoint, self.endpoint = self._extract_endpoints(data)
        if not self.temp_url_key:
            resp = yield from self.make_request('HEAD', self.endpoint, expects=(204, ))
            try:
                self.temp_url_key = resp.headers['X-Account-Meta-Temp-URL-Key'].encode()
            except KeyError:
                raise exceptions.ProviderError('No temp url key is available', code=503)

    def _extract_endpoints(self, data):
        """Pulls both the public and internal cloudfiles urls,
        returned respectively, from the return of tokens
        Very optimized.
        :param dict data: The json response from the token endpoint
        :rtype (str, str):
        """
        for service in reversed(data['access']['serviceCatalog']):
            if service['name'].lower() == 'cloudfiles':
                for region in service['endpoints']:
                    if region['region'].lower() == self.region.lower():
                        return region['publicURL'], region['internalURL']

    @asyncio.coroutine
    def _get_token(self):
        """Fetches an access token from cloudfiles for actual api requests
        Returns the entire json response from the tokens endpoint
        Notably containing our token and proper endpoint to send requests to
        :rtype dict:
        """
        resp = yield from self.make_request(
            'POST',
            settings.AUTH_URL,
            data=json.dumps({
                'auth': {
                    'RAX-KSKEY:apiKeyCredentials': {
                        'username': self.username,
                        'apiKey': self.og_token,
                    }
                }
            }),
            headers={
                'Content-Type': 'application/json',
            },
            expects=(200, ),
        )
        data = yield from resp.json()
        return data

    def _metadata_file(self, path, is_folder=False, **kwargs):
        """Get Metadata about the requested file
        :param str path: The path to a key
        :rtype dict:
        :rtype list:
        """
        resp = yield from self.make_request(
            'HEAD',
            self.build_url(path.path),
            expects=(200, ),
            throws=exceptions.MetadataError,
        )

        if (resp.headers['Content-Type'] == 'application/directory' and not is_folder):
            raise exceptions.MetadataError(
                'Could not retrieve file \'{0}\''.format(str(path)),
                code=404,
            )

        return CloudFilesHeaderMetadata(resp.headers, path.path).serialized()

    def _metadata_folder(self, path, recursive=False, **kwargs):
        """Get Metadata about the requested folder
        :param str path: The path to a folder
        :rtype dict:
        :rtype list:
        """
        # prefix must be blank when searching the root of the container
        query = {'prefix': path.path}
        if not recursive:
            query.update({'delimiter': '/'})
        resp = yield from self.make_request(
            'GET',
            self.build_url('', **query),
            expects=(200, ),
            throws=exceptions.MetadataError,
        )
        data = yield from resp.json()

        # no data and the provider path is not root, we are left with either a file or a directory marker
        if not data and not path.is_root:
            # Convert the parent path into a directory marker (file) and check for an empty folder
            dir_marker = path.parent.child(path.name, folder=False)
            metadata = yield from self._metadata_file(dir_marker, is_folder=True, **kwargs)
            if not metadata:
                raise exceptions.MetadataError(
                    'Could not retrieve folder \'{0}\''.format(str(path)),
                    code=404,
                )

        # normalized metadata, remove extraneous directory markers
        for item in data:
            if 'subdir' in item:
                for marker in data:
                    if 'content_type' in marker and marker['content_type'] == 'application/directory':
                        subdir_path = item['subdir'].rstrip('/')
                        if marker['name'] == subdir_path:
                            data.remove(marker)
                            break

        return [
            self._serialize_folder_metadata(item)
            for item in data
        ]

    def _serialize_folder_metadata(self, data):
        if data.get('subdir'):
            return CloudFilesFolderMetadata(data).serialized()
        elif data['content_type'] == 'application/directory':
            return CloudFilesFolderMetadata({'subdir': data['name'] + '/'}).serialized()
        return CloudFilesFileMetadata(data).serialized()
<|endoftext|>


<commit_before>import sys
from passlib.context import CryptContext

ctx = CryptContext(schemes=["pbkdf2_sha512"])
result = ctx.encrypt(sys.argv[1])

print result<commit_msg>Escape the crypted password<commit_after>import sys
from passlib.context import CryptContext

ctx = CryptContext(schemes=["pbkdf2_sha512"])
unescaped = ctx.encrypt(sys.argv[1])

escaped = unescaped.replace('/', '\/')
result = escaped.replace("$", "\$")

print result<|endoftext|>


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

from appium.webdriver.common.touch_action import TouchAction
from AppiumLibrary import utils
from AppiumLibrary.locators import ElementFinder
from keywordgroup import KeywordGroup

class _ElementKeywords(KeywordGroup):

    def __init__(self):
        self._element_finder = ElementFinder()

    # Public, element lookups
    def clear_text(self, locator):
        """Clears the text field identified by `locator`.

        See `introduction` for details about locating elements.
        """
        self._info("Clear text field '%s'" % (locator))
        self._element_clear_text_by_locator(locator)

    def click_element(self, locator):
        """Click element identified by `locator`.

        Key attributes for arbitrary elements are `index` and `name`. See
        `introduction` for details about locating elements.
        """
        self._info("Clicking element '%s'." % locator)
        self._element_find(locator, True, True).click()

    def click_button(self, index_or_name):
        """ Click button """
        _platform_class_dict = {'ios':'UIAButton',
                                   'android': 'android.widget.Button'}
        if self._is_support_platform(_platform_class_dict):
            class_name = self._get_class(_platform_class_dict)
            self._click_element_by_class_name(class_name, index_or_name)

    def input_text(self, locator, text):
        """Types the given `text` into text field identified by `locator`.

        See `introduction` for details about locating elements.
        """
        self._info("Typing text '%s' into text field '%s'" % (text, locator))
        self._element_input_text_by_locator(locator, text)

    def input_password(self, locator, text):
        """Types the given password into text field identified by `locator`.

        Difference between this keyword and `Input Text` is that this keyword
        does not log the given password. See `introduction` for details about
        locating elements.
        """
        self._info("Typing password into text field '%s'" % locator)
        self._element_input_text_by_locator(locator, text)

    def input_value(self, locator, text):
        """Sets the given value into text field identified by `locator`. This is an IOS only keyword, input value makes use of set_value

        See `introduction` for details about locating elements.
        """
        self._info("Setting text '%s' into text field '%s'" % (text, locator))
        self._element_input_value_by_locator(locator, text)

    def hide_keyboard(self):
        """
        Hides the software keyboard on the device, using the specified key to
        press. If no key name is given, the keyboard is closed by moving focus
        from the text field. iOS only.
        """
        driver = self._current_application()
        driver.hide_keyboard()

    def page_should_contain_text(self, text, loglevel='INFO'):
        """Verifies that current page contains `text`.

        If this keyword fails, it automatically logs the page source
        using the log level specified with the optional `loglevel` argument.
        Giving `NONE` as level disables logging.
        """
        if not text in self.log_source(loglevel):
            self.log_source(loglevel)
            raise AssertionError("Page should have contained text '%s' "
                                 "but did not" % text)
        self._info("Current page contains text '%s'." % text)

    def page_should_not_contain_text(self, text, loglevel='INFO'):
        """Verifies that current page not contains `text`.

        If this keyword fails, it automatically logs the page source
        using the log level specified with the optional `loglevel` argument.
        Giving `NONE` as level disables logging.
        """
        if text in self.log_source(loglevel):
            self.log_source(loglevel)
            raise AssertionError("Page should not have contained text '%s' "
                                 "but did not" % text)
        self._info("Current page does not contains text '%s'." % text)

    def page_should_contain_element(self, locator, loglevel='INFO'):
        """Verifies that current page contains `locator` element.

        If this keyword fails, it automatically logs the page source
        using the log level specified with the optional `loglevel` argument.
        Givin
        """
        if not self._is_element_present(locator):
            self.log_source(loglevel)
            raise AssertionError("Page should have contained element '%s' "
                                 "but did not" % locator)
        self._info("Current page contains element '%s'." % locator)

    def page_should_not_contain_element(self, locator, loglevel='INFO'):
        """Verifies that current page not contains `locator` element.

        If this keyword fails, it automatically logs the page source
        using the log level specified with the optional `loglevel` argument.
        Givin
        """
        if self._is_element_present(locator):
            self.log_source(loglevel)
            raise AssertionError("Page should not have contained element '%s' "
                                 "but did not" % locator)
        self._info("Current page not contains element '%s'." % locator)

    def element_should_be_disabled(self, locator, loglevel='INFO'):
        """Verifies that element identified with locator is disabled.

        Key attributes for arbitrary elements are `id` and `name`. See
        `introduction` for details about locating elements.
        """
        if self._element_find(locator, True, True).is_enabled():
            self.log_source(loglevel)
            raise AssertionError("Element '%s' should be disabled "
                                 "but did not" % locator)
        self._info("Element '%s' is disabled ." % locator)

    def element_should_be_enabled(self, locator, loglevel='INFO'):
        """Verifies that element identified with locator is enabled.

        Key attributes for arbitrary elements are `id` and `name`. See
        `introduction` for details about locating elements.
        """
        if not self._element_find(locator, True, True).is_enabled():
            self.log_source(loglevel)
            raise AssertionError("Element '%s' should be enabled "
                                 "but did not" % locator)
        self._info("Element '%s' is enabled ." % locator)

    def element_name_should_be(self, locator, expected):
        element = self._element_find(locator, True, True)
        if expected != element.get_attribute('name'):
            raise AssertionError("Element '%s' name should be '%s' "
                                 "but it is '%s'." % (locator, expected, element.get_attribute('name')))
        self._info("Element '%s' name is '%s' " % (locator, expected))

    # Private

    def _is_index(self, index_or_name):
        if index_or_name.startswith('index='):
            return True
        else:
            return False

    def _click_element_by_name(self, name):
        driver = self._current_application()
        try:
            element = driver.find_element_by_name(name)
        except Exception, e:
            raise Exception, e

        try:
            element.click()
        except Exception, e:
            raise Exception, 'Cannot click the element with name "%s"' % name

    def _find_elements_by_class_name(self, class_name):
        driver = self._current_application()
        elements = driver.find_elements_by_class_name(class_name)
        return elements

    def _find_element_by_class_name(self, class_name, index_or_name):
        elements = self._find_elements_by_class_name(class_name)

        if self._is_index(index_or_name):
            try:
                index = int(index_or_name.split('=')[-1])
                element = elements[index]
            except IndexError, TypeError:
                raise Exception, 'Cannot find the element with index "%s"' % index_or_name
        else:
            found = False
            for element in elements:
                self._info("'%s'." % element.text)
                if element.text == index_or_name:
                    found = True
                    break
            if not found:
                raise Exception, 'Cannot find the element with name "%s"' % index_or_name

        return element

    def _get_class(self, platform_class_dict):
        return platform_class_dict.get(self._get_platform())

    def _is_support_platform(self, platform_class_dict):
        return platform_class_dict.has_key(self._get_platform())

    def _click_element_by_class_name(self, class_name, index_or_name):
        element = self._find_element_by_class_name(class_name, index_or_name)
        self._info("Clicking element '%s'." % element.text)
        try:
            element.click()
        except Exception, e:
            raise Exception, 'Cannot click the %s element "%s"' % (class_name, index_or_name)

    def _element_clear_text_by_locator(self, locator):
        try:
            element = self._element_find(locator, True, True)
            element.clear()
        except Exception, e:
            raise e

    def _element_input_text_by_locator(self, locator, text):
        try:
            element = self._element_find(locator, True, True)
            element.send_keys(text)
        except Exception, e:
            raise e

    def _element_input_text_by_class_name(self, class_name, index_or_name, text):
        try:
            element = self._find_element_by_class_name(class_name, index_or_name)
        except Exception, e:
            raise Exception, e

        self._info("input text in element as '%s'." % element.text)
        try:
            element.send_keys(text)
        except Exception, e:
            raise Exception, 'Cannot input text "%s" for the %s element "%s"' % (text, class_name, index_or_name)

    def _element_input_value_by_locator(self, locator, text):
        try:
            element = self._element_find(locator, True, True)
            element.set_value(text)
        except Exception, e:
            raise e

    def _element_find(self, locator, first_only, required, tag=None):
        application = self._current_application()
        elements = self._element_finder.find(application, locator, tag)
        if required and len(elements) == 0:
            raise ValueError("Element locator '" + locator + "' did not match any elements.")
        if first_only:
            if len(elements) == 0: return None
            return elements[0]
        return elements

    def _is_text_present(self, text):
        return text in self.get_source()

    def _is_element_present(self, locator):
        application = self._current_application()
        elements = self._element_finder.find(application, locator, None)
        return len(elements) > 0
<commit_msg>add 2 keywords: 1. get element attribute, 2. element value should be. Both of them are documented and stored in _element file<commit_after># -*- coding: utf-8 -*-

from appium.webdriver.common.touch_action import TouchAction
from AppiumLibrary import utils
from AppiumLibrary.locators import ElementFinder
from keywordgroup import KeywordGroup

class _ElementKeywords(KeywordGroup):

    def __init__(self):
        self._element_finder = ElementFinder()

    # Public, element lookups
    def clear_text(self, locator):
        """Clears the text field identified by `locator`.

        See `introduction` for details about locating elements.
        """
        self._info("Clear text field '%s'" % (locator))
        self._element_clear_text_by_locator(locator)

    def click_element(self, locator):
        """Click element identified by `locator`.

        Key attributes for arbitrary elements are `index` and `name`. See
        `introduction` for details about locating elements.
        """
        self._info("Clicking element '%s'." % locator)
        self._element_find(locator, True, True).click()

    def click_button(self, index_or_name):
        """ Click button """
        _platform_class_dict = {'ios':'UIAButton',
                                   'android': 'android.widget.Button'}
        if self._is_support_platform(_platform_class_dict):
            class_name = self._get_class(_platform_class_dict)
            self._click_element_by_class_name(class_name, index_or_name)

    def input_text(self, locator, text):
        """Types the given `text` into text field identified by `locator`.

        See `introduction` for details about locating elements.
        """
        self._info("Typing text '%s' into text field '%s'" % (text, locator))
        self._element_input_text_by_locator(locator, text)

    def input_password(self, locator, text):
        """Types the given password into text field identified by `locator`.

        Difference between this keyword and `Input Text` is that this keyword
        does not log the given password. See `introduction` for details about
        locating elements.
        """
        self._info("Typing password into text field '%s'" % locator)
        self._element_input_text_by_locator(locator, text)

    def input_value(self, locator, text):
        """Sets the given value into text field identified by `locator`. This is an IOS only keyword, input value makes use of set_value

        See `introduction` for details about locating elements.
        """
        self._info("Setting text '%s' into text field '%s'" % (text, locator))
        self._element_input_value_by_locator(locator, text)

    def hide_keyboard(self):
        """
        Hides the software keyboard on the device, using the specified key to
        press. If no key name is given, the keyboard is closed by moving focus
        from the text field. iOS only.
        """
        driver = self._current_application()
        driver.hide_keyboard()

    def page_should_contain_text(self, text, loglevel='INFO'):
        """Verifies that current page contains `text`.

        If this keyword fails, it automatically logs the page source
        using the log level specified with the optional `loglevel` argument.
        Giving `NONE` as level disables logging.
        """
        if not text in self.log_source(loglevel):
            self.log_source(loglevel)
            raise AssertionError("Page should have contained text '%s' "
                                 "but did not" % text)
        self._info("Current page contains text '%s'." % text)

    def page_should_not_contain_text(self, text, loglevel='INFO'):
        """Verifies that current page not contains `text`.

        If this keyword fails, it automatically logs the page source
        using the log level specified with the optional `loglevel` argument.
        Giving `NONE` as level disables logging.
        """
        if text in self.log_source(loglevel):
            self.log_source(loglevel)
            raise AssertionError("Page should not have contained text '%s' "
                                 "but did not" % text)
        self._info("Current page does not contains text '%s'." % text)

    def page_should_contain_element(self, locator, loglevel='INFO'):
        """Verifies that current page contains `locator` element.

        If this keyword fails, it automatically logs the page source
        using the log level specified with the optional `loglevel` argument.
        Givin
        """
        if not self._is_element_present(locator):
            self.log_source(loglevel)
            raise AssertionError("Page should have contained element '%s' "
                                 "but did not" % locator)
        self._info("Current page contains element '%s'." % locator)

    def page_should_not_contain_element(self, locator, loglevel='INFO'):
        """Verifies that current page not contains `locator` element.

        If this keyword fails, it automatically logs the page source
        using the log level specified with the optional `loglevel` argument.
        Givin
        """
        if self._is_element_present(locator):
            self.log_source(loglevel)
            raise AssertionError("Page should not have contained element '%s' "
                                 "but did not" % locator)
        self._info("Current page not contains element '%s'." % locator)

    def element_should_be_disabled(self, locator, loglevel='INFO'):
        """Verifies that element identified with locator is disabled.

        Key attributes for arbitrary elements are `id` and `name`. See
        `introduction` for details about locating elements.
        """
        if self._element_find(locator, True, True).is_enabled():
            self.log_source(loglevel)
            raise AssertionError("Element '%s' should be disabled "
                                 "but did not" % locator)
        self._info("Element '%s' is disabled ." % locator)

    def element_should_be_enabled(self, locator, loglevel='INFO'):
        """Verifies that element identified with locator is enabled.

        Key attributes for arbitrary elements are `id` and `name`. See
        `introduction` for details about locating elements.
        """
        if not self._element_find(locator, True, True).is_enabled():
            self.log_source(loglevel)
            raise AssertionError("Element '%s' should be enabled "
                                 "but did not" % locator)
        self._info("Element '%s' is enabled ." % locator)

    def element_name_should_be(self, locator, expected):
        element = self._element_find(locator, True, True)
        if expected != element.get_attribute('name'):
            raise AssertionError("Element '%s' name should be '%s' "
                                 "but it is '%s'." % (locator, expected, element.get_attribute('name')))
        self._info("Element '%s' name is '%s' " % (locator, expected))

    def get_element_attribute(self, locator, attribute):
        """Get element attribute using given attribute: name, value,...

        Example:

        |Get Element Attribute| locator | name |
        or
        |Get Element Attribute| locator | value |
        """
        element = self._element_find(locator, True, True)
        try:
            return element.get_attribute(attribute)
        except:
            raise AssertionError("Element '%s' could not be found or "
                                 "attribute '%s' is not valid." % (locator, attribute))
        self._info("Element '%s' attribute is '%s' " % (locator, attribute))

    def element_value_should_be(self, locator, expected):
        element = self._element_find(locator, True, True)
        if expected != element.get_attribute('value'):
            raise AssertionError("Element '%s' value should be '%s' "
                                 "but it is '%s'." % (locator, expected, element.get_attribute('value')))
        self._info("Element '%s' value is '%s' " % (locator, expected))

    # Private

    def _is_index(self, index_or_name):
        if index_or_name.startswith('index='):
            return True
        else:
            return False

    def _click_element_by_name(self, name):
        driver = self._current_application()
        try:
            element = driver.find_element_by_name(name)
        except Exception, e:
            raise Exception, e

        try:
            element.click()
        except Exception, e:
            raise Exception, 'Cannot click the element with name "%s"' % name

    def _find_elements_by_class_name(self, class_name):
        driver = self._current_application()
        elements = driver.find_elements_by_class_name(class_name)
        return elements

    def _find_element_by_class_name(self, class_name, index_or_name):
        elements = self._find_elements_by_class_name(class_name)

        if self._is_index(index_or_name):
            try:
                index = int(index_or_name.split('=')[-1])
                element = elements[index]
            except IndexError, TypeError:
                raise Exception, 'Cannot find the element with index "%s"' % index_or_name
        else:
            found = False
            for element in elements:
                self._info("'%s'." % element.text)
                if element.text == index_or_name:
                    found = True
                    break
            if not found:
                raise Exception, 'Cannot find the element with name "%s"' % index_or_name

        return element

    def _get_class(self, platform_class_dict):
        return platform_class_dict.get(self._get_platform())

    def _is_support_platform(self, platform_class_dict):
        return platform_class_dict.has_key(self._get_platform())

    def _click_element_by_class_name(self, class_name, index_or_name):
        element = self._find_element_by_class_name(class_name, index_or_name)
        self._info("Clicking element '%s'." % element.text)
        try:
            element.click()
        except Exception, e:
            raise Exception, 'Cannot click the %s element "%s"' % (class_name, index_or_name)

    def _element_clear_text_by_locator(self, locator):
        try:
            element = self._element_find(locator, True, True)
            element.clear()
        except Exception, e:
            raise e

    def _element_input_text_by_locator(self, locator, text):
        try:
            element = self._element_find(locator, True, True)
            element.send_keys(text)
        except Exception, e:
            raise e

    def _element_input_text_by_class_name(self, class_name, index_or_name, text):
        try:
            element = self._find_element_by_class_name(class_name, index_or_name)
        except Exception, e:
            raise Exception, e

        self._info("input text in element as '%s'." % element.text)
        try:
            element.send_keys(text)
        except Exception, e:
            raise Exception, 'Cannot input text "%s" for the %s element "%s"' % (text, class_name, index_or_name)

    def _element_input_value_by_locator(self, locator, text):
        try:
            element = self._element_find(locator, True, True)
            element.set_value(text)
        except Exception, e:
            raise e

    def _element_find(self, locator, first_only, required, tag=None):
        application = self._current_application()
        elements = self._element_finder.find(application, locator, tag)
        if required and len(elements) == 0:
            raise ValueError("Element locator '" + locator + "' did not match any elements.")
        if first_only:
            if len(elements) == 0: return None
            return elements[0]
        return elements

    def _is_text_present(self, text):
        return text in self.get_source()

    def _is_element_present(self, locator):
        application = self._current_application()
        elements = self._element_finder.find(application, locator, None)
        return len(elements) > 0
<|endoftext|>


<commit_before># Copyright 2015 Google Inc. 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.

import main

def test_index():
    main.app.testing = True
    client = main.app.test_client()

    r = client.get('/', environ_base={'REMOTE_ADDR': '127.0.0.1'})
    assert r.status_code == 200
    assert '127.0' in r.data.decode('utf-8')
<commit_msg>[appengine] testing: relax datastore test (#3768)<commit_after># Copyright 2015 Google Inc. 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.

import main

def test_index():
    main.app.testing = True
    client = main.app.test_client()

    r = client.get('/', environ_base={'REMOTE_ADDR': '127.0.0.1'})
    assert r.status_code == 200
    assert 'Last 10 visits' in r.data.decode('utf-8')
<|endoftext|>


<commit_before>"""
.. module:: company.package.config
    :platform: Unix
    :synopsis: Configuration utilities.

.. moduleauthor:: Your Name <email address>
"""

from __future__ import absolute_import

import os.path

try:
    from ConfigParser import SafeConfigParser as ConfigParser
except ImportError:
    from configparser import ConfigParser

import logging

DEFAULT_CONFIG_FILE = '/etc/package/package.cfg'

SETTINGS = None

def load_configuration(config_file=DEFAULT_CONFIG_FILE):
    """
    Loads configuration.

    :param config_file: the configuration file(s).
    :type config_file: str or list of str
    """
    global SETTINGS

    if not os.path.exists(config_file) or not os.path.isfile(config_file):
        msg = '%s configuration file does not exist!' % config_file
        logging.getLogger(__name__).error(msg)
        raise ValueError(msg)

    parser = ConfigParser()
    try:
        parser.read(config_file)
        SETTINGS = {}
        for section in parser.sections():
            SETTINGS[section] = dict(parser.items(section))
        logging.getLogger(__name__).info('%s configuration file was loaded.' % config_file)
        return SETTINGS
    except StandardError as error:
        SETTINGS = None
        msg = 'Failed to load configuration from %s!' % config_file
        logging.getLogger(__name__).error(msg)
        logging.getLogger(__name__).debug(str(error), exc_info=True)
        raise error

def get():
    """
    Returns the configuration.

    :return: the configuration.
    :rtype: object (configParser.ConfigParser)
    """
    if SETTINGS is None:
        return load_configuration()
    return SETTINGS

def reset():
    """
    Reset the configuration.
    """
    global SETTINGS

    SETTINGS = None
<commit_msg>fixed problem reported by landscape.io.<commit_after>"""
.. module:: company.package.config
    :platform: Unix
    :synopsis: Configuration utilities.

.. moduleauthor:: Your Name <email address>
"""

from __future__ import absolute_import

import os.path

try:
    from ConfigParser import SafeConfigParser as ConfigParser
except ImportError:
    from configparser import ConfigParser

import logging

DEFAULT_CONFIG_FILE = '/etc/package/package.cfg'

SETTINGS = None

def load_configuration(config_file=DEFAULT_CONFIG_FILE):
    """
    Loads configuration.

    :param config_file: the configuration file(s).
    :type config_file: str or list of str
    """
    global SETTINGS

    if not os.path.exists(config_file) or not os.path.isfile(config_file):
        msg = '%s configuration file does not exist!' % config_file
        logging.getLogger(__name__).error(msg)
        raise ValueError(msg)

    parser = ConfigParser()
    try:
        parser.read(config_file)
        SETTINGS = {}
        for section in parser.sections():
            SETTINGS[section] = dict(parser.items(section))
        logging.getLogger(__name__).info('%s configuration file was loaded.', config_file)
        return SETTINGS
    except StandardError as error:
        SETTINGS = None
        logging.getLogger(__name__).error('Failed to load configuration from %s!', config_file)
        logging.getLogger(__name__).debug(str(error), exc_info=True)
        raise error

def get():
    """
    Returns the configuration.

    :return: the configuration.
    :rtype: object (configParser.ConfigParser)
    """
    if SETTINGS is None:
        return load_configuration()
    return SETTINGS

def reset():
    """
    Reset the configuration.
    """
    global SETTINGS

    SETTINGS = None
<|endoftext|>


<commit_before>from time import time
import zope.interface

class Increments(zope.interface.Interface):

    def increment():
        """Increment something"""

class IncrementsBar(Increments):

    """Provide bar as an attribute"""

    bar = 1
    bar = zope.interface.Attribute("""An attribute""")

@zope.interface.implementer(IncrementsBar)
class IncrementingInteger:

    """Increment an integer when increment is called."""

    bar = 2

    def increment(self):
        self.bar += 1

def f(incrementer):
    incrementer.increment()

def test_time():
    start = time()
    for i in range(1000000):
        inc = IncrementingInteger()
        f(inc)
    stop = time()
    print(stop - start)

def test_time1():
    start = time()
    inc = IncrementingInteger()
    for i in range(1000000):
        f(inc)
    stop = time()
    print(stop - start)

def main():
    test_time()
    test_time1()

if __name__ == '__main__':
    main()
<commit_msg>Remove extra attribute<commit_after>from time import time
import zope.interface

class Increments(zope.interface.Interface):

    def increment():
        """Increment something"""

class IncrementsBar(Increments):

    """Provide bar as an attribute"""

    bar = zope.interface.Attribute("""An attribute""")

@zope.interface.implementer(IncrementsBar)
class IncrementingInteger:

    """Increment an integer when increment is called."""

    bar = 2

    def increment(self):
        self.bar += 1

def f(incrementer):
    incrementer.increment()

def test_time():
    start = time()
    for i in range(1000000):
        inc = IncrementingInteger()
        f(inc)
    stop = time()
    print(stop - start)

def test_time1():
    start = time()
    inc = IncrementingInteger()
    for i in range(1000000):
        f(inc)
    stop = time()
    print(stop - start)

def main():
    test_time()
    test_time1()

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


<commit_before># -*- coding: utf-8 -*-
#
# Copyright (C) 2003-2006 Edgewall Software
# Copyright (C) 2003-2006 Jonas Borgström <jonas@edgewall.com>
# Copyright (C) 2006 Matthew Good <trac@matt-good.net>
# Copyright (C) 2005-2006 Christian Boos <cboos@neuf.fr>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Jonas Borgström <jonas@edgewall.com>
#         Matthew Good <trac@matt-good.net>

import locale
import re
import sys
import time
from datetime import tzinfo, timedelta, datetime

from trac.core import TracError
from trac.util.text import to_unicode

# Date/time utilities

# -- conversion

def to_datetime(t, tzinfo=None):
    """Convert `t` into a `datetime` object, using the following rules:

     - If `t` is already a `datetime` object, it is simply returned.
     - If `t` is None, the current time will be used.
     - If `t` is a number, it is interpreted as a timestamp. If no `tzinfo`
       is given, the local timezone will be used for the conversion.

    Any other input will trigger a `TypeError`.
    """
    if t is None:
        return datetime.now(localtz)
    elif isinstance(t, datetime):
        return t
    elif isinstance(t, (int,long,float)):
        return datetime.fromtimestamp(t, tzinfo or localtz)
    raise TypeError('expecting datetime, int, long, float, or None; got %s' %
                    type(t))

def to_timestamp(dt):
    """Return the corresponding POSIX timestamp"""
    if dt:
        diff = dt - _epoc
        return diff.days * 86400 + diff.seconds
    else:
        return 0

# -- formatting

def pretty_timedelta(time1, time2=None, resolution=None):
    """Calculate time delta between two `datetime` objects.
    (the result is somewhat imprecise, only use for prettyprinting).

    If either `time1` or `time2` is None, the current time will be used
    instead.
    """
    time1 = to_datetime(time1)
    time2 = to_datetime(time2)
    if time1 > time2:
        time2, time1 = time1, time2
    units = ((3600 * 24 * 365, 'year',   'years'),
             (3600 * 24 * 30,  'month',  'months'),
             (3600 * 24 * 7,   'week',   'weeks'),
             (3600 * 24,       'day',    'days'),
             (3600,            'hour',   'hours'),
             (60,              'minute', 'minutes'))
    diff = time2 - time1
    age_s = int(diff.days * 86400 + diff.seconds)
    if resolution and age_s < resolution:
        return ''
    if age_s < 60:
        return '%i second%s' % (age_s, age_s != 1 and 's' or '')
    for u, unit, unit_plural in units:
        r = float(age_s) / float(u)
        if r >= 0.9:
            r = int(round(r))
            return '%d %s' % (r, r == 1 and unit or unit_plural)
    return ''

def format_datetime(t=None, format='%x %X', tzinfo=None):
    """Format the `datetime` object `t` into an `unicode` string

    If `t` is None, the current time will be used.

    The formatting will be done using the given `format`, which consist
    of conventional `strftime` keys. In addition the format can be 'iso8601'
    to specify the international date format.

    `tzinfo` will default to the local timezone if left to `None`.
    """
    t = to_datetime(t, tzinfo).astimezone(tzinfo or localtz)
    if format.lower() == 'iso8601':
        format = '%Y-%m-%dT%H:%M:%SZ%z'
    text = t.strftime(format)
    encoding = locale.getpreferredencoding() or sys.getdefaultencoding()
    if sys.platform != 'win32':
        encoding = locale.getlocale(locale.LC_TIME)[1] or encoding
        # the above is broken on win32, e.g. we'd get '437' instead of 'cp437'
    return unicode(text, encoding, 'replace')

def format_date(t=None, format='%x', tzinfo=None):
    """Convenience method for formatting the date part of a `datetime` object.
    See `format_datetime` for more details.
    """
    if format == 'iso8601':
        format = '%Y-%m-%d'
    return format_datetime(t, format, tzinfo=tzinfo)

def format_time(t=None, format='%X', tzinfo=None):
    """Convenience method for formatting the time part of a `datetime` object.
    See `format_datetime` for more details.
    """
    if format == 'iso8601':
        format = '%H:%M:%SZ%z'
    return format_datetime(t, format, tzinfo=tzinfo)

def get_date_format_hint():
    """Present the default format used by `format_date` in a human readable
    form.
    This is a format that will be recognized by `parse_date` when reading a
    date.
    """
    t = datetime(1999, 10, 29, tzinfo=utc)
    tmpl = format_date(t, tzinfo=utc)
    return tmpl.replace('1999', 'YYYY', 1).replace('99', 'YY', 1) \
               .replace('10', 'MM', 1).replace('29', 'DD', 1)

def get_datetime_format_hint():
    """Present the default format used by `format_datetime` in a human readable
    form.
    This is a format that will be recognized by `parse_date` when reading a
    date.
    """
    t = datetime(1999, 10, 29, 23, 59, 58, tzinfo=utc)
    tmpl = format_datetime(t, tzinfo=utc)
    return tmpl.replace('1999', 'YYYY', 1).replace('99', 'YY', 1) \
               .replace('10', 'MM', 1).replace('29', 'DD', 1) \
               .replace('23', 'hh', 1).replace('11', 'hh', 1) \
               .replace('59', 'mm', 1).replace('58', 'ss', 1)

def http_date(t=None):
    """Format `datetime` object `t` as a rfc822 timestamp"""
    t = to_datetime(t).astimezone(utc)
    weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
              'Oct', 'Nov', 'Dec']
    return '%s, %02d %s %04d %02d:%02d:%02d GMT' % (
        weekdays[t.weekday()], t.day, months[t.month - 1], t.year,
        t.hour, t.minute, t.second)

# -- parsing

_ISO_8601_RE = re.compile(r'(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d))?)?'   # date
                          r'(?:T(\d\d)(?::?(\d\d)(?::?(\d\d))?)?)?' # time
                          r'(Z(?:([-+])?(\d\d):?(\d\d)?)?)?$'       # timezone
                          )

def parse_date(text, tzinfo=None):
    tzinfo = tzinfo or localtz
    if text == 'now': # TODO: today, yesterday, etc.
        return datetime.now(utc)
    tm = None
    text = text.strip()
    # normalize ISO time
    match = _ISO_8601_RE.match(text)
    if match:
        try:
            g = match.groups()
            years = g[0]
            months = g[1] or '01'
            days = g[2] or '01'
            hours, minutes, seconds = [x or '00' for x in g[3:6]]
            z, tzsign, tzhours, tzminutes = g[6:10]
            if z:
                tz = timedelta(hours=int(tzhours or '0'),
                               minutes=int(tzminutes or '0')).seconds / 60
                if tz == 0:
                    tzinfo = utc
                else:
                    tzinfo = FixedOffset(tzsign == '-' and -tz or tz,
                                         '%s%s:%s' %
                                         (tzsign, tzhours, tzminutes))
            tm = time.strptime('%s ' * 6 % (years, months, days,
                                            hours, minutes, seconds),
                               '%Y %m %d %H %M %S ')
        except ValueError:
            pass
    else:
        for format in ['%x %X', '%x, %X', '%X %x', '%X, %x', '%x', '%c',
                       '%b %d, %Y']:
            try:
                tm = time.strptime(text, format)
                break
            except ValueError:
                continue
    if tm == None:
        hint = get_date_format_hint()
        raise TracError('"%s" is an invalid date, or the date format '
                        'is not known. Try "%s" instead.' % (text, hint),
                        'Invalid Date')
    return datetime(*(tm[0:6] + (0, tzinfo)))

# -- timezone utilities

class FixedOffset(tzinfo):
    """Fixed offset in minutes east from UTC."""

    def __init__(self, offset, name):
        self._offset = timedelta(minutes=offset)
        self.zone = name

    def __str__(self):
        return self.zone

    def __repr__(self):
        return '<FixedOffset "%s" %s>' % (self.zone, self._offset)

    def utcoffset(self, dt):
        return self._offset

    def tzname(self, dt):
        return self.zone

    def dst(self, dt):
        return _zero

STDOFFSET = timedelta(seconds=-time.timezone)
if time.daylight:
    DSTOFFSET = timedelta(seconds=-time.altzone)
else:
    DSTOFFSET = STDOFFSET

DSTDIFF = DSTOFFSET - STDOFFSET

class LocalTimezone(tzinfo):
    """A 'local' time zone implementation"""

    def utcoffset(self, dt):
        if self._isdst(dt):
            return DSTOFFSET
        else:
            return STDOFFSET

    def dst(self, dt):
        if self._isdst(dt):
            return DSTDIFF
        else:
            return _zero

    def tzname(self, dt):
        return time.tzname[self._isdst(dt)]

    def _isdst(self, dt):
        tt = (dt.year, dt.month, dt.day,
              dt.hour, dt.minute, dt.second,
              dt.weekday(), 0, -1)
        try:
            stamp = time.mktime(tt)
            tt = time.localtime(stamp)
            return tt.tm_isdst > 0
        except OverflowError:
            return False

utc = FixedOffset(0, 'UTC')
utcmin = datetime.min.replace(tzinfo=utc)
utcmax = datetime.max.replace(tzinfo=utc)
_epoc = datetime(1970, 1, 1, tzinfo=utc)
_zero = timedelta(0)

localtz = LocalTimezone()

# Use a makeshift timezone implementation if pytz is not available.
# This implementation only supports fixed offset time zones.
#
_timezones = [
    FixedOffset(0, 'UTC'),
    FixedOffset(-720, 'GMT -12:00'), FixedOffset(-660, 'GMT -11:00'),
    FixedOffset(-600, 'GMT -10:00'), FixedOffset(-540, 'GMT -9:00'),
    FixedOffset(-480, 'GMT -8:00'),  FixedOffset(-420, 'GMT -7:00'),
    FixedOffset(-360, 'GMT -6:00'),  FixedOffset(-300, 'GMT -5:00'),
    FixedOffset(-240, 'GMT -4:00'),  FixedOffset(-180, 'GMT -3:00'),
    FixedOffset(-120, 'GMT -2:00'),  FixedOffset(-60, 'GMT -1:00'),
    FixedOffset(0, 'GMT'),           FixedOffset(60, 'GMT +1:00'),
    FixedOffset(120, 'GMT +2:00'),   FixedOffset(180, 'GMT +3:00'),
    FixedOffset(240, 'GMT +4:00'),   FixedOffset(300, 'GMT +5:00'),
    FixedOffset(360, 'GMT +6:00'),   FixedOffset(420, 'GMT +7:00'),
    FixedOffset(480, 'GMT +8:00'),   FixedOffset(540, 'GMT +9:00'),
    FixedOffset(600, 'GMT +10:00'),  FixedOffset(660, 'GMT +11:00'),
    FixedOffset(720, 'GMT +12:00'),  FixedOffset(780, 'GMT +13:00')]
_tzmap = dict([(z.zone, z) for z in _timezones])

all_timezones = [z.zone for z in _timezones]

try:
    import pytz

    _tzoffsetmap = dict([(tz.utcoffset(None), tz) for tz in _timezones
                         if tz.zone != 'UTC'])

    def timezone(tzname):
        tz = get_timezone(tzname)
        if not tz:
            raise KeyError(tzname)
        return tz

    def get_timezone(tzname):
        """Fetch timezone instance by name or return `None`"""
        try:
            # if given unicode parameter, pytz.timezone fails with:
            # "type() argument 1 must be string, not unicode"
            tz = pytz.timezone(to_unicode(tzname).encode('ascii', 'replace'))
        except (KeyError, IOError):
            tz = _tzmap.get(tzname)
        if tz and tzname.startswith('Etc/'):
            tz = _tzoffsetmap.get(tz.utcoffset(None))
        return tz

    _pytz_zones = [tzname for tzname in pytz.all_timezones
                   if not tzname.startswith('Etc/') and
                      not tzname.startswith('GMT')]
    # insert just the GMT timezones into the pytz zones at the right location
    # the pytz zones already include UTC so skip it
    from bisect import bisect
    _gmt_index = bisect(_pytz_zones, 'GMT')
    all_timezones = _pytz_zones[:_gmt_index] + all_timezones[1:] + \
                    _pytz_zones[_gmt_index:]

except ImportError:

    def timezone(tzname):
        """Fetch timezone instance by name or raise `KeyError`"""
        return _tzmap[tzname]

    def get_timezone(tzname):
        """Fetch timezone instance by name or return `None`"""
        return _tzmap.get(tzname)

<commit_msg>use tuple in `datefmt.http_date` since it gets optimized to a `LOAD_CONST` instead of building the list<commit_after># -*- coding: utf-8 -*-
#
# Copyright (C) 2003-2006 Edgewall Software
# Copyright (C) 2003-2006 Jonas Borgström <jonas@edgewall.com>
# Copyright (C) 2006 Matthew Good <trac@matt-good.net>
# Copyright (C) 2005-2006 Christian Boos <cboos@neuf.fr>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Jonas Borgström <jonas@edgewall.com>
#         Matthew Good <trac@matt-good.net>

import locale
import re
import sys
import time
from datetime import tzinfo, timedelta, datetime

from trac.core import TracError
from trac.util.text import to_unicode

# Date/time utilities

# -- conversion

def to_datetime(t, tzinfo=None):
    """Convert `t` into a `datetime` object, using the following rules:

     - If `t` is already a `datetime` object, it is simply returned.
     - If `t` is None, the current time will be used.
     - If `t` is a number, it is interpreted as a timestamp. If no `tzinfo`
       is given, the local timezone will be used for the conversion.

    Any other input will trigger a `TypeError`.
    """
    if t is None:
        return datetime.now(localtz)
    elif isinstance(t, datetime):
        return t
    elif isinstance(t, (int,long,float)):
        return datetime.fromtimestamp(t, tzinfo or localtz)
    raise TypeError('expecting datetime, int, long, float, or None; got %s' %
                    type(t))

def to_timestamp(dt):
    """Return the corresponding POSIX timestamp"""
    if dt:
        diff = dt - _epoc
        return diff.days * 86400 + diff.seconds
    else:
        return 0

# -- formatting

def pretty_timedelta(time1, time2=None, resolution=None):
    """Calculate time delta between two `datetime` objects.
    (the result is somewhat imprecise, only use for prettyprinting).

    If either `time1` or `time2` is None, the current time will be used
    instead.
    """
    time1 = to_datetime(time1)
    time2 = to_datetime(time2)
    if time1 > time2:
        time2, time1 = time1, time2
    units = ((3600 * 24 * 365, 'year',   'years'),
             (3600 * 24 * 30,  'month',  'months'),
             (3600 * 24 * 7,   'week',   'weeks'),
             (3600 * 24,       'day',    'days'),
             (3600,            'hour',   'hours'),
             (60,              'minute', 'minutes'))
    diff = time2 - time1
    age_s = int(diff.days * 86400 + diff.seconds)
    if resolution and age_s < resolution:
        return ''
    if age_s < 60:
        return '%i second%s' % (age_s, age_s != 1 and 's' or '')
    for u, unit, unit_plural in units:
        r = float(age_s) / float(u)
        if r >= 0.9:
            r = int(round(r))
            return '%d %s' % (r, r == 1 and unit or unit_plural)
    return ''

def format_datetime(t=None, format='%x %X', tzinfo=None):
    """Format the `datetime` object `t` into an `unicode` string

    If `t` is None, the current time will be used.

    The formatting will be done using the given `format`, which consist
    of conventional `strftime` keys. In addition the format can be 'iso8601'
    to specify the international date format.

    `tzinfo` will default to the local timezone if left to `None`.
    """
    t = to_datetime(t, tzinfo).astimezone(tzinfo or localtz)
    if format.lower() == 'iso8601':
        format = '%Y-%m-%dT%H:%M:%SZ%z'
    text = t.strftime(format)
    encoding = locale.getpreferredencoding() or sys.getdefaultencoding()
    if sys.platform != 'win32':
        encoding = locale.getlocale(locale.LC_TIME)[1] or encoding
        # the above is broken on win32, e.g. we'd get '437' instead of 'cp437'
    return unicode(text, encoding, 'replace')

def format_date(t=None, format='%x', tzinfo=None):
    """Convenience method for formatting the date part of a `datetime` object.
    See `format_datetime` for more details.
    """
    if format == 'iso8601':
        format = '%Y-%m-%d'
    return format_datetime(t, format, tzinfo=tzinfo)

def format_time(t=None, format='%X', tzinfo=None):
    """Convenience method for formatting the time part of a `datetime` object.
    See `format_datetime` for more details.
    """
    if format == 'iso8601':
        format = '%H:%M:%SZ%z'
    return format_datetime(t, format, tzinfo=tzinfo)

def get_date_format_hint():
    """Present the default format used by `format_date` in a human readable
    form.
    This is a format that will be recognized by `parse_date` when reading a
    date.
    """
    t = datetime(1999, 10, 29, tzinfo=utc)
    tmpl = format_date(t, tzinfo=utc)
    return tmpl.replace('1999', 'YYYY', 1).replace('99', 'YY', 1) \
               .replace('10', 'MM', 1).replace('29', 'DD', 1)

def get_datetime_format_hint():
    """Present the default format used by `format_datetime` in a human readable
    form.
    This is a format that will be recognized by `parse_date` when reading a
    date.
    """
    t = datetime(1999, 10, 29, 23, 59, 58, tzinfo=utc)
    tmpl = format_datetime(t, tzinfo=utc)
    return tmpl.replace('1999', 'YYYY', 1).replace('99', 'YY', 1) \
               .replace('10', 'MM', 1).replace('29', 'DD', 1) \
               .replace('23', 'hh', 1).replace('11', 'hh', 1) \
               .replace('59', 'mm', 1).replace('58', 'ss', 1)

def http_date(t=None):
    """Format `datetime` object `t` as a rfc822 timestamp"""
    t = to_datetime(t).astimezone(utc)
    weekdays = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
    months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
              'Oct', 'Nov', 'Dec')
    return '%s, %02d %s %04d %02d:%02d:%02d GMT' % (
        weekdays[t.weekday()], t.day, months[t.month - 1], t.year,
        t.hour, t.minute, t.second)

# -- parsing

_ISO_8601_RE = re.compile(r'(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d))?)?'   # date
                          r'(?:T(\d\d)(?::?(\d\d)(?::?(\d\d))?)?)?' # time
                          r'(Z(?:([-+])?(\d\d):?(\d\d)?)?)?$'       # timezone
                          )

def parse_date(text, tzinfo=None):
    tzinfo = tzinfo or localtz
    if text == 'now': # TODO: today, yesterday, etc.
        return datetime.now(utc)
    tm = None
    text = text.strip()
    # normalize ISO time
    match = _ISO_8601_RE.match(text)
    if match:
        try:
            g = match.groups()
            years = g[0]
            months = g[1] or '01'
            days = g[2] or '01'
            hours, minutes, seconds = [x or '00' for x in g[3:6]]
            z, tzsign, tzhours, tzminutes = g[6:10]
            if z:
                tz = timedelta(hours=int(tzhours or '0'),
                               minutes=int(tzminutes or '0')).seconds / 60
                if tz == 0:
                    tzinfo = utc
                else:
                    tzinfo = FixedOffset(tzsign == '-' and -tz or tz,
                                         '%s%s:%s' %
                                         (tzsign, tzhours, tzminutes))
            tm = time.strptime('%s ' * 6 % (years, months, days,
                                            hours, minutes, seconds),
                               '%Y %m %d %H %M %S ')
        except ValueError:
            pass
    else:
        for format in ['%x %X', '%x, %X', '%X %x', '%X, %x', '%x', '%c',
                       '%b %d, %Y']:
            try:
                tm = time.strptime(text, format)
                break
            except ValueError:
                continue
    if tm == None:
        hint = get_date_format_hint()
        raise TracError('"%s" is an invalid date, or the date format '
                        'is not known. Try "%s" instead.' % (text, hint),
                        'Invalid Date')
    return datetime(*(tm[0:6] + (0, tzinfo)))

# -- timezone utilities

class FixedOffset(tzinfo):
    """Fixed offset in minutes east from UTC."""

    def __init__(self, offset, name):
        self._offset = timedelta(minutes=offset)
        self.zone = name

    def __str__(self):
        return self.zone

    def __repr__(self):
        return '<FixedOffset "%s" %s>' % (self.zone, self._offset)

    def utcoffset(self, dt):
        return self._offset

    def tzname(self, dt):
        return self.zone

    def dst(self, dt):
        return _zero

STDOFFSET = timedelta(seconds=-time.timezone)
if time.daylight:
    DSTOFFSET = timedelta(seconds=-time.altzone)
else:
    DSTOFFSET = STDOFFSET

DSTDIFF = DSTOFFSET - STDOFFSET

class LocalTimezone(tzinfo):
    """A 'local' time zone implementation"""

    def utcoffset(self, dt):
        if self._isdst(dt):
            return DSTOFFSET
        else:
            return STDOFFSET

    def dst(self, dt):
        if self._isdst(dt):
            return DSTDIFF
        else:
            return _zero

    def tzname(self, dt):
        return time.tzname[self._isdst(dt)]

    def _isdst(self, dt):
        tt = (dt.year, dt.month, dt.day,
              dt.hour, dt.minute, dt.second,
              dt.weekday(), 0, -1)
        try:
            stamp = time.mktime(tt)
            tt = time.localtime(stamp)
            return tt.tm_isdst > 0
        except OverflowError:
            return False

utc = FixedOffset(0, 'UTC')
utcmin = datetime.min.replace(tzinfo=utc)
utcmax = datetime.max.replace(tzinfo=utc)
_epoc = datetime(1970, 1, 1, tzinfo=utc)
_zero = timedelta(0)

localtz = LocalTimezone()

# Use a makeshift timezone implementation if pytz is not available.
# This implementation only supports fixed offset time zones.
#
_timezones = [
    FixedOffset(0, 'UTC'),
    FixedOffset(-720, 'GMT -12:00'), FixedOffset(-660, 'GMT -11:00'),
    FixedOffset(-600, 'GMT -10:00'), FixedOffset(-540, 'GMT -9:00'),
    FixedOffset(-480, 'GMT -8:00'),  FixedOffset(-420, 'GMT -7:00'),
    FixedOffset(-360, 'GMT -6:00'),  FixedOffset(-300, 'GMT -5:00'),
    FixedOffset(-240, 'GMT -4:00'),  FixedOffset(-180, 'GMT -3:00'),
    FixedOffset(-120, 'GMT -2:00'),  FixedOffset(-60, 'GMT -1:00'),
    FixedOffset(0, 'GMT'),           FixedOffset(60, 'GMT +1:00'),
    FixedOffset(120, 'GMT +2:00'),   FixedOffset(180, 'GMT +3:00'),
    FixedOffset(240, 'GMT +4:00'),   FixedOffset(300, 'GMT +5:00'),
    FixedOffset(360, 'GMT +6:00'),   FixedOffset(420, 'GMT +7:00'),
    FixedOffset(480, 'GMT +8:00'),   FixedOffset(540, 'GMT +9:00'),
    FixedOffset(600, 'GMT +10:00'),  FixedOffset(660, 'GMT +11:00'),
    FixedOffset(720, 'GMT +12:00'),  FixedOffset(780, 'GMT +13:00')]
_tzmap = dict([(z.zone, z) for z in _timezones])

all_timezones = [z.zone for z in _timezones]

try:
    import pytz

    _tzoffsetmap = dict([(tz.utcoffset(None), tz) for tz in _timezones
                         if tz.zone != 'UTC'])

    def timezone(tzname):
        tz = get_timezone(tzname)
        if not tz:
            raise KeyError(tzname)
        return tz

    def get_timezone(tzname):
        """Fetch timezone instance by name or return `None`"""
        try:
            # if given unicode parameter, pytz.timezone fails with:
            # "type() argument 1 must be string, not unicode"
            tz = pytz.timezone(to_unicode(tzname).encode('ascii', 'replace'))
        except (KeyError, IOError):
            tz = _tzmap.get(tzname)
        if tz and tzname.startswith('Etc/'):
            tz = _tzoffsetmap.get(tz.utcoffset(None))
        return tz

    _pytz_zones = [tzname for tzname in pytz.all_timezones
                   if not tzname.startswith('Etc/') and
                      not tzname.startswith('GMT')]
    # insert just the GMT timezones into the pytz zones at the right location
    # the pytz zones already include UTC so skip it
    from bisect import bisect
    _gmt_index = bisect(_pytz_zones, 'GMT')
    all_timezones = _pytz_zones[:_gmt_index] + all_timezones[1:] + \
                    _pytz_zones[_gmt_index:]

except ImportError:

    def timezone(tzname):
        """Fetch timezone instance by name or raise `KeyError`"""
        return _tzmap[tzname]

    def get_timezone(tzname):
        """Fetch timezone instance by name or return `None`"""
        return _tzmap.get(tzname)

<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
A Python view of a Thredds data server

author: Scott Wales <scott.wales@unimelb.edu.au>

Copyright 2015 ARC Centre of Excellence for Climate Systems Science

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.
"""

import pytest

from threddsclient import *

def test_tpac():
    cat = read_url('http://portal.sf.utas.edu.au/thredds/catalog.xml')

def test_invalid_url():
    with pytest.raises(requests.ConnectionError):
        cat = read_url('http://example.invalid')

def test_null():
    xml = """
    """
    with pytest.raises(ValueError):
        cat = read_xml(xml, 'http://example.test')

def test_empty():
    xml = """
    <catalog></catalog>
    """
    cat = read_xml(xml, 'http://example.test')
    assert len(cat.references) == 0
    assert len(cat.datasets) == 0

def test_ref():
    xml = """
    <catalog><catalogRef name='' ID='foo' xlink:title='foo' /></catalog>
    """
    cat = read_xml(xml, 'http://example.test')
    assert len(cat.references) == 1
    assert len(cat.datasets) == 0

def test_data():
    xml = """
    <catalog><dataset name='' ID='foo' urlPath='' /></catalog>
    """
    cat = read_xml(xml, 'http://example.test')
    assert len(cat.references) == 0
    assert len(cat.datasets) == 1

def test_unidata_sample():
    xml = """
    <catalog xmlns="http://www.unidata.ucar.edu/namespaces/thredds/InvCatalog/v1.1" >
      <service name="aggServer" serviceType="DODS"  base="http://acd.ucar.edu/dodsC/" />
      <dataset name="SAGE III Ozone Loss" urlPath="sage.nc">
        <serviceName>aggServer</serviceName>
      </dataset>
    </catalog>
    """
    cat = read_xml(xml, 'http://example.test/catalog.xml')
    d = cat.datasets[0]
    assert d.name == "SAGE III Ozone Loss"

def test_noaa_sample():
    xml = """
    <catalog xmlns="http://www.unidata.ucar.edu/namespaces/thredds/InvCatalog/v1.0" xmlns:xlink="http://www.w3.org/1999/xlink" name="THREDDS PSD Test Catalog" version="1.0.1">
      <service name="all" serviceType="Compound" base="">
        <service name="odap" serviceType="OPENDAP" base="/psd/thredds/dodsC/" />
        <service name="http" serviceType="HTTPServer" base="/psd/thredds/fileServer/" />
        <service name="wcs" serviceType="WCS" base="/psd/thredds/wcs/" />
        <service name="wms" serviceType="WMS" base="/psd/thredds/wms/" />
      </service>
      <catalogRef name="" xlink:href="/psd/thredds/catalog/Datasets/catalog.xml" xlink:title="Datasets">
        <metadata inherited="true">
          <serviceName>all</serviceName>
          <dataType>GRID</dataType>
        </metadata>
        <property name="DatasetScan" value="true" />
      </catalogRef>
      <catalogRef xlink:href="aggregations.xml" xlink:title="Aggregations" name="" />
    </catalog>
    """
    cat = read_xml(xml, 'http://example.test/catalog.xml')
    assert cat.name == "THREDDS PSD Test Catalog"
    assert cat.references[0].name == "Datasets"
    assert cat.references[1].name == "Aggregations"
<commit_msg>added test_noaa_sample_2<commit_after>#!/usr/bin/env python
"""
A Python view of a Thredds data server

author: Scott Wales <scott.wales@unimelb.edu.au>

Copyright 2015 ARC Centre of Excellence for Climate Systems Science

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.
"""

import pytest

from threddsclient import *

def test_tpac():
    cat = read_url('http://portal.sf.utas.edu.au/thredds/catalog.xml')

def test_invalid_url():
    with pytest.raises(requests.ConnectionError):
        cat = read_url('http://example.invalid')

def test_null():
    xml = """
    """
    with pytest.raises(ValueError):
        cat = read_xml(xml, 'http://example.test')

def test_empty():
    xml = """
    <catalog></catalog>
    """
    cat = read_xml(xml, 'http://example.test')
    assert len(cat.references) == 0
    assert len(cat.datasets) == 0

def test_ref():
    xml = """
    <catalog><catalogRef name='' ID='foo' xlink:title='foo' /></catalog>
    """
    cat = read_xml(xml, 'http://example.test')
    assert len(cat.references) == 1
    assert len(cat.datasets) == 0

def test_data():
    xml = """
    <catalog><dataset name='' ID='foo' urlPath='' /></catalog>
    """
    cat = read_xml(xml, 'http://example.test')
    assert len(cat.references) == 0
    assert len(cat.datasets) == 1

def test_unidata_sample():
    xml = """
    <catalog xmlns="http://www.unidata.ucar.edu/namespaces/thredds/InvCatalog/v1.1" >
      <service name="aggServer" serviceType="DODS"  base="http://acd.ucar.edu/dodsC/" />
      <dataset name="SAGE III Ozone Loss" urlPath="sage.nc">
        <serviceName>aggServer</serviceName>
      </dataset>
    </catalog>
    """
    cat = read_xml(xml, 'http://example.test/catalog.xml')
    d = cat.datasets[0]
    assert d.name == "SAGE III Ozone Loss"

def test_noaa_sample_1():
    xml = """
    <catalog xmlns="http://www.unidata.ucar.edu/namespaces/thredds/InvCatalog/v1.0" xmlns:xlink="http://www.w3.org/1999/xlink" name="THREDDS PSD Test Catalog" version="1.0.1">
      <service name="all" serviceType="Compound" base="">
        <service name="odap" serviceType="OPENDAP" base="/psd/thredds/dodsC/" />
        <service name="http" serviceType="HTTPServer" base="/psd/thredds/fileServer/" />
        <service name="wcs" serviceType="WCS" base="/psd/thredds/wcs/" />
        <service name="wms" serviceType="WMS" base="/psd/thredds/wms/" />
      </service>
      <catalogRef name="" xlink:href="/psd/thredds/catalog/Datasets/catalog.xml" xlink:title="Datasets">
        <metadata inherited="true">
          <serviceName>all</serviceName>
          <dataType>GRID</dataType>
        </metadata>
        <property name="DatasetScan" value="true" />
      </catalogRef>
      <catalogRef xlink:href="aggregations.xml" xlink:title="Aggregations" name="" />
    </catalog>
    """
    cat = read_xml(xml, 'http://example.test/catalog.xml')
    assert cat.name == "THREDDS PSD Test Catalog"
    assert cat.references[0].name == "Datasets"
    assert cat.references[1].name == "Aggregations"

def test_noaa_sample_2():
    xml = """
    <catalog xmlns="http://www.unidata.ucar.edu/namespaces/thredds/InvCatalog/v1.0" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0.1">
      <service name="all" serviceType="Compound" base="">
        <service name="odap" serviceType="OPENDAP" base="/psd/thredds/dodsC/" />
        <service name="http" serviceType="HTTPServer" base="/psd/thredds/fileServer/" />
        <service name="wcs" serviceType="WCS" base="/psd/thredds/wcs/" />
        <service name="wms" serviceType="WMS" base="/psd/thredds/wms/" />
      </service>
      <dataset name="Datasets" ID="Datasets">
        <metadata inherited="true">
          <serviceName>all</serviceName>
          <dataType>GRID</dataType>
        </metadata>
        <catalogRef xlink:href="ncep.reanalysis/catalog.xml" xlink:title="ncep.reanalysis" ID="Datasets/ncep.reanalysis" name="" />
        <catalogRef xlink:href="ncep.reanalysis.dailyavgs/catalog.xml" xlink:title="ncep.reanalysis.dailyavgs" ID="Datasets/ncep.reanalysis.dailyavgs" name="" />
        <catalogRef xlink:href="ncep.reanalysis2/catalog.xml" xlink:title="ncep.reanalysis2" ID="Datasets/ncep.reanalysis2" name="" />
        <catalogRef xlink:href="ncep.reanalysis2.dailyavgs/catalog.xml" xlink:title="ncep.reanalysis2.dailyavgs" ID="Datasets/ncep.reanalysis2.dailyavgs" name="" />
      </dataset>
    </catalog>
    """
    cat = read_xml(xml, 'http://example.test/catalog.xml')
    assert cat.datasets[0].name == "Datasets"
    assert cat.datasets[0].content_type == "application/directory"
    assert cat.datasets[0].references[0].name == "ncep.reanalysis"
    assert cat.datasets[0].references[0].url == "http://example.test/ncep.reanalysis/catalog.xml"
<|endoftext|>


<commit_before>from alerta.models.alert import Alert
from alerta.webhooks import WebhookBase
import json

class AzureMonitorWebhook(WebhookBase):

    def incoming(self, query_string, payload):

        # fail-safe to a default environment
        try:
            environment = query_string['environment']
        except:
            environment = 'Production'

        # Azure has two formats for their webhooks (the first one is new format and the second one is old format)
        try:
            if payload['data']['status'] == 'Activated':
                severity = 'critical'
            elif payload['data']['status'] == 'Resolved':
                severity = 'ok'
            else:
                severity = 'unknown'

            resource        = payload['data']['context']['resourceName']
            create_time     = payload['data']['context']['timestamp']
            event           = payload['data']['context']['name']
            service         = payload['data']['context']['resourceType']
            group           = payload['data']['context']['resourceGroupName']
            tags            = ['{}={}'.format(k, v) for k, v in payload['data']['properties'].items()]

            if payload['schemaId'] == 'AzureMonitorMetricAlert':
                event_type = 'MetricAlert'
                text = '{}: {} {} ({} {})'.format(severity.upper(), payload['data']['context']['condition']['allOf'][0]['metricValue'], payload['data']['context']['condition']['allOf'][0]['metricName'], payload['data']['context']['condition']['allOf'][0]['operator'], payload['data']['context']['condition']['allOf'][0]['threshold'])
                value = '{} {}'.format(payload['data']['context']['condition']['allOf'][0]['metricValue'], payload['data']['context']['condition']['allOf'][0]['metricName'])
            else:
                text = '{}'.format(severity.upper())
                value = ''
                event_type = 'EventAlert'

        except:
            if payload['status'] == 'Activated':
                severity = 'critical'
            elif payload['status'] == 'Resolved':
                severity = 'ok'
            else:
                severity = 'unknown'

            if payload['context']['conditionType'] == 'Metric':
                text = '{}: {} {} ({} {})'.format(severity.upper(), payload['context']['condition']['metricValue'], payload['context']['condition']['metricName'], payload['context']['condition']['operator'], payload['context']['condition']['threshold'])
                value = '{} {}'.format(payload['context']['condition']['metricValue'], payload['context']['condition']['metricName'])
            else:
                text = '{}'.format(severity.upper())
                value = ''

            resource        = payload['context']['resourceName']
            create_time     = payload['context']['timestamp']
            event_type      = '{}Alert'.format(payload['context']['conditionType'])
            event           = payload['context']['name']
            service         = [payload['context']['resourceType']]
            group           = payload['context']['resourceGroupName']
            tags            = ['{}={}'.format(k, v) for k, v in payload['properties'].items()]

        return Alert(
            resource=resource,
            create_time=create_time,
            type=event_type,
            event=event,
            environment=environment,
            severity=severity,
            service=service,
            group=group,
            value=value,
            text=text,
            tags=tags,
            attributes={},
            origin='Azure Monitor',
            raw_data=json.dumps(payload, indent=4)
        )
<commit_msg>#234: azuremonitor webhook support for JSON payload with data.propert… (#235)<commit_after>from alerta.models.alert import Alert
from alerta.webhooks import WebhookBase
import json

class AzureMonitorWebhook(WebhookBase):

    def incoming(self, query_string, payload):

        # fail-safe to a default environment
        try:
            environment = query_string['environment']
        except:
            environment = 'Production'

        # Azure has two formats for their webhooks (the first one is new format and the second one is old format)
        try:
            if payload['data']['status'] == 'Activated':
                severity = 'critical'
            elif payload['data']['status'] == 'Resolved':
                severity = 'ok'
            else:
                severity = 'unknown'

            resource        = payload['data']['context']['resourceName']
            create_time     = payload['data']['context']['timestamp']
            event           = payload['data']['context']['name']
            service         = [payload['data']['context']['resourceType']]
            group           = payload['data']['context']['resourceGroupName']
            tags            = [] if payload['data']['properties'] is None else ['{}={}'.format(k, v) for k, v in payload['data']['properties'].items()]

            if payload['schemaId'] == 'AzureMonitorMetricAlert':
                event_type = 'MetricAlert'
                text = '{}: {} {} ({} {})'.format(severity.upper(), payload['data']['context']['condition']['allOf'][0]['metricValue'], payload['data']['context']['condition']['allOf'][0]['metricName'], payload['data']['context']['condition']['allOf'][0]['operator'], payload['data']['context']['condition']['allOf'][0]['threshold'])
                value = '{} {}'.format(payload['data']['context']['condition']['allOf'][0]['metricValue'], payload['data']['context']['condition']['allOf'][0]['metricName'])
            else:
                text = '{}'.format(severity.upper())
                value = ''
                event_type = 'EventAlert'

        except:
            if payload['status'] == 'Activated':
                severity = 'critical'
            elif payload['status'] == 'Resolved':
                severity = 'ok'
            else:
                severity = 'unknown'

            if payload['context']['conditionType'] == 'Metric':
                text = '{}: {} {} ({} {})'.format(severity.upper(), payload['context']['condition']['metricValue'], payload['context']['condition']['metricName'], payload['context']['condition']['operator'], payload['context']['condition']['threshold'])
                value = '{} {}'.format(payload['context']['condition']['metricValue'], payload['context']['condition']['metricName'])
            else:
                text = '{}'.format(severity.upper())
                value = ''

            resource        = payload['context']['resourceName']
            create_time     = payload['context']['timestamp']
            event_type      = '{}Alert'.format(payload['context']['conditionType'])
            event           = payload['context']['name']
            service         = [payload['context']['resourceType']]
            group           = payload['context']['resourceGroupName']
            tags            = [] if payload['properties'] is None else ['{}={}'.format(k, v) for k, v in payload['properties'].items()]

        return Alert(
            resource=resource,
            create_time=create_time,
            type=event_type,
            event=event,
            environment=environment,
            severity=severity,
            service=service,
            group=group,
            value=value,
            text=text,
            tags=tags,
            attributes={},
            origin='Azure Monitor',
            raw_data=json.dumps(payload, indent=4)
        )
<|endoftext|>