Пример #1
0
def test_build_with_query_and_query_string():
    with pytest.raises(ValueError):
        URL.build(
            scheme='http',
            host='127.0.0.1',
            user='******',
            password='******',
            port=8000,
            path='/index.html',
            query=dict(arg="value1"),
            query_string="arg=value1",
            fragment="top"
        )
Пример #2
0
def test_build_with_query_and_query_string():
    with pytest.raises(ValueError):
        URL.build(
            scheme="http",
            host="127.0.0.1",
            user="******",
            password="******",
            port=8000,
            path="/index.html",
            query=dict(arg="value1"),
            query_string="arg=value1",
            fragment="top",
        )
Пример #3
0
    def __init__(self, path: str, *, name: Optional[str]=None) -> None:
        super().__init__(name=name)
        pattern = ''
        formatter = ''
        for part in ROUTE_RE.split(path):
            match = self.DYN.fullmatch(part)
            if match:
                pattern += '(?P<{}>{})'.format(match.group('var'), self.GOOD)
                formatter += '{' + match.group('var') + '}'
                continue

            match = self.DYN_WITH_RE.fullmatch(part)
            if match:
                pattern += '(?P<{var}>{re})'.format(**match.groupdict())
                formatter += '{' + match.group('var') + '}'
                continue

            if '{' in part or '}' in part:
                raise ValueError("Invalid path '{}'['{}']".format(path, part))

            path = URL.build(path=part).raw_path
            formatter += path
            pattern += re.escape(path)

        try:
            compiled = re.compile(pattern)
        except re.error as exc:
            raise ValueError(
                "Bad pattern '{}': {}".format(pattern, exc)) from None
        assert compiled.pattern.startswith(PATH_SEP)
        assert formatter.startswith('/')
        self._pattern = compiled
        self._formatter = formatter
Пример #4
0
    def url_for(self, *, filename: Union[str, Path],  # type: ignore
                append_version: Optional[bool]=None) -> URL:
        if append_version is None:
            append_version = self._append_version
        if isinstance(filename, Path):
            filename = str(filename)
        while filename.startswith('/'):
            filename = filename[1:]
        filename = '/' + filename

        # filename is not encoded
        url = URL.build(path=self._prefix + filename)

        if append_version:
            try:
                if filename.startswith('/'):
                    filename = filename[1:]
                filepath = self._directory.joinpath(filename).resolve()
                if not self._follow_symlinks:
                    filepath.relative_to(self._directory)
            except (ValueError, FileNotFoundError):
                # ValueError for case when path point to symlink
                # with follow_symlinks is False
                return url  # relatively safe
            if filepath.is_file():
                # TODO cache file content
                # with file watcher for cache invalidation
                with open(str(filepath), mode='rb') as f:
                    file_bytes = f.read()
                h = self._get_file_hash(file_bytes)
                url = url.with_query({self.VERSION_KEY: h})
                return url
        return url
Пример #5
0
def test_build_drop_dots():
    u = URL.build(
        scheme='http',
        host='example.com',
        path='/path/../to',
    )
    assert str(u) == 'http://example.com/to'
Пример #6
0
 def _match(self, path: str) -> Optional[Dict[str, str]]:
     match = self._pattern.fullmatch(path)
     if match is None:
         return None
     else:
         return {key: URL.build(path=value, encoded=True).path
                 for key, value in match.groupdict().items()}
Пример #7
0
def test_build_query_quoting():
    u = URL.build(scheme="http", host="127.0.0.1", path="/файл.jpg", query="arg=Привет")

    assert u == URL("http://127.0.0.1/файл.jpg?arg=Привет")
    assert str(u) == (
        "http://127.0.0.1/%D1%84%D0%B0%D0%B9%D0%BB.jpg?"
        "arg=%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82"
    )
Пример #8
0
def test_query_str():
    u = URL.build(
        scheme='http',
        host='127.0.0.1',
        path='/',
        query_string="arg=value1"
    )
    assert str(u) == 'http://127.0.0.1/?arg=value1'
Пример #9
0
def test_build_path_quoting():
    u = URL.build(
        scheme='http',
        host='127.0.0.1',
        path='/файл.jpg',
        query=dict(arg="Привет")
    )

    assert u == URL('http://127.0.0.1/файл.jpg?arg=Привет')
    assert str(u) == ('http://127.0.0.1/%D1%84%D0%B0%D0%B9%D0%BB.jpg?'
                      'arg=%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82')
Пример #10
0
def test_build_already_encoded():
    # resulting URL is invalid but not encoded
    u = URL.build(
        scheme="http",
        host="историк.рф",
        path="/путь/файл",
        query_string="ключ=знач",
        fragment="фраг",
        encoded=True,
    )
    assert str(u) == "http://историк.рф/путь/файл?ключ=знач#фраг"
Пример #11
0
def test_build_with_all():
    u = URL.build(
        scheme='http',
        host='127.0.0.1',
        user='******',
        password='******',
        port=8000,
        path='/index.html',
        query_string="arg=value1",
        fragment="top"
    )
    assert str(u) == 'http://*****:*****@127.0.0.1:8000/index.html?arg=value1#top'
Пример #12
0
def test_build_with_all():
    u = URL.build(
        scheme="http",
        host="127.0.0.1",
        user="******",
        password="******",
        port=8000,
        path="/index.html",
        query_string="arg=value1",
        fragment="top",
    )
    assert str(u) == "http://*****:*****@127.0.0.1:8000/index.html?arg=value1#top"
Пример #13
0
 def __init__(self, runner, sock, *,
              shutdown_timeout=60.0, ssl_context=None,
              backlog=128):
     super().__init__(runner, shutdown_timeout=shutdown_timeout,
                      ssl_context=ssl_context, backlog=backlog)
     self._sock = sock
     scheme = 'https' if self._ssl_context else 'http'
     if hasattr(socket, 'AF_UNIX') and sock.family == socket.AF_UNIX:
         name = '{}://unix:{}:'.format(scheme, sock.getsockname())
     else:
         host, port = sock.getsockname()[:2]
         name = str(URL.build(scheme=scheme, host=host, port=port))
     self._name = name
Пример #14
0
    async def resolve(self, request: Request) -> _Resolve:
        path = request.rel_url.raw_path
        method = request.method
        allowed_methods = set(self._routes)
        if not path.startswith(self._prefix):
            return None, set()

        if method not in allowed_methods:
            return None, allowed_methods

        match_dict = {'filename': URL.build(path=path[len(self._prefix)+1:],
                                            encoded=True).path}
        return (UrlMappingMatchInfo(match_dict, self._routes[method]),
                allowed_methods)
Пример #15
0
def test_build_encode():
    u = URL.build(
        scheme="http",
        host="историк.рф",
        path="/путь/файл",
        query_string="ключ=знач",
        fragment="фраг",
    )
    expected = (
        "http://xn--h1aagokeh.xn--p1ai"
        "/%D0%BF%D1%83%D1%82%D1%8C/%D1%84%D0%B0%D0%B9%D0%BB"
        "?%D0%BA%D0%BB%D1%8E%D1%87=%D0%B7%D0%BD%D0%B0%D1%87"
        "#%D1%84%D1%80%D0%B0%D0%B3"
    )
    assert str(u) == expected
Пример #16
0
 def add_resource(self, path, *, name=None):
     if path and not path.startswith('/'):
         raise ValueError("path should be started with / or be empty")
     # Reuse last added resource if path and name are the same
     if self._resources:
         resource = self._resources[-1]
         if resource.name == name and resource.raw_match(path):
             return resource
     if not ('{' in path or '}' in path or ROUTE_RE.search(path)):
         url = URL.build(path=path)
         resource = PlainResource(url.raw_path, name=name)
         self.register_resource(resource)
         return resource
     resource = DynamicResource(path, name=name)
     self.register_resource(resource)
     return resource
Пример #17
0
    def url_for(  # type: ignore
        self,
        *,
        filename: Union[str, Path],
        append_version: Optional[bool] = None,
    ) -> URL:
        if append_version is None:
            append_version = self._append_version
        if isinstance(filename, Path):
            filename = str(filename)
        filename = filename.lstrip("/")

        url = URL.build(path=self._prefix, encoded=True)
        # filename is not encoded
        if YARL_VERSION < (1, 6):
            url = url / filename.replace("%", "%25")
        else:
            url = url / filename

        if append_version:
            try:
                filepath = self._directory.joinpath(filename).resolve()
                if not self._follow_symlinks:
                    filepath.relative_to(self._directory)
            except (ValueError, FileNotFoundError):
                # ValueError for case when path point to symlink
                # with follow_symlinks is False
                return url  # relatively safe
            if filepath.is_file():
                # TODO cache file content
                # with file watcher for cache invalidation
                with filepath.open("rb") as f:
                    file_bytes = f.read()
                h = self._get_file_hash(file_bytes)
                url = url.with_query({self.VERSION_KEY: h})
                return url
        return url
Пример #18
0
 def __init__(
     self,
     host: str,
     mac: str,
     token='',
     session: aiohttp.client.ClientSession = None,
 ):
     """Initialize the bulb."""
     self._close_session = False
     self._host = host
     self._mac = mac
     self._session = session
     self.brightness = 0
     self._color = None
     self._consumption = 0
     self.data = None
     self._firmware = None
     self._mode = None
     self._bulb_type = None
     self._state = None
     self._transition_time = 0
     self.uri = URL.build(scheme="http",
                          host=self._host).join(URI_BULB) / self._mac
     self.token = token
Пример #19
0
    def url_for(
            self,
            *,
            filename: Union[str, Path],  # type: ignore
            append_version: Optional[bool] = None) -> URL:
        if append_version is None:
            append_version = self._append_version
        if isinstance(filename, Path):
            filename = str(filename)
        while filename.startswith('/'):
            filename = filename[1:]
        filename = '/' + filename

        # filename is not encoded
        url = URL.build(path=self._prefix + filename)

        if append_version:
            try:
                if filename.startswith('/'):
                    filename = filename[1:]
                filepath = self._directory.joinpath(filename).resolve()
                if not self._follow_symlinks:
                    filepath.relative_to(self._directory)
            except (ValueError, FileNotFoundError):
                # ValueError for case when path point to symlink
                # with follow_symlinks is False
                return url  # relatively safe
            if filepath.is_file():
                # TODO cache file content
                # with file watcher for cache invalidation
                with open(str(filepath), mode='rb') as f:
                    file_bytes = f.read()
                h = self._get_file_hash(file_bytes)
                url = url.with_query({self.VERSION_KEY: h})
                return url
        return url
Пример #20
0
def setup_catalog(app: web.Application, *, disable_auth=False):
    # ----------------------------------------------
    # TODO: temporary, just to check compatibility between
    # trafaret and pydantic schemas
    cfg, _ = assert_valid_config(app)
    # ---------------------------------------------

    # resolve url
    app[KCATALOG_ORIGIN] = URL.build(scheme="http",
                                     host=cfg["host"],
                                     port=cfg["port"])
    app[KCATALOG_VERSION_PREFIX] = cfg["version"]

    specs = app[APP_OPENAPI_SPECS_KEY]  # validated openapi specs

    exclude: List[str] = []
    route_def: RouteDef
    for route_def in catalog_api_handlers.routes:
        route_def.kwargs["name"] = operation_id = route_def.handler.__name__
        exclude.append(operation_id)

    app.add_routes(catalog_api_handlers.routes)

    # bind the rest routes with the reverse-proxy-handler
    # FIXME: this would reroute **anything** to the catalog service!
    handler = (_reverse_proxy_handler.__wrapped__
               if disable_auth else _reverse_proxy_handler)
    routes = [
        web.route(method.upper(), path, handler, name=operation_id)
        for method, path, operation_id, tags in iter_path_operations(specs)
        if "catalog" in tags and operation_id not in exclude
    ]
    assert routes, "Got no paths tagged as catalog"  # nosec

    # reverse proxy to catalog's API
    app.router.add_routes(routes)
Пример #21
0
 def modify_request(self, request: web.Request) -> None:
     """
     Apply common path conventions eg. / > /index.html, /foobar > /foobar.html
     """
     filename = URL.build(path=request.match_info['filename'], encoded=True).path
     raw_path = self._directory.joinpath(filename)
     try:
         filepath = raw_path.resolve(strict=True)
     except FileNotFoundError:
         try:
             html_file = raw_path.with_name(raw_path.name + '.html').resolve().relative_to(self._directory)
         except (FileNotFoundError, ValueError):
             pass
         else:
             request.match_info['filename'] = str(html_file)
     else:
         if filepath.is_dir():
             index_file = filepath / 'index.html'
             if index_file.exists():
                 try:
                     request.match_info['filename'] = str(index_file.relative_to(self._directory))
                 except ValueError:
                     # path is not not relative to self._directory
                     pass
Пример #22
0
def coerce_url(url: Union[URL, str], https: bool = False) -> URL:
    """
    Coerce URL to valid format

    :param url: URL
    :param https: Force https if no scheme in url
    :return: str
    """
    if isinstance(url, str):
        url = URL(url.strip())

    scheme = "https" if https else "http"

    if not url.is_absolute():
        url_string = str(url)
        split = url_string.split("/", 1)
        url = URL.build(scheme=scheme, host=split[0])
        if len(split) > 1:
            url = url.with_path(split[1])

    if (url.scheme == "http" and https) or not url.scheme:
        url = url.with_scheme(scheme)

    return url
Пример #23
0
    async def _request(
        self,
        uri: str = "",
        *,
        data: Optional[Any] = None,
        method: str = "GET",
        no_agreement: bool = False,
    ) -> Any:
        """Handle a request to the Quby ToonAPI."""
        if self.token_refresh_method is not None:
            self.token = await self.token_refresh_method()

        if self._status is None and self.agreement_id and not no_agreement:
            self.activate_agreement(agreement_id=self.agreement_id, )

        url = URL.build(
            scheme=TOON_API_SCHEME,
            host=TOON_API_HOST,
            port=TOON_API_PORT,
            path=TOON_API_BASE_PATH,
        ).join(URL(uri))

        headers = {
            "Authorization": f"Bearer {self.token}",
            "User-Agent": self.user_agent,
            "Accept": "application/json",
        }

        if not no_agreement and self._status is not None:
            headers.update({
                "X-Common-Name":
                self._status.agreement.display_common_name,
                "X-Agreement-ID":
                self._status.agreement.agreement_id,
            })

        if self._session is None:
            self._session = aiohttp.ClientSession()
            self._close_session = True

        try:
            with async_timeout.timeout(self.request_timeout):
                response = await self._session.request(
                    method,
                    url,
                    json=data,
                    headers=headers,
                    ssl=True,
                )
        except asyncio.TimeoutError as exception:
            raise ToonConnectionTimeoutError(
                "Timeout occurred while connecting to the Quby ToonAPI"
            ) from exception
        except (aiohttp.ClientError, socket.gaierror) as exception:
            raise ToonConnectionError(
                "Error occurred while communicating with the Quby ToonAPI"
            ) from exception

        content_type = response.headers.get("Content-Type", "")
        # Error handling
        if (response.status // 100) in [4, 5]:
            contents = await response.read()
            response.close()

            if response.status == 429:
                raise ToonRateLimitError(
                    "Rate limit error has occurred with the Quby ToonAPI")

            if content_type == "application/json":
                raise ToonError(response.status,
                                json.loads(contents.decode("utf8")))
            raise ToonError(response.status,
                            {"message": contents.decode("utf8")})

        # Handle empty response
        if response.status == 204:
            return

        if "application/json" in content_type:
            return await response.json()
        return await response.text()
Пример #24
0
def build_amqp_url(
    user: str = None,
    password: str = None,
    host: str = None,
    port: int = None,
    virtual_host: str = None,
    connection_attempts: int = None,
    heartbeat_interval: int = None,
    ssl_options: dict = None,
) -> str:
    """
    Create a AMQP connection URL from parameters.

    If no parameters are passed to optional arguments then the environment is
    inspected for settings prefixed with ``RABBITMQ_`` and then defaults
    values are used.

    :param user: Login credentials username. Default value is 'guest'.

    :param password: Login credentials password. Default value is 'guest'.

    :param host: AMQP Broker host. Default value is 127.0.0.1.

    :param port: AMQP Broker port. Default value is 5672.

    :param virtualhost: AMQP virtualhost to use. Default value is '/'

    :param connection_attempts: The number of connections attempts.
      No default value.

    :param heartbeat_interval: The interval to use between heartbeat
      requests. No default value.

    :param ssl_options: A dict of public ssl context-related values for the
      SSL connection. Available keys are:

        - ca_certs as a string containing path to ca certificate file
        - cert_reqs
        - certfile
        - keyfile ia a string containing the path to key file
        - ssl_version
    """
    options = {}
    if connection_attempts:
        options["connection_attempts"] = connection_attempts
    if heartbeat_interval:
        options["heartbeat_interval"] = heartbeat_interval
    if ssl_options:
        # Convert any ssl enumerations to a scalar value prior to forming
        # the url.
        for k, v in ssl_options.items():
            if isinstance(v, enum.Enum):
                ssl_options[k] = v.value
        options.update(ssl_options)

    default_port = 5671 if ssl_options else 5672

    url = URL.build(
        scheme="amqps" if ssl_options else "amqp",
        host=host if host else os.getenv("RABBITMQ_HOST", "127.0.0.1"),
        port=port if port else int(os.getenv("RABBITMQ_PORT", str(default_port))),
        user=user if user else os.getenv("RABBITMQ_USER", "guest"),
        password=password if password else os.getenv("RABBITMQ_PASS", "guest"),
        path=f"/{virtual_host}" if virtual_host else "//",
        query=options,
    )

    return str(url)
Пример #25
0
 def url_for(self, **parts: str) -> URL:
     url = self._formatter.format_map(
         {k: _quote_path(v)
          for k, v in parts.items()})
     return URL.build(path=url, encoded=True)
Пример #26
0
def _quote_path(value: str) -> str:
    if YARL_VERSION < (1, 6):
        value = value.replace("%", "%25")
    return URL.build(path=value, encoded=False).raw_path
Пример #27
0
 def name(self) -> str:
     scheme = "https" if self._ssl_context else "http"
     host = "0.0.0.0" if self._host is None else self._host
     return str(URL.build(scheme=scheme, host=host, port=self._port))
Пример #28
0
    async def request(
        self,
        uri: str,
        method: str = "GET",
        additional_headers: dict | None = None,
        data: Any | None = None,
        json_data: dict | None = None,
        params: Mapping[str, str] | None = None,
    ) -> Any:
        """Handle a request to the weenect API.
        Make a request against the weenect API and handles the response.
        Args:
            uri: The request URI on the weenect API to call.
            method: HTTP method to use for the request; e.g., GET, POST.
            data: RAW HTTP request data to send with the request.
            json_data: Dictionary of data to send as JSON with the request.
            params: Mapping of request parameters to send with the request.
        Returns:
            The response from the API. In case the response is a JSON response,
            the method will return a decoded JSON response as a Python
            dictionary. In other cases, it will return the RAW text response.
        Raises:
            WeenectConnectionError: An error occurred while communicating
                with the weenect API (connection issues).
            WeenectHomeError: An error occurred while processing the
                response from the weenect API (invalid data).
        """
        url = URL.build(scheme=SCHEME, host=API_HOST, path=API_VERSION) / uri

        headers = {
            "User-Agent": self.user_agent,
            "Accept": "application/json, text/plain, */*",
            "Origin": APP_URL,
            "x-app-version": "0.1.0",
            "x-app-user-id": "",
            "x-app-type": "userspace",
            "DNT": "1",
        }
        if self._auth_token is not None:
            headers.update({"Authorization": self._auth_token})

        if additional_headers is not None:
            headers.update(additional_headers)

        if self._session is None:
            self._session = aiohttp.ClientSession()
            self._close_session = True

        try:
            async with async_timeout.timeout(self.request_timeout):
                response = await self._session.request(
                    method,
                    url,
                    data=data,
                    json=json_data,
                    params=params,
                    headers=headers,
                )
        except asyncio.TimeoutError as exception:
            raise WeenectConnectionError(
                "Timeout occurred while connecting to the weenect API."
            ) from exception
        except (aiohttp.ClientError, socket.gaierror) as exception:
            raise WeenectConnectionError(
                "Error occurred while communicating with the weenect API."
            ) from exception

        content_type = response.headers.get("Content-Type", "")
        if response.status // 100 in [4, 5]:
            contents = await response.read()
            response.close()

            if (response.status == 401 and json.loads(
                    contents.decode("utf8"))["error"] == "Invalid token"):
                self._auth_token = None
                return await self.authenticated_request(
                    uri=uri,
                    method=method,
                    additional_headers=additional_headers,
                    data=data,
                    json_data=json_data,
                    params=params,
                )

            if content_type == "application/json":
                raise WeenectError(response.status,
                                   json.loads(contents.decode("utf8")))
            raise WeenectError(response.status,
                               {"message": contents.decode("utf8")})

        if response.status == 204:  # NO CONTENT
            response.close()
            return None

        if "application/json" in content_type:
            return await response.json()

        text = await response.text()
        return {"message": text}
Пример #29
0
 def url(self) -> URL:
     url = URL.build(scheme=self.scheme, host=self.host)
     return url.join(self._rel_url)
Пример #30
0
def test_build_with_user_password():
    u = URL.build(scheme='http', host='127.0.0.1', user='******', password='******')
    assert str(u) == 'http://*****:*****@127.0.0.1'
Пример #31
0
 def url_for(self):
     return URL.build(path=self._path, encoded=True)
Пример #32
0
 def name(self):
     scheme = 'https' if self._ssl_context else 'http'
     return str(URL.build(scheme=scheme, host=self._host, port=self._port))
Пример #33
0
def test_query_dict():
    u = URL.build(scheme="http", host="127.0.0.1", path="/", query=dict(arg="value1"))

    assert str(u) == "http://127.0.0.1/?arg=value1"
Пример #34
0
 def url(self):
     url = URL.build(scheme=self.scheme, host=self.host)
     return url.join(self._rel_url)
Пример #35
0
 def url_for(self, **parts: str) -> URL:
     url = self._formatter.format_map(
         {k: URL.build(path=v).raw_path
          for k, v in parts.items()})
     return URL.build(path=url)
Пример #36
0
def make_default_endpoint(region: str) -> URL:
    return URL.build(scheme="https",
                     host=f"{SERVICE}.{region}.amazonaws.com",
                     path="/")
Пример #37
0
 def url_for(self) -> URL:  # type: ignore
     return URL.build(path=self._path, encoded=True)
Пример #38
0
def _make_server_creators(handler, *, loop, ssl_context,
                          host, port, path, sock, backlog):

    scheme = 'https' if ssl_context else 'http'
    base_url = URL.build(scheme=scheme, host='localhost', port=port)

    if path is None:
        paths = ()
    elif isinstance(path, (str, bytes, bytearray, memoryview))\
            or not isinstance(path, Iterable):
        paths = (path,)
    else:
        paths = path

    if sock is None:
        socks = ()
    elif not isinstance(sock, Iterable):
        socks = (sock,)
    else:
        socks = sock

    if host is None:
        if (paths or socks) and not port:
            hosts = ()
        else:
            hosts = ("0.0.0.0",)
    elif isinstance(host, (str, bytes, bytearray, memoryview))\
            or not isinstance(host, Iterable):
        hosts = (host,)
    else:
        hosts = host

    if hosts and port is None:
        port = 8443 if ssl_context else 8080

    server_creations = []
    uris = [str(base_url.with_host(host).with_port(port)) for host in hosts]
    if hosts:
        # Multiple hosts bound to same server is available in most loop
        # implementations, but only send multiple if we have multiple.
        host_binding = hosts[0] if len(hosts) == 1 else hosts
        server_creations.append(
            loop.create_server(
                handler, host_binding, port, ssl=ssl_context, backlog=backlog
            )
        )
    for path in paths:
        # Most loop implementations don't support multiple paths bound in same
        # server, so create a server for each.
        server_creations.append(
            loop.create_unix_server(
                handler, path, ssl=ssl_context, backlog=backlog
            )
        )
        uris.append('{}://unix:{}:'.format(scheme, path))

        # Clean up prior socket path if stale and not abstract.
        # CPython 3.5.3+'s event loop already does this. See
        # https://github.com/python/asyncio/issues/425
        if path[0] not in (0, '\x00'):  # pragma: no branch
            try:
                if stat.S_ISSOCK(os.stat(path).st_mode):
                    os.remove(path)
            except FileNotFoundError:
                pass
    for sock in socks:
        server_creations.append(
            loop.create_server(
                handler, sock=sock, ssl=ssl_context, backlog=backlog
            )
        )

        if hasattr(socket, 'AF_UNIX') and sock.family == socket.AF_UNIX:
            uris.append('{}://unix:{}:'.format(scheme, sock.getsockname()))
        else:
            host, port = sock.getsockname()[:2]
            uris.append(str(base_url.with_host(host).with_port(port)))
    return server_creations, uris
Пример #39
0
def test_build_with_user():
    u = URL.build(scheme='http', host='127.0.0.1', user='******')
    assert str(u) == 'http://[email protected]'
Пример #40
0
def test_build_with_port():
    u = URL.build(scheme='http', host='127.0.0.1', port=8000)
    assert str(u) == 'http://127.0.0.1:8000'
Пример #41
0
import asyncio
import json
import socket
from importlib import metadata
from typing import Any, Mapping

import aiohttp
import async_timeout
from yarl import URL

from .exceptions import WeenectConnectionError, WeenectError
from .zone_modes import ZoneNotificationMode

SCHEME = "https"
APP_HOST = "my.weenect.com"
APP_URL = str(URL.build(scheme=SCHEME, host=APP_HOST))
API_HOST = "apiv4.weenect.com"
API_VERSION = "/v4"


class AioWeenect:
    """Main class for handling connections with weenect."""
    def __init__(
        self,
        password: str,
        username: str,
        request_timeout: int = 10,
        session: aiohttp.client.ClientSession | None = None,
        user_agent: str | None = None,
    ) -> None:
        """Initialize connection with weenect.
Пример #42
0
 def url_for(self, **parts: str) -> URL:
     url = self._formatter.format_map({k: URL.build(path=v).raw_path
                                       for k, v in parts.items()})
     return URL.build(path=url)
Пример #43
0
    async def _request(
        self,
        uri: str = "",
        data: Optional[Any] = None,
        params: Optional[Mapping[str, str]] = None,
    ) -> Any:
        """Handle a request to an IPP server."""
        scheme = "https" if self.tls else "http"

        method = "POST"
        url = URL.build(scheme=scheme,
                        host=self.host,
                        port=self.port,
                        path=self.base_path).join(URL(uri))

        auth = None
        if self.username and self.password:
            auth = aiohttp.BasicAuth(self.username, self.password)

        headers = {
            "User-Agent": self.user_agent,
            "Content-Type": "application/ipp",
            "Accept": "application/ipp, text/plain, */*",
        }

        if self._session is None:
            self._session = aiohttp.ClientSession()
            self._close_session = True

        if isinstance(data, dict):
            data = encode_dict(data)

        try:
            with async_timeout.timeout(self.request_timeout):
                response = await self._session.request(
                    method,
                    url,
                    auth=auth,
                    data=data,
                    params=params,
                    headers=headers,
                    ssl=self.verify_ssl,
                )
        except asyncio.TimeoutError as exc:
            raise IPPConnectionError(
                "Timeout occurred while connecting to IPP server.") from exc
        except (aiohttp.ClientError, SocketGIAError) as exc:
            raise IPPConnectionError(
                "Error occurred while communicating with IPP server.") from exc

        if response.status == 426:
            raise IPPConnectionUpgradeRequired(
                "Connection upgrade required while communicating with IPP server.",
                {"upgrade": response.headers.get("Upgrade")},
            )

        if (response.status // 100) in [4, 5]:
            content = await response.read()
            response.close()

            raise IPPResponseError(
                f"HTTP {response.status}",
                {
                    "content-type": response.headers.get("Content-Type"),
                    "message": content.decode("utf8"),
                    "status-code": response.status,
                },
            )

        return await response.read()
Пример #44
0
 def __init__(self, prefix: str, *, name: Optional[str]=None) -> None:
     assert not prefix or prefix.startswith('/'), prefix
     assert prefix in ('', '/') or not prefix.endswith('/'), prefix
     super().__init__(name=name)
     self._prefix = URL.build(path=prefix).raw_path
Пример #45
0
    def __init__(
        self,
        method: Union[str, bytes],
        url: Union["URL", str, RawURL],
        *,
        params: QueryTypes = None,
        headers: HeaderTypes = None,
        cookies: CookieTypes = None,
        content: ContentTypes = None,
        data: DataTypes = None,
        json: Any = None,
        files: FilesTypes = None,
        version: Union[str, HTTPVersion] = HTTPVersion.H11,
        timeout: Optional[float] = None,
        proxy: Optional[str] = None,
    ):
        # method
        self.method: str = (method.decode("ascii").upper() if isinstance(
            method, bytes) else method.upper())
        # http version
        self.version: HTTPVersion = HTTPVersion(version)
        # timeout
        self.timeout: Optional[float] = timeout
        # proxy
        self.proxy: Optional[str] = proxy

        # url
        if isinstance(url, tuple):
            scheme, host, port, path = url
            url = URL.build(
                scheme=scheme.decode("ascii"),
                host=host.decode("ascii"),
                port=port,
                path=path.decode("ascii"),
            )
        else:
            url = URL(url)

        if params is not None:
            url = url.update_query(params)
        self.url: URL = url

        # headers
        self.headers: CIMultiDict[str]
        if headers is not None:
            self.headers = CIMultiDict(headers)
        else:
            self.headers = CIMultiDict()

        # cookies
        self.cookies = Cookies(cookies)

        # body
        self.content: ContentTypes = content
        self.data: DataTypes = data
        self.json: Any = json
        self.files: Optional[List[Tuple[str, FileType]]] = None
        if files:
            self.files = []
            files_ = files.items() if isinstance(files, dict) else files
            for name, file_info in files_:
                if not isinstance(file_info, tuple):
                    self.files.append((name, (None, file_info, None)))
                elif len(file_info) == 2:
                    self.files.append(
                        (name, (file_info[0], file_info[1], None)))
                else:
                    self.files.append((name, file_info))  # type: ignore
Пример #46
0
def test_build_scheme_and_host():
    with pytest.raises(ValueError):
        URL.build(host='127.0.0.1')

    with pytest.raises(ValueError):
        URL.build(scheme='http')
Пример #47
0
def _unquote_path(value: str) -> str:
    return URL.build(path=value, encoded=True).path
Пример #48
0
def test_build_simple():
    u = URL.build(scheme='http', host='127.0.0.1')
    assert str(u) == 'http://127.0.0.1'
Пример #49
0
async def connect(url: str = None,
                  *,
                  host: str = "localhost",
                  port: int = 5672,
                  login: str = "guest",
                  password: str = "guest",
                  virtualhost: str = "/",
                  ssl: bool = False,
                  loop: asyncio.AbstractEventLoop = None,
                  ssl_options: dict = None,
                  timeout: TimeoutType = None,
                  connection_class: Type[ConnectionType] = Connection,
                  client_properties: dict = None,
                  **kwargs) -> ConnectionType:
    """ Make connection to the broker.

    Example:

    .. code-block:: python

        import aio_pika

        async def main():
            connection = await aio_pika.connect(
                "amqp://*****:*****@127.0.0.1/"
            )

    Connect to localhost with default credentials:

    .. code-block:: python

        import aio_pika

        async def main():
            connection = await aio_pika.connect()

    .. note::

        The available keys for ssl_options parameter are:
            * cert_reqs
            * certfile
            * keyfile
            * ssl_version

        For an information on what the ssl_options can be set to reference the
        `official Python documentation`_ .

    Set connection name for RabbitMQ admin panel:

    .. code-block:: python

        read_connection = await connect(
            client_properties={
                'connection_name': 'Read connection'
            }
        )

        write_connection = await connect(
            client_properties={
                'connection_name': 'Write connection'
            }
        )

    .. note:

        ``client_properties`` argument requires ``aiormq>=2.9``

    URL string might be contain ssl parameters e.g.
    `amqps://user:pass@host//?ca_certs=ca.pem&certfile=crt.pem&keyfile=key.pem`

    :param client_properties: add custom client capability.
    :param url:
        RFC3986_ formatted broker address. When :class:`None`
        will be used keyword arguments.
    :param host: hostname of the broker
    :param port: broker port 5672 by default
    :param login: username string. `'guest'` by default.
    :param password: password string. `'guest'` by default.
    :param virtualhost: virtualhost parameter. `'/'` by default
    :param ssl: use SSL for connection. Should be used with addition kwargs.
    :param ssl_options: A dict of values for the SSL connection.
    :param timeout: connection timeout in seconds
    :param loop:
        Event loop (:func:`asyncio.get_event_loop()` when :class:`None`)
    :param connection_class: Factory of a new connection
    :param kwargs: addition parameters which will be passed to the connection.
    :return: :class:`aio_pika.connection.Connection`

    .. _RFC3986: https://goo.gl/MzgYAs
    .. _official Python documentation: https://goo.gl/pty9xA


    """

    if url is None:
        kw = kwargs
        kw.update(ssl_options or {})

        url = URL.build(
            scheme="amqps" if ssl else "amqp",
            host=host,
            port=port,
            user=login,
            password=password,
            # yarl >= 1.3.0 requires path beginning with slash
            path="/" + virtualhost,
            query=kw,
        )

    connection = connection_class(url, loop=loop)

    await connection.connect(
        timeout=timeout,
        client_properties=client_properties,
        loop=loop,
    )
    return connection
Пример #50
0
async def connect(url: str = None,
                  *,
                  host: str = 'localhost',
                  port: int = 5672,
                  login: str = 'guest',
                  password: str = 'guest',
                  virtualhost: str = '/',
                  ssl: bool = False,
                  loop: asyncio.AbstractEventLoop = None,
                  ssl_options: dict = None,
                  connection_class: Type[Connection] = Connection,
                  **kwargs) -> Connection:
    """ Make connection to the broker.

    Example:

    .. code-block:: python

        import aio_pika

        async def main():
            connection = await aio_pika.connect(
                "amqp://*****:*****@127.0.0.1/"
            )

    Connect to localhost with default credentials:

    .. code-block:: python

        import aio_pika

        async def main():
            connection = await aio_pika.connect()

    .. note::

        The available keys for ssl_options parameter are:
            * cert_reqs
            * certfile
            * keyfile
            * ssl_version

        For an information on what the ssl_options can be set to reference the
        `official Python documentation`_ .

    URL string might be contain ssl parameters e.g.
    `amqps://user:pass@host//?ca_certs=ca.pem&certfile=crt.pem&keyfile=key.pem`

    :param url:
        RFC3986_ formatted broker address. When :class:`None`
        will be used keyword arguments.
    :param host: hostname of the broker
    :param port: broker port 5672 by default
    :param login:
        username string. `'guest'` by default. Provide empty string
        for pika.credentials.ExternalCredentials usage.
    :param password: password string. `'guest'` by default.
    :param virtualhost: virtualhost parameter. `'/'` by default
    :param ssl:
        use SSL for connection. Should be used with addition kwargs.
        See `pika documentation`_ for more info.
    :param ssl_options: A dict of values for the SSL connection.
    :param loop:
        Event loop (:func:`asyncio.get_event_loop()` when :class:`None`)
    :param connection_class: Factory of a new connection
    :param kwargs:
        addition parameters which will be passed to the pika connection.
    :return: :class:`aio_pika.connection.Connection`

    .. _RFC3986: https://goo.gl/MzgYAs
    .. _pika documentation: https://goo.gl/TdVuZ9
    .. _official Python documentation: https://goo.gl/pty9xA


    """

    if url is None:
        kw = kwargs
        kw.update(ssl_options or {})

        url = URL.build(
            scheme='amqps' if ssl else 'amqp',
            host=host,
            port=port,
            user=login,
            password=password,
            # yarl >= 1.3.0 requires path beginning with slash
            path="/" + virtualhost,
            query=kw)

    connection = connection_class(url, loop=loop)
    await connection.connect()
    return connection
Пример #51
0
def _make_server_creators(handler, *, loop, ssl_context, host, port, path,
                          sock, backlog):

    scheme = 'https' if ssl_context else 'http'
    base_url = URL.build(scheme=scheme, host='localhost', port=port)

    if path is None:
        paths = ()
    elif isinstance(path, (str, bytes, bytearray, memoryview))\
            or not isinstance(path, Iterable):
        paths = (path, )
    else:
        paths = path

    if sock is None:
        socks = ()
    elif not isinstance(sock, Iterable):
        socks = (sock, )
    else:
        socks = sock

    if host is None:
        if (paths or socks) and not port:
            hosts = ()
        else:
            hosts = ("0.0.0.0", )
    elif isinstance(host, (str, bytes, bytearray, memoryview))\
            or not isinstance(host, Iterable):
        hosts = (host, )
    else:
        hosts = host

    if hosts and port is None:
        port = 8443 if ssl_context else 8080

    server_creations = []
    uris = [str(base_url.with_host(host).with_port(port)) for host in hosts]
    if hosts:
        # Multiple hosts bound to same server is available in most loop
        # implementations, but only send multiple if we have multiple.
        host_binding = hosts[0] if len(hosts) == 1 else hosts
        server_creations.append(
            loop.create_server(handler,
                               host_binding,
                               port,
                               ssl=ssl_context,
                               backlog=backlog))
    for path in paths:
        # Most loop implementations don't support multiple paths bound in same
        # server, so create a server for each.
        server_creations.append(
            loop.create_unix_server(handler,
                                    path,
                                    ssl=ssl_context,
                                    backlog=backlog))
        uris.append('{}://unix:{}:'.format(scheme, path))

        # Clean up prior socket path if stale and not abstract.
        # CPython 3.5.3+'s event loop already does this. See
        # https://github.com/python/asyncio/issues/425
        if path[0] not in (0, '\x00'):  # pragma: no branch
            try:
                if stat.S_ISSOCK(os.stat(path).st_mode):
                    os.remove(path)
            except FileNotFoundError:
                pass
    for sock in socks:
        server_creations.append(
            loop.create_server(handler,
                               sock=sock,
                               ssl=ssl_context,
                               backlog=backlog))

        if hasattr(socket, 'AF_UNIX') and sock.family == socket.AF_UNIX:
            uris.append('{}://unix:{}:'.format(scheme, sock.getsockname()))
        else:
            host, port = sock.getsockname()[:2]
            uris.append(str(base_url.with_host(host).with_port(port)))
    return server_creations, uris
Пример #52
0
    async def _request(
        self,
        uri: str,
        *,
        method: str = METH_GET,
        params: Mapping[str, str] | None = None,
    ) -> dict[str, Any]:
        """Handle a request to the Garages Amsterdam API.

        Args:
            uri: Request URI, without '/', for example, 'status'
            method: HTTP method to use, for example, 'GET'
            params: Extra options to improve or limit the response.

        Returns:
            A Python dictionary (text) with the response from
            the Garages Amsterdam API.

        Raises:
            GaragesAmsterdamConnectionError: An error occurred while
                communicating with the Garages Amsterdam API.
            GaragesAmsterdamError: Received an unexpected response from
                the Garages Amsterdam API.
        """
        version = metadata.version(__package__)
        url = URL.build(scheme="http",
                        host="opd.it-t.nl",
                        path="/data/amsterdam/").join(URL(uri))

        headers = {
            "Accept": "application/json, text/plain",
            "User-Agent": f"PythonGaragesAmsterdam/{version}",
        }

        if self.session is None:
            self.session = ClientSession()
            self._close_session = True

        try:
            async with async_timeout.timeout(self.request_timeout):
                response = await self.session.request(
                    method,
                    url,
                    params=params,
                    headers=headers,
                    ssl=False,
                )
                response.raise_for_status()
        except asyncio.TimeoutError as exception:
            raise GaragesAmsterdamConnectionError(
                "Timeout occurred while connecting to the Garages Amsterdam API.",
            ) from exception
        except (ClientError, ClientResponseError) as exception:
            raise GaragesAmsterdamConnectionError(
                "Error occurred while communicating with the Garages Amsterdam API."
            ) from exception

        content_type = response.headers.get("Content-Type", "")
        if "text/plain" not in content_type:
            text = await response.text()
            raise GaragesAmsterdamError(
                "Unexpected response from the Garages Amsterdam API",
                {
                    "Content-Type": content_type,
                    "response": text
                },
            )

        return await response.text()
Пример #53
0
 def url_for(self) -> URL:  # type: ignore
     return URL.build(path=self._path, encoded=True)
Пример #54
0
 def url(self):
     return str(
         URL.build(scheme=self['protocol'],
                   host=self['host'],
                   port=self['port'],
                   path=self['path']))
Пример #55
0
 def __init__(self, prefix: str, *, name: Optional[str] = None) -> None:
     assert not prefix or prefix.startswith('/'), prefix
     assert prefix in ('', '/') or not prefix.endswith('/'), prefix
     super().__init__(name=name)
     self._prefix = URL.build(path=prefix).raw_path
Пример #56
0
    def parse_message(self, lines: List[bytes]) -> RawRequestMessage:
        # request line
        line = lines[0].decode("utf-8", "surrogateescape")
        try:
            method, path, version = line.split(None, 2)
        except ValueError:
            raise BadStatusLine(line) from None

        if len(path) > self.max_line_size:
            raise LineTooLong("Status line is too long",
                              str(self.max_line_size), str(len(path)))

        path_part, _hash_separator, url_fragment = path.partition("#")
        path_part, _question_mark_separator, qs_part = path_part.partition("?")

        # method
        if not METHRE.match(method):
            raise BadStatusLine(method)

        # version
        try:
            if version.startswith("HTTP/"):
                n1, n2 = version[5:].split(".", 1)
                version_o = HttpVersion(int(n1), int(n2))
            else:
                raise BadStatusLine(version)
        except Exception:
            raise BadStatusLine(version)

        # read headers
        (
            headers,
            raw_headers,
            close,
            compression,
            upgrade,
            chunked,
        ) = self.parse_headers(lines)

        if close is None:  # then the headers weren't set in the request
            if version_o <= HttpVersion10:  # HTTP 1.0 must asks to not close
                close = True
            else:  # HTTP 1.1 must ask to close.
                close = False

        return RawRequestMessage(
            method,
            path,
            version_o,
            headers,
            raw_headers,
            close,
            compression,
            upgrade,
            chunked,
            # NOTE: `yarl.URL.build()` is used to mimic what the Cython-based
            # NOTE: parser does, otherwise it results into the same
            # NOTE: HTTP Request-Line input producing different
            # NOTE: `yarl.URL()` objects
            URL.build(
                path=path_part,
                query_string=qs_part,
                fragment=url_fragment,
                encoded=True,
            ),
        )
Пример #57
0
 def name(self) -> str:
     scheme = 'https' if self._ssl_context else 'http'
     return str(URL.build(scheme=scheme, host=self._host, port=self._port))
Пример #58
0
async def main():
    logger.debug('start')
    address = os.getenv('ADDRESS')
    base_url = URL.build(scheme='http', host=address, port=8000)
    logger.debug('base url: %s', base_url)
    await game(client=Client(base_url))
Пример #59
0
 async def connect(self, host, port, url='/', protocol='ws', cookies=None):
     url = URL.build(scheme=protocol, host=host, port=port, path=url)
     await self.connect_url(url, cookies=cookies)
Пример #60
0
def test_build_without_arguments():
    u = URL.build()
    assert str(u) == ''