Package: cbdevtools
ThePythonmodulecbdevtoolsI beg your pardon for my english...English is not my native language, so be nice if you notice misunderstandings, misspellings, or grammatical errors in my documents and codes.Last version: 0.0.11-betaThis version0.0.11-betawas made on2022-08-11.AboutcbdevtoolsThis project is a"Common Box of Dev Tools"(the name comes also from "Christophe BAL Dev Tools").cbdevtoolsproposes small scripts that can be helpful... at least for the author of this package. :-)Append one package tosys.pathThe functionaddfindsrc.addfindsrcadds one project folder to the system path.Let's see one fictive example with the following tree structure.+ mymod
    + doc
    + dist
    + src
        * __init__.py
        * ...
    + tools
        + debug
            * cli.pyThePythonscripttools/debug/cli.pycan easily load the localPythonmodulesrcthanks to the moduleaddfindsrcas it is shwon in the following code.fromcbdevtools.addfindsrcimportaddfindsrcaddfindsrc(file=__file__,project='mymod',)fromsrcimport*If you need to have the path of the project added, just use the value returned byaddfindsrc.addfindsrc.WARNING!The directory of the project to add must contain the file__file__.Selective version of the standarddir(obj)Building automatically somePythonscripts needs sometimes to play withdir(obj)of some classes, methods and functions. The functionshortdir.shortdircan be helpful in this kind of situation.Lets' consider the following code where the use of regexes allows enough flexibility to ignore some names.frompprintimportpprintfromcbdevtools.shortdirimport(shortdir,re_compile,# Just an alias for ``re.compile``.PATTERN_UNDERSCORE# Pattern matching ``-...``.)print("shortdir(1) =")pprint(shortdir(1))print()fortoignorein[[],['imag','real'],['as_.+','from_.+']]:toignore=[re_compile(s)forsintoignore]# For none empty list, we want also to ignore# the dunder methods.iftoignore:toignore.append(PATTERN_UNDERSCORE)print(f"{toignore= }")print("shortdir(1, toignore) =")pprint(shortdir(1,toignore))print()Launched in a terminal, this code produces the following output (the printings have been formatted, and truncated a little by hand to ease the reading).shortdir(1)=# Dunder methods ignored by default.['as_integer_ratio','bit_length','conjugate','denominator','from_bytes','imag','numerator','real','to_bytes']toignore=[]# To keep all the dunder methods.shortdir(1,toignore)=['__abs__','__add__','__and__',...,#  Some other dunder methods.'as_integer_ratio','bit_length','conjugate','denominator','from_bytes','imag','numerator','real','to_bytes']toignore=[re.compile('imag'),re.compile('real'),re.compile('_.*')]shortdir(1,toignore)=['as_integer_ratio','bit_length','conjugate','denominator','from_bytes','numerator','to_bytes']toignore=[re.compile('as_.+'),re.compile('from_.+'),re.compile('_.*')]shortdir(1,toignore)=['bit_length','conjugate','denominator','imag','numerator','real','to_bytes']Signature of a callable objectTo produce good quality code, it is very important to know the signature of a function, or a method. The purpose of the fucntion.easysignis to give an eays-to-use dictionary giving all the informations about a signature.Let's start with the code above where we usepprintto obtain well formatted output.frompprintimportpprintfromcbdevtools.easysignimporteasysigndeffuncOK(a:int,b:int=1)->str:...pprint(easysign(funcOK))Launched in a terminal, we obtain the output below showing that the dictionary returned is very easy to use.{'optional': ['b'],
 'params': {'a': {'default': None, 'typing': 'int'},
            'b': {'default': '1', 'typing': 'int'}},
 'return': 'str'}WARNING!When nothing has been indicated in the original code, the valueNoneis used.The signature of a method is also easy to obtain as it is done in the following code.classTest:defnothing(self):...defnoparam(self)->str:...defpartialsign(self,a:str,b):...defparamOK(self,a,b:bool=True)->str:...mytest=Test()fornamein["nothing","noparam","partialsign","paramOK",]:print(f"easysign(mytest.{name})")pprint(easysign(mytest.__getattribute__(name)))print()Here is the corresponding output.easysign(mytest.nothing)
{'optional': [], 'params': {}, 'return': None}

easysign(mytest.noparam)
{'optional': [], 'params': {}, 'return': 'str'}

easysign(mytest.partialsign)
{'optional': [],
 'params': {'a': {'default': None, 'typing': 'str'},
            'b': {'default': None, 'typing': None}},
 'return': None}

easysign(mytest.paramOK)
{'optional': ['b'],
 'params': {'a': {'default': None, 'typing': None},
            'b': {'default': 'True', 'typing': 'bool'}},
 'return': 'str'}To end this section, you have to know that usingeasysign(1)will raise the following error.[...]
TypeError: 1 is not a callable objectUsingorpystedatas withpytestThe author of this package usesorpysteto work with ready-to-makePEUFdata files in his tests.To avoid problem withpytest, a fixturepeuf_fixtureis proposed wich follows the convention that the name of thePEUFfile is obtained by removing the prefixtest_from the name of the testing file Here is a real example of use with the following partial tree structure.+ TeXitEasy
    + src
        * __init__.py
        * escape.py
    + tests
        + escape
            + fstringit.peuf
            + test_fstringit.pyThePythontesting filetest_fstringit.pyis associated to thePEUFfilefstringit.peufwhere the prefixtest_has been removed. Using the datas stored in thisPEUFfile becomes very easy: here is the code used wheretestsis an intuitive dictionary version of thePEUFfile.fromcbdevtoolsimport*addfindsrc(file=__file__,project='TeXitEasy',)fromsrc.escapeimportfstringitdeftest_latex_use_fstringit(peuf_fixture):tests=peuf_fixture(__file__)forinfosintests.values():found=fstringit(infos['source'])wanted=infos['fstring']assertwanted==found