{"id":13936620,"url":"https://github.com/Edinburgh-Genome-Foundry/Flametree","last_synced_at":"2025-07-19T22:31:13.923Z","repository":{"id":57430037,"uuid":"80863792","full_name":"Edinburgh-Genome-Foundry/Flametree","owner":"Edinburgh-Genome-Foundry","description":":fire: Python file and zip operations made easy","archived":false,"fork":false,"pushed_at":"2022-05-04T13:33:09.000Z","size":123,"stargazers_count":150,"open_issues_count":5,"forks_count":12,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-11-23T08:14:57.502Z","etag":null,"topics":["archive","file","filesystem","python","zip"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Edinburgh-Genome-Foundry.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-03T19:50:06.000Z","updated_at":"2024-08-03T16:34:32.000Z","dependencies_parsed_at":"2022-09-02T15:31:31.660Z","dependency_job_id":null,"html_url":"https://github.com/Edinburgh-Genome-Foundry/Flametree","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Edinburgh-Genome-Foundry%2FFlametree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Edinburgh-Genome-Foundry%2FFlametree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Edinburgh-Genome-Foundry%2FFlametree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Edinburgh-Genome-Foundry%2FFlametree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Edinburgh-Genome-Foundry","download_url":"https://codeload.github.com/Edinburgh-Genome-Foundry/Flametree/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226686729,"owners_count":17666928,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["archive","file","filesystem","python","zip"],"created_at":"2024-08-07T23:02:51.646Z","updated_at":"2025-07-19T22:31:13.902Z","avatar_url":"https://github.com/Edinburgh-Genome-Foundry.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":".. raw:: html\n\n    \u003cp align=\"center\"\u003e\n    \u003cimg alt=\"Flametree Logo\" title=\"Flametree Logo\" src=\"https://raw.githubusercontent.com/Edinburgh-Genome-Foundry/Flametree/master/images/logo.png\" width=\"500\"\u003e\n    \u003c/p\u003e\n    \u003ch2 align=\"center\"\u003e Python file operations made easy \u003c/h2\u003e\n\n\n\n.. image:: https://github.com/Edinburgh-Genome-Foundry/Flametree/actions/workflows/build.yml/badge.svg\n   :target: https://github.com/Edinburgh-Genome-Foundry/Flametree/actions/workflows/build.yml\n   :alt: GitHub CI build status\n\n.. image:: https://coveralls.io/repos/github/Edinburgh-Genome-Foundry/Flametree/badge.svg\n   :target: https://coveralls.io/github/Edinburgh-Genome-Foundry/Flametree\n\n\nFlametree is a Python library which provides a simple syntax for handling files and folders\n(no ``os.path.join``, ``os.listdir`` etc.), and works the same way for different file systems.\n\nWrite a Flametree program to read/write files in disk folders, and your code will also be\nable to read/write in zip archives and virtual (in-memory) archives - which is particularly\nuseful on web servers.\n\nAs an illustration, here is how to use Flametree to read a file ``texts/poems/the_raven.txt``, replace all\noccurences of the word \"raven\" by \"seagull\" in the text, and write the result to a new\nfile ``the_seagull.txt`` in the same folder:\n\n.. code:: python\n\n     from flametree import file_tree\n\n     with file_tree(\"texts\") as root:\n         poem_text = root.poems.the_raven_txt.read()\n         new_text = poem_text.replace(\"raven\", \"seagull\")\n         root.poems._file(\"the_seagull.txt\").write(new_text)\n\nEven in this very simple use case, the syntax is clearer than the ``os`` way,\nwhich would write as follows:\n\n.. code:: python\n\n    import os\n\n    with open(os.path.join(\"poems\", \"the_raven.txt\"), \"r\") as f:\n        poem_text = f.read()\n    new_text = poem_text.replace(\"raven\", \"seagull\")\n    with open(os.path.join(\"poems\", \"the_seagull.txt\"), \"w\") as f:\n        content = f.write(new_text)\n\nMoreover, the same Flametree code also works for files inside a zip archive:\n\n.. code:: python\n\n     with file_tree(\"my_archive.zip\") as root:\n         poem_text = root.poems.the_raven_txt.read()\n         new_text = poem_text.replace(\"raven\", \"seagull\")\n         root.poems._file(\"the_seagull.txt\").write(new_text)\n\nNow in hard mode: suppose that your server receives binary zip data of an\narchive containing ``poems/the_raven.txt``, and must return back a new zip\ncontaining a file ``poems/the_seagull.txt``. Here again, the syntax of the core\noperations is the same:\n\n.. code:: python\n\n     destination_zip = file_tree(\"@memory\") # Create a new virtual zip\n     with file_tree(the_raven_zip_data) as root:\n         poem_text = root.poems.the_raven_txt.read()\n         new_text = poem_text.replace(\"raven\", \"seagull\")\n         destination_zip._dir(\"poems\")._file(\"the_seagull.txt\").write(new_text)\n     destination_zip_data = destination_zip._close()\n     # Now send the data to the client\n\nSee section *Usage* below for more examples and features.\n\nInstallation\n------------\n\nFlametree should work on Windows/Max/Linux, with Python 2 and 3, and has no external dependency.\n\nIt can be installed by unzipping the source code in one directory and using this command: ::\n\n    python setup.py install\n\nYou can also install it directly from the Python Package Index with this command: ::\n\n    pip install flametree\n\n\nContribute\n----------\n\nFlametree is an open-source software originally written by Zulko_ and released on Github_\nunder the MIT licence (Copyright 2017 Edinburgh Genome Foundry, University of Edinburgh).\nEveryone is welcome to contribute!\nIn particular if you have ideas of new kinds of file systems to add to Flametree.\n\n\nUsage\n-----\n\nOpening a file tree\n~~~~~~~~~~~~~~~~~~~\n\nHere is how you open different kinds of file systems:\n\n.. code:: python\n\n     from flametree import file_tree\n\n     # Open a directory from the disk's file system:\n     root = file_tree(\"my_folder/\")\n\n     # Open a zip archive on the disk:\n     root = file_tree(\"my_archive.zip\")\n\n     # Connect to a file-like object (file handle, StringIO...) of a zip:\n     root = file_tree(file_like_object)\n\n     # Create a virtual 'in-memory' zip file:\n     root = file_tree(\"@memory\")\n\n     # Open some data string representing a zip to read\n     root = file_tree(some_big_zip_data_string)\n\n\n\nIn the two first examples, if ``my_folder`` or ``my_archive.zip`` do not exist, they\nwill be automatically created. If they do exist, it is possible to completely overwrite\nthem with the option ``replace=True``.\n\nExploring a file tree:\n~~~~~~~~~~~~~~~~~~~~~~\n\nOnce you have created the ``root`` element with one of the methods above, you can display the whole\nfile tree with ``root._tree_view()`` :\n\n.. code::\n\n    \u003e\u003e\u003e print (root._tree_view())\n    texts/\n      poems/\n        dover_beach.txt\n        the_raven.txt\n        the_tyger.txt\n      todo_list.txt\n    figures/\n      figure1.png\n      figure2.png\n    Readme.md\n\n\nThe attributes of a directory like ``root`` are its files and subdirectories.\nFor instance to print the content of ``dover_beach.txt`` you would write:\n\n.. code:: python\n\n  print( root.texts.poems.dover_beach_txt.read() )\n\nor even simpler:\n\n.. code:: python\n\n    root.texts.poems.dover_beach_txt.print_content()\n\nNotice that the ``.`` before ``txt`` was replaced by ``_`` so as to form a valid\n attribute name.\n\nThis syntactic sugar is particularly useful to explore a file tree in\nIPython Notebooks or other editors offering auto-completion:\n\n\n.. image:: https://raw.githubusercontent.com/Edinburgh-Genome-Foundry/Flametree/master/images/autocomplete.png\n   :alt: [illustration]\n   :align: center\n\nAlternatively, you can access files and directories using dictionary calls:\n\n.. code:: python\n\n    root[\"texts\"][\"poems\"][\"dover_beach.txt\"]\n\nTo iterate through the subdirectories of a directory, use the ``_dirs`` attribute:\n\n.. code:: python\n\n    for subdirectory in root._dirs:\n        print (subdirectory._name) # Will print 'texts' and 'figures'\n\nTo iterate through the files of a directory, use the ``_files`` attribute:\n\n.. code:: python\n\n    for f in root.figures._files:\n        print (f._name) # Will print 'figure1.png' and 'figure2.png'\n\nFinally, use ``_all_files`` to iterate through all files nested in a directory.\nThe snippet below prints the content of all ``.txt`` files in the file tree:\n\n.. code:: python\n\n    for f in root._all_files:\n        if f._name.endswith(\".txt\"):\n            f.print_content()\n\nCreating files and folders\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo create a new subdirectory use ``_dir``:\n\n.. code:: python\n\n    root._dir(\"data\") # create a 'data' folder at the root\n    root.data._dir(\"reports\") # create a 'reports' folder under `root/data`\n\nTo create a new file use ``_file``:\n\n.. code:: python\n\n    root._file(\"joke.txt\") # create a 'joke.txt' file at the root.\n    root.texts._file(\"hello.txt\") # create 'hello.txt' in `root/texts`.\n\nTo write content in a file, use ``.write``:\n\n.. code:: python\n\n    root.joke_txt.write(\"A plateau is the highest form of flattery.\")\n\nWriting to a file will use mode ``a`` (append) by default. To overwrite\nthe file set the write mode to ``\"w\"``. Let's erase and rewrite that ``joke.txt``:\n\n.. code:: python\n\n    root.joke_txt.write(\"'DNA' stands for National Dyslexic Association.\", \"w\")\n\nFile and directory creation commands can be chained.\nLet us create some new folders ``data/`` and ``data/test_1/``, and\nwrite to file ``data/test_1/values.csv``, all in a single line:\n\n.. code:: python\n\n    root._dir(\"data\")._dir(\"test_1\")._file(\"values.csv\").write(\"1,15,25\")\n\nBeware that ``._dir`` and ``._file`` **overwrite their target by default**, which means that if you write:\n\n.. code:: python\n\n    root._dir(\"data\")._file(\"values_1.csv\").write(\"1,4,7\")\n    root._dir(\"data\")._file(\"values_2.csv\").write(\"2,9,7\")\n\nThe directory ``data`` will only contain ``values_2.csv``, because the second\nline's ``_dir(\"data\")`` erases the ``data`` directory and starts a new one. To avoid this,\neither use ``root.data`` in the second line:\n\n.. code:: python\n\n    root._dir(\"data\")._file(\"values_1.csv\").write(\"1,4,7\")\n    root.data._file(\"values_2.csv\").write(\"2,9,7\")\n\nOr use ``replace=False`` in ``_dir``:\n\n.. code:: python\n\n    root._dir(\"data\")._file(\"values_1.csv\").write(\"1,4,7\")\n    root._dir(\"data\", replace=False)._file(\"values_2.csv\").write(\"2,9,7\")\n\n\nOther operations\n~~~~~~~~~~~~~~~~\n\nYou can move, copy, and delete a file with ``.move(folder)``, ``.copy(folder)``,\n``.delete()``, and a directory with ``._move(folder)``, ``._copy(folder)``,\n``._delete()``.\n\n.. code:: python\n\n    root.data.values1_csv.delete() # delete file 'values1.csv'\n    root.data._delete() # delete directory 'data'\n    # Move folder `plots` from `root/figures` to `other_root/figures`\n    root.figures.plots._move(other_root.figures)\n    # Move file `fig.png` from `root/figures` to `other_root/figures`\n    root.figures.fig_png.move(other_root.figures)\n\nSpecial rules for ZIP archives\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIt is not currently possible to modify/delete a file that is already zipped\ninto an archive (because zips are not really made for that, it would\nbe doable but would certainly be a hack).\n\nWhen creating files and folders in a zip with Flametree, the changes in the actual zip\nwill only be performed by closing the ``root`` with ``root._close()``\n(after which the ``root`` can't be used any more). If it is an in-memory zip, ``root._close()``\nreturns the value of the zip content as a string (Python 2) or bytes (Python 3).\n\nHere are a few examples:\n\n.. code:: python\n\n    root = file_tree(\"archive.zip\")\n    root._file(\"hello.txt\").write(\"Hi there !\")\n    root._close()\n\n    # Equivalent to the previous, using `with`:\n    with file_tree(\"archive.zip\") as root:\n        root._file(\"hello.txt\").write(\"Hi there !\")\n\n    # Getting binary data of an in-memory zip file:\n    root = file_tree(\"@memory\")\n    root._file(\"hello.txt\").write(\"Hi there !\")\n    binary_data = root._close()\n\n\nUsing file writers from other libraries\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSome libraries have file-generating methods which expect a file name or a file\nobject to write too.\nYou can also feed Flametree files to these functions. for instance here is\nhow to use Weasyprint to create a PDF ``pdfs/report.pdf``\n\n.. code:: python\n\n    import weasyprint\n    from flametree import file_tree\n    root = file_tree(\".\") # or 'archive.zip' to write in an archive.\n    html = weasyprint.HTML(string=\"\u003cb\u003eHello\u003c/b\u003e world!\", base_url='.')\n    html.write_pdf(root._dir(\"pdfs\")._file(\"test.pdf\"))\n\nAnd here is how you would save a Matplotlib figure in a zip archive:\n\n.. code:: python\n\n    import matplotlib.pyplot as plt\n    from flametree import file_tree\n    fig, ax = plt.subplots(1)\n    ax.plot([1, 2, 3], [3, 1, 2])\n    with file_tree(\"archive.zip\") as root:\n        fig.savefig(root._dir(\"plots\")._file(\"figure.png\"), format=\"png\")\n\nThat's all folks !\n\n\n.. _Zulko: https://github.com/Zulko/\n.. _Github: https://github.com/Edinburgh-Genome-Foundry/flametree\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEdinburgh-Genome-Foundry%2FFlametree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FEdinburgh-Genome-Foundry%2FFlametree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEdinburgh-Genome-Foundry%2FFlametree/lists"}