Skip to content

Commit

Permalink
it's the ciiiiiircle of tyyyypes
Browse files Browse the repository at this point in the history
  • Loading branch information
glyph committed Jan 11, 2024
1 parent 88151eb commit 5c6a94b
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 40 deletions.
2 changes: 1 addition & 1 deletion src/twisted/internet/_sslverify.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from zope.interface import Interface, implementer

from OpenSSL import SSL, crypto
from OpenSSL._util import lib as pyOpenSSLlib # type: ignore[import]
from OpenSSL._util import lib as pyOpenSSLlib

import attr
from constantly import FlagConstant, Flags, NamedConstant, Names # type: ignore[import]
Expand Down
17 changes: 15 additions & 2 deletions src/twisted/internet/iocpreactor/tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
import errno
import socket
import struct
from typing import Optional
from typing import TYPE_CHECKING, Optional, Union

from zope.interface import classImplements, implementer

from twisted.internet import address, defer, error, interfaces, main
from twisted.internet.abstract import _LogOwner, isIPv6Address
from twisted.internet.address import IPv4Address, IPv6Address
from twisted.internet.interfaces import IProtocol
from twisted.internet.iocpreactor import abstract, iocpsupport as _iocp
from twisted.internet.iocpreactor.const import (
ERROR_CONNECTION_REFUSED,
Expand Down Expand Up @@ -42,6 +44,9 @@
else:
_startTLS = __startTLS

if TYPE_CHECKING:
# Circular import only to describe a type.
from twisted.internet.iocpreactor.reactor import IOCPReactor

# ConnectEx returns these. XXX: find out what it does for timeout
connectExErrors = {
Expand Down Expand Up @@ -345,7 +350,15 @@ class Server(Connection):

_tlsClientDefault = False

def __init__(self, sock, protocol, clientAddr, serverAddr, sessionno, reactor):
def __init__(
self,
sock: socket.socket,
protocol: IProtocol,
clientAddr: Union[IPv4Address, IPv6Address],
serverAddr: Union[IPv4Address, IPv6Address],
sessionno: int,
reactor: IOCPReactor,
):
"""
Server(sock, protocol, client, server, sessionno)
Expand Down
3 changes: 3 additions & 0 deletions src/twisted/internet/ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
throughout the documentation.
"""

from __future__ import annotations

from zope.interface import implementedBy, implementer, implementer_only

Expand Down Expand Up @@ -180,6 +181,8 @@ class Server(tcp.Server):
I am an SSL server.
"""

server: Port

def __init__(self, *args, **kwargs):
tcp.Server.__init__(self, *args, **kwargs)
self.startTLS(self.server.ctxFactory)
Expand Down
24 changes: 18 additions & 6 deletions src/twisted/internet/tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
End users shouldn't use this module directly - use the reactor APIs instead.
"""

import os
from __future__ import annotations

# System Imports
import os
import socket
import struct
import sys
from typing import Callable, ClassVar, List, Optional
from typing import Callable, ClassVar, List, Optional, Union

from zope.interface import Interface, implementer

Expand All @@ -24,6 +24,8 @@
from twisted.internet.interfaces import (
IHalfCloseableProtocol,
IListeningPort,
IProtocol,
IReactorTCP,
ISystemHandle,
ITCPTransport,
)
Expand Down Expand Up @@ -781,9 +783,19 @@ class Server(_TLSServerMixin, Connection):

_base = Connection

_addressType = address.IPv4Address

def __init__(self, sock, protocol, client, server, sessionno, reactor):
_addressType: Union[
type[address.IPv4Address], type[address.IPv6Address]
] = address.IPv4Address

def __init__(
self,
sock: socket.socket,
protocol: IProtocol,
client: tuple[object, ...],
server: Port,
sessionno: int,
reactor: IReactorTCP,
) -> None:
"""
Server(sock, protocol, client, server, sessionno)
Expand Down
65 changes: 41 additions & 24 deletions src/twisted/protocols/amp.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,18 @@ def trapZero(result):
from itertools import count
from struct import pack
from types import MethodType
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar, Union
from typing import (
Any,
Callable,
ClassVar,
Dict,
List,
Optional,
Tuple,
Type,
TypeVar,
Union,
)

from zope.interface import Interface, implementer

Expand Down Expand Up @@ -1686,41 +1697,46 @@ def toStringProto(self, inObject, proto):
return outString


_Self = TypeVar("_Self")


class _CommandMeta(type):
"""
Metaclass hack to establish reverse-mappings for 'errors' and
'fatalErrors' as class vars.
"""

def __new__(cls, name, bases, attrs):
def __new__(
cls: type[_Self], name: str, bases: tuple[type], attrs: dict[str, object]
) -> Type[Command]:
reverseErrors = attrs["reverseErrors"] = {}
er = attrs["allErrors"] = {}
if "commandName" not in attrs:
attrs["commandName"] = name.encode("ascii")
newtype = type.__new__(cls, name, bases, attrs)
newtype: Type[Command] = type.__new__(cls, name, bases, attrs) # type:ignore

if not isinstance(newtype.commandName, bytes):
raise TypeError(
"Command names must be byte strings, got: {!r}".format(
newtype.commandName
)
)
for name, _ in newtype.arguments:
if not isinstance(name, bytes):
raise TypeError(f"Argument names must be byte strings, got: {name!r}")
for name, _ in newtype.response:
if not isinstance(name, bytes):
raise TypeError(f"Response names must be byte strings, got: {name!r}")
for bname, _ in newtype.arguments:
if not isinstance(bname, bytes):
raise TypeError(f"Argument names must be byte strings, got: {bname!r}")
for bname, _ in newtype.response:
if not isinstance(bname, bytes):
raise TypeError(f"Response names must be byte strings, got: {bname!r}")

errors: Dict[Type[Exception], bytes] = {}
fatalErrors: Dict[Type[Exception], bytes] = {}
accumulateClassDict(newtype, "errors", errors)
accumulateClassDict(newtype, "fatalErrors", fatalErrors)

if not isinstance(newtype.errors, dict):
newtype.errors = dict(newtype.errors)
newtype.errors = dict(newtype.errors) # type:ignore[unreachable]
if not isinstance(newtype.fatalErrors, dict):
newtype.fatalErrors = dict(newtype.fatalErrors)
newtype.fatalErrors = dict(newtype.fatalErrors) # type:ignore[unreachable]

for v, k in errors.items():
reverseErrors[k] = v
Expand All @@ -1729,13 +1745,13 @@ def __new__(cls, name, bases, attrs):
reverseErrors[k] = v
er[v] = k

for _, name in newtype.errors.items():
if not isinstance(name, bytes):
raise TypeError(f"Error names must be byte strings, got: {name!r}")
for _, name in newtype.fatalErrors.items():
if not isinstance(name, bytes):
for _, bname in newtype.errors.items():
if not isinstance(bname, bytes):
raise TypeError(f"Error names must be byte strings, got: {bname!r}")
for _, bname in newtype.fatalErrors.items():
if not isinstance(bname, bytes):
raise TypeError(
f"Fatal error names must be byte strings, got: {name!r}"
f"Fatal error names must be byte strings, got: {bname!r}"
)

return newtype
Expand Down Expand Up @@ -1784,14 +1800,15 @@ class Command(metaclass=_CommandMeta):
want one.
"""

arguments: List[Tuple[bytes, Argument]] = []
response: List[Tuple[bytes, Argument]] = []
extra: List[Any] = []
errors: Dict[Type[Exception], bytes] = {}
fatalErrors: Dict[Type[Exception], bytes] = {}
commandName: ClassVar[bytes]
arguments: ClassVar[List[Tuple[bytes, Argument]]] = []
response: ClassVar[List[Tuple[bytes, Argument]]] = []
extra: ClassVar[List[Any]] = []
errors: ClassVar[Dict[Type[Exception], bytes]] = {}
fatalErrors: ClassVar[Dict[Type[Exception], bytes]] = {}

commandType: "Union[Type[Command], Type[Box]]" = Box
responseType: Type[AmpBox] = Box
commandType: "ClassVar[Union[Type[Command], Type[Box]]]" = Box
responseType: ClassVar[Type[AmpBox]] = Box

requiresAnswer = True

Expand Down
9 changes: 7 additions & 2 deletions src/twisted/python/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
@type theSystemPath: L{PythonPath}
"""

from __future__ import annotations

import inspect
import sys
Expand Down Expand Up @@ -251,7 +252,9 @@ class PythonAttribute:
this class.
"""

def __init__(self, name, onObject, loaded, pythonValue):
def __init__(
self, name: str, onObject: PythonAttribute, loaded: bool, pythonValue: object
) -> None:
"""
Create a PythonAttribute. This is a private constructor. Do not construct
me directly, use PythonModule.iterAttributes.
Expand Down Expand Up @@ -306,7 +309,9 @@ class PythonModule(_ModuleIteratorHelper):
from.
"""

def __init__(self, name, filePath, pathEntry):
def __init__(
self, name: str, filePath: FilePath[str], pathEntry: PathEntry
) -> None:
"""
Create a PythonModule. Do not construct this directly, instead inspect a
PythonPath or other PythonModule instances.
Expand Down
12 changes: 7 additions & 5 deletions src/twisted/test/test_amp.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import datetime
import decimal
from typing import Dict, Type, TypeVar
from typing import ClassVar, Dict, Type, TypeVar
from unittest import skipIf

from zope.interface import implementer
Expand Down Expand Up @@ -136,9 +136,9 @@ class Hello(amp.Command):

response = [(b"hello", amp.String()), (b"print", amp.Unicode(optional=True))]

errors: Dict[Type[Exception], bytes] = {UnfriendlyGreeting: b"UNFRIENDLY"}
errors: ClassVar[Dict[Type[Exception], bytes]] = {UnfriendlyGreeting: b"UNFRIENDLY"}

fatalErrors: Dict[Type[Exception], bytes] = {DeathThreat: b"DEAD"}
fatalErrors: ClassVar[Dict[Type[Exception], bytes]] = {DeathThreat: b"DEAD"}


class NoAnswerHello(Hello):
Expand Down Expand Up @@ -2136,7 +2136,9 @@ class BaseCommand(amp.Command):
This provides a command that will be subclassed.
"""

errors: Dict[Type[Exception], bytes] = {InheritedError: b"INHERITED_ERROR"}
errors: ClassVar[Dict[Type[Exception], bytes]] = {
InheritedError: b"INHERITED_ERROR"
}


class InheritedCommand(BaseCommand):
Expand All @@ -2153,7 +2155,7 @@ class AddErrorsCommand(BaseCommand):
"""

arguments = [(b"other", amp.Boolean())]
errors: Dict[Type[Exception], bytes] = {
errors: ClassVar[Dict[Type[Exception], bytes]] = {
OtherInheritedError: b"OTHER_INHERITED_ERROR"
}

Expand Down

0 comments on commit 5c6a94b

Please sign in to comment.