From 8e524449cfc34f4b015be21f4045d1377da7b2f5 Mon Sep 17 00:00:00 2001 From: David Rousselie Date: Wed, 9 Aug 2006 22:18:49 +0200 Subject: [PATCH] First import create base structure with a first unit test darcs-hash:20060809201849-86b55-11969bedd39c27882a6b467c7360ac31fef9b6be.gz --- COPYING | 340 ++++++++++++++++++ README | 13 + TODO | 0 coverage.py | 596 ++++++++++++++++++++++++++++++++ run_tests.py | 55 +++ src/jcl/__init__.py | 0 src/jcl/jabber/__init__.py | 0 src/jcl/jabber/component.py | 74 ++++ src/jcl/jabber/x.py | 129 +++++++ src/jcl/model/__init__.py | 0 src/jcl/model/account.py | 30 ++ tests/__init__.py | 0 tests/jcl/__init__.py | 0 tests/jcl/jabber/__init__.py | 0 tests/jcl/jabber/test_feeder.py | 38 ++ 15 files changed, 1275 insertions(+) create mode 100644 COPYING create mode 100644 README create mode 100644 TODO create mode 100755 coverage.py create mode 100644 run_tests.py create mode 100644 src/jcl/__init__.py create mode 100644 src/jcl/jabber/__init__.py create mode 100644 src/jcl/jabber/component.py create mode 100644 src/jcl/jabber/x.py create mode 100644 src/jcl/model/__init__.py create mode 100644 src/jcl/model/account.py create mode 100644 tests/__init__.py create mode 100644 tests/jcl/__init__.py create mode 100644 tests/jcl/jabber/__init__.py create mode 100644 tests/jcl/jabber/test_feeder.py diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/README b/README new file mode 100644 index 0000000..c5466ac --- /dev/null +++ b/README @@ -0,0 +1,13 @@ +Jabber Component Library +======================== + +Present a higher level component framework for developing Jabber +component. + +Here is the class the implement to create a new Jabber component (be +sure to override every methods) : +- a class inheriting from JabberComponent +- a Feeder (inheriting from Feeder) +- a Sender (inheriting from Sender) + + diff --git a/TODO b/TODO new file mode 100644 index 0000000..e69de29 diff --git a/coverage.py b/coverage.py new file mode 100755 index 0000000..abd95da --- /dev/null +++ b/coverage.py @@ -0,0 +1,596 @@ +#!/usr/bin/python +# +# Perforce Defect Tracking Integration Project +# +# +# COVERAGE.PY -- COVERAGE TESTING +# +# Gareth Rees, Ravenbrook Limited, 2001-12-04 +# +# +# 1. INTRODUCTION +# +# This module provides coverage testing for Python code. +# +# The intended readership is all Python developers. +# +# This document is not confidential. +# +# See [GDR 2001-12-04a] for the command-line interface, programmatic +# interface and limitations. See [GDR 2001-12-04b] for requirements and +# design. + +"""Usage: + +coverage.py -x MODULE.py [ARG1 ARG2 ...] + Execute module, passing the given command-line arguments, collecting + coverage data. + +coverage.py -e + Erase collected coverage data. + +coverage.py -r [-m] FILE1 FILE2 ... + Report on the statement coverage for the given files. With the -m + option, show line numbers of the statements that weren't executed. + +coverage.py -a [-d dir] FILE1 FILE2 ... + Make annotated copies of the given files, marking statements that + are executed with > and statements that are missed with !. With + the -d option, make the copies in that directory. Without the -d + option, make each copy in the same directory as the original. + +Coverage data is saved in the file .coverage by default. Set the +COVERAGE_FILE environment variable to save it somewhere else.""" + +import os +import re +import string +import sys +import types + + +# 2. IMPLEMENTATION +# +# This uses the "singleton" pattern. +# +# The word "morf" means a module object (from which the source file can +# be deduced by suitable manipulation of the __file__ attribute) or a +# filename. +# +# When we generate a coverage report we have to canonicalize every +# filename in the coverage dictionary just in case it refers to the +# module we are reporting on. It seems a shame to throw away this +# information so the data in the coverage dictionary is transferred to +# the 'cexecuted' dictionary under the canonical filenames. +# +# The coverage dictionary is called "c" and the trace function "t". The +# reason for these short names is that Python looks up variables by name +# at runtime and so execution time depends on the length of variables! +# In the bottleneck of this application it's appropriate to abbreviate +# names to increase speed. + +# A dictionary with an entry for (Python source file name, line number +# in that file) if that line has been executed. +c = {} + +# t(f, x, y). This method is passed to sys.settrace as a trace +# function. See [van Rossum 2001-07-20b, 9.2] for an explanation of +# sys.settrace and the arguments and return value of the trace function. +# See [van Rossum 2001-07-20a, 3.2] for a description of frame and code +# objects. + +def t(f, x, y): + c[(f.f_code.co_filename, f.f_lineno)] = 1 + return t + +the_coverage = None + +class coverage: + error = "coverage error" + + # Name of the cache file (unless environment variable is set). + cache_default = ".coverage" + + # Environment variable naming the cache file. + cache_env = "COVERAGE_FILE" + + # A map from canonical Python source file name to a dictionary in + # which there's an entry for each line number that has been + # executed. + cexecuted = {} + + # Cache of results of calling the analysis() method, so that you can + # specify both -r and -a without doing double work. + analysis_cache = {} + + # Cache of results of calling the canonical_filename() method, to + # avoid duplicating work. + canonical_filename_cache = {} + + def __init__(self): + global the_coverage + if the_coverage: + raise self.error, "Only one coverage object allowed." + self.cache = os.environ.get(self.cache_env, self.cache_default) + self.restore() + self.analysis_cache = {} + + def help(self, error=None): + if error: + print error + print + print __doc__ + sys.exit(1) + + def command_line(self): + import getopt + settings = {} + optmap = { + '-a': 'annotate', + '-d:': 'directory=', + '-e': 'erase', + '-h': 'help', + '-i': 'ignore-errors', + '-m': 'show-missing', + '-r': 'report', + '-x': 'execute', + } + short_opts = string.join(map(lambda o: o[1:], optmap.keys()), '') + long_opts = optmap.values() + options, args = getopt.getopt(sys.argv[1:], short_opts, + long_opts) + for o, a in options: + if optmap.has_key(o): + settings[optmap[o]] = 1 + elif optmap.has_key(o + ':'): + settings[optmap[o + ':']] = a + elif o[2:] in long_opts: + settings[o[2:]] = 1 + elif o[2:] + '=' in long_opts: + settings[o[2:]] = a + else: + self.help("Unknown option: '%s'." % o) + if settings.get('help'): + self.help() + for i in ['erase', 'execute']: + for j in ['annotate', 'report']: + if settings.get(i) and settings.get(j): + self.help("You can't specify the '%s' and '%s' " + "options at the same time." % (i, j)) + args_needed = (settings.get('execute') + or settings.get('annotate') + or settings.get('report')) + action = settings.get('erase') or args_needed + if not action: + self.help("You must specify at least one of -e, -x, -r, " + "or -a.") + if not args_needed and args: + self.help("Unexpected arguments %s." % args) + if settings.get('erase'): + self.erase() + if settings.get('execute'): + if not args: + self.help("Nothing to do.") + sys.argv = args + self.start() + import __main__ + sys.path[0] = os.path.dirname(sys.argv[0]) + execfile(sys.argv[0], __main__.__dict__) + if not args: + args = self.cexecuted.keys() + ignore_errors = settings.get('ignore-errors') + show_missing = settings.get('show-missing') + directory = settings.get('directory=') + if settings.get('report'): + self.report(args, show_missing, ignore_errors) + if settings.get('annotate'): + self.annotate(args, directory, ignore_errors) + + def start(self): + sys.settrace(t) + + def stop(self): + sys.settrace(None) + + def erase(self): + global c + c = {} + self.analysis_cache = {} + self.cexecuted = {} + if os.path.exists(self.cache): + os.remove(self.cache) + + # save(). Save coverage data to the coverage cache. + + def save(self): + self.canonicalize_filenames() + cache = open(self.cache, 'wb') + import marshal + marshal.dump(self.cexecuted, cache) + cache.close() + + # restore(). Restore coverage data from the coverage cache (if it + # exists). + + def restore(self): + global c + c = {} + self.cexecuted = {} + if not os.path.exists(self.cache): + return + try: + cache = open(self.cache, 'rb') + import marshal + cexecuted = marshal.load(cache) + cache.close() + if isinstance(cexecuted, types.DictType): + self.cexecuted = cexecuted + except: + pass + + # canonical_filename(filename). Return a canonical filename for the + # file (that is, an absolute path with no redundant components and + # normalized case). See [GDR 2001-12-04b, 3.3]. + + def canonical_filename(self, filename): + if not self.canonical_filename_cache.has_key(filename): + f = filename + if os.path.isabs(f) and not os.path.exists(f): + f = os.path.basename(f) + if not os.path.isabs(f): + for path in [os.curdir] + sys.path: + g = os.path.join(path, f) + if os.path.exists(g): + f = g + break + cf = os.path.normcase(os.path.abspath(f)) + self.canonical_filename_cache[filename] = cf + return self.canonical_filename_cache[filename] + + # canonicalize_filenames(). Copy results from "executed" to + # "cexecuted", canonicalizing filenames on the way. Clear the + # "executed" map. + + def canonicalize_filenames(self): + global c + for filename, lineno in c.keys(): + f = self.canonical_filename(filename) + if not self.cexecuted.has_key(f): + self.cexecuted[f] = {} + self.cexecuted[f][lineno] = 1 + c = {} + + # morf_filename(morf). Return the filename for a module or file. + + def morf_filename(self, morf): + if isinstance(morf, types.ModuleType): + if not hasattr(morf, '__file__'): + raise self.error, "Module has no __file__ attribute." + file = morf.__file__ + else: + file = morf + return self.canonical_filename(file) + + # analyze_morf(morf). Analyze the module or filename passed as + # the argument. If the source code can't be found, raise an error. + # Otherwise, return a pair of (1) the canonical filename of the + # source code for the module, and (2) a list of lines of statements + # in the source code. + + def analyze_morf(self, morf): + if self.analysis_cache.has_key(morf): + return self.analysis_cache[morf] + filename = self.morf_filename(morf) + ext = os.path.splitext(filename)[1] + if ext == '.pyc': + if not os.path.exists(filename[0:-1]): + raise self.error, ("No source for compiled code '%s'." + % filename) + filename = filename[0:-1] + elif ext != '.py': + raise self.error, "File '%s' not Python source." % filename + source = open(filename, 'r') + import parser + tree = parser.suite(source.read()).totuple(1) + source.close() + statements = {} + self.find_statements(tree, statements) + lines = statements.keys() + lines.sort() + result = filename, lines + self.analysis_cache[morf] = result + return result + + # find_statements(tree, dict). Find each statement in the parse + # tree and record the line on which the statement starts in the + # dictionary (by assigning it to 1). + # + # It works by walking the whole tree depth-first. Every time it + # comes across a statement (symbol.stmt -- this includes compound + # statements like 'if' and 'while') it calls find_statement, which + # descends the tree below the statement to find the first terminal + # token in that statement and record the lines on which that token + # was found. + # + # This algorithm may find some lines several times (because of the + # grammar production statement -> compound statement -> statement), + # but that doesn't matter because we record lines as the keys of the + # dictionary. + # + # See also [GDR 2001-12-04b, 3.2]. + + def find_statements(self, tree, dict): + import symbol, token + if token.ISNONTERMINAL(tree[0]): + for t in tree[1:]: + self.find_statements(t, dict) + if tree[0] == symbol.stmt: + self.find_statement(tree[1], dict) + elif (tree[0] == token.NAME + and tree[1] in ['elif', 'except', 'finally']): + dict[tree[2]] = 1 + + def find_statement(self, tree, dict): + import token + while token.ISNONTERMINAL(tree[0]): + tree = tree[1] + dict[tree[2]] = 1 + + # format_lines(statements, lines). Format a list of line numbers + # for printing by coalescing groups of lines as long as the lines + # represent consecutive statements. This will coalesce even if + # there are gaps between statements, so if statements = + # [1,2,3,4,5,10,11,12,13,14] and lines = [1,2,5,10,11,13,14] then + # format_lines will return "1-2, 5-11, 13-14". + + def format_lines(self, statements, lines): + pairs = [] + i = 0 + j = 0 + start = None + pairs = [] + while i < len(statements) and j < len(lines): + if statements[i] == lines[j]: + if start == None: + start = lines[j] + end = lines[j] + j = j + 1 + elif start: + pairs.append((start, end)) + start = None + i = i + 1 + if start: + pairs.append((start, end)) + def stringify(pair): + start, end = pair + if start == end: + return "%d" % start + else: + return "%d-%d" % (start, end) + import string + return string.join(map(stringify, pairs), ", ") + + def analysis(self, morf): + filename, statements = self.analyze_morf(morf) + self.canonicalize_filenames() + if not self.cexecuted.has_key(filename): + self.cexecuted[filename] = {} + missing = [] + for line in statements: + if not self.cexecuted[filename].has_key(line): + missing.append(line) + return (filename, statements, missing, + self.format_lines(statements, missing)) + + def morf_name(self, morf): + if isinstance(morf, types.ModuleType): + return morf.__name__ + else: + return os.path.splitext(os.path.basename(morf))[0] + + def report(self, morfs, show_missing=1, ignore_errors=0): + if not isinstance(morfs, types.ListType): + morfs = [morfs] + max_name = max([5,] + map(len, map(self.morf_name, morfs))) + fmt_name = "%%- %ds " % max_name + fmt_err = fmt_name + "%s: %s" + header = fmt_name % "Name" + " Stmts Exec Cover" + fmt_coverage = fmt_name + "% 6d % 6d % 5d%%" + if show_missing: + header = header + " Missing" + fmt_coverage = fmt_coverage + " %s" + print header + print "-" * len(header) + total_statements = 0 + total_executed = 0 + for morf in morfs: + name = self.morf_name(morf) + try: + _, statements, missing, readable = self.analysis(morf) + n = len(statements) + m = n - len(missing) + if n > 0: + pc = 100.0 * m / n + else: + pc = 100.0 + args = (name, n, m, pc) + if show_missing: + args = args + (readable,) + print fmt_coverage % args + total_statements = total_statements + n + total_executed = total_executed + m + except KeyboardInterrupt: + raise + except: + if not ignore_errors: + type, msg = sys.exc_info()[0:2] + print fmt_err % (name, type, msg) + if len(morfs) > 1: + print "-" * len(header) + if total_statements > 0: + pc = 100.0 * total_executed / total_statements + else: + pc = 100.0 + args = ("TOTAL", total_statements, total_executed, pc) + if show_missing: + args = args + ("",) + print fmt_coverage % args + + # annotate(morfs, ignore_errors). + + blank_re = re.compile("\\s*(#|$)") + else_re = re.compile("\\s*else\\s*:\\s*(#|$)") + + def annotate(self, morfs, directory=None, ignore_errors=0): + for morf in morfs: + try: + filename, statements, missing, _ = self.analysis(morf) + source = open(filename, 'r') + if directory: + dest_file = os.path.join(directory, + os.path.basename(filename) + + ',cover') + else: + dest_file = filename + ',cover' + dest = open(dest_file, 'w') + lineno = 0 + i = 0 + j = 0 + covered = 1 + while 1: + line = source.readline() + if line == '': + break + lineno = lineno + 1 + while i < len(statements) and statements[i] < lineno: + i = i + 1 + while j < len(missing) and missing[j] < lineno: + j = j + 1 + if i < len(statements) and statements[i] == lineno: + covered = j >= len(missing) or missing[j] > lineno + if self.blank_re.match(line): + dest.write(' ') + elif self.else_re.match(line): + # Special logic for lines containing only + # 'else:'. See [GDR 2001-12-04b, 3.2]. + if i >= len(statements) and j >= len(missing): + dest.write('! ') + elif i >= len(statements) or j >= len(missing): + dest.write('> ') + elif statements[i] == missing[j]: + dest.write('! ') + else: + dest.write('> ') + elif covered: + dest.write('> ') + else: + dest.write('! ') + dest.write(line) + source.close() + dest.close() + except KeyboardInterrupt: + raise + except: + if not ignore_errors: + raise + + +# Singleton object. +the_coverage = coverage() + +# Module functions call methods in the singleton object. +def start(*args): return apply(the_coverage.start, args) +def stop(*args): return apply(the_coverage.stop, args) +def erase(*args): return apply(the_coverage.erase, args) +def analysis(*args): return apply(the_coverage.analysis, args) +def report(*args): return apply(the_coverage.report, args) + +# Save coverage data when Python exits. (The atexit module wasn't +# introduced until Python 2.0, so use sys.exitfunc when it's not +# available.) +try: + import atexit + atexit.register(the_coverage.save) +except ImportError: + sys.exitfunc = the_coverage.save + +# Command-line interface. +if __name__ == '__main__': + the_coverage.command_line() + + +# A. REFERENCES +# +# [GDR 2001-12-04a] "Statement coverage for Python"; Gareth Rees; +# Ravenbrook Limited; 2001-12-04; +# . +# +# [GDR 2001-12-04b] "Statement coverage for Python: design and +# analysis"; Gareth Rees; Ravenbrook Limited; 2001-12-04; +# . +# +# [van Rossum 2001-07-20a] "Python Reference Manual (releae 2.1.1)"; +# Guide van Rossum; 2001-07-20; +# . +# +# [van Rossum 2001-07-20b] "Python Library Reference"; Guido van Rossum; +# 2001-07-20; . +# +# +# B. DOCUMENT HISTORY +# +# 2001-12-04 GDR Created. +# +# 2001-12-06 GDR Added command-line interface and source code +# annotation. +# +# 2001-12-09 GDR Moved design and interface to separate documents. +# +# 2001-12-10 GDR Open cache file as binary on Windows. Allow +# simultaneous -e and -x, or -a and -r. +# +# 2001-12-12 GDR Added command-line help. Cache analysis so that it +# only needs to be done once when you specify -a and -r. +# +# 2001-12-13 GDR Improved speed while recording. Portable between +# Python 1.5.2 and 2.1.1. +# +# 2002-01-03 GDR Module-level functions work correctly. +# +# 2002-01-07 GDR Update sys.path when running a file with the -x option, +# so that it matches the value the program would get if it were run on +# its own. +# +# +# C. COPYRIGHT AND LICENCE +# +# Copyright 2001 Gareth Rees. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. +# +# +# +# $Id: coverage.py,v 1.1 2005/07/11 20:39:31 dax Exp $ diff --git a/run_tests.py b/run_tests.py new file mode 100644 index 0000000..70f44d1 --- /dev/null +++ b/run_tests.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +## +## run_tests.py +## Login : David Rousselie +## Started on Wed Aug 9 21:37:35 2006 David Rousselie +## $Id$ +## +## Copyright (C) 2006 David Rousselie +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## + +import coverage +coverage.erase() +coverage.start() +import logging +import unittest +from test import test_support + +import sys +sys.path.append("src") +reload(sys) +sys.setdefaultencoding('utf8') +del sys.setdefaultencoding + +import tests +from tests.jcl.jabber.test_feeder import * + +import jcl + +if __name__ == '__main__': + logger = logging.getLogger() + logger.addHandler(logging.StreamHandler()) + logger.setLevel(logging.INFO) + + feeder_suite = unittest.makeSuite(Feeder_TestCase, "test") + + jcl_suite = unittest.TestSuite((feeder_suite)) + test_support.run_suite(jcl_suite) + +coverage.stop() +coverage.analysis(jcl.jabber.component) +coverage.report([jcl.jabber.component]) + diff --git a/src/jcl/__init__.py b/src/jcl/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/jcl/jabber/__init__.py b/src/jcl/jabber/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/jcl/jabber/component.py b/src/jcl/jabber/component.py new file mode 100644 index 0000000..3278294 --- /dev/null +++ b/src/jcl/jabber/component.py @@ -0,0 +1,74 @@ +# -*- coding: UTF-8 -*- +## +## component.py +## Login : David Rousselie +## Started on Wed Aug 9 21:04:42 2006 David Rousselie +## $Id$ +## +## Copyright (C) 2006 David Rousselie +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## + +from jcl.model.account import * + +from pyxmpp.jid import JID +from pyxmpp.jabberd.component import Component + +class JabberComponent(object): + def __init__(self): + pass + +class Feeder(object): + def __init__(self): + pass + + def feed(self, account): + pass + +class Sender(object): + def __init__(self): + pass + + def send(self, to_account, message): + pass + + + +############################################################################### +# JCL implementation +############################################################################### +class JCLComponent(Component): + def __init__(self, + jid, + secret, + server, + port, + check_interval, + spool_dir, + storage, + name, + disco_category = "gateway", + disco_type = "headline"): + Component.__init__(self, \ + JID(jid), \ + secret, \ + port, \ + disco_category, \ + disco_type) + + def handle_tick(self): + for account in Account.select("*"): + for message in self.__jabber_component.feeder.feed(account): + self.__jabber_component.sender.send(account, message) diff --git a/src/jcl/jabber/x.py b/src/jcl/jabber/x.py new file mode 100644 index 0000000..a9e41d3 --- /dev/null +++ b/src/jcl/jabber/x.py @@ -0,0 +1,129 @@ +## +## x.py +## Login : David Rousselie +## Started on Fri Jan 7 11:06:42 2005 +## $Id: x.py,v 1.3 2005/09/18 20:24:07 dax Exp $ +## +## Copyright (C) 2005 +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## + +import sys +from pyxmpp.stanza import common_doc + +class Option(object): + def __init__(self, label, value): + self.__label = label + self.__value = value + + def get_xml(self, parent): + if parent is None: + option = common_doc.newChild(None, "option", None) + else: + option = parent.newChild(None, "option", None) + option.setProp("label", self.__label) + option.newChild(None, "value", self.__value) + return option + +class Field(object): + def __init__(self, type, label, var, value): + self.__type = type + self.__label = label + self.__var = var + self.value = value + self.__options = [] + + def add_option(self, label, value): + option = Option(label, value) + self.__options.append(option) + return option + + def get_xml(self, parent): + if parent is None: + raise Exception, "parent field should not be None" + else: + field = parent.newChild(None, "field", None) + field.setProp("type", self.__type) + if not self.__label is None: + field.setProp("label", self.__label) + if not self.__var is None: + field.setProp("var", self.__var) + if self.value: + field.newChild(None, "value", self.value) + for option in self.__options: + option.get_xml(field) + return field + +class X(object): + def __init__(self): + self.fields = {} + self.fields_tab = [] + self.title = None + self.instructions = None + self.type = None + self.xmlns = None + + def add_field(self, type = "fixed", label = None, var = None, value = ""): + field = Field(type, label, var, value) + self.fields[var] = field + # fields_tab exist to keep added fields order + self.fields_tab.append(field) + return field + + def attach_xml(self, iq): + node = iq.newChild(None, "x", None) + _ns = node.newNs(self.xmlns, None) + node.setNs(_ns) + if not self.title is None: + node.newTextChild(None, "title", self.title) + if not self.instructions is None: + node.newTextChild(None, "instructions", self.instructions) + for field in self.fields_tab: + field.get_xml(node) + return node + + def from_xml(self, node): + ## TODO : test node type and ns and clean that loop !!!! + while node and node.type != "element": + node = node.next + child = node.children + while child: + ## TODO : test child type (element) and ns (jabber:x:data) + if child.type == "element" and child.name == "field": + if child.hasProp("type"): + type = child.prop("type") + else: + type = "" + + if child.hasProp("label"): + label = child.prop("label") + else: + label = "" + + if child.hasProp("var"): + var = child.prop("var") + else: + var = "" + + xval = child.children + while xval and xval.name != "value": + xval = xval.next + if xval: + value = xval.getContent() + else: + value = "" + field = Field(type, label, var, value) + self.fields[var] = field + child = child.next diff --git a/src/jcl/model/__init__.py b/src/jcl/model/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/jcl/model/account.py b/src/jcl/model/account.py new file mode 100644 index 0000000..80bb4ec --- /dev/null +++ b/src/jcl/model/account.py @@ -0,0 +1,30 @@ +# -*- coding: UTF-8 -*- +## +## account.py +## Login : David Rousselie +## Started on Wed Aug 9 21:04:42 2006 David Rousselie +## $Id$ +## +## Copyright (C) 2006 David Rousselie +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## + +from sqlobject import * + +class Account(SQLObject): + jid = StringCol() + name = StringCol() + + diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/jcl/__init__.py b/tests/jcl/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/jcl/jabber/__init__.py b/tests/jcl/jabber/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/jcl/jabber/test_feeder.py b/tests/jcl/jabber/test_feeder.py new file mode 100644 index 0000000..e26f751 --- /dev/null +++ b/tests/jcl/jabber/test_feeder.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +## +## test_feeder.py +## Login : David Rousselie +## Started on Wed Aug 9 21:34:26 2006 David Rousselie +## $Id$ +## +## Copyright (C) 2006 David Rousselie +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## + +import unittest +from sqlobject import * + +from jcl.jabber.component import Feeder +from jcl.model.account import Account + +class Feeder_TestCase(unittest.TestCase): + def setUp(self): + connection = sqlhub.processConnection = connectionForURI('sqlite:/:memory:') + Account.createTable() + + def test_feed_exist(self): + feeder = Feeder() + feeder.feed(Account(jid="test@jid.com", name="test")) + self.assertTrue(True)