summaryrefslogtreecommitdiff
path: root/Params/__init__.py
blob: 60a0b586b6ced71ac419301aaa045d327dedb5a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import re
import os
import time
import sys
import urllib, urllib2
from subprocess import Popen, PIPE
Request = urllib2.Request
urlencode = urllib.urlencode
urlopen = urllib2.urlopen

from Config import WORKING_DIR, MAX_SIZE, \
  SPECIAL_DOWNLOADERS, SPECIAL_DOWNLOADERS_MAX_SIZE, \
  BIN_IDENTIFY

class BadParamError(Exception):
  pass

class Params(object):
    def __init__(self, classname="", **kwargs):
      self._working_dir = WORKING_DIR
      self._now = kwargs.get("now", str(int(time.time())));
      self._classname = classname 
      for key, value in kwargs.items():
        setattr(self, key, value)
    
    def __iter__(self):
        for key, value in vars(self).iteritems():
           yield key, value

    def err_warn(self, s, error=None):
      self._error_log(s, error=error);
      raise BadParamError("%s - %s" % (self._classname, s))
   
    def __getattr__(self, key):
      try: 
        return self.__getattribute__(key);
      except AttributeError:
        return None

    def err_fatal(self, s, error=None):
      self._log(s, error, fatal=True);
      sys.exit(1);

    def set_val(self, key, value, value_type=None, enum_values=None):
      try:
        if value_type == "color":
          value = self._color_sanitize(value)
        elif value_type == "float":
          value = float(value)
        elif value_type == "int":
          value = int(value)
        elif value_type == "bool":
          value = self._bool_correct(str(value))
        elif value_type == "string":
          value = self._sanitize(str(value))
        elif value_type == "img_url":
          _filename = self._filename_temporary(key)
          _path = os.path.join(self._working_dir, _filename)
          self._image_download(value, _path)
          _mimetype = self._image_mimetype(_path)
          value = {
            'url': value, 
            'path': _path, 
            'mimetype' : _mimetype
          }
        elif value_type == "enum":
          if value not in enum_values: 
            raise ValueError
        self.__setattr__(key, value) 
      except Exception as e:
        self.err_warn("key: %s value: %s" % (key, value), error=str(e))

    def _sanitize (self, s):
      return re.sub(r'\W+', '', s)

    def _color_sanitize(self, s):
      if s == "":
        return "transparent"
      if re.match('(rgba?\([0-9]+,[0-9]+,[0-9]+\))|([a-zA-Z]+)|(\#[A-Ha-h0-9]+)', s):
        return s.replace(' ', '');
      else:
        sys.stderr.write("Not a color: {}\n".format(s))
        raise ValueError

    def _bool_correct(self, b):
         if type(b) == str:
           if re.match(r'true', b, re.IGNORECASE):
              return True
           elif re.match(r'false', b, re.IGNORECASE):
              return False
         elif type(b) == bool:
           return b
         raise ValueError

    def _filename_temporary(self, s): 
      return "_tmp-{}-{}_{}".format(self._classname, self._now, s)

    def _error_log(self, s, error=None, fatal=False):
      message = "ERROR - BAD PARAM"
      if fatal: message += "- [FATAL] -"
      sys.stderr.write("{}:{} - {}\n".format(message, self._classname, s))
      if error:
        sys.stderr.write("PARAM ERROR: {}\n".format(str(error)))

    def _image_download(self, url, path):
      max_size = MAX_SIZE
      if self.username in SPECIAL_DOWNLOADERS:
        max_size = SPECIAL_DOWNLOADERS_MAX_SIZE
      try: 
        self._download(url, path, max_size=max_size)
      except Exception as e:
        self.err_warn("Download failed");

    def _browser_request (self, url, data=None):
        headers = {
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
            'Accept': '*/*',
        }
        try:
            req = Request(url, data, headers)
            response = urlopen(req)
        except IOError as e:
            if hasattr(e, 'code'):
                sys.stderr.write( 'browser request error: %s - ERROR %s' % (url, e.code) )
            raise IOError
        return response

    def _download(self, url, destination, max_size=MAX_SIZE):
        response = self._browser_request(url, None)

        rawimg = response.read()
        if len(rawimg) == 0:
            self.err_warn("got zero-length file")
        if len(rawimg) > max_size:
            self.err_warn("file too big: max size {} KB / {} is {} KB".format(
                str(MAX_SIZE/1024), 
                destination, 
                str(len(rawimg)/1024)
                )
            )    
        f = open(destination, "w")
        f.write(rawimg)
        f.close()

    def _image_mimetype(self, f):
        try: 
            mimetype =  Popen(
                [BIN_IDENTIFY, f], stdout=PIPE
            ).communicate()[0].split(" ")[1].lower()
            return mimetype
        except Exception as e:
            sys.stderr.write("couldn't determine mimetype\n")
            raise e;