‘filesysobjects.pathtools’ - Module¶
The filesysobjects.pathtools module provides advanced operations on paths, sub-paths, and side branches.
Implementation Details¶
Common Call Parameters¶
The current version calls ‘os.path.normpath’ by default - when ‘raw’ is not selected. This is consistent for all path related parameters including search paths: start, top, plist, spath, etc.. Thus generally clears double slashes, but also replaces symbolic links, so later literal post processing e.g. for match based processing should be normalized too.
Current supported URIs for filenames are: ‘file://‘, ‘smb://‘, and ‘cifs://’. Additionally UNC names and Posix-Netapps are suppored by the prefixes ‘\\’ and ‘//’. The syntax formats are interchangeable in accordance to RFC8089 [RFC8089] including the Annex.
For application specific URIs refer to filesysobjects.apppaths The following options are generic and common to multiple interfaces:
matchidx=#idx¶
Matches on the provided index count only:
#idx==2 - ignores 0,1 and >2, matches idx==2
matchcnt=#num¶
The maximal number of matches returned when multiple occur:
#num==0 - all
#num>0 - number of matches returned
spath¶
An existing path to be added to an entry from ‘plist’. The following cases are supported, for further specifics refer to the interfaces.
Independent path entry - spath is absolute, just added.
Subpath of current directory spath is relative and present in current working directory, added py prefixing ‘pwd’.
Arbitrary side-branch of a provided path spath is relative, searched in plist for an insertion hook, added when found as absolute.
Pattern matching - see manual ‘Semi-Literals’ and shortcut tables in manual:
- regexpr:
Regular expressions are applicable for match on ‘plist’ only. Thus the part to be matched on the file system is required to be a literal.
- glob:
Glob expressions are applicable on the file system itself only, thus the part to be matched on the ‘plist’ is required to be a literal.
- Is absolute path:
Is checked to be a sub path of at least one of ‘plist’, than applied.
start¶
Start directory or file, when a file is provided the directory portion is used as the starting pointer.
Each part is compared separately, but as a whole string.
top¶
The topmost path within a directory tree as an end point for a search operation. This is defined by the end of a directory path name string. E.g. the the bottom-up search beginning at the start directory:
start=/a/b/c/d/e/f/g
is terminated by:
top=d
at:
/a/b/c/d
This is used as a match string for processing literally on the parts of the provided start directory. The match is checked after application of ‘os.path.normpath’. Providing absolute paths still match, because of the string, but eventually match multiple times when equal sub paths exist and the match order is changed to bottom-up search.
The containment of ‘top’ within the absolute ‘start’ path is verified.
Each part is compared separately, but as a whole string.
plist¶
List of strings to be searched. By default first match is used. Each is split into it’s components and matched separately.
default := sys.path
raw¶
Suppress normalization by call of ‘os.path.normpath’. The caller has than to take care for appropriate measures for a feasible match.
Glob Parametters¶
The ‘glob‘ wildcard definitions comprise a subset of regular expressions whith some deviation of their semantics.
1 | path0 = '/a/b/(x[!opq]*.py'
|
The resolution of contained path-elements as ‘glob’ expressions is proceeded dynamically by applying the glob module onto the file system nodes.
Regular Expressions¶
The regular expressions support the full scope of the standard Pyhton ‘re‘ module. The expressions are used as post scan match-filter onto a set of fetched resource path names.
1 | path0 = '/a/b/(x[^opq]*|XYZ[^abc]*).(py|pyc|pyo)'
|
The regexpr are by default compiled/loaded once statically during load time of the module. The regular expressions for the path analysis permit the ‘os.path.sep‘ of the current platform thus supports multi-level path patterns.
In order to avoid conflicts of the search patterns with reserved characters such as ‘/’, ‘\’, ‘;’, and ‘:’, the filesysobjects supports two types of quoting, which could be used to mask arbitrary parts of a path. The quotes parts are kept literally, including non-printable and unicode characters.
triple double-quotes
1 2 3 4
path0 = '/a/b/(x[^"""\\\\/;:"""]*|XYZ[^abc]*).(py|pyc|pyo)' path0 = '/a/b/(x"""[^\\\\/;:]"""*|XYZ[^abc]*).(py|pyc|pyo) path0 = '/a/b/("""x[^\\\\/;:]*|XYZ[^abc]*""").(py|pyc|pyo)' path0 = '/a/b/"""(x[^\\\\/;:]*|XYZ[^abc]*).(py|pyc|pyo)"""'
triple single-quotes
1
path0 = "/a/b/(x[^'''\\\\/;:''']*|XYZ[^abc]*).(py|pyc|pyo)"
The quotings could be removed by the common parameter stripquote, which removes pairs of triple quotes.
The interfaces within pathtools remove the quotes by default before applying the provided paths.
Glob Parametters and Regular Expressions¶
The ‘glob‘ wildcard definitions comprise a subset of regular expressions whith some deviation of their semantics.
In the case of a dot for example this could be in addition ambiguous.
1 2 3 4 5 | # file path name: /a/b/xname
path0 = '/a/b/x.*'
# regexpr: matches
# glob: does not match
|
or
1 2 3 4 5 | # file path name: /a/b/xname.c
path0 = '/a/b/x.*'
# regexpr: matches
# glob: does not match
|
or
1 2 3 4 5 | # file path name: /a/b/x.name.c
path0 = '/a/b/x.*'
# regexpr: matches
# glob: matches
|
or
1 2 3 4 5 | # file path name: /a/b/x.name.c
path0 = '/a/b/x*.*'
# regexpr: matches
# glob: does not match
|
Generally the regular expressions of Python provide a more flexible set of features.
Performance Optimization¶
The internal performance optimization is based on the step-wise scan of the resource tree. This is the case when regular expressions spanning multiple directory segments are applied. When active, the regular expressions are - when possible - splitted into segments and applied for each segment partially. Due to the provided advanced and complex syntax of re, the applied optimization constraints some elements see Search Performance Optimization. This is based mainly on the compiled regular expression
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | _glob_prefix = re.compile(r"""
(\[[\^][^\]]*\][*]*) # 1 - [^...] it is a re
|(\[[^/\]]*\][*]*) # 2 - [...] a char class without separator
|(\[[!][^/\]]*[/][^\]]*\][*]*) # 3 - [!.../...] a non-def char class with separator
|(\[[/]*\][*]*) # 4 - [/] a char class with posix-separator ONLY
|(\[[^/\[\]]*[/][^/\[]*\][*]*) # 5 - [.../...] a char class with posix-separator
|(\[[\\\\]*\][*]*) # 6 - [\\\\] a char class with nt-separator ONLY
|(\[[^\\\\]*[\\\\][^\\\\]*\][*]*) # 7 - [...\\\\...] a char class with nt-separator
|(?<![\\\\])([/]+) # 8 - '/' class-less n * posix-separator
|(?<![\\\\])([\\\\]+) # 9 - '\\' class-less n * nt-separator
|([.][*]) # 10 - '.*' any char wildcard
|([*]) # 11 - wildcard character
|([^/\[\]]+) # 12 - any character
|(\[) # 13 - basically a syntax error, but could be a literal too
|(\]) # 14 - basically a syntax error, but could be a literal too
""", re.X)
|
As shown, this implies some constraints on the application of the re syntax elements.
Whitelists and Blacklists¶
The match parameters provide for positive lists and for negative droplists. These lists are defined as lists of regular expressions, which are dynamically compiled and applied on the searched names.
- whitelist parameters select in case of a match.
- blacklist parameters drop in case of a match.
The whitelist parameters select in case of a match, thus these are applied on the names of files and directories for match. The input could be either a list of regular expressions, which are applied in the provided order, or a single regular expression covering multiple filters.
The whitelist parameters are either file name arguments, which contain globs or reqgular expressions, or parameters for specific interfaces.
The blacklist parameters use a syntax similar to the whitelist parameters, but drop in case of a match.
Module¶
The filesysobjects.pathstools module provides operations for address paths of file system based resources.
Note
Current version supports local accessible file systems only.
Functions¶
clearpath¶
-
filesysobjects.pathtools.
clearpath
(plist=None, **kargs)[source]¶ Clears, splits and joins a list of path variables by various criteria.
- Args:
- plist:
List of paths to be cleared. See common options for details.
default := sys.path
- kargs:
- abs:
Converts all entries into absolute pathnames. This implies the activation of the options shellvars and uservars.
default := False
- existent:
Removes all existing items. For test and verification.
default := False
- nonexistent:
Removes all items which do not exist.
default := False
- nonredundant:
Removes all items which are not redundant. Results e.g. in multiple incarnations of the same file/path type.
default := False
- normpath:
Calls ‘os.path.normpath’ on each result.
default := False
- redundant:
Clears all items from redundancies.
default := True
- rel:
Converts all entries into relative pathnames.
default := False
- reverse:
This reverses the resulting search order from bottom-up to top-down. Takes effect on ‘redundant’ only.
default := False
- shellvars:
Replaces shell variables within pathnames.
$VAR, ${VAR} %VAR%
default := False
- uservars:
Replaces special user variables as path-prefix. Currently support:
~ (tilde) $HOME, ${HOME} %HOME%
default := False
- shrink:
Drops resulting empty items.
default := True
- split:
Forces split of multiple paths items within one item into separate item entries.
default := True
- stripquote:
Removes paired triple-quotes of protected/masked string sections.
"/a/'''head:'''/c" => "/a/head:/c"
default := False
- withinItemOnly:
Performs any action for each item of ‘plist’ only.
default := False
- Returns:
- When successful returns ‘True’, else returns either ‘False’, or raises an exception.
- Raises:
- passed through exceptions:
expandpath¶
-
filesysobjects.pathtools.
expandpath
(*paths, **kargs)[source]¶ Splits, expands and normalizes a list of paths and search paths.
REMINDER: Non-existent path entries are dropped.
The input list ‘*paths‘ may contain mixed entries of:
- search paths - combined by os.pathsep
- wildcards-paths containing ‘literal‘, ‘glob‘, and ‘regexpr‘ parts
- inserted user directory
- inserted environment variables
- file and directory paths
The resulting normalized list contains in case of matches one path in each entry by the following algorithm.
Expand contained: 1. expand environment variables 2. expand user directory 3. check and use if exists, else continue If wildcards are selected continue with 4. split and resolve paths and remove quotes - *stripquote* 5. expand *literals* and *globs* 6. expand *literals* and *regexpr*
Args:
- paths:
A list of paths and search paths to be expanded. For supported pattern of following table refer to parameter wildcards.
type W_LITERAL W_GLOB W_RE W_FULL literal X X X X glob X X re X X default := W_RE # see parameter wildcards
kargs:
- dironly:
Contained file name paths are cut to their dirname.
expandvars := (True | False)
default := False
- expandvars:
Expand embedded environment variables.
expandvars := (True | False)
default := True
- expanduser:
Expand embedded user directories.
expandvars := (True | False)
default := True
- isDir:
Returns directories only.
default := all
- isFile:
Returns files only.
default := all
- nestclear:
Clear nested subdirectories
expandvars := (True | False)
when True, e.g.
/a/b:/a/b/c::/a/b/c => /a/b
default := False
- regexprspandir:
Controls whether regexpr may span multiple directories, thus handling os.path.sep as ordinary chars.
This in particular controls the technical implementation of the iterative path resolution for paths by intermixed wildcards.
True:
The treatment of path seperators within regexpr has to be assured by the caller.
False:
The regular experessions are resolved in chunks seperated by the path seperator. Thus each chunk is technically wrapped by the re-module:
'<regexpr>' + os.path.sep+'$'
- strip:
Reduces by dropping redundancies. The strip parameter influences the match of regular expressions, which just do a pattern match, thus hit null-separator directories too. The strip of these prevents from unwanted matches on separator characters.
strip := ( True # clear null-separators | False # no strip at all | all # clear any redundancy | contain # contained sub directories | multiple # multiple occurance )
default := True
- spf:
Source platform, defines the input syntax domain. For the syntax refer to API in the manual at spf.
For additi0onal details refer to tpf and spf, paths.getspf(), normapppathx(), normpathx().
- wildcards:
Controls the type of path evaluation. Supported paths values types are:
wildcards := ( W_LITERAL # literal existence check | W_GLOB # globs, contains W_LITERAL | W_RE # re, contains W_GLOB | W_FULL # re )
Expects mixed path names with literals, globs, and regexpr.
default := W_RE
- Returns:
- In case of success a list with directory entries with splitted search paths. An empty list when no results.
- Raises:
PathToolsError
pass-through
findpattern¶
-
filesysobjects.pathtools.
findpattern
(*srcdirs, **kargs)[source]¶ Executes on each srcdirs a tree search with match and drop patterns. The interface is basically similar to ‘find’ with enhanced match options.
The search operation relies for Python3.5+ on os.scandir() - for Python2.7 on scandir.scandir(). The interface extends the lower layer API by lists of filters with support for ‘literal’, ‘glob’ and/or ‘regexpr’ pattern.
The search algorithm is performed as:
If srcdirs is provided use each as starting file path, else initialize based on current working directory.
Set behavior attributes, see options:
- listorder
- followlinks
- matchbehavior
- matchcnt
.
If no filter parameters are present return afterwards.
Else apply filter parameters. Each non-matching condition continues with next filter cycle by default. When no match the result is accepted, see options:
- check level
- check blacklist
- check whitelist
- check dropdirs
- check type
.
Apply string manipulation, see options
- check-cut topcutlist
.
The general behavior for the parameters is additive, this means e.g. when provided wildcards, globs, regexpr, and filter these are applied subsequently. Each match is added by default to the result list. The drop parameters instantly remove the match from the result list.
Args:
- srcdirs:
List of top level paths for search. Supports literal, re, and glob.
default := [<current-workdir>,]
- kargs:
Additional control:
- abs:
Defines the type of returned path value, when present.
abs := ( True # Force absolute paths. | False # Force relative paths. )
default := “depends on type of input”
- blacklist:
File system nodes to be dropped from the result. Supports Python re expressions, See Variants of Pathname Parameters - Literals, RegExpr, and Glob
default := None
- whitelist:
File system nodes to be added to the result. Supports Python re expressions, See Variants of Pathname Parameters - Literals, RegExpr, and Glob
default := *
- followlinks:
Follow symbolic links.
default := False
- gid:
- Group ID.
- level:
Depth of search. The values are:
None: Search the subtree unlimited. 0: Current directory only, basically the same as *os.listdir()*. >0: Sub-directories of given level.
default := None
- matchcnt:
Defines the selection of matches:
- n<0: the last n, last := -1.
- n=0: all
- n>0: the first n, first := 1.
default := 0
- nopostfix:
- Deletes for files the postfix.
- output:
Output format. Current available formats are:
output := ( OF_LIST_STR, # list of file system path names OF_LIST_OID, # list of dotted object notation OF_RAW # list of raw entries *DirEntry*, see scandir )
- topcutlist:
Cut listed topmost path elements from found list elements, resulting in relative pathnames.
default := [‘.’ + os.sep]
- topdown:
Defines the order or the resulting list, same as os.walk.
topdown := (True | False)
default := True
- types:
Search and list selected types only. The value is a bit-array.
T_ALL, T_DEV, T_FILE, T_DIR, T_HARDL, T_EXP, T_LOCAL, T_MNT, T_NODES, T_SYML
default := T_ALL
- uid:
- User ID.
- Returns:
- Results in an list of found entries. When none, an empty list.
Raises:
ffs.
findrelpath_in_searchpath¶
-
filesysobjects.pathtools.
findrelpath_in_searchpath
(spath, plist=None, **kargs)[source]¶ Search for subdirectory trees spath of the paths contained in plist.
MATCH : plist[x]/spath
supports glob.
- Args:
- spath:
A path to be hooked into ‘plist[]’ when present. Could be either a literal, or a glob as an relative or absolute path. Valid spath wildcard types:
literal X re – glob X See common options for details.
spath := (literal|glob):
- plist:
List of potential hooks for ‘spath’. The following formats are provided:
- list of single paths - used literally
- list of search path strings - each search path is split
- string with search path - split into it’s components
- string with a single path - used literally
The default behavior is:
- first: (1.)
- second: (3.), this contains (4.)
The case (2.) has to be forced by the key-option: ‘subsplit’, or to be prepared by the call ‘clearpath(split=True,)’.
Due to performance the case #1 should be preferred in order to save repetitive automatic conversion.
See common options for further details.
default := sys.path
- kargs:
- isDir:
- Is a directory.
- isFile:
- Is a file.
- isLink:
- Is a symbolic link.
- isPathByLink:
- Has a symbolic link in path.
- matchidx:
Ignore matches ‘< #idx’, return match ‘== #idx’. Depends on ‘reverse’
matchidx := #idx:
default := 0 # first match
- noglob:
- Suppress application of ‘glob’.
- not:
- Inverts to does not matched defined criteria.
- raw:
- Suppress normalization by call of ‘os.path.normpath’.
- reverse:
- Reversed search order.
- subsplit:
- Splits each item part of a ‘plist’ option.
- Returns:
- When successful returns the absolute pathname, else ‘None’. For a list refer to iterator.
- Raises:
- PathToolsError passed through exceptions
findrelpath_in_searchpath_iter¶
findrelpath_in_uppertree¶
Convenience function, uses ‘findrelpath_in_searchpath‘ and ‘set_uppertree_searchpath‘.
findrelpath_in_uppertree_iter¶
Convenience function, uses ‘findrelpath_in_searchpath‘ and ‘set_uppertree_searchpath‘.
get_subpath_product¶
-
filesysobjects.pathtools.
get_subpath_product
(dirs, subpaths)[source]¶ Creates the textual cartesian product of directories and relative sub-paths. Addditional checks sould be applied by clearpath() and expandpath().
The calls for the specific platforms notations:
cprod_posix = get_subpath_product(('/path/0', '/path/1'), ('suba', 'subb')) cprod_win32 = get_subpath_product(('c:\path ', 'd:\path'), ('suba', 'subb'))
results in:
cprod_posix == [ '/path/0/suba', '/path/0/subb', '/path/1/suba' '/path/1/subb' ] cprod_win32 == [ 'c:\path \suba', 'c:\path \subb', 'd:\path\suba' 'd:\path\subb' ]
- Args:
- dirs:
- Base directories for the provided subdirectories.
- subpaths:
- Sub-paths, each to be located within each of the directories dirs.
- Returns:
- The list of path names resulting from the literal textual cartesian product.
- Raises:
- pass-through
glob_to_re¶
-
filesysobjects.pathtools.
glob_to_re
(expr, **kargs)[source]¶ Compiles a glob to the corresponding re. The following mapping is implemented:
glob re * .* [!x] [^x] . [.] ? . - Args:
- expr:
- A glob expression. The function relies on the caller and ‘blindly’ assumes to process a glob.
- kargs:
- spf:
- The platform defining the syntax domain of expr.
- Returns:
- The converted expression.
- Raises:
- pass-through
Description:
The compilation of glob expressions into re expressions is basically straight forward. I is required in particular when partial glob expressions have to be used in combination with re expressions for match filters on file path names. The result is as long unambiguous, as long the input expression is actually a glob expression. The choosen compilation is not neccessarily syntactic idempotent. The compilation results may look suprisingly, because the input is trusted as a pure glob expression. So for example the expression
1 | /a/.*/b
|
is compiled to
1 | /a/[.].*/b
|
This is perfectly allright.
The term ‘.*‘ has the semantics in the glob domain:
A dot folowed by any number of any characters, which is terminated by the next os.sep.
While in the re domain the term ‘.*‘ has a slightly different semantics :
Any character followed by an arbitrary number of any characters, which is terminated by the next os.sep.
So the glob compiled as:
1 2 3 4 5 | /a/[.].*/b
# 0. /a/. => /a/[.]
# 1. /a/[.]*/b => /a/[.].*/b
|
This will match on any name within ‘/a/‘ starting with a ‘.’.
Thus for the design of the reagular expressions the specifics have to be considered.
The possible additional semantic of e.g. null-dir is not considered for the compilation, but is processed by the normalization interfaces accordingly.
1 | '*/./././*' => '*/[.]/[.]/[.]/*'
|
The semantics with the representation of one/character names is:
1 | '*/?/?/?/*' => '*/./././*'
|
For this reasons the basic compilation is not idempotent, which means that multiple calls finally change the semantics. The following repetitive application
1 2 3 4 5 | 0. 'a/*/b' => 'a/.*/b'
1. 'a/.*/b' => 'a/[.].*/b'
2. 'a/[.].*/b' => 'a/[.][.].*/b'
and so on...
|
leads to an unexpected result.
The windows domain requires special attention when prohibited special characters are used in a multiple platform application. The back-slash separator requires in general special consideration.
The following escaped characters on POSIX platforms are handled different on Windows platforms due to the standard file systems restrictions.
1 | /\:*?"<>|
|
Resulting in the non-ambiguous compilation of:
1 2 3 | 0. 'a\\b\\*' => a wildcard, no escape for '*'
1. 'a\\b\\?' => a single character, no escape for '?'
2. 'a\\\\b\\\\?' => still the path 'a\\b\\?', no escape for '\\'
|
The regular expressions may contain in addition control sequences and special terms of the re package. These are not yet supported.
See also pathtools.split_re_glob
split_re_glob¶
-
filesysobjects.pathtools.
split_re_glob
(expr, **kargs)[source]¶ Splits a mixed path expression into the glob + literal prefix and the regular expression re postfix. The cut for the expression is done by grouping the expressions at the edge of paths by matched free characters of path separators. The detection of the first re is done by detecting an unambiguously non-glob expression. These are considered as re expressions:
[^...] a exclusive character class (...) a group \[ or \] escaped square brackets
Due to the various permitted character ranges, where e.g. POSIX allows almost any character these maz still be valid characters. In this case they have to be either escaped, or to be applied within character classes.
The type resolution could in addition controlled by the option typeprio, which redfines some compilation priorities.
See manual for further details.
- Args:
- expr:
- expression to be split
- kargs:
- spf:
Source platform, defines the separator for path items.
default := None
- typeprio:
The priority type in case of ambiguity.
typeprio := ( W_GLOB # interprets as *glob* | W_RE # interprets as *re* )
default := W_RE
- Returns:
- A list of two elements, ‘L[0]- glob’ and ‘L[1]- re’
- Raises:
- pass-through
Description:
The interpretation of the paramater typeprio resolves the ambiguity for ambiguous syntax terms. The ambiguous terms are syntactical present in glob and re, while in could be even a literal. The interpretation results in the assignment to the return part with ‘ret[0]‘ as a literal or glob for direct resolution. The second part ‘ret[1]‘ as the regular expression re for the filtered resolution on of a search result.
1 2 3 4 5 6 | ret = [
[], # 0: resolved by glob(ret[0])
[] # 1: resolved by the post-filtered result of glob(ret[0]/*) by ret[1]
]
ret = split_re_glob(expr, typeprio=W_FULL)
|
The prefered assignment of terms containing the free ambiguous characters is performed in accordance to the folowing table.
type | .* | /* | [!..] | [^...] | ? | description |
---|---|---|---|---|---|---|
W_GLOB | 0 | 0 | 0 | 1 | 0 | split into prefered glob and re |
W_RE | 1 | 0 | 0 | 1 | 0 | split into prefered re and glob |
The assignment to the seconf re group for seacrh and filter operations could be forced by insertion of an unambiguous re expression, e.g. by
1 | arg = "/a/b/[^^]?/c" => [['a', 'b'],['[^^]?', 'c']]
|
The free characters are defined, when these are not masked. The characters could be masked by
- enclosing in a character class
- escaping by ‘\’
- triple quoting ‘’’ or “”“
For example by
1 2 3 | arg = "/a/b/[\!abc]/[.]*/\[abc\]/[\^abc]/[?]/"
arg = "/a/b/['''!'''abc]/'''.'''*/'''[abc]'''/['''^'''abc]/'''?'''/"
arg = '/a/b/["""!"""abc]/"""."""*/"""[abc]"""/["""^"""abc]/"""?"""/'
|
In case of ambiguity these could be resolved by forcing specific re syntax via zero-dummy entries. For exampe:
1 2 | /a/b/[^^]{0}c/ => matches: /a/b/c/
=> with ret = [['a', 'b'], ['[^^]{0}c']]
|
splitre_separator¶
-
filesysobjects.pathtools.
splitre_separator
(expr)[source]¶ Splits a literal and/or wildcard expressions into it’s directory items. This provides for intermediate file sets evaluated by directory-wise glob and re.
- Args:
- expr:
- expression to be split
- Returns:
- A list of partial wildcard expressions
- Raises:
- pass-through
stripquotes¶
-
filesysobjects.pathtools.
stripquotes
(path, scope=3)[source]¶ Strips quotes.
- Args:
- path:
- Path to strip off of quotes.
- scope:
Scope to be applied.
scope := ( Q_ALL_TRIPLE # " * 3 and ' * 3 | Q_DOUBLE_TRIPLE # " * 3 | Q_SINGLE_TRIPLE # ' * 3 )
- Returns:
- Path without selected triple-quotes.
- Raises:
- pass-through