diff --git a/.gitignore b/.gitignore index 894a44c..2720e07 100644 --- a/.gitignore +++ b/.gitignore @@ -89,6 +89,7 @@ venv/ ENV/ env.bak/ venv.bak/ +.vscode/ # Spyder project settings .spyderproject diff --git a/.pylintrc b/.pylintrc index 735722a..2cff6b5 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,28 +1,30 @@ [MASTER] - +# Ignore requiring existence of __init__.py to be able to have generic pylint . +disable=F0010 # Specify a configuration file. -rcfile= +#rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= -# Profiled execution. -profile=no - # Add files or directories to the blacklist. They should be base names, not # paths. -ignore=CVS +ignore=third_party,zuul.d,docs + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns=object_detection_grpc_client.py,prediction_pb2.py,prediction_pb2_grpc.py # Pickle collected data for later comparisons. -persistent=yes +persistent=no # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= # Use multiple processes to speed up Pylint. -jobs=1 +jobs=4 # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. @@ -33,29 +35,41 @@ unsafe-load-any-extension=no # run arbitrary code extension-pkg-whitelist= -# Allow optimization of some AST trees. This will activate a peephole AST -# optimizer, which will apply various small optimizations. For instance, it can -# be used to obtain the result of joining multiple strings with the addition -# operator. Joining a lot of strings can lead to a maximum recursion error in -# Pylint and this flag can prevent that. It has one side effect, the resulting -# AST will be different than the one from reality. -optimize-ast=no +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +# +# Kubeflow disables string-interpolation because we are starting to use f +# style strings [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. -output-format=text - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". -files-output=no +output-format=json # Tells whether to display a full report or only the messages -reports=yes +reports=no # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which @@ -64,84 +78,73 @@ reports=yes # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) -# Add a comment according to your evaluation note. This is used by the global -# evaluation report (RP0004). -comment=no - # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details #msg-template= -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= +[BASIC] -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time. See also the "--disable" option for examples. -#enable= +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -disable=I0011,R0201,R0902,R0903,R0912,R0913,R0921,R0922,R0801,C0325,W0511 +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= -[MISCELLANEOUS] +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ -[LOGGING] +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ -[VARIABLES] +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ -# Tells whether we should check for unused import in __init__ files. -init-import=no +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_$|dummy +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ -[SPELLING] +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 -# List of comma separated words that should not be checked. -spelling-ignore-words= -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= +[ELIF] -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 [TYPECHECK] @@ -152,27 +155,30 @@ ignore-mixin-members=yes # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. ignored-modules= -# List of classes names for which member attributes should not be checked -# (useful for classes with attributes dynamically set). -ignored-classes=SQLObject - -# When zope mode is activated, add a predefined set of Zope acquired attributes -# to generated-members. -zope=no +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local # List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E0201 when accessed. Python regular +# system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. -generated-members=REQUEST,acl_users,aq_parent +generated-members= + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager [FORMAT] # Maximum number of characters on a single line. -max-line-length=119 +max-line-length=120 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ @@ -181,132 +187,122 @@ ignore-long-lines=^\s*(# )??$ # else. single-line-if-stmt=no -# List of optional constructs for which whitespace checking is disabled -no-space-check=trailing-comma,dict-separator - # Maximum number of lines in a module max-module-lines=1000 -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). +# Use 2 spaces consistent with TensorFlow style. indent-string=' ' -# Number of spaces of indent required inside a hanging or continued line. +# Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format= -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=4 - -# Ignore comments when computing similarities. -ignore-comments=yes +[MISCELLANEOUS] -# Ignore docstrings when computing similarities. -ignore-docstrings=yes +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO -# Ignore imports when computing similarities. -ignore-imports=no +[VARIABLES] -[BASIC] +# Tells whether we should check for unused import in __init__ files. +init-import=no -# Required attributes for module, separated by a comma -required-attributes= +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy -# List of builtins function names that should not be used, separated by a comma -bad-functions=map,filter,apply,input +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_ +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,future.builtins -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no +[LOGGING] -# Regular expression matching correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging -# Naming hint for variable names -variable-name-hint=[a-z_][a-z0-9_]{2,30}$ -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +[SIMILARITIES] -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +# Minimum lines number of a similarity. +min-similarity-lines=4 -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ +# Ignore comments when computing similarities. +ignore-comments=yes -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ +# Ignore docstrings when computing similarities. +ignore-docstrings=yes -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ +# Ignore imports when computing similarities. +ignore-imports=no -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ -# Regular expression matching correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ +[SPELLING] -# Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ +# List of comma separated words that should not be checked. +spelling-ignore-words= -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= -# Regular expression matching correct function names -function-rgx=[a-z_][a-z0-9_]{2,30}$ +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no -# Naming hint for function names -function-name-hint=[a-z_][a-z0-9_]{2,30}$ -# Regular expression matching correct attribute names -attr-rgx=[a-z_][a-z0-9_]{2,30}$ +[IMPORTS] -# Naming hint for attribute names -attr-name-hint=[a-z_][a-z0-9_]{2,30}$ +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,TERMIOS,Bastion,rexec -# Regular expression matching correct method names -method-rgx=[a-z_][a-z0-9_]{2,30}$ +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= -# Naming hint for method names -method-name-hint=[a-z_][a-z0-9_]{2,30}$ +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= -# Regular expression matching correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= -# Naming hint for argument names -argument-name-hint=[a-z_][a-z0-9_]{2,30}$ +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=__.*__ +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no [DESIGN] # Maximum number of arguments for function / method -max-args=5 +max-args=7 # Argument names that match this expression will be ignored. Default to name # with leading underscore @@ -331,17 +327,16 @@ max-parents=7 max-attributes=7 # Minimum number of public methods for a class (see R0903). -min-public-methods=2 +min-public-methods=0 # Maximum number of public methods for a class (see R0904). max-public-methods=20 +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 -[CLASSES] -# List of interface methods to ignore, separated by a comma. This is used for -# instance to not check methods defines in Zope's Interface base class. -ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by +[CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp @@ -357,26 +352,7 @@ valid-metaclass-classmethod-first-arg=mcs exclude-protected=_asdict,_fields,_replace,_source,_make -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=stringprep,optparse - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - - [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" -overgeneral-exceptions=Exception diff --git a/dlt/core/core_2185.py b/dlt/core/core_2185.py deleted file mode 100644 index 5435eb0..0000000 --- a/dlt/core/core_2185.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (C) 2019. BMW Car IT GmbH. All rights reserved. -"""v2.18.5 specific class definitions""" -import ctypes - -# DltClientMode from dlt_client.h -DLT_CLIENT_MODE_UNDEFINED = -1 -DLT_CLIENT_MODE_TCP = 0 -DLT_CLIENT_MODE_SERIAL = 1 -DLT_CLIENT_MODE_UNIX = 2 -DLT_CLIENT_MODE_UDP_MULTICAST = 3 - -# DltReceiverType from dlt_common.h -# DltReceiverType is an enum type. These definitions could not be found in shared library (libdlt.so) so -# the enum values are defined here. -DLT_RECEIVE_SOCKET = 0 -DLT_RECEIVE_UDP_SOCKET = 1 -DLT_RECEIVE_FD = 2 - - -class sockaddr_in(ctypes.Structure): # pylint: disable=invalid-name - """Auxiliary definition for cDltReceiver. Defined in netinet/in.h header""" - - _fields_ = [ - ("sa_family", ctypes.c_ushort), # sin_family - ("sin_port", ctypes.c_ushort), - ("sin_addr", ctypes.c_byte * 4), - ("__pad", ctypes.c_byte * 8), - ] # struct sockaddr_in is 16 - - -class cDltReceiver(ctypes.Structure): # pylint: disable=invalid-name - """The structure is used to organise the receiving of data including buffer handling. - This structure is used by the corresponding functions. - - typedef struct - { - int32_t lastBytesRcvd; /**< bytes received in last receive call */ - int32_t bytesRcvd; /**< received bytes */ - int32_t totalBytesRcvd; /**< total number of received bytes */ - char *buffer; /**< pointer to receiver buffer */ - char *buf; /**< pointer to position within receiver buffer */ - char *backup_buf; /** pointer to the buffer with partial messages if any **/ - int fd; /**< connection handle */ - int32_t buffersize; /**< size of receiver buffer */ - struct sockaddr_in addr; /**< socket address information */ - } DltReceiver; - """ - - _fields_ = [ - ("lastBytesRcvd", ctypes.c_int32), - ("bytesRcvd", ctypes.c_int32), - ("totalBytesRcvd", ctypes.c_int32), - ("buffer", ctypes.POINTER(ctypes.c_char)), - ("buf", ctypes.POINTER(ctypes.c_char)), - ("backup_buf", ctypes.POINTER(ctypes.c_char)), - ("fd", ctypes.c_int), - ("buffersize", ctypes.c_int32), - ("addr", sockaddr_in), - ] - - -class cDltClient(ctypes.Structure): # pylint: disable=invalid-name - """ - typedef struct - { - DltReceiver receiver; /**< receiver pointer to dlt receiver structure */ - int sock; /**< sock Connection handle/socket */ - char *servIP; /**< servIP IP adress/Hostname of TCP/IP interface */ - char *hostip; /**< IP multicast address of group */ - int port; /**< Port for TCP connections (optional) */ - char *serialDevice; /**< serialDevice Devicename of serial device */ - char *socketPath; /**< socketPath Unix socket path */ - char ecuid[4]; /**< ECUiD */ - speed_t baudrate; /**< baudrate Baudrate of serial interface, as speed_t */ - DltClientMode mode; /**< mode DltClientMode */ - } DltClient; - """ - - _fields_ = [ - ("receiver", cDltReceiver), - ("sock", ctypes.c_int), - ("servIP", ctypes.c_char_p), - ("hostip", ctypes.c_char_p), - ("port", ctypes.c_int), - ("serialDevice", ctypes.c_char_p), - ("socketPath", ctypes.c_char_p), - ("ecuid", ctypes.c_char * 4), - ("baudrate", ctypes.c_uint), - ("mode", ctypes.c_int), - ] diff --git a/dlt/dlt.py b/dlt/dlt.py index 888b0d4..ac615c6 100644 --- a/dlt/dlt.py +++ b/dlt/dlt.py @@ -7,6 +7,7 @@ import re import socket import struct +import sys import time import threading import multiprocessing @@ -30,8 +31,10 @@ cDLTMessage, cDltStorageHeader, cDltStandardHeader, + DLT_TYPE_INFO_BOOL, DLT_TYPE_INFO_UINT, DLT_TYPE_INFO_SINT, + DLT_TYPE_INFO_FLOA, DLT_TYPE_INFO_STRG, DLT_TYPE_INFO_SCOD, DLT_TYPE_INFO_TYLE, @@ -171,7 +174,12 @@ def get_scod(type_info): value = struct.unpack_from("Q", self._buf, offset)[0] offset += 8 elif tyle == DLT_TYLE_128BIT: - raise TypeError("reading 128BIT values not supported") + value = struct.unpack_from("QQ", self._buf, offset) + offset += 16 + if sys.byteorder == "little": + value = (value[1] << 64) | value[0] + else: + value = (value[0] << 64) | value[1] elif type_info & DLT_TYPE_INFO_SINT: if type_info & DLT_TYPE_INFO_VARI: @@ -191,7 +199,20 @@ def get_scod(type_info): value = struct.unpack_from("q", self._buf, offset)[0] offset += 8 elif tyle == DLT_TYLE_128BIT: - raise TypeError("reading 128BIT values not supported") + value = struct.unpack_from("qq", self._buf, offset) + offset += 16 + if sys.byteorder == "little": + value = (value[1] << 64) | value[0] + else: + value = (value[0] << 64) | value[1] + + elif type_info & DLT_TYPE_INFO_FLOA: + if type_info & DLT_TYLE_64BIT: + value = struct.unpack_from("d", self._buf, offset)[0] + offset += 8 + else: + value = struct.unpack_from("f", self._buf, offset)[0] + offset += 4 elif type_info & DLT_TYPE_INFO_RAWD: if type_info & DLT_TYPE_INFO_VARI: @@ -203,6 +224,10 @@ def get_scod(type_info): value = self._buf[offset : offset + length] offset += length + elif type_info & DLT_TYPE_INFO_BOOL: + value = struct.unpack_from("?", self._buf, offset)[0] + offset += 1 + else: value = "ERROR" diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/img/favicon.ico b/docs/_static/img/favicon.ico new file mode 100644 index 0000000..99ccfd9 Binary files /dev/null and b/docs/_static/img/favicon.ico differ diff --git a/docs/_templates/versions.html b/docs/_templates/versions.html new file mode 100644 index 0000000..31a1257 --- /dev/null +++ b/docs/_templates/versions.html @@ -0,0 +1,27 @@ +{%- if current_version %} +
+ + Other Versions + v: {{ current_version.name }} + + +
+ {%- if versions.tags %} +
+
Tags
+ {%- for item in versions.tags %} +
{{ item.name }}
+ {%- endfor %} +
+ {%- endif %} + {%- if versions.branches %} +
+
Branches
+ {%- for item in versions.branches %} +
{{ item.name }}
+ {%- endfor %} +
+ {%- endif %} +
+
+{%- endif %} diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..18cf2a8 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,58 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) +import datetime + +# -- Project information ----------------------------------------------------- + +project = "dlt" +copyright = "%(year)s, %(author)s" % dict(year=datetime.date.today().year, author="BMW Car IT") +author = "BMW Car IT" + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ["sphinx.ext.autodoc", "sphinx.ext.autosectionlabel", "sphinx_click.ext", "sphinx_multiversion"] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "sphinx_rtd_theme" + +# 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"] + +# sphinx-multiversion configuration +# Format for versioned output directories inside the build directory +smv_outputdir_format = "{ref.name}" +# Include only master branch +smv_branch_whitelist = r"^master.*$" +# Determines whether remote or local git branches/tags are preferred if their output dirs conflict +smv_prefer_remote_refs = False diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..0ab8603 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,24 @@ + +Python DLT library +================================================ + +.. toctree:: + :maxdepth: 2 + + more_docu + api/modules + + +Purpose +_______ + +Python wrapper over libdlt2. + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..922152e --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/more_docu.rst b/docs/more_docu.rst new file mode 100644 index 0000000..f8c29d7 --- /dev/null +++ b/docs/more_docu.rst @@ -0,0 +1,10 @@ +More docu +========= + +Just a dummy file + +on +-- + +something +_________ \ No newline at end of file diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt new file mode 100644 index 0000000..1e8d8cb --- /dev/null +++ b/docs/requirements-docs.txt @@ -0,0 +1,6 @@ +sphinx==5.1.1 +sphinx-multiversion==0.2.4 +sphinx_rtd_theme==0.5.2 # NB: when upgrading, do not forget to check the templates in _templates! +sphinxcontrib-images==0.9.4 +sphinxcontrib-apidoc +sphinx-click diff --git a/pyproject.toml b/pyproject.toml index 955e6ef..e202e32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,9 +71,9 @@ exclude = ''' [tool.ruff] line-length = 119 -select = ["E", "F", "Q", "D"] +lint.select = ["E", "F", "Q", "D"] # the following is equivalent to --docstring-convention=pep8 -extend-ignore = [ +lint.extend-ignore = [ "D100", "D107", "D105", @@ -106,4 +106,7 @@ extend-ignore = [ # D104: Missing docstring in public package # This D104 error will be ignored only in __init__ files -per-file-ignores = {"__init__.py" = ["D104"]} +lint.per-file-ignores = {"__init__.py" = ["D104"]} + +[tool.bandit] +exclude_dirs = ["tests", ".tox"] diff --git a/tests/dlt_main_loop_unit_test.py b/tests/dlt_main_loop_unit_test.py new file mode 100644 index 0000000..857a721 --- /dev/null +++ b/tests/dlt_main_loop_unit_test.py @@ -0,0 +1,74 @@ +# Copyright (C) 2016. BMW Car IT GmbH. All rights reserved. +"""Basic unittests for the py_dlt_client_main_loop function""" +import ctypes +import functools +from io import BytesIO as StringIO +import socket +import unittest +from unittest.mock import patch, Mock + +from dlt.dlt import py_dlt_client_main_loop, DLTClient, logger +from dlt.core import cDltStorageHeader +from tests.utils import stream_one + + +def mock_dlt_receiver_receive_socket(client_receiver, partial=False, Fail=False): + if Fail: + return 0 + stream_one.seek(0) + buf = stream_one.read() + if partial: + buf = buf[:16] + + client_receiver._obj.buf = ctypes.create_string_buffer(buf) + client_receiver._obj.bytesRcvd = len(buf) + return len(buf) + + +class TestMainLoop(unittest.TestCase): + def setUp(self): + self.client = DLTClient() + self.client._connected_socket = Mock() + + def test_target_down(self): + with patch.object(self.client._connected_socket, "recv", side_effect=socket.timeout): + callback = Mock(return_value="should not be called") + + with self.assertLogs(logger=logger) as dlt_logger: + return_value = py_dlt_client_main_loop(self.client, callback=callback) + self.assertFalse(return_value) + + log_output = dlt_logger.output + self.assertEqual(len(log_output), 1) + self.assertEqual(log_output[0], "ERROR:dlt.dlt:[]: DLTLib closed connected socket") + + self.assertFalse(callback.called) + + def test_target_up_nothing_to_read(self): + with patch.object(self.client._connected_socket, "recv", return_value=b"") as mock_recv: + callback = Mock(return_value="should not be called") + self.assertFalse(py_dlt_client_main_loop(self.client, callback=callback)) + self.assertEqual(mock_recv.call_count, 1) + self.assertFalse(callback.called) + + @patch("dlt.dlt.dltlib.dlt_receiver_move_to_begin", return_value=0) + def test_exit_if_callback_returns_false(self, *ignored): + with patch.object(self.client._connected_socket, "recv", return_value=b"X"): + # setup dlt_receiver_receive to return a partial message + replacement = functools.partial(mock_dlt_receiver_receive_socket, partial=True) + with patch("dlt.dlt.dltlib.dlt_receiver_receive", new=replacement): + self.assertFalse(py_dlt_client_main_loop(self.client, callback=lambda msg: False)) + + def test_read_message(self, *ignored): + dumpfile = StringIO() + + stream_one.seek(0) + expected = stream_one.read() + + with patch.object(self.client._connected_socket, "recv", return_value=b"X"): + # setup dlt_receiver_receive to return a complete message + replacement = functools.partial(mock_dlt_receiver_receive_socket) + callback = Mock(side_effect=[True, False, False]) + with patch("dlt.dlt.dltlib.dlt_receiver_receive", new=replacement): + self.assertTrue(py_dlt_client_main_loop(self.client, dumpfile=dumpfile, callback=callback)) + self.assertEqual(dumpfile.getvalue()[ctypes.sizeof(cDltStorageHeader) :], expected) diff --git a/tox.ini b/tox.ini index d708a06..6a03854 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,8 @@ [tox] -envlist = py3,black,ruff +envlist = py3,flake8,black,lint,ruff,bandit,docs output_dir={env:SPHINX_OUTPUT_DIR:{toxworkdir}/_build} isolated_build = True +toxworkdir = {env:TOXWORKDIR:/tmp/tox} [testenv] deps = @@ -19,11 +20,20 @@ commands = filterwarnings = error + +[testenv:flake8] +basepython = python3 +skip_install = true +deps = + flake8 +commands = + flake8 --format=pylint --output-file=flake8.txt --max-line-length=119 + [testenv:ruff] basepython = python3 skip_install = true deps = - ruff + ruff==0.4.1 mypy commands = ruff check ./dlt ./tests @@ -34,15 +44,38 @@ skipsdist = True deps = black commands = - black -l 119 --check . + black -l 119 --check --diff . + +[testenv:lint] +basepython = python3 +skip_install = true +deps = + click + pylint==3.2.7 +commands = + pylint . --output-format=json:pylint.json,colorized + +[testenv:bandit] +basepython = python3 +skip_install = true +deps = + bandit + bandit[toml]==1.7.4 +commands = + bandit -c pyproject.toml -r . -f json -o bandit.json --exit-zero -[testenv:docs] -deps=-r{toxinidir}/docs/requirements-docs.txt -commands= - # Workaround for https://github.com/tox-dev/tox/issues/149 - pip install -q -r {toxinidir}/docs/requirements-docs.txt - sphinx-build -T -j auto --color -W -c docs docs {[tox]output_dir} {posargs} - python -c 'import pathlib; print("website available under file://\{0\}".format(pathlib.Path(r"{[tox]output_dir}") / "index.html"))' +[testenv:dev] +basepython = python3 +passenv = SOURCE_DATE_EPOCH +skip_install = True +skipsdist = True +deps = + build + twine + wheel +commands = + python -m build + twine upload -r software-factory-pypi-dev dist/* [testenv:release] basepython = python3