From d35e21be29b31c5494dac4da16da6d6686e00b4d Mon Sep 17 00:00:00 2001
From: Matthias Koefferlein
Date: Sun, 9 Aug 2026 16:43:11 +0200
Subject: [PATCH] Rewriting Python samples to klayout.* modules, fixing some
bugs and flaws in the samples
---
.../pcell_declaration_helper.lym | 12 ++--
src/doc/doc/programming/events.xml | 14 ++---
src/doc/doc/programming/introduction.xml | 5 +-
src/doc/doc/programming/python.xml | 44 +++++++++-----
src/lay/lay/built_in_pymacros/qt_helper.lym | 10 +++-
.../drag_box_sample_python.lym | 60 ++++++++++---------
.../editor_hooks_sample_python.lym | 21 +++----
.../lay/macro_templates/new_python_macro.lym | 3 +-
src/lay/lay/macro_templates/pcell.lym | 7 +++
src/lay/lay/macro_templates/pcell_python.lym | 23 ++++---
.../macro_templates/pcell_sample_python.lym | 20 +++----
.../macro_templates/qt_designer_python.lym | 10 ++--
.../lay/macro_templates/qt_dialog_python.lym | 20 ++++---
.../lay/macro_templates/qt_server_python.lym | 30 +++++-----
.../via_pcell_sample_python.lym | 34 +++++------
15 files changed, 177 insertions(+), 136 deletions(-)
diff --git a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym
index 8b763e6e7..c399e192b 100644
--- a/src/db/db/built-in-pymacros/pcell_declaration_helper.lym
+++ b/src/db/db/built-in-pymacros/pcell_declaration_helper.lym
@@ -8,10 +8,6 @@
@class [db] PCellDeclarationHelper < PCellDeclaration
@brief A helper class to simplify the declaration of a PCell (Python version)
-NOTE: in the following, "pya" can be replaced by "klayout.db" which is
-the canonical module and the preferred way of addressing the
-external Python library.
-
This class provides adds some convenience to the PCell declaration based
on PCellDeclaration. PCellDeclaration is a C++ object which is less
convenient to use than a Ruby-based approach. In particular this class
@@ -22,10 +18,10 @@ The basic usage of this class is the following:
@code
-import pya
+import klayout.db as kdb
# Derive your PCell from PCellDeclarationHelper
-class MyPCell(pya.PCellDeclarationHelper):
+class MyPCell(kdb.PCellDeclarationHelper):
def __init__(self):
@@ -35,7 +31,7 @@ class MyPCell(pya.PCellDeclarationHelper):
# your initialization: add parameters with name, type, description and
# optional other values
self.param("p", self.TypeInt, "The parameter", default = 1)
- self.param("l", self.TypeLayer, "The layer", default = pya.LayerInfo(1, 0))
+ self.param("l", self.TypeLayer, "The layer", default = kdb.LayerInfo(1, 0))
# add other parameters ..
# reimplement display_text_impl
@@ -71,7 +67,7 @@ we can access the layer index with the "l_layer" method:
@code
def produce_impl(self):
- cell.shapes(self.l_layer).insert(pya.Box(0, 0, self.p*100, self.p*200))
+ cell.shapes(self.l_layer).insert(kdb.Box(0, 0, self.p*100, self.p*200))
@/code
Again in this sample, we used "p" to access the parameter "p".
diff --git a/src/doc/doc/programming/events.xml b/src/doc/doc/programming/events.xml
index 044ea331b..13d82fb91 100644
--- a/src/doc/doc/programming/events.xml
+++ b/src/doc/doc/programming/events.xml
@@ -85,8 +85,7 @@ end
The Python version is this:
-
-from pya import BrowserSource, BrowserDialog
+ from klayout.lay import BrowserSource, BrowserDialog
class MyBrowserSource(BrowserSource):
def get(self, url):
@@ -157,8 +156,7 @@ end
The Python version is:
-
-from pya import Action, MessageBox, Application
+ from klayout.lay import Action, MessageBox, Application
def on_triggered():
MessageBox.info("A message", "The action was triggered", MessageBox.Ok)
@@ -235,8 +233,8 @@ end
The Python version is:
-
-from pya import QDialog, QVBoxLayout, QLineEdit, QLabel, Application
+ from klayout.lay import Application
+from klayout.QtWidgets import QDialog, QVBoxLayout, QLineEdit, QLabel
dialog = QDialog(Application.instance().main_window())
layout = QVBoxLayout(dialog)
@@ -285,8 +283,8 @@ end
with the Python version:
-
-from pya import QDialog, QVBoxLayout, QLineEdit, QLabel, Application
+ from klayout.lay import Application
+from klayout.QtWidgets import QDialog, QVBoxLayout, QLineEdit, QLabel
dialog = QDialog(Application.instance().main_window())
layout = QVBoxLayout(dialog)
diff --git a/src/doc/doc/programming/introduction.xml b/src/doc/doc/programming/introduction.xml
index dcc1fbd03..b91dbaade 100644
--- a/src/doc/doc/programming/introduction.xml
+++ b/src/doc/doc/programming/introduction.xml
@@ -9,16 +9,17 @@
+
- This chapter is about programming extensions for KLayout using the integrated Ruby API (RBA) or Python API (pya).
+ This chapter is about programming extensions for KLayout using the integrated Ruby API (RBA) or Python API (klayout.db, klayout.layer etc.).
To use RBA scripts, KLayout must be compiled with the Ruby interpreter. Check under "Help/About" whether
support is available. If there is, the "Build options" will include a "Ruby" or "Python" interpreter or both.
- RBA scripts require a Ruby interpreter. To use pya scripts, Python support must be included.
+ RBA scripts require a Ruby interpreter. To use Python scripts, Python support must be compiled in.
diff --git a/src/doc/doc/programming/python.xml b/src/doc/doc/programming/python.xml
index 9389c848b..d62aac1a0 100644
--- a/src/doc/doc/programming/python.xml
+++ b/src/doc/doc/programming/python.xml
@@ -7,6 +7,7 @@
+
@@ -55,8 +56,11 @@
Apart from a few specialities and the different language of course, Python macros do not look much different from Ruby
- macros. Ruby's "RBA" namespace is "pya" for Python (lowercase to conform with PEP-8). The
- class and methods names are the same with very few exceptions and the documentation can be
+ macros. Ruby's "RBA" namespace is "klayout" for Python (lowercase to conform with PEP-8).
+ The "klayout" module has a number of submodules like "klayout.db", "klayout.lay" etc.
+ The old combined Python module "pya" is still available, but deprecated in favor of
+ aligning code with the standalone "klayout" Python module.
+ The class and methods names are the same with very few exceptions and the documentation can be
used for Python too. Where necessary, a special remark is made regarding the Python implementation.
@@ -68,12 +72,12 @@
# Python version:
-import pya
+import klayout.db as kdb
-layout = pya.Layout()
+layout = kdb.Layout()
top = layout.create_cell("TOP")
l1 = layout.layer(1, 0)
-top.shapes(l1).insert(pya.Box(0, 0, 1000, 2000))
+top.shapes(l1).insert(kdb.Box(0, 0, 1000, 2000))
layout.write("t.gds")
@@ -139,7 +143,12 @@ layout.write("t.gds")
- KLayout module:
- KLayout's module is "pya" (lowercase conforming to PEP 8).
+ KLayout's module is "klayout" (lowercase conforming to PEP 8).
+ It has a number of submodules: "db", "lay", "pex", "rdb", "tl" and optionally
+ "QtCore", "QtGui" etc.
+ The built-in documentation mentiones the module containing a specific class
+ at the top of the class documentation. For example, "Box" is present in the
+ "db" submodule - i.e. it is present in "klayout.db".
- Reserved names:
@@ -154,8 +163,9 @@ layout.write("t.gds")
Assignment methods (i.e. "Box#left=" are available as attributes. If there is a
read accessor method too, the attribute can be read and written. For example:
-
-box = pya.Box()
+ import klayout.db as kdb
+
+box = kdb.Box()
box.left = 10
box.right = box.right + 100
@@ -200,8 +210,9 @@ box.right = box.right + 100
- Iterators:
Iterator binding:
-
-edges = pya.Edges()
+ import klayout.db as kdb
+
+edges = kdb.Edges()
...
for edge in edges.each():
...
@@ -221,8 +232,10 @@ for edge in edges:
Most methods support keyword arguments, for example:
- # a 45 degree rotation
-t = pya.CplxTrans(rot = 45)
+ import klayout.db as kdb
+
+# a 45 degree rotation
+t = kdb.CplxTrans(rot = 45)
Exceptions are some built-in methods like "assign". Keyword arguments can be used
@@ -257,10 +270,11 @@ t = pya.CplxTrans(rot = 45)
- Deep copies:
- Deep copies of pya objects can be made with dup()
+ Deep copies of klayout objects can be made with dup()
-
-box = pya.Box(10, 20, 110, 220)
+ import klayout.db as kdb
+
+box = kdb.Box(10, 20, 110, 220)
copy_box = box.dup()
diff --git a/src/lay/lay/built_in_pymacros/qt_helper.lym b/src/lay/lay/built_in_pymacros/qt_helper.lym
index 9dcb0a086..e56f7b4bf 100644
--- a/src/lay/lay/built_in_pymacros/qt_helper.lym
+++ b/src/lay/lay/built_in_pymacros/qt_helper.lym
@@ -9,7 +9,8 @@
python
- import pya
+
+import pya
def _qt_signal(s):
"""
@@ -39,9 +40,16 @@ def _getattr_with_child_objects(s, n):
# If Qt binding is enabled, install the new getattr function.
# Also install the qt_signal and qt_slot functions which go into the pya module.
if "QObject_Native" in pya.__dict__:
+
pya.QObject_Native.__getattr__ = _getattr_with_child_objects
pya.__dict__["qt_signal"] = _qt_signal
pya.__dict__["qt_slot"] = _qt_slot
+ # Do the same for klayout.QtCore
+ import klayout.QtCore
+ klayout.QtCore.QObject_Native.__getattr__ = _getattr_with_child_objects
+ klayout.QtCore.__dict__["qt_signal"] = _qt_signal
+ klayout.QtCore.__dict__["qt_slot"] = _qt_slot
+
diff --git a/src/lay/lay/macro_templates/drag_box_sample_python.lym b/src/lay/lay/macro_templates/drag_box_sample_python.lym
index ffd328910..2463dbf4d 100644
--- a/src/lay/lay/macro_templates/drag_box_sample_python.lym
+++ b/src/lay/lay/macro_templates/drag_box_sample_python.lym
@@ -26,12 +26,16 @@
# Register this macro as "autorun" to enable the plugin
# on startup.
+from klayout.lay import EditorOptionsPage, ConfigPage, Plugin, PluginFactory, MainWindow, Marker
+from klayout.db import DBox, DPoint
+from klayout.QtWidgets import QGridLayout, QVBoxLayout, QHBoxLayout, QLabel, QSpinBox, QLineEdit
+
cfg_color = "drag-box-color"
cfg_width = "drag-box-width"
# The widget placed into the editor options dock
-class DragBoxEditorOptionsPage(pya.EditorOptionsPage):
+class DragBoxEditorOptionsPage(EditorOptionsPage):
"""
An option page providing a single entry box for configuring the line width
@@ -47,12 +51,12 @@ class DragBoxEditorOptionsPage(pya.EditorOptionsPage):
super(DragBoxEditorOptionsPage, self).__init__("Options", 1)
- layout2 = pya.QVBoxLayout(self)
- layout = pya.QHBoxLayout(self)
+ layout2 = QVBoxLayout(self)
+ layout = QHBoxLayout(self)
layout2.addLayout(layout)
- label = pya.QLabel("Line width", self)
+ label = QLabel("Line width", self)
layout.addWidget(label)
- self.spin_box = pya.QSpinBox(self)
+ self.spin_box = QSpinBox(self)
self.spin_box.setMinimum(1)
self.spin_box.setMaximum(16)
layout.addWidget(self.spin_box)
@@ -87,7 +91,7 @@ class DragBoxEditorOptionsPage(pya.EditorOptionsPage):
# The modal dialog page that appears when "Tab" is pressed
-class DragBoxFocusPage(pya.EditorOptionsPage):
+class DragBoxFocusPage(EditorOptionsPage):
"""
A (modal) option page, also called a "focus page". This page is
@@ -115,21 +119,21 @@ class DragBoxFocusPage(pya.EditorOptionsPage):
self.focus_page = True
self.modal_page = True
- self.box = pya.DBox()
- self.pfix = pya.DPoint()
+ self.box = DBox()
+ self.pfix = DPoint()
self.update_box = None
- layout = pya.QGridLayout(self)
+ layout = QGridLayout(self)
layout.setColumnStretch(1, 1)
- label = pya.QLabel("Width", self)
+ label = QLabel("Width", self)
layout.addWidget(label, 0, 0, 1, 1)
- self.le_width = pya.QLineEdit(self)
+ self.le_width = QLineEdit(self)
layout.addWidget(self.le_width, 0, 1, 1, 1)
- label = pya.QLabel("Height", self)
+ label = QLabel("Height", self)
layout.addWidget(label, 1, 0, 1, 1)
- self.le_height = pya.QLineEdit(self)
+ self.le_height = QLineEdit(self)
layout.addWidget(self.le_height, 1, 1, 1, 1)
layout.setRowStretch(2, 1)
@@ -175,11 +179,11 @@ class DragBoxFocusPage(pya.EditorOptionsPage):
# issue the event (call the handler) to inform the plugin of this change
if self.update_box is not None:
- self.update_box(pya.DBox(l, b, r, t))
+ self.update_box(DBox(l, b, r, t))
# The widget placed into the configuration page
-class DragBoxConfigPage(pya.ConfigPage):
+class DragBoxConfigPage(ConfigPage):
"""
A configuration page with a single entry box to change
@@ -197,10 +201,10 @@ class DragBoxConfigPage(pya.ConfigPage):
super(DragBoxConfigPage, self).__init__("Drag Box|Configure")
- layout = pya.QHBoxLayout(self)
- label = pya.QLabel("Color (hex, rrggbb)", self)
+ layout = QHBoxLayout(self)
+ label = QLabel("Color (hex, rrggbb)", self)
layout.addWidget(label)
- self.line_edit = pya.QLineEdit(self)
+ self.line_edit = QLineEdit(self)
layout.addWidget(self.line_edit)
layout.addStretch(1)
@@ -217,7 +221,7 @@ class DragBoxConfigPage(pya.ConfigPage):
"""
dispatcher.set_config(cfg_color, self.line_edit.text)
-class DragBoxPlugin(pya.Plugin):
+class DragBoxPlugin(Plugin):
"""
The custom plugin implementation.
@@ -275,14 +279,14 @@ class DragBoxPlugin(pya.Plugin):
self.marker = None
# reset to idle
self.ungrab_mouse()
- pya.MainWindow.instance().message("Box finished: " + str(self.box), 10000)
+ MainWindow.instance().message("Box finished: " + str(self.box), 10000)
def _update_marker(self):
"""
updates the marker with the current box
"""
if self.marker is None:
- self.marker = pya.Marker(self.view)
+ self.marker = Marker(self.view)
self._configure_marker()
self.marker.set(self.box)
@@ -339,7 +343,7 @@ class DragBoxPlugin(pya.Plugin):
plugin is activated - i.e. the mode is selected
"""
- pya.MainWindow.instance().message("Click on point to start dragging a box", 10000)
+ MainWindow.instance().message("Click on point to start dragging a box", 10000)
def deactivated(self):
@@ -349,7 +353,7 @@ class DragBoxPlugin(pya.Plugin):
"""
self._clear_marker()
- pya.MainWindow.instance().message("", 0)
+ MainWindow.instance().message("", 0)
def mouse_click_event(self, p, buttons, prio):
@@ -363,15 +367,15 @@ class DragBoxPlugin(pya.Plugin):
# stop dragging it and freeze the box
if self.marker is None:
p = self.snap2(p)
- self.box = pya.DBox(p, p)
+ self.box = DBox(p, p)
self.start_point = p
self._clear_marker()
self._update_marker()
self.grab_mouse()
- pya.MainWindow.instance().message("Drag the box and click again", 10000)
+ MainWindow.instance().message("Drag the box and click again", 10000)
else:
p = self.snap2(p, self.start_point, True, self.ac_from_buttons(buttons))
- self._update_box(pya.DBox(self.start_point, p))
+ self._update_box(DBox(self.start_point, p))
self._finish()
return True
return False
@@ -395,13 +399,13 @@ class DragBoxPlugin(pya.Plugin):
self.clear_mouse_cursors()
p = self.snap2(p, self.start_point, True, self.ac_from_buttons(buttons), visualize=True)
self.add_mouse_cursor(p)
- self.box = pya.DBox(self.start_point, p)
+ self.box = DBox(self.start_point, p)
self._update_marker()
# NOTE: we must not digest this event (i.e. return True)
# to allow the mouse tracker to receive the events as well
return False
-class DragBoxPluginFactory(pya.PluginFactory):
+class DragBoxPluginFactory(PluginFactory):
"""
Implements a "plugin factory".
diff --git a/src/lay/lay/macro_templates/editor_hooks_sample_python.lym b/src/lay/lay/macro_templates/editor_hooks_sample_python.lym
index ced2aa4a4..62a98a0c9 100644
--- a/src/lay/lay/macro_templates/editor_hooks_sample_python.lym
+++ b/src/lay/lay/macro_templates/editor_hooks_sample_python.lym
@@ -7,7 +7,8 @@
false
pymacros
python
- import pya
+ import klayout.db as kdb
+import klayout.lay as klay
"""
This demo installs editor hooks to indicate the forbidding regions around a shape
@@ -24,7 +25,7 @@ are drawn.
Space between instances: 0.4
"""
-class MyEditorHooks(pya.EditorHooks):
+class MyEditorHooks(klay.EditorHooks):
def __init__(self):
@@ -36,9 +37,9 @@ class MyEditorHooks(pya.EditorHooks):
self.space = 0.0
self.spaces = {
- pya.LayerInfo(1, 0): ( 0.2, pya.Region.Euclidian ),
- pya.LayerInfo(2, 0): ( 0.5, pya.Region.Projection ),
- pya.LayerInfo(3, 0): ( 1.0, pya.Region.Projection )
+ kdb.LayerInfo(1, 0): ( 0.2, kdb.Region.Euclidian ),
+ kdb.LayerInfo(2, 0): ( 0.5, kdb.Region.Projection ),
+ kdb.LayerInfo(3, 0): ( 1.0, kdb.Region.Projection )
}
self.instance_space = 0.4
@@ -61,12 +62,12 @@ class MyEditorHooks(pya.EditorHooks):
p = shape.polygon
if p is not None and p.num_points() < 100:
- r = pya.Region()
+ r = kdb.Region()
r.merged_semantics = (p.num_points() != 2)
r.insert(p)
r = r.drc_hull(self.metrics, self.space)
for pp in r.each():
- m = pya.Marker(self.view)
+ m = klay.Marker(self.view)
m.line_style = 2
m.vertex_size = 0
m.set_polygon(trans * pp)
@@ -74,7 +75,7 @@ class MyEditorHooks(pya.EditorHooks):
t = shape.text
if t is not None:
- m = pya.Marker(self.view)
+ m = klay.Marker(self.view)
m.set_box(trans * t.bbox().enlarged(self.space))
self.markers.append(m)
@@ -117,7 +118,7 @@ class MyEditorHooks(pya.EditorHooks):
self.markers = []
def create_instance(self, instance, trans):
- m = pya.Marker(self.view)
+ m = klay.Marker(self.view)
m.set_box(trans * instance.bbox().enlarged(self.instance_space / self.layout.dbu))
self.markers.append(m)
@@ -143,7 +144,7 @@ class MyEditorHooks(pya.EditorHooks):
if path.shape is None:
- m = pya.Marker(self.view)
+ m = klay.Marker(self.view)
m.set_box(trans * (applied * path.inst().bbox()).enlarged(self.instance_space / self.layout.dbu))
self.markers.append(m)
diff --git a/src/lay/lay/macro_templates/new_python_macro.lym b/src/lay/lay/macro_templates/new_python_macro.lym
index 54354d1bf..9e839f2e8 100644
--- a/src/lay/lay/macro_templates/new_python_macro.lym
+++ b/src/lay/lay/macro_templates/new_python_macro.lym
@@ -7,7 +7,8 @@
python
pymacro
- import pya
+ import klayout.db as kdb
+import klayout.lay as klay
# Enter your Python code here ..
diff --git a/src/lay/lay/macro_templates/pcell.lym b/src/lay/lay/macro_templates/pcell.lym
index eb89f8096..25633bd77 100644
--- a/src/lay/lay/macro_templates/pcell.lym
+++ b/src/lay/lay/macro_templates/pcell.lym
@@ -78,6 +78,13 @@ module PCellLibModule
# In lazy mode, the user has to acknowledge parameter changes before
# they are executed.
# end
+ #
+ # optional:
+ # def callback_impl(name)
+ # TODO: implement functionality to change user interface element
+ # states for PCell parameter editors based on certain events
+ # like value changes.
+ # end
end
diff --git a/src/lay/lay/macro_templates/pcell_python.lym b/src/lay/lay/macro_templates/pcell_python.lym
index 474f91a9a..29bc0710c 100644
--- a/src/lay/lay/macro_templates/pcell_python.lym
+++ b/src/lay/lay/macro_templates/pcell_python.lym
@@ -7,18 +7,15 @@
false
python
- import pya
+ import klayout.db as kdb
# PCell template
# This macro template provides the framework for a PCell library
-# It is recommended to put PCell code into namespaces.
-# TODO: change the module name
-
# The PCell declaration
# Each PCell must provide a declaration. It is recommended to use the PCell name as the class name.
# TODO: change the class name
-class PCell(pya.PCellDeclarationHelper):
+class PCell(kdb.PCellDeclarationHelper):
def __init__(self):
@@ -26,8 +23,8 @@ class PCell(pya.PCellDeclarationHelper):
super(PCell, self).__init__()
# declare the parameters
- # i.e. self.param("l", self.TypeLayer, "Layer", default = pya.LayerInfo(1, 0))
- # self.param("s", self.TypeShape, "", default = pya.DPoint(0, 0))
+ # i.e. self.param("l", self.TypeLayer, "Layer", default = kdb.LayerInfo(1, 0))
+ # self.param("s", self.TypeShape, "", default = kdb.DPoint(0, 0))
def display_text_impl(self):
# Provide a descriptive text for the cell
@@ -35,10 +32,12 @@ class PCell(pya.PCellDeclarationHelper):
def coerce_parameters_impl(self):
# TODO: use x to access parameter x and set_x to modify its value
+ pass
def produce_impl(self):
# TODO: produce the cell content
- # i.e. self.cell.shapes(self.l_layer).insert(pya.Polygon(...))
+ # i.e. self.cell.shapes(self.l_layer).insert(kdb.Polygon(...))
+ pass
# optional:
# def can_create_from_shape_impl(self):
@@ -60,6 +59,12 @@ class PCell(pya.PCellDeclarationHelper):
# TODO: return "True" here if the PCell takes a long time to compute.
# In lazy mode, the user has to acknowledge parameter changes before
# they are executed.
+ #
+ # optional:
+ # def callback_impl(self, name):
+ # TODO: implement functionality to change user interface element
+ # states for PCell parameter editors based on certain events
+ # like value changes.
# TODO: add more PCell classes ..
@@ -68,7 +73,7 @@ class PCell(pya.PCellDeclarationHelper):
# The main purpose of this class is to provide the PCell declarations and to register itself
# with a proper name.
# TODO: change the class name
-class PCellLib(pya.Library):
+class PCellLib(kdb.Library):
def __init__(self):
diff --git a/src/lay/lay/macro_templates/pcell_sample_python.lym b/src/lay/lay/macro_templates/pcell_sample_python.lym
index 775f3241c..c95bd22fe 100644
--- a/src/lay/lay/macro_templates/pcell_sample_python.lym
+++ b/src/lay/lay/macro_templates/pcell_sample_python.lym
@@ -8,7 +8,7 @@
pymacros
python
- import pya
+ import klayout.db as kdb
import math
"""
@@ -22,7 +22,7 @@ implementation. The macro is also set to "auto run" to install the PCell
when KLayout is run.
"""
-class Circle(pya.PCellDeclarationHelper):
+class Circle(kdb.PCellDeclarationHelper):
"""
The PCell declaration for the circle
"""
@@ -34,7 +34,7 @@ class Circle(pya.PCellDeclarationHelper):
# declare the parameters
self.param("l", self.TypeLayer, "Layer")
- self.param("s", self.TypeShape, "", default = pya.DPoint(0, 0))
+ self.param("s", self.TypeShape, "", default = kdb.DPoint(0, 0))
self.param("r", self.TypeDouble, "Radius", default = 0.1)
self.param("n", self.TypeInt, "Number of points", default = 64)
# this hidden parameter is used to determine whether the radius has changed
@@ -53,15 +53,15 @@ class Circle(pya.PCellDeclarationHelper):
# radius ru) and set ru to the effective radius. We also update the
# numerical value or the shape, depending on which on has not changed.
rs = None
- if isinstance(self.s, pya.DPoint):
+ if isinstance(self.s, kdb.DPoint):
# compute distance in micron
- rs = self.s.distance(pya.DPoint(0, 0))
+ rs = self.s.distance(kdb.DPoint(0, 0))
if rs != None and abs(self.r-self.ru) < 1e-6:
self.ru = rs
self.r = rs
else:
self.ru = self.r
- self.s = pya.DPoint(-self.r, 0)
+ self.s = kdb.DPoint(-self.r, 0)
self.rd = 2*self.r
@@ -83,7 +83,7 @@ class Circle(pya.PCellDeclarationHelper):
def transformation_from_shape_impl(self):
# Implement the "Create PCell from shape" protocol: we use the center of the shape's
# bounding box to determine the transformation
- return pya.Trans(self.shape.bbox().center())
+ return kdb.Trans(self.shape.bbox().center())
def produce_impl(self):
@@ -91,13 +91,13 @@ class Circle(pya.PCellDeclarationHelper):
# compute the circle
da = math.pi * 2 / self.n
- pts = [ pya.DPoint(self.ru * math.cos(i * da), self.ru * math.sin(i * da)) for i in range(0, self.n) ]
+ pts = [ kdb.DPoint(self.ru * math.cos(i * da), self.ru * math.sin(i * da)) for i in range(0, self.n) ]
# create the shape
- self.cell.shapes(self.l_layer).insert(pya.DPolygon(pts))
+ self.cell.shapes(self.l_layer).insert(kdb.DPolygon(pts))
-class MyLib(pya.Library):
+class MyLib(kdb.Library):
"""
The library where we will put the PCell into
"""
diff --git a/src/lay/lay/macro_templates/qt_designer_python.lym b/src/lay/lay/macro_templates/qt_designer_python.lym
index dffd41731..b8d9b12dc 100644
--- a/src/lay/lay/macro_templates/qt_designer_python.lym
+++ b/src/lay/lay/macro_templates/qt_designer_python.lym
@@ -10,14 +10,16 @@
python
- import pya
+ from klayout.QtUiTools import QUiLoader
+from klayout.QtCore import QFile, QIODevice
+from klayout.lay import Application
import types
# Create the form object from the uic file:
-ui_file = pya.QFile(":/macro-templates/qt_designer.ui")
-ui_file.open(pya.QIODevice.ReadOnly)
-form = pya.QUiLoader().load(ui_file, pya.Application.instance().main_window())
+ui_file = QFile(":/macro-templates/qt_designer.ui")
+ui_file.open(QIODevice.ReadOnly)
+form = QUiLoader().load(ui_file, Application.instance().main_window())
ui_file.close()
# Install an event handler for the button clicked event
diff --git a/src/lay/lay/macro_templates/qt_dialog_python.lym b/src/lay/lay/macro_templates/qt_dialog_python.lym
index 3e4cee917..1527cbff3 100644
--- a/src/lay/lay/macro_templates/qt_dialog_python.lym
+++ b/src/lay/lay/macro_templates/qt_dialog_python.lym
@@ -14,9 +14,11 @@
python
- import pya
+ from klayout.QtWidgets import QDialog, QVBoxLayout, QLabel, QPushButton
+from klayout.QtGui import QPixmap, QFont
+from klayout.lay import Application
-class ScreenshotDialog(pya.QDialog):
+class ScreenshotDialog(QDialog):
"""
This class implements a dialog with a screenshot display area and a
screenshot button
@@ -25,11 +27,11 @@ class ScreenshotDialog(pya.QDialog):
def button_clicked(self, checked):
""" Event handler: "Screenshot" button clicked """
- view = pya.Application.instance().main_window().current_view()
+ view = Application.instance().main_window().current_view()
# get the screenshot and place it in the image label
if not view is None:
- self.image.setPixmap(pya.QPixmap.fromImage(view.get_image(400, 400)))
+ self.image.setPixmap(QPixmap.fromImage(view.get_image(400, 400)))
else:
self.image.setText("No layout opened to take screenshot from")
@@ -42,14 +44,14 @@ class ScreenshotDialog(pya.QDialog):
self.resize(400, 120)
- layout = pya.QVBoxLayout(self)
+ layout = QVBoxLayout(self)
self.setLayout(layout)
- self.image = pya.QLabel("Press the button to fetch a screenshot", self)
+ self.image = QLabel("Press the button to fetch a screenshot", self)
layout.addWidget(self.image)
- button = pya.QPushButton('Screenshot', self)
- button.setFont(pya.QFont('Times', 18, int(pya.QFont.Bold)))
+ button = QPushButton('Screenshot', self)
+ button.setFont(QFont('Times', 18, int(QFont.Bold)))
layout.addWidget(button)
# attach the event handler
@@ -57,7 +59,7 @@ class ScreenshotDialog(pya.QDialog):
# Instantiate the dialog and make it visible initially.
# Passing the main_window will make it stay on top of the main window.
-dialog = ScreenshotDialog(pya.Application.instance().main_window())
+dialog = ScreenshotDialog(Application.instance().main_window())
dialog.show()
diff --git a/src/lay/lay/macro_templates/qt_server_python.lym b/src/lay/lay/macro_templates/qt_server_python.lym
index 64585a4ec..4bae0d5b7 100644
--- a/src/lay/lay/macro_templates/qt_server_python.lym
+++ b/src/lay/lay/macro_templates/qt_server_python.lym
@@ -14,10 +14,12 @@
python
- import pya
-import re
+ import re
+from klayout.QtNetwork import QTcpServer, QTcpSocket, QHostAddress
+from klayout.QtCore import QUrl, QBuffer, QIODevice, QObject, qt_signal, qt_slot
+from klayout.lay import Application
-class MyServer(pya.QTcpServer):
+class MyServer(QTcpServer):
"""
Implements a TCP server listening on port 8082
This server will accept HTTP requests and deliver a HTML page containing an image
@@ -39,7 +41,7 @@ class MyServer(pya.QTcpServer):
connection = self.nextPendingConnection()
# Read the request header
- while connection.isOpen() and connection.state() == pya.QTcpSocket.ConnectedState:
+ while connection.isOpen() and connection.state() == QTcpSocket.ConnectedState:
if connection.canReadLine():
line = connection.readLine().decode("utf-8")
if line.rstrip('\n').rstrip('\r') == "":
@@ -47,19 +49,19 @@ class MyServer(pya.QTcpServer):
else:
m = re.match("GET\\s+(.*)\\s+HTTP", line)
if not m is None:
- url = pya.QUrl(m.groups()[0])
+ url = QUrl(m.groups()[0])
else:
connection.waitForReadyRead(100)
- view = pya.Application.instance().main_window().current_view()
+ view = Application.instance().main_window().current_view()
if url is None:
pass
- elif url.path == "/screenshot.png":
+ elif url.path() == "/screenshot.png":
# Deliver the image
if not view is None:
- b = pya.QBuffer()
- b.open(pya.QIODevice.WriteOnly)
+ b = QBuffer()
+ b.open(QIODevice.WriteOnly)
view.get_image(800, 800).save(b, "PNG")
b.close()
connection.write(b.buffer())
@@ -70,13 +72,13 @@ class MyServer(pya.QTcpServer):
connection.write("HTTP/1.0 200 OK\nContent-Type: text/html\n\n" + '<html><body>No view open to take screenshot from</body></html>\n\n')
# automatically delete when disconnected
- # Note: we cannot use RBA signal bindings for that purpose because the Ruby object might get
+ # Note: we cannot use native Python signal bindings for that purpose because the Python object might get
# deleted before the C++ object is. Hence we do it explicitly.
connection.disconnectFromHost()
#connection.destroy()
- signal = pya.qt_signal("disconnected()")
- slot = pya.qt_slot("deleteLater()")
- pya.QObject.connect(connection, signal, connection, slot)
+ signal = qt_signal("disconnected()")
+ slot = qt_slot("deleteLater()")
+ QObject.connect(connection, signal, connection, slot)
except Exception as ex:
print("ERROR " + str(ex))
@@ -89,7 +91,7 @@ class MyServer(pya.QTcpServer):
super(MyServer, self).__init__(parent)
- ha = pya.QHostAddress("0.0.0.0")
+ ha = QHostAddress("0.0.0.0")
self.listen(ha, 8082)
# install an event on a new connection
diff --git a/src/lay/lay/macro_templates/via_pcell_sample_python.lym b/src/lay/lay/macro_templates/via_pcell_sample_python.lym
index 64fb2adb8..f08623fec 100644
--- a/src/lay/lay/macro_templates/via_pcell_sample_python.lym
+++ b/src/lay/lay/macro_templates/via_pcell_sample_python.lym
@@ -7,7 +7,7 @@
false
pymacros
python
- import pya
+ import klayout.db as kdb
import math
"""
@@ -33,7 +33,7 @@ implementation. The macro is also set to "auto run" to install the PCell
when KLayout is run.
"""
-class ViaPCell(pya.PCellDeclarationHelper):
+class ViaPCell(kdb.PCellDeclarationHelper):
def __init__(self):
@@ -73,18 +73,18 @@ class ViaPCell(pya.PCellDeclarationHelper):
self.via_type_list = []
# Via1
- vt = pya.ViaType("V1", "Via1 (0.2x0.2)")
+ vt = kdb.ViaType("V1", "Via1 (0.2x0.2)")
vt.wbmin = 0.4
vt.hbmin = 0.4
vt.wtmin = 0.5
vt.htmin = 0.5
- vt.bottom = pya.LayerInfo(1, 0)
- vt.cut = pya.LayerInfo(2, 0)
- vt.top = pya.LayerInfo(3, 0)
+ vt.bottom = kdb.LayerInfo(1, 0)
+ vt.cut = kdb.LayerInfo(2, 0)
+ vt.top = kdb.LayerInfo(3, 0)
vt.bottom_grid = 0.01
vt.top_grid = 0.01
- # foreign attributes (not used by pya, but handy for
+ # foreign attributes (not used by KLayout, but handy for
# internal use):
vt.enc_bottom = 0.1
vt.enc_top = 0.15
@@ -94,18 +94,18 @@ class ViaPCell(pya.PCellDeclarationHelper):
self.via_type_list.append(vt)
# Via2
- vt = pya.ViaType("V2", "Via2 (0.3x0.3)")
+ vt = kdb.ViaType("V2", "Via2 (0.3x0.3)")
vt.wbmin = 0.5
vt.hbmin = 0.5
vt.wtmin = 0.5
vt.htmin = 0.5
- vt.bottom = pya.LayerInfo(3, 0)
- vt.cut = pya.LayerInfo(4, 0)
- vt.top = pya.LayerInfo(5, 0)
+ vt.bottom = kdb.LayerInfo(3, 0)
+ vt.cut = kdb.LayerInfo(4, 0)
+ vt.top = kdb.LayerInfo(5, 0)
vt.bottom_grid = 0.01
vt.top_grid = 0.01
- # foreign attributes (not used by pya, but handy for
+ # foreign attributes (not used by kdb, but handy for
# internal use):
vt.enc_bottom = 0.1
vt.enc_top = 0.1
@@ -159,7 +159,7 @@ class ViaPCell(pya.PCellDeclarationHelper):
"""
PCell interface implementation
"""
- return pya.Trans()
+ return kdb.Trans()
def min_dim(self, a, b, da, db):
"""
@@ -248,8 +248,8 @@ class ViaPCell(pya.PCellDeclarationHelper):
ltop = self.layout.layer(vt.top)
lcut = self.layout.layer(vt.cut)
- self.cell.shapes(lbottom).insert(pya.DBox(wbottom, hbottom))
- self.cell.shapes(ltop).insert(pya.DBox(wtop, htop))
+ self.cell.shapes(lbottom).insert(kdb.DBox(wbottom, hbottom))
+ self.cell.shapes(ltop).insert(kdb.DBox(wtop, htop))
scut = self.cell.shapes(lcut)
@@ -257,10 +257,10 @@ class ViaPCell(pya.PCellDeclarationHelper):
x = (ix - 0.5 * (nx - 1)) * (vt.vwidth + vt.vspace)
for iy in range(0, ny):
y = (iy - 0.5 * (ny - 1)) * (vt.vwidth + vt.vspace)
- scut.insert(pya.DBox(vt.vwidth, vt.vwidth).moved(x, y))
+ scut.insert(kdb.DBox(vt.vwidth, vt.vwidth).moved(x, y))
-class MyViaLib(pya.Library):
+class MyViaLib(kdb.Library):
"""
A declaration for a test library