diff options
author | Six <unknown> | 2010-04-10 17:05:55 -0400 |
---|---|---|
committer | Six <unknown> | 2010-04-10 17:05:55 -0400 |
commit | 418bb176021361f539fe5de13c6af0b316d8e4be (patch) | |
tree | bf2eb2bda93c523f739b7592d4d6bfd138e6641f | |
download | dodai-macsupport-418bb176021361f539fe5de13c6af0b316d8e4be.tar.bz2 dodai-macsupport-418bb176021361f539fe5de13c6af0b316d8e4be.tar.xz dodai-macsupport-418bb176021361f539fe5de13c6af0b316d8e4be.zip |
Initial import of source.
31 files changed, 3022 insertions, 0 deletions
diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..3b3ba75 --- /dev/null +++ b/.hgignore | |||
@@ -0,0 +1,4 @@ | |||
1 | syntax: glob | ||
2 | *.pyc | ||
3 | *~ | ||
4 | *.kpf | ||
@@ -0,0 +1,570 @@ | |||
1 | GNU General Public License version 3 (GPLv3) | ||
2 | |||
3 | GNU GENERAL PUBLIC LICENSE | ||
4 | |||
5 | Version 3, 29 June 2007 | ||
6 | |||
7 | Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | ||
8 | |||
9 | Everyone is permitted to copy and distribute verbatim copies of this license | ||
10 | document, but changing it is not allowed. | ||
11 | |||
12 | Preamble | ||
13 | |||
14 | The GNU General Public License is a free, copyleft license for software and | ||
15 | other kinds of works. | ||
16 | |||
17 | The licenses for most software and other practical works are designed to take | ||
18 | away your freedom to share and change the works. By contrast, the GNU General | ||
19 | Public License is intended to guarantee your freedom to share and change all | ||
20 | versions of a program--to make sure it remains free software for all its users. | ||
21 | We, the Free Software Foundation, use the GNU General Public License for most | ||
22 | of our software; it applies also to any other work released this way by its | ||
23 | authors. You can apply it to your programs, too. | ||
24 | |||
25 | When we speak of free software, we are referring to freedom, not price. Our | ||
26 | General Public Licenses are designed to make sure that you have the freedom to | ||
27 | distribute copies of free software (and charge for them if you wish), that you | ||
28 | receive source code or can get it if you want it, that you can change the | ||
29 | software or use pieces of it in new free programs, and that you know you can | ||
30 | do these things. | ||
31 | |||
32 | To protect your rights, we need to prevent others from denying you these | ||
33 | rights or asking you to surrender the rights. Therefore, you have certain | ||
34 | responsibilities if you distribute copies of the software, or if you modify it: | ||
35 | responsibilities to respect the freedom of others. | ||
36 | |||
37 | For example, if you distribute copies of such a program, whether gratis or for | ||
38 | a fee, you must pass on to the recipients the same freedoms that you received. | ||
39 | You must make sure that they, too, receive or can get the source code. And you | ||
40 | must show them these terms so they know their rights. | ||
41 | |||
42 | Developers that use the GNU GPL protect your rights with two steps: (1) assert | ||
43 | copyright on the software, and (2) offer you this License giving you legal | ||
44 | permission to copy, distribute and/or modify it. | ||
45 | |||
46 | For the developers' and authors' protection, the GPL clearly explains that | ||
47 | there is no warranty for this free software. For both users' and authors' sake, | ||
48 | the GPL requires that modified versions be marked as changed, so that their | ||
49 | problems will not be attributed erroneously to authors of previous versions. | ||
50 | |||
51 | Some devices are designed to deny users access to install or run modified | ||
52 | versions of the software inside them, although the manufacturer can do so. | ||
53 | This is fundamentally incompatible with the aim of protecting users' freedom | ||
54 | to change the software. The systematic pattern of such abuse occurs in the | ||
55 | area of products for individuals to use, which is precisely where it is most | ||
56 | unacceptable. Therefore, we have designed this version of the GPL to prohibit | ||
57 | the practice for those products. If such problems arise substantially in other | ||
58 | domains, we stand ready to extend this provision to those domains in future | ||
59 | versions of the GPL, as needed to protect the freedom of users. | ||
60 | |||
61 | Finally, every program is threatened constantly by software patents. States | ||
62 | should not allow patents to restrict development and use of software on | ||
63 | general-purpose computers, but in those that do, we wish to avoid the special | ||
64 | danger that patents applied to a free program could make it effectively | ||
65 | proprietary. To prevent this, the GPL assures that patents cannot be used to | ||
66 | render the program non-free. | ||
67 | |||
68 | The precise terms and conditions for copying, distribution and modification | ||
69 | follow. | ||
70 | |||
71 | TERMS AND CONDITIONS | ||
72 | 0. Definitions. | ||
73 | |||
74 | “This License” refers to version 3 of the GNU General Public License. | ||
75 | |||
76 | “Copyright” also means copyright-like laws that apply to other kinds of works, | ||
77 | such as semiconductor masks. | ||
78 | |||
79 | “The Program” refers to any copyrightable work licensed under this License. | ||
80 | Each licensee is addressed as “you”. “Licensees” and “recipients” may be | ||
81 | individuals or organizations. | ||
82 | |||
83 | To “modify” a work means to copy from or adapt all or part of the work in a | ||
84 | fashion requiring copyright permission, other than the making of an exact copy. | ||
85 | The resulting work is called a “modified version” of the earlier work or a work | ||
86 | “based on” the earlier work. | ||
87 | |||
88 | A “covered work” means either the unmodified Program or a work based on the | ||
89 | Program. | ||
90 | |||
91 | To “propagate” a work means to do anything with it that, without permission, | ||
92 | would make you directly or secondarily liable for infringement under applicable | ||
93 | copyright law, except executing it on a computer or modifying a private copy. | ||
94 | Propagation includes copying, distribution (with or without modification), | ||
95 | making available to the public, and in some countries other activities as well. | ||
96 | |||
97 | To “convey” a work means any kind of propagation that enables other parties to | ||
98 | make or receive copies. Mere interaction with a user through a computer | ||
99 | network, with no transfer of a copy, is not conveying. | ||
100 | |||
101 | An interactive user interface displays “Appropriate Legal Notices” to the | ||
102 | extent that it includes a convenient and prominently visible feature that (1) | ||
103 | displays an appropriate copyright notice, and (2) tells the user that there is | ||
104 | no warranty for the work (except to the extent that warranties are provided), | ||
105 | that licensees may convey the work under this License, and how to view a copy | ||
106 | of this License. If the interface presents a list of user commands or options, | ||
107 | such as a menu, a prominent item in the list meets this criterion. | ||
108 | |||
109 | 1. Source Code. | ||
110 | |||
111 | The “source code” for a work means the preferred form of the work for making | ||
112 | modifications to it. “Object code” means any non-source form of a work. | ||
113 | |||
114 | A “Standard Interface” means an interface that either is an official standard | ||
115 | defined by a recognized standards body, or, in the case of interfaces specified | ||
116 | for a particular programming language, one that is widely used among developers | ||
117 | working in that language. | ||
118 | |||
119 | The “System Libraries” of an executable work include anything, other than the | ||
120 | work as a whole, that (a) is included in the normal form of packaging a Major | ||
121 | Component, but which is not part of that Major Component, and (b) serves only | ||
122 | to enable use of the work with that Major Component, or to implement a Standard | ||
123 | Interface for which an implementation is available to the public in source code | ||
124 | form. A “Major Component”, in this context, means a major essential component | ||
125 | (kernel, window system, and so on) of the specific operating system (if any) on | ||
126 | which the executable work runs, or a compiler used to produce the work, or an | ||
127 | object code interpreter used to run it. | ||
128 | |||
129 | The “Corresponding Source” for a work in object code form means all the source | ||
130 | code needed to generate, install, and (for an executable work) run the object | ||
131 | code and to modify the work, including scripts to control those activities. | ||
132 | However, it does not include the work's System Libraries, or general-purpose | ||
133 | tools or generally available free programs which are used unmodified in | ||
134 | performing those activities but which are not part of the work. For example, | ||
135 | Corresponding Source includes interface definition files associated with source | ||
136 | files for the work, and the source code for shared libraries and dynamically | ||
137 | linked subprograms that the work is specifically designed to require, such as | ||
138 | by intimate data communication or control flow between those subprograms and | ||
139 | other parts of the work. | ||
140 | |||
141 | The Corresponding Source need not include anything that users can regenerate | ||
142 | automatically from other parts of the Corresponding Source. | ||
143 | |||
144 | The Corresponding Source for a work in source code form is that same work. | ||
145 | |||
146 | 2. Basic Permissions. | ||
147 | |||
148 | All rights granted under this License are granted for the term of copyright on | ||
149 | the Program, and are irrevocable provided the stated conditions are met. This | ||
150 | License explicitly affirms your unlimited permission to run the unmodified | ||
151 | Program. The output from running a covered work is covered by this License only | ||
152 | if the output, given its content, constitutes a covered work. This License | ||
153 | acknowledges your rights of fair use or other equivalent, as provided by | ||
154 | copyright law. | ||
155 | |||
156 | You may make, run and propagate covered works that you do not convey, without | ||
157 | conditions so long as your license otherwise remains in force. You may convey | ||
158 | covered works to others for the sole purpose of having them make modifications | ||
159 | exclusively for you, or provide you with facilities for running those works, | ||
160 | provided that you comply with the terms of this License in conveying all | ||
161 | material for which you do not control copyright. Those thus making or running | ||
162 | the covered works for you must do so exclusively on your behalf, under your | ||
163 | direction and control, on terms that prohibit them from making any copies of | ||
164 | your copyrighted material outside their relationship with you. | ||
165 | |||
166 | Conveying under any other circumstances is permitted solely under the | ||
167 | conditions stated below. Sublicensing is not allowed; section 10 makes it | ||
168 | unnecessary. | ||
169 | |||
170 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | ||
171 | |||
172 | No covered work shall be deemed part of an effective technological measure | ||
173 | under any applicable law fulfilling obligations under article 11 of the WIPO | ||
174 | copyright treaty adopted on 20 December 1996, or similar laws prohibiting or | ||
175 | restricting circumvention of such measures. | ||
176 | |||
177 | When you convey a covered work, you waive any legal power to forbid | ||
178 | circumvention of technological measures to the extent such circumvention is | ||
179 | effected by exercising rights under this License with respect to the covered | ||
180 | work, and you disclaim any intention to limit operation or modification of the | ||
181 | work as a means of enforcing, against the work's users, your or third parties' | ||
182 | legal rights to forbid circumvention of technological measures. | ||
183 | |||
184 | 4. Conveying Verbatim Copies. | ||
185 | |||
186 | You may convey verbatim copies of the Program's source code as you receive it, | ||
187 | in any medium, provided that you conspicuously and appropriately publish on | ||
188 | each copy an appropriate copyright notice; keep intact all notices stating that | ||
189 | this License and any non-permissive terms added in accord with section 7 apply | ||
190 | to the code; keep intact all notices of the absence of any warranty; and give | ||
191 | all recipients a copy of this License along with the Program. | ||
192 | |||
193 | You may charge any price or no price for each copy that you convey, and you may | ||
194 | offer support or warranty protection for a fee. | ||
195 | |||
196 | 5. Conveying Modified Source Versions. | ||
197 | |||
198 | You may convey a work based on the Program, or the modifications to produce it | ||
199 | from the Program, in the form of source code under the terms of section 4, | ||
200 | provided that you also meet all of these conditions: | ||
201 | |||
202 | * a) The work must carry prominent notices stating that you modified it, | ||
203 | and giving a relevant date. | ||
204 | * b) The work must carry prominent notices stating that it is released | ||
205 | under this License and any conditions added under section 7. This | ||
206 | requirement modifies the requirement in section 4 to “keep intact all | ||
207 | notices”. | ||
208 | * c) You must license the entire work, as a whole, under this License to | ||
209 | anyone who comes into possession of a copy. This License will | ||
210 | therefore apply, along with any applicable section 7 additional terms, | ||
211 | to the whole of the work, and all its parts, regardless of how they | ||
212 | are packaged. This License gives no permission to license the work in | ||
213 | any other way, but it does not invalidate such permission if you have | ||
214 | separately received it. | ||
215 | * d) If the work has interactive user interfaces, each must display | ||
216 | Appropriate Legal Notices; however, if the Program has interactive | ||
217 | interfaces that do not display Appropriate Legal Notices, your work | ||
218 | need not make them do so. | ||
219 | |||
220 | A compilation of a covered work with other separate and independent works, | ||
221 | which are not by their nature extensions of the covered work, and which are not | ||
222 | combined with it such as to form a larger program, in or on a volume of a | ||
223 | storage or distribution medium, is called an “aggregate” if the compilation and | ||
224 | its resulting copyright are not used to limit the access or legal rights of the | ||
225 | compilation's users beyond what the individual works permit. Inclusion of a | ||
226 | covered work in an aggregate does not cause this License to apply to the other | ||
227 | parts of the aggregate. | ||
228 | |||
229 | 6. Conveying Non-Source Forms. | ||
230 | |||
231 | You may convey a covered work in object code form under the terms of sections | ||
232 | 4 and 5, provided that you also convey the machine-readable Corresponding | ||
233 | Source under the terms of this License, in one of these ways: | ||
234 | |||
235 | * a) Convey the object code in, or embodied in, a physical product | ||
236 | (including a physical distribution medium), accompanied by the | ||
237 | Corresponding Source fixed on a durable physical medium customarily | ||
238 | used for software interchange. | ||
239 | * b) Convey the object code in, or embodied in, a physical product | ||
240 | (including a physical distribution medium), accompanied by a written | ||
241 | offer, valid for at least three years and valid for as long as you | ||
242 | offer spare parts or customer support for that product model, to give | ||
243 | anyone who possesses the object code either (1) a copy of the | ||
244 | Corresponding Source for all the software in the product that is | ||
245 | covered by this License, on a durable physical medium customarily used | ||
246 | for software interchange, for a price no more than your reasonable | ||
247 | cost of physically performing this conveying of source, or (2) access | ||
248 | to copy the Corresponding Source from a network server at no charge. | ||
249 | * c) Convey individual copies of the object code with a copy of the written | ||
250 | offer to provide the Corresponding Source. This alternative is allowed | ||
251 | only occasionally and noncommercially, and only if you received the | ||
252 | object code with such an offer, in accord with subsection 6b. | ||
253 | * d) Convey the object code by offering access from a designated place | ||
254 | (gratis or for a charge), and offer equivalent access to the | ||
255 | Corresponding Source in the same way through the same place at no | ||
256 | further charge. You need not require recipients to copy the | ||
257 | Corresponding Source along with the object code. If the place to copy | ||
258 | the object code is a network server, the Corresponding Source may be | ||
259 | on a different server (operated by you or a third party) that supports | ||
260 | equivalent copying facilities, provided you maintain clear directions | ||
261 | next to the object code saying where to find the Corresponding Source. | ||
262 | Regardless of what server hosts the Corresponding Source, you remain | ||
263 | obligated to ensure that it is available for as long as needed to | ||
264 | satisfy these requirements. | ||
265 | * e) Convey the object code using peer-to-peer transmission, provided you | ||
266 | inform other peers where the object code and Corresponding Source of | ||
267 | the work are being offered to the general public at no charge under | ||
268 | subsection 6d. | ||
269 | |||
270 | A separable portion of the object code, whose source code is excluded from the | ||
271 | Corresponding Source as a System Library, need not be included in conveying the | ||
272 | object code work. | ||
273 | |||
274 | A “User Product” is either (1) a “consumer product”, which means any tangible | ||
275 | personal property which is normally used for personal, family, or household | ||
276 | purposes, or (2) anything designed or sold for incorporation into a dwelling. | ||
277 | In determining whether a product is a consumer product, doubtful cases shall be | ||
278 | resolved in favor of coverage. For a particular product received by a | ||
279 | particular user, “normally used” refers to a typical or common use of that | ||
280 | class of product, regardless of the status of the particular user or of the way | ||
281 | in which the particular user actually uses, or expects or is expected to use, | ||
282 | the product. A product is a consumer product regardless of whether the product | ||
283 | has substantial commercial, industrial or non-consumer uses, unless such uses | ||
284 | represent the only significant mode of use of the product. | ||
285 | |||
286 | “Installation Information” for a User Product means any methods, procedures, | ||
287 | authorization keys, or other information required to install and execute | ||
288 | modified versions of a covered work in that User Product from a modified | ||
289 | version of its Corresponding Source. The information must suffice to ensure | ||
290 | that the continued functioning of the modified object code is in no case | ||
291 | prevented or interfered with solely because modification has been made. | ||
292 | |||
293 | If you convey an object code work under this section in, or with, or | ||
294 | specifically for use in, a User Product, and the conveying occurs as part of a | ||
295 | transaction in which the right of possession and use of the User Product is | ||
296 | transferred to the recipient in perpetuity or for a fixed term (regardless of | ||
297 | how the transaction is characterized), the Corresponding Source conveyed under | ||
298 | this section must be accompanied by the Installation Information. But this | ||
299 | requirement does not apply if neither you nor any third party retains the | ||
300 | ability to install modified object code on the User Product (for example, the | ||
301 | work has been installed in ROM). | ||
302 | |||
303 | The requirement to provide Installation Information does not include a | ||
304 | requirement to continue to provide support service, warranty, or updates for a | ||
305 | work that has been modified or installed by the recipient, or for the User | ||
306 | Product in which it has been modified or installed. Access to a network may be | ||
307 | denied when the modification itself materially and adversely affects the | ||
308 | operation of the network or violates the rules and protocols for communication | ||
309 | across the network. | ||
310 | |||
311 | Corresponding Source conveyed, and Installation Information provided, in accord | ||
312 | with this section must be in a format that is publicly documented (and with an | ||
313 | implementation available to the public in source code form), and must require | ||
314 | no special password or key for unpacking, reading or copying. | ||
315 | |||
316 | 7. Additional Terms. | ||
317 | |||
318 | “Additional permissions” are terms that supplement the terms of this License by | ||
319 | making exceptions from one or more of its conditions. Additional permissions | ||
320 | that are applicable to the entire Program shall be treated as though they were | ||
321 | included in this License, to the extent that they are valid under applicable | ||
322 | law. If additional permissions apply only to part of the Program, that part may | ||
323 | be used separately under those permissions, but the entire Program remains | ||
324 | governed by this License without regard to the additional permissions. | ||
325 | |||
326 | When you convey a copy of a covered work, you may at your option remove any | ||
327 | additional permissions from that copy, or from any part of it. (Additional | ||
328 | permissions may be written to require their own removal in certain cases when | ||
329 | you modify the work.) You may place additional permissions on material, added | ||
330 | by you to a covered work, for which you have or can give appropriate copyright | ||
331 | permission. | ||
332 | |||
333 | Notwithstanding any other provision of this License, for material you add to a | ||
334 | covered work, you may (if authorized by the copyright holders of that material) | ||
335 | supplement the terms of this License with terms: | ||
336 | |||
337 | * a) Disclaiming warranty or limiting liability differently from the terms | ||
338 | of sections 15 and 16 of this License; or | ||
339 | * b) Requiring preservation of specified reasonable legal notices or author | ||
340 | attributions in that material or in the Appropriate Legal Notices | ||
341 | displayed by works containing it; or | ||
342 | * c) Prohibiting misrepresentation of the origin of that material, or | ||
343 | requiring that modified versions of such material be marked in | ||
344 | reasonable ways as different from the original version; or | ||
345 | * d) Limiting the use for publicity purposes of names of licensors or | ||
346 | authors of the material; or | ||
347 | * e) Declining to grant rights under trademark law for use of some trade | ||
348 | names, trademarks, or service marks; or | ||
349 | * f) Requiring indemnification of licensors and authors of that material by | ||
350 | anyone who conveys the material (or modified versions of it) with | ||
351 | contractual assumptions of liability to the recipient, for any | ||
352 | liability that these contractual assumptions directly impose on those | ||
353 | licensors and authors. | ||
354 | |||
355 | All other non-permissive additional terms are considered “further restrictions” | ||
356 | within the meaning of section 10. If the Program as you received it, or any | ||
357 | part of it, contains a notice stating that it is governed by this License along | ||
358 | with a term that is a further restriction, you may remove that term. If a | ||
359 | license document contains a further restriction but permits relicensing or | ||
360 | conveying under this License, you may add to a covered work material governed | ||
361 | by the terms of that license document, provided that the further restriction | ||
362 | does not survive such relicensing or conveying. | ||
363 | |||
364 | If you add terms to a covered work in accord with this section, you must place, | ||
365 | in the relevant source files, a statement of the additional terms that apply to | ||
366 | those files, or a notice indicating where to find the applicable terms. | ||
367 | |||
368 | Additional terms, permissive or non-permissive, may be stated in the form of a | ||
369 | separately written license, or stated as exceptions; the above requirements | ||
370 | apply either way. | ||
371 | |||
372 | 8. Termination. | ||
373 | |||
374 | You may not propagate or modify a covered work except as expressly provided | ||
375 | under this License. Any attempt otherwise to propagate or modify it is void, | ||
376 | and will automatically terminate your rights under this License (including any | ||
377 | patent licenses granted under the third paragraph of section 11). | ||
378 | |||
379 | However, if you cease all violation of this License, then your license from a | ||
380 | particular copyright holder is reinstated (a) provisionally, unless and until | ||
381 | the copyright holder explicitly and finally terminates your license, and (b) | ||
382 | permanently, if the copyright holder fails to notify you of the violation by | ||
383 | some reasonable means prior to 60 days after the cessation. | ||
384 | |||
385 | Moreover, your license from a particular copyright holder is reinstated | ||
386 | permanently if the copyright holder notifies you of the violation by some | ||
387 | reasonable means, this is the first time you have received notice of violation | ||
388 | of this License (for any work) from that copyright holder, and you cure the | ||
389 | violation prior to 30 days after your receipt of the notice. | ||
390 | |||
391 | Termination of your rights under this section does not terminate the licenses | ||
392 | of parties who have received copies or rights from you under this License. If | ||
393 | your rights have been terminated and not permanently reinstated, you do not | ||
394 | qualify to receive new licenses for the same material under section 10. | ||
395 | |||
396 | 9. Acceptance Not Required for Having Copies. | ||
397 | |||
398 | You are not required to accept this License in order to receive or run a copy | ||
399 | of the Program. Ancillary propagation of a covered work occurring solely as a | ||
400 | consequence of using peer-to-peer transmission to receive a copy likewise does | ||
401 | not require acceptance. However, nothing other than this License grants you | ||
402 | permission to propagate or modify any covered work. These actions infringe | ||
403 | copyright if you do not accept this License. Therefore, by modifying or | ||
404 | propagating a covered work, you indicate your acceptance of this License to | ||
405 | do so. | ||
406 | |||
407 | 10. Automatic Licensing of Downstream Recipients. | ||
408 | |||
409 | Each time you convey a covered work, the recipient automatically receives a | ||
410 | license from the original licensors, to run, modify and propagate that work, | ||
411 | subject to this License. You are not responsible for enforcing compliance by | ||
412 | third parties with this License. | ||
413 | |||
414 | An “entity transaction” is a transaction transferring control of an | ||
415 | organization, or substantially all assets of one, or subdividing an | ||
416 | organization, or merging organizations. If propagation of a covered work | ||
417 | results from an entity transaction, each party to that transaction who receives | ||
418 | a copy of the work also receives whatever licenses to the work the party's | ||
419 | predecessor in interest had or could give under the previous paragraph, plus a | ||
420 | right to possession of the Corresponding Source of the work from the | ||
421 | predecessor in interest, if the predecessor has it or can get it with | ||
422 | reasonable efforts. | ||
423 | |||
424 | You may not impose any further restrictions on the exercise of the rights | ||
425 | granted or affirmed under this License. For example, you may not impose a | ||
426 | license fee, royalty, or other charge for exercise of rights granted under this | ||
427 | License, and you may not initiate litigation (including a cross-claim or | ||
428 | counterclaim in a lawsuit) alleging that any patent claim is infringed by | ||
429 | making, using, selling, offering for sale, or importing the Program or any | ||
430 | portion of it. | ||
431 | |||
432 | 11. Patents. | ||
433 | |||
434 | A “contributor” is a copyright holder who authorizes use under this License of | ||
435 | the Program or a work on which the Program is based. The work thus licensed is | ||
436 | called the contributor's “contributor version”. | ||
437 | |||
438 | A contributor's “essential patent claims” are all patent claims owned or | ||
439 | controlled by the contributor, whether already acquired or hereafter acquired, | ||
440 | that would be infringed by some manner, permitted by this License, of making, | ||
441 | using, or selling its contributor version, but do not include claims that would | ||
442 | be infringed only as a consequence of further modification of the contributor | ||
443 | version. For purposes of this definition, “control” includes the right to grant | ||
444 | patent sublicenses in a manner consistent with the requirements of this License. | ||
445 | |||
446 | Each contributor grants you a non-exclusive, worldwide, royalty-free patent | ||
447 | license under the contributor's essential patent claims, to make, use, sell, | ||
448 | offer for sale, import and otherwise run, modify and propagate the contents of | ||
449 | its contributor version. | ||
450 | |||
451 | In the following three paragraphs, a “patent license” is any express agreement | ||
452 | or commitment, however denominated, not to enforce a patent (such as an express | ||
453 | permission to practice a patent or covenant not to sue for patent | ||
454 | infringement). To “grant” such a patent license to a party means to make such | ||
455 | an agreement or commitment not to enforce a patent against the party. | ||
456 | |||
457 | If you convey a covered work, knowingly relying on a patent license, and the | ||
458 | Corresponding Source of the work is not available for anyone to copy, free of | ||
459 | charge and under the terms of this License, through a publicly available | ||
460 | network server or other readily accessible means, then you must either (1) | ||
461 | cause the Corresponding Source to be so available, or (2) arrange to deprive | ||
462 | yourself of the benefit of the patent license for this particular work, or (3) | ||
463 | arrange, in a manner consistent with the requirements of this License, to | ||
464 | extend the patent license to downstream recipients. “Knowingly relying” means | ||
465 | you have actual knowledge that, but for the patent license, your conveying the | ||
466 | covered work in a country, or your recipient's use of the covered work in a | ||
467 | country, would infringe one or more identifiable patents in that country that | ||
468 | you have reason to believe are valid. | ||
469 | |||
470 | If, pursuant to or in connection with a single transaction or arrangement, | ||
471 | you convey, or propagate by procuring conveyance of, a covered work, and grant | ||
472 | a patent license to some of the parties receiving the covered work authorizing | ||
473 | them to use, propagate, modify or convey a specific copy of the covered work, | ||
474 | then the patent license you grant is automatically extended to all recipients | ||
475 | of the covered work and works based on it. | ||
476 | |||
477 | A patent license is “discriminatory” if it does not include within the scope of | ||
478 | its coverage, prohibits the exercise of, or is conditioned on the non-exercise | ||
479 | of one or more of the rights that are specifically granted under this License. | ||
480 | You may not convey a covered work if you are a party to an arrangement with a | ||
481 | third party that is in the business of distributing software, under which you | ||
482 | make payment to the third party based on the extent of your activity of | ||
483 | conveying the work, and under which the third party grants, to any of the | ||
484 | parties who would receive the covered work from you, a discriminatory patent | ||
485 | license (a) in connection with copies of the covered work conveyed by you (or | ||
486 | copies made from those copies), or (b) primarily for and in connection with | ||
487 | specific products or compilations that contain the covered work, unless you | ||
488 | entered into that arrangement, or that patent license was granted, prior to | ||
489 | 28 March 2007. | ||
490 | |||
491 | Nothing in this License shall be construed as excluding or limiting any implied | ||
492 | license or other defenses to infringement that may otherwise be available to | ||
493 | you under applicable patent law. | ||
494 | |||
495 | 12. No Surrender of Others' Freedom. | ||
496 | |||
497 | If conditions are imposed on you (whether by court order, agreement or | ||
498 | otherwise) that contradict the conditions of this License, they do not excuse | ||
499 | you from the conditions of this License. If you cannot convey a covered work so | ||
500 | as to satisfy simultaneously your obligations under this License and any other | ||
501 | pertinent obligations, then as a consequence you may not convey it at all. For | ||
502 | example, if you agree to terms that obligate you to collect a royalty for | ||
503 | further conveying from those to whom you convey the Program, the only way you | ||
504 | could satisfy both those terms and this License would be to refrain entirely | ||
505 | from conveying the Program. | ||
506 | |||
507 | 13. Use with the GNU Affero General Public License. | ||
508 | |||
509 | Notwithstanding any other provision of this License, you have permission to | ||
510 | link or combine any covered work with a work licensed under version 3 of the | ||
511 | GNU Affero General Public License into a single combined work, and to convey | ||
512 | the resulting work. The terms of this License will continue to apply to the | ||
513 | part which is the covered work, but the special requirements of the GNU Affero | ||
514 | General Public License, section 13, concerning interaction through a network | ||
515 | will apply to the combination as such. | ||
516 | |||
517 | 14. Revised Versions of this License. | ||
518 | |||
519 | The Free Software Foundation may publish revised and/or new versions of the GNU | ||
520 | General Public License from time to time. Such new versions will be similar in | ||
521 | spirit to the present version, but may differ in detail to address new problems | ||
522 | or concerns. | ||
523 | |||
524 | Each version is given a distinguishing version number. If the Program specifies | ||
525 | that a certain numbered version of the GNU General Public License “or any later | ||
526 | version” applies to it, you have the option of following the terms and | ||
527 | conditions either of that numbered version or of any later version published by | ||
528 | the Free Software Foundation. If the Program does not specify a version number | ||
529 | of the GNU General Public License, you may choose any version ever published by | ||
530 | the Free Software Foundation. | ||
531 | |||
532 | If the Program specifies that a proxy can decide which future versions of the | ||
533 | GNU General Public License can be used, that proxy's public statement of | ||
534 | acceptance of a version permanently authorizes you to choose that version for | ||
535 | the Program. | ||
536 | |||
537 | Later license versions may give you additional or different permissions. | ||
538 | However, no additional obligations are imposed on any author or copyright | ||
539 | holder as a result of your choosing to follow a later version. | ||
540 | |||
541 | 15. Disclaimer of Warranty. | ||
542 | |||
543 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE | ||
544 | LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER | ||
545 | PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER | ||
546 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
547 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE | ||
548 | QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE | ||
549 | DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR | ||
550 | CORRECTION. | ||
551 | |||
552 | 16. Limitation of Liability. | ||
553 | |||
554 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY | ||
555 | COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS | ||
556 | PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, | ||
557 | INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE | ||
558 | THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED | ||
559 | INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE | ||
560 | PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY | ||
561 | HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | ||
562 | 17. Interpretation of Sections 15 and 16. | ||
563 | |||
564 | If the disclaimer of warranty and limitation of liability provided above cannot | ||
565 | be given local legal effect according to their terms, reviewing courts shall | ||
566 | apply local law that most closely approximates an absolute waiver of all civil | ||
567 | liability in connection with the Program, unless a warranty or assumption of | ||
568 | liability accompanies a copy of the Program in return for a fee. | ||
569 | |||
570 | END OF TERMS AND CONDITIONS \ No newline at end of file | ||
diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..4e3618d --- /dev/null +++ b/MANIFEST.in | |||
@@ -0,0 +1,5 @@ | |||
1 | include setup.py | ||
2 | include pavement.py | ||
3 | include paver-minilib.zip | ||
4 | include LICENSE | ||
5 | prune test | ||
@@ -0,0 +1,39 @@ | |||
1 | DODAI | ||
2 | |||
3 | A Python module to help with writing command line scripts | ||
4 | |||
5 | This module is to be a foundation to your command line python | ||
6 | scripts. This module provides for quick access to logger, configparser, | ||
7 | optionparse and databases via sqlalchemy. | ||
8 | |||
9 | |||
10 | INSTALLATION | ||
11 | ------------ | ||
12 | |||
13 | There are three ways to install dodai | ||
14 | |||
15 | 1. The easy_install method | ||
16 | |||
17 | easy_install dodai | ||
18 | |||
19 | 2. To do a traditional install, download compressed file from: | ||
20 | http://code.google.com/p/dodai/downloads/list | ||
21 | |||
22 | tar zxvf dodai-* | ||
23 | cd dodai-* | ||
24 | python setup.py install | ||
25 | |||
26 | 3. If you have Paver installed then download compressed file from | ||
27 | http://code.google.com/p/dodai/downloads/list | ||
28 | |||
29 | tar zxvf dodai-* | ||
30 | cd dodai-* | ||
31 | paver install | ||
32 | |||
33 | |||
34 | The installation will also install sqlalchemy. This installation will not | ||
35 | install the required system and python libs needed to get sqlalchemy to work | ||
36 | with your desired database. This includes things like: cx_Oracle, psycopg2, | ||
37 | pyodbc, mysql-python etc. For more information on installing these check out | ||
38 | the docs at http://code.google.com/p/dodai | ||
39 | |||
diff --git a/dodai/__init__.py b/dodai/__init__.py new file mode 100644 index 0000000..f1e90bc --- /dev/null +++ b/dodai/__init__.py | |||
@@ -0,0 +1,100 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | |||
19 | |||
20 | import os | ||
21 | import sys | ||
22 | from dodai.config import Config | ||
23 | from dodai.config.db import ConfigDbFile | ||
24 | |||
25 | |||
26 | class Configure(Config): | ||
27 | |||
28 | CONFIG_FILES = ['config', 'configs', 'configure', 'connect', 'connections', | ||
29 | 'connection'] | ||
30 | |||
31 | def __init__(self, project_name, config_files=None): | ||
32 | self.config_files = [] | ||
33 | self.project_name = project_name | ||
34 | self.home_directory = self._home_directory() | ||
35 | self._default_files() | ||
36 | self._add_files(config_files) | ||
37 | self._add_config_files() | ||
38 | |||
39 | def _add_files(self, filenames): | ||
40 | if filenames: | ||
41 | if isinstance(filenames, list) or isinstance(filenames, tuple): | ||
42 | for filename in filenames: | ||
43 | self._add_file(filename) | ||
44 | else: | ||
45 | self._add_file(filenames) | ||
46 | |||
47 | def _add_file(self, filename): | ||
48 | if os.path.isfile(filename): | ||
49 | if not filename in self.config_files: | ||
50 | self.config_files.append(filename) | ||
51 | |||
52 | def _default_files(self): | ||
53 | dirs = [] | ||
54 | dirs.append(self._construct_system_config_directory()) | ||
55 | dirs.append(self._construct_user_config_directory()) | ||
56 | dirs.append(self._construct_project_config_directory()) | ||
57 | files = [] | ||
58 | for dir in dirs: | ||
59 | for name in self.CONFIG_FILES: | ||
60 | files.append(os.path.join(dir, name)) | ||
61 | for filename in files: | ||
62 | self._add_file(filename) | ||
63 | |||
64 | def _home_directory(self): | ||
65 | out = None | ||
66 | try: | ||
67 | from win32com.shell import shellcon, shell | ||
68 | out = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0) | ||
69 | except ImportError: | ||
70 | out = os.path.expanduser("~") | ||
71 | return out | ||
72 | |||
73 | def _construct_system_config_directory(self): | ||
74 | out = os.path.join('etc', self.project_name.lower()) | ||
75 | return out | ||
76 | |||
77 | def _construct_user_config_directory(self): | ||
78 | project_directory = ".{dir}".format(dir=self.project_name.lower()) | ||
79 | out = os.path.join(self.home_directory, project_directory) | ||
80 | return out | ||
81 | |||
82 | def _construct_project_config_directory(self): | ||
83 | dir = os.path.dirname(os.path.abspath(sys.argv[0])) | ||
84 | out = os.path.join(dir, 'config') | ||
85 | return out | ||
86 | |||
87 | def _add_config_files(self): | ||
88 | if self.config_files: | ||
89 | self.files().add_file(self.config_files) | ||
90 | config = self.files().parser() | ||
91 | if self._has_connections(config): | ||
92 | self.dbs().add_config(config) | ||
93 | |||
94 | def _has_connections(self, config): | ||
95 | obj = ConfigDbFile(config) | ||
96 | connections = obj() | ||
97 | if connections: | ||
98 | return True | ||
99 | else: | ||
100 | return False | ||
diff --git a/dodai/config/__init__.py b/dodai/config/__init__.py new file mode 100644 index 0000000..aac9be7 --- /dev/null +++ b/dodai/config/__init__.py | |||
@@ -0,0 +1,64 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | |||
19 | |||
20 | class Config(object): | ||
21 | |||
22 | def __call__(self): | ||
23 | obj = ConfigResults() | ||
24 | if hasattr(self, 'vars'): | ||
25 | for key, val in self.vars.items(): | ||
26 | setattr(obj, key, val) | ||
27 | return obj | ||
28 | |||
29 | def set(self, key, val): | ||
30 | if not hasattr(self, 'vars'): | ||
31 | self.vars = {} | ||
32 | self.vars[key] = val | ||
33 | |||
34 | def options(self): | ||
35 | if not hasattr(self, '_options'): | ||
36 | from dodai.config.option import ConfigOption | ||
37 | self._options = ConfigOption() | ||
38 | return self._options | ||
39 | |||
40 | def files(self): | ||
41 | if not hasattr(self, '_files'): | ||
42 | from dodai.config.file import ConfigFile | ||
43 | self._files = ConfigFile() | ||
44 | return self._files | ||
45 | |||
46 | def logs(self): | ||
47 | if not hasattr(self, '_logs'): | ||
48 | from dodai.config.log import ConfigLog | ||
49 | self._logs = ConfigLog() | ||
50 | return self._logs | ||
51 | |||
52 | def dbs(self): | ||
53 | if not hasattr(self, '_dbs'): | ||
54 | from dodai.config.db import ConfigDb | ||
55 | self._dbs = ConfigDb() | ||
56 | return self._dbs | ||
57 | |||
58 | |||
59 | |||
60 | |||
61 | |||
62 | |||
63 | class ConfigResults(object): | ||
64 | pass | ||
diff --git a/dodai/config/db/__init__.py b/dodai/config/db/__init__.py new file mode 100644 index 0000000..fa510ac --- /dev/null +++ b/dodai/config/db/__init__.py | |||
@@ -0,0 +1,179 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | class ConfigDb(object): | ||
19 | |||
20 | def __init__(self): | ||
21 | self.connections = {} | ||
22 | self._handlers = {} | ||
23 | from dodai.config.db.sa import Sa | ||
24 | self.register_handler('sa', Sa) | ||
25 | |||
26 | def register_handler(self, name, obj): | ||
27 | self._handlers[name] = [obj, None] | ||
28 | |||
29 | def add_config(self, config_parser=None): | ||
30 | if config_parser: | ||
31 | if hasattr(config_parser, 'sections') and \ | ||
32 | hasattr(config_parser, 'options'): | ||
33 | config_obj = ConfigDbFile(config_parser) | ||
34 | self._add_connections(config_obj) | ||
35 | else: | ||
36 | raise NotConfigParserObject() | ||
37 | |||
38 | def _add_connections(self, config_obj): | ||
39 | connections = config_obj() | ||
40 | for name, obj in connections.items(): | ||
41 | self.connections[name] = obj | ||
42 | |||
43 | def load(self, name): | ||
44 | if name in self.connections: | ||
45 | connection = self.connections[name] | ||
46 | if connection.db_obj: | ||
47 | return connection.db_obj | ||
48 | else: | ||
49 | handler = self._load_handler(connection.handler) | ||
50 | db_obj = handler.load(connection) | ||
51 | self.connections[name].db_obj = db_obj | ||
52 | return db_obj | ||
53 | |||
54 | def _load_handler(self, name): | ||
55 | if name in self._handlers: | ||
56 | handler = self._handlers[name] | ||
57 | cls = handler[0] | ||
58 | obj = handler[1] | ||
59 | if not obj: | ||
60 | obj = cls() | ||
61 | self._handlers[name] = [cls, obj] | ||
62 | return obj | ||
63 | raise UnknownHandlerException(name) | ||
64 | |||
65 | |||
66 | |||
67 | class ConfigDbFile(object): | ||
68 | |||
69 | OPTIONS_REQUIRED = [ | ||
70 | ['protocol', 'hostname', 'port', 'username', 'password','database'], | ||
71 | ['protocol', 'filename'] | ||
72 | ] | ||
73 | OPTIONS_EXTRA = ['protocol_extra', 'handler'] | ||
74 | DEFAULT_HANDLER = 'sa' | ||
75 | |||
76 | def __init__(self, config_parser): | ||
77 | self.parser = config_parser | ||
78 | self._options = self._all_options() | ||
79 | self.connections = {} | ||
80 | |||
81 | def __call__(self): | ||
82 | if not self.connections: | ||
83 | for section in self.parser.sections(): | ||
84 | if self._is_valid(section): | ||
85 | obj = self._build_connection(section) | ||
86 | self.connections[obj.name] = obj | ||
87 | return self.connections | ||
88 | |||
89 | def _all_options(self): | ||
90 | out = [] | ||
91 | for option_group in self.OPTIONS_REQUIRED: | ||
92 | for option in option_group: | ||
93 | if option not in out: | ||
94 | out.append(option) | ||
95 | for option in self.OPTIONS_EXTRA: | ||
96 | if option not in out: | ||
97 | out.append(option) | ||
98 | return out | ||
99 | |||
100 | def _is_valid(self, section): | ||
101 | for option_group in self.OPTIONS_REQUIRED: | ||
102 | total = len(option_group) | ||
103 | count = 0 | ||
104 | for option in option_group: | ||
105 | if option in self.parser.options(section): | ||
106 | value = self.parser.get(section, option) | ||
107 | if value: | ||
108 | count += 1 | ||
109 | if count >= total: | ||
110 | return True | ||
111 | return False | ||
112 | |||
113 | def _build_connection(self, section): | ||
114 | obj = ConfigDbConnection() | ||
115 | for option in self._options: | ||
116 | obj.name = section | ||
117 | if self.parser.has_option(section, option): | ||
118 | value = self.parser.get(section, option) | ||
119 | setattr(obj, option, value) | ||
120 | if not hasattr(obj, 'handler') or not obj.handler: | ||
121 | obj.handler = self.DEFAULT_HANDLER | ||
122 | return obj | ||
123 | |||
124 | |||
125 | class BaseConfigDb(object): | ||
126 | |||
127 | PROTOCOLS = ['postgresql', 'mysql', 'sqlite', 'mssql', 'oracle'] | ||
128 | |||
129 | def _clean(self, obj): | ||
130 | obj.protocol = self._clean_protocol(obj.protocol) | ||
131 | if hasattr(obj, 'port'): | ||
132 | obj.port = self._clean_port(obj.port) | ||
133 | |||
134 | def _clean_protocol(self, data): | ||
135 | data = data.lower() | ||
136 | if data in ('postgres', 'postgre'): | ||
137 | data = 'postgresql' | ||
138 | if data not in self.PROTOCOLS: | ||
139 | raise InvalidProtocolException(data) | ||
140 | else: | ||
141 | return data | ||
142 | |||
143 | def _clean_port(self, data): | ||
144 | try: | ||
145 | data = int(data) | ||
146 | except ValueError: | ||
147 | data = None | ||
148 | except TypeError: | ||
149 | data = None | ||
150 | if data: | ||
151 | if data <1 or data > 65535: | ||
152 | raise InvalidPortException(data) | ||
153 | return data | ||
154 | |||
155 | |||
156 | class ConfigDbConnection(object): | ||
157 | |||
158 | def __init__(self): | ||
159 | self.db_obj = None | ||
160 | |||
161 | |||
162 | class NotConfigParserObject(Exception): | ||
163 | pass | ||
164 | |||
165 | |||
166 | class InvalidProtocolException(Exception): | ||
167 | pass | ||
168 | |||
169 | |||
170 | class InvalidPortException(Exception): | ||
171 | pass | ||
172 | |||
173 | |||
174 | class UnknownHandlerException(Exception): | ||
175 | pass | ||
176 | |||
177 | |||
178 | class UnknownConnectionException(Exception): | ||
179 | pass | ||
diff --git a/dodai/config/db/sa.py b/dodai/config/db/sa.py new file mode 100644 index 0000000..06adf9c --- /dev/null +++ b/dodai/config/db/sa.py | |||
@@ -0,0 +1,64 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | from dodai.config.db import BaseConfigDb | ||
19 | from dodai.db import Db | ||
20 | |||
21 | class Sa(BaseConfigDb): | ||
22 | |||
23 | |||
24 | def load(self, obj): | ||
25 | from sqlalchemy.orm import sessionmaker | ||
26 | self._clean(obj) | ||
27 | db = Db() | ||
28 | db.engine = self._build_engine(obj) | ||
29 | Session = sessionmaker(bind=db.engine) | ||
30 | db.session = Session() | ||
31 | db.name = obj.name | ||
32 | db.protocol = obj.protocol | ||
33 | if hasattr(obj, 'filename') and obj.filename: | ||
34 | db.filename = obj.filename | ||
35 | else: | ||
36 | db.hostname = obj.hostname | ||
37 | if hasattr(obj, 'port') and obj.port: | ||
38 | db.port = obj.port | ||
39 | db.database = obj.database | ||
40 | return db | ||
41 | |||
42 | def _build_connection_string(self, obj): | ||
43 | out = [] | ||
44 | out.append('{db.protocol}') | ||
45 | if hasattr(obj, 'protocol_extra') and obj.protocol_extra: | ||
46 | out.append('+{db.protocol_extra}') | ||
47 | out.append('://') | ||
48 | if hasattr(obj, 'filename') and obj.filename: | ||
49 | out.append('{db.filename}') | ||
50 | else: | ||
51 | out.append('{db.username}:{db.password}@') | ||
52 | out.append('{db.hostname}') | ||
53 | if hasattr(obj, 'port') and obj.port: | ||
54 | out.append(':{db.port}') | ||
55 | out.append('/{db.database}') | ||
56 | out = ''.join(out) | ||
57 | out = out.format(db=obj) | ||
58 | return out | ||
59 | |||
60 | def _build_engine(self, obj): | ||
61 | from sqlalchemy import create_engine | ||
62 | connection_string = self._build_connection_string(obj) | ||
63 | db_obj = create_engine(connection_string) | ||
64 | return db_obj | ||
diff --git a/dodai/config/file.py b/dodai/config/file.py new file mode 100644 index 0000000..5cab6f8 --- /dev/null +++ b/dodai/config/file.py | |||
@@ -0,0 +1,116 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | |||
19 | import os | ||
20 | import ConfigParser | ||
21 | |||
22 | class ConfigFile(object): | ||
23 | |||
24 | def __init__(self): | ||
25 | self._files = [] | ||
26 | self._parser = None | ||
27 | self.files_loaded = [] | ||
28 | self._dir = None | ||
29 | |||
30 | def set_directory(self, path): | ||
31 | """ Sets the direcory where files will be looked for | ||
32 | raises: InvalidDirectoryException or DirectoryDoesNotExistException | ||
33 | """ | ||
34 | if os.path.isdir(path): | ||
35 | self._dir = path | ||
36 | else: | ||
37 | if os.path.isfile(path): | ||
38 | raise InvalidDirectoryException(path) | ||
39 | else: | ||
40 | raise DirectoryDoesNotExistException(path) | ||
41 | |||
42 | def get_directory(self): | ||
43 | """ Returns the directory where files will be looked for | ||
44 | """ | ||
45 | return self._dir | ||
46 | |||
47 | def add_file(self, path): | ||
48 | """ Adds a full file path with the given path (list or string) | ||
49 | raises: FileDoesNotExistException | ||
50 | """ | ||
51 | if isinstance(path, list): | ||
52 | for file_ in path: | ||
53 | self._add_file(file_) | ||
54 | else: | ||
55 | if path not in self._files: | ||
56 | self._add_file(path) | ||
57 | |||
58 | def _add_file(self, path): | ||
59 | """ Adds the given file path file to the object if the filepath | ||
60 | doesn't already exist | ||
61 | """ | ||
62 | if os.path.isfile(path): | ||
63 | if path not in self._files: | ||
64 | self._files.append(path) | ||
65 | else: | ||
66 | raise FileDoesNotExistException(path) | ||
67 | |||
68 | def get_files(self): | ||
69 | """ Returns a list of files that were added to this object | ||
70 | """ | ||
71 | return self._files | ||
72 | |||
73 | def parser(self): | ||
74 | """ Returns a ConfigParser.ConfigParser object with files loaded | ||
75 | raises: NoFilesToLoadException | ||
76 | """ | ||
77 | self._reset_parser() | ||
78 | if not self._parser: | ||
79 | if not self._files: | ||
80 | raise NoFilesToLoadException() | ||
81 | self._parser = ConfigParser.ConfigParser() | ||
82 | self.files_loaded = self._parser.read(self._files) | ||
83 | return self._parser | ||
84 | |||
85 | def load(self, name): | ||
86 | """ Takes the given name and merges it with the object's directory | ||
87 | then adds the path to the object | ||
88 | """ | ||
89 | if not self._dir: | ||
90 | raise DirectoryNotSetException() | ||
91 | else: | ||
92 | path = os.path.join(self._dir, name) | ||
93 | self.add_file(path) | ||
94 | |||
95 | def _reset_parser(self): | ||
96 | """ Resets the _parser property if the files_loaded does not equal | ||
97 | the files assigned to this object | ||
98 | """ | ||
99 | if self._parser: | ||
100 | if self.files_loaded != self._files: | ||
101 | self._parser = None | ||
102 | |||
103 | class NoFilesToLoadException(Exception): | ||
104 | pass | ||
105 | |||
106 | class DirectoryNotSetException(Exception): | ||
107 | pass | ||
108 | |||
109 | class InvalidDirectoryException(Exception): | ||
110 | pass | ||
111 | |||
112 | class DirectoryDoesNotExistException(Exception): | ||
113 | pass | ||
114 | |||
115 | class FileDoesNotExistException(Exception): | ||
116 | pass | ||
diff --git a/dodai/config/log.py b/dodai/config/log.py new file mode 100644 index 0000000..fdb5c93 --- /dev/null +++ b/dodai/config/log.py | |||
@@ -0,0 +1,150 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | |||
19 | import logging | ||
20 | import logging.handlers | ||
21 | import os | ||
22 | |||
23 | class ConfigLog(object): | ||
24 | |||
25 | LEVELS = { | ||
26 | logging.CRITICAL: [ | ||
27 | 'critical', | ||
28 | "%(asctime)s - %(name)s - %(levelname)s - %(message)s", | ||
29 | "%(message)s"], | ||
30 | logging.ERROR: [ | ||
31 | 'error', | ||
32 | "%(asctime)s - %(name)s - %(levelname)s - %(message)s", | ||
33 | "%(message)s"], | ||
34 | logging.WARNING: [ | ||
35 | 'warning', | ||
36 | "%(asctime)s - %(name)s - %(levelname)s - %(message)s", | ||
37 | "%(message)s"], | ||
38 | logging.INFO: [ | ||
39 | 'info', | ||
40 | "%(asctime)s - %(name)s - %(levelname)s - %(message)s", | ||
41 | "%(message)s"], | ||
42 | logging.DEBUG: [ | ||
43 | 'debug', | ||
44 | "%(asctime)s - %(name)s - %(levelname)s - %(message)s", | ||
45 | "%(message)s"] | ||
46 | } | ||
47 | |||
48 | MAX_BYTES = 10485760 | ||
49 | BACKUP_COUNT = 5 | ||
50 | FILE_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" | ||
51 | STDOUT_FORMAT = "%(message)s" | ||
52 | |||
53 | def __init__(self): | ||
54 | self.log_level = logging.CRITICAL | ||
55 | self.directory = None | ||
56 | self._levels = {} | ||
57 | |||
58 | def set_log_level(self, level): | ||
59 | try: | ||
60 | level = self._fetch_log_level(level) | ||
61 | except InvalidLevelException: | ||
62 | pass | ||
63 | else: | ||
64 | self.log_level = level | ||
65 | |||
66 | def set_directory(self, directory): | ||
67 | if os.path.isdir(directory): | ||
68 | self.directory = directory | ||
69 | else: | ||
70 | raise NoDirectoryExistException(directory) | ||
71 | |||
72 | def get_file_message_format(self, level): | ||
73 | if not self._levels: | ||
74 | self._levels = self.LEVELS | ||
75 | level = self._fetch_log_level(level) | ||
76 | return self._levels[level][1] | ||
77 | |||
78 | def get_screen_message_format(self, level): | ||
79 | if not self._levels: | ||
80 | self._levels = self.LEVELS | ||
81 | level = self._fetch_log_level(level) | ||
82 | return self._levels[level][2] | ||
83 | |||
84 | def _fetch_log_level(self, level): | ||
85 | out = None | ||
86 | if isinstance(level, str): | ||
87 | level = level.strip().lower() | ||
88 | if level in self.LEVELS: | ||
89 | out = level | ||
90 | else: | ||
91 | for key, items in self.LEVELS.items(): | ||
92 | if level == items[0]: | ||
93 | out = key | ||
94 | if not out: | ||
95 | raise InvalidLevelException(level) | ||
96 | else: | ||
97 | return out | ||
98 | |||
99 | def _build_filepath(self, data): | ||
100 | data = os.path.normpath(data) | ||
101 | if data.startswith(os.path.sep): | ||
102 | dir = os.path.dirname(data) | ||
103 | if not os.path.isdir(dir): | ||
104 | raise NoDirectoryExistException(dir) | ||
105 | else: | ||
106 | if not self.directory: | ||
107 | raise DirectoryNotSetException() | ||
108 | else: | ||
109 | data = os.path.join(self.directory, data) | ||
110 | return data | ||
111 | |||
112 | def load(self, name): | ||
113 | log =logging.getLogger(name) | ||
114 | log.setLevel(self.log_level) | ||
115 | return log | ||
116 | |||
117 | def attach_file_handler(self, log, filename): | ||
118 | filepath = self._build_filepath(filename) | ||
119 | handler = logging.handlers.RotatingFileHandler( | ||
120 | filepath, maxBytes = self.MAX_BYTES, | ||
121 | backupCount=self.BACKUP_COUNT) | ||
122 | file_format = self.get_file_message_format(self.log_level) | ||
123 | format_obj = logging.Formatter(file_format) | ||
124 | handler.setFormatter(format_obj) | ||
125 | handler.setLevel(self.log_level) | ||
126 | log.addHandler(handler) | ||
127 | |||
128 | def attach_screen_handler(self, log, level=None): | ||
129 | if level: | ||
130 | level = self._fetch_log_level(level) | ||
131 | else: | ||
132 | level = self.log_level | ||
133 | message_format = self.get_screen_message_format(level) | ||
134 | handler = logging.StreamHandler() | ||
135 | handler.setLevel(level) | ||
136 | format_obj = logging.Formatter(message_format) | ||
137 | handler.setFormatter(format_obj) | ||
138 | log.addHandler(handler) | ||
139 | |||
140 | |||
141 | class NoDirectoryExistException(Exception): | ||
142 | pass | ||
143 | |||
144 | |||
145 | class DirectoryNotSetException(Exception): | ||
146 | pass | ||
147 | |||
148 | |||
149 | class InvalidLevelException(Exception): | ||
150 | pass | ||
diff --git a/dodai/config/option.py b/dodai/config/option.py new file mode 100644 index 0000000..0561881 --- /dev/null +++ b/dodai/config/option.py | |||
@@ -0,0 +1,61 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | |||
19 | from optparse import OptionParser | ||
20 | |||
21 | class ConfigOption(object): | ||
22 | |||
23 | def __init__(self): | ||
24 | |||
25 | self.parser = OptionParser() | ||
26 | self._options = None | ||
27 | self._args = [] | ||
28 | |||
29 | def get_args(self): | ||
30 | self._parse_args() | ||
31 | return self._args | ||
32 | |||
33 | def get_options(self): | ||
34 | self._parse_args() | ||
35 | return self._options | ||
36 | |||
37 | def _parse_args(self): | ||
38 | options, args = self.parser.parse_args() | ||
39 | self._options = options | ||
40 | self._args = args | ||
41 | |||
42 | def add_quiet(self): | ||
43 | |||
44 | self.parser.add_option("-q", "--quiet", dest="verbose", default=True, | ||
45 | action="store_false", | ||
46 | help="Don't print status messages to the screen") | ||
47 | |||
48 | def add_verbose(self): | ||
49 | self.parser.add_option("-v", "--verbose", dest="verbose", | ||
50 | action="store_true", | ||
51 | default=False, help="Print status messages to the screen") | ||
52 | |||
53 | def add_log_level(self, default='critical'): | ||
54 | self.parser.add_option("-l", "--log-level", dest="log_level", | ||
55 | default=default, help="Sets the log level") | ||
56 | |||
57 | def add_setup(self): | ||
58 | self.parser.add_option('', "--setup", dest="setup", | ||
59 | action="store_true", default=False, | ||
60 | help="run the setup which builds the config "\ | ||
61 | "files.") | ||
diff --git a/dodai/config/sections.py b/dodai/config/sections.py new file mode 100644 index 0000000..feb59be --- /dev/null +++ b/dodai/config/sections.py | |||
@@ -0,0 +1,172 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | import unicodedata | ||
19 | |||
20 | class ConfigSections(object): | ||
21 | """ | ||
22 | An iterable object that contains ConfigSection objects | ||
23 | |||
24 | """ | ||
25 | |||
26 | def __init__(self, string_object = None): | ||
27 | """ | ||
28 | Iterable object that handles the conversion of a config | ||
29 | parser object to a list of section objects. | ||
30 | |||
31 | |||
32 | string_object: This is an object (non instantiated or | ||
33 | callable) that the results of the config's | ||
34 | sections, and options will be stored in. | ||
35 | This enables you to store your values as a | ||
36 | custom object. A good object to use is the | ||
37 | dodai.tools.himo Himo object. If the | ||
38 | string_object is not given the default python | ||
39 | str() object will be used. | ||
40 | |||
41 | """ | ||
42 | self._string_object = string_object or None | ||
43 | self._sections = {} | ||
44 | |||
45 | def __call__(self, parser): | ||
46 | """ | ||
47 | Parses the given parser object into this object's sections. | ||
48 | |||
49 | parser: The actual parser object that is used to | ||
50 | get the sections. This object must have | ||
51 | the sections(), options() and get() | ||
52 | methods. A good object to use is the native | ||
53 | ConfigParse object. However, you can create | ||
54 | your own | ||
55 | |||
56 | """ | ||
57 | self._build_sections(parser) | ||
58 | |||
59 | def _build_sections(self, parser): | ||
60 | # Builds ConfigSection objects from the parser object | ||
61 | |||
62 | for section_name in parser.sections(): | ||
63 | section = self.get_section(section_name) | ||
64 | self._build_options(parser, section_name, section) | ||
65 | |||
66 | def _build_options(self, parser, section_name, section): | ||
67 | # Adds the options to the section object | ||
68 | |||
69 | for key in parser.options(section_name): | ||
70 | key = unicode(self._build_string_object(key)) | ||
71 | value = self._build_string_object(parser.get(section_name, key)) | ||
72 | setattr(section, key, value) | ||
73 | |||
74 | def _build_string_object(self, data): | ||
75 | if self._string_object: | ||
76 | return self._string_object(data) | ||
77 | else: | ||
78 | return data | ||
79 | |||
80 | def get_section(self, section_name): | ||
81 | """ | ||
82 | Returns a ConfigSection object from this object's section | ||
83 | dictionary or creates a new ConfigSection object, which is | ||
84 | stored int this object's section dictionary then is returned | ||
85 | |||
86 | """ | ||
87 | section_name = unicode(self._build_string_object(section_name)) | ||
88 | if section_name in self._sections: | ||
89 | return self._sections[section_name] | ||
90 | else: | ||
91 | section = ConfigSection(section_name) | ||
92 | self._sections[section_name] = section | ||
93 | return section | ||
94 | |||
95 | def __getitem__(self, key): | ||
96 | key = normalize_key(key) | ||
97 | return self._sections[key] | ||
98 | |||
99 | def __getattr__(self, key): | ||
100 | key = normalize_key(key) | ||
101 | try: | ||
102 | out = self._sections[key] | ||
103 | except KeyError: | ||
104 | return getattr(self._sections, key) | ||
105 | else: | ||
106 | return out | ||
107 | |||
108 | def __iter__(self, *args, **kargs): | ||
109 | return self._sections.__iter__(*args, **kargs) | ||
110 | |||
111 | |||
112 | def __len__(self): | ||
113 | return len(self._sections) | ||
114 | |||
115 | class ConfigSection(object): | ||
116 | """ | ||
117 | A generic object to hold keys and values primarily from a config file | ||
118 | |||
119 | """ | ||
120 | def __init__(self, title): | ||
121 | """ | ||
122 | Holds keys and values primarily from a section of a config file | ||
123 | |||
124 | title: The title of the section of the config file | ||
125 | |||
126 | """ | ||
127 | self.___title___ = title | ||
128 | self.___options___ = {} | ||
129 | |||
130 | |||
131 | def get_title(self): | ||
132 | """ | ||
133 | Returns the title of the section | ||
134 | |||
135 | """ | ||
136 | return self.___title___ | ||
137 | |||
138 | |||
139 | def __setattr__(self, key, value): | ||
140 | if key.startswith('___') and key.endswith('___'): | ||
141 | object.__setattr__(self, key, value) | ||
142 | else: | ||
143 | key = normalize_key(key) | ||
144 | if self.___options___.has_key(key): | ||
145 | self.___options___[key] = value | ||
146 | else: | ||
147 | dict.__setitem__(self.___options___, key, value) | ||
148 | |||
149 | def __getattr__(self, key): | ||
150 | if key.startswith('___') and key.endswith('___'): | ||
151 | return self.__dict__[key] | ||
152 | else: | ||
153 | key = normalize_key(key) | ||
154 | try: | ||
155 | out = self.___options___[key] | ||
156 | except KeyError: | ||
157 | return getattr(self.___options___, key) | ||
158 | else: | ||
159 | return out | ||
160 | |||
161 | def __getitem__(self, key): | ||
162 | key = normalize_key(key) | ||
163 | return self.___options___[key] | ||
164 | |||
165 | def __iter__(self, *args, **kargs): | ||
166 | return self.___options___.__iter__(*args, **kargs) | ||
167 | |||
168 | |||
169 | def normalize_key(key): | ||
170 | key = unicode(key) | ||
171 | key = unicodedata.normalize('NFC', key) | ||
172 | return key | ||
diff --git a/dodai/db.py b/dodai/db.py new file mode 100644 index 0000000..d65f60a --- /dev/null +++ b/dodai/db.py | |||
@@ -0,0 +1,30 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Sodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | |||
19 | class Db(object): | ||
20 | pass | ||
21 | |||
22 | def __init__(self): | ||
23 | self.name = None | ||
24 | self.protocol = None | ||
25 | self.hostname = None | ||
26 | self.port = None | ||
27 | self.database = None | ||
28 | self.filename = None | ||
29 | self.engine = None | ||
30 | self.session = None | ||
diff --git a/dodai/tools/__init__.py b/dodai/tools/__init__.py new file mode 100644 index 0000000..c54f7f2 --- /dev/null +++ b/dodai/tools/__init__.py | |||
@@ -0,0 +1,16 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
diff --git a/dodai/tools/himo.py b/dodai/tools/himo.py new file mode 100644 index 0000000..5a96f91 --- /dev/null +++ b/dodai/tools/himo.py | |||
@@ -0,0 +1,362 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | import chardet | ||
19 | import re | ||
20 | import sys | ||
21 | import unicodedata | ||
22 | from htmlentitydefs import name2codepoint | ||
23 | from htmlentitydefs import codepoint2name | ||
24 | from decimal import Decimal as D | ||
25 | |||
26 | class Himo(object): | ||
27 | """ | ||
28 | A unicode-string object with some added features to help with | ||
29 | unicode decoding and output conversions. | ||
30 | """ | ||
31 | |||
32 | MAP = {169:u'(C)', 174:u'(R)', 8471:u'(P)'} | ||
33 | |||
34 | def __init__(self, data, encoding=None): | ||
35 | """ | ||
36 | data: Accepts any type of string object (int, float, | ||
37 | string, unicode) | ||
38 | |||
39 | encoding: Character encoding to help with converting the input | ||
40 | into unicode | ||
41 | |||
42 | The input data will be converted into an unicode object, unless | ||
43 | the input data is already an unicode object. If the param | ||
44 | 'encoding' is set, the input data will be converted to unicode | ||
45 | using that value. If no 'encoding' is given this object will | ||
46 | attempt to figure out the encoding. First the encoding of the | ||
47 | operating system will be used. If there are any errors, the | ||
48 | chardet module will be used. This object makes no guarantees | ||
49 | that the correct encoding will be detected. | ||
50 | |||
51 | """ | ||
52 | |||
53 | self._encoding = encoding or self._system_encoding() | ||
54 | self.data = self._decode(data) | ||
55 | |||
56 | def ascii(self): | ||
57 | """ | ||
58 | Returns an ascii representation of this object value. | ||
59 | Throws HimoAsciiError if this method was unable to | ||
60 | convert a unicode character down to it's root character. | ||
61 | For example if in your string you have a character | ||
62 | like the letter 'e' but it has an accent mark over it, | ||
63 | this method will convert that character to it's root | ||
64 | character. Thus 'e' with an accent mark over it will | ||
65 | replaced with the regular letter 'e'. | ||
66 | |||
67 | """ | ||
68 | out = [] | ||
69 | for char in self.data: | ||
70 | if ord(char) < 127: | ||
71 | out.append(char) | ||
72 | elif ord(char) in self.MAP: | ||
73 | out.append(self.MAP[ord(char)]) | ||
74 | else: | ||
75 | num = unicodedata.decomposition(char).split(' ')[0] | ||
76 | if num: | ||
77 | out.append(unichr(int(num, 16))) | ||
78 | else: | ||
79 | print char | ||
80 | raise HimoAsciiError("Unable to convert 'u{0}' "\ | ||
81 | "character to ascii".format(ord(char))) | ||
82 | return str(''.join(out)) | ||
83 | |||
84 | def html(self): | ||
85 | """ | ||
86 | Returns a unicode string containing this object's value | ||
87 | html enetity encoded. | ||
88 | """ | ||
89 | out = [] | ||
90 | for char in self.data: | ||
91 | out.append(self._html_char_encode(char)) | ||
92 | return ''.join(out) | ||
93 | |||
94 | def decimal(self): | ||
95 | """ | ||
96 | Returns a decimal object with the value of this object | ||
97 | |||
98 | """ | ||
99 | |||
100 | return D(self.data) | ||
101 | |||
102 | def _decode(self, data): | ||
103 | # Returns a unicode string. If data contains any html encoded | ||
104 | # characters, the characters will be converted to their unicode | ||
105 | # equivalent | ||
106 | |||
107 | data = self._as_unicode(data) | ||
108 | expression = re.compile(r'&(#?)(x?)(\w+);') | ||
109 | return expression.subn(self._html_decode, data)[0] | ||
110 | |||
111 | def _as_unicode(self, data): | ||
112 | # Returns string as a unicode string | ||
113 | |||
114 | if not isinstance(data, unicode): | ||
115 | if not isinstance(data, str): | ||
116 | data = str(data) | ||
117 | try: | ||
118 | data = data.decode(self._encoding) | ||
119 | except UnicodeDecodeError: | ||
120 | info = chardet.detect(data) | ||
121 | self.encoding = info['encoding'] | ||
122 | data = data.decode(info['encoding']) | ||
123 | return unicodedata.normalize('NFC', data) | ||
124 | |||
125 | def _html_char_encode(self, char): | ||
126 | # Returns an html version of the char | ||
127 | |||
128 | number = ord(char) | ||
129 | try: | ||
130 | char = "&{0};".format(codepoint2name[number]) | ||
131 | except KeyError: | ||
132 | if number > 127: | ||
133 | char = "&#{0};".format(number) | ||
134 | return char | ||
135 | |||
136 | def _html_decode(self, values): | ||
137 | # Returns the unicode character from the re.subn | ||
138 | |||
139 | value = values.group(3) | ||
140 | if values.group(1): | ||
141 | if values.group(2): | ||
142 | return unichr(int('0x{0}'.format(value), 16)) | ||
143 | else: | ||
144 | return unichr(int(value)) | ||
145 | else: | ||
146 | try: | ||
147 | char = name2codepoint[value] | ||
148 | except KeyError: | ||
149 | return values.group() | ||
150 | else: | ||
151 | return unichr(char) | ||
152 | |||
153 | def _system_encoding(self): | ||
154 | # Returns the character encoding of the system | ||
155 | |||
156 | encoding = sys.getfilesystemencoding() | ||
157 | if not encoding: | ||
158 | encoding = sys.getdefaultencoding() | ||
159 | return encoding | ||
160 | |||
161 | #def __cmp__(self, other): | ||
162 | # if self.__eq__(other): | ||
163 | # return 1 | ||
164 | # else: | ||
165 | # pool = [str(self.data), str(other)] | ||
166 | # pool.sort() | ||
167 | # if pool[0] == self.data: | ||
168 | # return -1 | ||
169 | # else: | ||
170 | # return 1 | ||
171 | |||
172 | |||
173 | def _is_himo(self, other): | ||
174 | if hasattr(other, '_is_himo'): | ||
175 | return True | ||
176 | return False | ||
177 | |||
178 | def __len__(self): | ||
179 | return len(self.data) | ||
180 | |||
181 | def __repr__(self): | ||
182 | return repr(self.data) | ||
183 | |||
184 | def __str__(self): | ||
185 | return self.data.encode(self._encoding) | ||
186 | |||
187 | def __iter__(self): | ||
188 | for char in self.data: | ||
189 | yield char | ||
190 | |||
191 | def __int__(self): | ||
192 | return int(self.data) | ||
193 | |||
194 | def __float__(self): | ||
195 | return float(self.data) | ||
196 | |||
197 | def __eq__(self, other): | ||
198 | if self._is_himo(other): | ||
199 | other = other.data | ||
200 | return self.data.__eq__(other) | ||
201 | |||
202 | def __ne__(self, other): | ||
203 | if self._is_himo(other): | ||
204 | other = other.data | ||
205 | return self.data.__ne__(other) | ||
206 | |||
207 | def __gt__(self, other): | ||
208 | if self._is_himo(other): | ||
209 | other = other.data | ||
210 | lines = [self.data, other] | ||
211 | lines.sort() | ||
212 | if lines[0] == self.data: | ||
213 | return True | ||
214 | else: | ||
215 | return False | ||
216 | |||
217 | def __lt__(self, other): | ||
218 | if self._is_himo(other): | ||
219 | other = other.data | ||
220 | lines = [self.data, other] | ||
221 | lines.sort() | ||
222 | if lines[0] != self.data: | ||
223 | return True | ||
224 | else: | ||
225 | return False | ||
226 | |||
227 | def __cmp__(self, other): | ||
228 | if self.__eq__(other): | ||
229 | return 0 | ||
230 | elif self.__lt__(other): | ||
231 | return -1 | ||
232 | else: | ||
233 | return 1 | ||
234 | |||
235 | def __unicode__(self): | ||
236 | return self.data | ||
237 | |||
238 | def capitalize(self, *args, **kargs): | ||
239 | return self.data.capitalize(*args, **kargs) | ||
240 | |||
241 | def center(self, *args, **kargs): | ||
242 | return self.data.center(*args, **kargs) | ||
243 | |||
244 | def count(self, *args, **kargs): | ||
245 | return self.data.count(*args, **kargs) | ||
246 | |||
247 | def decode(self, *args, **kargs): | ||
248 | return self.data.decode(*args, **kargs) | ||
249 | |||
250 | def encode(self, *args, **kargs): | ||
251 | return self.data.encode(*args, **kargs) | ||
252 | |||
253 | def encode(self, *args, **kargs): | ||
254 | return self.data.encode(*args, **kargs) | ||
255 | |||
256 | def endswith(self, *args, **kargs): | ||
257 | return self.data.endswith(*args, **kargs) | ||
258 | |||
259 | def expandtabs(self, *args, **kargs): | ||
260 | return self.data.expandtabs(*args, **kargs) | ||
261 | |||
262 | def find(self, *args, **kargs): | ||
263 | return self.data.find(*args, **kargs) | ||
264 | |||
265 | def format(self, *args, **kargs): | ||
266 | return self.data.format(*args, **kargs) | ||
267 | |||
268 | def index(self, *args, **kargs): | ||
269 | return self.data.index(*args, **kargs) | ||
270 | |||
271 | def isalnum(self, *args, **kargs): | ||
272 | return self.data.isalnum(*args, **kargs) | ||
273 | |||
274 | def isalpha(self, *args, **kargs): | ||
275 | return self.data.isalpha(*args, **kargs) | ||
276 | |||
277 | def isdecimal(self, *args, **kargs): | ||
278 | return self.data.isdecimal(*args, **kargs) | ||
279 | |||
280 | def isdigit(self, *args, **kargs): | ||
281 | return self.data.isdigit(*args, **kargs) | ||
282 | |||
283 | def islower(self, *args, **kargs): | ||
284 | return self.data.islower(*args, **kargs) | ||
285 | |||
286 | def isnumeric(self, *args, **kargs): | ||
287 | return self.data.isnumeric(*args, **kargs) | ||
288 | |||
289 | def isspace(self, *args, **kargs): | ||
290 | return self.data.isspace(*args, **kargs) | ||
291 | |||
292 | def istitle(self, *args, **kargs): | ||
293 | return self.data.istitle(*args, **kargs) | ||
294 | |||
295 | def isupper(self, *args, **kargs): | ||
296 | return self.data.isupper(*args, **kargs) | ||
297 | |||
298 | def join(self, *args, **kargs): | ||
299 | return self.data.join(*args, **kargs) | ||
300 | |||
301 | def ljust(self, *args, **kargs): | ||
302 | return self.data.ljust(*args, **kargs) | ||
303 | |||
304 | def lower(self, *args, **kargs): | ||
305 | return self.data.lower(*args, **kargs) | ||
306 | |||
307 | def lstrip(self, *args, **kargs): | ||
308 | return self.data.lstrip(*args, **kargs) | ||
309 | |||
310 | def partition(self, *args, **kargs): | ||
311 | return self.data.partition(*args, **kargs) | ||
312 | |||
313 | def replace(self, *args, **kargs): | ||
314 | return self.data.replace(*args, **kargs) | ||
315 | |||
316 | def rfind(self, *args, **kargs): | ||
317 | return self.data.rfind(*args, **kargs) | ||
318 | |||
319 | def rindex(self, *args, **kargs): | ||
320 | return self.data.rindex(*args, **kargs) | ||
321 | |||
322 | def rjust(self, *args, **kargs): | ||
323 | return self.data.rjust(*args, **kargs) | ||
324 | |||
325 | def rpartition(self, *args, **kargs): | ||
326 | return self.data.rpartition(*args, **kargs) | ||
327 | |||
328 | def rsplit(self, *args, **kargs): | ||
329 | return self.data.rsplit(*args, **kargs) | ||
330 | |||
331 | def rstrip(self, *args, **kargs): | ||
332 | return self.data.rstrip(*args, **kargs) | ||
333 | |||
334 | def split(self, *args, **kargs): | ||
335 | return self.data.split(*args, **kargs) | ||
336 | |||
337 | def splitlines(self, *args, **kargs): | ||
338 | return self.data.splitlines(*args, **kargs) | ||
339 | |||
340 | def startswith(self, *args, **kargs): | ||
341 | return self.data.startswith(*args, **kargs) | ||
342 | |||
343 | def strip(self, *args, **kargs): | ||
344 | return self.data.strip(*args, **kargs) | ||
345 | |||
346 | def swapcase(self, *args, **kargs): | ||
347 | return self.data.swapcase(*args, **kargs) | ||
348 | |||
349 | def title(self, *args, **kargs): | ||
350 | return self.data.title(*args, **kargs) | ||
351 | |||
352 | def translate(self, *args, **kargs): | ||
353 | return self.data.translate(*args, **kargs) | ||
354 | |||
355 | def upper(self, *args, **kargs): | ||
356 | return self.data.upper(*args, **kargs) | ||
357 | |||
358 | def zfill(self, *args, **kargs): | ||
359 | return self.data.zfill(*args, **kargs) | ||
360 | |||
361 | class HimoAsciiError(Exception): | ||
362 | pass | ||
diff --git a/examples/config/config.cfg b/examples/config/config.cfg new file mode 100644 index 0000000..36b0414 --- /dev/null +++ b/examples/config/config.cfg | |||
@@ -0,0 +1,29 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | |||
19 | [title] | ||
20 | foo=bar | ||
21 | |||
22 | |||
23 | [test_db] | ||
24 | protocol=postgresql | ||
25 | hostname=127.0.0.1 | ||
26 | username=test | ||
27 | password=test | ||
28 | port=12345 | ||
29 | database=testing | ||
diff --git a/examples/config/connect b/examples/config/connect new file mode 100644 index 0000000..36b0414 --- /dev/null +++ b/examples/config/connect | |||
@@ -0,0 +1,29 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | |||
19 | [title] | ||
20 | foo=bar | ||
21 | |||
22 | |||
23 | [test_db] | ||
24 | protocol=postgresql | ||
25 | hostname=127.0.0.1 | ||
26 | username=test | ||
27 | password=test | ||
28 | port=12345 | ||
29 | database=testing | ||
diff --git a/examples/example_01.py b/examples/example_01.py new file mode 100644 index 0000000..7915e5f --- /dev/null +++ b/examples/example_01.py | |||
@@ -0,0 +1,69 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # Copyright (C) 2010 Leonard Thomas | ||
3 | # | ||
4 | # This file is part of Dodai. | ||
5 | # | ||
6 | # Dodai is free software: you can redistribute it and/or modify | ||
7 | # it under the terms of the GNU General Public License as published by | ||
8 | # the Free Software Foundation, either version 3 of the License, or | ||
9 | # (at your option) any later version. | ||
10 | # | ||
11 | # Dodai is distributed in the hope that it will be useful, | ||
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | # GNU General Public License for more details. | ||
15 | # | ||
16 | # You should have received a copy of the GNU General Public License | ||
17 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
18 | |||
19 | |||
20 | ############################################################################## | ||
21 | # The following is for setting up the correct python path. Ignore this | ||
22 | # section for your project | ||
23 | import sys | ||
24 | import os.path as p | ||
25 | path = p.dirname(p.dirname(p.abspath(__file__))) | ||
26 | sys.path.append(path) | ||
27 | ############################################################################## | ||
28 | |||
29 | from dodai.config import Config | ||
30 | |||
31 | def main(config): | ||
32 | |||
33 | config.log.debug('testing one two three') | ||
34 | config.log.critical('testing of critical') | ||
35 | print config.__dict__ | ||
36 | |||
37 | |||
38 | |||
39 | if __name__ == "__main__": | ||
40 | |||
41 | config = Config() | ||
42 | config.options().add_quiet() | ||
43 | config.options().add_log_level() | ||
44 | config.options().parser.add_option('-c', '--crazy', dest='crazy', | ||
45 | default=False, help="Crazy mode") | ||
46 | config.set('crazy', config.options().get_options().crazy) | ||
47 | config.set('verbose', config.options().get_options().verbose) | ||
48 | |||
49 | |||
50 | path = p.join(p.dirname(p.abspath(__file__)), 'logs') | ||
51 | config.logs().set_directory(path) | ||
52 | config.logs().set_log_level(config.options().get_options().log_level) | ||
53 | log = config.logs().load(__file__) | ||
54 | config.logs().attach_file_handler(log, 'example.log') | ||
55 | config.logs().attach_screen_handler(log, 'critical') | ||
56 | config.set('log', log) | ||
57 | |||
58 | |||
59 | path = p.join(p.dirname(p.abspath(__file__)), 'config') | ||
60 | config.files().set_directory(path) | ||
61 | config.files().load('config.cfg') | ||
62 | foo = config.files().parser().get('title', 'foo') | ||
63 | config.set('foo', foo) | ||
64 | |||
65 | |||
66 | |||
67 | |||
68 | |||
69 | main(config()) | ||
diff --git a/examples/example_02.py b/examples/example_02.py new file mode 100644 index 0000000..2844121 --- /dev/null +++ b/examples/example_02.py | |||
@@ -0,0 +1,57 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # Copyright (C) 2010 Leonard Thomas | ||
3 | # | ||
4 | # This file is part of dodai. | ||
5 | # | ||
6 | # dodai is free software: you can redistribute it and/or modify | ||
7 | # it under the terms of the GNU General Public License as published by | ||
8 | # the Free Software Foundation, either version 3 of the License, or | ||
9 | # (at your option) any later version. | ||
10 | # | ||
11 | # Foobar is distributed in the hope that it will be useful, | ||
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | # GNU General Public License for more details. | ||
15 | # | ||
16 | # You should have received a copy of the GNU General Public License | ||
17 | # along with dodai. If not, see <http://www.gnu.org/licenses/>. | ||
18 | |||
19 | |||
20 | ############################################################################## | ||
21 | # The following is for setting up the correct python path. Ignore this | ||
22 | # section for your project | ||
23 | import sys | ||
24 | import os.path as p | ||
25 | path = p.dirname(p.dirname(p.abspath(__file__))) | ||
26 | sys.path.append(path) | ||
27 | ############################################################################## | ||
28 | |||
29 | """ | ||
30 | This example requires that you have sqlalchemy installed as well as the | ||
31 | psycopg2 package. | ||
32 | |||
33 | On ubuntu you can do: | ||
34 | apt-get install libpq-dev | ||
35 | easy_install psycopg2 | ||
36 | easy_install sqlalchemy | ||
37 | |||
38 | """ | ||
39 | |||
40 | |||
41 | from dodai.config import Config | ||
42 | |||
43 | |||
44 | def main(config): | ||
45 | print config.db.__dict__ | ||
46 | |||
47 | |||
48 | if __name__ == "__main__": | ||
49 | |||
50 | config = Config() | ||
51 | path = p.join(p.dirname(p.abspath(__file__)), 'config') | ||
52 | config.files().set_directory(path) | ||
53 | config.files().load('config.cfg') | ||
54 | config.dbs().add_config(config_parser=config.files().parser()) | ||
55 | db = config.dbs().load('test_db') | ||
56 | config.set('db', db) | ||
57 | main(config()) | ||
diff --git a/examples/example_03.py b/examples/example_03.py new file mode 100644 index 0000000..b94c39e --- /dev/null +++ b/examples/example_03.py | |||
@@ -0,0 +1,54 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # Copyright (C) 2010 Leonard Thomas | ||
3 | # | ||
4 | # This file is part of dodai. | ||
5 | # | ||
6 | # dodai is free software: you can redistribute it and/or modify | ||
7 | # it under the terms of the GNU General Public License as published by | ||
8 | # the Free Software Foundation, either version 3 of the License, or | ||
9 | # (at your option) any later version. | ||
10 | # | ||
11 | # Foobar is distributed in the hope that it will be useful, | ||
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | # GNU General Public License for more details. | ||
15 | # | ||
16 | # You should have received a copy of the GNU General Public License | ||
17 | # along with dodai. If not, see <http://www.gnu.org/licenses/>. | ||
18 | |||
19 | |||
20 | ############################################################################## | ||
21 | # The following is for setting up the correct python path. Ignore this | ||
22 | # section for your project | ||
23 | import sys | ||
24 | import os.path as p | ||
25 | path = p.dirname(p.dirname(p.abspath(__file__))) | ||
26 | sys.path.append(path) | ||
27 | ############################################################################## | ||
28 | |||
29 | """ | ||
30 | This example requires that you have sqlalchemy installed as well as the | ||
31 | psycopg2 package. | ||
32 | |||
33 | On ubuntu you can do: | ||
34 | apt-get install libpq-dev | ||
35 | easy_install psycopg2 | ||
36 | easy_install sqlalchemy | ||
37 | |||
38 | """ | ||
39 | |||
40 | from dodai import Configure | ||
41 | |||
42 | |||
43 | def main(config): | ||
44 | print config.db.engine | ||
45 | print config.db.session | ||
46 | print config.home_directory | ||
47 | |||
48 | if __name__ == "__main__": | ||
49 | |||
50 | config = Configure('test') | ||
51 | db = config.dbs().load('test_db') | ||
52 | config.set('db', db) | ||
53 | config.set('home_directory', config.home_directory) | ||
54 | main(config()) | ||
diff --git a/pavement.py b/pavement.py new file mode 100644 index 0000000..ff49926 --- /dev/null +++ b/pavement.py | |||
@@ -0,0 +1,116 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | PACKAGE = 'dodai' | ||
19 | LICENSE='GPLv3' | ||
20 | VERSION = '0.3' | ||
21 | AUTHOR='Leonard Thomas' | ||
22 | AUTHOR_EMAIL='six@choushi.net' | ||
23 | URL='http://code.google.com/p/dodai' | ||
24 | DOWNLOAD_URL = 'http://code.google.com/p/dodai/downloads/list' | ||
25 | PY_VERSION_LOW = '2.6.0' | ||
26 | PY_VERSION_HIGH = '3.0.0' | ||
27 | PLATFORMS = ['Linux'] | ||
28 | SETUP_REQUIRES=['sqlalchemy'] | ||
29 | CLASSIFIERS = [ | ||
30 | 'Development Status :: 4 - Beta', | ||
31 | 'Environment :: Console', | ||
32 | 'Intended Audience :: Developers', | ||
33 | 'License :: OSI Approved :: GNU Affero General Public License v3', | ||
34 | 'Natural Language :: English', | ||
35 | 'Operating System :: POSIX', | ||
36 | 'Operating System :: POSIX :: Linux', | ||
37 | 'Programming Language :: Python', | ||
38 | 'Programming Language :: Python :: 2.6', | ||
39 | 'Topic :: Database', | ||
40 | 'Topic :: Software Development', | ||
41 | 'Topic :: Software Development :: Libraries', | ||
42 | 'Topic :: Software Development :: Libraries :: Application Frameworks', | ||
43 | 'Topic :: Software Development :: Libraries :: Python Modules',] | ||
44 | DESCRIPTION = 'Tools for writing python scripts' | ||
45 | LONG_DESCRIPTION = "This module is to be a foundation to your command line "\ | ||
46 | "python scripts. This module provides for quick access to logger, "\ | ||
47 | "configparser, optionparse and databases via sqlalchemy."\ | ||
48 | |||
49 | |||
50 | |||
51 | import sys | ||
52 | import platform | ||
53 | import paver | ||
54 | import paver.setuputils | ||
55 | from paver.easy import options | ||
56 | from paver.easy import Bunch | ||
57 | from paver.easy import task | ||
58 | from paver.easy import needs | ||
59 | from paver.misctasks import generate_setup | ||
60 | from paver.misctasks import minilib | ||
61 | from setuptools import setup | ||
62 | from setuptools import find_packages | ||
63 | |||
64 | #from paver.easy import * | ||
65 | #from paver.misctasks import generate_setup, minilib | ||
66 | #from setuptools import setup, find_packages | ||
67 | #import paver.setuputils | ||
68 | paver.setuputils.install_distutils_tasks() | ||
69 | |||
70 | options( | ||
71 | setup=Bunch( | ||
72 | name=PACKAGE, | ||
73 | version=VERSION, | ||
74 | zip_safe=False, | ||
75 | description=DESCRIPTION, | ||
76 | author=AUTHOR, | ||
77 | author_email=AUTHOR_EMAIL, | ||
78 | url=URL, | ||
79 | download_url=DOWNLOAD_URL, | ||
80 | packages=find_packages(), | ||
81 | classifiers=CLASSIFIERS, | ||
82 | long_description=LONG_DESCRIPTION, | ||
83 | license=LICENSE, | ||
84 | setup_requires=SETUP_REQUIRES, | ||
85 | install_requires=[], | ||
86 | platforms = PLATFORMS | ||
87 | |||
88 | )) | ||
89 | |||
90 | |||
91 | def is_valid_version(): | ||
92 | if sys.version >= PY_VERSION_LOW and sys.version < PY_VERSION_HIGH: | ||
93 | return True | ||
94 | else: | ||
95 | return False | ||
96 | |||
97 | def is_valid_platform(): | ||
98 | if platform.system() in PLATFORMS: | ||
99 | return True | ||
100 | else: | ||
101 | return False | ||
102 | |||
103 | @task | ||
104 | def build(): | ||
105 | if not is_valid_version(): | ||
106 | raise Exception('Invalid Python version') | ||
107 | if not is_valid_platform(): | ||
108 | error='{0} not install on: {1}'.format(PACKAGE, platform.system()) | ||
109 | raise Exception(error) | ||
110 | |||
111 | |||
112 | @task | ||
113 | @needs('build', 'generate_setup', 'minilib', 'setuptools.command.sdist') | ||
114 | def sdist(): | ||
115 | """Overrides sdist to make sure that our setup.py is generated.""" | ||
116 | pass | ||
diff --git a/test/config/connection b/test/config/connection new file mode 100644 index 0000000..36b0414 --- /dev/null +++ b/test/config/connection | |||
@@ -0,0 +1,29 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | |||
19 | [title] | ||
20 | foo=bar | ||
21 | |||
22 | |||
23 | [test_db] | ||
24 | protocol=postgresql | ||
25 | hostname=127.0.0.1 | ||
26 | username=test | ||
27 | password=test | ||
28 | port=12345 | ||
29 | database=testing | ||
diff --git a/test/test_config/config b/test/test_config/config new file mode 100644 index 0000000..d3b7019 --- /dev/null +++ b/test/test_config/config | |||
@@ -0,0 +1,19 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | [test_section] | ||
19 | foo=bar | ||
diff --git a/test/test_config/config.cfg b/test/test_config/config.cfg new file mode 100644 index 0000000..14764ae --- /dev/null +++ b/test/test_config/config.cfg | |||
@@ -0,0 +1,67 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | [testing] | ||
19 | foo=bar | ||
20 | |||
21 | |||
22 | |||
23 | [test_db] | ||
24 | protocol=postgresql | ||
25 | hostname=127.0.0.1 | ||
26 | username=test | ||
27 | password=test | ||
28 | port=12345 | ||
29 | database=testing | ||
30 | schema=tesuto | ||
31 | |||
32 | [test_db_two] | ||
33 | protocol=postgre | ||
34 | protocol_extra=psycopg2 | ||
35 | hostname=127.0.0.1 | ||
36 | username=test | ||
37 | password=test | ||
38 | port=12345 | ||
39 | database=testing | ||
40 | |||
41 | [test_db_three] | ||
42 | protocol=postgresss | ||
43 | hostname=127.0.0.1 | ||
44 | username=test | ||
45 | password=test | ||
46 | port=12345 | ||
47 | database=testing | ||
48 | |||
49 | [test_db_four] | ||
50 | protocol=postgre | ||
51 | hostname=127.0.0.1 | ||
52 | username=test | ||
53 | password=test | ||
54 | port=tea | ||
55 | database=testing | ||
56 | |||
57 | [test_db_five] | ||
58 | protocol=postgres | ||
59 | hostname=127.0.0.1 | ||
60 | username=test | ||
61 | password=test | ||
62 | port=12345ad | ||
63 | database=testing | ||
64 | |||
65 | [test_db_six] | ||
66 | protocol=sqlite | ||
67 | filename=/tmp/test | ||
diff --git a/test/test_config/test_db.py b/test/test_config/test_db.py new file mode 100644 index 0000000..ed46eae --- /dev/null +++ b/test/test_config/test_db.py | |||
@@ -0,0 +1,106 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | import unittest | ||
19 | import os | ||
20 | from dodai.config.db import ConfigDb | ||
21 | from dodai.config.db import ConfigDbFile | ||
22 | from dodai.config.db import BaseConfigDb | ||
23 | from dodai.config.db import NotConfigParserObject | ||
24 | from dodai.config.db import InvalidProtocolException | ||
25 | from dodai.config.db import InvalidPortException | ||
26 | from dodai.config.db import UnknownHandlerException | ||
27 | from dodai.config.db import UnknownConnectionException | ||
28 | from dodai.config.db.sa import Sa | ||
29 | from dodai.config.file import ConfigFile | ||
30 | from dodai.db import Db | ||
31 | |||
32 | class TestConfigDb(unittest.TestCase): | ||
33 | |||
34 | |||
35 | def setUp(self): | ||
36 | self.config_db = ConfigDb() | ||
37 | config = ConfigFile() | ||
38 | config.set_directory(os.path.dirname(os.path.abspath(__file__))) | ||
39 | config.load('config.cfg') | ||
40 | self.parser = config.parser() | ||
41 | |||
42 | def test_setup(self): | ||
43 | obj = self.config_db._handlers['sa'][0] | ||
44 | self.assertTrue(obj == Sa) | ||
45 | |||
46 | def test_register_handler(self): | ||
47 | self.config_db.register_handler('foo', Exception) | ||
48 | self.assertTrue('foo' in self.config_db._handlers.keys()) | ||
49 | |||
50 | def test_add_config_one(self): | ||
51 | self.config_db.add_config(config_parser=self.parser) | ||
52 | self.assertTrue('test_db' in self.config_db.connections.keys()) | ||
53 | |||
54 | def test_add_config_two(self): | ||
55 | self.failUnlessRaises(NotConfigParserObject, self.config_db.add_config, | ||
56 | config_parser='blah') | ||
57 | |||
58 | def test_load_one(self): | ||
59 | self.config_db.add_config(config_parser=self.parser) | ||
60 | obj = self.config_db.load('test_db') | ||
61 | self.assertTrue(isinstance(obj, Db)) | ||
62 | |||
63 | def test_load_two(self): | ||
64 | self.config_db.add_config(config_parser=self.parser) | ||
65 | obj = self.config_db.load('test_db') | ||
66 | obj = self.config_db.load('test_db') | ||
67 | self.assertTrue(isinstance(obj, Db)) | ||
68 | |||
69 | def test_load_handler(self): | ||
70 | self.failUnlessRaises(UnknownHandlerException, | ||
71 | self.config_db._load_handler, 'test') | ||
72 | |||
73 | def test_clean_protocol_one(self): | ||
74 | self.config_db.add_config(config_parser=self.parser) | ||
75 | obj = self.config_db.load('test_db_two') | ||
76 | self.assertTrue(isinstance(obj, Db)) | ||
77 | |||
78 | def test_clean_protocol_one(self): | ||
79 | self.config_db.add_config(config_parser=self.parser) | ||
80 | obj = self.config_db.load('test_db_two') | ||
81 | self.assertTrue(isinstance(obj, Db)) | ||
82 | |||
83 | def test_clean_protocol_two(self): | ||
84 | self.config_db.add_config(config_parser=self.parser) | ||
85 | self.failUnlessRaises(InvalidProtocolException, self.config_db.load, | ||
86 | 'test_db_three') | ||
87 | |||
88 | def test_clean_port_one(self): | ||
89 | obj = BaseConfigDb() | ||
90 | data = obj._clean_port('ad') | ||
91 | self.assertTrue(data == None) | ||
92 | |||
93 | def test_clean_port_two(self): | ||
94 | obj = BaseConfigDb() | ||
95 | data = obj._clean_port(None) | ||
96 | self.assertTrue(data == None) | ||
97 | |||
98 | def test_clean_port_three(self): | ||
99 | obj = BaseConfigDb() | ||
100 | self.failUnlessRaises(InvalidPortException, obj._clean_port, 66666) | ||
101 | |||
102 | |||
103 | def test_file_load_one(self): | ||
104 | self.config_db.add_config(config_parser=self.parser) | ||
105 | obj = self.config_db.load('test_db_six') | ||
106 | self.assertTrue(isinstance(obj, Db)) | ||
diff --git a/test/test_config/test_file.py b/test/test_config/test_file.py new file mode 100644 index 0000000..1ed014e --- /dev/null +++ b/test/test_config/test_file.py | |||
@@ -0,0 +1,101 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | import unittest | ||
19 | import os | ||
20 | from dodai.config.file import ConfigFile | ||
21 | from dodai.config.file import DirectoryDoesNotExistException | ||
22 | from dodai.config.file import DirectoryNotSetException | ||
23 | from dodai.config.file import InvalidDirectoryException | ||
24 | from dodai.config.file import FileDoesNotExistException | ||
25 | from dodai.config.file import NoFilesToLoadException | ||
26 | import ConfigParser | ||
27 | |||
28 | class TestConfigFile(unittest.TestCase): | ||
29 | |||
30 | def setUp(self): | ||
31 | self.obj = ConfigFile() | ||
32 | self.path = os.path.dirname(__file__) | ||
33 | self.filename = 'config' | ||
34 | self.filepath = os.path.join(self.path, self.filename) | ||
35 | next_file = os.path.join(self.path, 'config.cfg') | ||
36 | self.paths = [self.filepath, next_file] | ||
37 | |||
38 | def test_file_add(self): | ||
39 | self.obj.add_file(self.filepath) | ||
40 | paths = [self.filepath] | ||
41 | files = self.obj.get_files() | ||
42 | self.assertEqual(files, paths) | ||
43 | |||
44 | def test_double_file_add(self): | ||
45 | self.obj.add_file(self.filepath) | ||
46 | self.obj.add_file(self.filepath) | ||
47 | paths = [self.filepath] | ||
48 | files = self.obj.get_files() | ||
49 | self.assertEqual(files, paths) | ||
50 | |||
51 | def test_file_does_not_exist(self): | ||
52 | path = os.path.join(self.path, 'foo') | ||
53 | self.failUnlessRaises(FileDoesNotExistException, | ||
54 | self.obj.add_file, path) | ||
55 | |||
56 | def test_multiple_file_add(self): | ||
57 | self.obj.add_file(self.paths) | ||
58 | files = self.obj.get_files() | ||
59 | self.assertEqual(files, self.paths) | ||
60 | |||
61 | def test_empty_parser(self): | ||
62 | self.failUnlessRaises(Exception, self.obj.parser) | ||
63 | |||
64 | def test_parser(self): | ||
65 | self.obj.add_file(self.filepath) | ||
66 | parser = self.obj.parser() | ||
67 | self.assertTrue(isinstance(parser, ConfigParser.ConfigParser)) | ||
68 | |||
69 | def test_parser_error(self): | ||
70 | self.failUnlessRaises(NoFilesToLoadException, self.obj.parser) | ||
71 | |||
72 | def test_set_directory(self): | ||
73 | self.obj.set_directory(self.path) | ||
74 | dir = self.obj.get_directory() | ||
75 | self.assertEqual(dir, self.path) | ||
76 | |||
77 | def test_invalid_directory(self): | ||
78 | self.failUnlessRaises(InvalidDirectoryException, | ||
79 | self.obj.set_directory, self.filepath) | ||
80 | |||
81 | def test_directory_does_not_exist(self): | ||
82 | path = os.path.join(self.path, 'nowayjose') | ||
83 | self.failUnlessRaises(DirectoryDoesNotExistException, | ||
84 | self.obj.set_directory, path) | ||
85 | |||
86 | def test_load(self): | ||
87 | self.obj.set_directory(self.path) | ||
88 | self.obj.load(self.filename) | ||
89 | check = [self.filepath] | ||
90 | self.assertEqual(check, self.obj.get_files()) | ||
91 | |||
92 | def test_no_directory_set(self): | ||
93 | self.failUnlessRaises(DirectoryNotSetException, | ||
94 | self.obj.load, self.filename) | ||
95 | |||
96 | def test_reset_parser(self): | ||
97 | self.obj.add_file(self.filepath) | ||
98 | self.obj.parser() | ||
99 | self.obj.add_file(self.paths) | ||
100 | self.obj.parser() | ||
101 | self.assertEqual(self.obj.files_loaded, self.obj.get_files()) | ||
diff --git a/test/test_config/test_init.py b/test/test_config/test_init.py new file mode 100644 index 0000000..92b44c6 --- /dev/null +++ b/test/test_config/test_init.py | |||
@@ -0,0 +1,62 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | import unittest | ||
19 | from dodai.config import Config | ||
20 | from dodai.config.option import ConfigOption | ||
21 | from dodai.config.file import ConfigFile | ||
22 | from dodai.config.log import ConfigLog | ||
23 | from dodai.config import ConfigResults | ||
24 | from dodai.config.db import ConfigDb | ||
25 | |||
26 | class TestConfig(unittest.TestCase): | ||
27 | |||
28 | def setUp(self): | ||
29 | self.obj = Config() | ||
30 | |||
31 | def test_set_one(self): | ||
32 | self.obj.set('foo', 'bar') | ||
33 | self.assertTrue('foo' in self.obj.vars.keys()) | ||
34 | |||
35 | def test_set_two(self): | ||
36 | self.obj.set('foo', 'bar') | ||
37 | self.assertTrue('bar' == self.obj.vars['foo']) | ||
38 | |||
39 | def test_options(self): | ||
40 | obj = self.obj.options() | ||
41 | self.assertTrue(isinstance(obj, ConfigOption)) | ||
42 | |||
43 | def test_files(self): | ||
44 | obj = self.obj.files() | ||
45 | self.assertTrue(isinstance(obj, ConfigFile)) | ||
46 | |||
47 | def test_logs(self): | ||
48 | obj = self.obj.logs() | ||
49 | self.assertTrue(isinstance(obj, ConfigLog)) | ||
50 | |||
51 | def test_call_one(self): | ||
52 | obj = self.obj() | ||
53 | self.assertTrue(isinstance(obj, ConfigResults)) | ||
54 | |||
55 | def test_call_two(self): | ||
56 | self.obj.set('foo', 'bar') | ||
57 | obj = self.obj() | ||
58 | self.assertTrue(obj.foo == 'bar') | ||
59 | |||
60 | def test_db_one(self): | ||
61 | obj = self.obj.dbs() | ||
62 | self.assertTrue(isinstance(obj, ConfigDb)) | ||
diff --git a/test/test_config/test_log.py b/test/test_config/test_log.py new file mode 100644 index 0000000..d3c46bc --- /dev/null +++ b/test/test_config/test_log.py | |||
@@ -0,0 +1,147 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | import unittest | ||
19 | import os | ||
20 | import logging | ||
21 | from logging import Logger | ||
22 | from dodai.config.log import ConfigLog | ||
23 | from dodai.config.log import NoDirectoryExistException | ||
24 | from dodai.config.log import DirectoryNotSetException | ||
25 | from dodai.config.log import InvalidLevelException | ||
26 | from logging.handlers import RotatingFileHandler | ||
27 | from logging import StreamHandler | ||
28 | |||
29 | class TestConfigLog(unittest.TestCase): | ||
30 | |||
31 | |||
32 | def setUp(self): | ||
33 | self.obj = ConfigLog() | ||
34 | self.path = os.path.dirname(__file__) | ||
35 | self.filename = 'test_log_file' | ||
36 | self.filepath = os.path.join(self.path, self.filename) | ||
37 | |||
38 | def tearDown(self): | ||
39 | if os.path.isfile(self.filepath): | ||
40 | os.remove(self.filepath) | ||
41 | |||
42 | def test_set_log_level_one(self): | ||
43 | self.obj.set_log_level(logging.INFO) | ||
44 | self.assertTrue(self.obj.log_level == logging.INFO) | ||
45 | |||
46 | def test_set_log_level_two(self): | ||
47 | self.obj.set_log_level('wArnIng') | ||
48 | self.assertTrue(self.obj.log_level == logging.WARNING) | ||
49 | |||
50 | def test_set_log_level_three(self): | ||
51 | default = self.obj.log_level | ||
52 | self.obj.set_log_level('i08w9umY3ngas') | ||
53 | self.assertTrue(self.obj.log_level == default) | ||
54 | |||
55 | def test_fetch_log_level_one(self): | ||
56 | level = self.obj._fetch_log_level(logging.DEBUG) | ||
57 | self.assertTrue(level == logging.DEBUG) | ||
58 | |||
59 | def test_fetch_log_level_two(self): | ||
60 | level = self.obj._fetch_log_level('ErRoR') | ||
61 | self.assertTrue(level == logging.ERROR) | ||
62 | |||
63 | def test_fetch_log_level_three(self): | ||
64 | self.failUnlessRaises(InvalidLevelException, | ||
65 | self.obj._fetch_log_level, | ||
66 | 'ba_ri08w9as') | ||
67 | |||
68 | def test_get_file_message_format(self): | ||
69 | default = self.obj.LEVELS[logging.DEBUG][1] | ||
70 | out = self.obj.get_file_message_format(logging.DEBUG) | ||
71 | self.assertTrue(default == out) | ||
72 | |||
73 | def test_get_screen_message_format(self): | ||
74 | default = self.obj.LEVELS[logging.WARNING][2] | ||
75 | out = self.obj.get_screen_message_format(logging.WARNING) | ||
76 | self.assertTrue(default == out) | ||
77 | |||
78 | def test_set_directory_one(self): | ||
79 | self.obj.set_directory(self.path) | ||
80 | self.assertTrue(self.obj.directory == self.path) | ||
81 | |||
82 | def test_set_directory_two(self): | ||
83 | self.failUnlessRaises(NoDirectoryExistException, | ||
84 | self.obj.set_directory, | ||
85 | __file__) | ||
86 | |||
87 | def test_load_one(self): | ||
88 | log = self.obj.load('test') | ||
89 | self.assertTrue(isinstance(log, Logger)) | ||
90 | |||
91 | def test_build_filepath_one(self): | ||
92 | path = self.obj._build_filepath(self.filepath) | ||
93 | self.assertTrue(self.filepath == path) | ||
94 | |||
95 | def test_build_filepath_two(self): | ||
96 | self.obj.set_directory(self.path) | ||
97 | path = self.obj._build_filepath(self.filename) | ||
98 | self.assertTrue(self.filepath == path) | ||
99 | |||
100 | def test_build_filepath_three(self): | ||
101 | self.failUnlessRaises(NoDirectoryExistException, | ||
102 | self.obj._build_filepath, | ||
103 | os.path.join(__file__, 'blah')) | ||
104 | |||
105 | def test_build_filepath_four(self): | ||
106 | self.failUnlessRaises(DirectoryNotSetException, | ||
107 | self.obj._build_filepath, | ||
108 | self.filename) | ||
109 | |||
110 | def test_attach_file_handler(self): | ||
111 | self.obj.set_log_level(logging.WARNING) | ||
112 | self.obj.set_directory(self.path) | ||
113 | log = self.obj.load('test') | ||
114 | self.obj.attach_file_handler(log, self.filename) | ||
115 | handlers = log.handlers | ||
116 | has_stream = False | ||
117 | for handle in handlers: | ||
118 | print handle | ||
119 | if isinstance(handle, RotatingFileHandler): | ||
120 | has_stream = True | ||
121 | self.assertTrue(has_stream, 'RotatingFileHandler is missing') | ||
122 | |||
123 | def test_attach_screen_handler_one(self): | ||
124 | self.obj.set_log_level(logging.DEBUG) | ||
125 | self.obj.set_directory(self.path) | ||
126 | log = self.obj.load('testing') | ||
127 | self.obj.attach_screen_handler(log, logging.CRITICAL) | ||
128 | handlers = log.handlers | ||
129 | has_stream = False | ||
130 | for handle in handlers: | ||
131 | print handle | ||
132 | if isinstance(handle, StreamHandler): | ||
133 | has_stream = True | ||
134 | self.assertTrue(has_stream, 'StreamHandler is missing') | ||
135 | |||
136 | def test_attach_screen_handler_two(self): | ||
137 | self.obj.set_log_level(logging.DEBUG) | ||
138 | self.obj.set_directory(self.path) | ||
139 | log = self.obj.load('testing') | ||
140 | self.obj.attach_screen_handler(log) | ||
141 | handlers = log.handlers | ||
142 | has_stream = False | ||
143 | for handle in handlers: | ||
144 | print handle | ||
145 | if isinstance(handle, StreamHandler): | ||
146 | has_stream = True | ||
147 | self.assertTrue(has_stream, 'StreamHandler is missing') | ||
diff --git a/test/test_config/test_option.py b/test/test_config/test_option.py new file mode 100644 index 0000000..3fc9e6f --- /dev/null +++ b/test/test_config/test_option.py | |||
@@ -0,0 +1,53 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | import unittest | ||
19 | from dodai.config.option import ConfigOption | ||
20 | from optparse import OptionParser | ||
21 | |||
22 | class TestConfigOption(unittest.TestCase): | ||
23 | |||
24 | def setUp(self): | ||
25 | self.obj = ConfigOption() | ||
26 | |||
27 | def test_parser(self): | ||
28 | self.assertTrue(isinstance(self.obj.parser, OptionParser)) | ||
29 | |||
30 | def test_add_quiet(self): | ||
31 | self.obj.add_quiet() | ||
32 | self.assertTrue(self.obj.parser.has_option('-q')) | ||
33 | |||
34 | def test_add_verbose(self): | ||
35 | self.obj.add_verbose() | ||
36 | self.assertTrue(self.obj.parser.has_option('-v')) | ||
37 | |||
38 | def test_add_log_level(self): | ||
39 | self.obj.add_log_level('critical') | ||
40 | self.assertTrue(self.obj.parser.has_option('-l')) | ||
41 | |||
42 | def test_add_setup(self): | ||
43 | self.obj.add_setup() | ||
44 | self.assertTrue(self.obj.parser.has_option('--setup')) | ||
45 | |||
46 | def test_get_args(self): | ||
47 | args = self.obj.get_args() | ||
48 | self.assertTrue(args == []) | ||
49 | |||
50 | def test_get_options(self): | ||
51 | self.obj.add_quiet() | ||
52 | options = self.obj.get_options() | ||
53 | self.assertTrue(options.verbose == True) | ||
diff --git a/test/test_config/test_sections.py b/test/test_config/test_sections.py new file mode 100644 index 0000000..2aba3c7 --- /dev/null +++ b/test/test_config/test_sections.py | |||
@@ -0,0 +1,114 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | import sys | ||
19 | import os | ||
20 | import ConfigParser | ||
21 | import unittest | ||
22 | path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..')) | ||
23 | sys.path.append(path) | ||
24 | from dodai.tools.himo import Himo | ||
25 | from dodai.config.sections import ConfigSections | ||
26 | |||
27 | |||
28 | class TestSections(unittest.TestCase): | ||
29 | |||
30 | def setUp(self): | ||
31 | path = os.path.dirname(__file__) | ||
32 | filepath = os.path.join(path, 'config.cfg') | ||
33 | self.parser = ConfigParser.ConfigParser() | ||
34 | self.parser.readfp(open(filepath)) | ||
35 | self.sections = ConfigSections(Himo) | ||
36 | |||
37 | def test_call(self): | ||
38 | self.sections(self.parser) | ||
39 | count = len(self.parser.sections()) | ||
40 | self.assertEqual(count, len(self.sections)) | ||
41 | |||
42 | def test_iterator(self): | ||
43 | result = True | ||
44 | for section in self.sections: | ||
45 | if not section.get_title() in self.parser.sections(): | ||
46 | result = False | ||
47 | self.assertTrue(result==True) | ||
48 | |||
49 | def test_get_section(self): | ||
50 | self.sections(self.parser) | ||
51 | self.sections(self.parser) | ||
52 | check = self.sections.get_section('test_db') | ||
53 | self.assertEqual(check.get_title(), 'test_db') | ||
54 | |||
55 | def test_build_string_object(self): | ||
56 | sections = ConfigSections() | ||
57 | sections(self.parser) | ||
58 | count = len(self.parser.sections()) | ||
59 | self.assertEqual(count, len(sections)) | ||
60 | |||
61 | def test_getitem(self): | ||
62 | self.sections(self.parser) | ||
63 | title = self.sections['test_db'].get_title() | ||
64 | self.assertEqual(title, 'test_db') | ||
65 | |||
66 | def test_getattr(self): | ||
67 | self.sections(self.parser) | ||
68 | title = self.sections.test_db.get_title() | ||
69 | self.assertEqual(title, 'test_db') | ||
70 | |||
71 | def test_get_keys(self): | ||
72 | self.sections(self.parser) | ||
73 | keys = self.sections.keys() | ||
74 | self.assertTrue(len(keys)) | ||
75 | |||
76 | def test_section_object_one(self): | ||
77 | self.sections(self.parser) | ||
78 | keys = self.sections.test_db.keys() | ||
79 | self.assertTrue(len(keys)) | ||
80 | |||
81 | def test_section_object_two(self): | ||
82 | self.sections(self.parser) | ||
83 | keys = self.sections.test_db.___options___.keys() | ||
84 | self.assertTrue(len(keys)) | ||
85 | |||
86 | def test_section_object_three(self): | ||
87 | self.sections(self.parser) | ||
88 | self.sections.test_db.___blah___ = 'test' | ||
89 | val = self.sections.test_db.__getattr__('___blah___') | ||
90 | self.assertTrue(val == 'test') | ||
91 | |||
92 | def test_section_object_four(self): | ||
93 | self.sections(self.parser) | ||
94 | self.sections.test_db.foo = 'bar' | ||
95 | val = self.sections.test_db.__getattr__('foo') | ||
96 | self.assertTrue(val == 'bar') | ||
97 | |||
98 | def test_section_object_five(self): | ||
99 | self.sections(self.parser) | ||
100 | keys = [] | ||
101 | for key in self.sections.test_db: | ||
102 | keys.append(key) | ||
103 | self.assertTrue(keys) | ||
104 | |||
105 | def test_section_object_six(self): | ||
106 | self.sections(self.parser) | ||
107 | self.sections.test_db.foo = 'bar' | ||
108 | val = self.sections.test_db['foo'] | ||
109 | self.assertTrue(val == 'bar') | ||
110 | |||
111 | |||
112 | |||
113 | if __name__ == '__main__': | ||
114 | unittest.main() | ||
diff --git a/test/test_dodai.py b/test/test_dodai.py new file mode 100644 index 0000000..a521a38 --- /dev/null +++ b/test/test_dodai.py | |||
@@ -0,0 +1,38 @@ | |||
1 | # Copyright (C) 2010 Leonard Thomas | ||
2 | # | ||
3 | # This file is part of Dodai. | ||
4 | # | ||
5 | # Dodai is free software: you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation, either version 3 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # Dodai is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with Dodai. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | import unittest | ||
19 | import os | ||
20 | from dodai import Configure | ||
21 | |||
22 | class TestConfigure(unittest.TestCase): | ||
23 | |||
24 | def setUp(self): | ||
25 | path = os.path.dirname(os.path.abspath(__file__)) | ||
26 | path = os.path.join(path, 'config') | ||
27 | filename = os.path.join(path, 'connection') | ||
28 | self.filename = filename | ||
29 | self.obj = Configure('test', config_files=[filename]) | ||
30 | |||
31 | def test_results(self): | ||
32 | files = self.obj.config_files | ||
33 | self.assertTrue(len(files) == 1) | ||
34 | |||
35 | def test_add_files(self): | ||
36 | self.obj._add_files(self.filename) | ||
37 | files = self.obj.config_files | ||
38 | self.assertTrue(len(files) == 1) | ||