From 0f2433d3aafd98d9a6fdd97eb273e71745b657e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Tue, 18 Feb 2025 23:13:38 +0100 Subject: [PATCH 01/14] pyproject.toml: add ruff config Taken from mkosi, using the common systemd line length. --- pyproject.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 16afedd..35488ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,3 +9,8 @@ build-backend = 'setuptools.build_meta' [tool.setuptools_scm] local_scheme = "no-local-version" + +[tool.ruff] +target-version = "py39" +line-length = 109 +lint.select = ["E", "F", "I", "UP"] From f334e4975b8a471045350830c89e78c1349e496b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Tue, 18 Feb 2025 23:14:16 +0100 Subject: [PATCH 02/14] treewide: use ruff to format codebase --- docs/conf.py | 59 ++++---- setup.py | 10 +- varlink/__init__.py | 65 ++++++-- varlink/cli.py | 129 +++++++++------- varlink/client.py | 100 +++++++------ varlink/error.py | 47 +++--- varlink/mock.py | 107 +++++++------- varlink/scanner.py | 143 +++++++++--------- varlink/server.py | 154 +++++++++++-------- varlink/tests/__init__.py | 1 + varlink/tests/test_basic_network.py | 38 +++-- varlink/tests/test_certification.py | 212 +++++++++++++++------------ varlink/tests/test_mocks.py | 44 ++---- varlink/tests/test_orgexamplemore.py | 123 +++++++--------- varlink/tests/test_scanner.py | 24 ++- 15 files changed, 690 insertions(+), 566 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 30b498d..3b30409 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,14 +19,14 @@ # -- Project information ----------------------------------------------------- -project = u'varlink' -copyright = u'2018, Harald Hoyer, Lars Karlitski' -author = u'Harald Hoyer, Lars Karlitski' +project = "varlink" +copyright = "2018, Harald Hoyer, Lars Karlitski" +author = "Harald Hoyer, Lars Karlitski" # The short X.Y version -version = u'' +version = "" # The full version, including alpha/beta/rc tags -release = u'' +release = "" # -- General configuration --------------------------------------------------- @@ -39,21 +39,21 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.viewcode', - 'sphinx.ext.githubpages', + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinx.ext.githubpages", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # -source_suffix = ['.rst', '.md'] +source_suffix = [".rst", ".md"] # The master toctree document. -master_doc = 'index' +master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -68,7 +68,7 @@ exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'default' +pygments_style = "default" # -- Options for HTML output ------------------------------------------------- @@ -76,7 +76,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'classic' +html_theme = "classic" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -87,7 +87,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -103,7 +103,7 @@ # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'varlinkdoc' +htmlhelp_basename = "varlinkdoc" # -- Options for LaTeX output ------------------------------------------------ @@ -112,15 +112,12 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -130,8 +127,13 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'varlink.tex', u'varlink Documentation', - u'Harald Hoyer\\textless{}harald@redhat.com\\textgreater{}, Lars Karlitski\\textless{}lars@karlitski.net\\textgreater{}', 'manual'), + ( + master_doc, + "varlink.tex", + "varlink Documentation", + "Harald Hoyer\\textless{}harald@redhat.com\\textgreater{}, Lars Karlitski\\textless{}lars@karlitski.net\\textgreater{}", + "manual", + ), ] @@ -139,10 +141,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'varlink', u'varlink Documentation', - [author], 1) -] +man_pages = [(master_doc, "varlink", "varlink Documentation", [author], 1)] # -- Options for Texinfo output ---------------------------------------------- @@ -151,9 +150,15 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'varlink', u'varlink Documentation', - author, 'varlink', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "varlink", + "varlink Documentation", + author, + "varlink", + "One line description of project.", + "Miscellaneous", + ), ] diff --git a/setup.py b/setup.py index 4abb68b..07b902d 100644 --- a/setup.py +++ b/setup.py @@ -1,13 +1,15 @@ from setuptools import setup + def local_scheme(_): """Enables a version format so that upload to TestPyPI is successful. - For example: 2.6.2.dev8 - See https://github.com/pypa/setuptools_scm/issues/342. - """ + For example: 2.6.2.dev8 + See https://github.com/pypa/setuptools_scm/issues/342. + """ return "" + setup( use_scm_version={"local_scheme": "no-local-version"}, - setup_requires=['setuptools_scm'], + setup_requires=["setuptools_scm"], ) diff --git a/varlink/__init__.py b/varlink/__init__.py index 36c66fd..bef489b 100644 --- a/varlink/__init__.py +++ b/varlink/__init__.py @@ -16,24 +16,57 @@ import os if hasattr(os, "fork"): - __all__ = ['Client', 'ClientInterfaceHandler', 'SimpleClientInterfaceHandler', - 'Service', 'RequestHandler', 'Server', 'ThreadingServer', 'ForkingServer', - 'InterfaceNotFound', 'MethodNotFound', 'MethodNotImplemented', 'InvalidParameter', - 'VarlinkEncoder', 'VarlinkError', - 'Interface', 'Scanner', 'get_listen_fd'] + __all__ = [ + "Client", + "ClientInterfaceHandler", + "SimpleClientInterfaceHandler", + "Service", + "RequestHandler", + "Server", + "ThreadingServer", + "ForkingServer", + "InterfaceNotFound", + "MethodNotFound", + "MethodNotImplemented", + "InvalidParameter", + "VarlinkEncoder", + "VarlinkError", + "Interface", + "Scanner", + "get_listen_fd", + ] from .server import ForkingServer else: - __all__ = ['Client', 'ClientInterfaceHandler', 'SimpleClientInterfaceHandler', - 'Service', 'RequestHandler', 'Server', 'ThreadingServer', - 'InterfaceNotFound', 'MethodNotFound', 'MethodNotImplemented', 'InvalidParameter', - 'VarlinkEncoder', 'VarlinkError', - 'Interface', 'Scanner', 'get_listen_fd'] - -from .client import (Client, ClientInterfaceHandler, SimpleClientInterfaceHandler) -from .error import (VarlinkEncoder, VarlinkError, InvalidParameter, InterfaceNotFound, MethodNotImplemented, - MethodNotFound) -from .scanner import (Scanner, Interface) -from .server import (Service, get_listen_fd, Server, ThreadingServer, RequestHandler) + __all__ = [ + "Client", + "ClientInterfaceHandler", + "SimpleClientInterfaceHandler", + "Service", + "RequestHandler", + "Server", + "ThreadingServer", + "InterfaceNotFound", + "MethodNotFound", + "MethodNotImplemented", + "InvalidParameter", + "VarlinkEncoder", + "VarlinkError", + "Interface", + "Scanner", + "get_listen_fd", + ] + +from .client import Client, ClientInterfaceHandler, SimpleClientInterfaceHandler +from .error import ( + VarlinkEncoder, + VarlinkError, + InvalidParameter, + InterfaceNotFound, + MethodNotImplemented, + MethodNotFound, +) +from .scanner import Scanner, Interface +from .server import Service, get_listen_fd, Server, ThreadingServer, RequestHandler # There are no tests here, so don't try to run anything discovered from diff --git a/varlink/cli.py b/varlink/cli.py index 58a66cb..c9a2ee7 100644 --- a/varlink/cli.py +++ b/varlink/cli.py @@ -21,13 +21,13 @@ def varlink_call(args): print("No method found", file=sys.stderr) sys.exit(1) - method = args.METHOD[deli + 1:] + method = args.METHOD[deli + 1 :] interface = args.METHOD[:deli] deli = interface.rfind("/") if deli != -1: address = interface[:deli] - interface = interface[deli + 1:] + interface = interface[deli + 1 :] else: address = None @@ -47,8 +47,12 @@ def new_client(address): got = False try: with client.open(interface) as con: - out = {'method': interface + '.' + method, 'more': args.more, 'parameters': json.loads(args.ARGUMENTS or "{}" )} - con._send_message(json.dumps(out, cls=varlink.VarlinkEncoder).encode('utf-8')) + out = { + "method": interface + "." + method, + "more": args.more, + "parameters": json.loads(args.ARGUMENTS or "{}"), + } + con._send_message(json.dumps(out, cls=varlink.VarlinkEncoder).encode("utf-8")) more = True while more: (message, more) = con._next_varlink_message() @@ -62,8 +66,9 @@ def new_client(address): print("Connection closed") sys.exit(1) + def varlink_bridge(args): - message = b'' + message = b"" last_interface = None con = None client = None @@ -80,13 +85,12 @@ def varlink_bridge(args): else: print("No --connect or --bridge or --activate") - - if hasattr(sys.stdout, 'buffer'): + if hasattr(sys.stdout, "buffer"): stdout = sys.stdout.buffer else: stdout = sys.stdout - if hasattr(sys.stdin, 'buffer'): + if hasattr(sys.stdin, "buffer"): stdin = sys.stdin.buffer else: stdin = sys.stdin @@ -94,35 +98,39 @@ def varlink_bridge(args): while not sys.stdin.closed: c = stdin.read(1) - if c == b'': + if c == b"": break - if c != b'\0': + if c != b"\0": message += c continue - req = json.loads(message.decode('utf-8')) + req = json.loads(message.decode("utf-8")) if not args.connect and not args.activate and not args.bridge: - if req['method'] == "org.varlink.service.GetInfo": - req['method'] = "org.varlink.resolver.GetInfo" + if req["method"] == "org.varlink.service.GetInfo": + req["method"] = "org.varlink.resolver.GetInfo" - interface_name, _, method_name = req.get('method', '').rpartition('.') + interface_name, _, method_name = req.get("method", "").rpartition(".") - if req['method'] == "org.varlink.service.GetInterfaceDescription": - resolving_interface = req['parameters']['interface'] + if req["method"] == "org.varlink.service.GetInterfaceDescription": + resolving_interface = req["parameters"]["interface"] else: resolving_interface = interface_name if not interface_name or not method_name: - stdout.write(json.dumps(varlink.InterfaceNotFound(interface_name), cls=varlink.VarlinkEncoder).encode( - 'utf-8') + b'\0') + stdout.write( + json.dumps(varlink.InterfaceNotFound(interface_name), cls=varlink.VarlinkEncoder).encode( + "utf-8" + ) + + b"\0" + ) sys.stdout.flush() continue if last_interface != resolving_interface: if con: - if hasattr(con, 'shutdown'): + if hasattr(con, "shutdown"): con.shutdown(socket.SHUT_RDWR) else: con.close() @@ -131,12 +139,11 @@ def varlink_bridge(args): client.cleanup() try: - client = varlink.Client.new_with_resolved_interface(resolving_interface, - resolver_address=args.resolver) + client = varlink.Client.new_with_resolved_interface( + resolving_interface, resolver_address=args.resolver + ) except varlink.VarlinkError as e: - stdout.write( - json.dumps(e, cls=varlink.VarlinkEncoder).encode( - 'utf-8') + b'\0') + stdout.write(json.dumps(e, cls=varlink.VarlinkEncoder).encode("utf-8") + b"\0") sys.stdout.flush() continue @@ -144,37 +151,37 @@ def varlink_bridge(args): last_interface = resolving_interface if hasattr(con, "send"): - con.send(message + b'\0') + con.send(message + b"\0") else: - con.write(message + b'\0') + con.write(message + b"\0") if req.get("oneway", False): continue - message = b'' + message = b"" - ret_message = b'' + ret_message = b"" while True: c = con.recv(1) - if c == b'': + if c == b"": break - if c != b'\0': + if c != b"\0": ret_message += c continue - stdout.write(ret_message + b'\0') + stdout.write(ret_message + b"\0") sys.stdout.flush() - ret = json.loads(ret_message.decode('utf-8')) - ret_message = b'' + ret = json.loads(ret_message.decode("utf-8")) + ret_message = b"" - if not ret.get('continues', False): + if not ret.get("continues", False): break - if ret.get('upgraded', False): + if ret.get("upgraded", False): raise NotImplementedError("Bridging upgraded connection not yet supported") @@ -182,7 +189,7 @@ def varlink_help(args): deli = args.INTERFACE.rfind("/") if deli != -1: address = args.INTERFACE[:deli] - interface_name = args.INTERFACE[deli + 1:] + interface_name = args.INTERFACE[deli + 1 :] client = varlink.Client.new_with_address(address) else: interface_name = args.INTERFACE @@ -197,6 +204,7 @@ def varlink_help(args): del client print(interface.description) + def varlink_info(args): if args.ADDRESS: client = varlink.Client.new_with_address(args.ADDRESS) @@ -207,7 +215,6 @@ def varlink_info(args): else: print("No ADDRESS or --bridge or --activate") - client.get_interfaces() info = client.info del client @@ -220,33 +227,45 @@ def varlink_info(args): print(" ", i) -if __name__ == '__main__': +if __name__ == "__main__": parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(title="commands") - parser.add_argument('-r', '--resolver', default=None, help='address of the resolver') - parser.add_argument('-A', '--activate', default=None, - help='Service to socket-activate and connect to. ' - 'The temporary UNIX socket address is exported as $VARLINK_ADDRESS.') - parser.add_argument('-b', '--bridge', default=None, help='Command to execute and connect to') - - parser_info = subparsers.add_parser('info', help='Print information about a service') - parser_info.add_argument('ADDRESS', nargs='?') + parser.add_argument("-r", "--resolver", default=None, help="address of the resolver") + parser.add_argument( + "-A", + "--activate", + default=None, + help="Service to socket-activate and connect to. " + "The temporary UNIX socket address is exported as $VARLINK_ADDRESS.", + ) + parser.add_argument("-b", "--bridge", default=None, help="Command to execute and connect to") + + parser_info = subparsers.add_parser("info", help="Print information about a service") + parser_info.add_argument("ADDRESS", nargs="?") parser_info.set_defaults(func=varlink_info) - parser_help = subparsers.add_parser('help', help='Print interface description or service information') - parser_help.add_argument('INTERFACE') + parser_help = subparsers.add_parser("help", help="Print interface description or service information") + parser_help.add_argument("INTERFACE") parser_help.set_defaults(func=varlink_help) - parser_bridge = subparsers.add_parser('bridge', help='Bridge varlink messages to services on this machine') - parser_bridge.add_argument('-c', '--connect', default=None, help='Optional varlink address to connect to, ' - 'without using the resolver.') + parser_bridge = subparsers.add_parser( + "bridge", help="Bridge varlink messages to services on this machine" + ) + parser_bridge.add_argument( + "-c", + "--connect", + default=None, + help="Optional varlink address to connect to, without using the resolver.", + ) parser_bridge.set_defaults(func=varlink_bridge) - parser_call = subparsers.add_parser('call', help='Call a method') - parser_call.add_argument('-m', '--more', action='store_true', help='wait for multiple method returns if supported') - parser_call.add_argument('METHOD') - parser_call.add_argument('ARGUMENTS', nargs='?', default="") + parser_call = subparsers.add_parser("call", help="Call a method") + parser_call.add_argument( + "-m", "--more", action="store_true", help="wait for multiple method returns if supported" + ) + parser_call.add_argument("METHOD") + parser_call.add_argument("ARGUMENTS", nargs="?", default="") parser_call.set_defaults(func=varlink_call) args = parser.parse_args() diff --git a/varlink/client.py b/varlink/client.py index ee2acd6..ba52040 100644 --- a/varlink/client.py +++ b/varlink/client.py @@ -10,8 +10,8 @@ import subprocess import threading -from .error import (VarlinkError, InterfaceNotFound, VarlinkEncoder) -from .scanner import (Interface, _Method) +from .error import VarlinkError, InterfaceNotFound, VarlinkEncoder +from .scanner import Interface, _Method class ClientInterfaceHandler: @@ -59,7 +59,6 @@ def _next_message(self): raise NotImplementedError def _add_method(self, method): - def _wrapped(*args, **kwargs): if "_more" in kwargs and kwargs.pop("_more"): return self._call_more(method.name, *args, **kwargs) @@ -82,15 +81,15 @@ def _next_varlink_message(self): message = next(self._next_message()) message = json.loads(message) - if 'parameters' not in message: - message['parameters'] = {} + if "parameters" not in message: + message["parameters"] = {} - if 'error' in message and message["error"] is not None: + if "error" in message and message["error"] is not None: self._in_use = False e = VarlinkError.new(message, self._namespaced) raise e else: - return message['parameters'], ('continues' in message) and message['continues'] + return message["parameters"], ("continues" in message) and message["continues"] def _call(self, method_name, *args, **kwargs): if self._in_use: @@ -104,15 +103,15 @@ def _call(self, method_name, *args, **kwargs): parameters = self._interface.filter_params("client.call", method.in_type, False, args, kwargs) - out = {'method': self._interface.name + "." + method_name} + out = {"method": self._interface.name + "." + method_name} if oneway: - out['oneway'] = True + out["oneway"] = True if parameters: - out['parameters'] = parameters + out["parameters"] = parameters - self._send_message(json.dumps(out, cls=VarlinkEncoder).encode('utf-8')) + self._send_message(json.dumps(out, cls=VarlinkEncoder).encode("utf-8")) if oneway: return None @@ -126,7 +125,9 @@ def _call(self, method_name, *args, **kwargs): self._in_use = False if message: - message = self._interface.filter_params("client.reply", method.out_type, self._namespaced, message, None) + message = self._interface.filter_params( + "client.reply", method.out_type, self._namespaced, message, None + ) return message @@ -137,17 +138,18 @@ def _call_more(self, method_name, *args, **kwargs): method = self._interface.get_method(method_name) parameters = self._interface.filter_params("client.call", method.in_type, False, args, kwargs) - out = {'method': self._interface.name + "." + method_name, 'more': True, 'parameters': parameters} + out = {"method": self._interface.name + "." + method_name, "more": True, "parameters": parameters} - self._send_message(json.dumps(out, cls=VarlinkEncoder).encode('utf-8')) + self._send_message(json.dumps(out, cls=VarlinkEncoder).encode("utf-8")) more = True self._in_use = True while more: (message, more) = self._next_varlink_message() if message: - message = self._interface.filter_params("client.reply", method.out_type, self._namespaced, message, - None) + message = self._interface.filter_params( + "client.reply", method.out_type, self._namespaced, message, None + ) yield message self._in_use = False @@ -171,31 +173,31 @@ def __init__(self, interface, file_or_socket, namespaced=False): ClientInterfaceHandler.__init__(self, interface, namespaced=namespaced) self._connection = file_or_socket - if hasattr(self._connection, 'send_bytes'): + if hasattr(self._connection, "send_bytes"): self._send_bytes = True self._sendall = False - elif hasattr(self._connection, 'sendall'): + elif hasattr(self._connection, "sendall"): self._send_bytes = False self._sendall = True else: - if not hasattr(self._connection, 'write'): + if not hasattr(self._connection, "write"): raise TypeError self._sendall = False self._send_bytes = False - if hasattr(self._connection, 'recv_bytes'): + if hasattr(self._connection, "recv_bytes"): self._recv_bytes = True self._recv = False - elif hasattr(self._connection, 'recv'): + elif hasattr(self._connection, "recv"): self._recv = True self._recv_bytes = False else: - if not hasattr(self._connection, 'read'): + if not hasattr(self._connection, "read"): raise TypeError self._recv = False self._recv_bytes = False - self._in_buffer = b'' + self._in_buffer = b"" def __enter__(self): return self @@ -205,7 +207,7 @@ def __exit__(self, _type, _value, _traceback): def close(self): try: - if hasattr(self._connection, 'shutdown'): + if hasattr(self._connection, "shutdown"): self._connection.shutdown(socket.SHUT_RDWR) except: pass @@ -214,22 +216,22 @@ def close(self): def _send_message(self, out): if self._send_bytes: - self._connection.send_bytes(out + b'\0') + self._connection.send_bytes(out + b"\0") elif self._sendall: - self._connection.sendall(out + b'\0') + self._connection.sendall(out + b"\0") elif hasattr: - self._connection.write(out + b'\0') + self._connection.write(out + b"\0") def _next_message(self): while True: - message, sep, self._in_buffer = self._in_buffer.partition(b'\0') + message, sep, self._in_buffer = self._in_buffer.partition(b"\0") if not sep: # No zero byte found self._in_buffer = message message = None if message: - yield message.decode('utf-8') + yield message.decode("utf-8") continue if self._recv_bytes: @@ -331,6 +333,7 @@ class Client: which yields the return values and waits (blocks) for the service to return more return values in the generator's .__next__() call. """ + handler = SimpleClientInterfaceHandler def __init__(self, address=None, resolve_interface=None, resolver=None): @@ -350,7 +353,7 @@ def __init__(self, address=None, resolve_interface=None, resolver=None): self._child_pid = 0 self._str = "Client" - with open(os.path.join(os.path.dirname(__file__), 'org.varlink.service.varlink')) as f: + with open(os.path.join(os.path.dirname(__file__), "org.varlink.service.varlink")) as f: interface = Interface(f.read()) self.add_interface(interface) @@ -402,7 +405,7 @@ def _with_activate(self, argv): pass os.dup2(n, 3) - address = address.replace('\0', '@', 1) + address = address.replace("\0", "@", 1) for i in range(1, len(argv)): argv[i] = argv[i].replace("$VARLINK_ADDRESS", "unix:" + address) @@ -442,8 +445,9 @@ def new_bridge_socket(): def new_bridge_socket_compat(): sp = socket.socketpair() - p = subprocess.Popen(" ".join(argv), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, - close_fds=True) + p = subprocess.Popen( + " ".join(argv), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True + ) self._child_pid = p.pid thread1 = threading.Thread(daemon=True, target=pipe_bridge, args=(sp[1], p.stdin)) @@ -453,7 +457,7 @@ def new_bridge_socket_compat(): return sp[0] self._str = "Bridge with: '%s'" % " ".join(argv) - if sys.platform == 'win32': + if sys.platform == "win32": self._socket_fn = new_bridge_socket_compat else: self._socket_fn = new_bridge_socket @@ -475,11 +479,11 @@ def _with_address(self, address): if address.startswith("unix:"): self._str = address address = address[5:] - mode = address.find(';') + mode = address.find(";") if mode != -1: address = address[:mode] - if address[0] == '@': - address = address.replace('@', '\0', 1) + if address[0] == "@": + address = address.replace("@", "\0", 1) def open_unix(): s = socket.socket(socket.AF_UNIX) @@ -492,14 +496,14 @@ def open_unix(): elif address.startswith("tcp:"): self._str = address address = address[4:] - p = address.rfind(':') + p = address.rfind(":") if p != -1: - port = address[p + 1:] + port = address[p + 1 :] address = address[:p] else: raise ConnectionError("Invalid address 'tcp:%s'" % address) - address = address.replace('[', '') - address = address.replace(']', '') + address = address.replace("[", "") + address = address.replace("]", "") def open_tcp(): s = socket.create_connection((address, int(port))) @@ -529,14 +533,16 @@ def _with_resolved_interface(self, interface, resolver_address=None): if not resolver_address: resolver_address = "unix:/run/org.varlink.resolver" - if interface == 'org.varlink.resolver': + if interface == "org.varlink.resolver": self._with_address(resolver_address) else: - with Client.new_with_address(resolver_address) as client, \ - client.open('org.varlink.resolver') as _rc: + with ( + Client.new_with_address(resolver_address) as client, + client.open("org.varlink.resolver") as _rc, + ): # noinspection PyUnresolvedReferences _r = _rc.Resolve(interface) - self._with_address(_r['address']) + self._with_address(_r["address"]) return self @@ -602,7 +608,7 @@ def get_interfaces(self, socket_connection=None): if close_socket: socket_connection.close() - return self.info['interfaces'] + return self.info["interfaces"] def get_interface(self, interface_name, socket_connection=None): if not socket_connection: @@ -614,7 +620,7 @@ def get_interface(self, interface_name, socket_connection=None): _service = self.handler(self._interfaces["org.varlink.service"], socket_connection) # noinspection PyUnresolvedReferences desc = _service.GetInterfaceDescription(interface_name) - interface = Interface(desc['description']) + interface = Interface(desc["description"]) self._interfaces[interface.name] = interface if close_socket: diff --git a/varlink/error.py b/varlink/error.py index 2a8de47..8d11378 100644 --- a/varlink/error.py +++ b/varlink/error.py @@ -22,16 +22,16 @@ class VarlinkError(Exception): @classmethod def new(cls, message, namespaced=False): - if message['error'] == 'org.varlink.service.InterfaceNotFound': + if message["error"] == "org.varlink.service.InterfaceNotFound": return InterfaceNotFound.new(message, namespaced) - elif message['error'] == 'org.varlink.service.InvalidParameter': + elif message["error"] == "org.varlink.service.InvalidParameter": return InvalidParameter.new(message, namespaced) - elif message['error'] == 'org.varlink.service.MethodNotImplemented': + elif message["error"] == "org.varlink.service.MethodNotImplemented": return MethodNotImplemented.new(message, namespaced) - elif message['error'] == 'org.varlink.service.MethodNotImplemented': + elif message["error"] == "org.varlink.service.MethodNotImplemented": return MethodNotImplemented.new(message, namespaced) else: @@ -45,14 +45,16 @@ def __init__(self, message, namespaced=False): def error(self): """returns the exception varlink error name""" - return self.args[0].get('error') + return self.args[0].get("error") def parameters(self, namespaced=False): """returns the exception varlink error parameters""" if namespaced: - return json.loads(json.dumps(self.args[0]['parameters']), object_hook=lambda d: SimpleNamespace(**d)) + return json.loads( + json.dumps(self.args[0]["parameters"]), object_hook=lambda d: SimpleNamespace(**d) + ) else: - return self.args[0].get('parameters') + return self.args[0].get("parameters") def as_dict(self): return self.args[0] @@ -63,11 +65,14 @@ class InterfaceNotFound(VarlinkError): @classmethod def new(cls, message, namespaced=False): - return cls(namespaced and message['parameters'].interface or message['parameters'].get('interface', None)) + return cls( + namespaced and message["parameters"].interface or message["parameters"].get("interface", None) + ) def __init__(self, interface): - VarlinkError.__init__(self, {'error': 'org.varlink.service.InterfaceNotFound', - 'parameters': {'interface': interface}}) + VarlinkError.__init__( + self, {"error": "org.varlink.service.InterfaceNotFound", "parameters": {"interface": interface}} + ) class MethodNotFound(VarlinkError): @@ -75,10 +80,12 @@ class MethodNotFound(VarlinkError): @classmethod def new(cls, message, namespaced=False): - return cls(namespaced and message['parameters'].method or message['parameters'].get('method', None)) + return cls(namespaced and message["parameters"].method or message["parameters"].get("method", None)) def __init__(self, method): - VarlinkError.__init__(self, {'error': 'org.varlink.service.MethodNotFound', 'parameters': {'method': method}}) + VarlinkError.__init__( + self, {"error": "org.varlink.service.MethodNotFound", "parameters": {"method": method}} + ) class MethodNotImplemented(VarlinkError): @@ -86,11 +93,12 @@ class MethodNotImplemented(VarlinkError): @classmethod def new(cls, message, namespaced=False): - return cls(namespaced and message['parameters'].method or message['parameters'].get('method', None)) + return cls(namespaced and message["parameters"].method or message["parameters"].get("method", None)) def __init__(self, method): - VarlinkError.__init__(self, - {'error': 'org.varlink.service.MethodNotImplemented', 'parameters': {'method': method}}) + VarlinkError.__init__( + self, {"error": "org.varlink.service.MethodNotImplemented", "parameters": {"method": method}} + ) class InvalidParameter(VarlinkError): @@ -98,8 +106,11 @@ class InvalidParameter(VarlinkError): @classmethod def new(cls, message, namespaced=False): - return cls(namespaced and message['parameters'].parameter or message['parameters'].get('parameter', None)) + return cls( + namespaced and message["parameters"].parameter or message["parameters"].get("parameter", None) + ) def __init__(self, name): - VarlinkError.__init__(self, - {'error': 'org.varlink.service.InvalidParameter', 'parameters': {'parameter': name}}) + VarlinkError.__init__( + self, {"error": "org.varlink.service.InvalidParameter", "parameters": {"parameter": name}} + ) diff --git a/varlink/mock.py b/varlink/mock.py index ab25d4c..7b815ad 100644 --- a/varlink/mock.py +++ b/varlink/mock.py @@ -11,7 +11,7 @@ def cast_type(typeof): - cast = {'str': 'string'} + cast = {"str": "string"} typeof = str(typeof).replace("", "") return cast.get(typeof, typeof) @@ -49,9 +49,7 @@ def generate_callable_interface(interface, attr): returned = cast_type(returned) doc = attribut.__doc__ if not doc: - raise ValueError( - "docstring format must be:" - "return name: type") + raise ValueError("docstring format must be:return name: type") doc = doc.replace("return ", "") if ":" in doc: returned = doc @@ -60,13 +58,11 @@ def generate_callable_interface(interface, attr): else: returned = "" return "method {name}({signature}) -> ({returned})".format( - name=attr, - signature=",".join(sign), - returned=returned + name=attr, signature=",".join(sign), returned=returned ) -class MockedServiceProcess(): +class MockedServiceProcess: address = None vendor = None product = None @@ -80,33 +76,32 @@ class MockedServiceProcess(): def run(self): mocked_service = varlink.Service( - vendor=self.vendor, - product=self.product, - version=self.version, - url=self.url) + vendor=self.vendor, product=self.product, version=self.version, url=self.url + ) instanciated_service = self.service_to_mock() - mocked_service._set_interface( - self.interface_file, - instanciated_service) + mocked_service._set_interface(self.interface_file, instanciated_service) class ServiceRequestHandler(varlink.RequestHandler): service = mocked_service - self.varlink_server = varlink.ThreadingServer( - self.address, ServiceRequestHandler) + self.varlink_server = varlink.ThreadingServer(self.address, ServiceRequestHandler) self.varlink_server.serve_forever() def service_generator(service, info, filename="mockedservice.py"): with open(filename, "w+") as pyfp: - pyfp.write(textwrap.dedent("""\ + pyfp.write( + textwrap.dedent( + """\ ''' Generated by varlink mocking system {datetime} Only for testing purpose and unit testing ''' - """.format(datetime=datetime.datetime.now()))) + """.format(datetime=datetime.datetime.now()) + ) + ) pyfp.write("import varlink\n\n") pyfp.write(inspect.getsource(service)) pyfp.write("\n\n") @@ -118,15 +113,24 @@ def service_generator(service, info, filename="mockedservice.py"): surround = "'" if value["type"] == "raw": surround = "" - pyfp.write(" msp.{key} = {surround}{value}{surround}\n".format( - key=key, value=value["value"], surround=surround)) + pyfp.write( + " msp.{key} = {surround}{value}{surround}\n".format( + key=key, value=value["value"], surround=surround + ) + ) pyfp.write(" msp.run()\n") -def mockedservice(fake_service=None, fake_types=None, - address='unix:@test', name=None, - vendor='varlink', product='mock', version=1, - url='http://localhost'): +def mockedservice( + fake_service=None, + fake_types=None, + address="unix:@test", + name=None, + vendor="varlink", + product="mock", + version=1, + url="http://localhost", +): """ Varlink mocking service @@ -220,29 +224,38 @@ def mockedservice(fake_service=None, fake_types=None, If you try to use it with python 2.x it will raise an ``ImportError``. """ + def decorator(func): def wrapper(*args, **kwargs): - with MockedService(fake_service, fake_types, name=name, - address=address): + with MockedService(fake_service, fake_types, name=name, address=address): try: func(*args, **kwargs) except BrokenPipeError: # manage fake service stopping pass return + return wrapper - return decorator + return decorator -class MockedService(): - def __init__(self, service, types, address='unix:@test', name=None, - vendor='varlink', product='mock', version=1, - url='http://localhost'): +class MockedService: + def __init__( + self, + service, + types, + address="unix:@test", + name=None, + vendor="varlink", + product="mock", + version=1, + url="http://localhost", + ): if not name: module = service.__module__ try: - self.name = os.path.splitext(module)[1].replace('.', '') + self.name = os.path.splitext(module)[1].replace(".", "") except IndexError: self.name = module else: @@ -257,16 +270,14 @@ def __init__(self, service, types, address='unix:@test', name=None, self.version = version self.url = url self.service_info = { - "address": {'type': 'inherited', 'value': address}, - "vendor": {'type': 'inherited', 'value': vendor}, - "product": {'type': 'inherited', 'value': product}, - "version": {'type': 'raw', 'value': version}, - "url": {'type': 'inherited', 'value': url}, - "interface_name": {'type': 'inherited', 'value': self.name}, - "interface_file": { - 'type': 'inherited', - 'value': self.get_interface_file_path()}, - "service_to_mock": {'type': 'raw', 'value': service.__name__}, + "address": {"type": "inherited", "value": address}, + "vendor": {"type": "inherited", "value": vendor}, + "product": {"type": "inherited", "value": product}, + "version": {"type": "raw", "value": version}, + "url": {"type": "inherited", "value": url}, + "interface_name": {"type": "inherited", "value": self.name}, + "interface_file": {"type": "inherited", "value": self.get_interface_file_path()}, + "service_to_mock": {"type": "raw", "value": service.__name__}, } self.generate_interface() @@ -278,8 +289,7 @@ def generate_interface(self): self.interface_description.append(line) attributs = get_interface_attributs(self.service, ignore) for attr in attributs["callables"]: - self.interface_description.append(generate_callable_interface( - self.service, attr)) + self.interface_description.append(generate_callable_interface(self.service, attr)) def get_interface_file_path(self): return "/tmp/{}".format(self.name) @@ -295,8 +305,7 @@ def delete_interface_files(self): def service_start(self): self.service_pid = subprocess.Popen( - [sys.executable, self.mocked_service_file], - env = { "PYTHONPATH": ':'.join(sys.path) } + [sys.executable, self.mocked_service_file], env={"PYTHONPATH": ":".join(sys.path)} ) time.sleep(2) @@ -306,9 +315,7 @@ def service_stop(self): def __enter__(self): self.mocked_service_file = "/tmp/{}".format(self.identifier) - service_generator( - self.service, self.service_info, - filename=self.mocked_service_file) + service_generator(self.service, self.service_info, filename=self.mocked_service_file) self.generate_interface_file() self.service_start() return self diff --git a/varlink/scanner.py b/varlink/scanner.py index f4f9fcf..cf801b4 100644 --- a/varlink/scanner.py +++ b/varlink/scanner.py @@ -3,28 +3,33 @@ import re from types import SimpleNamespace -from collections.abc import (Set, Mapping) +from collections.abc import Set, Mapping from collections import OrderedDict -from .error import (MethodNotFound, InvalidParameter) +from .error import MethodNotFound, InvalidParameter class Scanner: """Class for scanning a varlink interface definition.""" def __init__(self, string): - self.whitespace = re.compile(r'([ \t\n]|#.*$)+', re.ASCII | re.MULTILINE) - self.docstring = re.compile(r'(?:.?)+#(.*)(?:\n|\r\n)') + self.whitespace = re.compile(r"([ \t\n]|#.*$)+", re.ASCII | re.MULTILINE) + self.docstring = re.compile(r"(?:.?)+#(.*)(?:\n|\r\n)") # FIXME: nested () - self.method_signature = re.compile(r'([ \t\n]|#.*$)*(\([^)]*\))([ \t\n]|#.*$)*->([ \t\n]|#.*$)*(\([^)]*\))', - re.ASCII | re.MULTILINE) + self.method_signature = re.compile( + r"([ \t\n]|#.*$)*(\([^)]*\))([ \t\n]|#.*$)*->([ \t\n]|#.*$)*(\([^)]*\))", re.ASCII | re.MULTILINE + ) - self.keyword_pattern = re.compile(r'\b[a-z]+\b|[:,(){}]|->|\[\]|\?|\[string\]\(\)|\[string\]', re.ASCII) + self.keyword_pattern = re.compile( + r"\b[a-z]+\b|[:,(){}]|->|\[\]|\?|\[string\]\(\)|\[string\]", re.ASCII + ) self.patterns = { - 'interface-name': re.compile(r'[A-Za-z]([A-Za-z])*([.][A-Za-z0-9]([-]*[A-Za-z0-9])*)+|xn--([0-9a-z])*([.][A-Za-z0-9]([-]*[A-Za-z0-9])*)+'), - 'member-name': re.compile(r'\b[A-Z][A-Za-z0-9]*\b', re.ASCII), - 'identifier': re.compile(r'\b[A-Za-z]([_]?[A-Za-z0-9])*\b', re.ASCII), + "interface-name": re.compile( + r"[A-Za-z]([A-Za-z])*([.][A-Za-z0-9]([-]*[A-Za-z0-9])*)+|xn--([0-9a-z])*([.][A-Za-z0-9]([-]*[A-Za-z0-9])*)+" + ), + "member-name": re.compile(r"\b[A-Z][A-Za-z0-9]*\b", re.ASCII), + "identifier": re.compile(r"\b[A-Za-z]([_]?[A-Za-z0-9])*\b", re.ASCII), } self.string = string @@ -34,13 +39,12 @@ def __init__(self, string): def get(self, expected): m = self.whitespace.match(self.string, self.pos) if m: - doc = self.docstring.findall(self.string[m.start():m.end()]) + doc = self.docstring.findall(self.string[m.start() : m.end()]) if len(doc): try: self.current_doc += "\n".join(doc) except UnicodeError: - self.current_doc += "\n".join( - [el.decode("utf-8") for el in doc]) + self.current_doc += "\n".join([el.decode("utf-8") for el in doc]) self.pos = m.end() pattern = self.patterns.get(expected) @@ -64,45 +68,44 @@ def expect(self, expected): def end(self): m = self.whitespace.match(self.string, self.pos) if m: - doc = self.docstring.findall(self.string[m.start():m.end()]) + doc = self.docstring.findall(self.string[m.start() : m.end()]) if len(doc): try: self.current_doc += "\n".join(doc) except UnicodeError: - self.current_doc += "\n".join( - [el.decode("utf-8") for el in doc]) + self.current_doc += "\n".join([el.decode("utf-8") for el in doc]) self.pos = m.end() return self.pos >= len(self.string) def read_type(self, lastmaybe=False): - if self.get('?'): + if self.get("?"): if lastmaybe: raise SyntaxError("double '??'") return _Maybe(self.read_type(lastmaybe=True)) - if self.get('[string]()'): + if self.get("[string]()"): return set() - if self.get('[string]'): + if self.get("[string]"): return _Dict(self.read_type()) - if self.get('[]'): + if self.get("[]"): return _Array(self.read_type()) - if self.get('object'): + if self.get("object"): return _Object() - if self.get('bool'): + if self.get("bool"): t = bool() - elif self.get('int'): + elif self.get("int"): t = int() - elif self.get('float'): + elif self.get("float"): t = float() - elif self.get('string'): + elif self.get("string"): t = str() else: - name = self.get('member-name') + name = self.get("member-name") if name: t = _CustomType(name) else: @@ -112,19 +115,19 @@ def read_type(self, lastmaybe=False): def read_struct(self): _isenum = None - self.expect('(') + self.expect("(") fields = OrderedDict() - if not self.get(')'): + if not self.get(")"): while True: - name = self.expect('identifier') + name = self.expect("identifier") if _isenum is None: - if self.get(':'): + if self.get(":"): _isenum = False fields[name] = self.read_type() - if not self.get(','): + if not self.get(","): break continue - elif self.get(','): + elif self.get(","): _isenum = True fields[name] = True continue @@ -132,25 +135,25 @@ def read_struct(self): raise SyntaxError("after '{}'".format(name)) elif not _isenum: try: - self.expect(':') + self.expect(":") fields[name] = self.read_type() except SyntaxError as e: raise SyntaxError("after '{}': {}".format(name, e)) else: fields[name] = True - if not self.get(','): + if not self.get(","): break - self.expect(')') + self.expect(")") if _isenum: return _Enum(fields.keys()) else: return _Struct(fields) def read_member(self): - if self.get('type'): + if self.get("type"): try: - _name = self.expect('member-name') + _name = self.expect("member-name") except SyntaxError: m = self.whitespace.match(self.string, self.pos) if m: @@ -171,24 +174,24 @@ def read_member(self): doc = self.current_doc self.current_doc = "" return _Alias(_name, _type, doc) - elif self.get('method'): - name = self.expect('member-name') + elif self.get("method"): + name = self.expect("member-name") # FIXME sig = self.method_signature.match(self.string, self.pos) if sig: sig = name + sig.group(0) in_type = self.read_struct() - self.expect('->') + self.expect("->") out_type = self.read_struct() doc = self.current_doc self.current_doc = "" return _Method(name, in_type, out_type, sig, doc) - elif self.get('error'): + elif self.get("error"): doc = self.current_doc self.current_doc = "" - return _Error(self.expect('member-name'), self.read_type(), doc) + return _Error(self.expect("member-name"), self.read_type(), doc) else: - raise SyntaxError('expected type, method, or error') + raise SyntaxError("expected type, method, or error") class _Object: @@ -196,43 +199,36 @@ class _Object: class _Struct: - def __init__(self, fields): self.fields = OrderedDict(fields) class _Enum: - def __init__(self, fields): self.fields = fields class _Array: - def __init__(self, element_type): self.element_type = element_type class _Maybe: - def __init__(self, element_type): self.element_type = element_type class _Dict: - def __init__(self, element_type): self.element_type = element_type class _CustomType: - def __init__(self, name): self.name = name class _Alias: - def __init__(self, name, varlink_type, doc=None): self.name = name self.type = varlink_type @@ -240,7 +236,6 @@ def __init__(self, name, varlink_type, doc=None): class _Method: - def __init__(self, name, in_type, out_type, _signature, doc=None): self.name = name self.in_type = in_type @@ -250,7 +245,6 @@ def __init__(self, name, in_type, out_type, _signature, doc=None): class _Error: - def __init__(self, name, varlink_type, doc=None): self.name = name self.type = varlink_type @@ -265,8 +259,8 @@ def __init__(self, description): self.description = description scanner = Scanner(description) - scanner.expect('interface') - self.name = scanner.expect('interface-name') + scanner.expect("interface") + self.name = scanner.expect("interface-name") self.doc = scanner.current_doc scanner.current_doc = "" self.members = OrderedDict() @@ -297,16 +291,19 @@ def filter_params(self, parent_name, varlink_type, _namespaced, args, kwargs): return {} if isinstance(args, Mapping): - for (k, v) in args.items(): - args[k] = self.filter_params(parent_name + '[' + k + ']', varlink_type.element_type, _namespaced, v, - None) + for k, v in args.items(): + args[k] = self.filter_params( + parent_name + "[" + k + "]", varlink_type.element_type, _namespaced, v, None + ) return args else: InvalidParameter(parent_name) if isinstance(varlink_type, _CustomType): # print("CustomType", varlink_type.name) - return self.filter_params(parent_name, self.members.get(varlink_type.name), _namespaced, args, kwargs) + return self.filter_params( + parent_name, self.members.get(varlink_type.name), _namespaced, args, kwargs + ) if isinstance(varlink_type, _Alias): # print("Alias", varlink_type.name) @@ -323,8 +320,10 @@ def filter_params(self, parent_name, varlink_type, _namespaced, args, kwargs): if args is None: return [] - return [self.filter_params(parent_name + '[]', varlink_type.element_type, _namespaced, x, None) for x in - args] + return [ + self.filter_params(parent_name + "[]", varlink_type.element_type, _namespaced, x, None) + for x in args + ] if isinstance(varlink_type, Set): # print("Returned set:", set(args)) @@ -370,8 +369,9 @@ def filter_params(self, parent_name, varlink_type, _namespaced, args, kwargs): args = args[1:] else: args = None - ret = self.filter_params(parent_name + "." + name, varlink_type.fields[name], _namespaced, val, - None) + ret = self.filter_params( + parent_name + "." + name, varlink_type.fields[name], _namespaced, val, None + ) if ret is not None: # print("SetOUT:", name) if _namespaced: @@ -381,8 +381,13 @@ def filter_params(self, parent_name, varlink_type, _namespaced, args, kwargs): continue else: if name in kwargs: - ret = self.filter_params(parent_name + "." + name, varlink_type.fields[name], _namespaced, - kwargs[name], None) + ret = self.filter_params( + parent_name + "." + name, + varlink_type.fields[name], + _namespaced, + kwargs[name], + None, + ) if ret is not None: # print("SetOUT:", name) if _namespaced: @@ -397,8 +402,9 @@ def filter_params(self, parent_name, varlink_type, _namespaced, args, kwargs): continue val = varlink_struct[name] - ret = self.filter_params(parent_name + "." + name, varlink_type.fields[name], _namespaced, val, - None) + ret = self.filter_params( + parent_name + "." + name, varlink_type.fields[name], _namespaced, val, None + ) if ret is not None: # print("SetOUT:", name) if _namespaced: @@ -407,8 +413,9 @@ def filter_params(self, parent_name, varlink_type, _namespaced, args, kwargs): out[name] = ret elif hasattr(varlink_struct, name): val = getattr(varlink_struct, name) - ret = self.filter_params(parent_name + "." + name, varlink_type.fields[name], _namespaced, val, - None) + ret = self.filter_params( + parent_name + "." + name, varlink_type.fields[name], _namespaced, val, None + ) if ret is not None: # print("SetOUT:", name) if _namespaced: diff --git a/varlink/server.py b/varlink/server.py index bab7ef8..894f3b7 100644 --- a/varlink/server.py +++ b/varlink/server.py @@ -7,11 +7,11 @@ import stat import string -from .error import (InterfaceNotFound, InvalidParameter, MethodNotImplemented, VarlinkEncoder, VarlinkError) +from .error import InterfaceNotFound, InvalidParameter, MethodNotImplemented, VarlinkEncoder, VarlinkError from .scanner import Interface -from socketserver import (StreamRequestHandler, BaseServer, ThreadingMixIn) +from socketserver import StreamRequestHandler, BaseServer, ThreadingMixIn if hasattr(os, "fork"): from socketserver import ForkingMixIn @@ -55,7 +55,7 @@ class Service: """ - def __init__(self, vendor='', product='', version='', url='', interface_dir='.', namespaced=False): + def __init__(self, vendor="", product="", version="", url="", interface_dir=".", namespaced=False): """Initialize the service with the data org.varlink.service.GetInfo() returns :param interface_dir: the directory with the \\*.varlink files for the interfaces @@ -71,16 +71,16 @@ def __init__(self, vendor='', product='', version='', url='', interface_dir='.', self.interfaces = {} self.interfaces_handlers = {} directory = os.path.dirname(__file__) - self._add_interface(os.path.abspath(os.path.join(directory, 'org.varlink.service.varlink')), self) + self._add_interface(os.path.abspath(os.path.join(directory, "org.varlink.service.varlink")), self) def GetInfo(self): """The standardized org.varlink.service.GetInfo() varlink method.""" return { - 'vendor': self.vendor, - 'product': self.product, - 'version': self.version, - 'url': self.url, - 'interfaces': list(self.interfaces.keys()) + "vendor": self.vendor, + "product": self.product, + "version": self.version, + "url": self.url, + "interfaces": list(self.interfaces.keys()), } def GetInterfaceDescription(self, interface): @@ -90,11 +90,11 @@ def GetInterfaceDescription(self, interface): except KeyError: raise InterfaceNotFound(interface) - return {'description': i.description} + return {"description": i.description} def _handle(self, message, raw_message, _server=None, _request=None): try: - interface_name, _, method_name = message.get('method', '').rpartition('.') + interface_name, _, method_name = message.get("method", "").rpartition(".") if not interface_name or not method_name: raise InterfaceNotFound(interface_name) @@ -104,7 +104,7 @@ def _handle(self, message, raw_message, _server=None, _request=None): method = interface.get_method(method_name) - parameters = message.get('parameters', {}) + parameters = message.get("parameters", {}) if parameters is None: parameters = {} @@ -118,7 +118,9 @@ def _handle(self, message, raw_message, _server=None, _request=None): if name not in parameters: parameters[name] = None - parameters = interface.filter_params("server.call", method.in_type, self._namespaced, parameters, None) + parameters = interface.filter_params( + "server.call", method.in_type, self._namespaced, parameters, None + ) func = getattr(handler, method_name, None) @@ -129,41 +131,50 @@ def _handle(self, message, raw_message, _server=None, _request=None): if hasattr(inspect, "signature"): sig = inspect.signature(func) - arg_names = [(sig.parameters[k].kind in ( - inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY) and k or None) for k in - sig.parameters.keys()] + arg_names = [ + ( + sig.parameters[k].kind + in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY) + and k + or None + ) + for k in sig.parameters.keys() + ] else: from itertools import izip + spec = inspect.getargspec(func) matched_args = [reversed(x) for x in [spec.args, spec.defaults or []]] arg_names = dict(izip(*matched_args)) - if message.get('more', False) or message.get('oneway', False) or message.get('upgrade', False): - if message.get('more', False) and '_more' in arg_names: + if message.get("more", False) or message.get("oneway", False) or message.get("upgrade", False): + if message.get("more", False) and "_more" in arg_names: kwargs["_more"] = True - if message.get('oneway', False) and '_oneway' in arg_names: + if message.get("oneway", False) and "_oneway" in arg_names: kwargs["_oneway"] = True - if message.get('upgrade', False) and '_upgrade' in arg_names: + if message.get("upgrade", False) and "_upgrade" in arg_names: kwargs["_upgrade"] = True - if '_raw' in arg_names: + if "_raw" in arg_names: kwargs["_raw"] = raw_message - if '_message' in arg_names: + if "_message" in arg_names: kwargs["_message"] = message - if '_interface' in arg_names: + if "_interface" in arg_names: kwargs["_interface"] = interface - if '_method' in arg_names: + if "_method" in arg_names: kwargs["_method"] = method - if '_server' in arg_names: + if "_server" in arg_names: kwargs["_server"] = _server - if '_request' in arg_names: + if "_request" in arg_names: kwargs["_request"] = _request if self._namespaced: # FIXME: check for Maybe before taking None as default value - out = func(*(getattr(parameters, k, default=None) for k in method.in_type.fields.keys()), **kwargs) + out = func( + *(getattr(parameters, k, default=None) for k in method.in_type.fields.keys()), **kwargs + ) else: # FIXME: check for Maybe before taking None as default value out = func(*(parameters.get(k) for k in method.in_type.fields.keys()), **kwargs) @@ -178,17 +189,23 @@ def _handle(self, message, raw_message, _server=None, _request=None): continue cont = True - if '_continues' in o: - cont = o['_continues'] - del o['_continues'] - yield {'continues': bool(cont), - 'parameters': interface.filter_params("server.reply", method.out_type, - self._namespaced, o, - None) or {}} + if "_continues" in o: + cont = o["_continues"] + del o["_continues"] + yield { + "continues": bool(cont), + "parameters": interface.filter_params( + "server.reply", method.out_type, self._namespaced, o, None + ) + or {}, + } else: - yield {'parameters': interface.filter_params("server.reply", method.out_type, - self._namespaced, o, - None) or {}} + yield { + "parameters": interface.filter_params( + "server.reply", method.out_type, self._namespaced, o, None + ) + or {} + } if not cont: return @@ -198,10 +215,10 @@ def _handle(self, message, raw_message, _server=None, _request=None): except StopIteration: pass else: - if message.get('oneway', False): + if message.get("oneway", False): yield None else: - yield {'parameters': out or {}} + yield {"parameters": out or {}} except VarlinkError as error: yield error @@ -220,13 +237,13 @@ def handle(self, message, _server=None, _request=None): if message[-1] == 0: message = message[:-1] - string = message.decode('utf-8') + string = message.decode("utf-8") handle = self._handle(json.loads(string), message, _server, _request) for out in handle: if out is None: return try: - yield json.dumps(out, cls=VarlinkEncoder).encode('utf-8') + yield json.dumps(out, cls=VarlinkEncoder).encode("utf-8") except ConnectionError as e: try: handle.throw(e) @@ -235,7 +252,7 @@ def handle(self, message, _server=None, _request=None): def _add_interface(self, filename, handler): if not os.path.isabs(filename): - filename = os.path.join(self.interface_dir, filename + '.varlink') + filename = os.path.join(self.interface_dir, filename + ".varlink") with open(filename) as f: interface = Interface(f.read()) @@ -243,7 +260,7 @@ def _add_interface(self, filename, handler): self.interfaces_handlers[interface.name] = handler def _set_interface(self, filename, interface_class): - if 'class' in str(type(interface_class)): + if "class" in str(type(interface_class)): ic = interface_class else: ic = interface_class() @@ -251,7 +268,6 @@ def _set_interface(self, filename, interface_class): return interface_class def interface(self, filename): - def decorator(interface_class): self._add_interface(filename, interface_class()) return interface_class @@ -309,10 +325,11 @@ class RequestHandler(StreamRequestHandler): To use as an argument for the VarlinkServer constructor. Instantiate your own class and set the class variable service to your global :class:`Service` object. """ + service = None def handle(self): - message = b'' + message = b"" self.request.setblocking(True) while not self.rfile.closed: @@ -321,18 +338,18 @@ def handle(self): except BrokenPipeError: break - if c == b'': + if c == b"": break - if c != b'\0': + if c != b"\0": message += c continue for reply in self.service.handle(message, _server=self.server, _request=self.request): if reply is not None: - self.wfile.write(reply + b'\0') + self.wfile.write(reply + b"\0") - message = b'' + message = b"" class Server(BaseServer): @@ -380,13 +397,13 @@ def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): elif server_address.startswith("unix:"): self.address_family = socket.AF_UNIX address = server_address[5:] - m = address.rfind(';mode=') + m = address.rfind(";mode=") if m != -1: - self.mode = address[m + 6:] + self.mode = address[m + 6 :] address = address[:m] - if address[0] == '@': - address = address.replace('@', '\0', 1) + if address[0] == "@": + address = address.replace("@", "\0", 1) self.mode = None else: self.remove_file = address @@ -397,20 +414,28 @@ def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): elif server_address.startswith("tcp:"): address = server_address[4:] - p = address.rfind(':') + p = address.rfind(":") if p != -1: - port = int(address[p + 1:]) + port = int(address[p + 1 :]) address = address[:p] else: raise ConnectionError("Invalid address 'tcp:%s'" % address) - address = address.replace('[', '') - address = address.replace(']', '') + address = address.replace("[", "") + address = address.replace("]", "") try: - res = socket.getaddrinfo(address, port, proto=socket.IPPROTO_TCP, flags=socket.AI_NUMERICHOST) + res = socket.getaddrinfo( + address, port, proto=socket.IPPROTO_TCP, flags=socket.AI_NUMERICHOST + ) except TypeError: - res = socket.getaddrinfo(address, port, self.address_family, self.socket_type, socket.IPPROTO_TCP, - socket.AI_NUMERICHOST) + res = socket.getaddrinfo( + address, + port, + self.address_family, + self.socket_type, + socket.IPPROTO_TCP, + socket.AI_NUMERICHOST, + ) af, socktype, proto, canonname, sa = res[0] self.address_family = af @@ -447,7 +472,7 @@ def server_bind(self): self.server_address = self.socket.getsockname() if self.server_address[0] == 0: - self.server_address = '@' + self.server_address[1:].decode('utf-8') + self.server_address = "@" + self.server_address[1:].decode("utf-8") if self.mode: os.fchmod(self.socket.fileno(), mode=int(self.mode, 8)) elif self.mode: @@ -512,8 +537,11 @@ def __exit__(self, *args): self.server_close() -class ThreadingServer(ThreadingMixIn, Server): pass +class ThreadingServer(ThreadingMixIn, Server): + pass if hasattr(os, "fork"): - class ForkingServer(ForkingMixIn, Server): pass + + class ForkingServer(ForkingMixIn, Server): + pass diff --git a/varlink/tests/__init__.py b/varlink/tests/__init__.py index 2223c79..145e7dd 100644 --- a/varlink/tests/__init__.py +++ b/varlink/tests/__init__.py @@ -5,6 +5,7 @@ here = os.path.dirname(__file__) loader = unittest.defaultTestLoader + def suite(): suite = unittest.TestSuite() for fn in os.listdir(here): diff --git a/varlink/tests/test_basic_network.py b/varlink/tests/test_basic_network.py index 76eb7b9..1712eae 100755 --- a/varlink/tests/test_basic_network.py +++ b/varlink/tests/test_basic_network.py @@ -8,11 +8,11 @@ import varlink service = varlink.Service( - vendor='Varlink', - product='Varlink Examples', - version='1', - url='http://varlink.org', - interface_dir=os.path.dirname(__file__) + vendor="Varlink", + product="Varlink Examples", + version="1", + url="http://varlink.org", + interface_dir=os.path.dirname(__file__), ) @@ -28,15 +28,14 @@ def do_run(self, address): server_thread.start() try: - with varlink.Client(address) as client, \ - client.open('org.varlink.service') as _connection: + with varlink.Client(address) as client, client.open("org.varlink.service") as _connection: info = _connection.GetInfo() - self.assertEqual(len(info['interfaces']), 1) - self.assertEqual(info['interfaces'][0], "org.varlink.service") + self.assertEqual(len(info["interfaces"]), 1) + self.assertEqual(info["interfaces"][0], "org.varlink.service") self.assertEqual(info, service.GetInfo()) - desc = _connection.GetInterfaceDescription(info['interfaces'][0]) + desc = _connection.GetInterfaceDescription(info["interfaces"][0]) self.assertEqual(desc, service.GetInterfaceDescription("org.varlink.service")) _connection.close() @@ -50,18 +49,17 @@ def test_tcp(self): def test_anon_unix(self): if platform.startswith("linux"): - self.do_run("unix:@org.varlink.service_anon_test" - + str(os.getpid()) - + threading.current_thread().name - ) + self.do_run( + "unix:@org.varlink.service_anon_test" + str(os.getpid()) + threading.current_thread().name + ) def test_unix(self): if hasattr(socket, "AF_UNIX"): - self.do_run("unix:org.varlink.service_anon_test_" - + str(os.getpid()) - + threading.current_thread().name - ) + self.do_run( + "unix:org.varlink.service_anon_test_" + str(os.getpid()) + threading.current_thread().name + ) def test_wrong_url(self): - self.assertRaises(ConnectionError, self.do_run, - "uenix:org.varlink.service_wrong_url_test_%d" % os.getpid()) + self.assertRaises( + ConnectionError, self.do_run, "uenix:org.varlink.service_wrong_url_test_%d" % os.getpid() + ) diff --git a/varlink/tests/test_certification.py b/varlink/tests/test_certification.py index 3c43a66..c86e55d 100755 --- a/varlink/tests/test_certification.py +++ b/varlink/tests/test_certification.py @@ -18,9 +18,10 @@ ######## CLIENT ############# + def run_client(client): - print('Connecting to %s\n' % client) - with client.open('org.varlink.certification') as con: + print("Connecting to %s\n" % client) + with client.open("org.varlink.certification") as con: ret = con.Start() client_id = ret["client_id"] print("client_id:", client_id) @@ -56,11 +57,11 @@ def run_client(client): ######## SERVER ############# service = varlink.Service( - vendor='Varlink', - product='Varlink Examples', - version='1', - url='http://varlink.org', - interface_dir=os.path.dirname(__file__) + vendor="Varlink", + product="Varlink Examples", + version="1", + url="http://varlink.org", + interface_dir=os.path.dirname(__file__), ) @@ -75,19 +76,22 @@ def sorted_json(dct): class CertificationError(varlink.VarlinkError): - def __init__(self, wants, got): - varlink.VarlinkError.__init__(self, - {'error': 'org.varlink.certification.CertificationError', - 'parameters': {'wants': wants, 'got': got}}) + varlink.VarlinkError.__init__( + self, + { + "error": "org.varlink.certification.CertificationError", + "parameters": {"wants": wants, "got": got}, + }, + ) -@service.interface('org.varlink.certification') +@service.interface("org.varlink.certification") class CertService: next_method = {} def new_client_id(self, _server): - client_id = codecs.getencoder('hex')(os.urandom(16))[0].decode("ascii") + client_id = codecs.getencoder("hex")(os.urandom(16))[0].decode("ascii") if not hasattr(_server, "next_method"): _server.next_method = {} if not hasattr(_server, "lifetimes"): @@ -117,42 +121,55 @@ def check_lifetimes(self, _server): def assert_raw(self, client_id, _server, _raw, _message, wants): if wants != _message: del _server.next_method[client_id] - raise CertificationError(wants, json.loads(_raw.decode('utf-8'))) + raise CertificationError(wants, json.loads(_raw.decode("utf-8"))) def assert_cmp(self, client_id, _server, _raw, wants, _bool): if not _bool: del _server.next_method[client_id] - raise CertificationError(wants, json.loads(_raw.decode('utf-8'))) + raise CertificationError(wants, json.loads(_raw.decode("utf-8"))) def assert_method(self, client_id, _server, from_method, next_method): if not hasattr(_server, "next_method") or client_id not in _server.next_method: - raise CertificationError({"method": "org.varlink.certification.Start+++"}, - {"method": "org.varlink.certification." + from_method}) + raise CertificationError( + {"method": "org.varlink.certification.Start+++"}, + {"method": "org.varlink.certification." + from_method}, + ) self.check_lifetimes(_server) if from_method != _server.next_method[client_id]: - raise CertificationError("Call to method org.varlink.certification." + _server.next_method[client_id], - "Call to method org.varlink.certification." + from_method) + raise CertificationError( + "Call to method org.varlink.certification." + _server.next_method[client_id], + "Call to method org.varlink.certification." + from_method, + ) _server.next_method[client_id] = next_method def Start(self, _server=None, _raw=None, _message=None, _oneway=False): client_id = self.new_client_id(_server) - if 'parameters' in _message and not _message['parameters']: - del _message['parameters'] + if "parameters" in _message and not _message["parameters"]: + del _message["parameters"] self.assert_method(client_id, _server, "Start", "Test01") - self.assert_raw(client_id, _server, _raw, _message, { - "method": "org.varlink.certification.Start", - }) + self.assert_raw( + client_id, + _server, + _raw, + _message, + { + "method": "org.varlink.certification.Start", + }, + ) return {"client_id": client_id} # () -> (bool: bool) def Test01(self, client_id, _server=None, _raw=None, _message=None): self.assert_method(client_id, _server, "Test01", "Test02") - self.assert_raw(client_id, _server, _raw, _message, { - "method": "org.varlink.certification.Test01", - "parameters": {"client_id": client_id} - }) + self.assert_raw( + client_id, + _server, + _raw, + _message, + {"method": "org.varlink.certification.Test01", "parameters": {"client_id": client_id}}, + ) return {"bool": True} # (bool: bool) -> (int: int) @@ -160,7 +177,7 @@ def Test02(self, client_id, _bool, _server=None, _raw=None, _message=None): self.assert_method(client_id, _server, "Test02", "Test03") wants = { "method": "org.varlink.certification.Test02", - "parameters": {"client_id": client_id, "bool": True} + "parameters": {"client_id": client_id, "bool": True}, } self.assert_cmp(client_id, _server, _raw, wants, _bool == True) self.assert_raw(client_id, _server, _raw, _message, wants) @@ -171,7 +188,7 @@ def Test03(self, client_id, _int, _server=None, _raw=None, _message=None): self.assert_method(client_id, _server, "Test03", "Test04") wants = { "method": "org.varlink.certification.Test03", - "parameters": {"client_id": client_id, "int": 1} + "parameters": {"client_id": client_id, "int": 1}, } self.assert_cmp(client_id, _server, _raw, wants, _int == 1) self.assert_raw(client_id, _server, _raw, _message, wants) @@ -182,7 +199,7 @@ def Test04(self, client_id, _float, _server=None, _raw=None, _message=None): self.assert_method(client_id, _server, "Test04", "Test05") wants = { "method": "org.varlink.certification.Test04", - "parameters": {"client_id": client_id, "float": 1.0} + "parameters": {"client_id": client_id, "float": 1.0}, } self.assert_cmp(client_id, _server, _raw, wants, _float == 1.0) self.assert_raw(client_id, _server, _raw, _message, wants) @@ -193,7 +210,7 @@ def Test05(self, client_id, _string, _server=None, _raw=None, _message=None): self.assert_method(client_id, _server, "Test05", "Test06") wants = { "method": "org.varlink.certification.Test05", - "parameters": {"client_id": client_id, "string": "ping"} + "parameters": {"client_id": client_id, "string": "ping"}, } self.assert_cmp(client_id, _server, _raw, wants, _string == "ping") self.assert_raw(client_id, _server, _raw, _message, wants) @@ -210,8 +227,8 @@ def Test06(self, client_id, _bool, _int, _float, _string, _server=None, _raw=Non "bool": False, "int": 2, "float": math.pi, - "string": "a lot of string" - } + "string": "a lot of string", + }, } self.assert_raw(client_id, _server, _raw, _message, wants) self.assert_cmp(client_id, _server, _raw, wants, _int == 2) @@ -228,8 +245,8 @@ def Test07(self, client_id, _dict, _server=None, _raw=None, _message=None): "method": "org.varlink.certification.Test07", "parameters": { "client_id": client_id, - "struct": {"bool": False, "int": 2, "float": math.pi, "string": "a lot of string"} - } + "struct": {"bool": False, "int": 2, "float": math.pi, "string": "a lot of string"}, + }, } self.assert_raw(client_id, _server, _raw, _message, wants) self.assert_cmp(client_id, _server, _raw, wants, _dict["int"] == 2) @@ -241,11 +258,16 @@ def Test07(self, client_id, _dict, _server=None, _raw=None, _message=None): # (map: [string]string) -> (set: [string]()) def Test08(self, client_id, _map, _server=None, _raw=None, _message=None): self.assert_method(client_id, _server, "Test08", "Test09") - self.assert_raw(client_id, _server, _raw, _message, - { - "method": "org.varlink.certification.Test08", - "parameters": {"client_id": client_id, "map": {"foo": "Foo", "bar": "Bar"}} - }) + self.assert_raw( + client_id, + _server, + _raw, + _message, + { + "method": "org.varlink.certification.Test08", + "parameters": {"client_id": client_id, "map": {"foo": "Foo", "bar": "Bar"}}, + }, + ) return {"set": {"one", "two", "three"}} # (set: [string]()) -> (mytype: MyType) @@ -253,10 +275,7 @@ def Test09(self, client_id, _set, _server=None, _raw=None, _message=None): self.assert_method(client_id, _server, "Test09", "Test10") wants = { "method": "org.varlink.certification.Test09", - "parameters": { - "client_id": client_id, - "set": {"one": {}, "three": {}, "two": {}} - } + "parameters": {"client_id": client_id, "set": {"one": {}, "three": {}, "two": {}}}, } self.assert_raw(client_id, _server, _raw, _message, wants) self.assert_cmp(client_id, _server, _raw, wants, isinstance(_set, set)) @@ -267,8 +286,10 @@ def Test09(self, client_id, _set, _server=None, _raw=None, _message=None): return { "client_id": client_id, "mytype": { - "object": {"method": "org.varlink.certification.Test09", - "parameters": {"map": {"foo": "Foo", "bar": "Bar"}}}, + "object": { + "method": "org.varlink.certification.Test09", + "parameters": {"map": {"foo": "Foo", "bar": "Bar"}}, + }, "enum": "two", "struct": {"first": 1, "second": "2"}, "array": ["one", "two", "three"], @@ -277,15 +298,10 @@ def Test09(self, client_id, _set, _server=None, _raw=None, _message=None): "nullable": None, "nullable_array_struct": None, "interface": { - "foo": [ - None, - {"foo": "foo", "bar": "bar"}, - None, - {"one": "foo", "two": "bar"} - ], - "anon": {"foo": True, "bar": False} - } - } + "foo": [None, {"foo": "foo", "bar": "bar"}, None, {"one": "foo", "two": "bar"}], + "anon": {"foo": True, "bar": False}, + }, + }, } # method Test10(mytype: MyType) -> (string: string) @@ -298,24 +314,21 @@ def Test10(self, client_id, mytype, _server=None, _raw=None, _message=None): "parameters": { "client_id": client_id, "mytype": { - "object": {"method": "org.varlink.certification.Test09", - "parameters": {"map": {"foo": "Foo", "bar": "Bar"}}}, + "object": { + "method": "org.varlink.certification.Test09", + "parameters": {"map": {"foo": "Foo", "bar": "Bar"}}, + }, "enum": "two", "struct": {"first": 1, "second": "2"}, "array": ["one", "two", "three"], "dictionary": {"foo": "Foo", "bar": "Bar"}, "stringset": {"one", "two", "three"}, "interface": { - "foo": [ - None, - {"foo": "foo", "bar": "bar"}, - None, - {"one": "foo", "two": "bar"} - ], - "anon": {"foo": True, "bar": False} - } - } - } + "foo": [None, {"foo": "foo", "bar": "bar"}, None, {"one": "foo", "two": "bar"}], + "anon": {"foo": True, "bar": False}, + }, + }, + }, } if "nullable" in mytype: @@ -329,7 +342,7 @@ def Test10(self, client_id, mytype, _server=None, _raw=None, _message=None): self.assert_cmp(client_id, _server, _raw, wants, mytype == wants["parameters"]["mytype"]) for i in range(1, 11): - yield {"string": "Reply number %d" % i, '_continues': i != 10} + yield {"string": "Reply number %d" % i, "_continues": i != 10} # method Test11(last_more_replies: []string) -> () def Test11(self, client_id, last_more_replies, _server=None, _raw=None, _message=None, _oneway=False): @@ -340,26 +353,38 @@ def Test11(self, client_id, last_more_replies, _server=None, _raw=None, _message "parameters": { "client_id": client_id, "last_more_replies": [ - "Reply number 1", "Reply number 2", "Reply number 3", "Reply number 4", - "Reply number 5", "Reply number 6", "Reply number 7", "Reply number 8", - "Reply number 9", "Reply number 10" - ] - } + "Reply number 1", + "Reply number 2", + "Reply number 3", + "Reply number 4", + "Reply number 5", + "Reply number 6", + "Reply number 7", + "Reply number 8", + "Reply number 9", + "Reply number 10", + ], + }, } self.assert_cmp(client_id, _server, _raw, wants, _oneway) for i in range(0, 10): - self.assert_cmp(client_id, _server, _raw, wants, last_more_replies[i] == "Reply number %d" % (i + 1)) + self.assert_cmp( + client_id, _server, _raw, wants, last_more_replies[i] == "Reply number %d" % (i + 1) + ) # method End() -> () def End(self, client_id, _server=None, _raw=None, _message=None): self.assert_method(client_id, _server, "End", "Start") - self.assert_raw(client_id, _server, _raw, _message, { - "method": "org.varlink.certification.End", - "parameters": {"client_id": client_id} - }) + self.assert_raw( + client_id, + _server, + _raw, + _message, + {"method": "org.varlink.certification.End", "parameters": {"client_id": client_id}}, + ) del _server.next_method[client_id] return {"all_ok": True} @@ -376,18 +401,21 @@ def run_server(address): ######## MAIN ############# + def usage(): - print('Usage: %s [[--client] --varlink=]' % sys.argv[0], file=sys.stderr) - print('\tSelf Exec: $ %s' % sys.argv[0], file=sys.stderr) - print('\tServer : $ %s --varlink=' % sys.argv[0], file=sys.stderr) - print('\tClient : $ %s --client --varlink=' % sys.argv[0], file=sys.stderr) - print('\tClient : $ %s --client --bridge=' % sys.argv[0], file=sys.stderr) - print('\tClient : $ %s --client --activate=' % sys.argv[0], file=sys.stderr) + print("Usage: %s [[--client] --varlink=]" % sys.argv[0], file=sys.stderr) + print("\tSelf Exec: $ %s" % sys.argv[0], file=sys.stderr) + print("\tServer : $ %s --varlink=" % sys.argv[0], file=sys.stderr) + print("\tClient : $ %s --client --varlink=" % sys.argv[0], file=sys.stderr) + print("\tClient : $ %s --client --bridge=" % sys.argv[0], file=sys.stderr) + print("\tClient : $ %s --client --activate=" % sys.argv[0], file=sys.stderr) -if __name__ == '__main__': +if __name__ == "__main__": try: - opts, args = getopt.getopt(sys.argv[1:], "b:A:", ["help", "client", "varlink=", "bridge=", "activate="]) + opts, args = getopt.getopt( + sys.argv[1:], "b:A:", ["help", "client", "varlink=", "bridge=", "activate="] + ) except getopt.GetoptError: usage() sys.exit(2) @@ -440,13 +468,14 @@ def usage(): ######## UNITTEST ############# + class TestService(unittest.TestCase): @classmethod def setUpClass(cls): if hasattr(socket, "AF_UNIX"): - cls.address = "unix:org.varlink.certification_" \ - + str(os.getpid()) \ - + threading.current_thread().name + cls.address = ( + "unix:org.varlink.certification_" + str(os.getpid()) + threading.current_thread().name + ) else: cls.address = "tcp:127.0.0.1:23456" @@ -459,8 +488,7 @@ def test_client(self): run_client(varlink.Client.new_with_address(self.address)) def test_01(self): - with varlink.Client(self.address) as client, \ - client.open('org.varlink.certification') as con: + with varlink.Client(self.address) as client, client.open("org.varlink.certification") as con: ret = con.Start() client_id = ret["client_id"] ret = con.Test01(client_id) diff --git a/varlink/tests/test_mocks.py b/varlink/tests/test_mocks.py index e39cc28..188c26e 100644 --- a/varlink/tests/test_mocks.py +++ b/varlink/tests/test_mocks.py @@ -11,18 +11,12 @@ """ -class Service(): - +class Service: def Test1(self, param1: int) -> str: """return test: MyPersonalType""" - return { - "test": { - "foo": "bim", - "bar": "boom" - } - } + return {"test": {"foo": "bim", "bar": "boom"}} - def Test2(self, param1: str="test") -> None: + def Test2(self, param1: str = "test") -> None: pass def Test3(self, param1: str) -> str: @@ -31,25 +25,18 @@ def Test3(self, param1: str) -> str: class TestMockMechanisms(unittest.TestCase): - - @mock.mockedservice( - fake_service=Service, - fake_types=types, - name='org.service.com', - address='unix:@foo' - ) + @mock.mockedservice(fake_service=Service, fake_types=types, name="org.service.com", address="unix:@foo") def test_init(self): with varlink.Client("unix:@foo") as client: - connection = client.open('org.service.com') + connection = client.open("org.service.com") self.assertEqual(connection.Test1(param1=1)["test"]["bar"], "boom") self.assertEqual(connection.Test3(param1="foo")["test"], "foo") class TestMockUtilities(unittest.TestCase): - def test_cast_type(self): - self.assertEqual(mock.cast_type(""), 'int') - self.assertEqual(mock.cast_type(""), 'string') + self.assertEqual(mock.cast_type(""), "int") + self.assertEqual(mock.cast_type(""), "string") def test_get_ignored(self): expected_ignore = dir(mock.MockedService) @@ -59,19 +46,12 @@ def test_get_ignored(self): def test_get_attributs(self): service = Service() attributs = mock.get_interface_attributs(service, mock.get_ignored()) - expected_result = { - "callables": ["Test1", "Test2", "Test3"], - "others": [] - } + expected_result = {"callables": ["Test1", "Test2", "Test3"], "others": []} self.assertEqual(attributs, expected_result) def test_generate_callable_interface(self): service = Service() - generated_itf = mock.generate_callable_interface(service, 'Test1') - self.assertEqual( - generated_itf, - "method Test1(param1: int) -> (test: MyPersonalType)") - generated_itf = mock.generate_callable_interface(service, 'Test3') - self.assertEqual( - generated_itf, - "method Test3(param1: string) -> (test: string)") + generated_itf = mock.generate_callable_interface(service, "Test1") + self.assertEqual(generated_itf, "method Test1(param1: int) -> (test: MyPersonalType)") + generated_itf = mock.generate_callable_interface(service, "Test3") + self.assertEqual(generated_itf, "method Test3(param1: string) -> (test: string)") diff --git a/varlink/tests/test_orgexamplemore.py b/varlink/tests/test_orgexamplemore.py index 834c6bb..5931f48 100755 --- a/varlink/tests/test_orgexamplemore.py +++ b/varlink/tests/test_orgexamplemore.py @@ -32,23 +32,24 @@ ######## CLIENT ############# + def run_client(client): - print('Connecting to %s\n' % client) + print("Connecting to %s\n" % client) try: - with \ - client.open('org.example.more', namespaced=True) as con1, \ - client.open('org.example.more', namespaced=True) as con2: - + with ( + client.open("org.example.more", namespaced=True) as con1, + client.open("org.example.more", namespaced=True) as con2, + ): for m in con1.TestMore(10, _more=True): - if hasattr(m.state, 'start') and m.state.start is not None: + if hasattr(m.state, "start") and m.state.start is not None: if m.state.start: print("--- Start ---", file=sys.stderr) - if hasattr(m.state, 'end') and m.state.end is not None: + if hasattr(m.state, "end") and m.state.end is not None: if m.state.end: print("--- End ---", file=sys.stderr) - if hasattr(m.state, 'progress') and m.state.progress is not None: + if hasattr(m.state, "progress") and m.state.progress is not None: print("Progress:", m.state.progress, file=sys.stderr) if m.state.progress > 50: ret = con2.Ping("Test") @@ -67,11 +68,11 @@ def run_client(client): ######## SERVER ############# service = varlink.Service( - vendor='Varlink', - product='Varlink Examples', - version='1', - url='http://varlink.org', - interface_dir=os.path.dirname(__file__) + vendor="Varlink", + product="Varlink Examples", + version="1", + url="http://varlink.org", + interface_dir=os.path.dirname(__file__), ) @@ -80,38 +81,37 @@ class ServiceRequestHandler(varlink.RequestHandler): class ActionFailed(varlink.VarlinkError): - def __init__(self, reason): - varlink.VarlinkError.__init__(self, - {'error': 'org.example.more.ActionFailed', - 'parameters': {'field': reason}}) + varlink.VarlinkError.__init__( + self, {"error": "org.example.more.ActionFailed", "parameters": {"field": reason}} + ) -@service.interface('org.example.more') +@service.interface("org.example.more") class Example: sleep_duration = 1 def TestMore(self, n, _more=True, _server=None): try: if not _more: - yield varlink.InvalidParameter('more') + yield varlink.InvalidParameter("more") - yield {'state': {'start': True}, '_continues': True} + yield {"state": {"start": True}, "_continues": True} for i in range(0, n): - yield {'state': {'progress': int(i * 100 / n)}, '_continues': True} + yield {"state": {"progress": int(i * 100 / n)}, "_continues": True} time.sleep(self.sleep_duration) - yield {'state': {'progress': 100}, '_continues': True} + yield {"state": {"progress": 100}, "_continues": True} - yield {'state': {'end': True}, '_continues': False} + yield {"state": {"end": True}, "_continues": False} except Exception as error: print("ERROR", error, file=sys.stderr) if _server: _server.shutdown() def Ping(self, ping): - return {'pong': ping} + return {"pong": ping} def StopServing(self, reason=None, _request=None, _server=None): print("Server ends.") @@ -127,13 +127,14 @@ def StopServing(self, reason=None, _request=None, _server=None): def TestMap(self, map): i = 1 ret = {} - for (key, val) in map.items(): + for key, val in map.items(): ret[key] = {"i": i, "val": val} i += 1 - return {'map': ret} + return {"map": ret} def TestObject(self, object): import json + return {"object": json.loads(json.dumps(object))} @@ -148,43 +149,30 @@ def run_server(address): ######## MAIN ############# + def epilog(): - return textwrap.dedent(""" + return textwrap.dedent( + """ Examples: \tSelf Exec: $ {0} \tServer : $ {0} --varlink= \tClient : $ {0} --client --varlink= \tClient : $ {0} --client --bridge= \tClient : $ {0} --client --activate= - """.format(sys.argv[0])) + """.format(sys.argv[0]) + ) -if __name__ == '__main__': +if __name__ == "__main__": parser = argparse.ArgumentParser( - description='Varlink org.example.more test case', + description="Varlink org.example.more test case", epilog=epilog(), - formatter_class=argparse.RawTextHelpFormatter - ) - parser.add_argument( - '--varlink', - type=str, - help='The varlink address' - ) - parser.add_argument( - '-b', '--bridge', - type=str, - help='bridge command' - ) - parser.add_argument( - '-A', '--activate', - type=str, - help='activation command' - ) - parser.add_argument( - '--client', - action='store_true', - help='launch the client mode' + formatter_class=argparse.RawTextHelpFormatter, ) + parser.add_argument("--varlink", type=str, help="The varlink address") + parser.add_argument("-b", "--bridge", type=str, help="bridge command") + parser.add_argument("-A", "--activate", type=str, help="activation command") + parser.add_argument("--client", action="store_true", help="launch the client mode") args = parser.parse_args() address = args.varlink @@ -204,14 +192,12 @@ def epilog(): if not address and not client_mode: if not hasattr(socket, "AF_UNIX"): - print("varlink activate: not supported on platform %s" % platform, - file=sys.stderr) + print("varlink activate: not supported on platform %s" % platform, file=sys.stderr) parser.print_help() sys.exit(2) client_mode = True - with varlink.Client.new_with_activate( - [__file__, "--varlink=$VARLINK_ADDRESS"]) as client: + with varlink.Client.new_with_activate([__file__, "--varlink=$VARLINK_ADDRESS"]) as client: run_client(client) elif client_mode: with client: @@ -224,6 +210,7 @@ def epilog(): ######## UNITTEST ############# + class TestService(unittest.TestCase): def test_service(self): address = "tcp:127.0.0.1:23451" @@ -238,25 +225,25 @@ def test_service(self): run_client(client) - with \ - client.open('org.example.more', namespaced=True) as con1, \ - client.open('org.example.more', namespaced=True) as con2: - + with ( + client.open("org.example.more", namespaced=True) as con1, + client.open("org.example.more", namespaced=True) as con2, + ): self.assertEqual(con1.Ping("Test").pong, "Test") it = con1.TestMore(10, _more=True) m = next(it) - self.assertTrue(hasattr(m.state, 'start')) - self.assertFalse(hasattr(m.state, 'end')) - self.assertFalse(hasattr(m.state, 'progress')) + self.assertTrue(hasattr(m.state, "start")) + self.assertFalse(hasattr(m.state, "end")) + self.assertFalse(hasattr(m.state, "progress")) self.assertIsNotNone(m.state.start) for i in range(0, 110, 10): m = next(it) - self.assertTrue(hasattr(m.state, 'progress')) - self.assertFalse(hasattr(m.state, 'start')) - self.assertFalse(hasattr(m.state, 'end')) + self.assertTrue(hasattr(m.state, "progress")) + self.assertFalse(hasattr(m.state, "start")) + self.assertFalse(hasattr(m.state, "end")) self.assertIsNotNone(m.state.progress) self.assertEqual(i, m.state.progress) @@ -265,9 +252,9 @@ def test_service(self): self.assertEqual("Test", ret.pong) m = next(it) - self.assertTrue(hasattr(m.state, 'end')) - self.assertFalse(hasattr(m.state, 'start')) - self.assertFalse(hasattr(m.state, 'progress')) + self.assertTrue(hasattr(m.state, "end")) + self.assertFalse(hasattr(m.state, "start")) + self.assertFalse(hasattr(m.state, "progress")) self.assertIsNotNone(m.state.end) self.assertRaises(StopIteration, next, it) diff --git a/varlink/tests/test_scanner.py b/varlink/tests/test_scanner.py index da5f2da..cb4e95e 100755 --- a/varlink/tests/test_scanner.py +++ b/varlink/tests/test_scanner.py @@ -83,10 +83,18 @@ def test_complex(self): def test_interfacename(self): self.assertRaises(SyntaxError, varlink.Interface, "interface .a.b.c\nmethod F()->()") - self.assertRaises(SyntaxError, varlink.Interface, "interface com.-example.leadinghyphen\nmethod F()->()") - self.assertRaises(SyntaxError, varlink.Interface, "interface com.example-.danglinghyphen-\nmethod F()->()") - self.assertRaises(SyntaxError, varlink.Interface, "interface co9.example.number-toplevel\nmethod F()->()") - self.assertRaises(SyntaxError, varlink.Interface, "interface 1om.example.number-toplevel\nmethod F()->()") + self.assertRaises( + SyntaxError, varlink.Interface, "interface com.-example.leadinghyphen\nmethod F()->()" + ) + self.assertRaises( + SyntaxError, varlink.Interface, "interface com.example-.danglinghyphen-\nmethod F()->()" + ) + self.assertRaises( + SyntaxError, varlink.Interface, "interface co9.example.number-toplevel\nmethod F()->()" + ) + self.assertRaises( + SyntaxError, varlink.Interface, "interface 1om.example.number-toplevel\nmethod F()->()" + ) self.assertRaises(SyntaxError, varlink.Interface, "interface ab\nmethod F()->()") self.assertRaises(SyntaxError, varlink.Interface, "interface .a.b.c\nmethod F()->()") self.assertRaises(SyntaxError, varlink.Interface, "interface a.b.c.\nmethod F()->()") @@ -107,5 +115,9 @@ def test_interfacename(self): self.assertIsNotNone(varlink.Interface("interface org.varlink.service\nmethod F()->()").name) self.assertIsNotNone(varlink.Interface("interface com.example.0example\nmethod F()->()").name) self.assertIsNotNone(varlink.Interface("interface com.example.example-dash\nmethod F()->()").name) - self.assertIsNotNone(varlink.Interface("interface xn--lgbbat1ad8j.example.algeria\nmethod F()->()").name) - self.assertIsNotNone(varlink.Interface("interface xn--c1yn36f.xn--c1yn36f.xn--c1yn36f\nmethod F()->()").name) + self.assertIsNotNone( + varlink.Interface("interface xn--lgbbat1ad8j.example.algeria\nmethod F()->()").name + ) + self.assertIsNotNone( + varlink.Interface("interface xn--c1yn36f.xn--c1yn36f.xn--c1yn36f\nmethod F()->()").name + ) From c05b9584c7ff27fac01608a281fb0402487655a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 09:47:55 +0100 Subject: [PATCH 03/14] treewide: add trailing commas to make ruff format a bit more vertical --- varlink/error.py | 27 ++++++++++++++++++++++----- varlink/mock.py | 5 ++++- varlink/scanner.py | 3 ++- varlink/server.py | 12 ++++++++++-- varlink/tests/test_certification.py | 19 ++++++++++++++++--- varlink/tests/test_mocks.py | 7 ++++++- 6 files changed, 60 insertions(+), 13 deletions(-) diff --git a/varlink/error.py b/varlink/error.py index 8d11378..101e94f 100644 --- a/varlink/error.py +++ b/varlink/error.py @@ -51,7 +51,8 @@ def parameters(self, namespaced=False): """returns the exception varlink error parameters""" if namespaced: return json.loads( - json.dumps(self.args[0]["parameters"]), object_hook=lambda d: SimpleNamespace(**d) + json.dumps(self.args[0]["parameters"]), + object_hook=lambda d: SimpleNamespace(**d), ) else: return self.args[0].get("parameters") @@ -71,7 +72,11 @@ def new(cls, message, namespaced=False): def __init__(self, interface): VarlinkError.__init__( - self, {"error": "org.varlink.service.InterfaceNotFound", "parameters": {"interface": interface}} + self, + { + "error": "org.varlink.service.InterfaceNotFound", + "parameters": {"interface": interface}, + }, ) @@ -84,7 +89,11 @@ def new(cls, message, namespaced=False): def __init__(self, method): VarlinkError.__init__( - self, {"error": "org.varlink.service.MethodNotFound", "parameters": {"method": method}} + self, + { + "error": "org.varlink.service.MethodNotFound", + "parameters": {"method": method}, + }, ) @@ -97,7 +106,11 @@ def new(cls, message, namespaced=False): def __init__(self, method): VarlinkError.__init__( - self, {"error": "org.varlink.service.MethodNotImplemented", "parameters": {"method": method}} + self, + { + "error": "org.varlink.service.MethodNotImplemented", + "parameters": {"method": method}, + }, ) @@ -112,5 +125,9 @@ def new(cls, message, namespaced=False): def __init__(self, name): VarlinkError.__init__( - self, {"error": "org.varlink.service.InvalidParameter", "parameters": {"parameter": name}} + self, + { + "error": "org.varlink.service.InvalidParameter", + "parameters": {"parameter": name}, + }, ) diff --git a/varlink/mock.py b/varlink/mock.py index 7b815ad..4df2636 100644 --- a/varlink/mock.py +++ b/varlink/mock.py @@ -76,7 +76,10 @@ class MockedServiceProcess: def run(self): mocked_service = varlink.Service( - vendor=self.vendor, product=self.product, version=self.version, url=self.url + vendor=self.vendor, + product=self.product, + version=self.version, + url=self.url, ) instanciated_service = self.service_to_mock() mocked_service._set_interface(self.interface_file, instanciated_service) diff --git a/varlink/scanner.py b/varlink/scanner.py index cf801b4..9b74230 100644 --- a/varlink/scanner.py +++ b/varlink/scanner.py @@ -18,7 +18,8 @@ def __init__(self, string): self.docstring = re.compile(r"(?:.?)+#(.*)(?:\n|\r\n)") # FIXME: nested () self.method_signature = re.compile( - r"([ \t\n]|#.*$)*(\([^)]*\))([ \t\n]|#.*$)*->([ \t\n]|#.*$)*(\([^)]*\))", re.ASCII | re.MULTILINE + r"([ \t\n]|#.*$)*(\([^)]*\))([ \t\n]|#.*$)*->([ \t\n]|#.*$)*(\([^)]*\))", + re.ASCII | re.MULTILINE, ) self.keyword_pattern = re.compile( diff --git a/varlink/server.py b/varlink/server.py index 894f3b7..52eb90f 100644 --- a/varlink/server.py +++ b/varlink/server.py @@ -195,14 +195,22 @@ def _handle(self, message, raw_message, _server=None, _request=None): yield { "continues": bool(cont), "parameters": interface.filter_params( - "server.reply", method.out_type, self._namespaced, o, None + "server.reply", + method.out_type, + self._namespaced, + o, + None, ) or {}, } else: yield { "parameters": interface.filter_params( - "server.reply", method.out_type, self._namespaced, o, None + "server.reply", + method.out_type, + self._namespaced, + o, + None, ) or {} } diff --git a/varlink/tests/test_certification.py b/varlink/tests/test_certification.py index c86e55d..a53ce22 100755 --- a/varlink/tests/test_certification.py +++ b/varlink/tests/test_certification.py @@ -168,7 +168,10 @@ def Test01(self, client_id, _server=None, _raw=None, _message=None): _server, _raw, _message, - {"method": "org.varlink.certification.Test01", "parameters": {"client_id": client_id}}, + { + "method": "org.varlink.certification.Test01", + "parameters": {"client_id": client_id}, + }, ) return {"bool": True} @@ -298,7 +301,12 @@ def Test09(self, client_id, _set, _server=None, _raw=None, _message=None): "nullable": None, "nullable_array_struct": None, "interface": { - "foo": [None, {"foo": "foo", "bar": "bar"}, None, {"one": "foo", "two": "bar"}], + "foo": [ + None, + {"foo": "foo", "bar": "bar"}, + None, + {"one": "foo", "two": "bar"}, + ], "anon": {"foo": True, "bar": False}, }, }, @@ -324,7 +332,12 @@ def Test10(self, client_id, mytype, _server=None, _raw=None, _message=None): "dictionary": {"foo": "Foo", "bar": "Bar"}, "stringset": {"one", "two", "three"}, "interface": { - "foo": [None, {"foo": "foo", "bar": "bar"}, None, {"one": "foo", "two": "bar"}], + "foo": [ + None, + {"foo": "foo", "bar": "bar"}, + None, + {"one": "foo", "two": "bar"}, + ], "anon": {"foo": True, "bar": False}, }, }, diff --git a/varlink/tests/test_mocks.py b/varlink/tests/test_mocks.py index 188c26e..5a9ddc6 100644 --- a/varlink/tests/test_mocks.py +++ b/varlink/tests/test_mocks.py @@ -14,7 +14,12 @@ class Service: def Test1(self, param1: int) -> str: """return test: MyPersonalType""" - return {"test": {"foo": "bim", "bar": "boom"}} + return { + "test": { + "foo": "bim", + "bar": "boom", + }, + } def Test2(self, param1: str = "test") -> None: pass From e929e3fe031e00a162d89216c192112ffb3233e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Tue, 18 Feb 2025 23:06:34 +0100 Subject: [PATCH 04/14] ci: run ruff format check --- .github/workflows/main.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8bd1e1e..17ce5a0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,3 +25,22 @@ jobs: # Use GitHub's Linux Docker host runs-on: ubuntu-latest + + lints: + name: Lints + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install ruff + run: | + python3 -m pip install --break-system-packages ruff + - name: Run ruff format + run: | + ruff --version + if ! ruff format --check --quiet varlink + then + echo "Please run 'ruff format' on the above files or apply the diffs below manually" + ruff format --check --quiet --diff varlink + fi + runs-on: ubuntu-latest From 255f583697e5a3adb934219e5edaa26fe27b2bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 09:50:41 +0100 Subject: [PATCH 05/14] treewide: remove utf-8 markers from files Not all files have them, they are inconsistent in style and Python 3 defaults to UTF-8 anyway. --- docs/conf.py | 2 -- varlink/client.py | 2 -- varlink/scanner.py | 2 -- varlink/server.py | 2 -- 4 files changed, 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 3b30409..ad6691e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- -# # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a diff --git a/varlink/client.py b/varlink/client.py index ba52040..8f1eb51 100644 --- a/varlink/client.py +++ b/varlink/client.py @@ -1,5 +1,3 @@ -# coding=utf-8 - import json import os import shutil diff --git a/varlink/scanner.py b/varlink/scanner.py index 9b74230..952e9fa 100644 --- a/varlink/scanner.py +++ b/varlink/scanner.py @@ -1,5 +1,3 @@ -#!-*-coding:utf8-*- - import re from types import SimpleNamespace diff --git a/varlink/server.py b/varlink/server.py index 52eb90f..f6bf888 100644 --- a/varlink/server.py +++ b/varlink/server.py @@ -1,5 +1,3 @@ -# coding=utf-8 - import inspect import json import os From a2d53fe8e1744949d86261aaecd2dedf24306db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 09:52:24 +0100 Subject: [PATCH 06/14] treewide: run pyupgrade --39-plus --- varlink/mock.py | 10 +++++----- varlink/scanner.py | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/varlink/mock.py b/varlink/mock.py index 4df2636..869eab3 100644 --- a/varlink/mock.py +++ b/varlink/mock.py @@ -43,7 +43,7 @@ def generate_callable_interface(interface, attr): if param.name == "self": continue typeof = param.annotation - sign.append("{}: {}".format(param.name, cast_type(typeof))) + sign.append(f"{param.name}: {cast_type(typeof)}") returned = signature.return_annotation if returned: returned = cast_type(returned) @@ -54,7 +54,7 @@ def generate_callable_interface(interface, attr): if ":" in doc: returned = doc else: - returned = "{}: {}".format(doc, returned) + returned = f"{doc}: {returned}" else: returned = "" return "method {name}({signature}) -> ({returned})".format( @@ -286,7 +286,7 @@ def __init__( def generate_interface(self): ignore = get_ignored() - self.interface_description = ["interface {}".format(self.name)] + self.interface_description = [f"interface {self.name}"] if self.types: for line in self.types.split("\n"): self.interface_description.append(line) @@ -295,7 +295,7 @@ def generate_interface(self): self.interface_description.append(generate_callable_interface(self.service, attr)) def get_interface_file_path(self): - return "/tmp/{}".format(self.name) + return f"/tmp/{self.name}" def generate_interface_file(self): tfp = open(self.get_interface_file_path(), "w+") @@ -317,7 +317,7 @@ def service_stop(self): self.service_pid.communicate() def __enter__(self): - self.mocked_service_file = "/tmp/{}".format(self.identifier) + self.mocked_service_file = f"/tmp/{self.identifier}" service_generator(self.service, self.service_info, filename=self.mocked_service_file) self.generate_interface_file() self.service_start() diff --git a/varlink/scanner.py b/varlink/scanner.py index 952e9fa..ae5bac0 100644 --- a/varlink/scanner.py +++ b/varlink/scanner.py @@ -61,7 +61,7 @@ def get(self, expected): def expect(self, expected): value = self.get(expected) if not value: - raise SyntaxError("expected '{}'".format(expected)) + raise SyntaxError(f"expected '{expected}'") return value def end(self): @@ -102,7 +102,7 @@ def read_type(self, lastmaybe=False): elif self.get("float"): t = float() elif self.get("string"): - t = str() + t = "" else: name = self.get("member-name") if name: @@ -131,13 +131,13 @@ def read_struct(self): fields[name] = True continue else: - raise SyntaxError("after '{}'".format(name)) + raise SyntaxError(f"after '{name}'") elif not _isenum: try: self.expect(":") fields[name] = self.read_type() except SyntaxError as e: - raise SyntaxError("after '{}': {}".format(name, e)) + raise SyntaxError(f"after '{name}': {e}") else: fields[name] = True @@ -165,11 +165,11 @@ def read_member(self): else: stop = start - raise SyntaxError("'{}' not a valid type name.".format(self.string[start:stop])) + raise SyntaxError(f"'{self.string[start:stop]}' not a valid type name.") try: _type = self.read_type() except SyntaxError as e: - raise SyntaxError("in '{}': {}".format(_name, e)) + raise SyntaxError(f"in '{_name}': {e}") doc = self.current_doc self.current_doc = "" return _Alias(_name, _type, doc) From 9a362dccb55ac09ce745da93183da3d68e14faf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 10:11:19 +0100 Subject: [PATCH 07/14] treewide: remove old-style string formatting --- varlink/client.py | 14 ++++++------- varlink/scanner.py | 3 +-- varlink/server.py | 4 ++-- varlink/tests/test_basic_network.py | 10 +++------ varlink/tests/test_certification.py | 31 +++++++++++++++++----------- varlink/tests/test_orgexamplemore.py | 4 ++-- 6 files changed, 34 insertions(+), 32 deletions(-) diff --git a/varlink/client.py b/varlink/client.py index 8f1eb51..3cd0726 100644 --- a/varlink/client.py +++ b/varlink/client.py @@ -317,7 +317,7 @@ class Client: >>> for m in connection.Monitor(_more=True): >>> for e in m.entries: - >>> print("%s: %s" % (e.time, e.message)) + >>> print(f"{e.time}: {e.message}") 2018-01-29 12:19:59Z: [system] Activating via systemd: service name='[…] 2018-01-29 12:19:59Z: Starting Network Manager Script Dispatcher Service... 2018-01-29 12:19:59Z: bound to 10.200.159.150 -- renewal in 1423 seconds. @@ -384,7 +384,7 @@ def _with_activate(self, argv): s = socket.socket(socket.AF_UNIX) s.setblocking(False) self._tmpdir = tempfile.mkdtemp() - address = self._tmpdir + "/" + str(os.getpid()) + address = f"{self._tmpdir}/{os.getpid()}" s.bind(address) s.listen(100) @@ -406,9 +406,9 @@ def _with_activate(self, argv): address = address.replace("\0", "@", 1) for i in range(1, len(argv)): - argv[i] = argv[i].replace("$VARLINK_ADDRESS", "unix:" + address) + argv[i] = argv[i].replace("$VARLINK_ADDRESS", f"unix:{address}") - os.environ["VARLINK_ADDRESS"] = "unix:" + address + os.environ["VARLINK_ADDRESS"] = f"unix:{address}" os.environ["LISTEN_FDS"] = "1" os.environ["LISTEN_FDNAMES"] = "varlink" os.environ["LISTEN_PID"] = str(os.getpid()) @@ -454,7 +454,7 @@ def new_bridge_socket_compat(): thread2.start() return sp[0] - self._str = "Bridge with: '%s'" % " ".join(argv) + self._str = f"Bridge with: '{' '.join(argv)}'" if sys.platform == "win32": self._socket_fn = new_bridge_socket_compat else: @@ -499,7 +499,7 @@ def open_unix(): port = address[p + 1 :] address = address[:p] else: - raise ConnectionError("Invalid address 'tcp:%s'" % address) + raise ConnectionError(f"Invalid address 'tcp:{address}'") address = address.replace("[", "") address = address.replace("]", "") @@ -511,7 +511,7 @@ def open_tcp(): self._socket_fn = open_tcp elif address is not None: - raise ConnectionError("Invalid address '%s'" % address) + raise ConnectionError(f"Invalid address '{address}'") return self diff --git a/varlink/scanner.py b/varlink/scanner.py index ae5bac0..44ca55a 100644 --- a/varlink/scanner.py +++ b/varlink/scanner.py @@ -347,8 +347,7 @@ def filter_params(self, parent_name, varlink_type, _namespaced, args, kwargs): if not isinstance(varlink_type, _Struct): raise InvalidParameter(parent_name) - # SyntaxError("Expected type %s, got %s with value '%s'" % (type(varlink_type), type(args), - # args)) + # SyntaxError(f"Expected type {type(varlink_type)}, got {type(args)} with value '{args}'" if _namespaced: out = SimpleNamespace() diff --git a/varlink/server.py b/varlink/server.py index f6bf888..cfe241d 100644 --- a/varlink/server.py +++ b/varlink/server.py @@ -425,7 +425,7 @@ def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): port = int(address[p + 1 :]) address = address[:p] else: - raise ConnectionError("Invalid address 'tcp:%s'" % address) + raise ConnectionError(f"Invalid address 'tcp:{address}'") address = address.replace("[", "") address = address.replace("]", "") @@ -450,7 +450,7 @@ def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): server_address = sa[0:2] else: - raise ConnectionError("Invalid address '%s'" % server_address) + raise ConnectionError(f"Invalid address '{server_address}'") BaseServer.__init__(self, server_address, RequestHandlerClass) diff --git a/varlink/tests/test_basic_network.py b/varlink/tests/test_basic_network.py index 1712eae..4389cd2 100755 --- a/varlink/tests/test_basic_network.py +++ b/varlink/tests/test_basic_network.py @@ -49,17 +49,13 @@ def test_tcp(self): def test_anon_unix(self): if platform.startswith("linux"): - self.do_run( - "unix:@org.varlink.service_anon_test" + str(os.getpid()) + threading.current_thread().name - ) + self.do_run(f"unix:@org.varlink.service_anon_test{os.getpid()}{threading.current_thread().name}") def test_unix(self): if hasattr(socket, "AF_UNIX"): - self.do_run( - "unix:org.varlink.service_anon_test_" + str(os.getpid()) + threading.current_thread().name - ) + self.do_run(f"unix:org.varlink.service_anon_test_{os.getpid()}{threading.current_thread().name}") def test_wrong_url(self): self.assertRaises( - ConnectionError, self.do_run, "uenix:org.varlink.service_wrong_url_test_%d" % os.getpid() + ConnectionError, self.do_run, f"uenix:org.varlink.service_wrong_url_test_{os.getpid()}" ) diff --git a/varlink/tests/test_certification.py b/varlink/tests/test_certification.py index a53ce22..107d11a 100755 --- a/varlink/tests/test_certification.py +++ b/varlink/tests/test_certification.py @@ -8,6 +8,7 @@ import shlex import socket import sys +import textwrap import threading import time import unittest @@ -20,7 +21,7 @@ def run_client(client): - print("Connecting to %s\n" % client) + print(f"Connecting to {client}\n") with client.open("org.varlink.certification") as con: ret = con.Start() client_id = ret["client_id"] @@ -355,7 +356,7 @@ def Test10(self, client_id, mytype, _server=None, _raw=None, _message=None): self.assert_cmp(client_id, _server, _raw, wants, mytype == wants["parameters"]["mytype"]) for i in range(1, 11): - yield {"string": "Reply number %d" % i, "_continues": i != 10} + yield {"string": f"Reply number {i}", "_continues": i != 10} # method Test11(last_more_replies: []string) -> () def Test11(self, client_id, last_more_replies, _server=None, _raw=None, _message=None, _oneway=False): @@ -383,9 +384,7 @@ def Test11(self, client_id, last_more_replies, _server=None, _raw=None, _message self.assert_cmp(client_id, _server, _raw, wants, _oneway) for i in range(0, 10): - self.assert_cmp( - client_id, _server, _raw, wants, last_more_replies[i] == "Reply number %d" % (i + 1) - ) + self.assert_cmp(client_id, _server, _raw, wants, last_more_replies[i] == f"Reply number {i + 1}") # method End() -> () def End(self, client_id, _server=None, _raw=None, _message=None): @@ -416,12 +415,20 @@ def run_server(address): def usage(): - print("Usage: %s [[--client] --varlink=]" % sys.argv[0], file=sys.stderr) - print("\tSelf Exec: $ %s" % sys.argv[0], file=sys.stderr) - print("\tServer : $ %s --varlink=" % sys.argv[0], file=sys.stderr) - print("\tClient : $ %s --client --varlink=" % sys.argv[0], file=sys.stderr) - print("\tClient : $ %s --client --bridge=" % sys.argv[0], file=sys.stderr) - print("\tClient : $ %s --client --activate=" % sys.argv[0], file=sys.stderr) + arg0 = sys.argv[0] + print( + textwrap.dedent( + f"""\ + Usage: {arg0} [[--client] --varlink=] + \tSelf Exec: $ {arg0} + \tServer : $ {arg0} --varlink= + \tClient : $ {arg0} --client --varlink= + \tClient : $ {arg0} --client --bridge= + \tClient : $ {arg0} --client --activate= + """ + ), + file=sys.stderr, + ) if __name__ == "__main__": @@ -463,7 +470,7 @@ def usage(): if not address and not client_mode: if not hasattr(socket, "AF_UNIX"): - print("varlink activate: not supported on platform %s" % platform, file=sys.stderr) + print(f"varlink activate: not supported on platform {platform}", file=sys.stderr) usage() sys.exit(2) diff --git a/varlink/tests/test_orgexamplemore.py b/varlink/tests/test_orgexamplemore.py index 5931f48..b58b3ac 100755 --- a/varlink/tests/test_orgexamplemore.py +++ b/varlink/tests/test_orgexamplemore.py @@ -34,7 +34,7 @@ def run_client(client): - print("Connecting to %s\n" % client) + print(f"Connecting to {client}\n") try: with ( client.open("org.example.more", namespaced=True) as con1, @@ -192,7 +192,7 @@ def epilog(): if not address and not client_mode: if not hasattr(socket, "AF_UNIX"): - print("varlink activate: not supported on platform %s" % platform, file=sys.stderr) + print(f"varlink activate: not supported on platform {platform}", file=sys.stderr) parser.print_help() sys.exit(2) From d634074f788a94c255dff2f346b8ac73e4a87a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 10:11:32 +0100 Subject: [PATCH 08/14] client: add comments for later cleanup --- varlink/client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/varlink/client.py b/varlink/client.py index 3cd0726..6cff40e 100644 --- a/varlink/client.py +++ b/varlink/client.py @@ -383,6 +383,7 @@ def new_with_activate(cls, argv): def _with_activate(self, argv): s = socket.socket(socket.AF_UNIX) s.setblocking(False) + # TODO: this is not cleaned up self._tmpdir = tempfile.mkdtemp() address = f"{self._tmpdir}/{os.getpid()}" s.bind(address) @@ -413,6 +414,7 @@ def _with_activate(self, argv): os.environ["LISTEN_FDNAMES"] = "varlink" os.environ["LISTEN_PID"] = str(os.getpid()) os.execvp(argv[0], argv) + # TODO: this is unreachable sys.exit(1) # parent s.close() From 95720980c281bba9063566544bf97a256f3020fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 10:29:01 +0100 Subject: [PATCH 09/14] treewide: remove str.format calls in favour of f-strings --- varlink/mock.py | 16 +++++----------- varlink/tests/test_orgexamplemore.py | 15 ++++++++------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/varlink/mock.py b/varlink/mock.py index 869eab3..1a452c7 100644 --- a/varlink/mock.py +++ b/varlink/mock.py @@ -57,9 +57,7 @@ def generate_callable_interface(interface, attr): returned = f"{doc}: {returned}" else: returned = "" - return "method {name}({signature}) -> ({returned})".format( - name=attr, signature=",".join(sign), returned=returned - ) + return f"method {attr}({','.join(sign)}) -> ({returned})" class MockedServiceProcess: @@ -95,14 +93,14 @@ def service_generator(service, info, filename="mockedservice.py"): with open(filename, "w+") as pyfp: pyfp.write( textwrap.dedent( - """\ + f"""\ ''' Generated by varlink mocking system - {datetime} + {datetime.datetime.now()} Only for testing purpose and unit testing ''' - """.format(datetime=datetime.datetime.now()) + """ ) ) pyfp.write("import varlink\n\n") @@ -116,11 +114,7 @@ def service_generator(service, info, filename="mockedservice.py"): surround = "'" if value["type"] == "raw": surround = "" - pyfp.write( - " msp.{key} = {surround}{value}{surround}\n".format( - key=key, value=value["value"], surround=surround - ) - ) + pyfp.write(f" msp.{key} = {surround}{value['value']}{surround}\n") pyfp.write(" msp.run()\n") diff --git a/varlink/tests/test_orgexamplemore.py b/varlink/tests/test_orgexamplemore.py index b58b3ac..fd0859c 100755 --- a/varlink/tests/test_orgexamplemore.py +++ b/varlink/tests/test_orgexamplemore.py @@ -151,15 +151,16 @@ def run_server(address): def epilog(): + arg0 = sys.argv[0] return textwrap.dedent( - """ + f""" Examples: - \tSelf Exec: $ {0} - \tServer : $ {0} --varlink= - \tClient : $ {0} --client --varlink= - \tClient : $ {0} --client --bridge= - \tClient : $ {0} --client --activate= - """.format(sys.argv[0]) + \tSelf Exec: $ {arg0} + \tServer : $ {arg0} --varlink= + \tClient : $ {arg0} --client --varlink= + \tClient : $ {arg0} --client --bridge= + \tClient : $ {arg0} --client --activate= + """ ) From 474c111ac2fe1c9bafec94329cb1668a71bd2a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 10:29:47 +0100 Subject: [PATCH 10/14] treewide: sort imports --- varlink/__init__.py | 12 ++++++------ varlink/client.py | 4 ++-- varlink/error.py | 2 -- varlink/scanner.py | 8 +++----- varlink/server.py | 4 +--- varlink/tests/test_basic_network.py | 1 - varlink/tests/test_certification.py | 1 - varlink/tests/test_mocks.py | 4 ++-- varlink/tests/test_orgexamplemore.py | 1 - 9 files changed, 14 insertions(+), 23 deletions(-) diff --git a/varlink/__init__.py b/varlink/__init__.py index bef489b..2d501f2 100644 --- a/varlink/__init__.py +++ b/varlink/__init__.py @@ -58,15 +58,15 @@ from .client import Client, ClientInterfaceHandler, SimpleClientInterfaceHandler from .error import ( - VarlinkEncoder, - VarlinkError, - InvalidParameter, InterfaceNotFound, - MethodNotImplemented, + InvalidParameter, MethodNotFound, + MethodNotImplemented, + VarlinkEncoder, + VarlinkError, ) -from .scanner import Scanner, Interface -from .server import Service, get_listen_fd, Server, ThreadingServer, RequestHandler +from .scanner import Interface, Scanner +from .server import RequestHandler, Server, Service, ThreadingServer, get_listen_fd # There are no tests here, so don't try to run anything discovered from diff --git a/varlink/client.py b/varlink/client.py index 6cff40e..152acba 100644 --- a/varlink/client.py +++ b/varlink/client.py @@ -3,12 +3,12 @@ import shutil import signal import socket +import subprocess import sys import tempfile -import subprocess import threading -from .error import VarlinkError, InterfaceNotFound, VarlinkEncoder +from .error import InterfaceNotFound, VarlinkEncoder, VarlinkError from .scanner import Interface, _Method diff --git a/varlink/error.py b/varlink/error.py index 101e94f..d72e872 100644 --- a/varlink/error.py +++ b/varlink/error.py @@ -1,6 +1,4 @@ import json - - from types import SimpleNamespace diff --git a/varlink/scanner.py b/varlink/scanner.py index 44ca55a..6df03a6 100644 --- a/varlink/scanner.py +++ b/varlink/scanner.py @@ -1,11 +1,9 @@ import re - -from types import SimpleNamespace -from collections.abc import Set, Mapping - from collections import OrderedDict +from collections.abc import Mapping, Set +from types import SimpleNamespace -from .error import MethodNotFound, InvalidParameter +from .error import InvalidParameter, MethodNotFound class Scanner: diff --git a/varlink/server.py b/varlink/server.py index cfe241d..633eda9 100644 --- a/varlink/server.py +++ b/varlink/server.py @@ -4,13 +4,11 @@ import socket import stat import string +from socketserver import BaseServer, StreamRequestHandler, ThreadingMixIn from .error import InterfaceNotFound, InvalidParameter, MethodNotImplemented, VarlinkEncoder, VarlinkError from .scanner import Interface - -from socketserver import StreamRequestHandler, BaseServer, ThreadingMixIn - if hasattr(os, "fork"): from socketserver import ForkingMixIn diff --git a/varlink/tests/test_basic_network.py b/varlink/tests/test_basic_network.py index 4389cd2..fcabe3b 100755 --- a/varlink/tests/test_basic_network.py +++ b/varlink/tests/test_basic_network.py @@ -4,7 +4,6 @@ import unittest from sys import platform - import varlink service = varlink.Service( diff --git a/varlink/tests/test_certification.py b/varlink/tests/test_certification.py index 107d11a..dd24243 100755 --- a/varlink/tests/test_certification.py +++ b/varlink/tests/test_certification.py @@ -16,7 +16,6 @@ import varlink - ######## CLIENT ############# diff --git a/varlink/tests/test_mocks.py b/varlink/tests/test_mocks.py index 5a9ddc6..6bdac1d 100644 --- a/varlink/tests/test_mocks.py +++ b/varlink/tests/test_mocks.py @@ -1,7 +1,7 @@ import unittest -from varlink import mock -import varlink +import varlink +from varlink import mock types = """ type MyPersonalType ( diff --git a/varlink/tests/test_orgexamplemore.py b/varlink/tests/test_orgexamplemore.py index fd0859c..51ed30a 100755 --- a/varlink/tests/test_orgexamplemore.py +++ b/varlink/tests/test_orgexamplemore.py @@ -29,7 +29,6 @@ import varlink - ######## CLIENT ############# From 5966ec839e7952530db5145cad5b5682e5a42043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 10:30:02 +0100 Subject: [PATCH 11/14] treewide: run ruff --fix This removes unused imports and empty constructor calls for constants. --- varlink/client.py | 2 +- varlink/scanner.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/varlink/client.py b/varlink/client.py index 152acba..0e9dda7 100644 --- a/varlink/client.py +++ b/varlink/client.py @@ -275,7 +275,7 @@ def pipe_bridge(reader, writer): elif hasattr: writer.write(data) writer.flush() - except Exception as e: + except Exception: reader.close() writer.close() return diff --git a/varlink/scanner.py b/varlink/scanner.py index 6df03a6..71bc27c 100644 --- a/varlink/scanner.py +++ b/varlink/scanner.py @@ -94,11 +94,11 @@ def read_type(self, lastmaybe=False): return _Object() if self.get("bool"): - t = bool() + t = False elif self.get("int"): - t = int() + t = 0 elif self.get("float"): - t = float() + t = 0.0 elif self.get("string"): t = "" else: From e10d9f37c6ced561abd52254c755c11befe72b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 14:23:22 +0100 Subject: [PATCH 12/14] treewide: silence minor ruff warnings Silence the warning for overly long lines and the warnings for direct comparions with bools (E712). The latter *cannot* be fixed by using the bare values, as is recommended and needs investigation in the future. --- varlink/client.py | 2 +- varlink/server.py | 2 +- varlink/tests/test_certification.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/varlink/client.py b/varlink/client.py index 0e9dda7..00e611e 100644 --- a/varlink/client.py +++ b/varlink/client.py @@ -330,7 +330,7 @@ class Client: not return a normal namespace wrapped varlink return value, but a generator, which yields the return values and waits (blocks) for the service to return more return values in the generator's .__next__() call. - """ + """ # noqa: E501 handler = SimpleClientInterfaceHandler diff --git a/varlink/server.py b/varlink/server.py index 633eda9..d204f27 100644 --- a/varlink/server.py +++ b/varlink/server.py @@ -378,7 +378,7 @@ class Server(BaseServer): >>> >>> server = varlink.ThreadingServer(sys.argv[1][10:], ServiceRequestHandler) >>> server.serve_forever() - """ + """ # noqa: E501 address_family = socket.AF_INET diff --git a/varlink/tests/test_certification.py b/varlink/tests/test_certification.py index dd24243..8fc59fd 100755 --- a/varlink/tests/test_certification.py +++ b/varlink/tests/test_certification.py @@ -182,7 +182,7 @@ def Test02(self, client_id, _bool, _server=None, _raw=None, _message=None): "method": "org.varlink.certification.Test02", "parameters": {"client_id": client_id, "bool": True}, } - self.assert_cmp(client_id, _server, _raw, wants, _bool == True) + self.assert_cmp(client_id, _server, _raw, wants, _bool == True) # noqa: E712 self.assert_raw(client_id, _server, _raw, _message, wants) return {"int": 1} @@ -235,7 +235,7 @@ def Test06(self, client_id, _bool, _int, _float, _string, _server=None, _raw=Non } self.assert_raw(client_id, _server, _raw, _message, wants) self.assert_cmp(client_id, _server, _raw, wants, _int == 2) - self.assert_cmp(client_id, _server, _raw, wants, _bool == False) + self.assert_cmp(client_id, _server, _raw, wants, _bool == False) # noqa: E712 self.assert_cmp(client_id, _server, _raw, wants, _float == math.pi) self.assert_cmp(client_id, _server, _raw, wants, _string == "a lot of string") @@ -253,7 +253,7 @@ def Test07(self, client_id, _dict, _server=None, _raw=None, _message=None): } self.assert_raw(client_id, _server, _raw, _message, wants) self.assert_cmp(client_id, _server, _raw, wants, _dict["int"] == 2) - self.assert_cmp(client_id, _server, _raw, wants, _dict["bool"] == False) + self.assert_cmp(client_id, _server, _raw, wants, _dict["bool"] == False) # noqa: E712 self.assert_cmp(client_id, _server, _raw, wants, _dict["float"] == math.pi) self.assert_cmp(client_id, _server, _raw, wants, _dict["string"] == "a lot of string") return {"map": {"foo": "Foo", "bar": "Bar"}} From d04ff599b9074d2d26a7f0baa8ea2a29209bdeee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 14:39:53 +0100 Subject: [PATCH 13/14] treewide: remove usage of bare except Bare except catches BaseException, which includes SystemExit and KeyboardInterrupt. This is probably not intended in the places where this is used. Instead except Exception instead, which all "normal" exceptions derive from. Where possible use the correct exception, use exception-free code or annotate a more likely exception for the future. --- varlink/client.py | 8 ++++---- varlink/server.py | 16 +++++----------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/varlink/client.py b/varlink/client.py index 00e611e..e103e43 100644 --- a/varlink/client.py +++ b/varlink/client.py @@ -207,7 +207,7 @@ def close(self): try: if hasattr(self._connection, "shutdown"): self._connection.shutdown(socket.SHUT_RDWR) - except: + except Exception: # TODO: maybe just OSError? pass self._connection.close() @@ -261,7 +261,7 @@ def pipe_bridge(reader, writer): data = reader.recv(8192) else: data = reader.read(1) - except: + except Exception: # TODO: maybe just OsError? data = [] if len(data) == 0: @@ -275,7 +275,7 @@ def pipe_bridge(reader, writer): elif hasattr: writer.write(data) writer.flush() - except Exception: + except Exception: # TODO: maybe just OsError? reader.close() writer.close() return @@ -560,7 +560,7 @@ def cleanup(self): pass try: os.waitpid(self._child_pid, 0) - except: + except Exception: # TODO: maybe just ChildProcessError? pass def open(self, interface_name, namespaced=False, connection=None): diff --git a/varlink/server.py b/varlink/server.py index d204f27..4dc54d8 100644 --- a/varlink/server.py +++ b/varlink/server.py @@ -284,16 +284,10 @@ def get_listen_fd(): return None if "LISTEN_PID" not in os.environ: return None - try: - if int(os.environ["LISTEN_PID"]) != os.getpid(): - return None - except: + if int(os.environ.get("LISTEN_PID", -1)) != os.getpid(): return None - try: - fds = int(os.environ["LISTEN_FDS"]) - except: - return None + fds = int(os.environ.get("LISTEN_FDS", -1)) if fds < 1: return None @@ -456,7 +450,7 @@ def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): try: self.server_bind() self.server_activate() - except: + except Exception: # TODO: maybe just OSError? self.server_close() raise @@ -499,7 +493,7 @@ def server_close(self): if self.remove_file: try: os.remove(self.remove_file) - except: + except OSError: pass self.socket.close() @@ -526,7 +520,7 @@ def shutdown_request(self, request): # the socket and waits for GC to perform the actual close. request.shutdown(socket.SHUT_RDWR) - except: + except Exception: # TODO: maybe just OSError? pass # some platforms may raise ENOTCONN here self.close_request(request) From 25ab289f4f4266f27e18a0f8c29eec70b61f3492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Behrmann?= Date: Wed, 19 Feb 2025 14:42:51 +0100 Subject: [PATCH 14/14] ci: enable ruff check --- .github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 17ce5a0..a6f53a4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,4 +43,8 @@ jobs: echo "Please run 'ruff format' on the above files or apply the diffs below manually" ruff format --check --quiet --diff varlink fi + - name: Run ruff check + run: | + ruff --version + ruff check varlink runs-on: ubuntu-latest