Skip to content

Commit

Permalink
Merge pull request #85 from vkottler/dev/type-system
Browse files Browse the repository at this point in the history
Add initial type system
  • Loading branch information
vkottler authored Aug 27, 2023
2 parents c10858a + c13e430 commit f395211
Show file tree
Hide file tree
Showing 36 changed files with 796 additions and 64 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
- run: |
mk python-release owner=vkottler \
repo=runtimepy version=1.7.4
repo=runtimepy version=2.0.0
if: |
matrix.python-version == '3.11'
&& matrix.system == 'ubuntu-latest'
Expand Down
1 change: 1 addition & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[DESIGN]
max-args=7
max-attributes=12
max-parents=8

[MESSAGES CONTROL]
disable=too-few-public-methods
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
=====================================
generator=datazen
version=3.1.2
hash=2ef9727ee775cc1db5301385b5959bd0
hash=31bf81f7cf74ce38be9e121deda89fbe
=====================================
-->

# runtimepy ([1.7.4](https://pypi.org/project/runtimepy/))
# runtimepy ([2.0.0](https://pypi.org/project/runtimepy/))

[![python](https://img.shields.io/pypi/pyversions/runtimepy.svg)](https://pypi.org/project/runtimepy/)
![Build Status](https://github.com/vkottler/runtimepy/workflows/Python%20Package/badge.svg)
Expand Down
6 changes: 3 additions & 3 deletions local/variables/package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
major: 1
minor: 7
patch: 4
major: 2
minor: 0
patch: 0
entry: runtimepy
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta:__legacy__"

[project]
name = "runtimepy"
version = "1.7.4"
version = "2.0.0"
description = "A framework for implementing Python services."
readme = "README.md"
requires-python = ">=3.8"
Expand Down
4 changes: 2 additions & 2 deletions runtimepy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# =====================================
# generator=datazen
# version=3.1.2
# hash=548569c24ddae75778158fe4d0904de5
# hash=25c862b538abb92065ece95c39caae77
# =====================================

"""
Expand All @@ -10,4 +10,4 @@

DESCRIPTION = "A framework for implementing Python services."
PKG_NAME = "runtimepy"
VERSION = "1.7.4"
VERSION = "2.0.0"
11 changes: 8 additions & 3 deletions runtimepy/codec/protocol/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def __copy__(self: T) -> T:
def add_field(
self,
name: str,
kind: _Primitivelike,
kind: _Primitivelike = None,
enum: _RegistryKey = None,
track: bool = True,
) -> None:
Expand All @@ -134,11 +134,16 @@ def add_field(
ident = self._names.register_name(name)
assert ident is not None, f"Couldn't register field '{name}'!"

if enum is not None:
runtime_enum = self._enum_registry[enum]
self._enum_fields[name] = runtime_enum
kind = runtime_enum.primitive

assert kind is not None
new = _create(kind)

self.array.add(new)
self._regular_fields[name] = new
if enum is not None:
self._enum_fields[name] = self._enum_registry[enum]

if track:
self._build.append(FieldSpec(name, kind, enum))
Expand Down
79 changes: 79 additions & 0 deletions runtimepy/codec/system/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""
A basic type-system implementation.
"""

# built-in
from typing import Dict

# third-party
from vcorelib.namespace import CPP_DELIM, Namespace

# internal
from runtimepy.codec.protocol import Protocol
from runtimepy.enum import RuntimeEnum
from runtimepy.enum.registry import EnumRegistry
from runtimepy.primitives.byte_order import ByteOrder
from runtimepy.primitives.type import AnyPrimitiveType, PrimitiveTypes


class TypeSystem:
"""A class for managing a custom type system."""

def __init__(self, *namespace: str) -> None:
"""Initialize this instance."""

self.primitives: Dict[str, AnyPrimitiveType] = {}
self.custom: Dict[str, Protocol] = {}

global_namespace = Namespace(delim=CPP_DELIM)

# Register global names.
for name, kind in PrimitiveTypes.items():
self.primitives[global_namespace.namespace(name)] = kind

self.root_namespace = global_namespace.child(*namespace)

# Register enums.
self._enums = EnumRegistry()
self.runtime_enum(
"ByteOrder", ByteOrder.register_enum(self._enums, name="ByteOrder")
)

def register(self, name: str) -> Protocol:
"""Register a custom type."""

new_type = Protocol(self._enums)
name = self.root_namespace.namespace(name)
self.custom[name] = new_type
return new_type

def runtime_enum(self, name: str, enum: RuntimeEnum) -> bool:
"""Register an enumeration."""

name = self.root_namespace.namespace(name)

result = self._enums.register(name, enum)

assert name not in self.primitives, name
self.primitives[name] = PrimitiveTypes[enum.primitive]

return result

def enum(
self, name: str, items: Dict[str, int], primitive: str = "uint8"
) -> None:
"""Register an enumeration."""

self._enums.enum(name, "int", items=items, primitive=primitive)

def size(self, name: str) -> int:
"""Get the size of a named type."""

matches = list(self.root_namespace.search(pattern=name))
assert len(matches) == 1, f"Duplicate type names {name}: {matches}"
name = matches[0]

if name in self.primitives:
return self.primitives[name].size

return self.custom[name].array.size
4 changes: 4 additions & 0 deletions runtimepy/data/schemas/RuntimeEnum.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ properties:
type:
enum: [bool, int]

primitive:
enum: [int8, int16, int32, int64, uint8, uint16, uint32, uint64]
default: uint8

items:
type: object
additionalProperties: false
Expand Down
10 changes: 8 additions & 2 deletions runtimepy/enum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
from vcorelib.io.types import JsonObject as _JsonObject
from vcorelib.io.types import JsonValue as _JsonValue

# internal
from runtimepy.enum.type import EnumType as _EnumType
from runtimepy.mapping import BoolMappingData as _BoolMappingData
from runtimepy.mapping import IntMappingData as _IntMappingData

# internal
from runtimepy.registry.bool import BooleanRegistry as _BooleanRegistry
from runtimepy.registry.item import RegistryItem as _RegistryItem
from runtimepy.registry.name import NameRegistry as _NameRegistry
Expand Down Expand Up @@ -53,6 +54,7 @@ def init(self, data: _JsonObject) -> None:
super().init(data)

self.type = _EnumType.normalize(str(data["type"]))
self.primitive = str(data["primitive"])

# Use distinct storage attributes for each kind of underlying
# enumeration.
Expand All @@ -74,7 +76,11 @@ def init(self, data: _JsonObject) -> None:
def asdict(self) -> _JsonObject:
"""Obtain a dictionary representing this instance."""

result: _JsonObject = {"id": self.id, "type": str(self.type)}
result: _JsonObject = {
"id": self.id,
"type": str(self.type),
"primitive": self.primitive,
}
if self.is_integer:
result["items"] = _cast(_JsonValue, self.ints.asdict())
else:
Expand Down
3 changes: 2 additions & 1 deletion runtimepy/enum/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ def enum(
name: str,
kind: _EnumTypelike,
items: _EnumMappingData = None,
primitive: str = "uint8",
) -> _Optional[_RuntimeEnum]:
"""Create a new runtime enumeration."""

data: _JsonObject = {"type": _cast(str, kind)}
data: _JsonObject = {"type": _cast(str, kind), "primitive": primitive}
if items is not None:
data["items"] = items # type: ignore
return self.register_dict(name, data)
Expand Down
3 changes: 3 additions & 0 deletions runtimepy/net/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

# internal
from runtimepy.net.metrics import ConnectionMetrics
from runtimepy.primitives.byte_order import DEFAULT_BYTE_ORDER, ByteOrder

BinaryMessage = _Union[bytes, bytearray, memoryview]

Expand All @@ -27,6 +28,8 @@ class Connection(_LoggerMixin, _ABC):
uses_text_tx_queue = True
uses_binary_tx_queue = True

byte_order: ByteOrder = DEFAULT_BYTE_ORDER

def __init__(self, logger: _LoggerType) -> None:
"""Initialize this connection."""

Expand Down
34 changes: 34 additions & 0 deletions runtimepy/net/factories/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
from runtimepy.net.arbiter.tcp import TcpConnectionFactory
from runtimepy.net.arbiter.udp import UdpConnectionFactory
from runtimepy.net.arbiter.websocket import WebsocketConnectionFactory
from runtimepy.net.stream import (
EchoTcpMessageConnection,
EchoUdpMessageConnection,
TcpPrefixedMessageConnection,
UdpPrefixedMessageConnection,
)
from runtimepy.net.tcp import (
EchoTcpConnection,
NullTcpConnection,
Expand All @@ -27,10 +33,14 @@
"TcpConnection",
"TcpConnectionFactory",
"TcpEcho",
"TcpMessage",
"TcpMessageEcho",
"TcpNull",
"UdpConnection",
"UdpConnectionFactory",
"UdpEcho",
"UdpMessage",
"UdpMessageEcho",
"UdpNull",
"WebsocketConnection",
"WebsocketConnectionFactory",
Expand All @@ -45,6 +55,18 @@ class UdpEcho(UdpConnectionFactory[EchoUdpConnection]):
kind = EchoUdpConnection


class UdpMessage(UdpConnectionFactory[UdpPrefixedMessageConnection]):
"""UDP message-connection factory."""

kind = UdpPrefixedMessageConnection


class UdpMessageEcho(UdpConnectionFactory[EchoUdpMessageConnection]):
"""UDP echo-connection factory."""

kind = EchoUdpMessageConnection


class UdpNull(UdpConnectionFactory[NullUdpConnection]):
"""UDP null-connection factory."""

Expand All @@ -57,6 +79,18 @@ class TcpEcho(TcpConnectionFactory[EchoTcpConnection]):
kind = EchoTcpConnection


class TcpMessage(TcpConnectionFactory[TcpPrefixedMessageConnection]):
"""TCP message-connection factory."""

kind = TcpPrefixedMessageConnection


class TcpMessageEcho(TcpConnectionFactory[EchoTcpMessageConnection]):
"""TCP message-connection factory."""

kind = EchoTcpMessageConnection


class TcpNull(TcpConnectionFactory[NullTcpConnection]):
"""TCP null-connection factory."""

Expand Down
Loading

0 comments on commit f395211

Please sign in to comment.