Skip to content

octoprint.util.files#

find_collision_free_name(filename, extension, existing_filenames, max_power = 2) #

Tries to find a collision free translation of "." to the 8.3 DOS compatible format, preventing collisions with any of the existing_filenames.

First strips all of ."/\[]:;=, from the filename and extensions, converts them to lower case and truncates the extension to a maximum length of 3 characters.

If the filename is already equal or less than 8 characters in length after that procedure and "." are not contained in the existing_files, that concatenation will be returned as the result.

If not, the following algorithm will be applied to try to find a collision free name::

set counter := power := 1
while counter < 10^max_power:
    set truncated := substr(filename, 0, 6 - power + 1) + "~" + counter
    set result := "<truncated>.<extension>"
    if result is collision free:
        return result
    counter++
    if counter >= 10 ** power:
        power++
raise ValueError

This will basically -- for a given original filename of some_filename and an extension of gco -- iterate through names of the format some_f~1.gco, some_f~2.gco, ..., some_~10.gco, some_~11.gco, ..., <prefix>~<n>.gco for n less than 10 ^ max_power, returning as soon as one is found that is not colliding.

Parameters:

  • filename (string) –

    The filename without the extension to convert to 8.3.

  • extension (string) –

    The extension to convert to 8.3 -- will be truncated to 3 characters if it's longer than that.

  • existing_filenames (list) –

    A list of existing filenames to prevent name collisions with.

  • max_power (int) –

    Limits the possible attempts of generating a collision free name to 10 ^ max_power variations. Defaults to 2, so the name generation will maximally reach <name>~99.<ext> before aborting and raising an exception.

Returns:

  • string

    A 8.3 representation of the provided original filename, ensured to not collide with the provided existing_filenames

Raises:

  • ValueError

    No collision free name could be found.

Examples:

>>> find_collision_free_name("test1234", "gco", [])
'test1234.gco'
>>> find_collision_free_name("test1234", "gcode", [])
'test1234.gco'
>>> find_collision_free_name("test12345", "gco", [])
'test12~1.gco'
>>> find_collision_free_name("test 123", "gco", [])
'test_123.gco'
>>> find_collision_free_name("test1234", "g o", [])
'test1234.g_o'
>>> find_collision_free_name("test12345", "gco", ["/test12~1.gco"])
'test12~2.gco'
>>> many_files = ["/test12~{}.gco".format(x) for x in range(10)[1:]]
>>> find_collision_free_name("test12345", "gco", many_files)
'test1~10.gco'
>>> many_more_files = many_files + ["/test1~{}.gco".format(x) for x in range(10, 99)]
>>> find_collision_free_name("test12345", "gco", many_more_files)
'test1~99.gco'
>>> many_more_files_plus_one = many_more_files + ["/test1~99.gco"]
>>> find_collision_free_name("test12345", "gco", many_more_files_plus_one)
Traceback (most recent call last):
...
ValueError: Can't create a collision free filename
>>> find_collision_free_name("test12345", "gco", many_more_files_plus_one, max_power=3)
'test~100.gco'

get_dos_filename(input, existing_filenames = None, extension = None, whitelisted_extensions = None, **kwargs) #

Converts the provided input filename to a 8.3 DOS compatible filename. If existing_filenames is provided, the conversion result will be guaranteed not to collide with any of the filenames provided thus.

Uses :func:find_collision_free_name internally.

Parameters:

  • input (string) –

    The original filename incl. extension to convert to the 8.3 format.

  • existing_filenames (list) –

    A list of existing filenames with which the generated 8.3 name must not collide. Optional.

  • extension (string) –

    The .3 file extension to use for the generated filename. If not provided, the extension of the provided filename will simply be truncated to 3 characters.

  • whitelisted_extensions (list) –

    A list of extensions on input that will be left as-is instead of exchanging for extension.

  • kwargs (dict) –

    Additional keyword arguments to provide to :func:find_collision_free_name.

Returns:

  • string

    A 8.3 compatible translation of the original filename, not colliding with the optionally provided existing_filenames and with the provided extension or the original extension shortened to a maximum of 3 characters.

Raises:

  • ValueError

    No 8.3 compatible name could be found that doesn't collide with the provided existing_filenames.

Examples:

>>> get_dos_filename("test1234.gco")
'test1234.gco'
>>> get_dos_filename("test1234.gcode")
'test1234.gco'
>>> get_dos_filename("test12345.gco")
'test12~1.gco'
>>> get_dos_filename("Wölfe 🐺.gcode")
'wolfe_~1.gco'
>>> get_dos_filename("💚.gcode")
'green_~1.gco'
>>> get_dos_filename("test1234.fnord", extension="gco")
'test1234.gco'
>>> get_dos_filename("auto0.g", extension="gco")
'auto0.gco'
>>> get_dos_filename("auto0.g", extension="gco", whitelisted_extensions=["g"])
'auto0.g'
>>> get_dos_filename(None)
>>> get_dos_filename("foo")
'foo'

m20_timestamp_to_unix_timestamp(timestamp) #

Converts "M20 T" timestamp to unix timestamp. Upper 16 bit contain date, lower 16 bit contain time.

https://reprap.org/wiki/G-code#M20:_List_SD_card

Format derived from FAT filesystem timestamps: https://wiki.osdev.org/FAT

Parameters:

  • timestamp (string) –

    M20 T timestamp as hex string

Returns:

  • int

    Unix timestamp in seconds

sanitize_filename(name, really_universal = False) #

Sanitizes the provided filename. Implementation differs between Python versions.

Under normal operation, pathvalidate.sanitize_filename will be used, leaving the name as intact as possible while still being a legal file name under all operating systems.

Behaviour can be changed by setting really_universal to True. In this case, the name will be ASCII-fied, using octoprint.util.text.sanitize with safe chars -_.()[] and all spaces replaced by _. This is the old behaviour.

In all cases, a single leading . will be removed (as it denotes hidden files on *nix).

Parameters:

  • name

    The file name to sanitize. Only the name, no path elements.

  • really_universal

    If True, the old method of sanitization will always be used. Defaults to False.

Returns:

  • the sanitized file name

silent_remove(file) #

Silently removes a file. Does not raise an error if the file doesn't exist.

Parameters:

  • file (string) –

    The path of the file to be removed

unix_timestamp_to_m20_timestamp(unix_timestamp) #

Converts unix timestamp to "M20 T" format which embeds date and time into 32bit int. Upper 16 bit contain date, lower 16 bit contain time.

https://reprap.org/wiki/G-code#M20:_List_SD_card

Format derived from FAT filesystem timestamps: https://wiki.osdev.org/FAT

Parameters:

  • unix_timestamp (int) –

    Unix timestamp in seconds

Returns:

  • string

    M20 T timestamp as hex string