Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Upgraded python and dependencies #460

Merged
merged 24 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: '3.9'
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/unittest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.9]
python-version: [3.11]

steps:
- uses: actions/checkout@v1
Expand Down
2 changes: 1 addition & 1 deletion .scrutinizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ checks:
duplicate_code: true
build:
environment:
python: 3.9.12
python: 3.11.8
postgresql: false
redis: false
dependencies:
Expand Down
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ python:
- "3.7"
- "3.8"
- "3.9"
- "3.11"
install:
- pip install --upgrade pip
- pip install -r requirements/dev.txt
Expand Down
4 changes: 2 additions & 2 deletions kytos/core/atcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def __init__(self):
if not self.server:
raise ValueError("server instance must be assigned before init")

def connection_made(self, transport):
def connection_made(self, transport: asyncio.Transport):
"""Handle new client connection, passing it to the controller.

Build a new Kytos `Connection` and send a ``kytos/core.connection.new``
Expand All @@ -130,7 +130,7 @@ def connection_made(self, transport):

LOG.info("New connection from %s:%s", addr, port)

self.connection = Connection(addr, port, socket)
self.connection = Connection(addr, port, socket, transport)

# This allows someone to inherit from KytosServer and start a server
# on another port to handle a different protocol.
Expand Down
21 changes: 15 additions & 6 deletions kytos/core/connection.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Module with main classes related to Connections."""
import logging
from asyncio import Transport, trsock
from enum import Enum
from errno import EBADF, ENOTCONN
from socket import SHUT_RDWR
from socket import error as SocketError

__all__ = ('Connection', 'ConnectionProtocol', 'ConnectionState')

Expand Down Expand Up @@ -33,19 +33,28 @@ def __init__(self, name=None, version=None, state=None):
class Connection:
"""Connection class to abstract a network connections."""

def __init__(self, address, port, socket, switch=None):
def __init__(
self,
address: str,
port: int,
socket: trsock.TransportSocket,
transport: Transport,
switch=None
):
"""Assign parameters to instance variables.

Args:
address (|hw_address|): Source address.
port (int): Port number.
socket (socket): socket.
socket (TransportSocket): socket.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

socket docstring become obsolete, feel free to nuke it

Alopalao marked this conversation as resolved.
Show resolved Hide resolved
transport (Transport): transport.
switch (:class:`~.Switch`): switch with this connection.
"""
self.address = address
self.port = port
self.socket = socket
self.switch = switch
self.transport = transport
self.state = ConnectionState.NEW
self.protocol = ConnectionProtocol()
self.remaining_data = b''
Expand Down Expand Up @@ -90,8 +99,8 @@ def send(self, buffer):
"""
try:
if self.is_alive():
self.socket.sendall(buffer)
except (OSError, SocketError) as exception:
viniarck marked this conversation as resolved.
Show resolved Hide resolved
self.transport.write(buffer)
except (OSError, TypeError) as exception:
viniarck marked this conversation as resolved.
Show resolved Hide resolved
LOG.debug('Could not send packet. Exception: %s', exception)
self.close()
raise
Expand All @@ -103,7 +112,7 @@ def close(self):

try:
self.socket.shutdown(SHUT_RDWR)
self.socket.close()
self.transport.close()
viniarck marked this conversation as resolved.
Show resolved Hide resolved
self.socket = None
LOG.debug('Connection Closed: %s', self.id)
except OSError as exception:
Expand Down
7 changes: 3 additions & 4 deletions kytos/core/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
from importlib import reload as reload_module
from importlib.util import module_from_spec, spec_from_file_location
from pathlib import Path
from socket import error as SocketError

from pyof.foundation.exceptions import PackException

Expand All @@ -38,7 +37,7 @@
from kytos.core.auth import Auth
from kytos.core.buffers import KytosBuffers
from kytos.core.config import KytosConfig
from kytos.core.connection import ConnectionState
from kytos.core.connection import Connection, ConnectionState
from kytos.core.db import db_conn_wait
from kytos.core.dead_letter import DeadLetter
from kytos.core.events import KytosEvent
Expand Down Expand Up @@ -107,7 +106,7 @@ def __init__(self, options=None, loop: AbstractEventLoop = None):
#: This dict stores all connections between the controller and the
#: switches. The key for this dict is a tuple (ip, port). The content
#: is a Connection
self.connections = {}
self.connections: dict[tuple, Connection] = {}
#: dict: mapping of events and event listeners.
#:
#: The key of the dict is a KytosEvent (or a string that represent a
Expand Down Expand Up @@ -626,7 +625,7 @@ async def msg_out_event_handler(self):
message.header.xid,
packet.hex())
self.notify_listeners(triggered_event)
except (OSError, SocketError):
except (OSError, TypeError):
await self.publish_connection_error(triggered_event)
self.log.info("connection closed. Cannot send message")
except PackException as err:
Expand Down
41 changes: 16 additions & 25 deletions kytos/core/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@
from pathlib import Path
from threading import Thread

from openapi_core.spec import Spec
from openapi_core.spec.shortcuts import create_spec
from openapi_core.validation.request import openapi_request_validator
from openapi_core.validation.request.datatypes import RequestValidationResult
from openapi_spec_validator import validate_spec
from openapi_spec_validator.readers import read_from_filename
from openapi_core import OpenAPI
from openapi_core.contrib.starlette import StarletteOpenAPIRequest
from openapi_core.unmarshalling.request.datatypes import RequestUnmarshalResult

from kytos.core.apm import ElasticAPM
from kytos.core.config import KytosConfig
from kytos.core.rest_api import (AStarletteOpenAPIRequest, HTTPException,
Request, StarletteOpenAPIRequest,
from kytos.core.rest_api import (HTTPException, Request,
content_type_json_or_415, get_body)

__all__ = ['listen_to', 'now', 'run_on_thread', 'get_time']
Expand Down Expand Up @@ -351,28 +347,23 @@ def get_time(data=None):
return date.replace(tzinfo=timezone.utc)


def _read_from_filename(yml_file_path: Path) -> dict:
"""Read from yml filename."""
spec_dict, _ = read_from_filename(yml_file_path)
return spec_dict


def load_spec(yml_file_path: Path):
"""Load and validate spec object given a yml file path."""
spec_dict = _read_from_filename(yml_file_path)
validate_spec(spec_dict)
return create_spec(spec_dict)
return OpenAPI.from_file_path(yml_file_path)


def _request_validation_result_or_400(result: RequestValidationResult) -> None:
def _request_validation_result_or_400(result: RequestUnmarshalResult) -> None:
"""Request validation result or raise HTTP 400."""
if not result.errors:
return
error_response = (
"The request body contains invalid API data."
)
errors = result.errors[0]
if hasattr(errors, "schema_errors"):
if not errors.__cause__:
error_response = str(errors)
elif hasattr(errors.__cause__, "schema_errors"):
errors = errors.__cause__
schema_errors = errors.schema_errors[0]
error_log = {
"error_message": schema_errors.message,
Expand All @@ -388,12 +379,12 @@ def _request_validation_result_or_400(result: RequestValidationResult) -> None:
f" {'/'.join(map(str,schema_errors.path))}."
)
else:
error_response = str(errors)
error_response = str(errors.__cause__)
raise HTTPException(400, detail=error_response)


def validate_openapi_request(
spec: Spec, request: Request, loop: AbstractEventLoop
spec: OpenAPI, request: Request, loop: AbstractEventLoop
) -> bytes:
"""Validate a Request given an OpenAPI spec.

Expand All @@ -405,13 +396,13 @@ def validate_openapi_request(
if body:
content_type_json_or_415(request)
openapi_request = StarletteOpenAPIRequest(request, body)
result = openapi_request_validator.validate(spec, openapi_request)
result = spec.unmarshal_request(openapi_request)
_request_validation_result_or_400(result)
return body


async def avalidate_openapi_request(
spec: Spec,
spec: OpenAPI,
request: Request,
) -> bytes:
"""Async validate_openapi_request.
Expand All @@ -429,8 +420,8 @@ async def avalidate_openapi_request(
body = await request.body()
if body:
content_type_json_or_415(request)
openapi_request = AStarletteOpenAPIRequest(request, body)
result = openapi_request_validator.validate(spec, openapi_request)
openapi_request = StarletteOpenAPIRequest(request, body)
result = spec.unmarshal_request(openapi_request)
_request_validation_result_or_400(result)
return body

Expand Down
2 changes: 1 addition & 1 deletion kytos/core/kytosd.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def start_shell(controller=None):

# Avoiding sqlite3.ProgrammingError when trying to save command history
# on Kytos shutdown
cfg.HistoryAccessor.enabled = False
cfg.HistoryAccessor.enabled = True
viniarck marked this conversation as resolved.
Show resolved Hide resolved

ipshell = InteractiveShellEmbed(config=cfg,
banner1=banner1,
Expand Down
58 changes: 0 additions & 58 deletions kytos/core/rest_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,9 @@
from datetime import datetime
from typing import Any, Optional

from openapi_core.contrib.starlette import \
StarletteOpenAPIRequest as _StarletteOpenAPIRequest
from openapi_core.validation.request.datatypes import RequestParameters
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import JSONResponse as StarletteJSONResponse
from starlette.responses import Response

Request = Request
Response = Response
HTTPException = HTTPException


def _json_serializer(obj):
Expand Down Expand Up @@ -99,53 +91,3 @@ def render(self, content) -> bytes:
separators=(",", ":"),
default=_json_serializer,
).encode("utf-8")


# pylint: disable=super-init-not-called
class AStarletteOpenAPIRequest(_StarletteOpenAPIRequest):
"""Async StarletteOpenAPIRequest."""

def __init__(self, request: Request, body: bytes) -> None:
"""Constructor of AsycnStarletteOpenAPIRequest.

This constructor doesn't call super().__init__() to keep it async
"""
self.request = request
self.parameters = RequestParameters(
query=self.request.query_params,
header=self.request.headers,
cookie=self.request.cookies,
)
self._body = body

@property
def body(self) -> Optional[str]:
body = self._body
if body is None:
return None
return body.decode("utf-8")


# pylint: disable=super-init-not-called
class StarletteOpenAPIRequest(_StarletteOpenAPIRequest):
"""Sync StarletteOpenAPIRequest."""

def __init__(self, request: Request, body: bytes) -> None:
"""Constructor of AsycnStarletteOpenAPIRequest.

This constructor doesn't call super().__init__() to keep it async
"""
self.request = request
self.parameters = RequestParameters(
query=self.request.query_params,
header=self.request.headers,
cookie=self.request.cookies,
)
self._body = body

@property
def body(self) -> Optional[str]:
body = self._body
if body is None:
return None
return body.decode("utf-8")
viniarck marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading