Skip to content

Commit

Permalink
Merge pull request #191 from unihd-cag/support-tables-and-vectors
Browse files Browse the repository at this point in the history
Add support for tables and vectors
  • Loading branch information
TM90 authored Aug 12, 2022
2 parents 4b4b39c + 32b2bff commit aab5056
Show file tree
Hide file tree
Showing 18 changed files with 579 additions and 123 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ env/*

**/__pycache__/*

skillbridge/server/python_server.py.log
skillbridge/server/python_server.log
*.log
skillbridge/client/definitions*
skillbridge/client/workspace.pyi

Expand Down
129 changes: 129 additions & 0 deletions docs/examples/tables_vectors.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
.. _tables_vectors.rst:

Tables and Vectors
==================

SKILL provides two data structures called ``table`` and ``vector``.
These are mapped similar to remote objects which means that the full content
of these data structures is never send to the python side unless requested.

The following examples assume that the skillbridge is running and a workspace
was opened like this:

.. code-block:: python
from skillbridge import Workspace, Symbol
ws = Workspace.open()
Tables
------

You can create a new table

.. code-block:: python
t = ws.make_table('MyTable')
# translates to makeTable("MyTable")
Or access an existing table (e.g. through a global variable)

.. code-block:: python
t = ws.__.existing_table
Now ``t`` behaves like a python dictionary.


>>> t['x'] = 1
>>> t[2] = 3
>>> t[Symbol('x')] = 4
>>> t['x']
1
>>> t[2]
3
>>> t[Symbol('x')]
4
>>> t['missing']
Traceback (most recent call last):
...
KeyError: 'missing'
>>> t.get('missing')
None
>>> dict(t)
{'x': 1, 2: 3, Symbol('x'): 4}

It is possible to provide a default value like this:

.. code-block:: python
t = ws.make_table('MyDefaultTable', None)
# translates to makeTable("MyDefaultTable" nil)
>>> t['missing']
None

.. warning::

The default value is evaluated on the SKILL side. That means only
values that can be safely send to SKILL are possible. Empty containers
and ``False`` are converted to ``None`` as usual.

>>> ws.make_table('nil', [])['missing'] # translates to makeTable("nil" nil)
None


As a convenience the attribute access to tables is an alias for item access with ``Symbol`` keys.

.. code-block:: python
t = ws.make_table('Table')
t.snake_case = 10
print(t[Symbol('snakeCase')]) # prints 10
t[Symbol('snakeCase')] = 20
print(t.snake_case) # prints 20
Vectors
-------

Vectors behave like python sequences with a somewhat fixed length. Note, that
vectors without a default value behave different from the usual python lists.

.. code-block:: python
v = ws.make_vector(10)
# translates to makeVector(10)
>>> len(v)
10
>>> v[0]
Traceback (most recent call last):
...
IndexError: 0
>>> list(v)
[]

You have to fill the "empty" slots of the vector before you can use them

>>> v[0] = 1
>>> v[2] = 3
>>> list(v)
[1]
>>> v[1] = 2
>>> list(v)
[1, 2, 3]

Vectors with a default value behave more like python sequences

.. code-block:: python
v = ws.make_vector(5, 0)
# translates to makeVector(5 0)
>>> list(v)
[0, 0, 0, 0, 0]
>>> v[0]
0
>>> v[0] = 10
>>> list(v)
[10, 0, 0, 0, 0]
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = skillbridge
version = dev
version = 1dev
author = Niels Buwen
author_email = [email protected]
maintainer = Tobias Markus
Expand Down
5 changes: 5 additions & 0 deletions skillbridge/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .client.functions import FunctionCollection, keys
from .client.globals import Globals, GlobalVar
from .client.hints import Function, Key, SkillCode, SkillList, SkillTuple, Symbol
from .client.objects import LazyList, RemoteObject, RemoteTable, RemoteVector
from .client.translator import ParseError
from .client.var import Var
from .client.workspace import Workspace, current_workspace
Expand All @@ -25,6 +26,10 @@
'loop_var_j',
'Globals',
'GlobalVar',
'RemoteTable',
'RemoteVector',
'RemoteObject',
'LazyList',
]

loop_var = Var('i')
Expand Down
6 changes: 3 additions & 3 deletions skillbridge/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def print_skill_script_location() -> None:
print(f'load("{escaped}")')


def deprecated_command() -> None:
def deprecated_command() -> None: # pragma: no cover
print("This command is deprecated")
print("It is no longer necessary to export function definitions")
print("You don't have to do anything")
Expand Down Expand Up @@ -81,9 +81,9 @@ def main() -> None:
sub_parser, func = commands[args.command]
try:
func()
except RuntimeError as e:
except RuntimeError as e: # pragma: no cover
sub_parser.error(str(e))


if __name__ == '__main__':
if __name__ == '__main__': # pragma: no cover
main()
10 changes: 5 additions & 5 deletions skillbridge/client/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ def __init__(self, max_transmission_length: int):
self._max_transmission_length = max_transmission_length

def send(self, data: str) -> str:
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def close(self) -> None:
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def flush(self) -> None:
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def try_repair(self) -> Any:
raise NotImplementedError
raise NotImplementedError # pragma: no cover

@property
def max_transmission_length(self) -> int:
Expand Down Expand Up @@ -80,7 +80,7 @@ def __init__(self, address: Any):

@staticmethod
def create_address(id_: Any) -> Any:
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def start(self) -> socket:
sock = self.create_socket()
Expand Down
12 changes: 5 additions & 7 deletions skillbridge/client/hints.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import TYPE_CHECKING, Any, Callable, Dict, List, NamedTuple, NewType, Set, Tuple, Union
from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, NewType, Set, Tuple, Union

if TYPE_CHECKING:
if TYPE_CHECKING: # pragma: no cover
from typing_extensions import Protocol
else:

Expand All @@ -15,11 +15,11 @@ class Protocol:
'SkillComponent',
'SkillCode',
'Skill',
'Replicator',
'Definition',
'Function',
'SkillTuple',
'SkillList',
'SupportsReprSkill',
]

Number = Union[int, float]
Expand All @@ -37,11 +37,11 @@ class Function(NamedTuple):


class SupportsReprSkill(Protocol):
def __repr_skill__(self) -> SkillCode:
def __repr_skill__(self) -> SkillCode: # pragma: no cover
...


if TYPE_CHECKING:
if TYPE_CHECKING: # pragma: no cover
from .var import Var

Skill = Union[
Expand All @@ -50,8 +50,6 @@ def __repr_skill__(self) -> SkillCode:
else:
Skill = Any

Replicator = Callable[[str], Skill]


class SkillList(List[Skill]):
pass
Expand Down
Loading

0 comments on commit aab5056

Please sign in to comment.