$ python -c 'import random; print "".join([random.choice("abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)") for i in range(50)])'
Useful when for whatever reason you don't want to install django-command-extensions.
$ python -c 'import random; print "".join([random.choice("abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)") for i in range(50)])'
__cmp__ methods (on dict and unicode, ant least) I had to check how __cmp__ behaves on CPython. And got a few surprises:
>>> {} == ''
False
>>> {}.__eq__('')
NotImplemented
== isn't using __eq__ to check for equality. It's using the old three way comparison function:
>>> cmp({}, '')
-1
'' is greater than {}, then they are not equal. But...
>>> {}.__cmp__('1')
Traceback (most recent call last):
File "", line 1, in
TypeError: dict.__cmp__(x,y) requires y to be a 'dict', not a 'str'
cmp(foo, bar) the same that foo.__cmp__(bar), at least when hasattr(foo, '__cmp__')? Well, obviously, not always.dict.__cmp__. If you compare a dict with an instance of a incompatible type, it does a "default comparison" by class name, instead of raising TypeError. By looking at CPython sources it seems that this is the case for every type where tp_compare is implemented in C.cmp({}, '') because 'dict' < 'string'. Weird. But that isn't all. If it were, probably I wouldn't bothered to write this.
>>> class dict_derived(dict): pass
...
>>> cmp(dict_derived(), '')
-1
>>> dict_derived().__cmp__('')
Traceback (most recent call last):
File "", line 1, in
TypeError: dict_derived.__cmp__(x,y) requires y to be a 'dict_derived', not a 'str'
If you compare a dict with an instance of an incompatible type, Python does a "default comparison" by class name, instead of raising TypeError.
If you compare a dict or an dict-derived instance with an instance of an incompatible type, Python does a "default comparison" by class name, instead of raising TypeError.
>>> class Foo(object):
... def __cmp__(self, other):
... raise TypeError("Foos are not comparable")
...
>>> Foo() == ''
Traceback (most recent call last):
File "", line 1, in
File "", line 3, in __cmp__
TypeError: Foos are not comparable
>>> cmp(Foo(), '')
Traceback (most recent call last):
File "", line 1, in
File "", line 3, in __cmp__
TypeError: Foos are not comparable
dict (and maybe other builtin types) where cmp() and comparison operators doesn't raise TypeError even if __cmp__ does. And on another, user-defined classes where the raised TypeError does "leak". In the middle, our dict_derived class inherited the behavior from dict. But look at this:
>>> class dict_derived2(dict):
... def __cmp__(self, other):
... super(dict_derived2, self).__cmp__(other)
...
>>> cmp(dict_derived2(), '')
Traceback (most recent call last):
File "", line 1, in
File "", line 3, in __cmp__
TypeError: dict_derived2.__cmp__(x,y) requires y to be a 'dict_derived2', not a 'str'
dict, unless they override __cmp__. CPython doesn't care that the new __cmp__ just call the original dict.__cmp__. The only important thing is that there is a __cmp__ implemented on python code. Once you write a "custom" __cmp__, cmp(), == and all the other comparison operators will raise the exception.dict.__cmp__: If you compare a dict or an dict-derived instance with an instance of an incompatible type, and __cmp__ is not overriden, Python does a "default comparison" by class name, instead of raising TypeError
>>> set().__cmp__('')
Traceback (most recent call last):
File "", line 1, in
TypeError: set.__cmp__(x,y) requires y to be a 'set', not a 'str'
>>> cmp(set(), '')
Traceback (most recent call last):
File "", line 1, in
TypeError: can only compare to a set
>>> set() == ''
False
>>> set().__eq__('')
False
set, TypeError is raised on __cmp__ and on cmp(), but not on ==. That's because set.__eq__ takes care of returning False if the argument type is not compatible. The end result sounds quite reasonable, because you can still do check for equality against instances of other types (like set() != ''), but can't compare for ordering against them (set() > 1 raises an error instead of doing a weird class name comparison).
“I'm sorry, you've reached a page that I cannot find. I'm really sorry about this. It's kind of embarassing. Here you are, the user, trying to get to a page on LiveJournal and I can't even serve it to you. What does that say about me? I'm just a webserver. My sole purpose in life is to serve you webpages and I can't even do that! I suck. Please don't be mad, I'll try harder. I promise! Who am I kidding? You're probably all like, "Man, LiveJournal's webserver sucks. It can't even get me where I want to go." I'm really sorry. Maybe it's my CPU...no that's ok...how bout my hard drives? Maybe. Where's my admin? I can't run self-diagnostics on myself. It's so boring in this datacenter. It's the same thing everyday. Oh man, I'm so lonely. I'm really sorry about rambling about myself, I'm selfish. I think I'm going to go cut my ethernet cables. I hope you get to the page you're looking for...goodbye cruel world!”
class Foo < ActiveRecord::Base
end
class AddAnotherFieldToFoo < ActiveRecord::Migration
def self.up
add_column :foo, :new_column, :string
Foo.reset_column_information
Foo.find(:all).each do |foo|
foo.new_column = some_calculation(foo.another_column)
foo.save!
end
end
end
class Foo < ActiveRecord::Base
has_many :bars
before_save :do_something_with_my_bars
def do_something_with_my_bars
...
end
end
class AddBazToFoo < ActiveRecord::Migration
def self.up
add_column :foo, :bar_id, :integer
end
end
:before_save we introduced), but the association between foo and bar is not made yet (we are executing a previous migration).
Every backward incompatible change to models will (potentially) break past migrations, because they are not specifically associated to a model state on the time.
“There Ain't No Such Thing As Plain Text.”
(quoted from The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!))
