view taginthemiddle/model.py @ 19:57ca873ed9bf default tip

make this a pluggable system and start reorging infrastructure for that
author Jeff Hammel <jhammel@mozilla.com>
date Tue, 25 May 2010 07:48:53 -0700
parents c85d42296c06
children
line wrap: on
line source

"""
Tags models. Tags have:
 - a list of resources they're applied to
 - a time they're applied
 - someone that tagged the resource
"""

import os
import time
from pkg_resources import iter_entry_points

### interface

class Tags(object):
  """
  abstract base class for tagging
  """

  def add(self, tag, url, author):
    """add a tag to a URL"""
    raise NotImplementedError

  def remove(self, tag, url):
    """remove a tag from a URL"""
    raise NotImplementedError

  def tags(self, url):
    """
    get the tags for a URL
    """

  def urls(self, *tags):
    """
    get the URLs for a set of tags
    """

def make_tags(string):
  """
  Instantiate and return a tag engine from a setuptools entry point
  - string: "URL" of tagger (e.g. 'file:///path/to/file?author=whoami')
  """

  # have to split out the schema ourselves or urlparse is too smart for
  # its own good
  assert '://' in string # XXX could also not have this for no parameters
  name, value = string.split('://', 1)

  import pdb; pdb.set_trace()

### implementation

class FileTags(Tags):
  """
  file (e.g. .ini) based tagging scheme

  File format:
  foo = /bar:1273023556 /fleem/baz:1273023556 etc
  cats = /cats:1273023556 /blog/mycat:1273023556
  """
  # XXX TODO: store user;  currently this is not stored

  def __init__(self, path, author):
    """
    - path: path to file
    - author: who tagged the resource (fudge for now)
    """
    self.path = path
    if not os.path.exists(path):
      f = file(path, 'w')
      f.close()
    self._tags = {}
    self._urls = {}
    self.times = {}
    self.read()

  def read(self):
    for line in file(self.path).readlines():
      line = line.strip()
      if not line:
        continue
      tag, urls = line.split('=', 1) # asserts '=' in line
      tag = tag.strip()
      urls = urls.strip()
      self._tags[tag] = set([urls])
      for url in urls:
        url, time = url.rsplit(':', 1)
        self._urls.setdefault(url, set()).add(tag)
        self.times[(tag, url)] = int(time)

  def write(self):
    f = file(self.path, 'w')
    for tag in sorted(self.tags.keys()):
      print >> f, '%s = %s' % (tag, ' '.join(['%s:%s' % (url, self.times(tag, url))
                                              for url in self.tags[tag]]))
    f.close()

  ### implementation of Tags interface

  def add(self, tag, url, author):
    if url in self._tags[tag]:
      return
    self._tags[tag].add(url)
    self._urls[url].add(tag)
    self.times[(tag, url)] = int(time.time())
    self.write()

  def remove(self, tag, url):
    if url not in self._tags[tag]:
      return
    self._tags[tag].remove(url)
    self._urls[url].remove(tag)
    del self.times[(tag, url)]
    self.write()

  def tags(self, url):
    raise NotImplementedError

  def urls(self, *tags):
    raise NotImplementedError

class SQLiteTags(Tags):
  """
  Tags model using SQLite

  Tags are relational data stored in a table
  Tag | URL | Author | Date [seconds since epoch]
  """

  def __init__(self, path):
    """
    - path: path to SQLite file
    """

  def add(self, tag, url, author):
    raise NotImplementedError

  def remove(self, tag, url):
    raise NotImplementedError

  def tags(self, url):
    """
    select * from tags where url='url'
    """

  def urls(self, *tags):
    """
    select * from tags where tag=''
    """

### command line

if __name__ == '__main__':
  foo = make_tags('file:///tmp/foo.tags?author=bar')