Mercurial > ift6266
comparison data_generation/transformations/pycaptcha/Captcha/Base.py @ 167:1f5937e9e530
More moves - transformations into data_generation, added "deep" folder
author | Dumitru Erhan <dumitru.erhan@gmail.com> |
---|---|
date | Fri, 26 Feb 2010 14:15:38 -0500 |
parents | pycaptcha/Captcha/Base.py@4775b4195b4b |
children |
comparison
equal
deleted
inserted
replaced
166:17ae5a1a4dd1 | 167:1f5937e9e530 |
---|---|
1 """ Captcha.Base | |
2 | |
3 Base class for all types of CAPTCHA tests. All tests have one or | |
4 more solution, determined when the test is generated. Solutions | |
5 can be any python object, | |
6 | |
7 All tests can be solved by presenting at least some preset number | |
8 of correct solutions. Some tests may only have one solution and require | |
9 one solution, but other tests may require N correct solutions of M | |
10 possible solutions. | |
11 """ | |
12 # | |
13 # PyCAPTCHA Package | |
14 # Copyright (C) 2004 Micah Dowty <micah@navi.cx> | |
15 # | |
16 | |
17 import random, string, time, shelve | |
18 | |
19 __all__ = ["BaseCaptcha", "Factory", "PersistentFactory"] | |
20 | |
21 | |
22 def randomIdentifier(alphabet = string.ascii_letters + string.digits, | |
23 length = 24): | |
24 return "".join([random.choice(alphabet) for i in xrange(length)]) | |
25 | |
26 | |
27 class BaseCaptcha(object): | |
28 """Base class for all CAPTCHA tests""" | |
29 # Subclasses can override these to set the solution criteria | |
30 minCorrectSolutions = 1 | |
31 maxIncorrectSolutions = 0 | |
32 | |
33 def __init__(self): | |
34 self.solutions = [] | |
35 self.valid = True | |
36 | |
37 # Each test has a unique identifier, used to refer to that test | |
38 # later, and a creation time so it can expire later. | |
39 self.id = randomIdentifier() | |
40 self.creationTime = time.time() | |
41 | |
42 def addSolution(self, solution): | |
43 self.solutions.append(solution) | |
44 | |
45 def testSolutions(self, solutions): | |
46 """Test whether the given solutions are sufficient for this CAPTCHA. | |
47 A given CAPTCHA can only be tested once, after that it is invalid | |
48 and always returns False. This makes random guessing much less effective. | |
49 """ | |
50 if not self.valid: | |
51 return False | |
52 self.valid = False | |
53 | |
54 numCorrect = 0 | |
55 numIncorrect = 0 | |
56 | |
57 for solution in solutions: | |
58 if solution in self.solutions: | |
59 numCorrect += 1 | |
60 else: | |
61 numIncorrect += 1 | |
62 | |
63 return numCorrect >= self.minCorrectSolutions and \ | |
64 numIncorrect <= self.maxIncorrectSolutions | |
65 | |
66 | |
67 class Factory(object): | |
68 """Creates BaseCaptcha instances on demand, and tests solutions. | |
69 CAPTCHAs expire after a given amount of time, given in seconds. | |
70 The default is 15 minutes. | |
71 """ | |
72 def __init__(self, lifetime=60*15): | |
73 self.lifetime = lifetime | |
74 self.storedInstances = {} | |
75 | |
76 def new(self, cls, *args, **kwargs): | |
77 """Create a new instance of our assigned BaseCaptcha subclass, passing | |
78 it any extra arguments we're given. This stores the result for | |
79 later testing. | |
80 """ | |
81 self.clean() | |
82 inst = cls(*args, **kwargs) | |
83 self.storedInstances[inst.id] = inst | |
84 return inst | |
85 | |
86 def get(self, id): | |
87 """Retrieve the CAPTCHA with the given ID. If it's expired already, | |
88 this will return None. A typical web application will need to | |
89 new() a CAPTCHA when generating an html page, then get() it later | |
90 when its images or sounds must be rendered. | |
91 """ | |
92 return self.storedInstances.get(id) | |
93 | |
94 def clean(self): | |
95 """Removed expired tests""" | |
96 expiredIds = [] | |
97 now = time.time() | |
98 for inst in self.storedInstances.itervalues(): | |
99 if inst.creationTime + self.lifetime < now: | |
100 expiredIds.append(inst.id) | |
101 for id in expiredIds: | |
102 del self.storedInstances[id] | |
103 | |
104 def test(self, id, solutions): | |
105 """Test the given list of solutions against the BaseCaptcha instance | |
106 created earlier with the given id. Returns True if the test passed, | |
107 False on failure. In either case, the test is invalidated. Returns | |
108 False in the case of an invalid id. | |
109 """ | |
110 self.clean() | |
111 inst = self.storedInstances.get(id) | |
112 if not inst: | |
113 return False | |
114 result = inst.testSolutions(solutions) | |
115 return result | |
116 | |
117 | |
118 class PersistentFactory(Factory): | |
119 """A simple persistent factory, for use in CGI or multi-process environments | |
120 where the state must remain across python interpreter sessions. | |
121 This implementation uses the 'shelve' module. | |
122 """ | |
123 def __init__(self, filename, lifetime=60*15): | |
124 Factory.__init__(self, lifetime) | |
125 self.storedInstances = shelve.open(filename) | |
126 | |
127 ### The End ### |