Ticket #645: class-module.patch

File class-module.patch, 27.2 KB (added by Sune Kirkeby <sune.kirkeby@…>, 19 years ago)
  • django/contrib/comments/models/comments.py

    ==== Patch <class-module> level 1
    Source: d410f328-f502-0410-afc1-bf1322476e67:/django/patches/class-module:2921
    Target: d410f328-f502-0410-afc1-bf1322476e67:/django/trunk:2920
    Log:
     r2906@moria:  sune | 2005-10-18 21:58:25 +0200
     Create patch-branch for "class MODULE" as discussed in
     http://tinyurl.com/bv7fy (googlegroups).
     r2921@moria:  sune | 2005-10-18 23:33:19 +0200
     Implement "class MODEL"; removing support for _module_ and module_constants.
    
    === django/contrib/comments/models/comments.py
    ==================================================================
     
    2727    site = meta.ForeignKey(core.Site)
    2828    class META:
    2929        db_table = 'comments'
    30         module_constants = {
    31             # min. and max. allowed dimensions for photo resizing (in pixels)
    32             'MIN_PHOTO_DIMENSION': 5,
    33             'MAX_PHOTO_DIMENSION': 1000,
    34 
    35             # option codes for comment-form hidden fields
    36             'PHOTOS_REQUIRED': 'pr',
    37             'PHOTOS_OPTIONAL': 'pa',
    38             'RATINGS_REQUIRED': 'rr',
    39             'RATINGS_OPTIONAL': 'ra',
    40             'IS_PUBLIC': 'ip',
    41         }
    4230        ordering = ('-submit_date',)
    4331        admin = meta.Admin(
    4432            fields = (
     
    11199            (self.get_user().username, self.submit_date,
    112100            self.comment, self.get_site().domain, self.get_absolute_url())
    113101
    114     def _module_get_security_hash(options, photo_options, rating_options, target):
    115         """
    116         Returns the MD5 hash of the given options (a comma-separated string such as
    117         'pa,ra') and target (something like 'lcom.eventtimes:5157'). Used to
    118         validate that submitted form options have not been tampered-with.
    119         """
    120         from django.conf.settings import SECRET_KEY
    121         import md5
    122         return md5.new(options + photo_options + rating_options + target + SECRET_KEY).hexdigest()
     102    class MODULE:
     103        # min. and max. allowed dimensions for photo resizing (in pixels)
     104        MIN_PHOTO_DIMENSION = 5
     105        MAX_PHOTO_DIMENSION = 1000
    123106
    124     def _module_get_rating_options(rating_string):
    125         """
    126         Given a rating_string, this returns a tuple of (rating_range, options).
    127         >>> s = "scale:1-10|First_category|Second_category"
    128         >>> get_rating_options(s)
    129         ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ['First category', 'Second category'])
    130         """
    131         rating_range, options = rating_string.split('|', 1)
    132         rating_range = range(int(rating_range[6:].split('-')[0]), int(rating_range[6:].split('-')[1])+1)
    133         choices = [c.replace('_', ' ') for c in options.split('|')]
    134         return rating_range, choices
     107        # option codes for comment-form hidden fields
     108        PHOTOS_REQUIRED = 'pr'
     109        PHOTOS_OPTIONAL = 'pa'
     110        RATINGS_REQUIRED = 'rr'
     111        RATINGS_OPTIONAL = 'ra'
     112        IS_PUBLIC = 'ip'
    135113
    136     def _module_get_list_with_karma(**kwargs):
    137         """
    138         Returns a list of Comment objects matching the given lookup terms, with
    139         _karma_total_good and _karma_total_bad filled.
    140         """
    141         kwargs.setdefault('select', {})
    142         kwargs['select']['_karma_total_good'] = 'SELECT COUNT(*) FROM comments_karma WHERE comments_karma.comment_id=comments.id AND score=1'
    143         kwargs['select']['_karma_total_bad'] = 'SELECT COUNT(*) FROM comments_karma WHERE comments_karma.comment_id=comments.id AND score=-1'
    144         return get_list(**kwargs)
     114        def get_security_hash(options, photo_options, rating_options, target):
     115            """
     116            Returns the MD5 hash of the given options (a comma-separated string such as
     117            'pa,ra') and target (something like 'lcom.eventtimes:5157'). Used to
     118            validate that submitted form options have not been tampered-with.
     119            """
     120            from django.conf.settings import SECRET_KEY
     121            import md5
     122            return md5.new(options + photo_options + rating_options + target + SECRET_KEY).hexdigest()
    145123
    146     def _module_user_is_moderator(user):
    147         from django.conf.settings import COMMENTS_MODERATORS_GROUP
    148         if user.is_superuser:
    149             return True
    150         for g in user.get_group_list():
    151             if g.id == COMMENTS_MODERATORS_GROUP:
     124        def get_rating_options(rating_string):
     125            """
     126            Given a rating_string, this returns a tuple of (rating_range, options).
     127            >>> s = "scale:1-10|First_category|Second_category"
     128            >>> get_rating_options(s)
     129            ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ['First category', 'Second category'])
     130            """
     131            rating_range, options = rating_string.split('|', 1)
     132            rating_range = range(int(rating_range[6:].split('-')[0]), int(rating_range[6:].split('-')[1])+1)
     133            choices = [c.replace('_', ' ') for c in options.split('|')]
     134            return rating_range, choices
     135
     136        def get_list_with_karma(**kwargs):
     137            """
     138            Returns a list of Comment objects matching the given lookup terms, with
     139            _karma_total_good and _karma_total_bad filled.
     140            """
     141            kwargs.setdefault('select', {})
     142            kwargs['select']['_karma_total_good'] = 'SELECT COUNT(*) FROM comments_karma WHERE comments_karma.comment_id=comments.id AND score=1'
     143            kwargs['select']['_karma_total_bad'] = 'SELECT COUNT(*) FROM comments_karma WHERE comments_karma.comment_id=comments.id AND score=-1'
     144            return get_list(**kwargs)
     145
     146        def user_is_moderator(user):
     147            from django.conf.settings import COMMENTS_MODERATORS_GROUP
     148            if user.is_superuser:
    152149                return True
    153         return False
     150            for g in user.get_group_list():
     151                if g.id == COMMENTS_MODERATORS_GROUP:
     152                    return True
     153            return False
    154154
    155155class FreeComment(meta.Model):
    156156    # A FreeComment is a comment by a non-registered user.
     
    206206    class META:
    207207        module_name = 'karma'
    208208        unique_together = (('user', 'comment'),)
    209         module_constants = {
    210             # what users get if they don't have any karma
    211             'DEFAULT_KARMA': 5,
    212             'KARMA_NEEDED_BEFORE_DISPLAYED': 3,
    213         }
    214209
    215210    def __repr__(self):
    216211        return "%d rating by %s" % (self.score, self.get_user())
    217212
    218     def _module_vote(user_id, comment_id, score):
    219         try:
    220             karma = get_object(comment__id__exact=comment_id, user__id__exact=user_id)
    221         except KarmaScoreDoesNotExist:
    222             karma = KarmaScore(None, user_id, comment_id, score, datetime.datetime.now())
    223             karma.save()
    224         else:
    225             karma.score = score
    226             karma.scored_date = datetime.datetime.now()
    227             karma.save()
     213    class MODULE:
     214        # what users get if they don't have any karma
     215        DEFAULT_KARMA = 5
     216        KARMA_NEEDED_BEFORE_DISPLAYED = 3
    228217
    229     def _module_get_pretty_score(score):
    230         """
    231         Given a score between -1 and 1 (inclusive), returns the same score on a
    232         scale between 1 and 10 (inclusive), as an integer.
    233         """
    234         if score is None:
    235             return DEFAULT_KARMA
    236         return int(round((4.5 * score) + 5.5))
     218        def vote(user_id, comment_id, score):
     219            try:
     220                karma = get_object(comment__id__exact=comment_id, user__id__exact=user_id)
     221            except KarmaScoreDoesNotExist:
     222                karma = KarmaScore(None, user_id, comment_id, score, datetime.datetime.now())
     223                karma.save()
     224            else:
     225                karma.score = score
     226                karma.scored_date = datetime.datetime.now()
     227                karma.save()
    237228
     229        def get_pretty_score(score):
     230            """
     231            Given a score between -1 and 1 (inclusive), returns the same score on a
     232            scale between 1 and 10 (inclusive), as an integer.
     233            """
     234            if score is None:
     235                return DEFAULT_KARMA
     236            return int(round((4.5 * score) + 5.5))
     237
    238238class UserFlag(meta.Model):
    239239    user = meta.ForeignKey(auth.User)
    240240    comment = meta.ForeignKey(Comment)
     
    246246    def __repr__(self):
    247247        return "Flag by %r" % self.get_user()
    248248
    249     def _module_flag(comment, user):
    250         """
    251         Flags the given comment by the given user. If the comment has already
    252         been flagged by the user, or it was a comment posted by the user,
    253         nothing happens.
    254         """
    255         if int(comment.user_id) == int(user.id):
    256             return # A user can't flag his own comment. Fail silently.
    257         try:
    258             f = get_object(user__id__exact=user.id, comment__id__exact=comment.id)
    259         except UserFlagDoesNotExist:
    260             from django.core.mail import mail_managers
    261             f = UserFlag(None, user.id, comment.id, None)
    262             message = 'This comment was flagged by %s:\n\n%s' % (user.username, comment.get_as_text())
    263             mail_managers('Comment flagged', message, fail_silently=True)
    264             f.save()
     249    class MODULE:
     250        def flag(comment, user):
     251            """
     252            Flags the given comment by the given user. If the comment has already
     253            been flagged by the user, or it was a comment posted by the user,
     254            nothing happens.
     255            """
     256            if int(comment.user_id) == int(user.id):
     257                return # A user can't flag his own comment. Fail silently.
     258            try:
     259                f = get_object(user__id__exact=user.id, comment__id__exact=comment.id)
     260            except UserFlagDoesNotExist:
     261                from django.core.mail import mail_managers
     262                f = UserFlag(None, user.id, comment.id, None)
     263                message = 'This comment was flagged by %s:\n\n%s' % (user.username, comment.get_as_text())
     264                mail_managers('Comment flagged', message, fail_silently=True)
     265                f.save()
    265266
    266267class ModeratorDeletion(meta.Model):
    267268    user = meta.ForeignKey(auth.User, verbose_name='moderator')
  • django/models/core.py

    === django/models/core.py
    ==================================================================
     
    1010    def __repr__(self):
    1111        return self.domain
    1212
    13     def _module_get_current():
    14         "Returns the current site, according to the SITE_ID constant."
    15         from django.conf.settings import SITE_ID
    16         return get_object(pk=SITE_ID)
     13    class MODULE:
     14        def get_current():
     15            "Returns the current site, according to the SITE_ID constant."
     16            from django.conf.settings import SITE_ID
     17            return get_object(pk=SITE_ID)
    1718
    1819class Package(meta.Model):
    1920    label = meta.CharField(maxlength=20, primary_key=True)
     
    104105    session_key = meta.CharField(maxlength=40, primary_key=True)
    105106    session_data = meta.TextField()
    106107    expire_date = meta.DateTimeField()
    107     class META:
    108         module_constants = {
    109             'base64': base64,
    110             'md5': md5,
    111             'pickle': pickle,
    112             'random': random,
    113             'sys': sys,
    114         }
    115108
    116109    def get_decoded(self):
    117110        from django.conf.settings import SECRET_KEY
     
    122115            raise SuspiciousOperation, "User tampered with session cookie."
    123116        return pickle.loads(pickled)
    124117
    125     def _module_encode(session_dict):
    126         "Returns the given session dictionary pickled and encoded as a string."
    127         from django.conf.settings import SECRET_KEY
    128         pickled = pickle.dumps(session_dict)
    129         pickled_md5 = md5.new(pickled + SECRET_KEY).hexdigest()
    130         return base64.encodestring(pickled + pickled_md5)
     118    class MODULE:
     119        base64 = base64
     120        md5 = md5
     121        pickle = pickle
     122        random = random
     123        sys = sys
    131124
    132     def _module_get_new_session_key():
    133         "Returns session key that isn't being used."
    134         from django.conf.settings import SECRET_KEY
    135         # The random module is seeded when this Apache child is created.
    136         # Use person_id and SECRET_KEY as added salt.
    137         while 1:
    138             session_key = md5.new(str(random.randint(0, sys.maxint - 1)) + SECRET_KEY).hexdigest()
    139             try:
    140                 get_object(session_key__exact=session_key)
    141             except SessionDoesNotExist:
    142                 break
    143         return session_key
     125        def encode(session_dict):
     126            "Returns the given session dictionary pickled and encoded as a string."
     127            from django.conf.settings import SECRET_KEY
     128            pickled = pickle.dumps(session_dict)
     129            pickled_md5 = md5.new(pickled + SECRET_KEY).hexdigest()
     130            return base64.encodestring(pickled + pickled_md5)
    144131
    145     def _module_save(session_key, session_dict, expire_date):
    146         s = Session(session_key, encode(session_dict), expire_date)
    147         if session_dict:
    148             s.save()
    149         else:
    150             s.delete() # Clear sessions with no data.
    151         return s
     132        def get_new_session_key():
     133            "Returns session key that isn't being used."
     134            from django.conf.settings import SECRET_KEY
     135            # The random module is seeded when this Apache child is created.
     136            # Use person_id and SECRET_KEY as added salt.
     137            while 1:
     138                session_key = md5.new(str(random.randint(0, sys.maxint - 1)) + SECRET_KEY).hexdigest()
     139                try:
     140                    get_object(session_key__exact=session_key)
     141                except SessionDoesNotExist:
     142                    break
     143            return session_key
     144
     145        def save(session_key, session_dict, expire_date):
     146            s = Session(session_key, encode(session_dict), expire_date)
     147            if session_dict:
     148                s.save()
     149            else:
     150                s.delete() # Clear sessions with no data.
     151            return s
  • django/models/auth.py

    === django/models/auth.py
    ==================================================================
     
    3939        help_text="In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in.")
    4040    user_permissions = meta.ManyToManyField(Permission, blank=True, filter_interface=meta.HORIZONTAL)
    4141    class META:
    42         module_constants = {
    43             'SESSION_KEY': '_auth_user_id',
    44         }
    4542        ordering = ('username',)
    4643        exceptions = ('SiteProfileNotAvailable',)
    4744        admin = meta.Admin(
     
    154151                    raise SiteProfileNotAvailable
    155152        return self._profile_cache
    156153
    157     def _module_create_user(username, email, password):
    158         "Creates and saves a User with the given username, e-mail and password."
    159         import md5
    160         password_md5 = md5.new(password).hexdigest()
    161         now = datetime.datetime.now()
    162         user = User(None, username, '', '', email.strip().lower(), password_md5, False, True, False, now, now)
    163         user.save()
    164         return user
     154    class MODULE:
     155        SESSION_KEY = '_auth_user_id'
    165156
    166     def _module_make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
    167         "Generates a random password with the given length and given allowed_chars"
    168         # Note that default value of allowed_chars does not have "I" or letters
    169         # that look like it -- just to avoid confusion.
    170         from random import choice
    171         return ''.join([choice(allowed_chars) for i in range(length)])
     157        def create_user(username, email, password):
     158            "Creates and saves a User with the given username, e-mail and password."
     159            import md5
     160            password_md5 = md5.new(password).hexdigest()
     161            now = datetime.datetime.now()
     162            user = User(None, username, '', '', email.strip().lower(), password_md5, False, True, False, now, now)
     163            user.save()
     164            return user
    172165
     166        def make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
     167            "Generates a random password with the given length and given allowed_chars"
     168            # Note that default value of allowed_chars does not have "I" or letters
     169            # that look like it -- just to avoid confusion.
     170            from random import choice
     171            return ''.join([choice(allowed_chars) for i in range(length)])
     172
    173173class Message(meta.Model):
    174174    user = meta.ForeignKey(User)
    175175    message = meta.TextField()
     
    190190        verbose_name_plural = 'log entries'
    191191        db_table = 'auth_admin_log'
    192192        ordering = ('-action_time',)
    193         module_constants = {
    194             'ADDITION': 1,
    195             'CHANGE': 2,
    196             'DELETION': 3,
    197         }
    198193
    199194    def __repr__(self):
    200195        return str(self.action_time)
     
    219214        """
    220215        return "%s/%s/%s/" % (self.get_content_type().package, self.get_content_type().python_module_name, self.object_id)
    221216
    222     def _module_log_action(user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
    223         e = LogEntry(None, None, user_id, content_type_id, object_id, object_repr[:200], action_flag, change_message)
    224         e.save()
     217    class MODULE:
     218        ADDITION = 1
     219        CHANGE = 2
     220        DELETION = 3
     221
     222        def log_action(user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
     223            e = LogEntry(None, None, user_id, content_type_id, object_id, object_repr[:200], action_flag, change_message)
     224            e.save()
  • django/core/meta/__init__.py

    === django/core/meta/__init__.py
    ==================================================================
     
    151151        fields=None, ordering=None, unique_together=None, admin=None, has_related_links=False,
    152152        where_constraints=None, object_name=None, app_label=None,
    153153        exceptions=None, permissions=None, get_latest_by=None,
    154         order_with_respect_to=None, module_constants=None):
     154        order_with_respect_to=None):
    155155
    156156        # Save the original function args, for use by copy(). Note that we're
    157157        # NOT using copy.deepcopy(), because that would create a new copy of
     
    194194            self.ordering = ('_order',)
    195195        else:
    196196            self.order_with_respect_to = None
    197         self.module_constants = module_constants or {}
    198197        self.admin = admin
    199198
    200199        # Calculate one_to_one_field.
     
    463462                permissions = meta_attrs.pop('permissions', None),
    464463                get_latest_by = meta_attrs.pop('get_latest_by', None),
    465464                order_with_respect_to = meta_attrs.pop('order_with_respect_to', None),
    466                 module_constants = meta_attrs.pop('module_constants', None),
    467465            )
    468466
    469467        if meta_attrs != {}:
     
    476474        else:
    477475            new_mod = types.ModuleType(opts.module_name)
    478476
     477        # Update new module with attributes from 'class MODULE'
     478        try:
     479            module_attrs = attrs.pop('MODULE').__dict__
     480            del module_attrs['__module__']
     481            del module_attrs['__doc__']
     482        except KeyError:
     483            module_attrs = {}
     484        new_mod.__dict__.update(module_attrs)
     485
     486        # Extract functions into custom_functions for later massage
     487        custom_functions = {}
     488        for k, v in new_mod.__dict__.items():
     489            if hasattr(v, 'custom') or isinstance(v, types.FunctionType):
     490                del new_mod.__dict__[k]
     491                custom_functions[k] = v
     492
    479493        # Collect any/all custom class methods and module functions, and move
    480494        # them to a temporary holding variable. We'll deal with them later.
    481495        if replaces_module is not None:
    482             # Initialize these values to the base class' custom_methods and
    483             # custom_functions.
     496            # Initialize these values to the base class' custom_methods.
    484497            custom_methods = dict([(k, v) for k, v in new_mod.Klass.__dict__.items() if hasattr(v, 'custom')])
    485             custom_functions = dict([(k, v) for k, v in new_mod.__dict__.items() if hasattr(v, 'custom')])
    486498        else:
    487             custom_methods, custom_functions = {}, {}
     499            custom_methods = {}
    488500        manipulator_methods = {}
    489501        for k, v in attrs.items():
    490502            if k in ('__module__', '__init__', '_overrides', '__doc__'):
     
    494506            # it's a custom function/method.
    495507            v.custom = True
    496508            if k.startswith(MODEL_FUNCTIONS_PREFIX):
    497                 custom_functions[k[len(MODEL_FUNCTIONS_PREFIX):]] = v
    498             elif k.startswith(MANIPULATOR_FUNCTIONS_PREFIX):
     509                raise AssertionError, '%s prefix deprecated' % MODEL_FUNCTIONS_PREFIX
     510            if k.startswith(MANIPULATOR_FUNCTIONS_PREFIX):
    499511                manipulator_methods[k[len(MANIPULATOR_FUNCTIONS_PREFIX):]] = v
    500512            else:
    501513                custom_methods[k] = v
     
    515527            exc.__module__ = MODEL_PREFIX + '.' + opts.module_name # Set this explicitly, as above.
    516528            setattr(new_mod, exception_name, exc)
    517529
    518         # Create any module-level constants, if applicable.
    519         for k, v in opts.module_constants.items():
    520             setattr(new_mod, k, v)
    521 
    522530        # Create the default class methods.
    523531        attrs['__init__'] = curry(method_init, opts)
    524532        attrs['__eq__'] = curry(method_eq, opts)
  • tests/testapp/models/custom_methods.py

    === tests/testapp/models/custom_methods.py
    ==================================================================
     
    5050        # positional arguments to Article().
    5151        return [Article(*row) for row in cursor.fetchall()]
    5252
     53    class MODULE:
     54        answer = 42
     55
     56        def the_answer():
     57            return answer
     58
     59        def the_question():
     60            return the_answer() / 7
     61
    5362API_TESTS = """
    5463# Create a couple of Articles.
    5564>>> from datetime import date
     
    6978[Area man programs in Python]
    7079>>> b.get_articles_from_same_day_2()
    7180[Area man programs in Python]
     81
     82>>> articles.the_answer()
     8342
     84>>> articles.the_question()
     856
    7286"""
Back to Top