Cherry-picked Python type hint enhancements from master

This commit is contained in:
Matthias Koefferlein 2022-10-19 22:13:03 +02:00
parent c9c9d6198b
commit c012bb846e
20 changed files with 3940 additions and 1011 deletions

2
.gitignore vendored
View File

@ -68,3 +68,5 @@ dist/
# Macos artifacts
*.dmg
*.dmg.md5
.DS_Store

634
setup.py
View File

@ -1,4 +1,3 @@
"""
KLayout standalone Python module setup script
@ -55,6 +54,7 @@ and won't find them. So we need to take away the path with
"-Wl,-soname" on Linux (see Config.link_args).
"""
from typing import List
from setuptools import setup, Distribution, find_packages
from setuptools.extension import Extension, Library
import glob
@ -70,17 +70,28 @@ import multiprocessing
# for Jenkins we do not want to be greedy
multicore = os.getenv("KLAYOUT_SETUP_MULTICORE")
if multicore:
N_cores = int(multicore)
N_cores = int(multicore)
else:
N_cores = multiprocessing.cpu_count()
N_cores = multiprocessing.cpu_count()
# monkey-patch for parallel compilation
# from https://stackoverflow.com/questions/11013851/speeding-up-build-process-with-distutils
def parallelCCompile(self, sources, output_dir=None, macros=None, include_dirs=None, debug=0, extra_preargs=None, extra_postargs=None, depends=None):
def parallelCCompile(
self,
sources,
output_dir=None,
macros=None,
include_dirs=None,
debug=0,
extra_preargs=None,
extra_postargs=None,
depends=None,
):
# those lines are copied from distutils.ccompiler.CCompiler directly
macros, objects, extra_postargs, pp_opts, build = self._setup_compile(
output_dir, macros, include_dirs, sources, depends, extra_postargs)
output_dir, macros, include_dirs, sources, depends, extra_postargs
)
cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
# parallel code
@ -104,6 +115,7 @@ def parallelCCompile(self, sources, output_dir=None, macros=None, include_dirs=N
print("Building", obj, "has failed. Trying again.")
else:
break
# convert to list, imap is evaluated on-demand
list(multiprocessing.pool.ThreadPool(N).map(_single_compile, objects))
return objects
@ -112,6 +124,7 @@ def parallelCCompile(self, sources, output_dir=None, macros=None, include_dirs=N
# only if python version > 2.6, somehow the travis compiler hangs in 2.6
if sys.version_info[0] * 100 + sys.version_info[1] > 206:
import distutils.ccompiler
distutils.ccompiler.CCompiler.compile = parallelCCompile
@ -119,7 +132,7 @@ if sys.version_info[0] * 100 + sys.version_info[1] > 206:
def quote_path(path):
# looks like disutils don't need path quoting in version >= 3.9:
if " " in path and sys.version_info[0] * 100 + sys.version_info[1] < 309:
return "\"" + path + "\""
return '"' + path + '"'
else:
return path
@ -127,6 +140,7 @@ def quote_path(path):
# TODO: delete (Obsolete)
# patch get_ext_filename
from distutils.command.build_ext import build_ext
_old_get_ext_filename = build_ext.get_ext_filename
@ -137,8 +151,8 @@ def patched_get_ext_filename(self, ext_name):
"""
filename = _old_get_ext_filename(self, ext_name)
# Making sure this matches qmake's default extension .dylib, instead of .so
if platform.system() == "Darwin" and '_dbpi' in ext_name:
filename = filename.replace('.so', '.dylib')
if platform.system() == "Darwin" and "_dbpi" in ext_name:
filename = filename.replace(".so", ".dylib")
return filename
@ -152,15 +166,18 @@ distutils.command.build_ext.build_ext.get_ext_filename = patched_get_ext_filenam
# hence the patch
from distutils.ccompiler import CCompiler
old_library_filename = CCompiler.library_filename
def patched_library_filename(self, libname, lib_type='static', # or 'shared'
strip_dir=0, output_dir=''):
if platform.system() == "Darwin" and '_dbpi' in libname:
lib_type = 'dylib'
return old_library_filename(self, libname, lib_type=lib_type,
strip_dir=strip_dir, output_dir=output_dir)
def patched_library_filename(
self, libname, lib_type="static", strip_dir=0, output_dir="" # or 'shared'
):
if platform.system() == "Darwin" and "_dbpi" in libname:
lib_type = "dylib"
return old_library_filename(
self, libname, lib_type=lib_type, strip_dir=strip_dir, output_dir=output_dir
)
distutils.ccompiler.CCompiler.library_filename = patched_library_filename
@ -172,16 +189,36 @@ distutils.ccompiler.CCompiler.library_filename = patched_library_filename
# link a shared object on Linux, but a static library and patches distutils
# for this ... We're patching this back now.
def always_link_shared_object(
self, objects, output_libname, output_dir=None, libraries=None,
library_dirs=None, runtime_library_dirs=None, export_symbols=None,
debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
target_lang=None):
self,
objects,
output_libname,
output_dir=None,
libraries=None,
library_dirs=None,
runtime_library_dirs=None,
export_symbols=None,
debug=0,
extra_preargs=None,
extra_postargs=None,
build_temp=None,
target_lang=None,
):
self.link(
self.SHARED_LIBRARY, objects, output_libname,
output_dir, libraries, library_dirs, runtime_library_dirs,
export_symbols, debug, extra_preargs, extra_postargs,
build_temp, target_lang
self.SHARED_LIBRARY,
objects,
output_libname,
output_dir,
libraries,
library_dirs,
runtime_library_dirs,
export_symbols,
debug,
extra_preargs,
extra_postargs,
build_temp,
target_lang,
)
@ -201,7 +238,7 @@ class Config(object):
# TODO: is this really how we get the build paths?
build_cmd = Distribution().get_command_obj('build')
build_cmd = Distribution().get_command_obj("build")
build_cmd.finalize_options()
self.build_platlib = build_cmd.build_platlib
self.build_temp = build_cmd.build_temp
@ -212,7 +249,7 @@ class Config(object):
else:
self.build_temp = os.path.join(self.build_temp, "Release")
build_ext_cmd = Distribution().get_command_obj('build_ext')
build_ext_cmd = Distribution().get_command_obj("build_ext")
build_ext_cmd.initialize_options()
build_ext_cmd.setup_shlib_compiler()
@ -230,7 +267,7 @@ class Config(object):
This code was extracted from the source in setuptools.command.build_ext.build_ext
"""
libtype = setuptools.command.build_ext.libtype
full_mod = self.root + '.' + mod
full_mod = self.root + "." + mod
if is_lib is True:
# Here we are guessing it is a library and that the filename
# is to be computed by shlib_compiler.
@ -246,8 +283,8 @@ class Config(object):
ext_filename = os.path.basename(ext_path)
# Exception for database plugins, which will always be dylib.
if platform.system() == "Darwin" and '_dbpi' in mod:
ext_filename = ext_filename.replace('.so', '.dylib')
if platform.system() == "Darwin" and "_dbpi" in mod:
ext_filename = ext_filename.replace(".so", ".dylib")
return ext_filename
def path_of(self, mod, mod_src_path):
@ -265,20 +302,25 @@ class Config(object):
"""
Gets additional compiler arguments
"""
args: List[str]
if platform.system() == "Windows":
bits = os.getenv("KLAYOUT_BITS")
if bits:
return [quote_path("-I" + os.path.join(bits, "zlib", "include")),
quote_path("-I" + os.path.join(bits, "ptw", "include")),
quote_path("-I" + os.path.join(bits, "png", "include")),
quote_path("-I" + os.path.join(bits, "expat", "include")),
quote_path("-I" + os.path.join(bits, "curl", "include"))]
args = [
quote_path("-I" + os.path.join(bits, "zlib", "include")),
quote_path("-I" + os.path.join(bits, "ptw", "include")),
quote_path("-I" + os.path.join(bits, "png", "include")),
quote_path("-I" + os.path.join(bits, "expat", "include")),
quote_path("-I" + os.path.join(bits, "curl", "include")),
]
else:
return []
args = []
else:
return ["-Wno-strict-aliasing", # Avoids many "type-punned pointer" warnings
"-std=c++11", # because we use unordered_map/unordered_set
]
args = [
"-Wno-strict-aliasing", # Avoids many "type-punned pointer" warnings
"-std=c++11", # because we use unordered_map/unordered_set
]
return args
def libraries(self, mod):
"""
@ -286,10 +328,10 @@ class Config(object):
"""
if platform.system() == "Windows":
if mod == "_tl":
return [ "libcurl", "expat", "pthreadVCE2", "zlib", "wsock32", "libpng16" ]
return ["libcurl", "expat", "pthreadVCE2", "zlib", "wsock32", "libpng16"]
else:
if mod == "_tl":
return [ "curl", "expat", "png" ]
return ["curl", "expat", "png"]
return []
def link_args(self, mod):
@ -300,19 +342,24 @@ class Config(object):
args = ["/DLL"]
bits = os.getenv("KLAYOUT_BITS")
if bits:
args += [quote_path("/LIBPATH:" + os.path.join(bits, "zlib", "lib")),
quote_path("/LIBPATH:" + os.path.join(bits, "ptw", "libraries")),
quote_path("/LIBPATH:" + os.path.join(bits, "png", "libraries")),
quote_path("/LIBPATH:" + os.path.join(bits, "expat", "libraries")),
quote_path("/LIBPATH:" + os.path.join(bits, "curl", "libraries"))]
args += [
quote_path("/LIBPATH:" + os.path.join(bits, "zlib", "libraries")),
quote_path("/LIBPATH:" + os.path.join(bits, "ptw", "libraries")),
quote_path("/LIBPATH:" + os.path.join(bits, "png", "libraries")),
quote_path("/LIBPATH:" + os.path.join(bits, "expat", "libraries")),
quote_path("/LIBPATH:" + os.path.join(bits, "curl", "libraries")),
]
return args
elif platform.system() == "Darwin":
# For the dependency modules, make sure we produce a dylib.
# We can only link against such, but the bundles produced otherwise.
args = []
if mod[0] == "_":
args += ["-Wl,-dylib", '-Wl,-install_name,@rpath/%s' % self.libname_of(mod, is_lib=True)]
args += ['-Wl,-rpath,@loader_path/']
args += [
"-Wl,-dylib",
"-Wl,-install_name,@rpath/%s" % self.libname_of(mod, is_lib=True),
]
args += ["-Wl,-rpath,@loader_path/"]
return args
else:
# this makes the libraries suitable for linking with a path -
@ -321,23 +368,30 @@ class Config(object):
# will look for the path-qualified library. But that's the
# build path and the loader will fail.
args = []
args += ['-Wl,-soname,' + self.libname_of(mod, is_lib=True)]
if '_dbpi' not in mod:
loader_path = '$ORIGIN'
args += ["-Wl,-soname," + self.libname_of(mod, is_lib=True)]
if "_dbpi" not in mod:
loader_path = "$ORIGIN"
else:
loader_path = '$ORIGIN/..'
args += ['-Wl,-rpath,' + loader_path]
loader_path = "$ORIGIN/.."
args += ["-Wl,-rpath," + loader_path]
# default linux shared object compilation uses the '-g' flag,
# which generates unnecessary debug information
# removing with strip-all during the linking stage
args += ['-Wl,--strip-all']
args += ["-Wl,--strip-all"]
return args
def macros(self):
"""
Returns the macros to use for building
"""
return [('HAVE_PNG', 1), ('HAVE_CURL', 1), ('HAVE_EXPAT', 1), ('KLAYOUT_MAJOR_VERSION', self.major_version()), ('KLAYOUT_MINOR_VERSION', self.minor_version())]
return [
("HAVE_PNG", 1),
("HAVE_CURL", 1),
("HAVE_EXPAT", 1),
("KLAYOUT_MAJOR_VERSION", self.major_version()),
("KLAYOUT_MINOR_VERSION", self.minor_version()),
("GSI_ALIAS_INSPECT", 1),
]
def minor_version(self):
"""
@ -349,7 +403,9 @@ class Config(object):
version_file = os.path.join(os.path.dirname(__file__), "version.sh")
with open(version_file, "r") as file:
version_txt = file.read()
rm = re.search(r"KLAYOUT_VERSION\s*=\s*\"(.*?)\.(.*?)(\..*)?\".*", version_txt)
rm = re.search(
r"KLAYOUT_VERSION\s*=\s*\"(.*?)\.(.*?)(\..*)?\".*", version_txt
)
if rm:
version_string = rm.group(2)
return version_string
@ -366,7 +422,9 @@ class Config(object):
version_file = os.path.join(os.path.dirname(__file__), "version.sh")
with open(version_file, "r") as file:
version_txt = file.read()
rm = re.search(r"KLAYOUT_VERSION\s*=\s*\"(.*?)\.(.*?)(\..*)?\".*", version_txt)
rm = re.search(
r"KLAYOUT_VERSION\s*=\s*\"(.*?)\.(.*?)(\..*)?\".*", version_txt
)
if rm:
version_string = rm.group(1)
return version_string
@ -407,13 +465,15 @@ _tl_sources.discard(os.path.join(_tl_path, "tlHttpStreamNoQt.cc"))
_tl_sources.discard(os.path.join(_tl_path, "tlFileSystemWatcher.cc"))
_tl_sources.discard(os.path.join(_tl_path, "tlDeferredExecutionQt.cc"))
_tl = Library(config.root + '._tl',
define_macros=config.macros() + [('MAKE_TL_LIBRARY', 1)],
language='c++',
libraries=config.libraries('_tl'),
extra_link_args=config.link_args('_tl'),
extra_compile_args=config.compile_args('_tl'),
sources=list(_tl_sources))
_tl = Library(
config.root + "._tl",
define_macros=config.macros() + [("MAKE_TL_LIBRARY", 1)],
language="c++",
libraries=config.libraries("_tl"),
extra_link_args=config.link_args("_tl"),
extra_compile_args=config.compile_args("_tl"),
sources=list(_tl_sources),
)
config.add_extension(_tl)
@ -423,15 +483,17 @@ config.add_extension(_tl)
_gsi_path = os.path.join("src", "gsi", "gsi")
_gsi_sources = set(glob.glob(os.path.join(_gsi_path, "*.cc")))
_gsi = Library(config.root + '._gsi',
define_macros=config.macros() + [('MAKE_GSI_LIBRARY', 1)],
include_dirs=[_tl_path],
extra_objects=[config.path_of('_tl', _tl_path)],
language='c++',
libraries=config.libraries('_gsi'),
extra_link_args=config.link_args('_gsi'),
extra_compile_args=config.compile_args('_gsi'),
sources=list(_gsi_sources))
_gsi = Library(
config.root + "._gsi",
define_macros=config.macros() + [("MAKE_GSI_LIBRARY", 1)],
include_dirs=[_tl_path],
extra_objects=[config.path_of("_tl", _tl_path)],
language="c++",
libraries=config.libraries('_gsi'),
extra_link_args=config.link_args("_gsi"),
extra_compile_args=config.compile_args("_gsi"),
sources=list(_gsi_sources),
)
config.add_extension(_gsi)
# ------------------------------------------------------------------
@ -440,15 +502,17 @@ config.add_extension(_gsi)
_pya_path = os.path.join("src", "pya", "pya")
_pya_sources = set(glob.glob(os.path.join(_pya_path, "*.cc")))
_pya = Library(config.root + '._pya',
define_macros=config.macros() + [('MAKE_PYA_LIBRARY', 1)],
include_dirs=[_tl_path, _gsi_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path)],
language='c++',
libraries=config.libraries('_pya'),
extra_link_args=config.link_args('_pya'),
extra_compile_args=config.compile_args('_pya'),
sources=list(_pya_sources))
_pya = Library(
config.root + "._pya",
define_macros=config.macros() + [("MAKE_PYA_LIBRARY", 1)],
include_dirs=[_tl_path, _gsi_path],
extra_objects=[config.path_of("_tl", _tl_path), config.path_of("_gsi", _gsi_path)],
language="c++",
libraries=config.libraries('_pya'),
extra_link_args=config.link_args("_pya"),
extra_compile_args=config.compile_args("_pya"),
sources=list(_pya_sources),
)
config.add_extension(_pya)
# ------------------------------------------------------------------
@ -457,15 +521,17 @@ config.add_extension(_pya)
_rba_path = os.path.join("src", "rbastub")
_rba_sources = set(glob.glob(os.path.join(_rba_path, "*.cc")))
_rba = Library(config.root + '._rba',
define_macros=config.macros() + [('MAKE_RBA_LIBRARY', 1)],
include_dirs=[_tl_path, _gsi_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path)],
language='c++',
libraries=config.libraries('_rba'),
extra_link_args=config.link_args('_rba'),
extra_compile_args=config.compile_args('_rba'),
sources=list(_rba_sources))
_rba = Library(
config.root + '._rba',
define_macros=config.macros() + [('MAKE_RBA_LIBRARY', 1)],
include_dirs=[_tl_path, _gsi_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path)],
language='c++',
libraries=config.libraries('_rba'),
extra_link_args=config.link_args('_rba'),
extra_compile_args=config.compile_args('_rba'),
sources=list(_rba_sources)
)
config.add_extension(_rba)
# ------------------------------------------------------------------
@ -474,15 +540,17 @@ config.add_extension(_rba)
_db_path = os.path.join("src", "db", "db")
_db_sources = set(glob.glob(os.path.join(_db_path, "*.cc")))
_db = Library(config.root + '._db',
define_macros=config.macros() + [('MAKE_DB_LIBRARY', 1)],
include_dirs=[_tl_path, _gsi_path, _db_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path)],
language='c++',
libraries=config.libraries('_db'),
extra_link_args=config.link_args('_db'),
extra_compile_args=config.compile_args('_db'),
sources=list(_db_sources))
_db = Library(
config.root + "._db",
define_macros=config.macros() + [("MAKE_DB_LIBRARY", 1)],
include_dirs=[_tl_path, _gsi_path, _db_path],
extra_objects=[config.path_of("_tl", _tl_path), config.path_of("_gsi", _gsi_path)],
language="c++",
libraries=config.libraries('_db'),
extra_link_args=config.link_args("_db"),
extra_compile_args=config.compile_args("_db"),
sources=list(_db_sources),
)
config.add_extension(_db)
# ------------------------------------------------------------------
@ -491,15 +559,21 @@ config.add_extension(_db)
_lib_path = os.path.join("src", "lib", "lib")
_lib_sources = set(glob.glob(os.path.join(_lib_path, "*.cc")))
_lib = Library(config.root + '._lib',
define_macros=config.macros() + [('MAKE_LIB_LIBRARY', 1)],
include_dirs=[_tl_path, _gsi_path, _db_path, _lib_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
language='c++',
libraries=config.libraries('_lib'),
extra_link_args=config.link_args('_lib'),
extra_compile_args=config.compile_args('_lib'),
sources=list(_lib_sources))
_lib = Library(
config.root + "._lib",
define_macros=config.macros() + [("MAKE_LIB_LIBRARY", 1)],
include_dirs=[_tl_path, _gsi_path, _db_path, _lib_path],
extra_objects=[
config.path_of("_tl", _tl_path),
config.path_of("_gsi", _gsi_path),
config.path_of("_db", _db_path),
],
language="c++",
libraries=config.libraries('_lib'),
extra_link_args=config.link_args("_lib"),
extra_compile_args=config.compile_args("_lib"),
sources=list(_lib_sources),
)
config.add_extension(_lib)
# ------------------------------------------------------------------
@ -508,15 +582,21 @@ config.add_extension(_lib)
_rdb_path = os.path.join("src", "rdb", "rdb")
_rdb_sources = set(glob.glob(os.path.join(_rdb_path, "*.cc")))
_rdb = Library(config.root + '._rdb',
define_macros=config.macros() + [('MAKE_RDB_LIBRARY', 1)],
include_dirs=[_db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
language='c++',
libraries=config.libraries('_rdb'),
extra_link_args=config.link_args('_rdb'),
extra_compile_args=config.compile_args('_rdb'),
sources=list(_rdb_sources))
_rdb = Library(
config.root + "._rdb",
define_macros=config.macros() + [("MAKE_RDB_LIBRARY", 1)],
include_dirs=[_db_path, _tl_path, _gsi_path],
extra_objects=[
config.path_of("_tl", _tl_path),
config.path_of("_gsi", _gsi_path),
config.path_of("_db", _db_path),
],
language="c++",
libraries=config.libraries('_rdb'),
extra_link_args=config.link_args("_rdb"),
extra_compile_args=config.compile_args("_rdb"),
sources=list(_rdb_sources),
)
config.add_extension(_rdb)
# ------------------------------------------------------------------
@ -525,15 +605,22 @@ config.add_extension(_rdb)
_laybasic_path = os.path.join("src", "laybasic", "laybasic")
_laybasic_sources = set(glob.glob(os.path.join(_laybasic_path, "*.cc")))
_laybasic = Library(config.root + '._laybasic',
define_macros=config.macros() + [('MAKE_LAYBASIC_LIBRARY', 1)],
include_dirs=[_rdb_path, _db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_rdb', _rdb_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
language='c++',
libraries=config.libraries('_laybasic'),
extra_link_args=config.link_args('_laybasic'),
extra_compile_args=config.compile_args('_laybasic'),
sources=list(_laybasic_sources))
_laybasic = Library(
config.root + '._laybasic',
define_macros=config.macros() + [('MAKE_LAYBASIC_LIBRARY', 1)],
include_dirs=[_rdb_path, _db_path, _tl_path, _gsi_path],
extra_objects=[
config.path_of('_rdb', _rdb_path),
config.path_of('_tl', _tl_path),
config.path_of('_gsi', _gsi_path),
config.path_of('_db', _db_path)
],
language='c++',
libraries=config.libraries('_laybasic'),
extra_link_args=config.link_args('_laybasic'),
extra_compile_args=config.compile_args('_laybasic'),
sources=list(_laybasic_sources)
)
config.add_extension(_laybasic)
# ------------------------------------------------------------------
@ -542,15 +629,23 @@ config.add_extension(_laybasic)
_layview_path = os.path.join("src", "layview", "layview")
_layview_sources = set(glob.glob(os.path.join(_layview_path, "*.cc")))
_layview = Library(config.root + '._layview',
define_macros=config.macros() + [('MAKE_LAYVIEW_LIBRARY', 1)],
include_dirs=[_laybasic_path, _rdb_path, _db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_laybasic', _laybasic_path), config.path_of('_rdb', _rdb_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
language='c++',
libraries=config.libraries('_layview'),
extra_link_args=config.link_args('_layview'),
extra_compile_args=config.compile_args('_layview'),
sources=list(_layview_sources))
_layview = Library(
config.root + '._layview',
define_macros=config.macros() + [('MAKE_LAYVIEW_LIBRARY', 1)],
include_dirs=[_laybasic_path, _rdb_path, _db_path, _tl_path, _gsi_path],
extra_objects=[
config.path_of('_laybasic', _laybasic_path),
config.path_of('_rdb', _rdb_path),
config.path_of('_tl', _tl_path),
config.path_of('_gsi', _gsi_path),
config.path_of('_db', _db_path)
],
language='c++',
libraries=config.libraries('_layview'),
extra_link_args=config.link_args('_layview'),
extra_compile_args=config.compile_args('_layview'),
sources=list(_layview_sources)
)
config.add_extension(_layview)
# ------------------------------------------------------------------
@ -559,15 +654,22 @@ config.add_extension(_layview)
_lym_path = os.path.join("src", "lym", "lym")
_lym_sources = set(glob.glob(os.path.join(_lym_path, "*.cc")))
_lym = Library(config.root + '._lym',
define_macros=config.macros() + [('MAKE_LYM_LIBRARY', 1)],
include_dirs=[_pya_path, _rba_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_rba', _rba_path), config.path_of('_pya', _pya_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path)],
language='c++',
libraries=config.libraries('_lym'),
extra_link_args=config.link_args('_lym'),
extra_compile_args=config.compile_args('_lym'),
sources=list(_lym_sources))
_lym = Library(
config.root + '._lym',
define_macros=config.macros() + [('MAKE_LYM_LIBRARY', 1)],
include_dirs=[_pya_path, _rba_path, _tl_path, _gsi_path],
extra_objects=[
config.path_of('_rba', _rba_path),
config.path_of('_pya', _pya_path),
config.path_of('_tl', _tl_path),
config.path_of('_gsi', _gsi_path)
],
language='c++',
libraries=config.libraries('_lym'),
extra_link_args=config.link_args('_lym'),
extra_compile_args=config.compile_args('_lym'),
sources=list(_lym_sources)
)
config.add_extension(_lym)
# ------------------------------------------------------------------
@ -576,15 +678,24 @@ config.add_extension(_lym)
_ant_path = os.path.join("src", "ant", "ant")
_ant_sources = set(glob.glob(os.path.join(_ant_path, "*.cc")))
_ant = Library(config.root + '._ant',
define_macros=config.macros() + [('MAKE_ANT_LIBRARY', 1)],
include_dirs=[_laybasic_path, _layview_path, _rdb_path, _db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_laybasic', _laybasic_path), config.path_of('_layview', _layview_path), config.path_of('_rdb', _rdb_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
language='c++',
libraries=config.libraries('_ant'),
extra_link_args=config.link_args('_ant'),
extra_compile_args=config.compile_args('_ant'),
sources=list(_ant_sources))
_ant = Library(
config.root + '._ant',
define_macros=config.macros() + [('MAKE_ANT_LIBRARY', 1)],
include_dirs=[_laybasic_path, _layview_path, _rdb_path, _db_path, _tl_path, _gsi_path],
extra_objects=[
config.path_of('_laybasic', _laybasic_path),
config.path_of('_layview', _layview_path),
config.path_of('_rdb', _rdb_path),
config.path_of('_tl', _tl_path),
config.path_of('_gsi', _gsi_path),
config.path_of('_db', _db_path)
],
language='c++',
libraries=config.libraries('_ant'),
extra_link_args=config.link_args('_ant'),
extra_compile_args=config.compile_args('_ant'),
sources=list(_ant_sources)
)
config.add_extension(_ant)
# ------------------------------------------------------------------
@ -593,15 +704,24 @@ config.add_extension(_ant)
_img_path = os.path.join("src", "img", "img")
_img_sources = set(glob.glob(os.path.join(_img_path, "*.cc")))
_img = Library(config.root + '._img',
define_macros=config.macros() + [('MAKE_IMG_LIBRARY', 1)],
include_dirs=[_laybasic_path, _layview_path, _rdb_path, _db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_laybasic', _laybasic_path), config.path_of('_layview', _layview_path), config.path_of('_rdb', _rdb_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
language='c++',
libraries=config.libraries('_img'),
extra_link_args=config.link_args('_img'),
extra_compile_args=config.compile_args('_img'),
sources=list(_img_sources))
_img = Library(
config.root + '._img',
define_macros=config.macros() + [('MAKE_IMG_LIBRARY', 1)],
include_dirs=[_laybasic_path, _layview_path, _rdb_path, _db_path, _tl_path, _gsi_path],
extra_objects=[
config.path_of('_laybasic', _laybasic_path),
config.path_of('_layview', _layview_path),
config.path_of('_rdb', _rdb_path),
config.path_of('_tl', _tl_path),
config.path_of('_gsi', _gsi_path),
config.path_of('_db', _db_path)
],
language='c++',
libraries=config.libraries('_img'),
extra_link_args=config.link_args('_img'),
extra_compile_args=config.compile_args('_img'),
sources=list(_img_sources)
)
config.add_extension(_img)
# ------------------------------------------------------------------
@ -610,15 +730,24 @@ config.add_extension(_img)
_edt_path = os.path.join("src", "edt", "edt")
_edt_sources = set(glob.glob(os.path.join(_edt_path, "*.cc")))
_edt = Library(config.root + '._edt',
define_macros=config.macros() + [('MAKE_EDT_LIBRARY', 1)],
include_dirs=[_laybasic_path, _layview_path, _rdb_path, _db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_laybasic', _laybasic_path), config.path_of('_layview', _layview_path), config.path_of('_rdb', _rdb_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
language='c++',
libraries=config.libraries('_edt'),
extra_link_args=config.link_args('_edt'),
extra_compile_args=config.compile_args('_edt'),
sources=list(_edt_sources))
_edt = Library(
config.root + '._edt',
define_macros=config.macros() + [('MAKE_EDT_LIBRARY', 1)],
include_dirs=[_laybasic_path, _layview_path, _rdb_path, _db_path, _tl_path, _gsi_path],
extra_objects=[
config.path_of('_laybasic', _laybasic_path),
config.path_of('_layview', _layview_path),
config.path_of('_rdb', _rdb_path),
config.path_of('_tl', _tl_path),
config.path_of('_gsi', _gsi_path),
config.path_of('_db', _db_path)
],
language='c++',
libraries=config.libraries('_edt'),
extra_link_args=config.link_args('_edt'),
extra_compile_args=config.compile_args('_edt'),
sources=list(_edt_sources)
)
config.add_extension(_edt)
# ------------------------------------------------------------------
@ -635,15 +764,25 @@ for pi in dbpi_dirs:
pi_sources = glob.glob(os.path.join(pi, "*.cc"))
pi_ext = Library(config.root + '.db_plugins.' + mod_name,
define_macros=config.macros() + [('MAKE_DB_PLUGIN_LIBRARY', 1)],
include_dirs=[os.path.join("src", "plugins", "common"),
_db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
language='c++',
extra_link_args=config.link_args(mod_name),
extra_compile_args=config.compile_args(mod_name),
sources=pi_sources)
pi_ext = Library(
config.root + ".db_plugins." + mod_name,
define_macros=config.macros() + [("MAKE_DB_PLUGIN_LIBRARY", 1)],
include_dirs=[
os.path.join("src", "plugins", "common"),
_db_path,
_tl_path,
_gsi_path,
],
extra_objects=[
config.path_of("_tl", _tl_path),
config.path_of("_gsi", _gsi_path),
config.path_of("_db", _db_path),
],
language="c++",
extra_link_args=config.link_args(mod_name),
extra_compile_args=config.compile_args(mod_name),
sources=pi_sources,
)
db_plugins.append(pi_ext)
config.add_extension(pi_ext)
@ -654,13 +793,19 @@ for pi in dbpi_dirs:
tl_path = os.path.join("src", "pymod", "tl")
tl_sources = set(glob.glob(os.path.join(tl_path, "*.cc")))
tl = Extension(config.root + '.tlcore',
define_macros=config.macros(),
include_dirs=[_tl_path, _gsi_path, _pya_path],
extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_pya', _pya_path)],
extra_link_args=config.link_args('tlcore'),
extra_compile_args=config.compile_args('tlcore'),
sources=list(tl_sources))
tl = Extension(
config.root + ".tlcore",
define_macros=config.macros(),
include_dirs=[_tl_path, _gsi_path, _pya_path],
extra_objects=[
config.path_of("_tl", _tl_path),
config.path_of("_gsi", _gsi_path),
config.path_of("_pya", _pya_path),
],
extra_link_args=config.link_args("tlcore"),
extra_compile_args=config.compile_args("tlcore"),
sources=list(tl_sources),
)
# ------------------------------------------------------------------
# db extension library
@ -668,13 +813,20 @@ tl = Extension(config.root + '.tlcore',
db_path = os.path.join("src", "pymod", "db")
db_sources = set(glob.glob(os.path.join(db_path, "*.cc")))
db = Extension(config.root + '.dbcore',
define_macros=config.macros(),
include_dirs=[_db_path, _tl_path, _gsi_path, _pya_path],
extra_objects=[config.path_of('_db', _db_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_pya', _pya_path)],
extra_link_args=config.link_args('dbcore'),
extra_compile_args=config.compile_args('dbcore'),
sources=list(db_sources))
db = Extension(
config.root + ".dbcore",
define_macros=config.macros(),
include_dirs=[_db_path, _tl_path, _gsi_path, _pya_path],
extra_objects=[
config.path_of("_db", _db_path),
config.path_of("_tl", _tl_path),
config.path_of("_gsi", _gsi_path),
config.path_of("_pya", _pya_path),
],
extra_link_args=config.link_args("dbcore"),
extra_compile_args=config.compile_args("dbcore"),
sources=list(db_sources),
)
# ------------------------------------------------------------------
# lib extension library
@ -682,13 +834,20 @@ db = Extension(config.root + '.dbcore',
lib_path = os.path.join("src", "pymod", "lib")
lib_sources = set(glob.glob(os.path.join(lib_path, "*.cc")))
lib = Extension(config.root + '.libcore',
define_macros=config.macros(),
include_dirs=[_lib_path, _tl_path, _gsi_path, _pya_path],
extra_objects=[config.path_of('_lib', _lib_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_pya', _pya_path)],
extra_link_args=config.link_args('libcore'),
extra_compile_args=config.compile_args('libcore'),
sources=list(lib_sources))
lib = Extension(
config.root + ".libcore",
define_macros=config.macros(),
include_dirs=[_lib_path, _tl_path, _gsi_path, _pya_path],
extra_objects=[
config.path_of("_lib", _lib_path),
config.path_of("_tl", _tl_path),
config.path_of("_gsi", _gsi_path),
config.path_of("_pya", _pya_path),
],
extra_link_args=config.link_args("libcore"),
extra_compile_args=config.compile_args("libcore"),
sources=list(lib_sources),
)
# ------------------------------------------------------------------
# rdb extension library
@ -696,13 +855,20 @@ lib = Extension(config.root + '.libcore',
rdb_path = os.path.join("src", "pymod", "rdb")
rdb_sources = set(glob.glob(os.path.join(rdb_path, "*.cc")))
rdb = Extension(config.root + '.rdbcore',
define_macros=config.macros(),
include_dirs=[_rdb_path, _tl_path, _gsi_path, _pya_path],
extra_objects=[config.path_of('_rdb', _rdb_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_pya', _pya_path)],
extra_link_args=config.link_args('rdbcore'),
extra_compile_args=config.compile_args('rdbcore'),
sources=list(rdb_sources))
rdb = Extension(
config.root + ".rdbcore",
define_macros=config.macros(),
include_dirs=[_rdb_path, _tl_path, _gsi_path, _pya_path],
extra_objects=[
config.path_of("_rdb", _rdb_path),
config.path_of("_tl", _tl_path),
config.path_of("_gsi", _gsi_path),
config.path_of("_pya", _pya_path),
],
extra_link_args=config.link_args("rdbcore"),
extra_compile_args=config.compile_args("rdbcore"),
sources=list(rdb_sources),
)
# ------------------------------------------------------------------
# lay extension library
@ -737,28 +903,34 @@ lay = Extension(config.root + '.laycore',
# ------------------------------------------------------------------
# Core setup function
if __name__ == '__main__':
setup(name=config.root,
version=config.version(),
license='GNU GPLv3',
description='KLayout standalone Python package',
long_description='This package is a standalone distribution of KLayout\'s Python API.\n\nFor more details see here: https://www.klayout.org/klayout-pypi',
author='Matthias Koefferlein',
author_email='matthias@klayout.de',
classifiers=[
# Recommended classifiers
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
# Optional classifiers
"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
],
url='https://github.com/klayout/klayout',
packages=find_packages('src/pymod/distutils_src'),
package_dir={'': 'src/pymod/distutils_src'}, # https://github.com/pypa/setuptools/issues/230
package_data={config.root: ["src/pymod/distutils_src/klayout/*.pyi"]},
include_package_data=True,
ext_modules=[_tl, _gsi, _pya, _rba, _db, _lib, _rdb, _lym, _laybasic, _layview, _ant, _edt, _img] + db_plugins + [tl, db, lib, rdb, lay])
if __name__ == "__main__":
setup(
name=config.root,
version=config.version(),
license="GNU GPLv3",
description="KLayout standalone Python package",
long_description="This package is a standalone distribution of KLayout's Python API.\n\nFor more details see here: https://www.klayout.org/klayout-pypi",
author="Matthias Koefferlein",
author_email="matthias@klayout.de",
classifiers=[
# Recommended classifiers
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
# Optional classifiers
"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
],
url="https://github.com/klayout/klayout",
packages=find_packages("src/pymod/distutils_src"),
package_dir={
"": "src/pymod/distutils_src"
}, # https://github.com/pypa/setuptools/issues/230
package_data={config.root: ["src/pymod/distutils_src/klayout/*.pyi"]},
include_package_data=True,
ext_modules=[_tl, _gsi, _pya, _rba, _db, _lib, _rdb, _lym, _laybasic, _layview, _ant, _edt, _img]
+ db_plugins
+ [tl, db, lib, rdb, lay])
)

View File

@ -36,7 +36,7 @@ namespace gsi
// db::Library binding
/**
* @brief A basic implementation of the library
* @brief A basic implementation of the library
*/
static db::Library *new_lib ()
{
@ -172,15 +172,15 @@ LibraryClass decl_Library ("db", "Library",
"\n"
"This method has been introduced in version 0.25.\n"
) +
gsi::method ("name", &db::Library::get_name,
gsi::method ("name", &db::Library::get_name,
"@brief Returns the libraries' name\n"
"The name is set when the library is registered and cannot be changed\n"
) +
gsi::method ("id", &db::Library::get_id,
gsi::method ("id", &db::Library::get_id,
"@brief Returns the library's ID\n"
"The ID is set when the library is registered and cannot be changed \n"
) +
gsi::method ("description", &db::Library::get_description,
gsi::method ("description", &db::Library::get_description,
"@brief Returns the libraries' description text\n"
) +
gsi::method ("description=", &db::Library::set_description, gsi::arg ("description"),
@ -231,7 +231,7 @@ LibraryClass decl_Library ("db", "Library",
gsi::method ("layout_const", (const db::Layout &(db::Library::*)() const) &db::Library::layout,
"@brief The layout object where the cells reside that this library defines (const version)\n"
) +
gsi::method ("layout", (db::Layout &(db::Library::*)()) &db::Library::layout,
gsi::method ("layout", (db::Layout &(db::Library::*)()) &db::Library::layout,
"@brief The layout object where the cells reside that this library defines\n"
) +
gsi::method ("refresh", &db::Library::refresh,
@ -303,7 +303,7 @@ class PCellDeclarationImpl
: public db::PCellDeclaration
{
public:
// dummy implementation to provide the signature
// dummy implementation to provide the signature
virtual std::vector<db::LayerProperties> get_layer_declarations_impl (const db::pcell_parameters_type &) const
{
return std::vector<db::LayerProperties> ();
@ -340,7 +340,7 @@ public:
}
}
// dummy implementation to provide the signature
// dummy implementation to provide the signature
virtual db::pcell_parameters_type coerce_parameters_impl (const db::Layout & /*layout*/, const db::pcell_parameters_type &input) const
{
return input;
@ -472,7 +472,7 @@ Class<PCellDeclarationImpl> decl_PCellDeclaration (decl_PCellDeclaration_Native,
"This method receives the PCell parameters which allows it to deduce layers\n"
"from the parameters."
) +
gsi::callback ("get_parameters", &PCellDeclarationImpl::get_parameter_declarations, &PCellDeclarationImpl::cb_get_parameter_declarations,
gsi::callback ("get_parameters", &PCellDeclarationImpl::get_parameter_declarations, &PCellDeclarationImpl::cb_get_parameter_declarations,
"@brief Returns a list of parameter declarations\n"
"Reimplement this method to return a list of parameters used in that PCell \n"
"implementation. A parameter declaration is a PCellParameterDeclaration object\n"
@ -691,33 +691,33 @@ Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCel
"@param default The default (initial) value\n"
"@param unit The unit string\n"
) +
gsi::method ("name", &db::PCellParameterDeclaration::get_name,
gsi::method ("name", &db::PCellParameterDeclaration::get_name,
"@brief Gets the name\n"
) +
gsi::method ("name=", &db::PCellParameterDeclaration::set_name, gsi::arg ("value"),
"@brief Sets the name\n"
) +
gsi::method ("unit", &db::PCellParameterDeclaration::get_unit,
gsi::method ("unit", &db::PCellParameterDeclaration::get_unit,
"@brief Gets the unit string\n"
) +
gsi::method ("unit=", &db::PCellParameterDeclaration::set_unit, gsi::arg ("unit"),
"@brief Sets the unit string\n"
"The unit string is shown right to the edit fields for numeric parameters.\n"
) +
gsi::method_ext ("type", &get_type,
gsi::method_ext ("type", &get_type,
"@brief Gets the type\n"
"The type is one of the T... constants."
) +
gsi::method_ext ("type=", &set_type, gsi::arg ("type"),
"@brief Sets the type\n"
) +
gsi::method ("description", &db::PCellParameterDeclaration::get_description,
gsi::method ("description", &db::PCellParameterDeclaration::get_description,
"@brief Gets the description text\n"
) +
gsi::method ("description=", &db::PCellParameterDeclaration::set_description, gsi::arg ("description"),
"@brief Sets the description\n"
) +
gsi::method ("hidden?", &db::PCellParameterDeclaration::is_hidden,
gsi::method ("hidden?", &db::PCellParameterDeclaration::is_hidden,
"@brief Returns true, if the parameter is a hidden parameter that should not be shown in the user interface\n"
"By making a parameter hidden, it is possible to create internal parameters which cannot be\n"
"edited.\n"
@ -725,7 +725,7 @@ Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCel
gsi::method ("hidden=", &db::PCellParameterDeclaration::set_hidden, gsi::arg ("flag"),
"@brief Makes the parameter hidden if this attribute is set to true\n"
) +
gsi::method ("readonly?", &db::PCellParameterDeclaration::is_readonly,
gsi::method ("readonly?", &db::PCellParameterDeclaration::is_readonly,
"@brief Returns true, if the parameter is a read-only parameter\n"
"By making a parameter read-only, it is shown but cannot be\n"
"edited.\n"
@ -733,7 +733,7 @@ Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCel
gsi::method ("readonly=", &db::PCellParameterDeclaration::set_readonly, gsi::arg ("flag"),
"@brief Makes the parameter read-only if this attribute is set to true\n"
) +
gsi::method_ext ("clear_choices", &clear_choices,
gsi::method_ext ("clear_choices", &clear_choices,
"@brief Clears the list of choices\n"
) +
gsi::method_ext ("add_choice", &add_choice, gsi::arg ("description"), gsi::arg ("value"),
@ -742,13 +742,13 @@ Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCel
"choices. If choices are defined, KLayout will show a drop-down box instead of an\n"
"entry field in the parameter user interface.\n"
) +
gsi::method ("choice_values", &db::PCellParameterDeclaration::get_choices,
gsi::method ("choice_values", &db::PCellParameterDeclaration::get_choices,
"@brief Returns a list of choice values\n"
) +
gsi::method ("choice_descriptions", &db::PCellParameterDeclaration::get_choice_descriptions,
gsi::method ("choice_descriptions", &db::PCellParameterDeclaration::get_choice_descriptions,
"@brief Returns a list of choice descriptions\n"
) +
gsi::method ("default", &db::PCellParameterDeclaration::get_default,
gsi::method ("default", &db::PCellParameterDeclaration::get_default,
"@brief Gets the default value\n"
) +
gsi::method ("default=", &db::PCellParameterDeclaration::set_default, gsi::arg ("value"),
@ -763,7 +763,7 @@ Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCel
gsi::method ("TypeList", &pd_type_list, "@brief Type code: a list of variants") +
gsi::method ("TypeLayer", &pd_type_layer, "@brief Type code: a layer (a \\LayerInfo object)") +
gsi::method ("TypeShape", &pd_type_shape, "@brief Type code: a guiding shape (Box, Edge, Point, Polygon or Path)") +
gsi::method ("TypeNone", &pd_type_none, "@brief Type code: unspecific type")
gsi::method ("TypeNone", &pd_type_none, "@brief Type code: unspecific type")
,
"@brief A PCell parameter declaration\n"
"\n"
@ -776,4 +776,3 @@ Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCel
);
}

View File

@ -33,7 +33,7 @@ namespace gsi
// point binding
template <class C>
struct point_defs
struct point_defs
{
typedef typename C::coord_type coord_type;
@ -141,6 +141,14 @@ struct point_defs
"\n"
"Starting with version 0.25, this method renders a vector."
) +
method ("-", (C (C::*) (const db::vector<coord_type> &) const) &C::subtract, gsi::arg ("v"),
"@brief Subtract one vector from a point\n"
"\n"
"\n"
"Subtract vector v from from self by subtracting the coordinates. This renders a point.\n"
"\n"
"This method has been added in version 0.27."
) +
method ("<", &C::less, gsi::arg ("p"),
"@brief \"less\" comparison operator\n"
"\n"

View File

@ -752,7 +752,7 @@ extern Class<db::ShapeCollection> decl_dbShapeCollection;
Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
constructor ("new", &new_v,
constructor ("new", &new_v,
"@brief Default constructor\n"
"\n"
"This constructor creates an empty region.\n"
@ -798,8 +798,8 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@code\n"
"layout = ... # a layout\n"
"cell = ... # the index of the initial cell\n"
"layer = ... # the index of the layer from where to take the shapes from\n"
"cell = ... # the index of the initial cell\n"
"layer = ... # the index of the layer from where to take the shapes from\n"
"r = RBA::Region::new(layout.begin_shapes(cell, layer))\n"
"@/code\n"
) +
@ -814,8 +814,8 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@code\n"
"layout = ... # a layout\n"
"cell = ... # the index of the initial cell\n"
"layer = ... # the index of the layer from where to take the shapes from\n"
"cell = ... # the index of the initial cell\n"
"layer = ... # the index of the layer from where to take the shapes from\n"
"dbu = 0.1 # the target database unit\n"
"r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
"@/code\n"
@ -925,11 +925,11 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"as single regions and artificial edges such as cut-lines will not be considered.\n"
"Merged semantics thus is equivalent to considering coherent areas rather than\n"
"single polygons\n"
) +
) +
method ("merged_semantics?", &db::Region::merged_semantics,
"@brief Gets a flag indicating whether merged semantics is enabled\n"
"See \\merged_semantics= for a description of this attribute.\n"
) +
) +
method ("strict_handling=", &db::Region::set_strict_handling, gsi::arg ("f"),
"@brief Enables or disables strict handling\n"
"\n"
@ -941,7 +941,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"Strict handling is disabled by default and optimization is in place.\n"
"\n"
"This method has been introduced in version 0.23.2."
) +
) +
method ("strict_handling?", &db::Region::strict_handling,
"@brief Gets a flag indicating whether merged semantics is enabled\n"
"See \\strict_handling= for a description of this attribute.\n"
@ -957,11 +957,11 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"created which touch at a corner).\n"
"\n"
"The default setting is maximum coherence (min_coherence = false).\n"
) +
) +
method ("min_coherence?", &db::Region::min_coherence,
"@brief Gets a flag indicating whether minimum coherence is selected\n"
"See \\min_coherence= for a description of this attribute.\n"
) +
) +
method_ext ("complex_op", &complex_op, gsi::arg ("node"),
"@brief Executes a complex operation (see \\CompoundRegionOperationNode for details)\n"
"\n"
@ -1337,7 +1337,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"of these boxes for example.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method_ext ("extents", &extents1, gsi::arg ("d"),
"@brief Returns a region with the enlarged bounding boxes of the polygons\n"
"This method will return a region consisting of the bounding boxes of the polygons enlarged by the given distance d.\n"
@ -1346,7 +1346,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"of these boxes for example.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method_ext ("extents", &extents2, gsi::arg ("dx"), gsi::arg ("dy"),
"@brief Returns a region with the enlarged bounding boxes of the polygons\n"
"This method will return a region consisting of the bounding boxes of the polygons enlarged by the given distance dx in x direction and dy in y direction.\n"
@ -1355,7 +1355,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"of these boxes for example.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method_ext ("extent_refs", &extent_refs,
"@hide\n"
"This method is provided for DRC implementation.\n"
@ -1589,7 +1589,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"This method returns the sized region (see \\size), but does not modify self.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method_ext ("andnot", &andnot, gsi::arg ("other"),
"@brief Returns the boolean AND and NOT between self and the other region\n"
"\n"
@ -1607,7 +1607,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method will compute the boolean AND (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
) +
method ("&=", &db::Region::operator&=, gsi::arg ("other"),
"@brief Performs the boolean AND between self and the other region\n"
"\n"
@ -1615,7 +1615,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method will compute the boolean AND (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
) +
method ("-", &db::Region::operator-, gsi::arg ("other"),
"@brief Returns the boolean NOT between self and the other region\n"
"\n"
@ -1623,7 +1623,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method will compute the boolean NOT (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
) +
method ("-=", &db::Region::operator-=, gsi::arg ("other"),
"@brief Performs the boolean NOT between self and the other region\n"
"\n"
@ -1631,15 +1631,15 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method will compute the boolean NOT (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
) +
method ("^", &db::Region::operator^, gsi::arg ("other"),
"@brief Returns the boolean NOT between self and the other region\n"
"@brief Returns the boolean XOR between self and the other region\n"
"\n"
"@return The result of the boolean XOR operation\n"
"\n"
"This method will compute the boolean XOR (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
) +
method ("^=", &db::Region::operator^=, gsi::arg ("other"),
"@brief Performs the boolean XOR between self and the other region\n"
"\n"
@ -1647,7 +1647,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method will compute the boolean XOR (intersection) between two regions. "
"The result is often but not necessarily always merged.\n"
) +
) +
method ("\\|", &db::Region::operator|, gsi::arg ("other"),
"@brief Returns the boolean OR between self and the other region\n"
"\n"
@ -1655,7 +1655,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"The boolean OR is implemented by merging the polygons of both regions. To simply join the regions "
"without merging, the + operator is more efficient."
) +
) +
method ("\\|=", &db::Region::operator|=, gsi::arg ("other"),
"@brief Performs the boolean OR between self and the other region\n"
"\n"
@ -1663,7 +1663,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"The boolean OR is implemented by merging the polygons of both regions. To simply join the regions "
"without merging, the + operator is more efficient."
) +
) +
method ("+", &db::Region::operator+, gsi::arg ("other"),
"@brief Returns the combined region of self and the other region\n"
"\n"
@ -1671,7 +1671,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This operator adds the polygons of the other region to self and returns a new combined region. "
"This usually creates unmerged regions and polygons may overlap. Use \\merge if you want to ensure the result region is merged.\n"
) +
) +
method ("+=", &db::Region::operator+=, gsi::arg ("other"),
"@brief Adds the polygons of the other region to self\n"
"\n"
@ -1679,7 +1679,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This operator adds the polygons of the other region to self. "
"This usually creates unmerged regions and polygons may overlap. Use \\merge if you want to ensure the result region is merged.\n"
) +
) +
method ("covering", &db::Region::selected_enclosing, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which are completely covering polygons from the other region\n"
"\n"
@ -1740,14 +1740,14 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@return A new region containing the polygons which are inside polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method ("not_inside", &db::Region::selected_not_inside, gsi::arg ("other"),
"@brief Returns the polygons of this region which are not completely inside polygons from the other region\n"
"\n"
"@return A new region containing the polygons which are not inside polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method_ext ("split_inside", &split_inside, gsi::arg ("other"),
"@brief Returns the polygons of this region which are completely inside polygons from the other region and the ones which are not at the same time\n"
"\n"
@ -1764,28 +1764,28 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method ("select_not_inside", &db::Region::select_not_inside, gsi::arg ("other"),
"@brief Selects the polygons of this region which are not completely inside polygons from the other region\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method ("outside", &db::Region::selected_outside, gsi::arg ("other"),
"@brief Returns the polygons of this region which are completely outside polygons from the other region\n"
"\n"
"@return A new region containing the polygons which are outside polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method ("not_outside", &db::Region::selected_not_outside, gsi::arg ("other"),
"@brief Returns the polygons of this region which are not completely outside polygons from the other region\n"
"\n"
"@return A new region containing the polygons which are not outside polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method_ext ("split_outside", &split_outside, gsi::arg ("other"),
"@brief Returns the polygons of this region which are completely outside polygons from the other region and the ones which are not at the same time\n"
"\n"
@ -1802,14 +1802,14 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method ("select_not_outside", &db::Region::select_not_outside, gsi::arg ("other"),
"@brief Selects the polygons of this region which are not completely outside polygons from the other region\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
method ("interacting", (db::Region (db::Region::*) (const db::Region &, size_t, size_t) const) &db::Region::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which overlap or touch polygons from the other region\n"
"\n"
@ -2020,7 +2020,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The count options have been introduced in version 0.27."
) +
) +
method ("not_overlapping", &db::Region::selected_not_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which do not overlap polygons from the other region\n"
"\n"
@ -2129,7 +2129,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"possibilities of the edge collection.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
) +
factory_ext ("decompose_convex", &decompose_convex<db::Shapes>, gsi::arg ("preferred_orientation", po_any (), "\\Polygon#PO_any"),
"@brief Decomposes the region into convex pieces.\n"
"\n"
@ -2166,7 +2166,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
method ("swap", &db::Region::swap, gsi::arg ("other"),
"@brief Swap the contents of this region with the contents of another region\n"
"This method is useful to avoid excessive memory allocation in some cases. "
"For managed memory languages such as Ruby, those cases will be rare. "
"For managed memory languages such as Ruby, those cases will be rare. "
) +
method ("holes", &db::Region::holes,
"@brief Returns the holes of the region\n"
@ -3099,4 +3099,3 @@ gsi::EnumIn<db::Region, db::OppositeFilter> decl_Region_OppositeFilter ("db", "O
gsi::ClassExt<db::Region> inject_OppositeFilter_in_parent (decl_Region_OppositeFilter.defs ());
}

View File

@ -246,6 +246,12 @@ struct vector_defs
"\n"
"The scalar product of a and b is defined as: vp = ax*bx+ay*by.\n"
) +
method_ext ("*", &sprod, gsi::arg ("v"),
"@brief Computes the scalar product between self and the given vector\n"
"\n"
"\n"
"The scalar product of a and b is defined as: vp = ax*bx+ay*by.\n"
) +
method_ext ("sprod_sign", &sprod_sign, gsi::arg ("v"),
"@brief Computes the scalar product between self and the given vector and returns a value indicating the sign of the product\n"
"\n"

View File

@ -68,7 +68,7 @@ namespace pya
} catch (...) { \
if (PythonInterpreter::instance ()) { PythonInterpreter::instance ()->end_execution (); } \
throw; \
}
}
/**
* @brief A class encapsulating a python exception
@ -92,7 +92,7 @@ class PYA_PUBLIC PythonInterpreter
{
public:
/**
* @brief The constructor
* @brief The constructor
*
* If embedded is true, the interpreter is an embedded one. Only in this case, the
* Python interpreter is initialized. Otherwise, it is assumed the interpreter
@ -101,7 +101,7 @@ public:
PythonInterpreter (bool embedded = true);
/**
* @brief The destructor
* @brief The destructor
*/
~PythonInterpreter ();
@ -160,10 +160,10 @@ public:
* @brief Implementation of gsi::Interpreter::eval_expr
*/
tl::Variant eval_expr (const char *string, const char *filename = 0, int line = 1, int context = -1);
/**
* @brief Implementation of gsi::Interpreter::eval_string_and_print
*/
*/
void eval_string_and_print (const char *string, const char *filename = 0, int line = 1, int context = -1);
/**
@ -172,7 +172,7 @@ public:
virtual gsi::Inspector *inspector (int context = -1);
/**
* @brief Defines a global variable with the given name and value
* @brief Defines a global variable with the given name and value
*/
void define_variable (const std::string &name, const tl::Variant &value);
@ -284,4 +284,3 @@ private:
}
#endif

View File

@ -45,14 +45,14 @@ long python2c_func<long>::operator() (PyObject *rval)
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
return PyInt_AsLong (rval);
} else
} else
#endif
if (PyLong_Check (rval)) {
return PyLong_AsLong (rval);
} else if (PyFloat_Check (rval)) {
return (long) (PyFloat_AsDouble (rval));
} else {
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to an integer")));
throw tl::TypeError (tl::to_string (tr ("Value cannot be converted to an integer")));
}
}
@ -68,14 +68,14 @@ char python2c_func<char>::operator() (PyObject *rval)
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
return char (PyInt_AsLong (rval));
} else
} else
#endif
if (PyLong_Check (rval)) {
return char (PyLong_AsLong (rval));
} else if (PyFloat_Check (rval)) {
return char (PyFloat_AsDouble (rval));
} else {
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to a character")));
throw tl::TypeError (tl::to_string (tr ("Value cannot be converted to a character")));
}
}
@ -85,14 +85,14 @@ unsigned long python2c_func<unsigned long>::operator() (PyObject *rval)
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
return PyInt_AsUnsignedLongMask (rval);
} else
} else
#endif
if (PyLong_Check (rval)) {
return PyLong_AsUnsignedLongMask (rval);
} else if (PyFloat_Check (rval)) {
return (unsigned long) (PyFloat_AsDouble (rval));
} else {
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to an integer")));
throw tl::TypeError (tl::to_string (tr ("Value cannot be converted to an integer")));
}
}
@ -102,14 +102,14 @@ long long python2c_func<long long>::operator() (PyObject *rval)
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
return PyInt_AsLong (rval);
} else
} else
#endif
if (PyLong_Check (rval)) {
return PyLong_AsLongLong (rval);
} else if (PyFloat_Check (rval)) {
return (long long) (PyFloat_AsDouble (rval));
} else {
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to an integer")));
throw tl::TypeError (tl::to_string (tr ("Value cannot be converted to an integer")));
}
}
@ -119,14 +119,14 @@ unsigned long long python2c_func<unsigned long long>::operator() (PyObject *rval
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
return PyInt_AsUnsignedLongMask (rval);
} else
} else
#endif
if (PyLong_Check (rval)) {
return PyLong_AsUnsignedLongLongMask (rval);
} else if (PyFloat_Check (rval)) {
return (unsigned long long) (PyFloat_AsDouble (rval));
} else {
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to an integer")));
throw tl::TypeError (tl::to_string (tr ("Value cannot be converted to an integer")));
}
}
@ -138,14 +138,14 @@ __int128 python2c_func<__int128>::operator() (PyObject *rval)
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
return PyInt_AsLong (rval);
} else
} else
#endif
if (PyLong_Check (rval)) {
return PyLong_AsLongLong (rval);
} else if (PyFloat_Check (rval)) {
return PyFloat_AsDouble (rval);
} else {
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to an integer")));
throw tl::TypeError (tl::to_string (tr ("Value cannot be converted to an integer")));
}
}
#endif
@ -156,14 +156,14 @@ double python2c_func<double>::operator() (PyObject *rval)
#if PY_MAJOR_VERSION < 3
if (PyInt_Check (rval)) {
return PyInt_AsLong (rval);
} else
} else
#endif
if (PyLong_Check (rval)) {
return PyLong_AsLongLong (rval);
} else if (PyFloat_Check (rval)) {
return PyFloat_AsDouble (rval);
} else {
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to a floating-point value")));
throw tl::TypeError (tl::to_string (tr ("Value cannot be converted to a floating-point value")));
}
}
@ -173,11 +173,11 @@ std::string python2c_func<std::string>::operator() (PyObject *rval)
#if PY_MAJOR_VERSION < 3
if (PyString_Check (rval)) {
return std::string (PyString_AsString (rval), PyString_Size (rval));
} else
} else
#else
if (PyBytes_Check (rval)) {
return std::string (PyBytes_AsString (rval), PyBytes_Size (rval));
} else
} else
#endif
if (PyUnicode_Check (rval)) {
PythonRef ba (PyUnicode_AsUTF8String (rval));
@ -188,7 +188,7 @@ std::string python2c_func<std::string>::operator() (PyObject *rval)
} else if (PyByteArray_Check (rval)) {
return std::string (PyByteArray_AsString (rval), PyByteArray_Size (rval));
} else {
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to a string")));
throw tl::TypeError (tl::to_string (tr ("Value cannot be converted to a string")));
}
}
@ -224,7 +224,7 @@ std::vector<char> python2c_func<std::vector<char> >::operator() (PyObject *rval)
Py_ssize_t sz = PyByteArray_Size (rval);
return std::vector<char> (cp, cp + sz);
} else {
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to a byte array")));
throw tl::TypeError (tl::to_string (tr ("Value cannot be converted to a byte array")));
}
}
@ -235,11 +235,11 @@ QByteArray python2c_func<QByteArray>::operator() (PyObject *rval)
#if PY_MAJOR_VERSION < 3
if (PyString_Check (rval)) {
return QByteArray (PyString_AsString (rval), PyString_Size (rval));
} else
} else
#else
if (PyBytes_Check (rval)) {
return QByteArray (PyBytes_AsString (rval), PyBytes_Size (rval));
} else
} else
#endif
if (PyUnicode_Check (rval)) {
PythonRef ba (PyUnicode_AsUTF8String (rval));
@ -250,7 +250,7 @@ QByteArray python2c_func<QByteArray>::operator() (PyObject *rval)
} else if (PyByteArray_Check (rval)) {
return QByteArray (PyByteArray_AsString (rval), PyByteArray_Size (rval));
} else {
throw tl::Exception (tl::to_string (tr ("Value cannot be converted to a byte array")));
throw tl::TypeError (tl::to_string (tr ("Value cannot be converted to a byte array")));
}
}
@ -325,13 +325,13 @@ tl::Variant python2c_func<tl::Variant>::operator() (PyObject *rval)
return r;
} else {
const gsi::ClassBase *cls = PythonModule::cls_for_type (Py_TYPE (rval));
if (cls) {
PYAObjectBase *p = PYAObjectBase::from_pyobject (rval);
// employ the tl::Variant binding capabilities of the Expression binding to derive the
// employ the tl::Variant binding capabilities of the Expression binding to derive the
// variant value.
void *obj = p->obj ();
@ -519,7 +519,7 @@ PyObject *c2python_func<const tl::Variant &>::operator() (const tl::Variant &c)
PyDict_SetItem (ret, c2python (i->first), c2python (i->second));
}
return ret;
} else if (c.is_list ()) {
PyObject *ret = PyList_New (c.get_list ().size ());
@ -619,4 +619,3 @@ PyObject *c2python_func<const QString &>::operator() (const QString &qs)
#endif
}

View File

@ -469,7 +469,7 @@ struct writer<gsi::ObjectType>
const gsi::ClassBase *cls_decl = PythonModule::cls_for_type (Py_TYPE (arg));
if (! cls_decl) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s, got %s)")), atype.cls ()->name (), Py_TYPE (arg)->tp_name));
throw tl::TypeError (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s, got %s)")), atype.cls ()->name (), Py_TYPE (arg)->tp_name));
}
if (cls_decl->is_derived_from (atype.cls ())) {
@ -494,14 +494,14 @@ struct writer<gsi::ObjectType>
aa->write<void *> (new_obj);
} else {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s, got %s)")), atype.cls ()->name (), cls_decl->name ()));
throw tl::TypeError (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s, got %s)")), atype.cls ()->name (), cls_decl->name ()));
}
} else {
const gsi::ClassBase *cls_decl = PythonModule::cls_for_type (Py_TYPE (arg));
if (! cls_decl) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s, got %s)")), atype.cls ()->name (), Py_TYPE (arg)->tp_name));
throw tl::TypeError (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s, got %s)")), atype.cls ()->name (), Py_TYPE (arg)->tp_name));
}
if (cls_decl->is_derived_from (atype.cls ())) {
@ -521,7 +521,7 @@ struct writer<gsi::ObjectType>
aa->write<void *> (atype.cls ()->create_obj_from (cls_decl, p->obj ()));
} else {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s, got %s)")), atype.cls ()->name (), cls_decl->name ()));
throw tl::TypeError (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s, got %s)")), atype.cls ()->name (), cls_decl->name ()));
}
}

View File

@ -43,7 +43,7 @@ class PYAObjectBase;
* @param arg The argument to serialize (a Python object)
* @param heap A heap for temporary objects
*
* The heap collects objects created while filling the buffer.
* The heap collects objects created while filling the buffer.
* The stack must persist as long as the serial buffer is used.
*/
void
@ -84,4 +84,3 @@ void correct_constness (PyObject *obj, bool const_required);
}
#endif

View File

@ -920,7 +920,7 @@ match_method (int mid, PyObject *self, PyObject *args, bool strict)
if (! strict) {
return 0;
} else {
throw tl::Exception (tl::to_string (tr ("No overload with matching arguments")));
throw tl::TypeError (tl::to_string (tr ("No overload with matching arguments")));
}
}
@ -928,7 +928,7 @@ match_method (int mid, PyObject *self, PyObject *args, bool strict)
if (! strict) {
return 0;
} else {
throw tl::Exception (tl::to_string (tr ("Ambiguous overload variants - multiple method declarations match arguments")));
throw tl::TypeError (tl::to_string (tr ("Ambiguous overload variants - multiple method declarations match arguments")));
}
}
@ -2734,10 +2734,26 @@ public:
alt_names.push_back ("__iter__");
} else if (name == "__mul__") {
// Adding right multiplication
// Rationale: if pyaObj * x works, so should x * pyaObj
mp_module->add_python_doc (*cls, mt, int (mid), tl::to_string (tr ("This method is also available as '__mul__'")));
alt_names.push_back ("__rmul__");
// Adding right multiplication
// Rationale: if pyaObj * x works, so should x * pyaObj
// But this should only apply if the multiplication is commutative
// There are a few exceptions like Trans * Trans, so we support this case only if
// the second argument is double (scaling).
gsi::ArgType double_argtype;
double_argtype.template init<double> ();
if (m_first->arg (0) == double_argtype) {
add_python_doc (**c, mt, int (mid), tl::to_string (tr ("This method is also available as '__rmul__'")));
alt_names.push_back ("__rmul__");
}
} else if (name == "dup" && m_first->compatible_with_num_args (0) ) {
// If the object supports the dup method, then it is a good
// idea to define the __copy__ method.
add_python_doc (**c, mt, int (mid), tl::to_string (tr ("This method also implements '__copy__'")));
alt_names.push_back ("__copy__");
}
for (std::vector <std::string>::const_iterator an = alt_names.begin (); an != alt_names.end (); ++an) {
@ -2901,11 +2917,13 @@ public:
PyObject *attr_class = PyObject_GetAttrString ((PyObject *) type, ("_class_" + *a).c_str ());
if (attr_inst == NULL || attr_class == NULL) {
// some error or disambiguator is not required -> don't install it
// some error -> don't install the disambiguator
Py_XDECREF (attr_inst);
Py_XDECREF (attr_class);
PyErr_Clear ();
tl::warn << "Unable to install a static/non-static disambiguator for " << *a << " in class " << (*c)->name ();
} else {
PyObject *desc = PYAAmbiguousMethodDispatcher::create (attr_inst, attr_class);

View File

@ -43,6 +43,10 @@ namespace pya
} catch (std::exception &ex) { \
std::string msg = std::string(ex.what ()) + tl::to_string (tr (" in ")) + (where); \
PyErr_SetString (PyExc_RuntimeError, msg.c_str ()); \
} catch (tl::TypeError &ex) { \
std::string msg; \
msg = ex.msg () + tl::to_string (tr (" in ")) + (where); \
PyErr_SetString (PyExc_TypeError, msg.c_str ()); \
} catch (tl::Exception &ex) { \
std::string msg; \
msg = ex.msg () + tl::to_string (tr (" in ")) + (where); \
@ -73,4 +77,3 @@ void check_error ();
}
#endif

View File

@ -1,6 +1,79 @@
import functools
from typing import Type
import klayout.dbcore
from klayout.dbcore import *
from klayout.db.pcell_declaration_helper import PCellDeclarationHelper
__all__ = klayout.dbcore.__all__ + ['PCellDeclarationHelper']
__all__ = klayout.dbcore.__all__ + ["PCellDeclarationHelper"] # type: ignore
# Implementing deepcopy of common objects
# Point-like classes
PointLike = (Point, DPoint, DVector, Vector)
def pyaPoint__deepcopy__(self, memo):
return self.dup()
def convert_type_error_to_not_implemented(cls, method):
"""If cls.method exists raises a TypeError, patch it so
it returns a NotImplemented error instead.
"""
if not hasattr(cls, method):
return
old_func = getattr(cls, method)
@functools.wraps(old_func)
def new_func(*args, **kwargs):
try:
return old_func(*args, **kwargs)
except TypeError:
return NotImplemented
try:
setattr(cls, method, new_func)
except TypeError:
# Some classes are immutable and cannot be changed.
# At the time of writing, this happens to (_StaticAttribute, _AmbiguousMethodDispatcher, _Iterator, _Signal).__or__
return
for PClass in PointLike:
PClass.__deepcopy__ = pyaPoint__deepcopy__ # type: ignore
for cls in klayout.dbcore.__dict__.values():
if not isinstance(cls, type): # skip if not a class
continue
for method in (
"__add__",
"__sub__",
"__mul__",
"__matmul__",
"__truediv__",
"__floordiv__",
"__mod__",
"__divmod__",
"__pow__",
"__lshift__",
"__rshift__",
"__and__",
"__xor__",
"__or__",
):
# list of methods extracted from https://docs.python.org/3.7/reference/datamodel.html#emulating-numeric-types
convert_type_error_to_not_implemented(cls, method)
# If class has from_s, to_s, and assign, use them to
# enable serialization.
for name, cls in klayout.dbcore.__dict__.items():
if not isinstance(cls, type):
continue
if hasattr(cls, 'from_s') and hasattr(cls, 'to_s') and hasattr(cls, 'assign'):
cls.__getstate__ = cls.to_s # type: ignore
def _setstate(self, str):
cls = self.__class__
self.assign(cls.from_s(str))
cls.__setstate__ = _setstate # type: ignore

View File

@ -63,7 +63,17 @@ class _PCellDeclarationHelper(PCellDeclaration):
self.layer = None
self.cell = None
def param(self, name, value_type, description, hidden=False, readonly=False, unit=None, default=None, choices=None):
def param(
self,
name,
value_type,
description,
hidden=False,
readonly=False,
unit=None,
default=None,
choices=None,
):
"""
Defines a parameter
name -> the short name of the parameter
@ -84,11 +94,16 @@ class _PCellDeclarationHelper(PCellDeclaration):
# create accessor methods for the parameters
param_index = len(self._param_decls)
setattr(type(self), name, _PCellDeclarationHelperParameterDescriptor(param_index))
setattr(
type(self), name, _PCellDeclarationHelperParameterDescriptor(param_index)
)
if value_type == type(self).TypeLayer:
setattr(type(self), name + "_layer",
_PCellDeclarationHelperLayerDescriptor(len(self._layer_param_index)))
setattr(
type(self),
name + "_layer",
_PCellDeclarationHelperLayerDescriptor(len(self._layer_param_index)),
)
self._layer_param_index.append(param_index)
# store the parameter declarations
@ -104,10 +119,16 @@ class _PCellDeclarationHelper(PCellDeclaration):
pdecl.unit = unit
if not (choices is None):
if not isinstance(choices, list) and not isinstance(choices, tuple):
raise Exception("choices value must be an list/tuple of two-element arrays (description, value)")
raise Exception(
"choices value must be an list/tuple of two-element arrays (description, value)"
)
for c in choices:
if (not isinstance(choices, list) and not isinstance(choices, tuple)) or len(c) != 2:
raise Exception("choices value must be an list/tuple of two-element arrays (description, value)")
if (
not isinstance(choices, list) and not isinstance(choices, tuple)
) or len(c) != 2:
raise Exception(
"choices value must be an list/tuple of two-element arrays (description, value)"
)
pdecl.add_choice(c[0], c[1])
# return the declaration object for further operations

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
from typing import Any, ClassVar, Dict, Iterable, Optional
from typing import Any, ClassVar, Dict, Sequence, List, Iterator, Optional
from typing import overload
import klayout.db as db
class RdbReference:
@ -19,6 +19,10 @@ class RdbReference:
@return The transformation
@brief Sets the transformation for this reference
"""
def __copy__(self) -> RdbReference:
r"""
@brief Creates a copy of self
"""
def __init__(self, trans: db.DCplxTrans, parent_cell_id: int) -> None:
r"""
@brief Creates a reference with a given transformation and parent cell ID
@ -136,13 +140,13 @@ class RdbCell:
This method has been introduced in version 0.23.
"""
def each_item(self) -> Iterable[RdbItem]:
def each_item(self) -> Iterator[RdbItem]:
r"""
@brief Iterates over all items inside the database which are associated with this cell
This method has been introduced in version 0.23.
"""
def each_reference(self) -> Iterable[RdbReference]:
def each_reference(self) -> Iterator[RdbReference]:
r"""
@brief Iterates over all references
"""
@ -236,13 +240,13 @@ class RdbCategory:
This method has been introduced in version 0.23.
"""
def each_item(self) -> Iterable[RdbItem]:
def each_item(self) -> Iterator[RdbItem]:
r"""
@brief Iterates over all items inside the database which are associated with this category
This method has been introduced in version 0.23.
"""
def each_sub_category(self) -> Iterable[RdbCategory]:
def each_sub_category(self) -> Iterator[RdbCategory]:
r"""
@brief Iterates over all sub-categories
"""
@ -368,6 +372,10 @@ class RdbItemValue:
This variant has been introduced in version 0.24
"""
def __copy__(self) -> RdbItemValue:
r"""
@brief Creates a copy of self
"""
@overload
def __init__(self, b: db.DBox) -> None:
r"""
@ -414,6 +422,12 @@ class RdbItemValue:
This method has been introduced in version 0.22.
"""
def __repr__(self) -> str:
r"""
@brief Converts a value to a string
The string can be used by the string constructor to create another object from it.
@return The string
"""
def __str__(self) -> str:
r"""
@brief Converts a value to a string
@ -696,7 +710,7 @@ class RdbItem:
This method has been introduced in version 0.23.
"""
def each_value(self) -> Iterable[RdbItemValue]:
def each_value(self) -> Iterator[RdbItemValue]:
r"""
@brief Iterates over all values
"""
@ -892,7 +906,7 @@ class ReportDatabase:
@param iter The iterator (a \RecursiveShapeIterator object) from which to take the items
"""
@overload
def create_items(self, cell_id: int, category_id: int, trans: db.CplxTrans, array: Iterable[db.EdgePair]) -> None:
def create_items(self, cell_id: int, category_id: int, trans: db.CplxTrans, array: Sequence[db.EdgePair]) -> None:
r"""
@brief Creates new edge pair items for the given cell/category combination
For each edge pair a single item will be created. The value of the item will be this edge pair.
@ -906,7 +920,7 @@ class ReportDatabase:
@param edge_pairs The list of edge_pairs for which the items are created
"""
@overload
def create_items(self, cell_id: int, category_id: int, trans: db.CplxTrans, array: Iterable[db.Edge]) -> None:
def create_items(self, cell_id: int, category_id: int, trans: db.CplxTrans, array: Sequence[db.Edge]) -> None:
r"""
@brief Creates new edge items for the given cell/category combination
For each edge a single item will be created. The value of the item will be this edge.
@ -920,7 +934,7 @@ class ReportDatabase:
@param edges The list of edges for which the items are created
"""
@overload
def create_items(self, cell_id: int, category_id: int, trans: db.CplxTrans, array: Iterable[db.Polygon]) -> None:
def create_items(self, cell_id: int, category_id: int, trans: db.CplxTrans, array: Sequence[db.Polygon]) -> None:
r"""
@brief Creates new polygon items for the given cell/category combination
For each polygon a single item will be created. The value of the item will be this polygon.
@ -995,29 +1009,29 @@ class ReportDatabase:
@param shapes The shape container from which to take the items
@param trans The transformation to apply
"""
def each_category(self) -> Iterable[RdbCategory]:
def each_category(self) -> Iterator[RdbCategory]:
r"""
@brief Iterates over all top-level categories
"""
def each_cell(self) -> Iterable[RdbCell]:
def each_cell(self) -> Iterator[RdbCell]:
r"""
@brief Iterates over all cells
"""
def each_item(self) -> Iterable[RdbItem]:
def each_item(self) -> Iterator[RdbItem]:
r"""
@brief Iterates over all items inside the database
"""
def each_item_per_category(self, category_id: int) -> Iterable[RdbItem]:
def each_item_per_category(self, category_id: int) -> Iterator[RdbItem]:
r"""
@brief Iterates over all items inside the database which are associated with the given category
@param category_id The ID of the category for which all associated items should be retrieved
"""
def each_item_per_cell(self, cell_id: int) -> Iterable[RdbItem]:
def each_item_per_cell(self, cell_id: int) -> Iterator[RdbItem]:
r"""
@brief Iterates over all items inside the database which are associated with the given cell
@param cell_id The ID of the cell for which all associated items should be retrieved
"""
def each_item_per_cell_and_category(self, cell_id: int, category_id: int) -> Iterable[RdbItem]:
def each_item_per_cell_and_category(self, cell_id: int, category_id: int) -> Iterator[RdbItem]:
r"""
@brief Iterates over all items inside the database which are associated with the given cell and category
@param cell_id The ID of the cell for which all associated items should be retrieved
@ -1129,7 +1143,7 @@ class ReportDatabase:
This method has been added in version 0.24.
"""
def variants(self, name: str) -> Iterable[int]:
def variants(self, name: str) -> List[int]:
r"""
@brief Gets the variants for a given cell name
@param name The basic name of the cell

View File

@ -1,8 +1,12 @@
from typing import Any, ClassVar, Dict, Iterable, Optional
from typing import Any, ClassVar, Dict, Sequence, List, Iterator, Optional
from typing import overload
class EmptyClass:
r"""
"""
def __copy__(self) -> EmptyClass:
r"""
@brief Creates a copy of self
"""
def __init__(self) -> None:
r"""
@brief Creates a new object of this class
@ -64,6 +68,10 @@ class Value:
@brief Gets the actual value.
@brief Set the actual value.
"""
def __copy__(self) -> Value:
r"""
@brief Creates a copy of self
"""
@overload
def __init__(self) -> None:
r"""
@ -75,6 +83,10 @@ class Value:
@brief Constructs a non-nil object with the given value.
This constructor has been introduced in version 0.22.
"""
def __repr__(self) -> str:
r"""
@brief Convert this object to a string
"""
def __str__(self) -> str:
r"""
@brief Convert this object to a string
@ -148,14 +160,16 @@ class Interpreter:
This class was introduced in version 0.27.5.
"""
python_interpreter: ClassVar[Interpreter]
r"""
@brief Gets the instance of the Python interpreter
"""
ruby_interpreter: ClassVar[Interpreter]
r"""
@brief Gets the instance of the Ruby interpreter
"""
@classmethod
def python_interpreter(cls) -> Interpreter:
r"""
@brief Gets the instance of the Python interpreter
"""
@classmethod
def ruby_interpreter(cls) -> Interpreter:
r"""
@brief Gets the instance of the Ruby interpreter
"""
def __init__(self) -> None:
r"""
@brief Creates a new object of this class
@ -279,6 +293,10 @@ class ArgType:
TypeVoidPtr: ClassVar[int]
r"""
"""
def __copy__(self) -> ArgType:
r"""
@brief Creates a copy of self
"""
def __eq__(self, arg0: object) -> bool:
r"""
@brief Equality of two types
@ -291,6 +309,10 @@ class ArgType:
r"""
@brief Inequality of two types
"""
def __repr__(self) -> str:
r"""
@brief Convert to a string
"""
def __str__(self) -> str:
r"""
@brief Convert to a string
@ -413,6 +435,10 @@ class MethodOverload:
r"""
@hide
"""
def __copy__(self) -> MethodOverload:
r"""
@brief Creates a copy of self
"""
def __init__(self) -> None:
r"""
@brief Creates a new object of this class
@ -539,11 +565,11 @@ class Method:
r"""
@brief The documentation string for this method
"""
def each_argument(self) -> Iterable[ArgType]:
def each_argument(self) -> Iterator[ArgType]:
r"""
@brief Iterate over all arguments of this method
"""
def each_overload(self) -> Iterable[MethodOverload]:
def each_overload(self) -> Iterator[MethodOverload]:
r"""
@brief This iterator delivers the synonyms (overloads).
@ -608,10 +634,11 @@ class Class:
r"""
@hide
"""
each_class: ClassVar[Iterable[Class]]
r"""
@brief Iterate over all classes
"""
@classmethod
def each_class(cls) -> Iterator[Class]:
r"""
@brief Iterate over all classes
"""
def __init__(self) -> None:
r"""
@brief Creates a new object of this class
@ -673,11 +700,11 @@ class Class:
r"""
@brief The documentation string for this class
"""
def each_child_class(self) -> Iterable[Class]:
def each_child_class(self) -> Iterator[Class]:
r"""
@brief Iterate over all child classes defined within this class
"""
def each_method(self) -> Iterable[Method]:
def each_method(self) -> Iterator[Method]:
r"""
@brief Iterate over all methods of this class
"""
@ -801,16 +828,25 @@ class Timer:
This class has been introduced in version 0.23.
"""
memory_size: ClassVar[int]
r"""
@brief Gets the current memory usage of the process in Bytes
@classmethod
def memory_size(cls) -> int:
r"""
@brief Gets the current memory usage of the process in Bytes
This method has been introduced in version 0.27.
"""
This method has been introduced in version 0.27.
"""
def __copy__(self) -> Timer:
r"""
@brief Creates a copy of self
"""
def __init__(self) -> None:
r"""
@brief Creates a new object of this class
"""
def __repr__(self) -> str:
r"""
@brief Produces a string with the currently elapsed times
"""
def __str__(self) -> str:
r"""
@brief Produces a string with the currently elapsed times
@ -1229,6 +1265,10 @@ class ExpressionContext:
This class has been introduced in version 0.26 when \Expression was separated into the execution and context part.
"""
def __copy__(self) -> ExpressionContext:
r"""
@brief Creates a copy of self
"""
def __init__(self) -> None:
r"""
@brief Creates a new object of this class
@ -1384,6 +1424,10 @@ class GlobPattern:
@brief Sets a value indicating whether trailing characters are allowed.
If this predicate is false, the glob pattern needs to match the full subject string. If true, the match function will ignore trailing characters and return true if the front part of the subject string matches.
"""
def __copy__(self) -> GlobPattern:
r"""
@brief Creates a copy of self
"""
def __init__(self, pattern: str) -> None:
r"""
@brief Creates a new glob pattern match object
@ -1444,6 +1488,10 @@ class ExecutableBase:
@hide
@alias Executable
"""
def __copy__(self) -> ExecutableBase:
r"""
@brief Creates a copy of self
"""
def __init__(self) -> None:
r"""
@brief Creates a new object of this class

View File

@ -192,7 +192,9 @@ _type_dict[ktl.ArgType.TypeVoid] = "None"
_type_dict[ktl.ArgType.TypeVoidPtr] = "None"
def _translate_type(arg_type: ktl.ArgType, within_class: ktl.Class) -> str:
def _translate_type(
arg_type: ktl.ArgType, within_class: ktl.Class, is_return=False
) -> str:
"""Translates klayout's C-type to a type in Python.
This function is equivalent to the `type_to_s` in `pyaModule.cc`.
@ -205,16 +207,19 @@ def _translate_type(arg_type: ktl.ArgType, within_class: ktl.Class) -> str:
else:
py_str = qualified_name(arg_type.cls())
elif arg_type.type() == ktl.ArgType.TypeMap:
inner_key = _translate_type(arg_type.inner_k(), within_class)
inner_val = _translate_type(arg_type.inner(), within_class)
inner_key = _translate_type(arg_type.inner_k(), within_class, is_return)
inner_val = _translate_type(arg_type.inner(), within_class, is_return)
py_str = f"Dict[{inner_key}, {inner_val}]"
elif arg_type.type() == ktl.ArgType.TypeVector:
py_str = f"Iterable[{_translate_type(arg_type.inner(), within_class)}]"
if is_return:
py_str = f"List[{_translate_type(arg_type.inner(), within_class, is_return)}]"
else:
py_str = f"Sequence[{_translate_type(arg_type.inner(), within_class, is_return)}]"
else:
py_str = _type_dict[arg_type.type()]
if arg_type.is_iter():
py_str = f"Iterable[{py_str}]"
py_str = f"Iterator[{py_str}]"
if arg_type.has_default():
py_str = f"Optional[{py_str}] = ..."
return py_str
@ -324,7 +329,7 @@ def get_c_methods(c: ktl.Class) -> List[_Method]:
for ms in m.each_overload():
if ms.name() == m.primary_name():
return ms
raise ("Primary synonym not found for method " + m.name())
raise RuntimeError("Primary synonym not found for method " + m.name())
for m in c.each_method():
if m.is_signal():
@ -346,17 +351,35 @@ def get_c_methods(c: ktl.Class) -> List[_Method]:
)
is_setter = (num_args == 1) and method_def.is_setter()
is_classvar = (num_args == 0) and (m.is_static() and not m.is_constructor())
method_list.append(
_Method(
name=method_def.name(),
is_setter=is_setter,
is_getter=is_getter or is_classvar,
is_classmethod=m.is_constructor(),
is_classvar=is_classvar,
doc=m.doc(),
m=m,
is_const = m.is_const()
# static methods without arguments which start with a capital letter are treated as constants
# (rule from pyaModule.cc)
if is_classvar and m.name()[0].isupper():
is_getter = True
for method_synonym in m.each_overload():
if method_synonym.deprecated():
# method synonyms that start with # (pound) sign
continue
if method_synonym.name() == method_def.name():
doc = m.doc()
else:
doc = (
f"Note: This is an alias of '{translate_methodname(method_def.name())}'.\n"
+ m.doc()
)
method_list.append(
_Method(
name=method_synonym.name(),
is_setter=is_setter,
is_getter=is_getter,
is_classmethod=m.is_constructor() or is_classvar,
is_classvar=is_classvar,
doc=doc,
m=m,
)
)
)
# print(f"{m.name()}: {m.is_static()=}, {m.is_constructor()=}, {m.is_const_object()=}")
return method_list
@ -364,7 +387,7 @@ def get_c_methods(c: ktl.Class) -> List[_Method]:
def get_py_child_classes(c: ktl.Class):
for c_child in c.each_child_class():
return c_child
yield c_child
def get_py_methods(
@ -390,10 +413,13 @@ def get_py_methods(
return m
return None
translate_type = functools.partial(_translate_type, within_class=c)
translate_arg_type = functools.partial(_translate_type, within_class=c, is_return=False)
translate_ret_type = functools.partial(_translate_type, within_class=c, is_return=True)
def _get_arglist(m: ktl.Method, self_str) -> List[Tuple[str, ktl.ArgType]]:
args = [(self_str, None)]
def _get_arglist(
m: ktl.Method, self_str: str
) -> List[Tuple[str, Optional[ktl.ArgType]]]:
args: List[Tuple[str, Optional[ktl.ArgType]]] = [(self_str, None)]
for i, a in enumerate(m.each_argument()):
argname = a.name()
if is_reserved_word(argname):
@ -417,7 +443,7 @@ def get_py_methods(
new_arglist: List[Tuple[str, Optional[str]]] = []
for argname, a in arg_list:
if a:
new_arglist.append((argname, translate_type(a)))
new_arglist.append((argname, translate_arg_type(a)))
else:
new_arglist.append((argname, None))
return _format_args(new_arglist)
@ -425,7 +451,7 @@ def get_py_methods(
# Extract all properties (methods that have getters and/or setters)
properties: List[Stub] = list()
for m in copy(_c_methods):
ret_type = translate_type(m.m.ret_type())
ret_type = translate_ret_type(m.m.ret_type())
if m.is_getter:
m_setter = find_setter(c_methods, m.name)
if m_setter is not None: # full property
@ -476,10 +502,27 @@ def get_py_methods(
if m.is_setter:
_c_methods.remove(m)
def get_altnames(c_name: str):
def get_altnames(c_name: str, m: _Method):
args = list(m.m.each_argument())
ret = m.m.ret_type()
num_args = len(args)
names = [c_name]
if c_name == "to_s":
if c_name == "to_s" and num_args == 0:
names.append("__str__")
# Only works if GSI_ALIAS_INSPECT is activated
names.append("__repr__")
elif c_name == "hash" and num_args == 0:
names.append("__hash__")
elif c_name == "inspect" and num_args == 0:
names.append("__repr__")
elif c_name == "size" and num_args == 0:
names.append("__len__")
elif c_name == "each" and num_args == 0 and ret.is_iter():
names.append("__iter__")
elif c_name == "__mul__" and "Trans" not in c_name:
names.append("__rmul__")
elif c_name == "dup" and num_args == 0:
names.append("__copy__")
return names
# Extract all classmethods
@ -491,8 +534,8 @@ def get_py_methods(
if translate_methodname(m.name) == "__init__":
continue
decorator = "@classmethod"
ret_type = translate_type(m.m.ret_type())
for name in get_altnames(m.name):
ret_type = translate_ret_type(m.m.ret_type())
for name in get_altnames(m.name, m):
classmethods.append(
MethodStub(
decorator=decorator,
@ -515,9 +558,10 @@ def get_py_methods(
if translated_name == "__init__":
ret_type = "None"
else:
ret_type = translate_type(m.m.ret_type())
ret_type = translate_ret_type(m.m.ret_type())
arg_list = _get_arglist(m.m, "self")
# TODO: fix type errors
# Exceptions:
# For X.__eq__(self, a:X), treat second argument as type object instead of X
if translated_name in ("__eq__", "__ne__"):
@ -525,19 +569,20 @@ def get_py_methods(
# X._assign(self, other:X), mypy complains if _assign is defined at base class.
# We can't specialize other in this case.
elif translated_name in ("_assign", "assign"):
assert arg_list[1][1] is not None
assert arg_list[1][1].type() == ktl.ArgType.TypeObject
arg_list[1] = arg_list[1][0], superclass(arg_list[1][1].cls())
else:
new_arg_list = []
for argname, a in arg_list:
if a:
new_arg_list.append((argname, translate_type(a)))
new_arg_list.append((argname, translate_arg_type(a)))
else:
new_arg_list.append((argname, a))
arg_list = new_arg_list
formatted_args = _format_args(arg_list)
for name in get_altnames(translated_name):
for name in get_altnames(translated_name, m):
boundmethods.append(
MethodStub(
decorator=decorator,
@ -595,6 +640,7 @@ def get_class_stub(
_cstub.child_stubs.append(stub)
return _cstub
def get_classes(module: str) -> List[ktl.Class]:
_classes = []
for c in ktl.Class.each_class():
@ -603,7 +649,8 @@ def get_classes(module: str) -> List[ktl.Class]:
_classes.append(c)
return _classes
def get_module_stubs(module:str) -> List[ClassStub]:
def get_module_stubs(module: str) -> List[ClassStub]:
_stubs = []
_classes = get_classes(module)
for c in _classes:
@ -613,7 +660,7 @@ def get_module_stubs(module:str) -> List[ClassStub]:
def print_db():
print("from typing import Any, ClassVar, Dict, Iterable, Optional")
print("from typing import Any, ClassVar, Dict, Sequence, List, Iterator, Optional")
print("from typing import overload")
print("import klayout.rdb as rdb")
print("import klayout.tl as tl")
@ -622,14 +669,15 @@ def print_db():
def print_rdb():
print("from typing import Any, ClassVar, Dict, Iterable, Optional")
print("from typing import Any, ClassVar, Dict, Sequence, List, Iterator, Optional")
print("from typing import overload")
print("import klayout.db as db")
for stub in get_module_stubs("rdb"):
print(stub.format_stub(include_docstring=True) + "\n")
def print_tl():
print("from typing import Any, ClassVar, Dict, Iterable, Optional")
print("from typing import Any, ClassVar, Dict, Sequence, List, Iterator, Optional")
print("from typing import overload")
for stub in get_module_stubs("tl"):
print(stub.format_stub(include_docstring=True) + "\n")

View File

@ -36,13 +36,13 @@ namespace tl
/**
* @brief The unspecific exception class
*
* This class is the base class for all exceptions in this
* framework. It does not carry further information except
* a message string that can be created through different
* This class is the base class for all exceptions in this
* framework. It does not carry further information except
* a message string that can be created through different
* constructor methods.
*/
class TL_PUBLIC Exception
class TL_PUBLIC Exception
{
public:
Exception (const std::string &msg)
@ -169,6 +169,15 @@ private:
void init (const std::string &fmt, const std::vector<tl::Variant> &a);
};
/**
* @brief An exception thrown when the wrong type is provided as argument.
*/
struct TL_PUBLIC TypeError
: public Exception
{
using Exception::Exception;
};
/**
* @brief A "neutral" exception thrown to terminate some operation
* This exception is not shown.
@ -195,4 +204,3 @@ struct TL_PUBLIC InternalException
} // namespace tl
#endif

View File

@ -41,6 +41,19 @@ class BasicTest(unittest.TestCase):
v.read(os.path.join(os.path.dirname(__file__), "..", "gds", "t10.gds"))
self.assertEqual(v.top_cell().name, "RINGO")
def test_4(self):
class RMulObject:
def __init__(self, factor):
self.factor = factor
def __rmul__(self, point):
return point * self.factor
def __radd__(self, point):
return point + db.Vector(1,1) * self.factor
p = db.Point(1, 0)
fac2 = RMulObject(2)
self.assertEqual(p * 2, p * fac2) # p.__mul__(fac2) should return NotImplemented, which will call fac2.__rmul__(p)
self.assertEqual(db.Point(3,2), p + fac2)
# run unit tests
if __name__ == '__main__':
suite = unittest.TestSuite()
@ -48,5 +61,3 @@ if __name__ == '__main__':
if not unittest.TextTestRunner(verbosity = 1).run(suite).wasSuccessful():
sys.exit(1)