Miscellaneous missing tools that can help the py-developper.
Project description
About this package
misTool is the contraction of missing, miscellaneous and tool(s). This package contains some modules that could be useful for Python developments.
If you want more informations and examples than thereafter, just take a look at the docstrings.
I 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.
What's new in this version 1.2.2-beta
?
¨html and ¨latex basic frames have been added to be used with term_use.withframe
.
What's new in this version 1.2.1-beta
?
The function between
in string_use
has a new optional argument keepseps
so as to keep or not the separators.
What's new in this version 1.2.0-beta
?
The module date_use
has been changed to datetime_use
: see the presentation above to know how to work now with dates inside misTool.
What's new in this version 1.1.1-beta
?
In the module python_use
, the new class MKOrderedDict
allows to define kinds of ordered dictionaries accepting several times the same key but at different "places".
Warning ! Here are some important changes.
-
In the module
python_use
, the classOrderedRecuDict
becomesRecuOrderedDict
. -
In the module
string_use
, the functionascii_it
becomesasciify
.
The module os_use
Changing the working directory for commands
With os_use.cd
, you have a context which changes temporarily the directory where launching terminal like commands. When the context is closed, the working directory goes back to the one just before the call of os_use.cd
.
Let's see an example. We suppose that we have the following directory with the absolute path /Users/projetmbc/basic_dir
in a Unix system.
+ basic_dir
* latex_1.tex
* latex_2.tex
* python_1.py
* python_2.py
* python_3.py
* python_4.py
* text_1.txt
* text_2.txt
* text_3.txt
+ empty_dir
+ sub_dir
* code_A.py
* code_B.py
* slide_A.pdf
* slide_B.pdf
+ sub_sub_dir
* doc.pdf
The following code first goes inside /Users/projetmbc/basic_dir
and then it moves to /Users/projetmbc/basic_dir/sub_dir
. With subprocess.call("ls")
, we simply use the Unix command ls
so as to list files and folders inside the current working directory.
>>> import subprocess
>>> from mistool.os_use import cd
>>> with cd("/Users/projetmbc/basic_dir"):
... subprocess.call("ls")
empty_dir python_1.py python_4.py text_2.txt
latex_1.tex python_2.py sub_dir text_3.txt
latex_2.tex python_3.py text_1.txt
>>> with cd("/Users/projetmbc/basic_dir/sub_dir"):
... subprocess.call("ls")
code_A.py slide_A.pdf sub_sub_dir
code_B.py slide_B.pdf
Launching commands like in a terminal
The aim of the function os_use.runthis
is to simplify a lot the launching of subprocesses (just use commands as you were inside your terminal). Let's consider the basic following Python script with absolute path /Users/projetmbc/script.py
.
print("Everything is ok.")
To launch this program, we just have to use the single string Unix command python3 /Users/projetmbc/script.py
like in the following lines. You can see that by default nothing is printed, so you have to use showoutput = True
if
you want to see what the script launched prints.
>>> from mistool.os_use import PPath, runthis
>>> pyfile = PPath("/Users/projetmbc/script.py")
>>> runthis(cmd = "python3 {0}".format(ppath))
>>> runthis(cmd = "python3 {0}".format(ppath), showoutput = True)
Everything is ok.
System used and environment's path
The call to os_use.system()
returns the name, in lower case, of the OS used : possible strings returned can be for example "windows"
, "mac"
, "linux"
and also "java"
.
os_use.pathenv()
gives you the paths of executables known by your OS (this is indeed an alias for os.getenv('PATH')
).
Enhanced version of the class pathlib.Path
The class os_use.PPath
adds several methods to the useful class pathlib.Path
. Here are examples.
Informations about one path
The following code shows additional informations given by the class os_use.PPath
.
>>> from mistool.os_use import PPath
>>> path = PPath("dir/subdir/file.txt")
>>> path.parent
PPath('dir/subdir')
>>> print(path.depth)
2
>>> print(path.ext)
'txt'
Another useful method named is_protected
works as explained below.
-
If the path does not point to an existing file or folder, an OS error is raised.
-
If the path is the one of a folder, the answer returned is
True
for a modifiable directory andFalse
otherwise. -
Finally if the path points to a file, then that is its parent folder which is tested.
There is also the method is_empty
which can give three different responses.
-
If the path is the one of an empty directory,
False
is returned. -
True
is returned when the path corresponds to an non-empty folder. -
If the path doesn't point to an existing directory an OS error is raised.
Changing one path
Changing or adding an extension is very easy with the method with_ext
.
>>> from mistool.os_use import PPath
>>> path_no_ext = PPath("dir/subdir")
>>> path_no_ext.with_ext("ext")
PPath('dir/subdir.ext')
>>> path_ext = PPath("dir/subdir/file.txt")
>>> path_ext.with_ext("ext")
PPath('dir/subdir/file.ext')
Obtaining a short version or a normalized one of a path needs no effort. Here is how to do that (~
is a shortcut for the main OS user's folder).
>>> from mistool.os_use import PPath
>>> path_too_long = PPath("~/dir_1/dir_2/dir_3/../../file.txt")
>>> path_too_long.normpath
PPath('/Users/projetmbc/dir_1/file.txt')
>>> path_long = PPath("/Users/projetmbc/dir_1/dir_2/dir_3/../../file.txt")
>>> path_long.shortpath
PPath('~/dir_1/file.txt')
Comparing paths
The "common" folder of several paths is obtained by using the method common_with
or equivalently the magic operator &
.
>>> from mistool.os_use import PPath
>>> path = PPath("/Users/projetmbc/source/doc")
>>> path_1 = PPath("/Users/projetmbc/README")
>>> path_2 = PPath("/Users/projetmbc/source/misTool/os_use.py")
>>> path_danger = PPath("/NoUser/projects")
>>> path.common_with(path_1) # Same as ``path & path_1``
PPath('/Users/projetmbc')
>>> path.common_with(path_2) # Same as ``path & path_2``
PPath('/Users/projetmbc/source')
>>> path.common_with(path_danger) # No error raised !
PPath('/')
>>> path.common_with(path_1, path_2) # Same as ``path & path_1 & path_2``
PPath('/Users/projetmbc')
>>> path.common_with([path_1, path_2]) # Same as ``path & [path_1, path_2]``
PPath('/Users/projetmbc')
The class os_use.PPath
adds a magic method so as to use path - anotherpath
instead of path.relative_to(anotherpath)
where the method relative_to
is implemented by the class pathlib.Path
.
>>> from mistool.os_use import PPath
>>> main = PPath("/Users/projetmbc")
>>> path_1 = PPath("/Users/projetmbc/README")
>>> path_2 = PPath("/Users/projetmbc/source/misTool/os_use.py")
>>> path_1 - main
PPath('README')
>>> path_2 - main
PPath('source/misTool/os_use.py')
>>> path_2 - path_1
Traceback (most recent call last):
[...]
ValueError: '/Users/projetmbc/source/misTool/os_use.py' does not start with '/Users/projetmbc/README'
If you need to know the depth of one path relatively to another, just call the method depth_in
.
>>> from mistool.os_use import PPath
>>> main = PPath("/Users/projetmbc")
>>> path_1 = PPath("/Users/projetmbc/README")
>>> path_2 = PPath("/Users/projetmbc/source/misTool/os_use.py")
>>> path_pb = PPath("/NoUser/projects")
>>> print(path_1.depth_in(main))
0
>>> print(path_2.depth_in(main))
2
>>> print(path_pb.depth_in(main))
Traceback (most recent call last):
[...]
ValueError: '/NoUser/projects' does not start with '/Users/projetmbc'
The special concept of "regpath"
A "regpath" is a query mixing all the power of regexes and the Unix-glob special characters (there are also some additional query features). We will use some "regpaths" in the incoming examples.
See the docstring of the method regpath2meta
for complete informations about the "regpaths".
Walk and see
The method see
tries to open the current path with a possible associated application. For example, an HTML file will be opened by your default browser.
You can walk very easily inside a directory thanks to the method walk
and the "regpaths" (see the previous section). For example, let's suppose that we have the following directory with absolute path
/Users/projetmbc/basic_dir
in a Unix system.
+ basic_dir
* latex_1.tex
* latex_2.tex
* python_1.py
* python_2.py
* python_3.py
* python_4.py
* text_1.txt
* text_2.txt
* text_3.txt
+ empty_dir
+ sub_dir
* code_A.py
* code_B.py
* slide_A.pdf
* slide_B.pdf
+ sub_sub_dir
* doc.pdf
Here are easy to understand examples where the regpath "*"
is for a
non-recursive search contrary to the regpath "**"
.
>>> from mistool.os_use import PPath
>>> folder = PPath("/Users/projetmbc/basic_dir")
>>> for p in folder.walk("dir::**"):
... print("+", p)
...
+ /Users/projetmbc/basic_dir/empty_dir
+ /Users/projetmbc/basic_dir/sub_dir
+ /Users/projetmbc/basic_dir/sub_dir/sub_sub_dir
>>> for p in folder.walk("file::**.py"):
... print("+", p)
...
+ /Users/projetmbc/basic_dir/python_1.py
+ /Users/projetmbc/basic_dir/python_2.py
+ /Users/projetmbc/basic_dir/python_3.py
+ /Users/projetmbc/basic_dir/python_4.py
+ /Users/projetmbc/basic_dir/sub_dir/code_A.py
+ /Users/projetmbc/basic_dir/sub_dir/code_B.py
>>> for p in folder.walk("file::*.py"):
... print("+", p)
...
+ /Users/projetmbc/basic_dir/python_1.py
+ /Users/projetmbc/basic_dir/python_2.py
+ /Users/projetmbc/basic_dir/python_3.py
+ /Users/projetmbc/basic_dir/python_4.py
Create
Creating files and folders is straight forward with the method create
even if this needs to add several parent directories that don't yet exist. In the following example, we suppose that the current directory has absolute path /Users/projetmbc
, and doesn't contain any subfolder.
>>> from mistool.os_use import PPath
>>> path_1 = PPath("test/README")
>>> path_1.is_file()
False
>>> path_1.create("file")
>>> path_1.is_file()
True
>>> path_2 = PPath("test/README")
>>> path_2.create("dir")
Traceback (most recent call last):
[...]
ValueError: path points to an existing file.
Remove
If you want to destroy a whole directory, or simply a file, given by its PPath
, just use the method remove
.
Warning ! Because removing a file or a directory can be a dangerous thing, you can use the method can_be_removed
which by default will raise an OS error if the PPath
is one of an existing file or folder.
The method clean
allows to remove specific files and/or directories matching a regpath given as an argument.
Move & copy
By default, the method copy_to
allows you to copy a file or a directory into another location, whereas the method move_to
will move a file or a directory to another place.
The module string_use
Multi-replacements
The class string_use.MultiReplace
makes possible to do multi-replacements recursively or not (by default mode = "norecu"
).
>>> from mistool.string_use import MultiReplace
>>> from mistool.config.pattern import PATTERNS_WORDS
>>> oldnew = {
... 'W1': "Word #1",
... 'W2': "Word #2",
... 'W3': "W1 and W2"
... }
>>> mreplace = MultiReplace(
... oldnew = oldnew,
... mode = "recu",
... pattern = PATTERNS_WORDS['var']
... )
>>> print(mreplace("W1 and W2 = W3"))
Word #1 and Word #2 = Word #1 and Word #2
>>> mreplace.mode = "norecu"
>>> mreplace.build()
>>> print(mreplace("W1 and W2 = W3"))
Word #1 and Word #2 = W1 and W2
The code above show that cyclic definitions will raise a ValueError
exception.
>>> from mistool.string_use import MultiReplace
>>> from mistool.config.pattern import PATTERNS_WORDS
>>> oldnew = {
... 'WRONG_1': "one small text and WRONG_2",
... 'WRONG_2': "one small text, and then WRONG_3",
... 'WRONG_3': "with WRONG_1, there is one problem here"
... }
>>> mreplace = MultiReplace(
... oldnew = oldnew,
... mode = "recu",
... pattern = PATTERNS_WORDS["var"]
... )
Traceback (most recent call last):
[...]
ValueError: the following viscious circle has been found.
+ WRONG_2 --> WRONG_3 --> WRONG_1 --> WRONG_2
Multi-splits
The aim of the class string_use.MultiSplit
is to split a text on several semantic depths. Here is an example of use.
>>> from mistool.string_use import MultiSplit
>>> msplit = MultiSplit(seps = "|")
>>> print(msplit("p_1 ; p_2 ; p_3 | r_1 ; r_2 | s"))
[
'p_1 ; p_2 ; p_3 ',
' r_1 ; r_2 ',
' s'
]
>>> msplit.seps = ["|", ";"]
>>> msplit.strip = True
>>> print(msplit("p_1 ; p_2 ; p_3 | r_1 ; r_2 | s"))
[
['p_1', 'p_2', 'p_3'],
['r_1', 'r_2'],
['s']
]
Before, between and after
The function string_use.between
looks for two separators such as to return the text before, between and after the first matching of this separators. By default, separators are not kept but you can ask to the function to keep them. None
is returned if no matching has been found. Just take a look at a concrete example.
>>> from mistool.string_use import between
>>> text = "f(x ; y) = x**2 + y**2"
>>> seps = ["(", ")"]
>>> print(between(text, seps))
[
'f', # Before
'x ; y', # Between
' = x**2 + y**2' # After
]
>>> print(between(text, seps, True))
[
'f(', # Before
'x ; y', # Between
') = x**2 + y**2' # After
]
>>> seps = ["{", "}"]
>>> print(between(text, seps))
None
Join with a last special text
You can join several strings with a special final separator as the examples above show.
>>> from mistool.string_use import joinand
>>> texts = ["1", "2", "3"]
>>> print(joinand(texts))
1, 2 and 3
>>> print(joinand(texts = texts, andtext = "et"))
1, 2 et 3
>>> print(joinand(texts = texts, sep = " + ", andtext = "="))
1 + 2 = 3
Playing with cases of letters
The function string_use.case
gives more auto-formatting of strings (the last formatting looks strange but it is useful for an incoming project of the author of mistool
).
>>> from mistool.string_use import case
>>> text = "onE eXamPLe"
>>> for kind in ['lower', 'upper', 'sentence', 'title']:
... print("{0} [{1}]".format(case(text, kind), kind))
...
one example [lower]
ONE EXAMPLE [upper]
One example [sentence]
One Example [title]
A camel case string can be "uncamelized" by the function string_use.camelto
. Here is how to use it (you can change the separator by using the optional argument sep
which is "_"
by default).
>>> from mistool.string_use import camelto
>>> text = "OneSmallExampLE"
>>> for kind in ['lower', 'upper', 'sentence', 'title']:
... print("{0} [{1}]".format(camelto(text, kind), kind))
...
one_small_examp_l_e [lower]
ONE_SMALL_EXAMP_L_E [upper]
One_small_examp_l_e [sentence]
One_Small_Examp_L_E [title]
If you need to check the case of a string, just use string_use.iscase(text, kind)
.
Playing with ASCII
You can check if a string is a pure ASCII one.
>>> from mistool.string_use import isascii
>>> print(isascii("Vive la France !"))
True
>>> print(isascii("¡Viva España!"))
False
You can also transform a string to a pure ASCII one (this will not always work but in case of failure you can contribute very easily to enhance string_use.asciify
).
>>> from mistool.string_use import asciify
>>> print(asciify("¡Viva España!"))
Viva Espana!
>>> oldnew = {'!': ""}
>>> print(asciify(text = "¡Viva España!", oldnew = oldnew))
Viva Espana
The last example above shows how to be permissive : this means that string_use.asciify
will "asciify" the most characters as possible.
>>> from mistool.string_use import asciify
>>> print(asciify(text = "L'Odyssée de ∏", strict = False))
L'Odyssee de ∏
>>> print(asciify("L'Odyssée de ∏"))
Traceback (most recent call last):
[...]
ValueError: ASCII conversion can't be made because of the character << ∏ >>.
You can use the function ``_ascii_report`` so as to report more precisely
this fealure with eventually an ascii alternative.
Auto completion
The class string_use.AutoComplete
gives the auto-completion feature accessible without using any GUI package.
>>> from mistool.string_use import AutoComplete
>>> myac = AutoComplete(
... words = [
... "article", "artist", "art",
... "when", "who", "whendy",
... "bar", "barbie", "barber", "bar"
... ]
... )
>>> print(myac.matching("art"))
['article', 'artist']
>>> print(myac.matching(""))
[
'art', 'article', 'artist',
'bar', 'barber', 'barbie',
'when', 'whendy', 'who'
]
>>> print(myac.missing("art", 'article'))
icle
It is a convention in GUI applications to give auto-completion only for at least three characters. You can do that by using the optional argument minsize
which is 1
by default.
The module term_use
Auto-numbering steps
For terminal informations, it can be useful to number some important printed steps. This can be done easily with the class term_use.Step
.
>>> from mistool.term_use import Step
>>> mysteps = Step()
>>> i = 0
>>> while i <= 12:
... if i % 2:
... mysteps("Action #{0}".format(i))
... i += 1
...
1) Action #1
2) Action #3
3) Action #5
4) Action #7
5) Action #9
6) Action #11
The class term_use.Step
has two optional arguments.
-
start
gives the first number which is1
by default. -
textit
is a function of two variables(n, t)
returning the text containing the step numbern
and the textt
. By default,textit = lambda n, t: "{0}) {1}".format(n, t)
.
Frame
The function term_use.withframe
puts a text inside an ASCII frame (you can choose the alignment and use other kinds of frames if necessary as it is explained in the docstrings).
>>> from mistool.term_use import withframe
>>> text = '''
... One small
... text
... to do tests
... '''.strip()
>>> print(withframe(text))
###############
# One small #
# text #
# to do tests #
###############
ASCII tree views of one directory
For our examples, we consider a folder with the following structure and the absolute path /Users/projetmbc/dir
.
+ dir
* code_1.py
* code_2.py
* file_1.txt
* file_2.txt
+ doc
* code_A.py
* code_B.py
* slide_A.pdf
* slide_B.pdf
+ licence
* doc.pdf
+ emptydir
The preceding ASCII tree view was built easily using the following code (PPath
is the class defined in os_use
added in term_use
for you comfort).
>>> from mistool.term_use import DirView, PPath
>>> dir = PPath("/Users/projetmbc/dir")
>>> dirview = DirView(
... ppath = dir,
... sorting = "filefirst"
... )
>>> print(dirview.ascii)
+ dir
* code_1.py
* code_2.py
* file_1.txt
* file_2.txt
+ doc
* code_A.py
* code_B.py
* slide_A.pdf
* slide_B.pdf
+ licence
* doc.pdf
+ emptydir
Using the "regpath" concept of the module os_use
, we can filter folders and files shown as in the example above (we also use the argument display
so as to customize the output).
>>> from mistool.term_use import DirView, PPath
>>> dir = PPath("/Users/projetmbc/dir")
>>> dirview = DirView(
... ppath = dir,
... regpath = "file::**.py",
... display = "main short found"
... )
>>> print(dirview.ascii)
+ dir
* code_1.py
* code_2.py
+ doc
* code_A.py
* code_B.py
You can also use the following property methods.
-
dirview.tree
is a graphical tree. -
dirview.toc
gives a minimal tabulated tree. -
dirview.latex
is for the LaTeX packagedirtree
.
The module python_use
A multikeys dictionary
The class MKOrderedDict
allows to work easily with multikeys ordered dictionaries. Here is a complete example of use.
>>> from mistool.python_use import MKOrderedDict
>>> onemkdict = MKOrderedDict()
>>> onemkdict[(1, 2, 4)] = "1st value"
>>> onemkdict["key"] = "2nd value"
>>> onemkdict["key"] = "3rd value"
>>> print(onemkdict)
MKOrderedDict([
((id=0, key=(1, 2, 4)), value='1st value'),
((id=0, key='key') , value='2nd value'),
((id=1, key='key') , value='3rd value')
])
>>> for k_id, val in onemkdict["key"]:
... print(k_id, val)
...
0 2nd value
1 3rd value
>>> print(onemkdict.getitembyid(1, "key"))
3rd value
>>> for (k_id, key), val in onemkdict.items():
... print((k_id, key), "===>", val)
...
(0, (1, 2, 4)) ===> 1st value
(0, 'key') ===> 2nd value
(1, 'key') ===> 3rd value
>>> for key, val in onemkdict.items(noid=True):
... print(key, "===>", val)
...
(1, 2, 4) ===> 1st value
key ===> 2nd value
key ===> 3rd value
>>> "key" in onemkdict
True
>>> "kaaaay" in onemkdict
False
>>> onemkdict.setitembyid(0, "key", "New 2nd value")
>>> print(onemkdict)
MKOrderedDict([
((id=0, key=(1, 2, 4)), value='1st value'),
((id=0, key='key') , value='New 2nd value'),
((id=1, key='key') , value='3rd value')])
A dictionary defined recursively
The class RecuOrderedDict
allows to use a list of hashable keys, or just a single hashable key. Here is a complete example of use.
>>> from mistool.python_use import RecuOrderedDict
>>> onerecudict = RecuOrderedDict()
>>> onerecudict[[1, 2, 4]] = "1st value"
>>> onerecudict[(1, 2, 4)] = "2nd value"
>>> onerecudict["key"] = "3rd value"
>>> print(onerecudict)
RecuOrderedDict([
(
1,
RecuOrderedDict([
(
2,
RecuOrderedDict([ (4, '1st value') ])
)
])
),
(
(1, 2, 4),
'2nd value'
),
(
'key',
'3rd value'
)
])
>>> [1, 2, 4] in onerecudict
True
>>> [2, 4] in onerecudict[1]
True
List of single values of a dictionary
If you need to list all the value of one dictionary, the function python_use.dictvalues
is made for you.
>>> from mistool.python_use import dictvalues
>>> onedict = {"a": 1, "b": 2, "c": 1}
>>> print(dictvalues(onedict))
[1, 2]
>>> print(list(onedict.values()))
[2, 1, 1]
Easy quoted text with the least escaped quote symbols
With python_use.quote
you can add without pain quotes around a text.
>>> from mistool.python_use import quote
>>> print(quote('First example.'))
'First example.'
>>> print(quote("Same example."))
'Same example.'
>>> print(quote('One "small" example.'))
'One "small" example.'
>>> print(quote("Another kind of \"example\"."))
'Another kind of "example".'
>>> print(quote("An example a 'little' more \"problematic\"."))
'An example a \'little\' more "problematic".'
The module datetime_use
Special class ddatetime
The class ddatetime
is an enhanced version of the class datetime.datetime
: see the two sections below. It is very easy to build an instance of ddatetime
thanks to the very cool function build_ddatetime
. The examples above show different ways to define a date.
>>> from mistool.datetime_use import build_ddatetime
>>> build_ddatetime((2017, 8, 1))
ddatetime(2017, 8, 1, 0, 0)
>>> build_ddatetime(2017, 8, 1)
ddatetime(2017, 8, 1, 0, 0)
>>> build_ddatetime("2017-08-01")
ddatetime(2017, 8, 1, 0, 0)
>>> build_ddatetime("Friday 01 august 2017")
ddatetime(2017, 8, 1, 0, 0)
>>> build_ddatetime("Vendredi 1er août 2017", lang = "fr_FR")
ddatetime(2017, 8, 1, 0, 0)
>>> build_ddatetime("Vendredi 1er août 2017")
[...]
ValueError: Unknown string format
>>> build_ddatetime("Vendredi 1er août 2017", "fr_FR")
[...]
TypeError: an integer is required (got type str)
Note that you must define a special language using lang = "fr_FR"
as you can see in the two last commands in the preceding example.
Next day having a fixed english name
In some applications you want to know the next monday after a fixing date.
>>> from mistool.datetime_use import ddatetime
>>> onedate = ddatetime(2017,8, 1)
>>> print(onedate.strftime("%Y-%m-%d is a %A."))
2017-08-01 is a Tuesday.
>>> nextfriday = onedate.nextday(name = "friday")
>>> print("Next Friday:", nextfriday.strftime("%Y-%m-%d"))
Next Friday: 2017-08-04
Translating a date
Thanks to the class ddatetime
, it is easy to safely translate all the names in a date.
>>> from mistool.datetime_use import ddatetime
>>> onedate = ddatetime(2015, 6, 2)
>>> oneformat = "%A %d %B %Y"
>>> print(onedate.translate(strformat = oneformat))
Tuesday 02 June 2015
>>> print(onedate.translate(strformat = oneformat, lang = "fr_FR"))
Mardi 02 juin 2015
Parsing a string to build a date
The function parsedate
is an international version of the function dateutil.parser.parse
(translations need external contributions : the job is very easy to do !).
>>> from mistool.datetime_use import parsedate
>>> parsedate("Friday 01 august 2017")
ddatetime(2017, 8, 1, 0, 0)
>>> parsedate(timestr = "Vendredi 1er Août 2017", lang = "fr_FR")
ddatetime(2017, 8, 1, 0, 0)
>>> parsedate(timestr = "Montag, 11. April 2016", lang = "de_DE")
[...]
ValueError: unsupported language ''de_DE''
The module url_use
Looking for dead or bad urls
For the following example, we suppose that we have a working internet connection.
>>> from mistool.url_use import islinked
>>> islinked("http://www.google.com")
True
>>> islinked("http://www.g-o-o-g-l-e.com")
False
Escaping special characters in urls
It is safe to not use non-ASCII characters in a url. Here is one way to do that.
>>> from mistool.url_use import escape
>>> print(escape("http://www.vivaespaña.com/camión/"))
http://www.vivaespa%C3%B1a.com/cami%C3%B3n/
The module latex_use
Escaping the special LaTeX characters
The function latex_use.escape
will escape all special characters for you regarding the text or math mode.
>>> from mistool.latex_use import escape
>>> onetext = "\OH/ & ..."
>>> print(escape(onetext))
\textbackslash{}OH/ \& ...
>>> print(escape(text = onetext, mode = "math"))
\backslash{}OH/ \& ...
Easy LaTeX compilation(s)
The class latex_use.Build
compiles a LaTeX file for you (for the moment only the PDF compilation is implemented). Let's consider the
following LaTeX file with the absolute path /Users/projetmbc/latex/file.tex
.
\documentclass[11pt, oneside]{article}
\begin{document}
\section{One little test}
One basic formula : $E = mc^2$.
\end{document}
In the following code, we call to the class term_use.DirView
so as to show the new files made by LaTeX (the ellipsis [...]
indicates some lines not reproduced here).
>>> from mistool.latex_use import Build, PPath
>>> from mistool.term_use import DirView
>>> latexdir = PPath("/Users/projetmbc/latex/file.tex")
>>> print(DirView(latexdir.parent).ascii)
+ latex
* file.tex
>>> builder = Build(latexdir)
>>> builder.pdf()
# -- Start of compilation Nb.1 -- #
This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2014) (preloaded
format=pdflatex)
restricted \write18 enabled.
entering extended mode
[...]
Output written on file.pdf (1 page, 36666 bytes).
Transcript written on file.log.
# -- End of compilation Nb.1 -- #
>>> print(DirView(latexdir.parent).ascii)
+ latex
* file.aux
* file.log
* file.pdf
* file.tex
The PDF file has been build by LaTeX but there are also temporary ones. If you need several compilations, so as to build a table of content for example, just use the attribut-argument repeat
, and if you don't want to see the LaTeX ouput, just set the attribut-argument showinfos
to False
.
Removing the temporary files produced by LaTeX
We keep the same LaTeX example file. The function latex_use.clean
cleans all unuseful temporary files when the compilation has been done.
>>> from mistool.latex_use import clean, PPath
>>> from mistool.term_use import DirView
>>> latexdir = PPath("/Users/projetmbc/latex")
>>> print(DirView(latexdir.parent).ascii)
+ latex
* file.aux
* file.log
* file.pdf
* file.synctex.gz
* file.tex
>>> clean(ppath = latexdir, showinfos = True)
* Cleaning for "/Users/projetmbc/latex/file.tex"
>>> print(DirView(latexdir.parent).ascii)
+ latex
* file.pdf
* file.tex
Automatic installation of personal LaTeX packages
Let's suppose that we have package named lyxam
stored in a folder having the absolute path /Users/projetmbc/latex/lyxam
and whose structure is the following one.
+ lyxam
+ change_log
+ 2012
* 02.txt
* 03.txt
* 04.txt
* 10.txt
* todo.txt
* lyxam.sty
+ config
* settings.tex
+ lang
* en.tex
* fr.tex
+ special
* fr.config
+ standard
* en.config
* fr.config
+ style
* apmep.tex
* default.tex
To install this package locally in your LaTeX distribution, just do like in the code above.
>>> from mistool.latex_use import install, PPath
>>> package = PPath("/Users/projetmbc/latex/lyxam")
>>> install(package)
Starting installation of the package locally.
* Deletion of the old << lyxam >> package in the local LaTeX directory.
* Creation of a new << lyxam >> package in the local LaTeX directory.
+ Adding the new file << lyxam.sty >>
+ Adding the new file << change_log/todo.txt >>
+ Adding the new file << change_log/2012/02.txt >>
+ Adding the new file << change_log/2012/03.txt >>
+ Adding the new file << change_log/2012/04.txt >>
+ Adding the new file << change_log/2012/10.txt >>
+ Adding the new file << config/settings.tex >>
+ Adding the new file << config/lang/en.tex >>
+ Adding the new file << config/lang/fr.tex >>
+ Adding the new file << config/lang/special/fr.config >>
+ Adding the new file << config/lang/standard/en.config >>
+ Adding the new file << config/lang/standard/fr.config >>
+ Adding the new file << config/style/apmep.tex >>
+ Adding the new file << config/style/default.tex >>
* Refreshing the list of LaTeX packages.
Using the concept of "regpath" of the module os_use
, you can for example choose to not install all the TXT
files.
>>> from mistool.latex_use import install, PPath
>>> package = PPath("/Users/projetmbc/latex/lyxam")
>>> install(ppath = package, regpath = "file not::**.txt")
Starting installation of the package locally.
* Deletion of the old << lyxam >> package in the local LaTeX directory.
* Creation of a new << lyxam >> package in the local LaTeX directory.
+ Adding the new file << lyxam.sty >>
+ Adding the new file << config/settings.tex >>
+ Adding the new file << config/lang/en.tex >>
+ Adding the new file << config/lang/fr.tex >>
+ Adding the new file << config/lang/special/fr.config >>
+ Adding the new file << config/lang/standard/en.config >>
+ Adding the new file << config/lang/standard/fr.config >>
+ Adding the new file << config/style/apmep.tex >>
+ Adding the new file << config/style/default.tex >>
* Refreshing the list of LaTeX packages.
Remove a personal LaTeX packages
Just use remove(name)
where name
is the name of a local LaTeX package.