{ "info": { "author": "Mathew Robinson", "author_email": "chasinglogic@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Affero General Public License v3", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# dfm\n\nA dotfile manager for lazy people and pair programmers.\n\n> dfm doesn't require that the dotfiles in your repository start with dots\n> though it handles either case equally well.\n\n## Table of Contents\n\n- [Features](#features)\n - [Multiple dotfile profiles](#multiple-dotfile-profiles)\n - [Profile modules](#profile-modules)\n - [Pre and post command hooks](#pre-and-post-command-hooks)\n - [Respects `$XDG_CONFIG_HOME`](#respects-xdg_config_home)\n - [Skips relevant files](#skips-relevant-files)\n - [Configurable mappings](#custom-mappings)\n- [Installation](#installation)\n- [Updating](#updating)\n- [Usage](#usage)\n- [Git quick start](#git-quick-start)\n - [Existing dotfiles repository](#quick-start-existing-dotfiles-repository)\n - [No existing dotfiles repository](#quick-start-no-existing-dotfiles-repository)\n- [Configuration](#configuration)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Features\n\ndfm supports these features that I was unable to find in other Dotfile\nManagement solutions.\n\n### Multiple dotfile profiles\n\ndfm's core feature is the idea of profiles. Profiles are simply a\ncollection of dotfiles that dfm manages and links in the `$HOME`\ndirectory or configuration directories. This means that you can have\nmultiple profiles and overlap them.\n\nThis feature is hard to describe, so I will illustrate it's usefulness\nwith two use cases:\n\n#### The work profile\n\nI use one laptop for work and personal projects in my dfm profiles I have my\npersonal profile `chasinglogic` which contains all my dotfiles for Emacs, git,\netc. and a \"work\" profile which only has a `.gitconfig` that has my work email\nin it. So my profile directory looks like this:\n\n```text\nprofiles/\n\u251c\u2500\u2500 chasinglogic\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 agignore\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 bash\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 bashrc\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 gitconfig\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 gnupg\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 password-store\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 pypirc\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 spacemacs.d\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 tmux.conf\n\u2514\u2500\u2500 work\n \u2514\u2500\u2500 gitconfig\n```\n\nSince dfm when linking only overwrites the files which are in the new\nprofile, I can run `dfm link work` and still have access to my emacs\nconfiguration but my `gitconfig` has been updated to use my work\nemail. Similarly when I leave work I just `dfm link chasinglogic` to\nswitch back.\n\nSee [profile modules](#profile-modules) for an even better solution to this\nparticular use case.\n\n#### Pair programming\n\nThe original inspiration for this tool was pair programming with my\nfriend [lionize](https://github.com/lionize). lionize has a dotfiles\nrepository so I can clone it using the git backend for dfm with `dfm\nclone --name lionize https://github.com/lionize/dotfiles`.\n\nNow our profile directory looks like:\n\n```text\nprofiles/\n\u251c\u2500\u2500 chasinglogic\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .dfm.yml\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .git\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .gitignore\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 agignore\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 bash\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 bashrc\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 gitconfig\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 gnupg\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 password-store\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 pypirc\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 spacemacs.d\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 tmux.conf\n\u251c\u2500\u2500 lionize\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .agignore\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .git\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .gitconfig\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .gitignore_global\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .gitmessage\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .scripts\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .tmux.conf\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .vim\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 .vimrc -> ./.vim/init.vim\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 .zshrc\n\u2514\u2500\u2500 work\n \u251c\u2500\u2500 .git\n \u2514\u2500\u2500 gitconfig\n```\n\nNow when I'm driving I simply `dfm link chasinglogic` and when passing back to\nlionize he runs `dfm link lionize` and we don't have to mess with multiple\nmachines vice versa.\n\n### Profile modules\n\ndfm supports profile modules which can be either additional dotfiles profiles as\naccepted by the `dfm clone` command or can be any git repository such as\n[Spacemacs](https://github.com/syl20bnr/spacemacs). You can get more info about\nhow to use them and configure them in [Configuration](#configuration)\n\n### Pre and Post command hooks\n\ndfm supports pre and post command hooks. that allows you to specify before and\nafter command shell scripts to run. For example, I use a profile module to keep\ncertain ssh keys in an encrypted git repository. Whenever I run the `dfm sync` command\nI have hooks which fix the permissions of the keys and ssh-add them to my ssh\nagent. You can read about how to write your own hooks in\n[Configuration](#configuration)\n\n### Respects `$XDG_CONFIG_HOME`\n\ndfm respects dotfiles which exist in the `$XDG_CONFIG_HOME` directory,\nmeaning if in your repository you have a folder named `config` or\n`.config` it'll translate those into the `$XDG_CONFIG_HOME`\ndirectory automatically. Similarly when using `dfm add` if inside your\n`$XDG_CONFIG_HOME` or $HOME/.configuration directories it'll add those to\nthe repository appropriately.\n\n### Skips relevant files\n\ndfm by default will skip multiple relevant files.\n\n- .git\n\ndfm will skip the .git directory so your `$HOME` directory isn't\nturned into a git repository.\n\n- .gitignore\n\nIf you would like to store a global `.gitignore` file you can either omit the\nleading dot (so just `gitignore`) or name the global one `.ggitignore` and dfm\nwill translate the name for you. Otherwise it assumes that `.gitignore` is the\ngitignore for the profile's repository and so skips it.\n\n- README\n\nWant to make a README for your dotfiles? Go ahead! As long as the file name\nstarts with README dfm will ignore it. So `README.txt` `README.md` and\n`README.rst` or whatever other permutations you can dream up all work.\n\n- LICENSE\n\nYou should put a LICENSE on all code you put on the internet and some dotfiles /\nconfigurations are actual code (See: Emacs). If you put a LICENSE in your\nprofile dfm will respect you being a good open source citizen and not clutter your\n`$HOME` directory.\n\n- .dfm.yml\n\nThis is a special dfm file used for hooks today and in the future for other ways\nto extend dfm. As such dfm doesn't put it in your `$HOME` directory.\n\n### Custom mappings\n\nThe above ignores are implemented as a dfm feature called\nMappings. You can write your own mappings to either skip, skip based\non platform or translate files to different locations than dfm would\nnormally place them. You can read how to configure your own mappings\nin [Configuration](#configuration)\n\n## Installation\n\n### Install from Release\n\ndfm is available on PyPi and should be installed from there:\n\n```text\n$ pip3 install dfm\n```\n\ndfm supports Python 3+.\n\n### Install from Source\n\nClone the repository and run `make install`:\n\n```bash\ngit clone https://github.com/chasinglogic/dfm\ncd dfm\nmake install\n```\n\n> It's possible that for your system you will need to run the make\n> command with sudo.\n\n## Usage\n\n```text\nUsage:\n dfm [options] [...]\n dfm help\n dfm sync\n dfm link \n\nDotfile management written for pair programmers. Examples on getting\nstarted with dfm are avialable at https://github.com/chasinglogic/dfm\n\nOptions:\n -v, --verbose If provided print more logging info\n --debug If provided print debug level logging info\n -h, --help Print this help information\n\nCommands:\n help Print usage information about dfm commands\n sync (s) Sync your dotfiles\n add (a) Add the file to the current dotfile profile\n clean (x) Clean dead symlinks\n clone (c) Use git clone to download an existing profile\n git (g) Run the given git command on the current profile\n init (i) Create a new profile\n link (l) Create links for a profile\n list (ls) List available profiles\n remove (rm) Remove a profile\n run-hook (rh) Run dfm hooks without using normal commands\n where (w) Prints the location of the current dotfile profile\n\nSee 'dfm help ' for more information on a specific command.\n```\n\n## Quick start\n\n### Quick start (Existing dotfiles repository)\n\nIf you already have a dotfiles repository you can start by cloning it using the clone\ncommand.\n\n> SSH URLs will work as well.\n\n```bash\ndfm clone https://github.com/chasinglogic/dotfiles\n```\n\nIf you're using GitHub you can shortcut the domain:\n\n```bash\ndfm clone chasinglogic/dotfiles\n```\n\nIf you want to clone and link the dotfiles in one command:\n\n```bash\ndfm clone --link chasinglogic/dotfiles\n```\n\nYou may have to use `--overwrite` as well if you have existing non-symlinked\nversions of your dotfiles\n\nOnce you have multiple profiles you can switch between them using `dfm link`\n\n```bash\ndfm link some-other-profile\n```\n\nSee the Usage Notes below for some quick info on what to expect from other dfm\ncommands.\n\n### Quick Start (No existing dotfiles repository)\n\nIf you don't have a dotfiles repository the best place to start is with `dfm init`\n\n```bash\ndfm init my-new-profile\n```\n\nThen run `dfm link` to set it as the active profile, this is also how you switch\nprofiles\n\n```bash\ndfm link my-new-profile\n```\n\nOnce that's done you can start adding your dotfiles\n\n```bash\ndfm add ~/.bashrc\n```\n\nAlternatively you can add multiple files at once\n\n```bash\ndfm add ~/.bashrc ~/.vimrc ~/.vim ~/.emacs.d\n```\n\nThen create your dotfiles repository on GitHub. Instructions for how to do that can be\nfound [here](https://help.github.com/articles/create-a-repository/). Once that's done\nget the \"clone\" URL for your new repository and set it as origin for the profile:\n\n**Note:** When creating the remote repository don't choose any options such as\n\"initialize this repository with a README\" otherwise git'll get cranky when you add\nthe remote because of a recent git update and how it handles [unrelated\nhistories](http://stackoverflow.com/questions/37937984/git-refusing-to-merge-unrelated-histories)\nif you do don't worry the linked post explains how to get past it.\n\n```bash\ndfm git remote add origin \n```\n\nThen simply run `dfm sync` to sync your dotfiles to the remote\n```bash\ndfm sync\n```\n\nNow you're done!\n\n## Configuration\n\ndfm supports a `.dfm.yml` file in the root of your repository that\nchanges dfm's behavior when syncing and linking your profile. This\nfile will be ignored when doing a `dfm link` so won't end up in\nyour home directory. The `.dfm.yml` can be used to configure these\nfeatures:\n\n- [Modules](#modules)\n- [Mappings](#mappings)\n- [Hooks](#hooks)\n\n### Modules\n\nModules in dfm are like sub profiles. They're git repositories that are cloned into a\na special directory: `$XDG_CONFIG_HOME/dfm/modules`. They're shared across\nprofiles so if two dotfile profiles have the same module they'll share that\nmodule.\n\nThe syntax for defining a minimum module is as follows:\n\n```yaml\nmodules:\n - repository: git@github.com:chasinglogic/dotfiles\n```\n\nThis would clone my dotfiles repository as a module into\n`$XDG_CONFIG_HOME/dfm/modules/dotfiles`. If I wanted to use a unique name or\nsome other folder name so it wouldn't be shared you can specify an additional\noption `name`:\n\n```yaml\nmodules:\n - repository: git@github.com:chasinglogic/dotfiles\n name: chasinglogic-dotfiles\n```\n\nWhich would instead clone into\n`$XDG_CONFIG_HOME/dfm/modules/chasinglogic-dotfiles`. You can define multiple\nmodules:\n\n```yaml\nmodules:\n - repository: git@github.com:chasinglogic/dotfiles\n name: chasinglogic-dotfiles\n - repository: git@github.com:lionize/dotfiles\n```\n\nMake sure that you specify a name if the resulting clone location as defined by\ngit would conflict as we see here. Both of these would have been cloned into\ndotfiles which would cause the clone to fail for the second module if we didn't\nspecify name for chasinglogic's dotfiles.\n\nAn additional use for modules is that of a git repository you want to clone but not\nlink. An example use would be for downloading\n[Spacemacs](https://github.com/syl20bnr/spacemacs) or any such community\nconfiguration like oh-my-zsh, etc.\n\n```yaml\nmodules:\n - repo: git@github.com:syl20bnr/spacemacs\n link: none\n pull_only: true\n location: ~/.emacs.d\n```\n\nHere we specify a few extra keys. There purpose should be self explanatory but\nif you're curious [below](#available-keys) is a detailed explanation of all keys\nthat each module configuration supports.\n\n#### Available keys\n\n- [repo](#repo)\n- [name](#name)\n- [location](#location)\n- [link](#link)\n- [pull\\_only](#pull\\_only)\n- [mappings](#mappings)\n\n##### repo\n\nRequired, this is the git repository to clone for the module.\n\n##### name\n\nThis changes the cloned name. This only has an effect if location isn't\nprovided. Normally a git repository would be cloned into\n`$XDG_CONFIG_HOME/dfm/modules` and the resulting folder would be named whatever\ngit decides it should be based on the git URL. If this is provided it'll be\ncloned into the modules directory with the specified name. This is useful if\nmultiple profiles use the same module.\n\n##### location\n\nIf provided module will be cloned into the specified location. You can use the\n`~` bash expansion here to represent `$HOME`. No other expansions are available.\nThis option is useful for cloning community configurations like oh-my-zsh or\nspacemacs.\n\n##### link\n\nDetermines when to link the module. Link in this context means that it'll be\ntreated like a normal dotfile profile, so all files will go through the same\ntranslation rules as a regular profile and be linked accordingly. Available\nvalues are `post`, `pre`, and `none`. `post` is the default and means that the\nmodule will be linked after the parent profile. \"pre\" means this will be linked\nbefore the parent profile, use this if for instance you want to use most files\nfrom this profile and override a few files with those from the parent file since\ndfm will overwrite the links with the last one found. \"none\" means the module is\nnot a dotfiles profile and shouldn't be linked at all, an example being\ncommunity configuration repositories like oh-my-zsh or spacemacs.\n\n##### pull\\_only\n\nIf set to `true` won't attempt to push any changes. It's important to\nknow that dfm always tries to push to origin master, so if you don't\nhave write access to the repository or don't want it to automatically\npush to master then you should set this to true. This is useful for\ncommunity configuration repositories.\n\n##### mappings\n\nA list of file mappings as described below in [Mappings](#mappings). Modules do\nnot inherit parent mappings, they do however inherit the default mappings as\ndescribed in [Skips Relevant Files](#skips-relevant-files)\n\n### Mappings\n\nMappings are a way of defining custom file locations. To understand\nmappings one must understand dfm's default link behavior:\n\n#### Default behavior\n\nFor an example let's say you have a file named `my_config.txt` in your\ndotfile repository. dfm will try and translate that to a new location\nof `$HOME/.my_config.txt`. It'll then create a symlink at that location\npointing to `my_config.txt` in your dotfile repository.\n\n#### Using mappings\n\nWith mappings you can replace this behavior and make it so dfm will\nlink `my_config` wherever you wish. This is useful if you need to\nstore config files that are actually global. Such as configuration\nfiles that would go into `/etc/` or if you want to sync some files in\nyour repo but not link them.\n\nHere is a simple example:\n\n```yaml\nmappings:\n - match: my_global_etc_files\n target_dir: /etc/\n - match: something_want_to_skip_but_sync\n skip: true\n - match: something_only_for_macos\n target_os: \"Darwin\"\n - match: some_file_for_mac_and_linux_only\n target_os:\n - \"Linux\"\n - \"Darwin\"\n```\n\nHere dfm uses the match as a regular expression to match the file\npaths in your dotfile repository. When it finds a path which matches\nthe regular expression it adds an alternative linking behavior. For\nanything where `skip` is true it simply skips linking. For anything\nwith `target_dir` that value will override `$HOME` when linking. For\nanything with a `target_os` value the file will only be linked if dfm\nis being run on the given os.\n\n#### Available configuration\n\nMappings support the following configuration options:\n\n- [match](#match)\n- [skip](#skip)\n- [target\\_dir](#target\\_dir)\n- [target\\_os](#target\\_os)\n\n##### match\n\nMatch is a regular expression used to match the file path of any files\nin your dotfile repository. This is used to determine if the custom\nlinking behavior for a file should be used.\n\nThese are python style regular expressions and are matched using the\n[`re.findall`](https://docs.python.org/3/library/re.html#re.findall)\nmethod so are by default fuzzy matching.\n\n##### skip\n\nIf provided the file/s will not be linked.\n\n##### target\\_dir\n\nWhere to link the file to. The `~` expansion for `$HOME` is supported\nhere but no other expansions are available. It is worth noting that if\nyou're using `~` in your target_dir then you should probably just\ncreate the directory structure in your git repo.\n\n##### target\\_os\n\nA string or list of strings matching the OS's to link this file\non. A non-exhaustive list of common values are: `Linux`, `Darwin`, or\n`Windows`. This matches the string returned by [Python's\n`platform.system()`\nfunction.](https://docs.python.org/3/library/platform.html#platform.system)\n\n### Hooks\n\nHooks in dfm are used for those few extra tasks that you need to do whenever\nyour dotfiles are synced or linked.\n\nAn example from my personal dotfiles is running an Ansible playbook\nwhenever I sync my dotfiles. To accomplish this I wrote an\n`after_sync` hook as follows:\n\n```yaml\nhooks:\n after_sync:\n - ansible-playbook ansible/dev-mac.yml\n```\n\nNow whenever I sync my dotfiles Ansible will run my `dev-mac` playbook to make\nsure that my packages etc are also in sync!\n\nThe hooks option is just a YAML map which supports the following keys:\n`after_link`, `before_link`, `after_sync`, and `before_sync`. The\nvalues of any of those keys is a YAML list of strings which will be\nexecuted in a shell via `/bin/sh -c '$YOUR COMMAND'`. An example would\nbe:\n\n```yaml\nhooks:\n after_link:\n - ls -l\n - whoami\n - echo \"All done!\"\n```\n\nAll commands are ran with a working directory of your dotfile\nrepository and the current process environment is passed down to the\nprocess so you can use `$HOME` etc environment variables in your\ncommands.\n\n## Contributing\n\n1. Fork it!\n2. Create your feature branch: `git checkout -b my-new-feature`\n3. Commit your changes: `git commit -am 'Add some feature'`\n4. Push to the branch: `git push origin my-new-feature`\n5. :fire: Submit a pull request :D :fire:\n\nAll pull requests should go to the develop branch not master. Thanks!\n\n## License\n\nThis code is distributed under the GNU General Public License\n\n```\n Copyright (C) 2018 Mathew Robinson\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program. If not, see .\n```\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/chasinglogic/dfm", "keywords": "", "license": "GPL-3.0", "maintainer": "", "maintainer_email": "", "name": "dfm", "package_url": "https://pypi.org/project/dfm/", "platform": "any", "project_url": "https://pypi.org/project/dfm/", "project_urls": { "Homepage": "https://github.com/chasinglogic/dfm" }, "release_url": "https://pypi.org/project/dfm/7.3.1/", "requires_dist": [ "docopt", "pyyaml (>=3.13)" ], "requires_python": "", "summary": "A dotfile manager for pair-programmers and lazy people.", "version": "7.3.1" }, "last_serial": 5837177, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "8da9bb60422d36d06c36b7f06e5630d5", "sha256": "5af37a880f8fe0d25e4d773d8228632af054712d40635985c4e3ae42f1b589bf" }, "downloads": -1, "filename": "dfm-0.1.tar.gz", "has_sig": false, "md5_digest": "8da9bb60422d36d06c36b7f06e5630d5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6317, "upload_time": "2016-09-30T18:45:26", "url": "https://files.pythonhosted.org/packages/52/14/328f9d94a17f488083d57ba68bca0e9eca117674718efecdca13c0b1fe4a/dfm-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "eb20f6e0a5369ca156570aaaa3e7d359", "sha256": "429d6bdf53a6ddee9ee667d47977e4307c07abfe9d7206b7b252cc3d5bf8052b" }, "downloads": -1, "filename": "dfm-0.2.tar.gz", "has_sig": false, "md5_digest": "eb20f6e0a5369ca156570aaaa3e7d359", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4418, "upload_time": "2016-09-30T18:51:42", "url": "https://files.pythonhosted.org/packages/78/4a/657ea802b2d8a51d2ff6162138b2c30b5106c580230513e812e5a865e479/dfm-0.2.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "c70968ee6a34ace8a0eaf8141109406f", "sha256": "66ee4af8224876765bf15c00c44931e9cb7f9d755f31e6ab327bdb81d71dc906" }, "downloads": -1, "filename": "dfm-0.3.tar.gz", "has_sig": false, "md5_digest": "c70968ee6a34ace8a0eaf8141109406f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4382, "upload_time": "2016-10-02T21:07:02", "url": "https://files.pythonhosted.org/packages/a7/13/5e5a8dea3ff3a7e8e449a5b84278e696557a6185cfd6ed20357546a83722/dfm-0.3.tar.gz" } ], "2.0": [ { "comment_text": "", "digests": { "md5": "b26a9c7a97806038904ce605f039f4b2", "sha256": "cbe213ff645d91358160dfa525fce4659ffced4eadb6dbe5e4a929a05a84a578" }, "downloads": -1, "filename": "dfm-2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "b26a9c7a97806038904ce605f039f4b2", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 8675, "upload_time": "2017-04-18T18:46:12", "url": "https://files.pythonhosted.org/packages/18/6b/b8f143c9a0eba0cf600a73054925c61c436266d17c4e6055018ead01182a/dfm-2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "31d4f6cb5d988ac8944471021c3b104a", "sha256": "34bf43fc10e8e0ef60fc03aa210b140dd9d0c1db323bb1153131ae036c8a1c4a" }, "downloads": -1, "filename": "dfm-2.0.tar.gz", "has_sig": false, "md5_digest": "31d4f6cb5d988ac8944471021c3b104a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5377, "upload_time": "2017-04-18T18:46:25", "url": "https://files.pythonhosted.org/packages/3e/b5/656d0189583c68f2c1f54a3da767de35102cbb6b3f71339e2c3bdfd558e7/dfm-2.0.tar.gz" } ], "2.1": [ { "comment_text": "", "digests": { "md5": "7cad6a21c40fddfba8df5462b9d67ad7", "sha256": "fe0d81649b09a44ae3228c6fbeff1ce938a859c3c2d9065b82ee437432fcf564" }, "downloads": -1, "filename": "dfm-2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "7cad6a21c40fddfba8df5462b9d67ad7", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 8671, "upload_time": "2017-04-19T13:00:54", "url": "https://files.pythonhosted.org/packages/68/f3/fd4229ed54f9ab8d000f609de309b917dd00ee40fb4140be583c2138fa6e/dfm-2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6ef0136f323de9937366ddc03419b08f", "sha256": "d7135c9918fc1ccca511c1946d0144190c9bd8f0609eda46f977c717f71033ce" }, "downloads": -1, "filename": "dfm-2.1.tar.gz", "has_sig": false, "md5_digest": "6ef0136f323de9937366ddc03419b08f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5379, "upload_time": "2017-04-19T13:01:11", "url": "https://files.pythonhosted.org/packages/6c/5d/2525dea5d5df02b41ece5fa35f62d0781888f6431ddbb612c5eb43d5e35c/dfm-2.1.tar.gz" } ], "2.2.1": [ { "comment_text": "", "digests": { "md5": "60bdc60447749d540e0dd9ebbcc01462", "sha256": "fc6586fb8c2fe175bd2160c3897debe8e6dc5b78e767da80325ef7a65947f1fd" }, "downloads": -1, "filename": "dfm-2.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "60bdc60447749d540e0dd9ebbcc01462", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 9022, "upload_time": "2017-04-27T00:08:58", "url": "https://files.pythonhosted.org/packages/f7/cc/92326248425a14acf93b6bf15781d604f5d23c9a5d56c8d24e13c37a1d76/dfm-2.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5fa8b60a40b6af1cda76a4ac98fcf94d", "sha256": "f1e0bdc73faed650b10ec614ce60b6b047d3a8babc26756f2cd50facad37fb64" }, "downloads": -1, "filename": "dfm-2.2.1.tar.gz", "has_sig": false, "md5_digest": "5fa8b60a40b6af1cda76a4ac98fcf94d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5566, "upload_time": "2017-04-27T00:08:56", "url": "https://files.pythonhosted.org/packages/88/81/670767bdbd8f53bc758f42f7443c0f24469e43b54ee324a08208a5387e13/dfm-2.2.1.tar.gz" } ], "2.2.2": [ { "comment_text": "", "digests": { "md5": "67fb8dab0adb478bc123834c9ec9b7fd", "sha256": "f45c39c974805a478b366d6303061b1ae6c2bf4126b2cecc8843e7cdeb6b937d" }, "downloads": -1, "filename": "dfm-2.2.2-py3-none-any.whl", "has_sig": false, "md5_digest": "67fb8dab0adb478bc123834c9ec9b7fd", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 9064, "upload_time": "2017-04-27T00:24:59", "url": "https://files.pythonhosted.org/packages/b4/f8/761fd3333fe71815d3b090e0eb0944893621567a0d281ec21a40d0d71df3/dfm-2.2.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1136039a5763a0f9872379bbd137109f", "sha256": "7fbac82049cc4a08878a763ae412ddbf726728998ddf27e0098af612b956cc3d" }, "downloads": -1, "filename": "dfm-2.2.2.tar.gz", "has_sig": false, "md5_digest": "1136039a5763a0f9872379bbd137109f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5612, "upload_time": "2017-04-27T00:24:57", "url": "https://files.pythonhosted.org/packages/99/19/cd3e9c013b2f3f50ce9bfb342a73473bea3b3d446a214c2f3676725e2b7b/dfm-2.2.2.tar.gz" } ], "2.3.0": [ { "comment_text": "", "digests": { "md5": "a3c97b8996903ab1ddac4c366443f9ac", "sha256": "d492ad86aac81f9d16c9ef7871160473606ec06e35e3edf3720c039ce17f4c7c" }, "downloads": -1, "filename": "dfm-2.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "a3c97b8996903ab1ddac4c366443f9ac", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 14474, "upload_time": "2017-05-15T17:09:49", "url": "https://files.pythonhosted.org/packages/bf/35/281f7c244ca6a1368d231eabb76c3e8130a8fc768eff7ec0a230c1f0ad94/dfm-2.3.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f7b09d88c30a13ce116d6de6475df201", "sha256": "1b1c00ea4f3fc15b798144757aa2ee534e62836f5116f8604221525974dccecc" }, "downloads": -1, "filename": "dfm-2.3.0.tar.gz", "has_sig": false, "md5_digest": "f7b09d88c30a13ce116d6de6475df201", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8368, "upload_time": "2017-05-15T17:09:47", "url": "https://files.pythonhosted.org/packages/31/f1/d5fc963f59f9fcd79df00ca95b06b899030c7b318ab13777ebf742aee7c5/dfm-2.3.0.tar.gz" } ], "2.3.1": [ { "comment_text": "", "digests": { "md5": "749631e8113e51567afcdc2ffa26b8cf", "sha256": "558f1650edf057441e500796c9feaf11e85d9c4ce1cccb031c3163bf96d76239" }, "downloads": -1, "filename": "dfm-2.3.1-py3-none-any.whl", "has_sig": false, "md5_digest": "749631e8113e51567afcdc2ffa26b8cf", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 13403, "upload_time": "2017-05-17T12:36:05", "url": "https://files.pythonhosted.org/packages/0b/fd/6a58223cc5799bc1473fc001a7fa5dd87191714ca17d796649cae561f523/dfm-2.3.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "61f80eb0e6921b4421a00c03446e1a65", "sha256": "0f842f1258b4316442d15f0c3f21c10585bce0f19b925b6ec1574122e94b66ed" }, "downloads": -1, "filename": "dfm-2.3.1.tar.gz", "has_sig": false, "md5_digest": "61f80eb0e6921b4421a00c03446e1a65", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8144, "upload_time": "2017-05-17T12:36:04", "url": "https://files.pythonhosted.org/packages/fd/75/59834bdcf34b24c3cdd88cbb1c96cb77b14e9f6eb98b28bff76976cd30c3/dfm-2.3.1.tar.gz" } ], "2.3.2": [ { "comment_text": "", "digests": { "md5": "f64f7a72baf4326ef1c7314de3e9716a", "sha256": "592ace245aae6d1019f09fd873f3433d7bb3827be96d691f86af4ee200f0c949" }, "downloads": -1, "filename": "dfm-2.3.2-py3-none-any.whl", "has_sig": false, "md5_digest": "f64f7a72baf4326ef1c7314de3e9716a", "packagetype": "bdist_wheel", "python_version": "3.6", "requires_python": null, "size": 13413, "upload_time": "2017-07-10T11:47:31", "url": "https://files.pythonhosted.org/packages/8d/94/37cd3c71ec73501bdf1f91f6bade3b5f4f603d4c3b1c4af8d8cd39e710ce/dfm-2.3.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1e1151e51a26dc5200c5f77c6d5e1456", "sha256": "588d1988f1e8b6658c762bc5c394e8d0c064088e4fc611d715c4034b68c3571d" }, "downloads": -1, "filename": "dfm-2.3.2.tar.gz", "has_sig": false, "md5_digest": "1e1151e51a26dc5200c5f77c6d5e1456", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8166, "upload_time": "2017-07-10T11:47:33", "url": "https://files.pythonhosted.org/packages/eb/80/5cdfc8668c25806a9155ae042900e40a0e852550c1ebc686a8869347d483/dfm-2.3.2.tar.gz" } ], "6.0.0": [ { "comment_text": "", "digests": { "md5": "c1df578f048614762e728889fe827c54", "sha256": "3009b0b1e66acac7c52a72a3290e5b821af19326646eee3c267b15ae9a67efa2" }, "downloads": -1, "filename": "dfm-6.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "c1df578f048614762e728889fe827c54", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19586, "upload_time": "2018-09-30T20:00:57", "url": "https://files.pythonhosted.org/packages/c4/28/9110ed795bc0439e3673394cfda70fd58d7c6dbbea5d50c8b99f09b854b7/dfm-6.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f0751a1405e34d9598ee8548ea0dcbe9", "sha256": "d89d158cd599b908e36e424b63eeedf20f4f87513074a435d42fb4b10048ad3e" }, "downloads": -1, "filename": "dfm-6.0.0.tar.gz", "has_sig": false, "md5_digest": "f0751a1405e34d9598ee8548ea0dcbe9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24478, "upload_time": "2018-09-30T20:00:59", "url": "https://files.pythonhosted.org/packages/d4/36/18227304a8cad0809913452b87d26ae283b220519e1fa93d4c70e25fa80c/dfm-6.0.0.tar.gz" } ], "6.0.1": [ { "comment_text": "", "digests": { "md5": "8ee84db75e19edea8b2e33689a6f8b7d", "sha256": "b2cedc6dc3f482ba96f558a6b4ef095df43e881aa3a3dbb8af51f6ea91542ce9" }, "downloads": -1, "filename": "dfm-6.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "8ee84db75e19edea8b2e33689a6f8b7d", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19588, "upload_time": "2018-10-02T13:59:11", "url": "https://files.pythonhosted.org/packages/16/e4/ebe891f5f63dfc203a1a853ba5f130d8ae67d5fa0ee8994b9a7934f2716d/dfm-6.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "157ea5845eee15718c4de4a42583bab7", "sha256": "bbe80750d3acc1d430404697a6c93ce99a50cdaee6c7e17ece95b31fc32647b2" }, "downloads": -1, "filename": "dfm-6.0.1.tar.gz", "has_sig": false, "md5_digest": "157ea5845eee15718c4de4a42583bab7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24487, "upload_time": "2018-10-02T13:59:12", "url": "https://files.pythonhosted.org/packages/db/59/97966d683c565f5719d2469931429150de1c7f1041f849e9a83ed5cf6870/dfm-6.0.1.tar.gz" } ], "7.0.0": [ { "comment_text": "", "digests": { "md5": "484c30ef836b593a5af06cfea1d7afa4", "sha256": "452d60a48358b9c125ca1e638e6657f9bc7b79294c99c69ef41dc9220fcef392" }, "downloads": -1, "filename": "dfm-7.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "484c30ef836b593a5af06cfea1d7afa4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19204, "upload_time": "2018-11-06T22:53:50", "url": "https://files.pythonhosted.org/packages/56/3d/ffd8e1d802590a94be7b2bc53e97f70871a19e6602fc59d16741df1996a0/dfm-7.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "130a669e6bcb56691691d0d0e65f70d0", "sha256": "b15abb176c3a1b5fd8a4cb9c516034445b2348a77b7078f40b86da37c6035363" }, "downloads": -1, "filename": "dfm-7.0.0.tar.gz", "has_sig": false, "md5_digest": "130a669e6bcb56691691d0d0e65f70d0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24163, "upload_time": "2018-11-06T22:53:52", "url": "https://files.pythonhosted.org/packages/69/3b/c2a3807794cbf3c4a5dbd7bbfc16b352264c6eff860c01a234c59851a513/dfm-7.0.0.tar.gz" } ], "7.1.0": [ { "comment_text": "", "digests": { "md5": "20bb401691e15dc6f68fee66ec5615fb", "sha256": "d5754a3ad1c0fdebc4e314a0826e65767f6ae1078e25ef6142124efddf7b496f" }, "downloads": -1, "filename": "dfm-7.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "20bb401691e15dc6f68fee66ec5615fb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19191, "upload_time": "2018-11-06T23:55:34", "url": "https://files.pythonhosted.org/packages/33/1f/d222a13909db0f122bbc9624ae497d7a3919a6230938bac7c5e077e5ab7f/dfm-7.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "feb2b15da93814502c97b9bb200e3302", "sha256": "516f3861872f2b226025109573cccdcf3b4579fac0a433c5c92213286b9df4c4" }, "downloads": -1, "filename": "dfm-7.1.0.tar.gz", "has_sig": false, "md5_digest": "feb2b15da93814502c97b9bb200e3302", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23679, "upload_time": "2018-11-06T23:55:35", "url": "https://files.pythonhosted.org/packages/46/2d/74ffba8c3c1b1325df19594d1b50b8018f6d7f611f3111a2e13da98c205d/dfm-7.1.0.tar.gz" } ], "7.2.0": [ { "comment_text": "", "digests": { "md5": "f6faf1ca00220cdd9209c7a2af6d5d83", "sha256": "724f53417bd8f644f14ab65dda06a21bab00959d8863f07dbaf8f6e9812a25cf" }, "downloads": -1, "filename": "dfm-7.2.0-py3.7.egg", "has_sig": false, "md5_digest": "f6faf1ca00220cdd9209c7a2af6d5d83", "packagetype": "bdist_egg", "python_version": "3.7", "requires_python": null, "size": 35362, "upload_time": "2019-03-14T13:27:12", "url": "https://files.pythonhosted.org/packages/a1/97/542c4cf5b483d5fa049e8e9996bb041a3a0af1534f2da865eff5ed22b8bb/dfm-7.2.0-py3.7.egg" }, { "comment_text": "", "digests": { "md5": "d3d46389d8f7171761552677f25e221a", "sha256": "dcd8c6eca5aa914e13181f918296b99cb262a841aed9e2147b9055218599d40a" }, "downloads": -1, "filename": "dfm-7.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "d3d46389d8f7171761552677f25e221a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19404, "upload_time": "2019-03-14T13:27:10", "url": "https://files.pythonhosted.org/packages/a8/a3/a3568e9173d00361b1ca2ee707c73173daace372e786a5dcae18674ee808/dfm-7.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "cc1b56abc57e07184a49370d30af913c", "sha256": "9ec70f8df274124f1f0cd3af643d81dd60831b1bd237f5fa7a4a9ae7d01016bc" }, "downloads": -1, "filename": "dfm-7.2.0.tar.gz", "has_sig": false, "md5_digest": "cc1b56abc57e07184a49370d30af913c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23879, "upload_time": "2019-03-14T13:27:13", "url": "https://files.pythonhosted.org/packages/55/02/4e88e1b8229012a37e75e0c95314a666d28d7862db21c10d55b06f311daf/dfm-7.2.0.tar.gz" } ], "7.2.1": [ { "comment_text": "", "digests": { "md5": "fc1354de2892f490f91934ff7aa0b601", "sha256": "3ffa02cb392aa4586644f0d8727acb0b41fc6716d95b76eeac3d0b0553194d0e" }, "downloads": -1, "filename": "dfm-7.2.1-py2-none-any.whl", "has_sig": false, "md5_digest": "fc1354de2892f490f91934ff7aa0b601", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 19454, "upload_time": "2019-05-13T14:34:25", "url": "https://files.pythonhosted.org/packages/50/62/61e30c6221de4caeda2a10dd78a9a532223fe5a694099e074a8875037468/dfm-7.2.1-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f1177da8499ada6cab78f8e1d6317f5b", "sha256": "633503014e73bb097ea665c36c921def4c427fa1155b10a3f1d842d51bec68da" }, "downloads": -1, "filename": "dfm-7.2.1.tar.gz", "has_sig": false, "md5_digest": "f1177da8499ada6cab78f8e1d6317f5b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24330, "upload_time": "2019-05-13T14:34:26", "url": "https://files.pythonhosted.org/packages/4a/15/6064ee0dafe33536cadbdeaebf180243a05cc5ccbac892bcaea7d80aadc5/dfm-7.2.1.tar.gz" } ], "7.3.0": [ { "comment_text": "", "digests": { "md5": "fe41958038cb64507adb1decd1716fc9", "sha256": "d80589da92669d72a5b92eae735a5a2f2ca465e417068844fdd1663ae8545144" }, "downloads": -1, "filename": "dfm-7.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "fe41958038cb64507adb1decd1716fc9", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19796, "upload_time": "2019-05-23T15:40:18", "url": "https://files.pythonhosted.org/packages/85/37/5af8451ff5de1cdbd50b7538912fff885177227fa06a37f7c9cf5dc117f6/dfm-7.3.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7dc0a4f0c11064b14c9aa0541c38c61c", "sha256": "0d67fc9f9b671149017184cd64b0767127048df0322d2b280d6cf1a952a2fc05" }, "downloads": -1, "filename": "dfm-7.3.0.tar.gz", "has_sig": false, "md5_digest": "7dc0a4f0c11064b14c9aa0541c38c61c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24503, "upload_time": "2019-05-23T15:40:19", "url": "https://files.pythonhosted.org/packages/ca/3e/4af1ec8041a63c8f4a3d7b165db6e16adb63c1647d36d5d69d29c4611081/dfm-7.3.0.tar.gz" } ], "7.3.1": [ { "comment_text": "", "digests": { "md5": "7e4da2d219d79fd263c179d1ba599ca9", "sha256": "20e787142dccd524c1a394e8903a3a1a3c451a88155b1ad83236b2e398e854d5" }, "downloads": -1, "filename": "dfm-7.3.1-py3-none-any.whl", "has_sig": false, "md5_digest": "7e4da2d219d79fd263c179d1ba599ca9", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19605, "upload_time": "2019-09-16T16:19:15", "url": "https://files.pythonhosted.org/packages/74/2e/04352160dcede6e5b2e9e1d29ca016d5fded152a42656d81543485ce2140/dfm-7.3.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4be2b78b3fb1eb26abf1c8d80cb507bb", "sha256": "5aa296e47d666bca37fb69a7fb489fea292148bb089cbafa19ae2aab5648362e" }, "downloads": -1, "filename": "dfm-7.3.1.tar.gz", "has_sig": false, "md5_digest": "4be2b78b3fb1eb26abf1c8d80cb507bb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24887, "upload_time": "2019-09-16T16:19:16", "url": "https://files.pythonhosted.org/packages/55/e5/44282a8938fb69ca592a437d3df075b11b9aa870eaaacccebf2c280a2409/dfm-7.3.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "7e4da2d219d79fd263c179d1ba599ca9", "sha256": "20e787142dccd524c1a394e8903a3a1a3c451a88155b1ad83236b2e398e854d5" }, "downloads": -1, "filename": "dfm-7.3.1-py3-none-any.whl", "has_sig": false, "md5_digest": "7e4da2d219d79fd263c179d1ba599ca9", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19605, "upload_time": "2019-09-16T16:19:15", "url": "https://files.pythonhosted.org/packages/74/2e/04352160dcede6e5b2e9e1d29ca016d5fded152a42656d81543485ce2140/dfm-7.3.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4be2b78b3fb1eb26abf1c8d80cb507bb", "sha256": "5aa296e47d666bca37fb69a7fb489fea292148bb089cbafa19ae2aab5648362e" }, "downloads": -1, "filename": "dfm-7.3.1.tar.gz", "has_sig": false, "md5_digest": "4be2b78b3fb1eb26abf1c8d80cb507bb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 24887, "upload_time": "2019-09-16T16:19:16", "url": "https://files.pythonhosted.org/packages/55/e5/44282a8938fb69ca592a437d3df075b11b9aa870eaaacccebf2c280a2409/dfm-7.3.1.tar.gz" } ] }