{ "info": { "author": "Erik Johnson", "author_email": "xtrementl@brokenresolve.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Topic :: Software Development", "Topic :: Utilities" ], "description": "Introduction\n============\n\nFocus is a command-line productivity tool for improved task workflows.\n\nWhy Focus?\n----------\n\nFor developers, Focus aims to help fight distractions while you work;\nless distractions means more focus. Currently, Focus targets Unix-like\noperating systems, such as Linux or Mac OSX.\n\nFeatures\n========\n\nOpen Applications\n-----------------\nLaunch applications needed for your task.\n\nClose Applications\n------------------\nQuit unnecessary applications when starting your task.\n\nBlock Applications\n------------------\nContinuously quit unnecessary applications if they are launched during a task.\n\nBlock Websites\n--------------\nBlock distracting websites, such as Hacker News, Facebook, YouTube, and\nTwitter.\n\nRun Commands\n------------\nExecute arbitrary shell commands useful for your task.\n\nPlay Sounds\n-----------\nPlay a sound after your task timer runs out or whenever you end the task.\nYou can also play a sound when starting tasks, in case you want to get\nyour groove on.\n\nNotifications\n-------------\nShow a popup system notification message when a task is started or\nhas ended, either by you completing the task or the timer running out.\n\nUpdate IM Status\n----------------\nUpdate the account status for your favorite instant messenger (IM) applications\nwhile you work. Focus supports `Pidgin `_,\n`Empathy `_, and\n`Skype `_ on Linux and `Adium `_ and\n`Skype `_ on Mac OSX.\n\nTrack Your Time\n---------------\nKeep tabs on how long you work on tasks per day. Focus will record your time\nautomatically and present your time as a simple report.\n\n**If these features won't do it for you, Focus boasts a simple, yet powerful\nplugin system. More on this later.**\n\nInstallation\n============\n\n $ sudo pip install focus\n\nor from source:\n\n $ sudo python setup.py install\n\nPython Libraries\n----------------\n\nThe following Python libraries are required to run Focus; though ``pip``\nshould handle taking care of installing them if not available.\n\n* psutil >= 0.4.1\n* argparse (Python <2.7)\n* dbus (Linux only)\n\nOptional External Dependencies\n------------------------------\n\n* Linux:\n `mpg123 `_, `play `_,\n or `aplay `_ [WAV only] (to play sounds)\n\n* Mac OSX:\n `terminal-notifier `_\n or `growlnotify `_\n (to show notifications)\n\nUsage\n=====\n\nCreate Task\n-----------\n\n $ focus make task_name [--skip-edit]\n\nor, clone from existing task:\n\n $ focus make task_name other_task [--skip-edit]\n\nThis command opens the task configuration file using the shell's default editor\n($EDITOR), unless the ``--skip-edit`` flag is provided. After the editor exits,\nthe configuration file is validated and will prompt for retry if validation\nfails.\n\nStart Task\n----------\n\n $ focus on task_name\n\nThis starts the provided task, running any initial settings as indicated in the\ntask's configuration file.\n\nEnd Task\n--------\n\n $ focus end\n\nThis ends the current task, running any ending settings as indicated in the\ntask's configuration file.\n\n*Note: this command is only available when a task is active.*\n\nEdit Task\n---------\n\n $ focus edit task_name [--skip-edit]\n\nLike the ``make`` command, this command opens the task configuration file using\nthe shell's default editor ($EDITOR). After the editor exits, the\nconfiguration file is validated and will prompt for retry if validation fails.\n\nList Tasks\n----------\n\n $ focus list [-v] [--verbose]\n\nThis will scan for existing tasks with valid configuration files and print\nthe names of the tasks found. Specify the ``-v`` or ``--verbose`` flag to also\nprint setting information for each task's configuration file. Invalid tasks\nare marked in red, while the active task is marked in green.\n\nView Task\n---------\n\n $ focus view [task_name]\n\nThis prints the setting information from the task's configuration file.\nIf no task name is provided, the active task will be shown.\n\nRename Task\n-----------\n\n $ focus rename old_task_name new_task_name\n\nThis commands gives the provided task a new name.\n\nDelete Task\n-----------\n\n $ focus destroy task_name [-f] [--force]\n\nThis commands removes the provided task after prompting for confirmation.\nSpecify the ``-f`` or ``--force`` flag to skip confirmation.\n\nShow Remaining Time for Active Task\n-----------------------------------\n\n $ focus left [-s] [--short]\n\nThis commands prints the amount of time remaining, in minutes, for the active\ntask. Specify the ``-s`` or ``--short`` flag to print just the number of\nminutes.\n\n*Note: this command is only available if the active task has defined the\nduration option.*\n\nShow Available Usage Statistics\n-------------------------------\n\n $ focus stat [start]\n\nThis commands prints the daily task usage summaries, broken out per task, for\nevery day from the starting period through the current day.\n\nThe starting period supports the following values ::\n\n today, t\n yesterday, y\n {n}d, {n}day, {n} day, {n}days, {n} days, {n} day ago, {n} days ago\n w, wk, week, last week\n {n}w, {n}wk, {n}week, {n}weeks, {n} week ago, {n} weeks ago\n\nwhere {n} is replaced with a number (e.g. ``1d`` for 1 day ago to today).\nIf no starting period is provided, then ``today`` will be used.\n\nTask Configuration\n==================\n\nEach task is described by its associated configuration file. When a new task\nis created, the `default task configuration file\n`_ will be\nused.\n\nThe task configuration file is composed of a number of either non-block or\nblock options. Each value for an option may be quoted with either single or\ndouble quote, or may be unquoted if spaces and quotes are escaped.\n\n**Examples:** ::\n\n # option => value 1, value2, value 3, value 4, value\\ 5\n option \"value 1\", value2, 'value 3', value\\ 4, value\\\\ 5;\n\n # option => a 'b', a 'b', a \\ b, a \\ b, a \\ b, a \\\\ b, 'abc' - \"d\"\n option 'a \\'b\\'', a\\ \\'b\\', \"a \\\\ b\", \"a \\ b\",\n a\\ \\\\ b, a\\ \\\\\\ b, \"'abc' - \\\"d\\\"\";\n\nApplications\n------------\n\nThe ``apps`` block allows for options to run, close, or block applications.\nEach option supports multiple values and can be repeated as multiple option\ndefinitions.\n\nThe ``run`` option supports an arbitrary shell command, an application name, or\nthe path to an executable script. Arguments and shell redirection are also\npossible. This option will be initiated when starting a task.\n\nThe ``close`` option supports an arbitrary shell command, an application name,\nor the path to an executable script. Unlike ``run``, shell redirection is not\nsupported and all arguments provided are considered as part of the\ncommand/application name provided (e.g. \"Google Chrome\" not \"Google\" with\n\"Chrome\" argument). This option will be initiated when starting on a task.\n\nThe ``block`` option behaves exactly like ``close``, except that it runs\ncontinously while the task is active (approximately once a second).\n\nThe ``run`` and ``close`` options also support the \"end_\" prefix which will\ninstead be activated when a task is manually ended.\n\nFor example: ::\n\n apps {\n run /path/to/file; # run app at task start\n close /path/to/file; # close app at task start\n end_run /path/to/file; # run app at task end (manual)\n end_close /path/to/file; # close app at task end (manual)\n\n # See Task Timer below..\n timer_run /path/to/file; # run app at task end (timer elapsed)\n timer_close /path/to/file; # close app at task end (timer elapsed)\n }\n\nTask Timer\n----------\n\nThe ``duration`` option will automatically end the task after the specified\nnumber of minutes. This option supports only a single value > 0 and the\noption cannot be defined more than once.\n\nThis also enables the ``left`` command when running the ``focus`` program to\nview remaining task time.\n\nAdditionally, any options that support the \"end_\" prefix will also support\nthe \"timer_\" prefix. They function similar to \"end_\" prefixed options, except\nthey are only activated after the task timer has elapsed.\n\nFor example: ::\n\n apps {\n timer_run /path/to/file; # run app at task end (timer elapsed)\n timer_close /path/to/file; # close app at task end (timer elapsed)\n }\n\nBlocking Websites\n-----------------\n\nThe ``block`` option under the ``sites`` block allows for blocking website\ndomains while the task is active. Each option supports one or more domain\nvalues. The option may be redefined multiple times.\n\nFor example: ::\n\n sites {\n block google.com, twitter.com;\n block youtube.com, \"othersite.com\";\n }\n\nUnder the hood, Focus updates the system HOSTS file (/etc/hosts) with mappings\nof the provided domains to the local machine. Because of this, you will have to\nprovide an entry for each relevant subdomain as well if necessary. As a result,\nthis strategy won't scale when blocking a site with numerous subdomains.\nPerhaps, another solution like a local DNS server would be more appropriate\n(e.g. `dnsmasq `_).\n\nAs a convenience, any domains configured will also map the following\nsubdomains: ``m``, ``www``, ``mobile``.\n\nFor example::\n\n google.com => google.com, www.google.com, m.google.com, mobile.google.com\n\nPlaying Sounds\n--------------\n\nThe ``play`` options for the ``sounds`` block support the path to a sound file\nthat is playable on your system via available external binaries (``mpg123``,\n``play``, and ``aplay`` [WAV only]). Only a single value is supported for each\noption, and each type of option cannot be defined more than once. Make sure\nyour preferred binary is installed and works correctly by manually running your\nsound file through the program.\n\nFor example: ::\n\n sounds {\n play /path/to/file; # play sound file at task start\n end_play /path/to/file; # play sound file at task end (manual)\n timer_play /path/to/file; # play sound file at task end (timer elapsed)\n }\n\nNotifications\n-------------\n\nThe ``show`` options for the ``notify`` block support a single message that\nwill be shown as a system notification. Only a single value is supported for\neach option, and each type of option cannot be defined more than once.\n\nOn Linux/Unix, the feature functions via the DBUS IPC bus. On Mac OSX, external\nbinaries (``terminal-notifier`` and ``growlnotify``) will be used when\navailable; otherwise, a fallback alert dialog will be shown. If using Mac OSX,\nmake sure your preferred binary is installed and works correctly, unless the\nfallback method is desired.\n\nFor example: ::\n\n notify {\n show \"message here\"; # notify at task start\n end_show \"message here\"; # notify at task end (manual)\n timer_show \"message here\"; # notify at task end (timer elapsed)\n }\n\nUpdating IM Status\n------------------\n\nThe ``im`` block allows for options to update the status information for\na number of running instant messenger applications.\n\nThe ``status_msg`` option supports defining a name that can be referenced when\nspecifying the ``status``, ``end_status`` and ``timer_status`` options. The\noption takes two arguments: the first being the identifier name, and the second,\nthe value for the status message. The option can be defined more than once to\ndefine multiple status messages to use.\n\nFor example: ::\n\n im {\n status_msg message_name, value;\n status_msg brb, brb;\n status_msg brb2, be\\ right\\ back;\n status_msg omg, \"oh em gee\";\n status_msg working, \"definitely busy here..\";\n }\n\nThe ``status`` option is activated at the start of a task, and it accepts\neither the new status, or both the new status and new status message as\narguments.\n\nFor the status argument, the following values are available: ::\n\n 'online' - Online/Available\n 'away' - Away\n 'long_away' - Extended Away\n 'busy' - Busy\n 'hidden' - Hidden/Invisible\n\nFor the optional message argument, a string value may be provided. To reference\nan existing ``status_msg`` option definition, simply provide the ``status_msg``\nname prefixed with \":\" (e.g. :working, :brb, :omg). The ``status`` option also\nsupports the \"end_\" and \"timer_\" prefixes which will instead be activated when\na task is manually ended or after the timer elapses, respectively.\n\nFor example: ::\n\n im {\n status_msg working, \"definitely busy here...\";\n status busy, :working; # change status at task start\n\n #status away;\n #status busy, really\\ busy;\n #status busy, \"don't bother\";\n end_status online; # change status at task end (manual)\n timer_status online; # change status at task end (timer elapsed)\n\n status_msg play, \"reading some twitters\";\n #status away, :play;\n }\n\nPlugin System\n=============\n\nFocus provides a simple and flexible plugin system to extend the core\nfunctionality. In fact, plugins are used internally for everything.\n\nInstalling Plugins\n------------------\n\nAfter running the ``focus`` command, the ``.focus`` directory is created in\nyour home directory ($HOME or ~). Under that lives a ``plugins`` subdirectory,\nwhere you can drop your .py python plugin files. If they are valid, the plugins\nwill automatically become available when running ``focus``. For command\nplugins, running ``focus`` will print a help banner with the installed\ncommands, which will include your plugins.\n\n*Remember, if the plugin is available only for active tasks, the appropriate\ntask must be active to see your plugin show up.*\n\nCommand Plugins\n---------------\n\nCommand plugins define the commands that are available for the Focus binary\n(e.g. ``on``, ``make``, etc.). These can be available always, only for tasks\nthat define certain options, or only for active tasks.\n\nThe ``command`` class attribute identifies the plugin as a command plugin and\nspecifies the actual command name to register with the plugin.\n\n*Note: The command name should be unique.*\n\nThe plugin should define the ``execute()`` method for running the command. The\n``env`` argument represents the environment and the ``args`` argument is the\nresult of parsing the command-line arguments using the ``ArgumentParser``\nobject.\n\n**Method Definition:** ::\n\n def execute(self, env, args):\n env.io.write('Verbose: {0}'.format(args.verbose))\n\nTo simply print an error message, use the ``env.io.error()`` method. If you\nneed to also return a specific error code along with printing an error message\nraise a ``FocusError`` exception from the ``focus.errors`` module: ::\n\n from focus.errors import FocusError\n\n def execute(self, env, args):\n # env.io.error('Oh noes!') # just prints and returns exit code 0\n raise FocusError('message here', code=123)\n\nIf the plugin needs to define any command-line arguments, it should define the\n``setup_parser()`` method. The ``parser`` argument is an instance of\n``argparse.ArgumentParser`` and should be updated as necessary to add\narguments.\n\n**Method Definition:** ::\n\n def setup_parser(self, parser):\n parser.add_argument('-v', '--verbose', action='store_true')\n\n**Plugin Example:** ::\n\n from focus.plugin import Plugin\n\n class Foo(Plugin):\n \"\"\" Description of plugin, used when generating help message.\n \"\"\"\n name = \"FooPlugin\" # Name of plugin, must be unique\n version = \"1.0\" # Plugin version\n target_version = \">=0.1\" # Target Focus version, (<, <=, ==, >=, >)\n command = \"bar\" # Command name\n\n def setup_parser(self, parser):\n parser.add_argument('-v', '--verbose', action='store_true')\n\n def execute(self, env, args):\n env.io.write('Verbose: {0}'.format(args.verbose))\n #env.io.error('Oh noes!')\n #env.io.success('Woot')\n\n # resp = env.io.prompt('Are you distracted? (y/n)')\n # stdin_data = env.io.read()\n\nTask Event Plugins\n------------------\n\nTask event plugins are only available for active tasks. They can be registered\nto run at the start of the task, during the task loop (every second), at the\nend of a task, or some combination therein. These plugins will be run within a\ndaemon process when the task starts.\n\nThe ``events`` class attribute identifies the plugin as a task event plugin and\nspecifies the events of the task that should be registered: ``task_start``,\n``task_run``, ``task_end``.\n\nThe plugin should define the ``on_taskstart()``, ``on_taskrun()``, or\n``on_taskend()`` methods corresponding to the values provided for the\n``events`` attribute. The ``task`` argument represents the active task, which\nincludes ``name``, ``duration`` (minutes), and a few methods such as\n``start()`` and ``stop()``.\n\n**Method Definition:** ::\n\n def on_taskstart(self, task):\n pass\n\n**Plugin Example:** ::\n\n from focus.plugin import Plugin\n\n class Foo(Plugin):\n \"\"\" Description of plugin.\n \"\"\"\n name = \"FooPlugin\" # Name of plugin, must be unique\n version = \"1.0\" # Plugin version\n target_version = \">=0.1\" # Target Focus version, (<, <=, ==, >=, >)\n events = ['task_start', 'task_run', 'task_end']\n\n def on_taskstart(self, task):\n pass\n\n def on_taskrun(self, task):\n pass\n\n def on_taskend(self, task):\n pass\n\nPlugin Options\n--------------\n\nTwo attributes exist to allow plugins to only be loaded for active tasks:\n\n1. **options**\n\n Set the ``options`` class attribute. This defines the options that, if\n provided in a task configuration file, will trigger the load of this plugin.\n Options are either non-block (e.g. ``duration``) or block\n (e.g. ``apps`` => { ``run``, ``close``, ``block`` }, ``sites`` =>\n { ``block`` }, etc.). When this attribute is set, the plugin should define\n the ``parse_option()`` method in order to parse the values set in a task\n configuration file. See example below.\n\n *Note: these options should be unique.*\n\n **Plugin Snippet:** ::\n\n from focus.plugin import Plugin\n\n class Foo(Plugin):\n ...\n options = [\n # duration (non-block option)\n {\n 'name': 'duration',\n 'allow_duplicates': False # disallow duplicate definitions\n },\n\n # apps.run, apps.close (block options)\n {\n 'block': 'apps',\n 'options': [\n {\n 'name': 'run',\n 'allow_duplicates': True # the default\n },\n { 'name': 'close' }\n ]\n }\n ]\n\n **Task Configuration Example:** ::\n\n task {\n duration 30;\n\n apps {\n run firefox, chromium, /path/to/file, /path/to/other\\ file;\n run \"/path/to/file arg1 arg2\", helloworld\\ -a\\ b;\n close adium;\n }\n }\n\n **Method Definition:** ::\n\n def parse_option(self, option, block_name, *values):\n # raise ValueError exception with a message to reject the provided\n # value. this will propagate up to the cli when loading a task\n\n Here, the ``option`` and ``block_name`` names for the currently parsed\n option are provided. ``block_name`` will be ``None`` when parsing non-block\n options. ``values`` holds one or more values associated with the provided\n option.\n\n2. **task_only**\n\n Set the ``task_only`` class attribute, so the plugin will be available for\n any task once started.\n\n **Plugin Snippet:** ::\n\n class Foo(Plugin):\n ...\n task_only = True\n ...\n\nRoot Access\n-----------\n\nIf a plugin needs root access, it should define the ``needs_root`` attribute.\nWhen set, this installs a ``run_root()`` method on the plugin class, which\naccepts an arbitrary command string and returns a boolean for success or\nfailure. Internally, Focus uses the ``sudo`` command to temporarily escalate\nprivileges.\n\n**Plugin Snippet:** ::\n\n from focus.plugin import Plugin\n\n class Foo(Plugin):\n ...\n command = 'foo'\n events = ['task_start']\n needs_root = True\n \n def execute(self, env, args):\n self.run_root('whoami >> /tmp/whoami_focus.log')\n\n def on_taskstart(self, task):\n self.run_root('whoami >> /tmp/whoami_focus2.log')", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/xtrementl/focus", "keywords": "focus", "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "focus", "package_url": "https://pypi.org/project/focus/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/focus/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/xtrementl/focus" }, "release_url": "https://pypi.org/project/focus/0.1.3/", "requires_dist": null, "requires_python": null, "summary": "Command-line productivity tool for improved task workflows.", "version": "0.1.3" }, "last_serial": 792096, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "98f09f099a7c634fbd1e3bdab6b6868e", "sha256": "50ecbf4c05e98b641940ef9cecfa49cb481f93c9b2a474848b068bfbe5fe4c02" }, "downloads": -1, "filename": "focus-0.1.0.tar.gz", "has_sig": false, "md5_digest": "98f09f099a7c634fbd1e3bdab6b6868e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 69608, "upload_time": "2012-06-22T09:29:43", "url": "https://files.pythonhosted.org/packages/16/c9/0d19ef4360a76589ee2d5cb7290dda484166a679a796ec647683ec242e2c/focus-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "a2c7e07d6311d7e1002318b7d0899ee8", "sha256": "eef4979a51ed39637dc19486247f616dcd4ab1be94351d28a2e4cf22eb8ed1e2" }, "downloads": -1, "filename": "focus-0.1.1.tar.gz", "has_sig": false, "md5_digest": "a2c7e07d6311d7e1002318b7d0899ee8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 77563, "upload_time": "2012-09-04T05:41:24", "url": "https://files.pythonhosted.org/packages/19/58/e69e6ef47e1c1bd2107f37a23651efbab373a7e3703993f82885efbca715/focus-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "621902d2ff6f48b695b4f56fe5ada80b", "sha256": "b4a6980c5522a719e07bb1c743368d03e1606b49c191f42f7c88b20c40cc5637" }, "downloads": -1, "filename": "focus-0.1.2.tar.gz", "has_sig": false, "md5_digest": "621902d2ff6f48b695b4f56fe5ada80b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 77620, "upload_time": "2012-09-04T16:26:01", "url": "https://files.pythonhosted.org/packages/cc/d0/34e17e311ae229e721d2e1b558df45e69a087351f88c465fa4b42ae6f086/focus-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "6628f0c7fd8a748cab3696523b4c0061", "sha256": "ccee1d881b2bb3c03b8594a90503df2d4224034ace5425a3062074639e91afd4" }, "downloads": -1, "filename": "focus-0.1.3.tar.gz", "has_sig": false, "md5_digest": "6628f0c7fd8a748cab3696523b4c0061", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 82833, "upload_time": "2012-11-23T04:39:26", "url": "https://files.pythonhosted.org/packages/9c/e8/01b6cbcf881e49cee9bb9ffcdf12e06188782535b364f39a8e11f2fda2c3/focus-0.1.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "6628f0c7fd8a748cab3696523b4c0061", "sha256": "ccee1d881b2bb3c03b8594a90503df2d4224034ace5425a3062074639e91afd4" }, "downloads": -1, "filename": "focus-0.1.3.tar.gz", "has_sig": false, "md5_digest": "6628f0c7fd8a748cab3696523b4c0061", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 82833, "upload_time": "2012-11-23T04:39:26", "url": "https://files.pythonhosted.org/packages/9c/e8/01b6cbcf881e49cee9bb9ffcdf12e06188782535b364f39a8e11f2fda2c3/focus-0.1.3.tar.gz" } ] }