зеркало из https://github.com/mozilla/mozillians.git
Remove vendor/vendor-local dependencies.
This commit is contained in:
Родитель
276639f814
Коммит
3e9431ecf4
|
@ -1,52 +0,0 @@
|
|||
[submodule "vendor-local/src/django-statsd"]
|
||||
path = vendor-local/src/django-statsd
|
||||
url = https://github.com/andymckay/django-statsd/
|
||||
[submodule "vendor-local/src/django-autocomplete-light"]
|
||||
path = vendor-local/src/django-autocomplete-light
|
||||
url = git://github.com/yourlabs/django-autocomplete-light
|
||||
[submodule "vendor"]
|
||||
ignore = dirty
|
||||
path = vendor
|
||||
url = git://github.com/mozilla/playdoh-lib
|
||||
[submodule "vendor-local/src/elasticutils"]
|
||||
path = vendor-local/src/elasticutils
|
||||
url = git://github.com/mozilla/elasticutils
|
||||
[submodule "vendor-local/src/django-tastypie"]
|
||||
path = vendor-local/src/django-tastypie
|
||||
url = git://github.com/toastdriven/django-tastypie
|
||||
[submodule "vendor-local/src/pystatsd"]
|
||||
path = vendor-local/src/pystatsd
|
||||
url = git://github.com/jsocol/pystatsd
|
||||
[submodule "vendor-local/src/django-csp"]
|
||||
path = vendor-local/src/django-csp
|
||||
url = git://github.com/mozilla/django-csp
|
||||
[submodule "vendor-local/src/happyforms"]
|
||||
path = vendor-local/src/happyforms
|
||||
url = https://github.com/mozilla/happyforms.git
|
||||
[submodule "vendor-local/src/basket-client-submodule"]
|
||||
path = vendor-local/src/basket-client-submodule
|
||||
url = git://github.com/mozilla/basket-client.git
|
||||
[submodule "mozillians/static/mozillians/css/less-prefixer"]
|
||||
path = mozillians/static/mozillians/css/less-prefixer
|
||||
url = https://github.com/JoelSutherland/LESS-Prefixer.git
|
||||
[submodule "vendor-local/src/sorl-thumbnail"]
|
||||
path = vendor-local/src/sorl-thumbnail
|
||||
url = git://github.com/mariocesar/sorl-thumbnail
|
||||
[submodule "vendor-local/src/django-waffle"]
|
||||
path = vendor-local/src/django-waffle
|
||||
url = git://github.com/jsocol/django-waffle.git
|
||||
[submodule "vendor-local/src/django-browserid"]
|
||||
path = vendor-local/src/django-browserid
|
||||
url = git://github.com/mozilla/django-browserid/
|
||||
[submodule "vendor-local/src/elasticsearch-py"]
|
||||
path = vendor-local/src/elasticsearch-py
|
||||
url = git://github.com/elasticsearch/elasticsearch-py.git
|
||||
[submodule "vendor-local/src/urllib3"]
|
||||
path = vendor-local/src/urllib3
|
||||
url = git://github.com/shazow/urllib3.git
|
||||
[submodule "vendor-local/src/django"]
|
||||
path = vendor-local/src/django
|
||||
url = git://github.com/django/django.git
|
||||
[submodule "vendor-local/src/jingo"]
|
||||
path = vendor-local/src/jingo
|
||||
url = git://github.com/jbalogh/jingo.git
|
|
@ -1 +0,0 @@
|
|||
Subproject commit f441f348096a89811ebd7a29b5089ca3bde036c1
|
|
@ -30,7 +30,7 @@
|
|||
@import "sandstone/sandstone.less";
|
||||
@import "sandstone/sandstone-resp.less";
|
||||
@import "mosaic.less";
|
||||
@import "less-prefixer/prefixer.less";
|
||||
@import "prefixer.less";
|
||||
|
||||
/* Fonts
|
||||
==================== */
|
||||
|
|
|
@ -0,0 +1,370 @@
|
|||
//---------------------------------------------------
|
||||
// LESS Prefixer
|
||||
//---------------------------------------------------
|
||||
//
|
||||
// All of the CSS3 fun, none of the prefixes!
|
||||
//
|
||||
// As a rule, you can use the CSS properties you
|
||||
// would expect just by adding a '.':
|
||||
//
|
||||
// box-shadow => .box-shadow(@args)
|
||||
//
|
||||
// Also, when shorthand is available, arguments are
|
||||
// not parameterized. Learn CSS, not LESS Prefixer.
|
||||
//
|
||||
// -------------------------------------------------
|
||||
// TABLE OF CONTENTS
|
||||
// (*) denotes a syntax-sugar helper
|
||||
// -------------------------------------------------
|
||||
//
|
||||
// .animation(@args)
|
||||
// .animation-delay(@delay)
|
||||
// .animation-direction(@direction)
|
||||
// .animation-duration(@duration)
|
||||
// .animation-fill-mode(@mode)
|
||||
// .animation-iteration-count(@count)
|
||||
// .animation-name(@name)
|
||||
// .animation-play-state(@state)
|
||||
// .animation-timing-function(@function)
|
||||
// .background-size(@args)
|
||||
// .border-radius(@args)
|
||||
// .box-shadow(@args)
|
||||
// .inner-shadow(@args) *
|
||||
// .box-sizing(@args)
|
||||
// .border-box() *
|
||||
// .content-box() *
|
||||
// .columns(@args)
|
||||
// .column-count(@count)
|
||||
// .column-gap(@gap)
|
||||
// .column-rule(@args)
|
||||
// .column-width(@width)
|
||||
// .gradient(@default,@start,@stop) *
|
||||
// .linear-gradient-top(@default,@color1,@stop1,@color2,@stop2,[@color3,@stop3,@color4,@stop4])*
|
||||
// .linear-gradient-left(@default,@color1,@stop1,@color2,@stop2,[@color3,@stop3,@color4,@stop4])*
|
||||
// .opacity(@factor)
|
||||
// .transform(@args)
|
||||
// .transform-origin(@args)
|
||||
// .transform-style(@style)
|
||||
// .rotate(@deg)
|
||||
// .scale(@factor)
|
||||
// .translate(@x,@y)
|
||||
// .translate3d(@x,@y,@z)
|
||||
// .translateHardware(@x,@y) *
|
||||
// .text-shadow(@args)
|
||||
// .transition(@args)
|
||||
// .transition-delay(@delay)
|
||||
// .transition-duration(@duration)
|
||||
// .transition-property(@property)
|
||||
// .transition-timing-function(@function)
|
||||
//
|
||||
//
|
||||
//
|
||||
// Credit to LESS Elements for the motivation and
|
||||
// to CSS3Please.com for implementation.
|
||||
//
|
||||
// Copyright (c) 2012 Joel Sutherland
|
||||
// MIT Licensed:
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
//---------------------------------------------------
|
||||
|
||||
|
||||
// Animation
|
||||
|
||||
.animation(@args) {
|
||||
-webkit-animation: @args;
|
||||
-moz-animation: @args;
|
||||
-ms-animation: @args;
|
||||
-o-animation: @args;
|
||||
animation: @args;
|
||||
}
|
||||
.animation-delay(@delay) {
|
||||
-webkit-animation-delay: @delay;
|
||||
-moz-animation-delay: @delay;
|
||||
-ms-animation-delay: @delay;
|
||||
-o-animation-delay: @delay;
|
||||
animation-delay: @delay;
|
||||
}
|
||||
.animation-direction(@direction) {
|
||||
-webkit-animation-direction: @direction;
|
||||
-moz-animation-direction: @direction;
|
||||
-ms-animation-direction: @direction;
|
||||
-o-animation-direction: @direction;
|
||||
}
|
||||
.animation-duration(@duration) {
|
||||
-webkit-animation-duration: @duration;
|
||||
-moz-animation-duration: @duration;
|
||||
-ms-animation-duration: @duration;
|
||||
-o-animation-duration: @duration;
|
||||
}
|
||||
.animation-fill-mode(@mode) {
|
||||
-webkit-animation-fill-mode: @mode;
|
||||
-moz-animation-fill-mode: @mode;
|
||||
-ms-animation-fill-mode: @mode;
|
||||
-o-animation-fill-mode: @mode;
|
||||
animation-fill-mode: @mode;
|
||||
}
|
||||
.animation-iteration-count(@count) {
|
||||
-webkit-animation-iteration-count: @count;
|
||||
-moz-animation-iteration-count: @count;
|
||||
-ms-animation-iteration-count: @count;
|
||||
-o-animation-iteration-count: @count;
|
||||
animation-iteration-count: @count;
|
||||
}
|
||||
.animation-name(@name) {
|
||||
-webkit-animation-name: @name;
|
||||
-moz-animation-name: @name;
|
||||
-ms-animation-name: @name;
|
||||
-o-animation-name: @name;
|
||||
animation-name: @name;
|
||||
}
|
||||
.animation-play-state(@state) {
|
||||
-webkit-animation-play-state: @state;
|
||||
-moz-animation-play-state: @state;
|
||||
-ms-animation-play-state: @state;
|
||||
-o-animation-play-state: @state;
|
||||
animation-play-state: @state;
|
||||
}
|
||||
.animation-timing-function(@function) {
|
||||
-webkit-animation-timing-function: @function;
|
||||
-moz-animation-timing-function: @function;
|
||||
-ms-animation-timing-function: @function;
|
||||
-o-animation-timing-function: @function;
|
||||
animation-timing-function: @function;
|
||||
}
|
||||
|
||||
|
||||
// Background Size
|
||||
|
||||
.background-size(@args) {
|
||||
-webkit-background-size: @args;
|
||||
background-size: @args;
|
||||
}
|
||||
|
||||
|
||||
// Border Radius
|
||||
|
||||
.border-radius(@args) {
|
||||
-webkit-border-radius: @args;
|
||||
border-radius: @args;
|
||||
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
// Box Shadows
|
||||
|
||||
.box-shadow(@args) {
|
||||
-webkit-box-shadow: @args;
|
||||
box-shadow: @args;
|
||||
}
|
||||
.inner-shadow(@args) {
|
||||
.box-shadow(inset @args);
|
||||
}
|
||||
|
||||
|
||||
// Box Sizing
|
||||
|
||||
.box-sizing(@args) {
|
||||
-webkit-box-sizing: @args;
|
||||
-moz-box-sizing: @args;
|
||||
box-sizing: @args;
|
||||
}
|
||||
.border-box(){
|
||||
.box-sizing(border-box);
|
||||
}
|
||||
.content-box(){
|
||||
.box-sizing(content-box);
|
||||
}
|
||||
|
||||
|
||||
// Columns
|
||||
|
||||
.columns(@args) {
|
||||
-webkit-columns: @args;
|
||||
-moz-columns: @args;
|
||||
columns: @args;
|
||||
}
|
||||
.column-count(@count) {
|
||||
-webkit-column-count: @count;
|
||||
-moz-column-count: @count;
|
||||
column-count: @count;
|
||||
}
|
||||
.column-gap(@gap) {
|
||||
-webkit-column-gap: @gap;
|
||||
-moz-column-gap: @gap;
|
||||
column-gap: @gap;
|
||||
}
|
||||
.column-width(@width) {
|
||||
-webkit-column-width: @width;
|
||||
-moz-column-width: @width;
|
||||
column-width: @width;
|
||||
}
|
||||
.column-rule(@args) {
|
||||
-webkit-column-rule: @args;
|
||||
-moz-column-rule: @args;
|
||||
column-rule: @args;
|
||||
}
|
||||
|
||||
|
||||
// Gradients
|
||||
|
||||
.gradient(@default: #F5F5F5, @start: #EEE, @stop: #FFF) {
|
||||
.linear-gradient-top(@default,@start,0%,@stop,100%);
|
||||
}
|
||||
.linear-gradient-top(@default,@color1,@stop1,@color2,@stop2) {
|
||||
background-color: @default;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(@stop1, @color1), color-stop(@stop2 @color2));
|
||||
background-image: -webkit-linear-gradient(top, @color1 @stop1, @color2 @stop2);
|
||||
background-image: -moz-linear-gradient(top, @color1 @stop1, @color2 @stop2);
|
||||
background-image: -ms-linear-gradient(top, @color1 @stop1, @color2 @stop2);
|
||||
background-image: -o-linear-gradient(top, @color1 @stop1, @color2 @stop2);
|
||||
background-image: linear-gradient(top, @color1 @stop1, @color2 @stop2);
|
||||
}
|
||||
.linear-gradient-top(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3) {
|
||||
background-color: @default;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3));
|
||||
background-image: -webkit-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3);
|
||||
background-image: -moz-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3);
|
||||
background-image: -ms-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3);
|
||||
background-image: -o-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3);
|
||||
background-image: linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3);
|
||||
}
|
||||
.linear-gradient-top(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3,@color4,@stop4) {
|
||||
background-color: @default;
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3), color-stop(@stop4 @color4));
|
||||
background-image: -webkit-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4);
|
||||
background-image: -moz-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4);
|
||||
background-image: -ms-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4);
|
||||
background-image: -o-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4);
|
||||
background-image: linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4);
|
||||
}
|
||||
.linear-gradient-left(@default,@color1,@stop1,@color2,@stop2) {
|
||||
background-color: @default;
|
||||
background-image: -webkit-gradient(linear, left top, left top, color-stop(@stop1, @color1), color-stop(@stop2 @color2));
|
||||
background-image: -webkit-linear-gradient(left, @color1 @stop1, @color2 @stop2);
|
||||
background-image: -moz-linear-gradient(left, @color1 @stop1, @color2 @stop2);
|
||||
background-image: -ms-linear-gradient(left, @color1 @stop1, @color2 @stop2);
|
||||
background-image: -o-linear-gradient(left, @color1 @stop1, @color2 @stop2);
|
||||
background-image: linear-gradient(left, @color1 @stop1, @color2 @stop2);
|
||||
}
|
||||
.linear-gradient-left(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3) {
|
||||
background-color: @default;
|
||||
background-image: -webkit-gradient(linear, left top, left top, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3));
|
||||
background-image: -webkit-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3);
|
||||
background-image: -moz-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3);
|
||||
background-image: -ms-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3);
|
||||
background-image: -o-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3);
|
||||
background-image: linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3);
|
||||
}
|
||||
.linear-gradient-left(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3,@color4,@stop4) {
|
||||
background-color: @default;
|
||||
background-image: -webkit-gradient(linear, left top, left top, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3), color-stop(@stop4 @color4));
|
||||
background-image: -webkit-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4);
|
||||
background-image: -moz-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4);
|
||||
background-image: -ms-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4);
|
||||
background-image: -o-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4);
|
||||
background-image: linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4);
|
||||
}
|
||||
|
||||
|
||||
// Opacity
|
||||
|
||||
.opacity(@factor) {
|
||||
@iefactor: @factor*100;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=@{iefactor})";
|
||||
filter: ~"alpha(opacity=(@{iefactor}))";
|
||||
opacity: @factor;
|
||||
}
|
||||
|
||||
|
||||
// Text Shadow
|
||||
|
||||
.text-shadow(@args) {
|
||||
text-shadow: @args;
|
||||
}
|
||||
|
||||
|
||||
// Transforms
|
||||
|
||||
.transform(@args) {
|
||||
-webkit-transform: @args;
|
||||
-moz-transform: @args;
|
||||
-ms-transform: @args;
|
||||
-o-transform: @args;
|
||||
transform: @args;
|
||||
}
|
||||
.transform-origin(@args) {
|
||||
-webkit-transform-origin: @args;
|
||||
-moz-transform-origin: @args;
|
||||
-ms-transform-origin: @args;
|
||||
-o-transform-origin: @args;
|
||||
transform-origin: @args;
|
||||
}
|
||||
.transform-style(@style) {
|
||||
-webkit-transform-style: @style;
|
||||
-moz-transform-style: @style;
|
||||
-ms-transform-style: @style;
|
||||
-o-transform-style: @style;
|
||||
transform-style: @style;
|
||||
}
|
||||
.rotate(@deg:45deg){
|
||||
.transform(rotate(@deg));
|
||||
}
|
||||
.scale(@factor:.5){
|
||||
.transform(scale(@factor));
|
||||
}
|
||||
.translate(@x,@y){
|
||||
.transform(translate(@x,@y));
|
||||
}
|
||||
.translate3d(@x,@y,@z) {
|
||||
.transform(translate3d(@x,@y,@z));
|
||||
}
|
||||
.translateHardware(@x,@y) {
|
||||
.translate(@x,@y);
|
||||
-webkit-transform: translate3d(@x,@y,0);
|
||||
-moz-transform: translate3d(@x,@y,0);
|
||||
-o-transform: translate3d(@x,@y,0);
|
||||
-ms-transform: translate3d(@x,@y,0);
|
||||
transform: translate3d(@x,@y,0);
|
||||
}
|
||||
|
||||
|
||||
// Transitions
|
||||
|
||||
.transition(@args:200ms) {
|
||||
-webkit-transition: @args;
|
||||
-moz-transition: @args;
|
||||
-o-transition: @args;
|
||||
-ms-transition: @args;
|
||||
transition: @args;
|
||||
}
|
||||
.transition-delay(@delay:0) {
|
||||
-webkit-transition-delay: @delay;
|
||||
-moz-transition-delay: @delay;
|
||||
-o-transition-delay: @delay;
|
||||
-ms-transition-delay: @delay;
|
||||
transition-delay: @delay;
|
||||
}
|
||||
.transition-duration(@duration:200ms) {
|
||||
-webkit-transition-duration: @duration;
|
||||
-moz-transition-duration: @duration;
|
||||
-o-transition-duration: @duration;
|
||||
-ms-transition-duration: @duration;
|
||||
transition-duration: @duration;
|
||||
}
|
||||
.transition-property(@property:all) {
|
||||
-webkit-transition-property: @property;
|
||||
-moz-transition-property: @property;
|
||||
-o-transition-property: @property;
|
||||
-ms-transition-property: @property;
|
||||
transition-property: @property;
|
||||
}
|
||||
.transition-timing-function(@function:ease) {
|
||||
-webkit-transition-timing-function: @function;
|
||||
-moz-transition-timing-function: @function;
|
||||
-o-transition-timing-function: @function;
|
||||
-ms-transition-timing-function: @function;
|
||||
transition-timing-function: @function;
|
||||
}
|
||||
|
1
vendor
1
vendor
|
@ -1 +0,0 @@
|
|||
Subproject commit c494144f80ead4398bdce27dcbb0e60b9edc065f
|
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'celery==2.5.5','console_scripts','camqadm'
|
||||
__requires__ = 'celery==2.5.5'
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(
|
||||
load_entry_point('celery==2.5.5', 'console_scripts', 'camqadm')()
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'celery==2.5.5','console_scripts','celerybeat'
|
||||
__requires__ = 'celery==2.5.5'
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(
|
||||
load_entry_point('celery==2.5.5', 'console_scripts', 'celerybeat')()
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'celery==2.5.5','console_scripts','celeryctl'
|
||||
__requires__ = 'celery==2.5.5'
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(
|
||||
load_entry_point('celery==2.5.5', 'console_scripts', 'celeryctl')()
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'celery==2.5.5','console_scripts','celeryd'
|
||||
__requires__ = 'celery==2.5.5'
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(
|
||||
load_entry_point('celery==2.5.5', 'console_scripts', 'celeryd')()
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'celery==2.5.5','console_scripts','celeryd-multi'
|
||||
__requires__ = 'celery==2.5.5'
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(
|
||||
load_entry_point('celery==2.5.5', 'console_scripts', 'celeryd-multi')()
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'celery==2.5.5','console_scripts','celeryev'
|
||||
__requires__ = 'celery==2.5.5'
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(
|
||||
load_entry_point('celery==2.5.5', 'console_scripts', 'celeryev')()
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'django-celery==2.5.5','console_scripts','djcelerymon'
|
||||
__requires__ = 'django-celery==2.5.5'
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(
|
||||
load_entry_point('django-celery==2.5.5', 'console_scripts', 'djcelerymon')()
|
||||
)
|
|
@ -1,34 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
Python Markdown, the Command Line Script
|
||||
========================================
|
||||
|
||||
This is the command line script for Python Markdown.
|
||||
|
||||
Basic use from the command line:
|
||||
|
||||
markdown source.txt > destination.html
|
||||
|
||||
Run "markdown --help" to see more options.
|
||||
|
||||
See markdown/__init__.py for information on using Python Markdown as a module.
|
||||
|
||||
## Authors and License
|
||||
|
||||
Started by [Manfred Stienstra](http://www.dwerg.net/). Continued and
|
||||
maintained by [Yuri Takhteyev](http://www.freewisdom.org), [Waylan
|
||||
Limberg](http://achinghead.com/) and [Artem Yunusov](http://blog.splyer.com).
|
||||
|
||||
Contact: markdown@freewisdom.org
|
||||
|
||||
Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
|
||||
Copyright 200? Django Software Foundation (OrderedDict implementation)
|
||||
Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
|
||||
Copyright 2004 Manfred Stienstra (the original version)
|
||||
|
||||
License: BSD (see docs/LICENSE for details).
|
||||
"""
|
||||
|
||||
if __name__ == '__main__':
|
||||
from markdown.__main__ import run
|
||||
run()
|
|
@ -1,47 +0,0 @@
|
|||
Metadata-Version: 1.1
|
||||
Name: Markdown
|
||||
Version: 2.3.1
|
||||
Summary: Python implementation of Markdown.
|
||||
Home-page: http://packages.python.org/Markdown/
|
||||
Author: Waylan Limberg
|
||||
Author-email: waylan [at] gmail.com
|
||||
License: BSD License
|
||||
Download-URL: http://pypi.python.org/packages/source/M/Markdown/Markdown-2.3.1.tar.gz
|
||||
Description: This is a Python implementation of John Gruber's Markdown_.
|
||||
It is almost completely compliant with the reference implementation,
|
||||
though there are a few known issues. See Features_ for information
|
||||
on what exactly is supported and what is not. Additional features are
|
||||
supported by the `Available Extensions`_.
|
||||
|
||||
.. _Markdown: http://daringfireball.net/projects/markdown/
|
||||
.. _Features: http://packages.python.org/Markdown/index.html#Features
|
||||
.. _`Available Extensions`: http://packages.python.org/Markdown/extensions/index.html
|
||||
|
||||
Support
|
||||
=======
|
||||
|
||||
You may ask for help and discuss various other issues on the
|
||||
`mailing list`_ and report bugs on the `bug tracker`_.
|
||||
|
||||
.. _`mailing list`: http://lists.sourceforge.net/lists/listinfo/python-markdown-discuss
|
||||
.. _`bug tracker`: http://github.com/waylan/Python-Markdown/issues
|
||||
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.1
|
||||
Classifier: Programming Language :: Python :: 3.2
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Topic :: Communications :: Email :: Filters
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
|
||||
Classifier: Topic :: Software Development :: Documentation
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: Text Processing :: Filters
|
||||
Classifier: Topic :: Text Processing :: Markup :: HTML
|
|
@ -1,35 +0,0 @@
|
|||
setup.cfg
|
||||
Markdown.egg-info/PKG-INFO
|
||||
Markdown.egg-info/SOURCES.txt
|
||||
Markdown.egg-info/dependency_links.txt
|
||||
Markdown.egg-info/top_level.txt
|
||||
bin/markdown_py
|
||||
markdown/__init__.py
|
||||
markdown/__main__.py
|
||||
markdown/__version__.py
|
||||
markdown/blockparser.py
|
||||
markdown/blockprocessors.py
|
||||
markdown/inlinepatterns.py
|
||||
markdown/odict.py
|
||||
markdown/postprocessors.py
|
||||
markdown/preprocessors.py
|
||||
markdown/serializers.py
|
||||
markdown/treeprocessors.py
|
||||
markdown/util.py
|
||||
markdown/extensions/__init__.py
|
||||
markdown/extensions/abbr.py
|
||||
markdown/extensions/admonition.py
|
||||
markdown/extensions/attr_list.py
|
||||
markdown/extensions/codehilite.py
|
||||
markdown/extensions/def_list.py
|
||||
markdown/extensions/extra.py
|
||||
markdown/extensions/fenced_code.py
|
||||
markdown/extensions/footnotes.py
|
||||
markdown/extensions/headerid.py
|
||||
markdown/extensions/meta.py
|
||||
markdown/extensions/nl2br.py
|
||||
markdown/extensions/sane_lists.py
|
||||
markdown/extensions/smart_strong.py
|
||||
markdown/extensions/tables.py
|
||||
markdown/extensions/toc.py
|
||||
markdown/extensions/wikilinks.py
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
../markdown/blockprocessors.py
|
||||
../markdown/__init__.py
|
||||
../markdown/blockparser.py
|
||||
../markdown/serializers.py
|
||||
../markdown/inlinepatterns.py
|
||||
../markdown/odict.py
|
||||
../markdown/postprocessors.py
|
||||
../markdown/__main__.py
|
||||
../markdown/preprocessors.py
|
||||
../markdown/__version__.py
|
||||
../markdown/util.py
|
||||
../markdown/treeprocessors.py
|
||||
../markdown/extensions/abbr.py
|
||||
../markdown/extensions/extra.py
|
||||
../markdown/extensions/__init__.py
|
||||
../markdown/extensions/wikilinks.py
|
||||
../markdown/extensions/footnotes.py
|
||||
../markdown/extensions/tables.py
|
||||
../markdown/extensions/toc.py
|
||||
../markdown/extensions/attr_list.py
|
||||
../markdown/extensions/codehilite.py
|
||||
../markdown/extensions/smart_strong.py
|
||||
../markdown/extensions/fenced_code.py
|
||||
../markdown/extensions/sane_lists.py
|
||||
../markdown/extensions/headerid.py
|
||||
../markdown/extensions/meta.py
|
||||
../markdown/extensions/nl2br.py
|
||||
../markdown/extensions/def_list.py
|
||||
../markdown/extensions/admonition.py
|
||||
../markdown/blockprocessors.pyc
|
||||
../markdown/__init__.pyc
|
||||
../markdown/blockparser.pyc
|
||||
../markdown/serializers.pyc
|
||||
../markdown/inlinepatterns.pyc
|
||||
../markdown/odict.pyc
|
||||
../markdown/postprocessors.pyc
|
||||
../markdown/__main__.pyc
|
||||
../markdown/preprocessors.pyc
|
||||
../markdown/__version__.pyc
|
||||
../markdown/util.pyc
|
||||
../markdown/treeprocessors.pyc
|
||||
../markdown/extensions/abbr.pyc
|
||||
../markdown/extensions/extra.pyc
|
||||
../markdown/extensions/__init__.pyc
|
||||
../markdown/extensions/wikilinks.pyc
|
||||
../markdown/extensions/footnotes.pyc
|
||||
../markdown/extensions/tables.pyc
|
||||
../markdown/extensions/toc.pyc
|
||||
../markdown/extensions/attr_list.pyc
|
||||
../markdown/extensions/codehilite.pyc
|
||||
../markdown/extensions/smart_strong.pyc
|
||||
../markdown/extensions/fenced_code.pyc
|
||||
../markdown/extensions/sane_lists.pyc
|
||||
../markdown/extensions/headerid.pyc
|
||||
../markdown/extensions/meta.pyc
|
||||
../markdown/extensions/nl2br.pyc
|
||||
../markdown/extensions/def_list.pyc
|
||||
../markdown/extensions/admonition.pyc
|
||||
./
|
||||
PKG-INFO
|
||||
SOURCES.txt
|
||||
top_level.txt
|
||||
dependency_links.txt
|
||||
../../../bin/markdown_py
|
|
@ -1 +0,0 @@
|
|||
markdown
|
|
@ -1,47 +0,0 @@
|
|||
Metadata-Version: 1.1
|
||||
Name: Markdown
|
||||
Version: 2.4
|
||||
Summary: Python implementation of Markdown.
|
||||
Home-page: http://packages.python.org/Markdown/
|
||||
Author: Waylan Limberg
|
||||
Author-email: waylan [at] gmail.com
|
||||
License: BSD License
|
||||
Download-URL: http://pypi.python.org/packages/source/M/Markdown/Markdown-2.4.tar.gz
|
||||
Description: This is a Python implementation of John Gruber's Markdown_.
|
||||
It is almost completely compliant with the reference implementation,
|
||||
though there are a few known issues. See Features_ for information
|
||||
on what exactly is supported and what is not. Additional features are
|
||||
supported by the `Available Extensions`_.
|
||||
|
||||
.. _Markdown: http://daringfireball.net/projects/markdown/
|
||||
.. _Features: http://packages.python.org/Markdown/index.html#Features
|
||||
.. _`Available Extensions`: http://packages.python.org/Markdown/extensions/index.html
|
||||
|
||||
Support
|
||||
=======
|
||||
|
||||
You may ask for help and discuss various other issues on the
|
||||
`mailing list`_ and report bugs on the `bug tracker`_.
|
||||
|
||||
.. _`mailing list`: http://lists.sourceforge.net/lists/listinfo/python-markdown-discuss
|
||||
.. _`bug tracker`: http://github.com/waylan/Python-Markdown/issues
|
||||
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.1
|
||||
Classifier: Programming Language :: Python :: 3.2
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Topic :: Communications :: Email :: Filters
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
|
||||
Classifier: Topic :: Software Development :: Documentation
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: Text Processing :: Filters
|
||||
Classifier: Topic :: Text Processing :: Markup :: HTML
|
|
@ -1,36 +0,0 @@
|
|||
setup.cfg
|
||||
Markdown.egg-info/PKG-INFO
|
||||
Markdown.egg-info/SOURCES.txt
|
||||
Markdown.egg-info/dependency_links.txt
|
||||
Markdown.egg-info/top_level.txt
|
||||
bin/markdown_py
|
||||
markdown/__init__.py
|
||||
markdown/__main__.py
|
||||
markdown/__version__.py
|
||||
markdown/blockparser.py
|
||||
markdown/blockprocessors.py
|
||||
markdown/inlinepatterns.py
|
||||
markdown/odict.py
|
||||
markdown/postprocessors.py
|
||||
markdown/preprocessors.py
|
||||
markdown/serializers.py
|
||||
markdown/treeprocessors.py
|
||||
markdown/util.py
|
||||
markdown/extensions/__init__.py
|
||||
markdown/extensions/abbr.py
|
||||
markdown/extensions/admonition.py
|
||||
markdown/extensions/attr_list.py
|
||||
markdown/extensions/codehilite.py
|
||||
markdown/extensions/def_list.py
|
||||
markdown/extensions/extra.py
|
||||
markdown/extensions/fenced_code.py
|
||||
markdown/extensions/footnotes.py
|
||||
markdown/extensions/headerid.py
|
||||
markdown/extensions/meta.py
|
||||
markdown/extensions/nl2br.py
|
||||
markdown/extensions/sane_lists.py
|
||||
markdown/extensions/smart_strong.py
|
||||
markdown/extensions/smarty.py
|
||||
markdown/extensions/tables.py
|
||||
markdown/extensions/toc.py
|
||||
markdown/extensions/wikilinks.py
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
../markdown/__version__.py
|
||||
../markdown/preprocessors.py
|
||||
../markdown/blockprocessors.py
|
||||
../markdown/blockparser.py
|
||||
../markdown/serializers.py
|
||||
../markdown/odict.py
|
||||
../markdown/__main__.py
|
||||
../markdown/util.py
|
||||
../markdown/inlinepatterns.py
|
||||
../markdown/treeprocessors.py
|
||||
../markdown/__init__.py
|
||||
../markdown/postprocessors.py
|
||||
../markdown/extensions/footnotes.py
|
||||
../markdown/extensions/sane_lists.py
|
||||
../markdown/extensions/meta.py
|
||||
../markdown/extensions/admonition.py
|
||||
../markdown/extensions/toc.py
|
||||
../markdown/extensions/codehilite.py
|
||||
../markdown/extensions/attr_list.py
|
||||
../markdown/extensions/extra.py
|
||||
../markdown/extensions/smarty.py
|
||||
../markdown/extensions/wikilinks.py
|
||||
../markdown/extensions/headerid.py
|
||||
../markdown/extensions/__init__.py
|
||||
../markdown/extensions/smart_strong.py
|
||||
../markdown/extensions/tables.py
|
||||
../markdown/extensions/nl2br.py
|
||||
../markdown/extensions/abbr.py
|
||||
../markdown/extensions/fenced_code.py
|
||||
../markdown/extensions/def_list.py
|
||||
../markdown/__version__.pyc
|
||||
../markdown/preprocessors.pyc
|
||||
../markdown/blockprocessors.pyc
|
||||
../markdown/blockparser.pyc
|
||||
../markdown/serializers.pyc
|
||||
../markdown/odict.pyc
|
||||
../markdown/__main__.pyc
|
||||
../markdown/util.pyc
|
||||
../markdown/inlinepatterns.pyc
|
||||
../markdown/treeprocessors.pyc
|
||||
../markdown/__init__.pyc
|
||||
../markdown/postprocessors.pyc
|
||||
../markdown/extensions/footnotes.pyc
|
||||
../markdown/extensions/sane_lists.pyc
|
||||
../markdown/extensions/meta.pyc
|
||||
../markdown/extensions/admonition.pyc
|
||||
../markdown/extensions/toc.pyc
|
||||
../markdown/extensions/codehilite.pyc
|
||||
../markdown/extensions/attr_list.pyc
|
||||
../markdown/extensions/extra.pyc
|
||||
../markdown/extensions/smarty.pyc
|
||||
../markdown/extensions/wikilinks.pyc
|
||||
../markdown/extensions/headerid.pyc
|
||||
../markdown/extensions/__init__.pyc
|
||||
../markdown/extensions/smart_strong.pyc
|
||||
../markdown/extensions/tables.pyc
|
||||
../markdown/extensions/nl2br.pyc
|
||||
../markdown/extensions/abbr.pyc
|
||||
../markdown/extensions/fenced_code.pyc
|
||||
../markdown/extensions/def_list.pyc
|
||||
./
|
||||
SOURCES.txt
|
||||
dependency_links.txt
|
||||
top_level.txt
|
||||
PKG-INFO
|
||||
../../../bin/markdown_py
|
|
@ -1 +0,0 @@
|
|||
markdown
|
|
@ -1,22 +0,0 @@
|
|||
Metadata-Version: 1.1
|
||||
Name: South
|
||||
Version: 1.0.2
|
||||
Summary: South: Migrations for Django
|
||||
Home-page: http://south.aeracode.org/
|
||||
Author: Andrew Godwin & Andy McCurdy
|
||||
Author-email: south@aeracode.org
|
||||
License: UNKNOWN
|
||||
Download-URL: http://south.aeracode.org/wiki/Download
|
||||
Description: South is an intelligent database migrations library for the Django web framework. It is database-independent and DVCS-friendly, as well as a whole host of other features.
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Framework :: Django
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: License :: OSI Approved :: Apache Software License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Topic :: Software Development
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
|
@ -1,123 +0,0 @@
|
|||
README
|
||||
setup.cfg
|
||||
South.egg-info/PKG-INFO
|
||||
South.egg-info/SOURCES.txt
|
||||
South.egg-info/dependency_links.txt
|
||||
South.egg-info/top_level.txt
|
||||
south/__init__.py
|
||||
south/exceptions.py
|
||||
south/logger.py
|
||||
south/models.py
|
||||
south/modelsinspector.py
|
||||
south/orm.py
|
||||
south/signals.py
|
||||
south/test_shim.py
|
||||
south/v2.py
|
||||
south/creator/__init__.py
|
||||
south/creator/actions.py
|
||||
south/creator/changes.py
|
||||
south/creator/freezer.py
|
||||
south/db/__init__.py
|
||||
south/db/firebird.py
|
||||
south/db/generic.py
|
||||
south/db/mysql.py
|
||||
south/db/oracle.py
|
||||
south/db/postgresql_psycopg2.py
|
||||
south/db/sqlite3.py
|
||||
south/db/sql_server/__init__.py
|
||||
south/db/sql_server/pyodbc.py
|
||||
south/hacks/__init__.py
|
||||
south/hacks/django_1_0.py
|
||||
south/introspection_plugins/__init__.py
|
||||
south/introspection_plugins/annoying_autoonetoone.py
|
||||
south/introspection_plugins/django_audit_log.py
|
||||
south/introspection_plugins/django_objectpermissions.py
|
||||
south/introspection_plugins/django_tagging.py
|
||||
south/introspection_plugins/django_taggit.py
|
||||
south/introspection_plugins/django_timezones.py
|
||||
south/introspection_plugins/geodjango.py
|
||||
south/management/__init__.py
|
||||
south/management/commands/__init__.py
|
||||
south/management/commands/convert_to_south.py
|
||||
south/management/commands/datamigration.py
|
||||
south/management/commands/graphmigrations.py
|
||||
south/management/commands/migrate.py
|
||||
south/management/commands/migrationcheck.py
|
||||
south/management/commands/schemamigration.py
|
||||
south/management/commands/startmigration.py
|
||||
south/management/commands/syncdb.py
|
||||
south/management/commands/test.py
|
||||
south/management/commands/testserver.py
|
||||
south/migration/__init__.py
|
||||
south/migration/base.py
|
||||
south/migration/migrators.py
|
||||
south/migration/utils.py
|
||||
south/tests/__init__.py
|
||||
south/tests/autodetection.py
|
||||
south/tests/db.py
|
||||
south/tests/db_firebird.py
|
||||
south/tests/db_mysql.py
|
||||
south/tests/freezer.py
|
||||
south/tests/inspector.py
|
||||
south/tests/logger.py
|
||||
south/tests/logic.py
|
||||
south/tests/brokenapp/__init__.py
|
||||
south/tests/brokenapp/models.py
|
||||
south/tests/brokenapp/migrations/0001_depends_on_unmigrated.py
|
||||
south/tests/brokenapp/migrations/0002_depends_on_unknown.py
|
||||
south/tests/brokenapp/migrations/0003_depends_on_higher.py
|
||||
south/tests/brokenapp/migrations/0004_higher.py
|
||||
south/tests/brokenapp/migrations/__init__.py
|
||||
south/tests/circular_a/__init__.py
|
||||
south/tests/circular_a/models.py
|
||||
south/tests/circular_a/migrations/0001_first.py
|
||||
south/tests/circular_a/migrations/__init__.py
|
||||
south/tests/circular_b/__init__.py
|
||||
south/tests/circular_b/models.py
|
||||
south/tests/circular_b/migrations/0001_first.py
|
||||
south/tests/circular_b/migrations/__init__.py
|
||||
south/tests/deps_a/__init__.py
|
||||
south/tests/deps_a/models.py
|
||||
south/tests/deps_a/migrations/0001_a.py
|
||||
south/tests/deps_a/migrations/0002_a.py
|
||||
south/tests/deps_a/migrations/0003_a.py
|
||||
south/tests/deps_a/migrations/0004_a.py
|
||||
south/tests/deps_a/migrations/0005_a.py
|
||||
south/tests/deps_a/migrations/__init__.py
|
||||
south/tests/deps_b/__init__.py
|
||||
south/tests/deps_b/models.py
|
||||
south/tests/deps_b/migrations/0001_b.py
|
||||
south/tests/deps_b/migrations/0002_b.py
|
||||
south/tests/deps_b/migrations/0003_b.py
|
||||
south/tests/deps_b/migrations/0004_b.py
|
||||
south/tests/deps_b/migrations/0005_b.py
|
||||
south/tests/deps_b/migrations/__init__.py
|
||||
south/tests/deps_c/__init__.py
|
||||
south/tests/deps_c/models.py
|
||||
south/tests/deps_c/migrations/0001_c.py
|
||||
south/tests/deps_c/migrations/0002_c.py
|
||||
south/tests/deps_c/migrations/0003_c.py
|
||||
south/tests/deps_c/migrations/0004_c.py
|
||||
south/tests/deps_c/migrations/0005_c.py
|
||||
south/tests/deps_c/migrations/__init__.py
|
||||
south/tests/emptyapp/__init__.py
|
||||
south/tests/emptyapp/models.py
|
||||
south/tests/emptyapp/migrations/__init__.py
|
||||
south/tests/fakeapp/__init__.py
|
||||
south/tests/fakeapp/models.py
|
||||
south/tests/fakeapp/migrations/0001_spam.py
|
||||
south/tests/fakeapp/migrations/0002_eggs.py
|
||||
south/tests/fakeapp/migrations/0003_alter_spam.py
|
||||
south/tests/fakeapp/migrations/__init__.py
|
||||
south/tests/non_managed/__init__.py
|
||||
south/tests/non_managed/models.py
|
||||
south/tests/non_managed/migrations/__init__.py
|
||||
south/tests/otherfakeapp/__init__.py
|
||||
south/tests/otherfakeapp/models.py
|
||||
south/tests/otherfakeapp/migrations/0001_first.py
|
||||
south/tests/otherfakeapp/migrations/0002_second.py
|
||||
south/tests/otherfakeapp/migrations/0003_third.py
|
||||
south/tests/otherfakeapp/migrations/__init__.py
|
||||
south/utils/__init__.py
|
||||
south/utils/datetime_utils.py
|
||||
south/utils/py3.py
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,239 +0,0 @@
|
|||
../south/orm.py
|
||||
../south/exceptions.py
|
||||
../south/__init__.py
|
||||
../south/signals.py
|
||||
../south/test_shim.py
|
||||
../south/models.py
|
||||
../south/logger.py
|
||||
../south/v2.py
|
||||
../south/modelsinspector.py
|
||||
../south/creator/__init__.py
|
||||
../south/creator/changes.py
|
||||
../south/creator/actions.py
|
||||
../south/creator/freezer.py
|
||||
../south/db/mysql.py
|
||||
../south/db/postgresql_psycopg2.py
|
||||
../south/db/__init__.py
|
||||
../south/db/sqlite3.py
|
||||
../south/db/oracle.py
|
||||
../south/db/generic.py
|
||||
../south/db/firebird.py
|
||||
../south/management/__init__.py
|
||||
../south/introspection_plugins/django_taggit.py
|
||||
../south/introspection_plugins/__init__.py
|
||||
../south/introspection_plugins/django_timezones.py
|
||||
../south/introspection_plugins/django_audit_log.py
|
||||
../south/introspection_plugins/annoying_autoonetoone.py
|
||||
../south/introspection_plugins/django_tagging.py
|
||||
../south/introspection_plugins/geodjango.py
|
||||
../south/introspection_plugins/django_objectpermissions.py
|
||||
../south/hacks/__init__.py
|
||||
../south/hacks/django_1_0.py
|
||||
../south/migration/base.py
|
||||
../south/migration/__init__.py
|
||||
../south/migration/utils.py
|
||||
../south/migration/migrators.py
|
||||
../south/tests/__init__.py
|
||||
../south/tests/db_mysql.py
|
||||
../south/tests/autodetection.py
|
||||
../south/tests/logger.py
|
||||
../south/tests/freezer.py
|
||||
../south/tests/db.py
|
||||
../south/tests/logic.py
|
||||
../south/tests/inspector.py
|
||||
../south/tests/db_firebird.py
|
||||
../south/db/sql_server/__init__.py
|
||||
../south/db/sql_server/pyodbc.py
|
||||
../south/management/commands/startmigration.py
|
||||
../south/management/commands/convert_to_south.py
|
||||
../south/management/commands/migrate.py
|
||||
../south/management/commands/__init__.py
|
||||
../south/management/commands/testserver.py
|
||||
../south/management/commands/syncdb.py
|
||||
../south/management/commands/schemamigration.py
|
||||
../south/management/commands/test.py
|
||||
../south/management/commands/migrationcheck.py
|
||||
../south/management/commands/datamigration.py
|
||||
../south/management/commands/graphmigrations.py
|
||||
../south/tests/circular_a/__init__.py
|
||||
../south/tests/circular_a/models.py
|
||||
../south/tests/emptyapp/__init__.py
|
||||
../south/tests/emptyapp/models.py
|
||||
../south/tests/deps_a/__init__.py
|
||||
../south/tests/deps_a/models.py
|
||||
../south/tests/fakeapp/__init__.py
|
||||
../south/tests/fakeapp/models.py
|
||||
../south/tests/brokenapp/__init__.py
|
||||
../south/tests/brokenapp/models.py
|
||||
../south/tests/circular_b/__init__.py
|
||||
../south/tests/circular_b/models.py
|
||||
../south/tests/otherfakeapp/__init__.py
|
||||
../south/tests/otherfakeapp/models.py
|
||||
../south/tests/deps_c/__init__.py
|
||||
../south/tests/deps_c/models.py
|
||||
../south/tests/deps_b/__init__.py
|
||||
../south/tests/deps_b/models.py
|
||||
../south/tests/non_managed/__init__.py
|
||||
../south/tests/non_managed/models.py
|
||||
../south/tests/circular_a/migrations/__init__.py
|
||||
../south/tests/circular_a/migrations/0001_first.py
|
||||
../south/tests/emptyapp/migrations/__init__.py
|
||||
../south/tests/deps_a/migrations/__init__.py
|
||||
../south/tests/deps_a/migrations/0004_a.py
|
||||
../south/tests/deps_a/migrations/0003_a.py
|
||||
../south/tests/deps_a/migrations/0001_a.py
|
||||
../south/tests/deps_a/migrations/0005_a.py
|
||||
../south/tests/deps_a/migrations/0002_a.py
|
||||
../south/tests/fakeapp/migrations/0002_eggs.py
|
||||
../south/tests/fakeapp/migrations/__init__.py
|
||||
../south/tests/fakeapp/migrations/0001_spam.py
|
||||
../south/tests/fakeapp/migrations/0003_alter_spam.py
|
||||
../south/tests/brokenapp/migrations/0001_depends_on_unmigrated.py
|
||||
../south/tests/brokenapp/migrations/__init__.py
|
||||
../south/tests/brokenapp/migrations/0003_depends_on_higher.py
|
||||
../south/tests/brokenapp/migrations/0002_depends_on_unknown.py
|
||||
../south/tests/brokenapp/migrations/0004_higher.py
|
||||
../south/tests/circular_b/migrations/__init__.py
|
||||
../south/tests/circular_b/migrations/0001_first.py
|
||||
../south/tests/otherfakeapp/migrations/__init__.py
|
||||
../south/tests/otherfakeapp/migrations/0002_second.py
|
||||
../south/tests/otherfakeapp/migrations/0003_third.py
|
||||
../south/tests/otherfakeapp/migrations/0001_first.py
|
||||
../south/tests/deps_c/migrations/0005_c.py
|
||||
../south/tests/deps_c/migrations/0001_c.py
|
||||
../south/tests/deps_c/migrations/__init__.py
|
||||
../south/tests/deps_c/migrations/0004_c.py
|
||||
../south/tests/deps_c/migrations/0002_c.py
|
||||
../south/tests/deps_c/migrations/0003_c.py
|
||||
../south/tests/deps_b/migrations/0003_b.py
|
||||
../south/tests/deps_b/migrations/0005_b.py
|
||||
../south/tests/deps_b/migrations/__init__.py
|
||||
../south/tests/deps_b/migrations/0004_b.py
|
||||
../south/tests/deps_b/migrations/0002_b.py
|
||||
../south/tests/deps_b/migrations/0001_b.py
|
||||
../south/tests/non_managed/migrations/__init__.py
|
||||
../south/utils/__init__.py
|
||||
../south/utils/py3.py
|
||||
../south/utils/datetime_utils.py
|
||||
../south/orm.pyc
|
||||
../south/exceptions.pyc
|
||||
../south/__init__.pyc
|
||||
../south/signals.pyc
|
||||
../south/test_shim.pyc
|
||||
../south/models.pyc
|
||||
../south/logger.pyc
|
||||
../south/v2.pyc
|
||||
../south/modelsinspector.pyc
|
||||
../south/creator/__init__.pyc
|
||||
../south/creator/changes.pyc
|
||||
../south/creator/actions.pyc
|
||||
../south/creator/freezer.pyc
|
||||
../south/db/mysql.pyc
|
||||
../south/db/postgresql_psycopg2.pyc
|
||||
../south/db/__init__.pyc
|
||||
../south/db/sqlite3.pyc
|
||||
../south/db/oracle.pyc
|
||||
../south/db/generic.pyc
|
||||
../south/db/firebird.pyc
|
||||
../south/management/__init__.pyc
|
||||
../south/introspection_plugins/django_taggit.pyc
|
||||
../south/introspection_plugins/__init__.pyc
|
||||
../south/introspection_plugins/django_timezones.pyc
|
||||
../south/introspection_plugins/django_audit_log.pyc
|
||||
../south/introspection_plugins/annoying_autoonetoone.pyc
|
||||
../south/introspection_plugins/django_tagging.pyc
|
||||
../south/introspection_plugins/geodjango.pyc
|
||||
../south/introspection_plugins/django_objectpermissions.pyc
|
||||
../south/hacks/__init__.pyc
|
||||
../south/hacks/django_1_0.pyc
|
||||
../south/migration/base.pyc
|
||||
../south/migration/__init__.pyc
|
||||
../south/migration/utils.pyc
|
||||
../south/migration/migrators.pyc
|
||||
../south/tests/__init__.pyc
|
||||
../south/tests/db_mysql.pyc
|
||||
../south/tests/autodetection.pyc
|
||||
../south/tests/logger.pyc
|
||||
../south/tests/freezer.pyc
|
||||
../south/tests/db.pyc
|
||||
../south/tests/logic.pyc
|
||||
../south/tests/inspector.pyc
|
||||
../south/tests/db_firebird.pyc
|
||||
../south/db/sql_server/__init__.pyc
|
||||
../south/db/sql_server/pyodbc.pyc
|
||||
../south/management/commands/startmigration.pyc
|
||||
../south/management/commands/convert_to_south.pyc
|
||||
../south/management/commands/migrate.pyc
|
||||
../south/management/commands/__init__.pyc
|
||||
../south/management/commands/testserver.pyc
|
||||
../south/management/commands/syncdb.pyc
|
||||
../south/management/commands/schemamigration.pyc
|
||||
../south/management/commands/test.pyc
|
||||
../south/management/commands/migrationcheck.pyc
|
||||
../south/management/commands/datamigration.pyc
|
||||
../south/management/commands/graphmigrations.pyc
|
||||
../south/tests/circular_a/__init__.pyc
|
||||
../south/tests/circular_a/models.pyc
|
||||
../south/tests/emptyapp/__init__.pyc
|
||||
../south/tests/emptyapp/models.pyc
|
||||
../south/tests/deps_a/__init__.pyc
|
||||
../south/tests/deps_a/models.pyc
|
||||
../south/tests/fakeapp/__init__.pyc
|
||||
../south/tests/fakeapp/models.pyc
|
||||
../south/tests/brokenapp/__init__.pyc
|
||||
../south/tests/brokenapp/models.pyc
|
||||
../south/tests/circular_b/__init__.pyc
|
||||
../south/tests/circular_b/models.pyc
|
||||
../south/tests/otherfakeapp/__init__.pyc
|
||||
../south/tests/otherfakeapp/models.pyc
|
||||
../south/tests/deps_c/__init__.pyc
|
||||
../south/tests/deps_c/models.pyc
|
||||
../south/tests/deps_b/__init__.pyc
|
||||
../south/tests/deps_b/models.pyc
|
||||
../south/tests/non_managed/__init__.pyc
|
||||
../south/tests/non_managed/models.pyc
|
||||
../south/tests/circular_a/migrations/__init__.pyc
|
||||
../south/tests/circular_a/migrations/0001_first.pyc
|
||||
../south/tests/emptyapp/migrations/__init__.pyc
|
||||
../south/tests/deps_a/migrations/__init__.pyc
|
||||
../south/tests/deps_a/migrations/0004_a.pyc
|
||||
../south/tests/deps_a/migrations/0003_a.pyc
|
||||
../south/tests/deps_a/migrations/0001_a.pyc
|
||||
../south/tests/deps_a/migrations/0005_a.pyc
|
||||
../south/tests/deps_a/migrations/0002_a.pyc
|
||||
../south/tests/fakeapp/migrations/0002_eggs.pyc
|
||||
../south/tests/fakeapp/migrations/__init__.pyc
|
||||
../south/tests/fakeapp/migrations/0001_spam.pyc
|
||||
../south/tests/fakeapp/migrations/0003_alter_spam.pyc
|
||||
../south/tests/brokenapp/migrations/0001_depends_on_unmigrated.pyc
|
||||
../south/tests/brokenapp/migrations/__init__.pyc
|
||||
../south/tests/brokenapp/migrations/0003_depends_on_higher.pyc
|
||||
../south/tests/brokenapp/migrations/0002_depends_on_unknown.pyc
|
||||
../south/tests/brokenapp/migrations/0004_higher.pyc
|
||||
../south/tests/circular_b/migrations/__init__.pyc
|
||||
../south/tests/circular_b/migrations/0001_first.pyc
|
||||
../south/tests/otherfakeapp/migrations/__init__.pyc
|
||||
../south/tests/otherfakeapp/migrations/0002_second.pyc
|
||||
../south/tests/otherfakeapp/migrations/0003_third.pyc
|
||||
../south/tests/otherfakeapp/migrations/0001_first.pyc
|
||||
../south/tests/deps_c/migrations/0005_c.pyc
|
||||
../south/tests/deps_c/migrations/0001_c.pyc
|
||||
../south/tests/deps_c/migrations/__init__.pyc
|
||||
../south/tests/deps_c/migrations/0004_c.pyc
|
||||
../south/tests/deps_c/migrations/0002_c.pyc
|
||||
../south/tests/deps_c/migrations/0003_c.pyc
|
||||
../south/tests/deps_b/migrations/0003_b.pyc
|
||||
../south/tests/deps_b/migrations/0005_b.pyc
|
||||
../south/tests/deps_b/migrations/__init__.pyc
|
||||
../south/tests/deps_b/migrations/0004_b.pyc
|
||||
../south/tests/deps_b/migrations/0002_b.pyc
|
||||
../south/tests/deps_b/migrations/0001_b.pyc
|
||||
../south/tests/non_managed/migrations/__init__.pyc
|
||||
../south/utils/__init__.pyc
|
||||
../south/utils/py3.pyc
|
||||
../south/utils/datetime_utils.pyc
|
||||
./
|
||||
top_level.txt
|
||||
PKG-INFO
|
||||
SOURCES.txt
|
||||
dependency_links.txt
|
|
@ -1 +0,0 @@
|
|||
south
|
|
@ -1,126 +0,0 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: amqp
|
||||
Version: 1.0.6
|
||||
Summary: Low-level AMQP client for Python (fork of amqplib)
|
||||
Home-page: http://github.com/celery/py-amqp
|
||||
Author: Ask Solem
|
||||
Author-email: pyamqp@celeryproject.org
|
||||
License: LGPL
|
||||
Description: =====================================================================
|
||||
Python AMQP 0.9.1 client library
|
||||
=====================================================================
|
||||
|
||||
:Version: 1.0.6
|
||||
:Web: http://amqp.readthedocs.org/
|
||||
:Download: http://pypi.python.org/pypi/amqp/
|
||||
:Source: http://github.com/celery/py-amqp/
|
||||
:Keywords: amqp, rabbitmq
|
||||
|
||||
About
|
||||
=====
|
||||
|
||||
This is a fork of amqplib_ which was originally written by Barry Pederson.
|
||||
It is maintained by the Celery_ project, and used by `kombu`_ as a pure python
|
||||
alternative when `librabbitmq`_ is not available.
|
||||
|
||||
This library should be API compatible with `librabbitmq`_.
|
||||
|
||||
.. _amqplib: http://pypi.python.org/pypi/amqplib
|
||||
.. _Celery: http://celeryproject.org/
|
||||
.. _kombu: http://kombu.readthedocs.org/
|
||||
.. _librabbitmq: http://pypi.python.org/pypi/librabbitmq
|
||||
|
||||
Differences from `amqplib`_
|
||||
===========================
|
||||
|
||||
- Supports draining events from multiple channels (``Connection.drain_events``)
|
||||
- Support for timeouts
|
||||
- Channels are restored after channel error, instead of having to close the
|
||||
connection.
|
||||
- Support for heartbeats
|
||||
|
||||
- ``Connection.heartbeat_tick(rate=2)`` must called at regular intervals
|
||||
(half of the heartbeat value if rate is 2).
|
||||
- Or some other scheme by using ``Connection.send_heartbeat``.
|
||||
- Supports RabbitMQ extensions:
|
||||
- Consumer Cancel Notifications
|
||||
- by default a cancel results in ``ChannelError`` being raised
|
||||
- but not if a ``on_cancel`` callback is passed to ``basic_consume``.
|
||||
- Publisher confirms
|
||||
- ``Channel.confirm_select()`` enables publisher confirms.
|
||||
- ``Channel.events['basic_ack'].append(my_callback)`` adds a callback
|
||||
to be called when a message is confirmed. This callback is then
|
||||
called with the signature ``(delivery_tag, multiple)``.
|
||||
- Exchange-to-exchange bindings: ``exchange_bind`` / ``exchange_unbind``.
|
||||
- ``Channel.confirm_select()`` enables publisher confirms.
|
||||
- ``Channel.events['basic_ack'].append(my_callback)`` adds a callback
|
||||
to be called when a message is confirmed. This callback is then
|
||||
called with the signature ``(delivery_tag, multiple)``.
|
||||
- Support for ``basic_return``
|
||||
- Uses AMQP 0-9-1 instead of 0-8.
|
||||
- ``Channel.access_request`` and ``ticket`` arguments to methods
|
||||
**removed**.
|
||||
- Supports the ``arguments`` argument to ``basic_consume``.
|
||||
- ``internal`` argument to ``exchange_declare`` removed.
|
||||
- ``auto_delete`` argument to ``exchange_declare`` deprecated
|
||||
- ``insist`` argument to ``Connection`` removed.
|
||||
- ``Channel.alerts`` has been removed.
|
||||
- Support for ``Channel.basic_recover_async``.
|
||||
- ``Channel.basic_recover`` deprecated.
|
||||
- Exceptions renamed to have idiomatic names:
|
||||
- ``AMQPException`` -> ``AMQPError``
|
||||
- ``AMQPConnectionException`` -> ConnectionError``
|
||||
- ``AMQPChannelException`` -> ChannelError``
|
||||
- ``Connection.known_hosts`` removed.
|
||||
- ``Connection`` no longer supports redirects.
|
||||
- ``exchange`` argument to ``queue_bind`` can now be empty
|
||||
to use the "default exchange".
|
||||
- Adds ``Connection.is_alive`` that tries to detect
|
||||
whether the connection can still be used.
|
||||
- Adds ``Connection.connection_errors`` and ``.channel_errors``,
|
||||
a list of recoverable errors.
|
||||
- Exposes the underlying socket as ``Connection.sock``.
|
||||
- Adds ``Channel.no_ack_consumers`` to keep track of consumer tags
|
||||
that set the no_ack flag.
|
||||
- Slightly better at error recovery
|
||||
|
||||
Further
|
||||
=======
|
||||
|
||||
- Differences between AMQP 0.8 and 0.9.1
|
||||
|
||||
http://www.rabbitmq.com/amqp-0-8-to-0-9-1.html
|
||||
|
||||
- AMQP 0.9.1 Quick Reference
|
||||
|
||||
http://www.rabbitmq.com/amqp-0-9-1-quickref.html
|
||||
|
||||
- RabbitMQ Extensions
|
||||
|
||||
http://www.rabbitmq.com/extensions.html
|
||||
|
||||
- For more information about AMQP, visit
|
||||
|
||||
http://www.amqp.org
|
||||
|
||||
- For other Python client libraries see:
|
||||
|
||||
http://www.rabbitmq.com/devtools.html#python-dev
|
||||
|
||||
|
||||
Platform: any
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.5
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.0
|
||||
Classifier: Programming Language :: Python :: 3.1
|
||||
Classifier: Programming Language :: Python :: 3.2
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: OS Independent
|
|
@ -1,62 +0,0 @@
|
|||
Changelog
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
README.rst
|
||||
setup.cfg
|
||||
setup.py
|
||||
amqp/__init__.py
|
||||
amqp/abstract_channel.py
|
||||
amqp/basic_message.py
|
||||
amqp/channel.py
|
||||
amqp/connection.py
|
||||
amqp/exceptions.py
|
||||
amqp/method_framing.py
|
||||
amqp/serialization.py
|
||||
amqp/transport.py
|
||||
amqp.egg-info/PKG-INFO
|
||||
amqp.egg-info/SOURCES.txt
|
||||
amqp.egg-info/dependency_links.txt
|
||||
amqp.egg-info/not-zip-safe
|
||||
amqp.egg-info/top_level.txt
|
||||
demo/amqp_clock.py
|
||||
demo/demo_receive.py
|
||||
demo/demo_send.py
|
||||
docs/Makefile
|
||||
docs/changelog.rst
|
||||
docs/conf.py
|
||||
docs/index.rst
|
||||
docs/.static/.keep
|
||||
docs/.templates/page.html
|
||||
docs/.templates/sidebarintro.html
|
||||
docs/.templates/sidebarlogo.html
|
||||
docs/_ext/applyxrefs.py
|
||||
docs/_ext/literals_to_xrefs.py
|
||||
docs/_theme/celery/theme.conf
|
||||
docs/_theme/celery/static/celery.css_t
|
||||
docs/includes/intro.txt
|
||||
docs/reference/amqp.abstract_channel.rst
|
||||
docs/reference/amqp.basic_message.rst
|
||||
docs/reference/amqp.channel.rst
|
||||
docs/reference/amqp.connection.rst
|
||||
docs/reference/amqp.exceptions.rst
|
||||
docs/reference/amqp.method_framing.rst
|
||||
docs/reference/amqp.serialization.rst
|
||||
docs/reference/amqp.transport.rst
|
||||
docs/reference/index.rst
|
||||
docs/templates/readme.txt
|
||||
extra/README
|
||||
extra/generate_skeleton_0_8.py
|
||||
extra/update_comments_from_spec.py
|
||||
extra/release/bump_version.py
|
||||
extra/release/sphinx-to-rst.py
|
||||
funtests/run_all.py
|
||||
funtests/settings.py
|
||||
funtests/test_basic_message.py
|
||||
funtests/test_channel.py
|
||||
funtests/test_connection.py
|
||||
funtests/test_exceptions.py
|
||||
funtests/test_serialization.py
|
||||
funtests/test_with.py
|
||||
requirements/docs.txt
|
||||
requirements/pkgutils.txt
|
||||
requirements/test.txt
|
|
@ -1,24 +0,0 @@
|
|||
../amqp/transport.py
|
||||
../amqp/abstract_channel.py
|
||||
../amqp/exceptions.py
|
||||
../amqp/basic_message.py
|
||||
../amqp/connection.py
|
||||
../amqp/__init__.py
|
||||
../amqp/method_framing.py
|
||||
../amqp/serialization.py
|
||||
../amqp/channel.py
|
||||
../amqp/transport.pyc
|
||||
../amqp/abstract_channel.pyc
|
||||
../amqp/exceptions.pyc
|
||||
../amqp/basic_message.pyc
|
||||
../amqp/connection.pyc
|
||||
../amqp/__init__.pyc
|
||||
../amqp/method_framing.pyc
|
||||
../amqp/serialization.pyc
|
||||
../amqp/channel.pyc
|
||||
./
|
||||
top_level.txt
|
||||
SOURCES.txt
|
||||
not-zip-safe
|
||||
PKG-INFO
|
||||
dependency_links.txt
|
|
@ -1 +0,0 @@
|
|||
amqp
|
|
@ -1,50 +0,0 @@
|
|||
"""Low-level AMQP client for Python (fork of amqplib)"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
from __future__ import absolute_import
|
||||
|
||||
VERSION = (1, 0, 6)
|
||||
__version__ = '.'.join(map(str, VERSION[0:3])) + ''.join(VERSION[3:])
|
||||
__author__ = 'Barry Pederson'
|
||||
__maintainer__ = 'Ask Solem'
|
||||
__contact__ = 'pyamqp@celeryproject.org'
|
||||
__homepage__ = 'http://github.com/celery/py-amqp'
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
# -eof meta-
|
||||
|
||||
#
|
||||
# Pull in the public items from the various sub-modules
|
||||
#
|
||||
from .basic_message import Message
|
||||
from .channel import Channel
|
||||
from .connection import Connection
|
||||
from .exceptions import (
|
||||
AMQPError,
|
||||
ConnectionError,
|
||||
ChannelError,
|
||||
ConsumerCancel,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'Connection',
|
||||
'Channel',
|
||||
'Message',
|
||||
'AMQPError',
|
||||
'ConnectionError',
|
||||
'ChannelError',
|
||||
'ConsumerCancel',
|
||||
]
|
|
@ -1,93 +0,0 @@
|
|||
"""Code common to Connection and Channel objects."""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .exceptions import AMQPError
|
||||
from .serialization import AMQPWriter
|
||||
|
||||
try:
|
||||
bytes
|
||||
except NameError:
|
||||
# Python 2.5 and lower
|
||||
bytes = str
|
||||
|
||||
__all__ = ['AbstractChannel']
|
||||
|
||||
|
||||
class AbstractChannel(object):
|
||||
"""Superclass for both the Connection, which is treated
|
||||
as channel 0, and other user-created Channel objects.
|
||||
|
||||
The subclasses must have a _METHOD_MAP class property, mapping
|
||||
between AMQP method signatures and Python methods.
|
||||
|
||||
"""
|
||||
def __init__(self, connection, channel_id):
|
||||
self.connection = connection
|
||||
self.channel_id = channel_id
|
||||
connection.channels[channel_id] = self
|
||||
self.method_queue = [] # Higher level queue for methods
|
||||
self.auto_decode = False
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc_info):
|
||||
self.close()
|
||||
|
||||
def _send_method(self, method_sig, args=bytes(), content=None):
|
||||
"""Send a method for our channel."""
|
||||
if isinstance(args, AMQPWriter):
|
||||
args = args.getvalue()
|
||||
|
||||
self.connection.method_writer.write_method(
|
||||
self.channel_id, method_sig, args, content)
|
||||
|
||||
def close(self):
|
||||
"""Close this Channel or Connection"""
|
||||
raise NotImplementedError('Must be overriden in subclass')
|
||||
|
||||
def wait(self, allowed_methods=None):
|
||||
"""Wait for a method that matches our allowed_methods parameter (the
|
||||
default value of None means match any method), and dispatch to it."""
|
||||
method_sig, args, content = self.connection._wait_method(
|
||||
self.channel_id, allowed_methods)
|
||||
|
||||
return self.dispatch_method(method_sig, args, content)
|
||||
|
||||
def dispatch_method(self, method_sig, args, content):
|
||||
if content and \
|
||||
self.auto_decode and \
|
||||
hasattr(content, 'content_encoding'):
|
||||
try:
|
||||
content.body = content.body.decode(content.content_encoding)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
amqp_method = self._METHOD_MAP[method_sig]
|
||||
except KeyError:
|
||||
raise AMQPError('Unknown AMQP method %r' % method_sig)
|
||||
|
||||
if content is None:
|
||||
return amqp_method(self, args)
|
||||
else:
|
||||
return amqp_method(self, args, content)
|
||||
|
||||
#: Placeholder, the concrete implementations will have to
|
||||
#: supply their own versions of _METHOD_MAP
|
||||
_METHOD_MAP = {}
|
|
@ -1,123 +0,0 @@
|
|||
"""Messages for AMQP"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .serialization import GenericContent
|
||||
|
||||
__all__ = ['Message']
|
||||
|
||||
|
||||
class Message(GenericContent):
|
||||
"""A Message for use with the Channnel.basic_* methods."""
|
||||
|
||||
#: Instances of this class have these attributes, which
|
||||
#: are passed back and forth as message properties between
|
||||
#: client and server
|
||||
PROPERTIES = [
|
||||
('content_type', 'shortstr'),
|
||||
('content_encoding', 'shortstr'),
|
||||
('application_headers', 'table'),
|
||||
('delivery_mode', 'octet'),
|
||||
('priority', 'octet'),
|
||||
('correlation_id', 'shortstr'),
|
||||
('reply_to', 'shortstr'),
|
||||
('expiration', 'shortstr'),
|
||||
('message_id', 'shortstr'),
|
||||
('timestamp', 'timestamp'),
|
||||
('type', 'shortstr'),
|
||||
('user_id', 'shortstr'),
|
||||
('app_id', 'shortstr'),
|
||||
('cluster_id', 'shortstr')
|
||||
]
|
||||
|
||||
def __init__(self, body='', children=None, **properties):
|
||||
"""Expected arg types
|
||||
|
||||
body: string
|
||||
children: (not supported)
|
||||
|
||||
Keyword properties may include:
|
||||
|
||||
content_type: shortstr
|
||||
MIME content type
|
||||
|
||||
content_encoding: shortstr
|
||||
MIME content encoding
|
||||
|
||||
application_headers: table
|
||||
Message header field table, a dict with string keys,
|
||||
and string | int | Decimal | datetime | dict values.
|
||||
|
||||
delivery_mode: octet
|
||||
Non-persistent (1) or persistent (2)
|
||||
|
||||
priority: octet
|
||||
The message priority, 0 to 9
|
||||
|
||||
correlation_id: shortstr
|
||||
The application correlation identifier
|
||||
|
||||
reply_to: shortstr
|
||||
The destination to reply to
|
||||
|
||||
expiration: shortstr
|
||||
Message expiration specification
|
||||
|
||||
message_id: shortstr
|
||||
The application message identifier
|
||||
|
||||
timestamp: datetime.datetime
|
||||
The message timestamp
|
||||
|
||||
type: shortstr
|
||||
The message type name
|
||||
|
||||
user_id: shortstr
|
||||
The creating user id
|
||||
|
||||
app_id: shortstr
|
||||
The creating application id
|
||||
|
||||
cluster_id: shortstr
|
||||
Intra-cluster routing identifier
|
||||
|
||||
Unicode bodies are encoded according to the 'content_encoding'
|
||||
argument. If that's None, it's set to 'UTF-8' automatically.
|
||||
|
||||
example::
|
||||
|
||||
msg = Message('hello world',
|
||||
content_type='text/plain',
|
||||
application_headers={'foo': 7})
|
||||
|
||||
"""
|
||||
super(Message, self).__init__(**properties)
|
||||
self.body = body
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Check if the properties and bodies of this Message and another
|
||||
Message are the same.
|
||||
|
||||
Received messages may contain a 'delivery_info' attribute,
|
||||
which isn't compared.
|
||||
|
||||
"""
|
||||
try:
|
||||
return (super(Message, self).__eq__(other) and
|
||||
self.body == other.body)
|
||||
except AttributeError:
|
||||
return NotImplemented
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,923 +0,0 @@
|
|||
"""AMQP Connections"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
import socket
|
||||
|
||||
from array import array
|
||||
try:
|
||||
from ssl import SSLError
|
||||
except ImportError:
|
||||
class SSLError(Exception): # noqa
|
||||
pass
|
||||
|
||||
from . import __version__
|
||||
from .abstract_channel import AbstractChannel
|
||||
from .channel import Channel
|
||||
from .exceptions import ChannelError, ConnectionError
|
||||
from .method_framing import MethodReader, MethodWriter
|
||||
from .serialization import AMQPWriter
|
||||
from .transport import create_transport
|
||||
|
||||
HAS_MSG_PEEK = hasattr(socket, 'MSG_PEEK')
|
||||
|
||||
START_DEBUG_FMT = """
|
||||
Start from server, version: %d.%d, properties: %s, mechanisms: %s, locales: %s
|
||||
""".strip()
|
||||
|
||||
__all__ = ['Connection']
|
||||
|
||||
#
|
||||
# Client property info that gets sent to the server on connection startup
|
||||
#
|
||||
LIBRARY_PROPERTIES = {
|
||||
'product': 'py-amqp',
|
||||
'product_version': __version__,
|
||||
'capabilities': {},
|
||||
}
|
||||
|
||||
AMQP_LOGGER = logging.getLogger('amqp')
|
||||
|
||||
|
||||
class Connection(AbstractChannel):
|
||||
"""The connection class provides methods for a client to establish a
|
||||
network connection to a server, and for both peers to operate the
|
||||
connection thereafter.
|
||||
|
||||
GRAMMAR::
|
||||
|
||||
connection = open-connection *use-connection close-connection
|
||||
open-connection = C:protocol-header
|
||||
S:START C:START-OK
|
||||
*challenge
|
||||
S:TUNE C:TUNE-OK
|
||||
C:OPEN S:OPEN-OK
|
||||
challenge = S:SECURE C:SECURE-OK
|
||||
use-connection = *channel
|
||||
close-connection = C:CLOSE S:CLOSE-OK
|
||||
/ S:CLOSE C:CLOSE-OK
|
||||
|
||||
"""
|
||||
Channel = Channel
|
||||
|
||||
prev_sent = None
|
||||
prev_recv = None
|
||||
missed_heartbeats = 0
|
||||
|
||||
def __init__(self,
|
||||
host='localhost',
|
||||
userid='guest',
|
||||
password='guest',
|
||||
login_method='AMQPLAIN',
|
||||
login_response=None,
|
||||
virtual_host='/',
|
||||
locale='en_US',
|
||||
client_properties=None,
|
||||
ssl=False,
|
||||
connect_timeout=None,
|
||||
channel_max=None,
|
||||
frame_max=None,
|
||||
heartbeat=0,
|
||||
**kwargs):
|
||||
"""Create a connection to the specified host, which should be
|
||||
a 'host[:port]', such as 'localhost', or '1.2.3.4:5672'
|
||||
(defaults to 'localhost', if a port is not specified then
|
||||
5672 is used)
|
||||
|
||||
If login_response is not specified, one is built up for you from
|
||||
userid and password if they are present.
|
||||
|
||||
The 'ssl' parameter may be simply True/False, or for Python >= 2.6
|
||||
a dictionary of options to pass to ssl.wrap_socket() such as
|
||||
requiring certain certificates.
|
||||
|
||||
"""
|
||||
channel_max = channel_max or 65535
|
||||
frame_max = frame_max or 131072
|
||||
if (login_response is None) \
|
||||
and (userid is not None) \
|
||||
and (password is not None):
|
||||
login_response = AMQPWriter()
|
||||
login_response.write_table({'LOGIN': userid, 'PASSWORD': password})
|
||||
login_response = login_response.getvalue()[4:] # Skip the length
|
||||
# at the beginning
|
||||
|
||||
d = dict(LIBRARY_PROPERTIES, **client_properties or {})
|
||||
self._method_override = {(60, 50): self._dispatch_basic_return}
|
||||
|
||||
self.channels = {}
|
||||
# The connection object itself is treated as channel 0
|
||||
super(Connection, self).__init__(self, 0)
|
||||
|
||||
self.transport = None
|
||||
|
||||
# Properties set in the Tune method
|
||||
self.channel_max = channel_max
|
||||
self.frame_max = frame_max
|
||||
self.heartbeat = heartbeat
|
||||
|
||||
self._avail_channel_ids = array('H', range(self.channel_max, 0, -1))
|
||||
|
||||
# Properties set in the Start method
|
||||
self.version_major = 0
|
||||
self.version_minor = 0
|
||||
self.server_properties = {}
|
||||
self.mechanisms = []
|
||||
self.locales = []
|
||||
|
||||
# Let the transport.py module setup the actual
|
||||
# socket connection to the broker.
|
||||
#
|
||||
self.transport = create_transport(host, connect_timeout, ssl)
|
||||
|
||||
self.method_reader = MethodReader(self.transport)
|
||||
self.method_writer = MethodWriter(self.transport, self.frame_max)
|
||||
|
||||
self.wait(allowed_methods=[
|
||||
(10, 10), # start
|
||||
])
|
||||
|
||||
self._x_start_ok(d, login_method, login_response, locale)
|
||||
|
||||
self._wait_tune_ok = True
|
||||
while self._wait_tune_ok:
|
||||
self.wait(allowed_methods=[
|
||||
(10, 20), # secure
|
||||
(10, 30), # tune
|
||||
])
|
||||
|
||||
return self._x_open(virtual_host)
|
||||
|
||||
def _do_close(self):
|
||||
try:
|
||||
self.transport.close()
|
||||
|
||||
temp_list = [x for x in self.channels.values() if x is not self]
|
||||
for ch in temp_list:
|
||||
ch._do_close()
|
||||
except socket.error:
|
||||
pass # connection already closed on the other end
|
||||
finally:
|
||||
self.transport = self.connection = self.channels = None
|
||||
|
||||
def _get_free_channel_id(self):
|
||||
try:
|
||||
return self._avail_channel_ids.pop()
|
||||
except IndexError:
|
||||
raise ConnectionError(
|
||||
'No free channel ids, current=%d, channel_max=%d' % (
|
||||
len(self.channels), self.channel_max), (20, 10))
|
||||
|
||||
def _wait_method(self, channel_id, allowed_methods):
|
||||
"""Wait for a method from the server destined for
|
||||
a particular channel."""
|
||||
#
|
||||
# Check the channel's deferred methods
|
||||
#
|
||||
method_queue = self.channels[channel_id].method_queue
|
||||
|
||||
for queued_method in method_queue:
|
||||
method_sig = queued_method[0]
|
||||
if (allowed_methods is None) \
|
||||
or (method_sig in allowed_methods) \
|
||||
or (method_sig == (20, 40)):
|
||||
method_queue.remove(queued_method)
|
||||
return queued_method
|
||||
|
||||
#
|
||||
# Nothing queued, need to wait for a method from the peer
|
||||
#
|
||||
while 1:
|
||||
channel, method_sig, args, content = \
|
||||
self.method_reader.read_method()
|
||||
|
||||
if (channel == channel_id) \
|
||||
and ((allowed_methods is None) \
|
||||
or (method_sig in allowed_methods) \
|
||||
or (method_sig == (20, 40))):
|
||||
return method_sig, args, content
|
||||
|
||||
#
|
||||
# Certain methods like basic_return should be dispatched
|
||||
# immediately rather than being queued, even if they're not
|
||||
# one of the 'allowed_methods' we're looking for.
|
||||
#
|
||||
if channel and method_sig in self.Channel._IMMEDIATE_METHODS:
|
||||
self.channels[channel].dispatch_method(
|
||||
method_sig, args, content)
|
||||
continue
|
||||
|
||||
#
|
||||
# Not the channel and/or method we were looking for. Queue
|
||||
# this method for later
|
||||
#
|
||||
self.channels[channel].method_queue.append(
|
||||
(method_sig, args, content)
|
||||
)
|
||||
|
||||
#
|
||||
# If we just queued up a method for channel 0 (the Connection
|
||||
# itself) it's probably a close method in reaction to some
|
||||
# error, so deal with it right away.
|
||||
#
|
||||
if not channel:
|
||||
self.wait()
|
||||
|
||||
def channel(self, channel_id=None):
|
||||
"""Fetch a Channel object identified by the numeric channel_id, or
|
||||
create that object if it doesn't already exist."""
|
||||
try:
|
||||
return self.channels[channel_id]
|
||||
except KeyError:
|
||||
return self.Channel(self, channel_id)
|
||||
|
||||
def is_alive(self):
|
||||
if HAS_MSG_PEEK:
|
||||
sock = self.sock
|
||||
prev = sock.gettimeout()
|
||||
sock.settimeout(0.0001)
|
||||
try:
|
||||
sock.recv(1, socket.MSG_PEEK)
|
||||
except socket.timeout:
|
||||
pass
|
||||
except socket.error:
|
||||
return False
|
||||
finally:
|
||||
sock.settimeout(prev)
|
||||
return True
|
||||
|
||||
def drain_events(self, timeout=None):
|
||||
"""Wait for an event on a channel."""
|
||||
chanmap = self.channels
|
||||
chanid, method_sig, args, content = self._wait_multiple(
|
||||
chanmap, None, timeout=timeout)
|
||||
|
||||
channel = chanmap[chanid]
|
||||
|
||||
if content \
|
||||
and channel.auto_decode \
|
||||
and hasattr(content, 'content_encoding'):
|
||||
try:
|
||||
content.body = content.body.decode(content.content_encoding)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
amqp_method = self._method_override.get(method_sig) or \
|
||||
channel._METHOD_MAP.get(method_sig, None)
|
||||
|
||||
if amqp_method is None:
|
||||
raise Exception('Unknown AMQP method (%d, %d)' % method_sig)
|
||||
|
||||
if content is None:
|
||||
return amqp_method(channel, args)
|
||||
else:
|
||||
return amqp_method(channel, args, content)
|
||||
|
||||
def read_timeout(self, timeout=None):
|
||||
if timeout is None:
|
||||
return self.method_reader.read_method()
|
||||
sock = self.sock
|
||||
prev = sock.gettimeout()
|
||||
if prev != timeout:
|
||||
sock.settimeout(timeout)
|
||||
try:
|
||||
try:
|
||||
return self.method_reader.read_method()
|
||||
except SSLError, exc:
|
||||
# http://bugs.python.org/issue10272
|
||||
if 'timed out' in str(exc):
|
||||
raise socket.timeout()
|
||||
# Non-blocking SSL sockets can throw SSLError
|
||||
if 'The operation did not complete' in str(exc):
|
||||
raise socket.timeout()
|
||||
raise
|
||||
finally:
|
||||
if prev != timeout:
|
||||
sock.settimeout(prev)
|
||||
|
||||
def _wait_multiple(self, channels, allowed_methods, timeout=None):
|
||||
for channel_id, channel in channels.iteritems():
|
||||
method_queue = channel.method_queue
|
||||
for queued_method in method_queue:
|
||||
method_sig = queued_method[0]
|
||||
if (allowed_methods is None) \
|
||||
or (method_sig in allowed_methods) \
|
||||
or (method_sig == (20, 40)):
|
||||
method_queue.remove(queued_method)
|
||||
method_sig, args, content = queued_method
|
||||
return channel_id, method_sig, args, content
|
||||
|
||||
# Nothing queued, need to wait for a method from the peer
|
||||
read_timeout = self.read_timeout
|
||||
wait = self.wait
|
||||
while 1:
|
||||
channel, method_sig, args, content = read_timeout(timeout)
|
||||
|
||||
if channel in channels and \
|
||||
(allowed_methods is None or \
|
||||
method_sig in allowed_methods or \
|
||||
method_sig == (20, 40)):
|
||||
return channel, method_sig, args, content
|
||||
|
||||
# Not the channel and/or method we were looking for. Queue
|
||||
# this method for later
|
||||
channels[channel].method_queue.append((method_sig, args, content))
|
||||
|
||||
#
|
||||
# If we just queued up a method for channel 0 (the Connection
|
||||
# itself) it's probably a close method in reaction to some
|
||||
# error, so deal with it right away.
|
||||
#
|
||||
if channel == 0:
|
||||
wait()
|
||||
|
||||
def _dispatch_basic_return(self, channel, args, msg):
|
||||
reply_code = args.read_short()
|
||||
reply_text = args.read_shortstr()
|
||||
exchange = args.read_shortstr()
|
||||
routing_key = args.read_shortstr()
|
||||
|
||||
exc = ChannelError('basic.return', reply_code, reply_text, (50, 60))
|
||||
handlers = channel.events.get('basic_return')
|
||||
if not handlers:
|
||||
raise exc
|
||||
for callback in handlers:
|
||||
callback(exc, exchange, routing_key, msg)
|
||||
|
||||
def close(self, reply_code=0, reply_text='', method_sig=(0, 0)):
|
||||
"""Request a connection close
|
||||
|
||||
This method indicates that the sender wants to close the
|
||||
connection. This may be due to internal conditions (e.g. a
|
||||
forced shut-down) or due to an error handling a specific
|
||||
method, i.e. an exception. When a close is due to an
|
||||
exception, the sender provides the class and method id of the
|
||||
method which caused the exception.
|
||||
|
||||
RULE:
|
||||
|
||||
After sending this method any received method except the
|
||||
Close-OK method MUST be discarded.
|
||||
|
||||
RULE:
|
||||
|
||||
The peer sending this method MAY use a counter or timeout
|
||||
to detect failure of the other peer to respond correctly
|
||||
with the Close-OK method.
|
||||
|
||||
RULE:
|
||||
|
||||
When a server receives the Close method from a client it
|
||||
MUST delete all server-side resources associated with the
|
||||
client's context. A client CANNOT reconnect to a context
|
||||
after sending or receiving a Close method.
|
||||
|
||||
PARAMETERS:
|
||||
reply_code: short
|
||||
|
||||
The reply code. The AMQ reply codes are defined in AMQ
|
||||
RFC 011.
|
||||
|
||||
reply_text: shortstr
|
||||
|
||||
The localised reply text. This text can be logged as an
|
||||
aid to resolving issues.
|
||||
|
||||
class_id: short
|
||||
|
||||
failing method class
|
||||
|
||||
When the close is provoked by a method exception, this
|
||||
is the class of the method.
|
||||
|
||||
method_id: short
|
||||
|
||||
failing method ID
|
||||
|
||||
When the close is provoked by a method exception, this
|
||||
is the ID of the method.
|
||||
|
||||
"""
|
||||
if self.transport is None:
|
||||
# already closed
|
||||
return
|
||||
|
||||
args = AMQPWriter()
|
||||
args.write_short(reply_code)
|
||||
args.write_shortstr(reply_text)
|
||||
args.write_short(method_sig[0]) # class_id
|
||||
args.write_short(method_sig[1]) # method_id
|
||||
self._send_method((10, 50), args)
|
||||
return self.wait(allowed_methods=[
|
||||
(10, 50), # Connection.close
|
||||
(10, 51), # Connection.close_ok
|
||||
])
|
||||
|
||||
def _close(self, args):
|
||||
"""Request a connection close
|
||||
|
||||
This method indicates that the sender wants to close the
|
||||
connection. This may be due to internal conditions (e.g. a
|
||||
forced shut-down) or due to an error handling a specific
|
||||
method, i.e. an exception. When a close is due to an
|
||||
exception, the sender provides the class and method id of the
|
||||
method which caused the exception.
|
||||
|
||||
RULE:
|
||||
|
||||
After sending this method any received method except the
|
||||
Close-OK method MUST be discarded.
|
||||
|
||||
RULE:
|
||||
|
||||
The peer sending this method MAY use a counter or timeout
|
||||
to detect failure of the other peer to respond correctly
|
||||
with the Close-OK method.
|
||||
|
||||
RULE:
|
||||
|
||||
When a server receives the Close method from a client it
|
||||
MUST delete all server-side resources associated with the
|
||||
client's context. A client CANNOT reconnect to a context
|
||||
after sending or receiving a Close method.
|
||||
|
||||
PARAMETERS:
|
||||
reply_code: short
|
||||
|
||||
The reply code. The AMQ reply codes are defined in AMQ
|
||||
RFC 011.
|
||||
|
||||
reply_text: shortstr
|
||||
|
||||
The localised reply text. This text can be logged as an
|
||||
aid to resolving issues.
|
||||
|
||||
class_id: short
|
||||
|
||||
failing method class
|
||||
|
||||
When the close is provoked by a method exception, this
|
||||
is the class of the method.
|
||||
|
||||
method_id: short
|
||||
|
||||
failing method ID
|
||||
|
||||
When the close is provoked by a method exception, this
|
||||
is the ID of the method.
|
||||
|
||||
"""
|
||||
reply_code = args.read_short()
|
||||
reply_text = args.read_shortstr()
|
||||
class_id = args.read_short()
|
||||
method_id = args.read_short()
|
||||
|
||||
self._x_close_ok()
|
||||
|
||||
raise ConnectionError(reply_code, reply_text, (class_id, method_id))
|
||||
|
||||
def _x_close_ok(self):
|
||||
"""Confirm a connection close
|
||||
|
||||
This method confirms a Connection.Close method and tells the
|
||||
recipient that it is safe to release resources for the
|
||||
connection and close the socket.
|
||||
|
||||
RULE:
|
||||
|
||||
A peer that detects a socket closure without having
|
||||
received a Close-Ok handshake method SHOULD log the error.
|
||||
|
||||
"""
|
||||
self._send_method((10, 51))
|
||||
self._do_close()
|
||||
|
||||
def _close_ok(self, args):
|
||||
"""Confirm a connection close
|
||||
|
||||
This method confirms a Connection.Close method and tells the
|
||||
recipient that it is safe to release resources for the
|
||||
connection and close the socket.
|
||||
|
||||
RULE:
|
||||
|
||||
A peer that detects a socket closure without having
|
||||
received a Close-Ok handshake method SHOULD log the error.
|
||||
|
||||
"""
|
||||
self._do_close()
|
||||
|
||||
def _x_open(self, virtual_host, capabilities=''):
|
||||
"""Open connection to virtual host
|
||||
|
||||
This method opens a connection to a virtual host, which is a
|
||||
collection of resources, and acts to separate multiple
|
||||
application domains within a server.
|
||||
|
||||
RULE:
|
||||
|
||||
The client MUST open the context before doing any work on
|
||||
the connection.
|
||||
|
||||
PARAMETERS:
|
||||
virtual_host: shortstr
|
||||
|
||||
virtual host name
|
||||
|
||||
The name of the virtual host to work with.
|
||||
|
||||
RULE:
|
||||
|
||||
If the server supports multiple virtual hosts, it
|
||||
MUST enforce a full separation of exchanges,
|
||||
queues, and all associated entities per virtual
|
||||
host. An application, connected to a specific
|
||||
virtual host, MUST NOT be able to access resources
|
||||
of another virtual host.
|
||||
|
||||
RULE:
|
||||
|
||||
The server SHOULD verify that the client has
|
||||
permission to access the specified virtual host.
|
||||
|
||||
RULE:
|
||||
|
||||
The server MAY configure arbitrary limits per
|
||||
virtual host, such as the number of each type of
|
||||
entity that may be used, per connection and/or in
|
||||
total.
|
||||
|
||||
capabilities: shortstr
|
||||
|
||||
required capabilities
|
||||
|
||||
The client may specify a number of capability names,
|
||||
delimited by spaces. The server can use this string
|
||||
to how to process the client's connection request.
|
||||
|
||||
"""
|
||||
args = AMQPWriter()
|
||||
args.write_shortstr(virtual_host)
|
||||
args.write_shortstr(capabilities)
|
||||
args.write_bit(False)
|
||||
self._send_method((10, 40), args)
|
||||
return self.wait(allowed_methods=[
|
||||
(10, 41), # Connection.open_ok
|
||||
])
|
||||
|
||||
def _open_ok(self, args):
|
||||
"""Signal that the connection is ready
|
||||
|
||||
This method signals to the client that the connection is ready
|
||||
for use.
|
||||
|
||||
PARAMETERS:
|
||||
known_hosts: shortstr (deprecated)
|
||||
|
||||
"""
|
||||
AMQP_LOGGER.debug('Open OK!')
|
||||
|
||||
def _secure(self, args):
|
||||
"""Security mechanism challenge
|
||||
|
||||
The SASL protocol works by exchanging challenges and responses
|
||||
until both peers have received sufficient information to
|
||||
authenticate each other. This method challenges the client to
|
||||
provide more information.
|
||||
|
||||
PARAMETERS:
|
||||
challenge: longstr
|
||||
|
||||
security challenge data
|
||||
|
||||
Challenge information, a block of opaque binary data
|
||||
passed to the security mechanism.
|
||||
|
||||
"""
|
||||
challenge = args.read_longstr() # noqa
|
||||
|
||||
def _x_secure_ok(self, response):
|
||||
"""Security mechanism response
|
||||
|
||||
This method attempts to authenticate, passing a block of SASL
|
||||
data for the security mechanism at the server side.
|
||||
|
||||
PARAMETERS:
|
||||
response: longstr
|
||||
|
||||
security response data
|
||||
|
||||
A block of opaque data passed to the security
|
||||
mechanism. The contents of this data are defined by
|
||||
the SASL security mechanism.
|
||||
|
||||
"""
|
||||
args = AMQPWriter()
|
||||
args.write_longstr(response)
|
||||
self._send_method((10, 21), args)
|
||||
|
||||
def _start(self, args):
|
||||
"""Start connection negotiation
|
||||
|
||||
This method starts the connection negotiation process by
|
||||
telling the client the protocol version that the server
|
||||
proposes, along with a list of security mechanisms which the
|
||||
client can use for authentication.
|
||||
|
||||
RULE:
|
||||
|
||||
If the client cannot handle the protocol version suggested
|
||||
by the server it MUST close the socket connection.
|
||||
|
||||
RULE:
|
||||
|
||||
The server MUST provide a protocol version that is lower
|
||||
than or equal to that requested by the client in the
|
||||
protocol header. If the server cannot support the
|
||||
specified protocol it MUST NOT send this method, but MUST
|
||||
close the socket connection.
|
||||
|
||||
PARAMETERS:
|
||||
version_major: octet
|
||||
|
||||
protocol major version
|
||||
|
||||
The protocol major version that the server agrees to
|
||||
use, which cannot be higher than the client's major
|
||||
version.
|
||||
|
||||
version_minor: octet
|
||||
|
||||
protocol major version
|
||||
|
||||
The protocol minor version that the server agrees to
|
||||
use, which cannot be higher than the client's minor
|
||||
version.
|
||||
|
||||
server_properties: table
|
||||
|
||||
server properties
|
||||
|
||||
mechanisms: longstr
|
||||
|
||||
available security mechanisms
|
||||
|
||||
A list of the security mechanisms that the server
|
||||
supports, delimited by spaces. Currently ASL supports
|
||||
these mechanisms: PLAIN.
|
||||
|
||||
locales: longstr
|
||||
|
||||
available message locales
|
||||
|
||||
A list of the message locales that the server
|
||||
supports, delimited by spaces. The locale defines the
|
||||
language in which the server will send reply texts.
|
||||
|
||||
RULE:
|
||||
|
||||
All servers MUST support at least the en_US
|
||||
locale.
|
||||
|
||||
"""
|
||||
self.version_major = args.read_octet()
|
||||
self.version_minor = args.read_octet()
|
||||
self.server_properties = args.read_table()
|
||||
self.mechanisms = args.read_longstr().split(' ')
|
||||
self.locales = args.read_longstr().split(' ')
|
||||
|
||||
AMQP_LOGGER.debug(START_DEBUG_FMT,
|
||||
self.version_major, self.version_minor,
|
||||
self.server_properties, self.mechanisms, self.locales)
|
||||
|
||||
def _x_start_ok(self, client_properties, mechanism, response, locale):
|
||||
"""Select security mechanism and locale
|
||||
|
||||
This method selects a SASL security mechanism. ASL uses SASL
|
||||
(RFC2222) to negotiate authentication and encryption.
|
||||
|
||||
PARAMETERS:
|
||||
client_properties: table
|
||||
|
||||
client properties
|
||||
|
||||
mechanism: shortstr
|
||||
|
||||
selected security mechanism
|
||||
|
||||
A single security mechanisms selected by the client,
|
||||
which must be one of those specified by the server.
|
||||
|
||||
RULE:
|
||||
|
||||
The client SHOULD authenticate using the highest-
|
||||
level security profile it can handle from the list
|
||||
provided by the server.
|
||||
|
||||
RULE:
|
||||
|
||||
The mechanism field MUST contain one of the
|
||||
security mechanisms proposed by the server in the
|
||||
Start method. If it doesn't, the server MUST close
|
||||
the socket.
|
||||
|
||||
response: longstr
|
||||
|
||||
security response data
|
||||
|
||||
A block of opaque data passed to the security
|
||||
mechanism. The contents of this data are defined by
|
||||
the SASL security mechanism. For the PLAIN security
|
||||
mechanism this is defined as a field table holding two
|
||||
fields, LOGIN and PASSWORD.
|
||||
|
||||
locale: shortstr
|
||||
|
||||
selected message locale
|
||||
|
||||
A single message local selected by the client, which
|
||||
must be one of those specified by the server.
|
||||
|
||||
"""
|
||||
if self.server_capabilities.get('consumer_cancel_notify'):
|
||||
if 'capabilities' not in client_properties:
|
||||
client_properties['capabilities'] = {}
|
||||
client_properties['capabilities']['consumer_cancel_notify'] = True
|
||||
args = AMQPWriter()
|
||||
args.write_table(client_properties)
|
||||
args.write_shortstr(mechanism)
|
||||
args.write_longstr(response)
|
||||
args.write_shortstr(locale)
|
||||
self._send_method((10, 11), args)
|
||||
|
||||
def _tune(self, args):
|
||||
"""Propose connection tuning parameters
|
||||
|
||||
This method proposes a set of connection configuration values
|
||||
to the client. The client can accept and/or adjust these.
|
||||
|
||||
PARAMETERS:
|
||||
channel_max: short
|
||||
|
||||
proposed maximum channels
|
||||
|
||||
The maximum total number of channels that the server
|
||||
allows per connection. Zero means that the server does
|
||||
not impose a fixed limit, but the number of allowed
|
||||
channels may be limited by available server resources.
|
||||
|
||||
frame_max: long
|
||||
|
||||
proposed maximum frame size
|
||||
|
||||
The largest frame size that the server proposes for
|
||||
the connection. The client can negotiate a lower
|
||||
value. Zero means that the server does not impose any
|
||||
specific limit but may reject very large frames if it
|
||||
cannot allocate resources for them.
|
||||
|
||||
RULE:
|
||||
|
||||
Until the frame-max has been negotiated, both
|
||||
peers MUST accept frames of up to 4096 octets
|
||||
large. The minimum non-zero value for the frame-
|
||||
max field is 4096.
|
||||
|
||||
heartbeat: short
|
||||
|
||||
desired heartbeat delay
|
||||
|
||||
The delay, in seconds, of the connection heartbeat
|
||||
that the server wants. Zero means the server does not
|
||||
want a heartbeat.
|
||||
|
||||
"""
|
||||
self.channel_max = args.read_short() or self.channel_max
|
||||
self.frame_max = args.read_long() or self.frame_max
|
||||
self.method_writer.frame_max = self.frame_max
|
||||
heartbeat = args.read_short() # noqa
|
||||
|
||||
self._x_tune_ok(self.channel_max, self.frame_max, self.heartbeat)
|
||||
|
||||
def send_heartbeat(self):
|
||||
self.transport.write_frame(8, 0, bytes())
|
||||
|
||||
def heartbeat_tick(self, rate=2):
|
||||
"""Verify that hartbeats are sent and received.
|
||||
|
||||
:keyword rate: Rate is how often the tick is called
|
||||
compared to the actual heartbeat value. E.g. if
|
||||
the heartbeat is set to 3 seconds, and the tick
|
||||
is called every 3 / 2 seconds, then the rate is 2.
|
||||
|
||||
"""
|
||||
sent_now = self.method_writer.bytes_sent
|
||||
recv_now = self.method_reader.bytes_recv
|
||||
|
||||
if self.prev_sent is not None and self.prev_sent == sent_now:
|
||||
self.send_heartbeat()
|
||||
|
||||
if self.prev_recv is not None and self.prev_recv == recv_now:
|
||||
self.missed_heartbeats += 1
|
||||
else:
|
||||
self.missed_heartbeats = 0
|
||||
|
||||
self.prev_sent, self.prev_recv = sent_now, recv_now
|
||||
|
||||
if self.missed_heartbeats >= rate:
|
||||
raise ConnectionError('Too many heartbeats missed')
|
||||
|
||||
def _x_tune_ok(self, channel_max, frame_max, heartbeat):
|
||||
"""Negotiate connection tuning parameters
|
||||
|
||||
This method sends the client's connection tuning parameters to
|
||||
the server. Certain fields are negotiated, others provide
|
||||
capability information.
|
||||
|
||||
PARAMETERS:
|
||||
channel_max: short
|
||||
|
||||
negotiated maximum channels
|
||||
|
||||
The maximum total number of channels that the client
|
||||
will use per connection. May not be higher than the
|
||||
value specified by the server.
|
||||
|
||||
RULE:
|
||||
|
||||
The server MAY ignore the channel-max value or MAY
|
||||
use it for tuning its resource allocation.
|
||||
|
||||
frame_max: long
|
||||
|
||||
negotiated maximum frame size
|
||||
|
||||
The largest frame size that the client and server will
|
||||
use for the connection. Zero means that the client
|
||||
does not impose any specific limit but may reject very
|
||||
large frames if it cannot allocate resources for them.
|
||||
Note that the frame-max limit applies principally to
|
||||
content frames, where large contents can be broken
|
||||
into frames of arbitrary size.
|
||||
|
||||
RULE:
|
||||
|
||||
Until the frame-max has been negotiated, both
|
||||
peers must accept frames of up to 4096 octets
|
||||
large. The minimum non-zero value for the frame-
|
||||
max field is 4096.
|
||||
|
||||
heartbeat: short
|
||||
|
||||
desired heartbeat delay
|
||||
|
||||
The delay, in seconds, of the connection heartbeat
|
||||
that the client wants. Zero means the client does not
|
||||
want a heartbeat.
|
||||
|
||||
"""
|
||||
args = AMQPWriter()
|
||||
args.write_short(channel_max)
|
||||
args.write_long(frame_max)
|
||||
args.write_short(heartbeat or 0)
|
||||
self._send_method((10, 31), args)
|
||||
self._wait_tune_ok = False
|
||||
|
||||
@property
|
||||
def sock(self):
|
||||
return self.transport.sock
|
||||
|
||||
@property
|
||||
def server_capabilities(self):
|
||||
return self.server_properties.get('capabilities') or {}
|
||||
|
||||
_METHOD_MAP = {
|
||||
(10, 10): _start,
|
||||
(10, 20): _secure,
|
||||
(10, 30): _tune,
|
||||
(10, 41): _open_ok,
|
||||
(10, 50): _close,
|
||||
(10, 51): _close_ok,
|
||||
}
|
||||
|
||||
_IMMEDIATE_METHODS = []
|
||||
connection_errors = (ConnectionError,
|
||||
socket.error,
|
||||
IOError,
|
||||
OSError)
|
||||
channel_errors = (ChannelError, )
|
|
@ -1,125 +0,0 @@
|
|||
"""Exceptions used by amqp"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
from __future__ import absolute_import
|
||||
|
||||
from struct import pack, unpack
|
||||
|
||||
__all__ = ['AMQPError', 'ConnectionError', 'ChannelError']
|
||||
|
||||
|
||||
class AMQPError(Exception):
|
||||
|
||||
def __init__(self, msg, reply_code=None, reply_text=None, method_sig=None,
|
||||
method_name=None):
|
||||
self.message = msg
|
||||
self.amqp_reply_code = reply_code
|
||||
self.amqp_reply_text = reply_text
|
||||
self.amqp_method_sig = method_sig
|
||||
self.method_name = method_name or ''
|
||||
if method_sig and not self.method_name:
|
||||
self.method_name = METHOD_NAME_MAP.get(method_sig, '')
|
||||
Exception.__init__(self, msg, reply_code,
|
||||
reply_text, method_sig, self.method_name)
|
||||
|
||||
def __str__(self):
|
||||
if self.amqp_reply_code:
|
||||
return '%s: (%s, %s, %s)' % (
|
||||
self.message, self.amqp_reply_code, self.amqp_reply_text,
|
||||
self.amqp_method_sig)
|
||||
return self.message
|
||||
|
||||
|
||||
class ConnectionError(AMQPError):
|
||||
pass
|
||||
|
||||
|
||||
class ChannelError(AMQPError):
|
||||
pass
|
||||
|
||||
|
||||
class ConsumerCancel(ChannelError):
|
||||
pass
|
||||
|
||||
|
||||
METHOD_NAME_MAP = {
|
||||
(10, 10): 'Connection.start',
|
||||
(10, 11): 'Connection.start_ok',
|
||||
(10, 20): 'Connection.secure',
|
||||
(10, 21): 'Connection.secure_ok',
|
||||
(10, 30): 'Connection.tune',
|
||||
(10, 31): 'Connection.tune_ok',
|
||||
(10, 40): 'Connection.open',
|
||||
(10, 41): 'Connection.open_ok',
|
||||
(10, 50): 'Connection.close',
|
||||
(10, 51): 'Connection.close_ok',
|
||||
(20, 10): 'Channel.open',
|
||||
(20, 11): 'Channel.open_ok',
|
||||
(20, 20): 'Channel.flow',
|
||||
(20, 21): 'Channel.flow_ok',
|
||||
(20, 40): 'Channel.close',
|
||||
(20, 41): 'Channel.close_ok',
|
||||
(30, 10): 'Access.request',
|
||||
(30, 11): 'Access.request_ok',
|
||||
(40, 10): 'Exchange.declare',
|
||||
(40, 11): 'Exchange.declare_ok',
|
||||
(40, 20): 'Exchange.delete',
|
||||
(40, 21): 'Exchange.delete_ok',
|
||||
(40, 30): 'Exchange.bind',
|
||||
(40, 31): 'Exchange.bind_ok',
|
||||
(40, 40): 'Exchange.unbind',
|
||||
(40, 41): 'Exchange.unbind_ok',
|
||||
(50, 10): 'Queue.declare',
|
||||
(50, 11): 'Queue.declare_ok',
|
||||
(50, 20): 'Queue.bind',
|
||||
(50, 21): 'Queue.bind_ok',
|
||||
(50, 30): 'Queue.purge',
|
||||
(50, 31): 'Queue.purge_ok',
|
||||
(50, 40): 'Queue.delete',
|
||||
(50, 41): 'Queue.delete_ok',
|
||||
(50, 50): 'Queue.unbind',
|
||||
(50, 51): 'Queue.unbind_ok',
|
||||
(60, 10): 'Basic.qos',
|
||||
(60, 11): 'Basic.qos_ok',
|
||||
(60, 20): 'Basic.consume',
|
||||
(60, 21): 'Basic.consume_ok',
|
||||
(60, 30): 'Basic.cancel',
|
||||
(60, 31): 'Basic.cancel_ok',
|
||||
(60, 40): 'Basic.publish',
|
||||
(60, 50): 'Basic.return',
|
||||
(60, 60): 'Basic.deliver',
|
||||
(60, 70): 'Basic.get',
|
||||
(60, 71): 'Basic.get_ok',
|
||||
(60, 72): 'Basic.get_empty',
|
||||
(60, 80): 'Basic.ack',
|
||||
(60, 90): 'Basic.reject',
|
||||
(60, 100): 'Basic.recover_async',
|
||||
(60, 110): 'Basic.recover',
|
||||
(60, 111): 'Basic.recover_ok',
|
||||
(60, 120): 'Basic.nack',
|
||||
(90, 10): 'Tx.select',
|
||||
(90, 11): 'Tx.select_ok',
|
||||
(90, 20): 'Tx.commit',
|
||||
(90, 21): 'Tx.commit_ok',
|
||||
(90, 30): 'Tx.rollback',
|
||||
(90, 31): 'Tx.rollback_ok',
|
||||
(85, 10): 'Confirm.select',
|
||||
(85, 11): 'Confirm.select_ok',
|
||||
}
|
||||
|
||||
|
||||
for _method_id, _method_name in list(METHOD_NAME_MAP.items()):
|
||||
METHOD_NAME_MAP[unpack('>I', pack('>HH', *_method_id))[0]] = _method_name
|
|
@ -1,228 +0,0 @@
|
|||
"""Convert between frames and higher-level AMQP methods"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
from __future__ import absolute_import
|
||||
|
||||
from collections import defaultdict
|
||||
from struct import pack, unpack
|
||||
from Queue import Queue
|
||||
|
||||
try:
|
||||
bytes
|
||||
except NameError:
|
||||
# Python 2.5 and lower
|
||||
bytes = str
|
||||
|
||||
from .basic_message import Message
|
||||
from .exceptions import AMQPError
|
||||
from .serialization import AMQPReader
|
||||
|
||||
__all__ = ['MethodReader']
|
||||
|
||||
#
|
||||
# MethodReader needs to know which methods are supposed
|
||||
# to be followed by content headers and bodies.
|
||||
#
|
||||
_CONTENT_METHODS = [
|
||||
(60, 50), # Basic.return
|
||||
(60, 60), # Basic.deliver
|
||||
(60, 71), # Basic.get_ok
|
||||
]
|
||||
|
||||
|
||||
class _PartialMessage(object):
|
||||
"""Helper class to build up a multi-frame method."""
|
||||
|
||||
def __init__(self, method_sig, args):
|
||||
self.method_sig = method_sig
|
||||
self.args = args
|
||||
self.msg = Message()
|
||||
self.body_parts = []
|
||||
self.body_received = 0
|
||||
self.body_size = None
|
||||
self.complete = False
|
||||
|
||||
def add_header(self, payload):
|
||||
class_id, weight, self.body_size = unpack('>HHQ', payload[:12])
|
||||
self.msg._load_properties(payload[12:])
|
||||
self.complete = (self.body_size == 0)
|
||||
|
||||
def add_payload(self, payload):
|
||||
self.body_parts.append(payload)
|
||||
self.body_received += len(payload)
|
||||
|
||||
if self.body_received == self.body_size:
|
||||
self.msg.body = bytes().join(self.body_parts)
|
||||
self.complete = True
|
||||
|
||||
|
||||
class MethodReader(object):
|
||||
"""Helper class to receive frames from the broker, combine them if
|
||||
necessary with content-headers and content-bodies into complete methods.
|
||||
|
||||
Normally a method is represented as a tuple containing
|
||||
(channel, method_sig, args, content).
|
||||
|
||||
In the case of a framing error, an :exc:`ConnectionError` is placed
|
||||
in the queue.
|
||||
|
||||
In the case of unexpected frames, a tuple made up of
|
||||
``(channel, ChannelError)`` is placed in the queue.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, source):
|
||||
self.source = source
|
||||
self.queue = Queue()
|
||||
self.running = False
|
||||
self.partial_messages = {}
|
||||
self.heartbeats = 0
|
||||
# For each channel, which type is expected next
|
||||
self.expected_types = defaultdict(lambda: 1)
|
||||
# not an actual byte count, just incremented whenever we receive
|
||||
self.bytes_recv = 0
|
||||
|
||||
def _next_method(self):
|
||||
"""Read the next method from the source, once one complete method has
|
||||
been assembled it is placed in the internal queue."""
|
||||
empty = self.queue.empty
|
||||
read_frame = self.source.read_frame
|
||||
while empty():
|
||||
try:
|
||||
frame_type, channel, payload = read_frame()
|
||||
except Exception, e:
|
||||
#
|
||||
# Connection was closed? Framing Error?
|
||||
#
|
||||
self.queue.put(e)
|
||||
break
|
||||
|
||||
self.bytes_recv += 1
|
||||
|
||||
if frame_type not in (self.expected_types[channel], 8):
|
||||
self.queue.put((
|
||||
channel,
|
||||
AMQPError(
|
||||
'Received frame type %s while expecting type: %s' % (
|
||||
frame_type, self.expected_types[channel]))
|
||||
))
|
||||
elif frame_type == 1:
|
||||
self._process_method_frame(channel, payload)
|
||||
elif frame_type == 2:
|
||||
self._process_content_header(channel, payload)
|
||||
elif frame_type == 3:
|
||||
self._process_content_body(channel, payload)
|
||||
elif frame_type == 8:
|
||||
self._process_heartbeat(channel, payload)
|
||||
|
||||
def _process_heartbeat(self, channel, payload):
|
||||
self.heartbeats += 1
|
||||
|
||||
def _process_method_frame(self, channel, payload):
|
||||
"""Process Method frames"""
|
||||
method_sig = unpack('>HH', payload[:4])
|
||||
args = AMQPReader(payload[4:])
|
||||
|
||||
if method_sig in _CONTENT_METHODS:
|
||||
#
|
||||
# Save what we've got so far and wait for the content-header
|
||||
#
|
||||
self.partial_messages[channel] = _PartialMessage(method_sig, args)
|
||||
self.expected_types[channel] = 2
|
||||
else:
|
||||
self.queue.put((channel, method_sig, args, None))
|
||||
|
||||
def _process_content_header(self, channel, payload):
|
||||
"""Process Content Header frames"""
|
||||
partial = self.partial_messages[channel]
|
||||
partial.add_header(payload)
|
||||
|
||||
if partial.complete:
|
||||
#
|
||||
# a bodyless message, we're done
|
||||
#
|
||||
self.queue.put((channel, partial.method_sig,
|
||||
partial.args, partial.msg))
|
||||
self.partial_messages.pop(channel, None)
|
||||
self.expected_types[channel] = 1
|
||||
else:
|
||||
#
|
||||
# wait for the content-body
|
||||
#
|
||||
self.expected_types[channel] = 3
|
||||
|
||||
def _process_content_body(self, channel, payload):
|
||||
"""Process Content Body frames"""
|
||||
partial = self.partial_messages[channel]
|
||||
partial.add_payload(payload)
|
||||
if partial.complete:
|
||||
#
|
||||
# Stick the message in the queue and go back to
|
||||
# waiting for method frames
|
||||
#
|
||||
self.queue.put((channel, partial.method_sig,
|
||||
partial.args, partial.msg))
|
||||
self.partial_messages.pop(channel, None)
|
||||
self.expected_types[channel] = 1
|
||||
|
||||
def read_method(self):
|
||||
"""Read a method from the peer."""
|
||||
self._next_method()
|
||||
m = self.queue.get()
|
||||
if isinstance(m, Exception):
|
||||
raise m
|
||||
if isinstance(m, tuple) and isinstance(m[1], AMQPError):
|
||||
raise m[1]
|
||||
return m
|
||||
|
||||
|
||||
class MethodWriter(object):
|
||||
"""Convert AMQP methods into AMQP frames and send them out
|
||||
to the peer."""
|
||||
|
||||
def __init__(self, dest, frame_max):
|
||||
self.dest = dest
|
||||
self.frame_max = frame_max
|
||||
self.bytes_sent = 0
|
||||
|
||||
def write_method(self, channel, method_sig, args, content=None):
|
||||
write_frame = self.dest.write_frame
|
||||
payload = pack('>HH', method_sig[0], method_sig[1]) + args
|
||||
|
||||
if content:
|
||||
# do this early, so we can raise an exception if there's a
|
||||
# problem with the content properties, before sending the
|
||||
# first frame
|
||||
body = content.body
|
||||
if isinstance(body, unicode):
|
||||
coding = content.properties.get('content_encoding', None)
|
||||
if coding is None:
|
||||
coding = content.properties['content_encoding'] = 'UTF-8'
|
||||
|
||||
body = body.encode(coding)
|
||||
properties = content._serialize_properties()
|
||||
|
||||
write_frame(1, channel, payload)
|
||||
|
||||
if content:
|
||||
payload = pack('>HHQ', method_sig[0], 0, len(body)) + properties
|
||||
|
||||
write_frame(2, channel, payload)
|
||||
|
||||
chunk_size = self.frame_max - 8
|
||||
for i in xrange(0, len(body), chunk_size):
|
||||
write_frame(3, channel, body[i:i + chunk_size])
|
||||
self.bytes_sent += 1
|
|
@ -1,432 +0,0 @@
|
|||
"""
|
||||
Convert between bytestreams and higher-level AMQP types.
|
||||
|
||||
2007-11-05 Barry Pederson <bp@barryp.org>
|
||||
|
||||
"""
|
||||
# Copyright (C) 2007 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
from __future__ import absolute_import
|
||||
|
||||
import sys
|
||||
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from struct import pack, unpack
|
||||
from time import mktime
|
||||
|
||||
IS_PY3K = sys.version_info[0] >= 3
|
||||
|
||||
if IS_PY3K:
|
||||
def byte(n):
|
||||
return bytes([n])
|
||||
else:
|
||||
byte = chr
|
||||
|
||||
try:
|
||||
from io import BytesIO
|
||||
except ImportError: # Py2.5
|
||||
try:
|
||||
from cStringIO import StringIO as BytesIO # noqa
|
||||
except ImportError:
|
||||
from StringIO import StringIO as BytesIO # noqa
|
||||
|
||||
try:
|
||||
bytes
|
||||
except NameError:
|
||||
# Python 2.5 and lower
|
||||
bytes = str
|
||||
|
||||
|
||||
class AMQPReader(object):
|
||||
"""Read higher-level AMQP types from a bytestream."""
|
||||
def __init__(self, source):
|
||||
"""Source should be either a file-like object with a read() method, or
|
||||
a plain (non-unicode) string."""
|
||||
if isinstance(source, bytes):
|
||||
self.input = BytesIO(source)
|
||||
elif hasattr(source, 'read'):
|
||||
self.input = source
|
||||
else:
|
||||
raise ValueError(
|
||||
'AMQPReader needs a file-like object or plain string')
|
||||
|
||||
self.bitcount = self.bits = 0
|
||||
|
||||
def close(self):
|
||||
self.input.close()
|
||||
|
||||
def read(self, n):
|
||||
"""Read n bytes."""
|
||||
self.bitcount = self.bits = 0
|
||||
return self.input.read(n)
|
||||
|
||||
def read_bit(self):
|
||||
"""Read a single boolean value."""
|
||||
if not self.bitcount:
|
||||
self.bits = ord(self.input.read(1))
|
||||
self.bitcount = 8
|
||||
result = (self.bits & 1) == 1
|
||||
self.bits >>= 1
|
||||
self.bitcount -= 1
|
||||
return result
|
||||
|
||||
def read_octet(self):
|
||||
"""Read one byte, return as an integer"""
|
||||
self.bitcount = self.bits = 0
|
||||
return unpack('B', self.input.read(1))[0]
|
||||
|
||||
def read_short(self):
|
||||
"""Read an unsigned 16-bit integer"""
|
||||
self.bitcount = self.bits = 0
|
||||
return unpack('>H', self.input.read(2))[0]
|
||||
|
||||
def read_long(self):
|
||||
"""Read an unsigned 32-bit integer"""
|
||||
self.bitcount = self.bits = 0
|
||||
return unpack('>I', self.input.read(4))[0]
|
||||
|
||||
def read_longlong(self):
|
||||
"""Read an unsigned 64-bit integer"""
|
||||
self.bitcount = self.bits = 0
|
||||
return unpack('>Q', self.input.read(8))[0]
|
||||
|
||||
def read_float(self):
|
||||
"""Read float value."""
|
||||
self.bitcount = self.bits = 0
|
||||
return unpack('>d', self.input.read(8))[0]
|
||||
|
||||
def read_shortstr(self):
|
||||
"""Read a short string that's stored in up to 255 bytes.
|
||||
|
||||
The encoding isn't specified in the AMQP spec, so
|
||||
assume it's utf-8
|
||||
|
||||
"""
|
||||
self.bitcount = self.bits = 0
|
||||
slen = unpack('B', self.input.read(1))[0]
|
||||
return self.input.read(slen).decode('utf-8')
|
||||
|
||||
def read_longstr(self):
|
||||
"""Read a string that's up to 2**32 bytes.
|
||||
|
||||
The encoding isn't specified in the AMQP spec, so
|
||||
assume it's utf-8
|
||||
|
||||
"""
|
||||
self.bitcount = self.bits = 0
|
||||
slen = unpack('>I', self.input.read(4))[0]
|
||||
return self.input.read(slen).decode('utf-8')
|
||||
|
||||
def read_table(self):
|
||||
"""Read an AMQP table, and return as a Python dictionary."""
|
||||
self.bitcount = self.bits = 0
|
||||
tlen = unpack('>I', self.input.read(4))[0]
|
||||
table_data = AMQPReader(self.input.read(tlen))
|
||||
result = {}
|
||||
while table_data.input.tell() < tlen:
|
||||
name = table_data.read_shortstr()
|
||||
ftype = ord(table_data.input.read(1))
|
||||
if ftype == 83: # 'S'
|
||||
val = table_data.read_longstr()
|
||||
elif ftype == 73: # 'I'
|
||||
val = unpack('>i', table_data.input.read(4))[0]
|
||||
elif ftype == 68: # 'D'
|
||||
d = table_data.read_octet()
|
||||
n = unpack('>i', table_data.input.read(4))[0]
|
||||
val = Decimal(n) / Decimal(10 ** d)
|
||||
elif ftype == 84: # 'T'
|
||||
val = table_data.read_timestamp()
|
||||
elif ftype == 70: # 'F'
|
||||
val = table_data.read_table() # recurse
|
||||
elif ftype == 116:
|
||||
val = table_data.read_bit()
|
||||
elif ftype == 100:
|
||||
val = table_data.read_float()
|
||||
else:
|
||||
raise ValueError('Unknown table item type: %s' % repr(ftype))
|
||||
result[name] = val
|
||||
return result
|
||||
|
||||
def read_timestamp(self):
|
||||
"""Read and AMQP timestamp, which is a 64-bit integer representing
|
||||
seconds since the Unix epoch in 1-second resolution.
|
||||
|
||||
Return as a Python datetime.datetime object,
|
||||
expressed as localtime.
|
||||
|
||||
"""
|
||||
return datetime.fromtimestamp(self.read_longlong())
|
||||
|
||||
|
||||
class AMQPWriter(object):
|
||||
"""Convert higher-level AMQP types to bytestreams."""
|
||||
|
||||
def __init__(self, dest=None):
|
||||
"""dest may be a file-type object (with a write() method). If None
|
||||
then a BytesIO is created, and the contents can be accessed with
|
||||
this class's getvalue() method."""
|
||||
self.out = BytesIO() if dest is None else dest
|
||||
self.bits = []
|
||||
self.bitcount = 0
|
||||
|
||||
def _flushbits(self):
|
||||
if self.bits:
|
||||
out = self.out
|
||||
for b in self.bits:
|
||||
out.write(pack('B', b))
|
||||
self.bits = []
|
||||
self.bitcount = 0
|
||||
|
||||
def close(self):
|
||||
"""Pass through if possible to any file-like destinations."""
|
||||
try:
|
||||
self.out.close()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def flush(self):
|
||||
"""Pass through if possible to any file-like destinations."""
|
||||
try:
|
||||
self.out.flush()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def getvalue(self):
|
||||
"""Get what's been encoded so far if we're working with a BytesIO."""
|
||||
self._flushbits()
|
||||
return self.out.getvalue()
|
||||
|
||||
def write(self, s):
|
||||
"""Write a plain Python string with no special encoding in Python 2.x,
|
||||
or bytes in Python 3.x"""
|
||||
self._flushbits()
|
||||
self.out.write(s)
|
||||
|
||||
def write_bit(self, b):
|
||||
"""Write a boolean value."""
|
||||
b = 1 if b else 0
|
||||
shift = self.bitcount % 8
|
||||
if shift == 0:
|
||||
self.bits.append(0)
|
||||
self.bits[-1] |= (b << shift)
|
||||
self.bitcount += 1
|
||||
|
||||
def write_octet(self, n):
|
||||
"""Write an integer as an unsigned 8-bit value."""
|
||||
if n < 0 or n > 255:
|
||||
raise ValueError('Octet %r out of range 0..255' % (n, ))
|
||||
self._flushbits()
|
||||
self.out.write(pack('B', n))
|
||||
|
||||
def write_short(self, n):
|
||||
"""Write an integer as an unsigned 16-bit value."""
|
||||
if n < 0 or n > 65535:
|
||||
raise ValueError('Octet %r out of range 0..65535' % (n, ))
|
||||
self._flushbits()
|
||||
self.out.write(pack('>H', int(n)))
|
||||
|
||||
def write_long(self, n):
|
||||
"""Write an integer as an unsigned2 32-bit value."""
|
||||
if n < 0 or n >= 2 ** 32:
|
||||
raise ValueError('Octet %r out of range 0..2**31-1' % (n, ))
|
||||
self._flushbits()
|
||||
self.out.write(pack('>I', n))
|
||||
|
||||
def write_longlong(self, n):
|
||||
"""Write an integer as an unsigned 64-bit value."""
|
||||
if n < 0 or n >= 2 ** 64:
|
||||
raise ValueError('Octet %r out of range 0..2**64-1' % (n, ))
|
||||
self._flushbits()
|
||||
self.out.write(pack('>Q', n))
|
||||
|
||||
def write_shortstr(self, s):
|
||||
"""Write a string up to 255 bytes long (after any encoding).
|
||||
|
||||
If passed a unicode string, encode with UTF-8.
|
||||
|
||||
"""
|
||||
self._flushbits()
|
||||
if isinstance(s, unicode):
|
||||
s = s.encode('utf-8')
|
||||
if len(s) > 255:
|
||||
raise ValueError('String too long (%r)' % (len(s), ))
|
||||
self.write_octet(len(s))
|
||||
self.out.write(s)
|
||||
|
||||
def write_longstr(self, s):
|
||||
"""Write a string up to 2**32 bytes long after encoding.
|
||||
|
||||
If passed a unicode string, encode as UTF-8.
|
||||
|
||||
"""
|
||||
self._flushbits()
|
||||
if isinstance(s, unicode):
|
||||
s = s.encode('utf-8')
|
||||
self.write_long(len(s))
|
||||
self.out.write(s)
|
||||
|
||||
def write_table(self, d):
|
||||
"""Write out a Python dictionary made of up string keys, and values
|
||||
that are strings, signed integers, Decimal, datetime.datetime, or
|
||||
sub-dictionaries following the same constraints."""
|
||||
self._flushbits()
|
||||
table_data = AMQPWriter()
|
||||
for k, v in d.iteritems():
|
||||
table_data.write_shortstr(k)
|
||||
if isinstance(v, basestring):
|
||||
if isinstance(v, unicode):
|
||||
v = v.encode('utf-8')
|
||||
table_data.write(byte(83)) # 'S'
|
||||
table_data.write_longstr(v)
|
||||
elif isinstance(v, bool):
|
||||
table_data.write(pack('>cB', 't', int(v)))
|
||||
elif isinstance(v, float):
|
||||
table_data.write(pack('>cd', 'd', v))
|
||||
elif isinstance(v, (int, long)):
|
||||
table_data.write(pack('>ci', 'I', v))
|
||||
elif isinstance(v, Decimal):
|
||||
table_data.write(byte(68)) # 'D'
|
||||
sign, digits, exponent = v.as_tuple()
|
||||
v = 0
|
||||
for d in digits:
|
||||
v = (v * 10) + d
|
||||
if sign:
|
||||
v = -v
|
||||
table_data.write_octet(-exponent)
|
||||
table_data.write(pack('>i', v))
|
||||
elif isinstance(v, datetime):
|
||||
table_data.write(byte(84)) # 'T'
|
||||
table_data.write_timestamp(v)
|
||||
## FIXME: timezone ?
|
||||
elif isinstance(v, dict):
|
||||
table_data.write(byte(70)) # 'F'
|
||||
table_data.write_table(v)
|
||||
else:
|
||||
raise ValueError('%r not serializable in AMQP' % (v, ))
|
||||
table_data = table_data.getvalue()
|
||||
self.write_long(len(table_data))
|
||||
self.out.write(table_data)
|
||||
|
||||
def write_timestamp(self, v):
|
||||
"""Write out a Python datetime.datetime object as a 64-bit integer
|
||||
representing seconds since the Unix epoch."""
|
||||
self.out.write(pack('>q', long(mktime(v.timetuple()))))
|
||||
|
||||
|
||||
class GenericContent(object):
|
||||
"""Abstract base class for AMQP content.
|
||||
|
||||
Subclasses should override the PROPERTIES attribute.
|
||||
|
||||
"""
|
||||
PROPERTIES = [('dummy', 'shortstr')]
|
||||
|
||||
def __init__(self, **props):
|
||||
"""Save the properties appropriate to this AMQP content type
|
||||
in a 'properties' dictionary."""
|
||||
d = {}
|
||||
for propname, _ in self.PROPERTIES:
|
||||
if propname in props:
|
||||
d[propname] = props[propname]
|
||||
# FIXME: should we ignore unknown properties?
|
||||
|
||||
self.properties = d
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Check if this object has the same properties as another
|
||||
content object."""
|
||||
try:
|
||||
return self.properties == other.properties
|
||||
except AttributeError:
|
||||
return NotImplemented
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Look for additional properties in the 'properties'
|
||||
dictionary, and if present - the 'delivery_info'
|
||||
dictionary."""
|
||||
if name == '__setstate__':
|
||||
# Allows pickling/unpickling to work
|
||||
raise AttributeError('__setstate__')
|
||||
|
||||
if name in self.properties:
|
||||
return self.properties[name]
|
||||
|
||||
if 'delivery_info' in self.__dict__ \
|
||||
and name in self.delivery_info:
|
||||
return self.delivery_info[name]
|
||||
|
||||
raise AttributeError(name)
|
||||
|
||||
def _load_properties(self, raw_bytes):
|
||||
"""Given the raw bytes containing the property-flags and property-list
|
||||
from a content-frame-header, parse and insert into a dictionary
|
||||
stored in this object as an attribute named 'properties'."""
|
||||
r = AMQPReader(raw_bytes)
|
||||
|
||||
#
|
||||
# Read 16-bit shorts until we get one with a low bit set to zero
|
||||
#
|
||||
flags = []
|
||||
while 1:
|
||||
flag_bits = r.read_short()
|
||||
flags.append(flag_bits)
|
||||
if flag_bits & 1 == 0:
|
||||
break
|
||||
|
||||
shift = 0
|
||||
d = {}
|
||||
for key, proptype in self.PROPERTIES:
|
||||
if shift == 0:
|
||||
if not flags:
|
||||
break
|
||||
flag_bits, flags = flags[0], flags[1:]
|
||||
shift = 15
|
||||
if flag_bits & (1 << shift):
|
||||
d[key] = getattr(r, 'read_' + proptype)()
|
||||
shift -= 1
|
||||
|
||||
self.properties = d
|
||||
|
||||
def _serialize_properties(self):
|
||||
"""serialize the 'properties' attribute (a dictionary) into
|
||||
the raw bytes making up a set of property flags and a
|
||||
property list, suitable for putting into a content frame header."""
|
||||
shift = 15
|
||||
flag_bits = 0
|
||||
flags = []
|
||||
raw_bytes = AMQPWriter()
|
||||
for key, proptype in self.PROPERTIES:
|
||||
val = self.properties.get(key, None)
|
||||
if val is not None:
|
||||
if shift == 0:
|
||||
flags.append(flag_bits)
|
||||
flag_bits = 0
|
||||
shift = 15
|
||||
|
||||
flag_bits |= (1 << shift)
|
||||
if proptype != 'bit':
|
||||
getattr(raw_bytes, 'write_' + proptype)(val)
|
||||
|
||||
shift -= 1
|
||||
|
||||
flags.append(flag_bits)
|
||||
result = AMQPWriter()
|
||||
for flag_bits in flags:
|
||||
result.write_short(flag_bits)
|
||||
result.write(raw_bytes.getvalue())
|
||||
|
||||
return result.getvalue()
|
|
@ -1,243 +0,0 @@
|
|||
"""
|
||||
Read/Write AMQP frames over network transports.
|
||||
|
||||
2009-01-14 Barry Pederson <bp@barryp.org>
|
||||
|
||||
"""
|
||||
# Copyright (C) 2009 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
from __future__ import absolute_import
|
||||
|
||||
import errno
|
||||
import re
|
||||
import socket
|
||||
|
||||
#
|
||||
# See if Python 2.6+ SSL support is available
|
||||
#
|
||||
try:
|
||||
import ssl
|
||||
HAVE_PY26_SSL = True
|
||||
except:
|
||||
HAVE_PY26_SSL = False
|
||||
|
||||
try:
|
||||
bytes
|
||||
except:
|
||||
# Python 2.5 and lower
|
||||
bytes = str
|
||||
|
||||
from struct import pack, unpack
|
||||
|
||||
from .exceptions import AMQPError
|
||||
|
||||
AMQP_PORT = 5672
|
||||
|
||||
# Yes, Advanced Message Queuing Protocol Protocol is redundant
|
||||
AMQP_PROTOCOL_HEADER = 'AMQP\x01\x01\x00\x09'.encode('latin_1')
|
||||
|
||||
# Match things like: [fe80::1]:5432, from RFC 2732
|
||||
IPV6_LITERAL = re.compile(r'\[([\.0-9a-f:]+)\](?::(\d+))?')
|
||||
|
||||
|
||||
class _AbstractTransport(object):
|
||||
"""Common superclass for TCP and SSL transports"""
|
||||
|
||||
def __init__(self, host, connect_timeout):
|
||||
msg = 'socket.getaddrinfo() for %s returned an empty list' % host
|
||||
port = AMQP_PORT
|
||||
|
||||
m = IPV6_LITERAL.match(host)
|
||||
if m:
|
||||
host = m.group(1)
|
||||
if m.group(2):
|
||||
port = int(m.group(2))
|
||||
else:
|
||||
if ':' in host:
|
||||
host, port = host.rsplit(':', 1)
|
||||
port = int(port)
|
||||
|
||||
self.sock = None
|
||||
for res in socket.getaddrinfo(host, port, 0,
|
||||
socket.SOCK_STREAM, socket.SOL_TCP):
|
||||
af, socktype, proto, canonname, sa = res
|
||||
try:
|
||||
self.sock = socket.socket(af, socktype, proto)
|
||||
self.sock.settimeout(connect_timeout)
|
||||
self.sock.connect(sa)
|
||||
except socket.error, msg:
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
continue
|
||||
break
|
||||
|
||||
if not self.sock:
|
||||
# Didn't connect, return the most recent error message
|
||||
raise socket.error, msg
|
||||
|
||||
self.sock.settimeout(None)
|
||||
self.sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
|
||||
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
|
||||
self._setup_transport()
|
||||
|
||||
self._write(AMQP_PROTOCOL_HEADER)
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
self.close()
|
||||
except socket.error:
|
||||
pass
|
||||
finally:
|
||||
self.sock = None
|
||||
|
||||
def _read(self, n, initial=False):
|
||||
"""Read exactly n bytes from the peer"""
|
||||
raise NotImplementedError('Must be overriden in subclass')
|
||||
|
||||
def _setup_transport(self):
|
||||
"""Do any additional initialization of the class (used
|
||||
by the subclasses)."""
|
||||
pass
|
||||
|
||||
def _shutdown_transport(self):
|
||||
"""Do any preliminary work in shutting down the connection."""
|
||||
pass
|
||||
|
||||
def _write(self, s):
|
||||
"""Completely write a string to the peer."""
|
||||
raise NotImplementedError('Must be overriden in subclass')
|
||||
|
||||
def close(self):
|
||||
if self.sock is not None:
|
||||
self._shutdown_transport()
|
||||
# Call shutdown first to make sure that pending messages
|
||||
# reach the AMQP broker if the program exits after
|
||||
# calling this method.
|
||||
self.sock.shutdown(socket.SHUT_RDWR)
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
|
||||
def read_frame(self):
|
||||
"""Read an AMQP frame."""
|
||||
frame_type, channel, size = unpack('>BHI', self._read(7, True))
|
||||
payload = self._read(size)
|
||||
ch = ord(self._read(1))
|
||||
if ch == 206: # '\xce'
|
||||
return frame_type, channel, payload
|
||||
else:
|
||||
raise AMQPError(
|
||||
'Framing Error, received 0x%02x while expecting 0xce' % ch)
|
||||
|
||||
def write_frame(self, frame_type, channel, payload):
|
||||
"""Write out an AMQP frame."""
|
||||
size = len(payload)
|
||||
self._write(pack('>BHI%dsB' % size,
|
||||
frame_type, channel, size, payload, 0xce))
|
||||
|
||||
|
||||
class SSLTransport(_AbstractTransport):
|
||||
"""Transport that works over SSL"""
|
||||
|
||||
def __init__(self, host, connect_timeout, ssl):
|
||||
if isinstance(ssl, dict):
|
||||
self.sslopts = ssl
|
||||
self.sslobj = None
|
||||
super(SSLTransport, self).__init__(host, connect_timeout)
|
||||
|
||||
def _setup_transport(self):
|
||||
"""Wrap the socket in an SSL object, either the
|
||||
new Python 2.6 version, or the older Python 2.5 and
|
||||
lower version."""
|
||||
if HAVE_PY26_SSL:
|
||||
if hasattr(self, 'sslopts'):
|
||||
self.sslobj = ssl.wrap_socket(self.sock, **self.sslopts)
|
||||
else:
|
||||
self.sslobj = ssl.wrap_socket(self.sock)
|
||||
self.sslobj.do_handshake()
|
||||
else:
|
||||
self.sslobj = socket.ssl(self.sock)
|
||||
|
||||
def _shutdown_transport(self):
|
||||
"""Unwrap a Python 2.6 SSL socket, so we can call shutdown()"""
|
||||
if HAVE_PY26_SSL and (self.sslobj is not None):
|
||||
self.sock = self.sslobj.unwrap()
|
||||
self.sslobj = None
|
||||
|
||||
def _read(self, n, initial=False):
|
||||
"""It seems that SSL Objects read() method may not supply as much
|
||||
as you're asking for, at least with extremely large messages.
|
||||
somewhere > 16K - found this in the test_channel.py test_large
|
||||
unittest."""
|
||||
result = ''
|
||||
|
||||
while len(result) < n:
|
||||
try:
|
||||
s = self.sslobj.read(n - len(result))
|
||||
except socket.error, exc:
|
||||
if not initial and exc.errno in (errno.EAGAIN, errno.EINTR):
|
||||
continue
|
||||
raise
|
||||
if not s:
|
||||
raise IOError('Socket closed')
|
||||
result += s
|
||||
|
||||
return result
|
||||
|
||||
def _write(self, s):
|
||||
"""Write a string out to the SSL socket fully."""
|
||||
while s:
|
||||
n = self.sslobj.write(s)
|
||||
if not n:
|
||||
raise IOError('Socket closed')
|
||||
s = s[n:]
|
||||
|
||||
|
||||
class TCPTransport(_AbstractTransport):
|
||||
"""Transport that deals directly with TCP socket."""
|
||||
|
||||
def _setup_transport(self):
|
||||
"""Setup to _write() directly to the socket, and
|
||||
do our own buffered reads."""
|
||||
self._write = self.sock.sendall
|
||||
self._read_buffer = bytes()
|
||||
|
||||
def _read(self, n, initial=False):
|
||||
"""Read exactly n bytes from the socket"""
|
||||
while len(self._read_buffer) < n:
|
||||
try:
|
||||
s = self.sock.recv(65536)
|
||||
except socket.error, exc:
|
||||
if not initial and exc.errno in (errno.EAGAIN, errno.EINTR):
|
||||
continue
|
||||
raise
|
||||
if not s:
|
||||
raise IOError('Socket closed')
|
||||
self._read_buffer += s
|
||||
|
||||
result = self._read_buffer[:n]
|
||||
self._read_buffer = self._read_buffer[n:]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def create_transport(host, connect_timeout, ssl=False):
|
||||
"""Given a few parameters from the Connection constructor,
|
||||
select and create a subclass of _AbstractTransport."""
|
||||
if ssl:
|
||||
return SSLTransport(host, connect_timeout, ssl)
|
||||
else:
|
||||
return TCPTransport(host, connect_timeout)
|
|
@ -1,22 +0,0 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: amqplib
|
||||
Version: 1.0.2
|
||||
Summary: AMQP Client Library
|
||||
Home-page: http://code.google.com/p/py-amqplib/
|
||||
Author: Barry Pederson
|
||||
Author-email: bp@barryp.org
|
||||
License: LGPL
|
||||
Description: UNKNOWN
|
||||
Platform: UNKNOWN
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.4
|
||||
Classifier: Programming Language :: Python :: 2.5
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.0
|
||||
Classifier: Programming Language :: Python :: 3.1
|
||||
Classifier: Programming Language :: Python :: 3.2
|
||||
Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
|
||||
Classifier: Intended Audience :: Developers
|
|
@ -1,38 +0,0 @@
|
|||
CHANGES
|
||||
INSTALL
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
README
|
||||
TODO
|
||||
setup.cfg
|
||||
setup.py
|
||||
amqplib/__init__.py
|
||||
amqplib.egg-info/PKG-INFO
|
||||
amqplib.egg-info/SOURCES.txt
|
||||
amqplib.egg-info/dependency_links.txt
|
||||
amqplib.egg-info/top_level.txt
|
||||
amqplib/client_0_8/__init__.py
|
||||
amqplib/client_0_8/abstract_channel.py
|
||||
amqplib/client_0_8/basic_message.py
|
||||
amqplib/client_0_8/channel.py
|
||||
amqplib/client_0_8/connection.py
|
||||
amqplib/client_0_8/exceptions.py
|
||||
amqplib/client_0_8/method_framing.py
|
||||
amqplib/client_0_8/serialization.py
|
||||
amqplib/client_0_8/transport.py
|
||||
demo/amqp_clock.py
|
||||
demo/demo_receive.py
|
||||
demo/demo_send.py
|
||||
docs/code_layout.txt
|
||||
docs/overview.txt
|
||||
extras/README
|
||||
extras/generate_skeleton_0_8.py
|
||||
tests/client_0_8/fake_redirect.py
|
||||
tests/client_0_8/run_all.py
|
||||
tests/client_0_8/settings.py
|
||||
tests/client_0_8/test_basic_message.py
|
||||
tests/client_0_8/test_channel.py
|
||||
tests/client_0_8/test_connection.py
|
||||
tests/client_0_8/test_exceptions.py
|
||||
tests/client_0_8/test_serialization.py
|
||||
tests/client_0_8/test_with.py
|
|
@ -1,25 +0,0 @@
|
|||
../amqplib/__init__.py
|
||||
../amqplib/client_0_8/transport.py
|
||||
../amqplib/client_0_8/abstract_channel.py
|
||||
../amqplib/client_0_8/exceptions.py
|
||||
../amqplib/client_0_8/basic_message.py
|
||||
../amqplib/client_0_8/connection.py
|
||||
../amqplib/client_0_8/__init__.py
|
||||
../amqplib/client_0_8/method_framing.py
|
||||
../amqplib/client_0_8/serialization.py
|
||||
../amqplib/client_0_8/channel.py
|
||||
../amqplib/__init__.pyc
|
||||
../amqplib/client_0_8/transport.pyc
|
||||
../amqplib/client_0_8/abstract_channel.pyc
|
||||
../amqplib/client_0_8/exceptions.pyc
|
||||
../amqplib/client_0_8/basic_message.pyc
|
||||
../amqplib/client_0_8/connection.pyc
|
||||
../amqplib/client_0_8/__init__.pyc
|
||||
../amqplib/client_0_8/method_framing.pyc
|
||||
../amqplib/client_0_8/serialization.pyc
|
||||
../amqplib/client_0_8/channel.pyc
|
||||
./
|
||||
top_level.txt
|
||||
SOURCES.txt
|
||||
PKG-INFO
|
||||
dependency_links.txt
|
|
@ -1 +0,0 @@
|
|||
amqplib
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
"""
|
||||
AMQP Client implementing the 0-8 spec.
|
||||
|
||||
"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
|
||||
#
|
||||
# Pull in the public items from the various sub-modules
|
||||
#
|
||||
from basic_message import *
|
||||
from channel import *
|
||||
from connection import *
|
||||
from exceptions import *
|
||||
|
||||
__all__ = [
|
||||
'Connection',
|
||||
'Channel', # here mainly so it shows in in pydoc
|
||||
'Message',
|
||||
'AMQPException',
|
||||
'AMQPConnectionException',
|
||||
'AMQPChannelException',
|
||||
]
|
|
@ -1,124 +0,0 @@
|
|||
"""
|
||||
Code common to Connection and Channel objects.
|
||||
|
||||
"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
|
||||
from serialization import AMQPWriter
|
||||
|
||||
try:
|
||||
bytes
|
||||
except NameError:
|
||||
# Python 2.5 and lower
|
||||
bytes = str
|
||||
|
||||
__all__ = [
|
||||
'AbstractChannel',
|
||||
]
|
||||
|
||||
|
||||
class AbstractChannel(object):
|
||||
"""
|
||||
Superclass for both the Connection, which is treated
|
||||
as channel 0, and other user-created Channel objects.
|
||||
|
||||
The subclasses must have a _METHOD_MAP class property, mapping
|
||||
between AMQP method signatures and Python methods.
|
||||
|
||||
"""
|
||||
def __init__(self, connection, channel_id):
|
||||
self.connection = connection
|
||||
self.channel_id = channel_id
|
||||
connection.channels[channel_id] = self
|
||||
self.method_queue = [] # Higher level queue for methods
|
||||
self.auto_decode = False
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
"""
|
||||
Support for Python >= 2.5 'with' statements.
|
||||
|
||||
"""
|
||||
return self
|
||||
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
"""
|
||||
Support for Python >= 2.5 'with' statements.
|
||||
|
||||
"""
|
||||
self.close()
|
||||
|
||||
|
||||
def _send_method(self, method_sig, args=bytes(), content=None):
|
||||
"""
|
||||
Send a method for our channel.
|
||||
|
||||
"""
|
||||
if isinstance(args, AMQPWriter):
|
||||
args = args.getvalue()
|
||||
|
||||
self.connection.method_writer.write_method(self.channel_id,
|
||||
method_sig, args, content)
|
||||
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Close this Channel or Connection
|
||||
|
||||
"""
|
||||
raise NotImplementedError('Must be overriden in subclass')
|
||||
|
||||
|
||||
|
||||
def wait(self, allowed_methods=None):
|
||||
"""
|
||||
Wait for a method that matches our allowed_methods parameter (the
|
||||
default value of None means match any method), and dispatch to it.
|
||||
|
||||
"""
|
||||
method_sig, args, content = self.connection._wait_method(
|
||||
self.channel_id, allowed_methods)
|
||||
|
||||
return self.dispatch_method(method_sig, args, content)
|
||||
|
||||
|
||||
def dispatch_method(self, method_sig, args, content):
|
||||
if content \
|
||||
and self.auto_decode \
|
||||
and hasattr(content, 'content_encoding'):
|
||||
try:
|
||||
content.body = content.body.decode(content.content_encoding)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
amqp_method = self._METHOD_MAP.get(method_sig, None)
|
||||
|
||||
if amqp_method is None:
|
||||
raise Exception('Unknown AMQP method (%d, %d)' % method_sig)
|
||||
|
||||
if content is None:
|
||||
return amqp_method(self, args)
|
||||
else:
|
||||
return amqp_method(self, args, content)
|
||||
|
||||
|
||||
#
|
||||
# Placeholder, the concrete implementations will have to
|
||||
# supply their own versions of _METHOD_MAP
|
||||
#
|
||||
_METHOD_MAP = {}
|
|
@ -1,132 +0,0 @@
|
|||
"""
|
||||
Messages for AMQP
|
||||
|
||||
"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
|
||||
|
||||
from serialization import GenericContent
|
||||
|
||||
__all__ = [
|
||||
'Message',
|
||||
]
|
||||
|
||||
|
||||
class Message(GenericContent):
|
||||
"""
|
||||
A Message for use with the Channnel.basic_* methods.
|
||||
|
||||
"""
|
||||
#
|
||||
# Instances of this class have these attributes, which
|
||||
# are passed back and forth as message properties between
|
||||
# client and server
|
||||
#
|
||||
PROPERTIES = [
|
||||
('content_type', 'shortstr'),
|
||||
('content_encoding', 'shortstr'),
|
||||
('application_headers', 'table'),
|
||||
('delivery_mode', 'octet'),
|
||||
('priority', 'octet'),
|
||||
('correlation_id', 'shortstr'),
|
||||
('reply_to', 'shortstr'),
|
||||
('expiration', 'shortstr'),
|
||||
('message_id', 'shortstr'),
|
||||
('timestamp', 'timestamp'),
|
||||
('type', 'shortstr'),
|
||||
('user_id', 'shortstr'),
|
||||
('app_id', 'shortstr'),
|
||||
('cluster_id', 'shortstr')
|
||||
]
|
||||
|
||||
def __init__(self, body='', children=None, **properties):
|
||||
"""
|
||||
Expected arg types
|
||||
|
||||
body: string
|
||||
children: (not supported)
|
||||
|
||||
Keyword properties may include:
|
||||
|
||||
content_type: shortstr
|
||||
MIME content type
|
||||
|
||||
content_encoding: shortstr
|
||||
MIME content encoding
|
||||
|
||||
application_headers: table
|
||||
Message header field table, a dict with string keys,
|
||||
and string | int | Decimal | datetime | dict values.
|
||||
|
||||
delivery_mode: octet
|
||||
Non-persistent (1) or persistent (2)
|
||||
|
||||
priority: octet
|
||||
The message priority, 0 to 9
|
||||
|
||||
correlation_id: shortstr
|
||||
The application correlation identifier
|
||||
|
||||
reply_to: shortstr
|
||||
The destination to reply to
|
||||
|
||||
expiration: shortstr
|
||||
Message expiration specification
|
||||
|
||||
message_id: shortstr
|
||||
The application message identifier
|
||||
|
||||
timestamp: datetime.datetime
|
||||
The message timestamp
|
||||
|
||||
type: shortstr
|
||||
The message type name
|
||||
|
||||
user_id: shortstr
|
||||
The creating user id
|
||||
|
||||
app_id: shortstr
|
||||
The creating application id
|
||||
|
||||
cluster_id: shortstr
|
||||
Intra-cluster routing identifier
|
||||
|
||||
Unicode bodies are encoded according to the 'content_encoding'
|
||||
argument. If that's None, it's set to 'UTF-8' automatically.
|
||||
|
||||
example:
|
||||
|
||||
msg = Message('hello world',
|
||||
content_type='text/plain',
|
||||
application_headers={'foo': 7})
|
||||
|
||||
"""
|
||||
super(Message, self).__init__(**properties)
|
||||
self.body = body
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
Check if the properties and bodies of this Message and another
|
||||
Message are the same.
|
||||
|
||||
Received messages may contain a 'delivery_info' attribute,
|
||||
which isn't compared.
|
||||
|
||||
"""
|
||||
return super(Message, self).__eq__(other) \
|
||||
and hasattr(other, 'body') and (self.body == other.body)
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,842 +0,0 @@
|
|||
"""
|
||||
AMQP 0-8 Connections
|
||||
|
||||
"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
|
||||
import logging
|
||||
|
||||
from abstract_channel import AbstractChannel
|
||||
from channel import Channel
|
||||
from exceptions import *
|
||||
from method_framing import MethodReader, MethodWriter
|
||||
from serialization import AMQPReader, AMQPWriter
|
||||
from transport import create_transport
|
||||
|
||||
__all__ = [
|
||||
'Connection',
|
||||
]
|
||||
|
||||
#
|
||||
# Client property info that gets sent to the server on connection startup
|
||||
#
|
||||
LIBRARY_PROPERTIES = {
|
||||
'library': 'Python amqplib',
|
||||
'library_version': '1.0.2',
|
||||
}
|
||||
|
||||
AMQP_LOGGER = logging.getLogger('amqplib')
|
||||
|
||||
|
||||
class Connection(AbstractChannel):
|
||||
"""
|
||||
The connection class provides methods for a client to establish a
|
||||
network connection to a server, and for both peers to operate the
|
||||
connection thereafter.
|
||||
|
||||
GRAMMAR:
|
||||
|
||||
connection = open-connection *use-connection close-connection
|
||||
open-connection = C:protocol-header
|
||||
S:START C:START-OK
|
||||
*challenge
|
||||
S:TUNE C:TUNE-OK
|
||||
C:OPEN S:OPEN-OK | S:REDIRECT
|
||||
challenge = S:SECURE C:SECURE-OK
|
||||
use-connection = *channel
|
||||
close-connection = C:CLOSE S:CLOSE-OK
|
||||
/ S:CLOSE C:CLOSE-OK
|
||||
|
||||
"""
|
||||
def __init__(self,
|
||||
host='localhost',
|
||||
userid='guest',
|
||||
password='guest',
|
||||
login_method='AMQPLAIN',
|
||||
login_response=None,
|
||||
virtual_host='/',
|
||||
locale='en_US',
|
||||
client_properties=None,
|
||||
ssl=False,
|
||||
insist=False,
|
||||
connect_timeout=None,
|
||||
**kwargs):
|
||||
"""
|
||||
Create a connection to the specified host, which should be
|
||||
a 'host[:port]', such as 'localhost', or '1.2.3.4:5672'
|
||||
(defaults to 'localhost', if a port is not specified then
|
||||
5672 is used)
|
||||
|
||||
If login_response is not specified, one is built up for you from
|
||||
userid and password if they are present.
|
||||
|
||||
The 'ssl' parameter may be simply True/False, or for Python >= 2.6
|
||||
a dictionary of options to pass to ssl.wrap_socket() such as
|
||||
requiring certain certificates.
|
||||
|
||||
"""
|
||||
if (login_response is None) \
|
||||
and (userid is not None) \
|
||||
and (password is not None):
|
||||
login_response = AMQPWriter()
|
||||
login_response.write_table({'LOGIN': userid, 'PASSWORD': password})
|
||||
login_response = login_response.getvalue()[4:] #Skip the length
|
||||
#at the beginning
|
||||
|
||||
d = {}
|
||||
d.update(LIBRARY_PROPERTIES)
|
||||
if client_properties:
|
||||
d.update(client_properties)
|
||||
|
||||
self.known_hosts = ''
|
||||
|
||||
while True:
|
||||
self.channels = {}
|
||||
# The connection object itself is treated as channel 0
|
||||
super(Connection, self).__init__(self, 0)
|
||||
|
||||
self.transport = None
|
||||
|
||||
# Properties set in the Tune method
|
||||
self.channel_max = 65535
|
||||
self.frame_max = 131072
|
||||
self.heartbeat = 0
|
||||
|
||||
# Properties set in the Start method
|
||||
self.version_major = 0
|
||||
self.version_minor = 0
|
||||
self.server_properties = {}
|
||||
self.mechanisms = []
|
||||
self.locales = []
|
||||
|
||||
# Let the transport.py module setup the actual
|
||||
# socket connection to the broker.
|
||||
#
|
||||
self.transport = create_transport(host, connect_timeout, ssl)
|
||||
|
||||
self.method_reader = MethodReader(self.transport)
|
||||
self.method_writer = MethodWriter(self.transport, self.frame_max)
|
||||
|
||||
self.wait(allowed_methods=[
|
||||
(10, 10), # start
|
||||
])
|
||||
|
||||
self._x_start_ok(d, login_method, login_response, locale)
|
||||
|
||||
self._wait_tune_ok = True
|
||||
while self._wait_tune_ok:
|
||||
self.wait(allowed_methods=[
|
||||
(10, 20), # secure
|
||||
(10, 30), # tune
|
||||
])
|
||||
|
||||
host = self._x_open(virtual_host, insist=insist)
|
||||
if host is None:
|
||||
# we weren't redirected
|
||||
return
|
||||
|
||||
# we were redirected, close the socket, loop and try again
|
||||
try:
|
||||
self.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _do_close(self):
|
||||
self.transport.close()
|
||||
self.transport = None
|
||||
|
||||
temp_list = [x for x in self.channels.values() if x is not self]
|
||||
for ch in temp_list:
|
||||
ch._do_close()
|
||||
|
||||
self.connection = self.channels = None
|
||||
|
||||
|
||||
def _get_free_channel_id(self):
|
||||
for i in xrange(1, self.channel_max+1):
|
||||
if i not in self.channels:
|
||||
return i
|
||||
raise AMQPException('No free channel ids, current=%d, channel_max=%d'
|
||||
% (len(self.channels), self.channel_max))
|
||||
|
||||
|
||||
def _wait_method(self, channel_id, allowed_methods):
|
||||
"""
|
||||
Wait for a method from the server destined for
|
||||
a particular channel.
|
||||
|
||||
"""
|
||||
#
|
||||
# Check the channel's deferred methods
|
||||
#
|
||||
method_queue = self.channels[channel_id].method_queue
|
||||
|
||||
for queued_method in method_queue:
|
||||
method_sig = queued_method[0]
|
||||
if (allowed_methods is None) \
|
||||
or (method_sig in allowed_methods) \
|
||||
or (method_sig == (20, 40)):
|
||||
method_queue.remove(queued_method)
|
||||
return queued_method
|
||||
|
||||
#
|
||||
# Nothing queued, need to wait for a method from the peer
|
||||
#
|
||||
while True:
|
||||
channel, method_sig, args, content = \
|
||||
self.method_reader.read_method()
|
||||
|
||||
if (channel == channel_id) \
|
||||
and ((allowed_methods is None) \
|
||||
or (method_sig in allowed_methods) \
|
||||
or (method_sig == (20, 40))):
|
||||
return method_sig, args, content
|
||||
|
||||
#
|
||||
# Certain methods like basic_return should be dispatched
|
||||
# immediately rather than being queued, even if they're not
|
||||
# one of the 'allowed_methods' we're looking for.
|
||||
#
|
||||
if (channel != 0) and (method_sig in Channel._IMMEDIATE_METHODS):
|
||||
self.channels[channel].dispatch_method(method_sig, args, content)
|
||||
continue
|
||||
|
||||
#
|
||||
# Not the channel and/or method we were looking for. Queue
|
||||
# this method for later
|
||||
#
|
||||
self.channels[channel].method_queue.append((method_sig, args, content))
|
||||
|
||||
#
|
||||
# If we just queued up a method for channel 0 (the Connection
|
||||
# itself) it's probably a close method in reaction to some
|
||||
# error, so deal with it right away.
|
||||
#
|
||||
if channel == 0:
|
||||
self.wait()
|
||||
|
||||
|
||||
def channel(self, channel_id=None):
|
||||
"""
|
||||
Fetch a Channel object identified by the numeric channel_id, or
|
||||
create that object if it doesn't already exist.
|
||||
|
||||
"""
|
||||
if channel_id in self.channels:
|
||||
return self.channels[channel_id]
|
||||
|
||||
return Channel(self, channel_id)
|
||||
|
||||
|
||||
#################
|
||||
|
||||
def close(self, reply_code=0, reply_text='', method_sig=(0, 0)):
|
||||
"""
|
||||
request a connection close
|
||||
|
||||
This method indicates that the sender wants to close the
|
||||
connection. This may be due to internal conditions (e.g. a
|
||||
forced shut-down) or due to an error handling a specific
|
||||
method, i.e. an exception. When a close is due to an
|
||||
exception, the sender provides the class and method id of the
|
||||
method which caused the exception.
|
||||
|
||||
RULE:
|
||||
|
||||
After sending this method any received method except the
|
||||
Close-OK method MUST be discarded.
|
||||
|
||||
RULE:
|
||||
|
||||
The peer sending this method MAY use a counter or timeout
|
||||
to detect failure of the other peer to respond correctly
|
||||
with the Close-OK method.
|
||||
|
||||
RULE:
|
||||
|
||||
When a server receives the Close method from a client it
|
||||
MUST delete all server-side resources associated with the
|
||||
client's context. A client CANNOT reconnect to a context
|
||||
after sending or receiving a Close method.
|
||||
|
||||
PARAMETERS:
|
||||
reply_code: short
|
||||
|
||||
The reply code. The AMQ reply codes are defined in AMQ
|
||||
RFC 011.
|
||||
|
||||
reply_text: shortstr
|
||||
|
||||
The localised reply text. This text can be logged as an
|
||||
aid to resolving issues.
|
||||
|
||||
class_id: short
|
||||
|
||||
failing method class
|
||||
|
||||
When the close is provoked by a method exception, this
|
||||
is the class of the method.
|
||||
|
||||
method_id: short
|
||||
|
||||
failing method ID
|
||||
|
||||
When the close is provoked by a method exception, this
|
||||
is the ID of the method.
|
||||
|
||||
"""
|
||||
if self.transport is None:
|
||||
# already closed
|
||||
return
|
||||
|
||||
args = AMQPWriter()
|
||||
args.write_short(reply_code)
|
||||
args.write_shortstr(reply_text)
|
||||
args.write_short(method_sig[0]) # class_id
|
||||
args.write_short(method_sig[1]) # method_id
|
||||
self._send_method((10, 60), args)
|
||||
return self.wait(allowed_methods=[
|
||||
(10, 61), # Connection.close_ok
|
||||
])
|
||||
|
||||
|
||||
def _close(self, args):
|
||||
"""
|
||||
request a connection close
|
||||
|
||||
This method indicates that the sender wants to close the
|
||||
connection. This may be due to internal conditions (e.g. a
|
||||
forced shut-down) or due to an error handling a specific
|
||||
method, i.e. an exception. When a close is due to an
|
||||
exception, the sender provides the class and method id of the
|
||||
method which caused the exception.
|
||||
|
||||
RULE:
|
||||
|
||||
After sending this method any received method except the
|
||||
Close-OK method MUST be discarded.
|
||||
|
||||
RULE:
|
||||
|
||||
The peer sending this method MAY use a counter or timeout
|
||||
to detect failure of the other peer to respond correctly
|
||||
with the Close-OK method.
|
||||
|
||||
RULE:
|
||||
|
||||
When a server receives the Close method from a client it
|
||||
MUST delete all server-side resources associated with the
|
||||
client's context. A client CANNOT reconnect to a context
|
||||
after sending or receiving a Close method.
|
||||
|
||||
PARAMETERS:
|
||||
reply_code: short
|
||||
|
||||
The reply code. The AMQ reply codes are defined in AMQ
|
||||
RFC 011.
|
||||
|
||||
reply_text: shortstr
|
||||
|
||||
The localised reply text. This text can be logged as an
|
||||
aid to resolving issues.
|
||||
|
||||
class_id: short
|
||||
|
||||
failing method class
|
||||
|
||||
When the close is provoked by a method exception, this
|
||||
is the class of the method.
|
||||
|
||||
method_id: short
|
||||
|
||||
failing method ID
|
||||
|
||||
When the close is provoked by a method exception, this
|
||||
is the ID of the method.
|
||||
|
||||
"""
|
||||
reply_code = args.read_short()
|
||||
reply_text = args.read_shortstr()
|
||||
class_id = args.read_short()
|
||||
method_id = args.read_short()
|
||||
|
||||
self._x_close_ok()
|
||||
|
||||
raise AMQPConnectionException(reply_code, reply_text, (class_id, method_id))
|
||||
|
||||
|
||||
def _x_close_ok(self):
|
||||
"""
|
||||
confirm a connection close
|
||||
|
||||
This method confirms a Connection.Close method and tells the
|
||||
recipient that it is safe to release resources for the
|
||||
connection and close the socket.
|
||||
|
||||
RULE:
|
||||
|
||||
A peer that detects a socket closure without having
|
||||
received a Close-Ok handshake method SHOULD log the error.
|
||||
|
||||
"""
|
||||
self._send_method((10, 61))
|
||||
self._do_close()
|
||||
|
||||
|
||||
def _close_ok(self, args):
|
||||
"""
|
||||
confirm a connection close
|
||||
|
||||
This method confirms a Connection.Close method and tells the
|
||||
recipient that it is safe to release resources for the
|
||||
connection and close the socket.
|
||||
|
||||
RULE:
|
||||
|
||||
A peer that detects a socket closure without having
|
||||
received a Close-Ok handshake method SHOULD log the error.
|
||||
|
||||
"""
|
||||
self._do_close()
|
||||
|
||||
|
||||
def _x_open(self, virtual_host, capabilities='', insist=False):
|
||||
"""
|
||||
open connection to virtual host
|
||||
|
||||
This method opens a connection to a virtual host, which is a
|
||||
collection of resources, and acts to separate multiple
|
||||
application domains within a server.
|
||||
|
||||
RULE:
|
||||
|
||||
The client MUST open the context before doing any work on
|
||||
the connection.
|
||||
|
||||
PARAMETERS:
|
||||
virtual_host: shortstr
|
||||
|
||||
virtual host name
|
||||
|
||||
The name of the virtual host to work with.
|
||||
|
||||
RULE:
|
||||
|
||||
If the server supports multiple virtual hosts, it
|
||||
MUST enforce a full separation of exchanges,
|
||||
queues, and all associated entities per virtual
|
||||
host. An application, connected to a specific
|
||||
virtual host, MUST NOT be able to access resources
|
||||
of another virtual host.
|
||||
|
||||
RULE:
|
||||
|
||||
The server SHOULD verify that the client has
|
||||
permission to access the specified virtual host.
|
||||
|
||||
RULE:
|
||||
|
||||
The server MAY configure arbitrary limits per
|
||||
virtual host, such as the number of each type of
|
||||
entity that may be used, per connection and/or in
|
||||
total.
|
||||
|
||||
capabilities: shortstr
|
||||
|
||||
required capabilities
|
||||
|
||||
The client may specify a number of capability names,
|
||||
delimited by spaces. The server can use this string
|
||||
to how to process the client's connection request.
|
||||
|
||||
insist: boolean
|
||||
|
||||
insist on connecting to server
|
||||
|
||||
In a configuration with multiple load-sharing servers,
|
||||
the server may respond to a Connection.Open method
|
||||
with a Connection.Redirect. The insist option tells
|
||||
the server that the client is insisting on a
|
||||
connection to the specified server.
|
||||
|
||||
RULE:
|
||||
|
||||
When the client uses the insist option, the server
|
||||
SHOULD accept the client connection unless it is
|
||||
technically unable to do so.
|
||||
|
||||
"""
|
||||
args = AMQPWriter()
|
||||
args.write_shortstr(virtual_host)
|
||||
args.write_shortstr(capabilities)
|
||||
args.write_bit(insist)
|
||||
self._send_method((10, 40), args)
|
||||
return self.wait(allowed_methods=[
|
||||
(10, 41), # Connection.open_ok
|
||||
(10, 50), # Connection.redirect
|
||||
])
|
||||
|
||||
|
||||
def _open_ok(self, args):
|
||||
"""
|
||||
signal that the connection is ready
|
||||
|
||||
This method signals to the client that the connection is ready
|
||||
for use.
|
||||
|
||||
PARAMETERS:
|
||||
known_hosts: shortstr
|
||||
|
||||
"""
|
||||
self.known_hosts = args.read_shortstr()
|
||||
AMQP_LOGGER.debug('Open OK! known_hosts [%s]' % self.known_hosts)
|
||||
return None
|
||||
|
||||
|
||||
def _redirect(self, args):
|
||||
"""
|
||||
asks the client to use a different server
|
||||
|
||||
This method redirects the client to another server, based on
|
||||
the requested virtual host and/or capabilities.
|
||||
|
||||
RULE:
|
||||
|
||||
When getting the Connection.Redirect method, the client
|
||||
SHOULD reconnect to the host specified, and if that host
|
||||
is not present, to any of the hosts specified in the
|
||||
known-hosts list.
|
||||
|
||||
PARAMETERS:
|
||||
host: shortstr
|
||||
|
||||
server to connect to
|
||||
|
||||
Specifies the server to connect to. This is an IP
|
||||
address or a DNS name, optionally followed by a colon
|
||||
and a port number. If no port number is specified, the
|
||||
client should use the default port number for the
|
||||
protocol.
|
||||
|
||||
known_hosts: shortstr
|
||||
|
||||
"""
|
||||
host = args.read_shortstr()
|
||||
self.known_hosts = args.read_shortstr()
|
||||
AMQP_LOGGER.debug('Redirected to [%s], known_hosts [%s]' % (host, self.known_hosts))
|
||||
return host
|
||||
|
||||
|
||||
def _secure(self, args):
|
||||
"""
|
||||
security mechanism challenge
|
||||
|
||||
The SASL protocol works by exchanging challenges and responses
|
||||
until both peers have received sufficient information to
|
||||
authenticate each other. This method challenges the client to
|
||||
provide more information.
|
||||
|
||||
PARAMETERS:
|
||||
challenge: longstr
|
||||
|
||||
security challenge data
|
||||
|
||||
Challenge information, a block of opaque binary data
|
||||
passed to the security mechanism.
|
||||
|
||||
"""
|
||||
challenge = args.read_longstr()
|
||||
|
||||
|
||||
def _x_secure_ok(self, response):
|
||||
"""
|
||||
security mechanism response
|
||||
|
||||
This method attempts to authenticate, passing a block of SASL
|
||||
data for the security mechanism at the server side.
|
||||
|
||||
PARAMETERS:
|
||||
response: longstr
|
||||
|
||||
security response data
|
||||
|
||||
A block of opaque data passed to the security
|
||||
mechanism. The contents of this data are defined by
|
||||
the SASL security mechanism.
|
||||
|
||||
"""
|
||||
args = AMQPWriter()
|
||||
args.write_longstr(response)
|
||||
self._send_method((10, 21), args)
|
||||
|
||||
|
||||
def _start(self, args):
|
||||
"""
|
||||
start connection negotiation
|
||||
|
||||
This method starts the connection negotiation process by
|
||||
telling the client the protocol version that the server
|
||||
proposes, along with a list of security mechanisms which the
|
||||
client can use for authentication.
|
||||
|
||||
RULE:
|
||||
|
||||
If the client cannot handle the protocol version suggested
|
||||
by the server it MUST close the socket connection.
|
||||
|
||||
RULE:
|
||||
|
||||
The server MUST provide a protocol version that is lower
|
||||
than or equal to that requested by the client in the
|
||||
protocol header. If the server cannot support the
|
||||
specified protocol it MUST NOT send this method, but MUST
|
||||
close the socket connection.
|
||||
|
||||
PARAMETERS:
|
||||
version_major: octet
|
||||
|
||||
protocol major version
|
||||
|
||||
The protocol major version that the server agrees to
|
||||
use, which cannot be higher than the client's major
|
||||
version.
|
||||
|
||||
version_minor: octet
|
||||
|
||||
protocol major version
|
||||
|
||||
The protocol minor version that the server agrees to
|
||||
use, which cannot be higher than the client's minor
|
||||
version.
|
||||
|
||||
server_properties: table
|
||||
|
||||
server properties
|
||||
|
||||
mechanisms: longstr
|
||||
|
||||
available security mechanisms
|
||||
|
||||
A list of the security mechanisms that the server
|
||||
supports, delimited by spaces. Currently ASL supports
|
||||
these mechanisms: PLAIN.
|
||||
|
||||
locales: longstr
|
||||
|
||||
available message locales
|
||||
|
||||
A list of the message locales that the server
|
||||
supports, delimited by spaces. The locale defines the
|
||||
language in which the server will send reply texts.
|
||||
|
||||
RULE:
|
||||
|
||||
All servers MUST support at least the en_US
|
||||
locale.
|
||||
|
||||
"""
|
||||
self.version_major = args.read_octet()
|
||||
self.version_minor = args.read_octet()
|
||||
self.server_properties = args.read_table()
|
||||
self.mechanisms = args.read_longstr().split(' ')
|
||||
self.locales = args.read_longstr().split(' ')
|
||||
|
||||
AMQP_LOGGER.debug('Start from server, version: %d.%d, properties: %s, mechanisms: %s, locales: %s'
|
||||
% (self.version_major, self.version_minor,
|
||||
str(self.server_properties), self.mechanisms, self.locales))
|
||||
|
||||
|
||||
def _x_start_ok(self, client_properties, mechanism, response, locale):
|
||||
"""
|
||||
select security mechanism and locale
|
||||
|
||||
This method selects a SASL security mechanism. ASL uses SASL
|
||||
(RFC2222) to negotiate authentication and encryption.
|
||||
|
||||
PARAMETERS:
|
||||
client_properties: table
|
||||
|
||||
client properties
|
||||
|
||||
mechanism: shortstr
|
||||
|
||||
selected security mechanism
|
||||
|
||||
A single security mechanisms selected by the client,
|
||||
which must be one of those specified by the server.
|
||||
|
||||
RULE:
|
||||
|
||||
The client SHOULD authenticate using the highest-
|
||||
level security profile it can handle from the list
|
||||
provided by the server.
|
||||
|
||||
RULE:
|
||||
|
||||
The mechanism field MUST contain one of the
|
||||
security mechanisms proposed by the server in the
|
||||
Start method. If it doesn't, the server MUST close
|
||||
the socket.
|
||||
|
||||
response: longstr
|
||||
|
||||
security response data
|
||||
|
||||
A block of opaque data passed to the security
|
||||
mechanism. The contents of this data are defined by
|
||||
the SASL security mechanism. For the PLAIN security
|
||||
mechanism this is defined as a field table holding two
|
||||
fields, LOGIN and PASSWORD.
|
||||
|
||||
locale: shortstr
|
||||
|
||||
selected message locale
|
||||
|
||||
A single message local selected by the client, which
|
||||
must be one of those specified by the server.
|
||||
|
||||
"""
|
||||
args = AMQPWriter()
|
||||
args.write_table(client_properties)
|
||||
args.write_shortstr(mechanism)
|
||||
args.write_longstr(response)
|
||||
args.write_shortstr(locale)
|
||||
self._send_method((10, 11), args)
|
||||
|
||||
|
||||
def _tune(self, args):
|
||||
"""
|
||||
propose connection tuning parameters
|
||||
|
||||
This method proposes a set of connection configuration values
|
||||
to the client. The client can accept and/or adjust these.
|
||||
|
||||
PARAMETERS:
|
||||
channel_max: short
|
||||
|
||||
proposed maximum channels
|
||||
|
||||
The maximum total number of channels that the server
|
||||
allows per connection. Zero means that the server does
|
||||
not impose a fixed limit, but the number of allowed
|
||||
channels may be limited by available server resources.
|
||||
|
||||
frame_max: long
|
||||
|
||||
proposed maximum frame size
|
||||
|
||||
The largest frame size that the server proposes for
|
||||
the connection. The client can negotiate a lower
|
||||
value. Zero means that the server does not impose any
|
||||
specific limit but may reject very large frames if it
|
||||
cannot allocate resources for them.
|
||||
|
||||
RULE:
|
||||
|
||||
Until the frame-max has been negotiated, both
|
||||
peers MUST accept frames of up to 4096 octets
|
||||
large. The minimum non-zero value for the frame-
|
||||
max field is 4096.
|
||||
|
||||
heartbeat: short
|
||||
|
||||
desired heartbeat delay
|
||||
|
||||
The delay, in seconds, of the connection heartbeat
|
||||
that the server wants. Zero means the server does not
|
||||
want a heartbeat.
|
||||
|
||||
"""
|
||||
self.channel_max = args.read_short() or self.channel_max
|
||||
self.frame_max = args.read_long() or self.frame_max
|
||||
self.method_writer.frame_max = self.frame_max
|
||||
self.heartbeat = args.read_short()
|
||||
|
||||
self._x_tune_ok(self.channel_max, self.frame_max, 0)
|
||||
|
||||
|
||||
def _x_tune_ok(self, channel_max, frame_max, heartbeat):
|
||||
"""
|
||||
negotiate connection tuning parameters
|
||||
|
||||
This method sends the client's connection tuning parameters to
|
||||
the server. Certain fields are negotiated, others provide
|
||||
capability information.
|
||||
|
||||
PARAMETERS:
|
||||
channel_max: short
|
||||
|
||||
negotiated maximum channels
|
||||
|
||||
The maximum total number of channels that the client
|
||||
will use per connection. May not be higher than the
|
||||
value specified by the server.
|
||||
|
||||
RULE:
|
||||
|
||||
The server MAY ignore the channel-max value or MAY
|
||||
use it for tuning its resource allocation.
|
||||
|
||||
frame_max: long
|
||||
|
||||
negotiated maximum frame size
|
||||
|
||||
The largest frame size that the client and server will
|
||||
use for the connection. Zero means that the client
|
||||
does not impose any specific limit but may reject very
|
||||
large frames if it cannot allocate resources for them.
|
||||
Note that the frame-max limit applies principally to
|
||||
content frames, where large contents can be broken
|
||||
into frames of arbitrary size.
|
||||
|
||||
RULE:
|
||||
|
||||
Until the frame-max has been negotiated, both
|
||||
peers must accept frames of up to 4096 octets
|
||||
large. The minimum non-zero value for the frame-
|
||||
max field is 4096.
|
||||
|
||||
heartbeat: short
|
||||
|
||||
desired heartbeat delay
|
||||
|
||||
The delay, in seconds, of the connection heartbeat
|
||||
that the client wants. Zero means the client does not
|
||||
want a heartbeat.
|
||||
|
||||
"""
|
||||
args = AMQPWriter()
|
||||
args.write_short(channel_max)
|
||||
args.write_long(frame_max)
|
||||
args.write_short(heartbeat)
|
||||
self._send_method((10, 31), args)
|
||||
self._wait_tune_ok = False
|
||||
|
||||
|
||||
_METHOD_MAP = {
|
||||
(10, 10): _start,
|
||||
(10, 20): _secure,
|
||||
(10, 30): _tune,
|
||||
(10, 41): _open_ok,
|
||||
(10, 50): _redirect,
|
||||
(10, 60): _close,
|
||||
(10, 61): _close_ok,
|
||||
}
|
||||
|
||||
|
||||
_IMMEDIATE_METHODS = []
|
|
@ -1,105 +0,0 @@
|
|||
"""
|
||||
Exceptions used by amqplib.client_0_8
|
||||
|
||||
"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
|
||||
|
||||
__all__ = [
|
||||
'AMQPException',
|
||||
'AMQPConnectionException',
|
||||
'AMQPChannelException',
|
||||
]
|
||||
|
||||
|
||||
class AMQPException(Exception):
|
||||
def __init__(self, reply_code, reply_text, method_sig):
|
||||
Exception.__init__(self)
|
||||
self.amqp_reply_code = reply_code
|
||||
self.amqp_reply_text = reply_text
|
||||
self.amqp_method_sig = method_sig
|
||||
self.args = (
|
||||
reply_code,
|
||||
reply_text,
|
||||
method_sig,
|
||||
METHOD_NAME_MAP.get(method_sig, '')
|
||||
)
|
||||
|
||||
|
||||
class AMQPConnectionException(AMQPException):
|
||||
pass
|
||||
|
||||
|
||||
class AMQPChannelException(AMQPException):
|
||||
pass
|
||||
|
||||
|
||||
METHOD_NAME_MAP = {
|
||||
(10, 10): 'Connection.start',
|
||||
(10, 11): 'Connection.start_ok',
|
||||
(10, 20): 'Connection.secure',
|
||||
(10, 21): 'Connection.secure_ok',
|
||||
(10, 30): 'Connection.tune',
|
||||
(10, 31): 'Connection.tune_ok',
|
||||
(10, 40): 'Connection.open',
|
||||
(10, 41): 'Connection.open_ok',
|
||||
(10, 50): 'Connection.redirect',
|
||||
(10, 60): 'Connection.close',
|
||||
(10, 61): 'Connection.close_ok',
|
||||
(20, 10): 'Channel.open',
|
||||
(20, 11): 'Channel.open_ok',
|
||||
(20, 20): 'Channel.flow',
|
||||
(20, 21): 'Channel.flow_ok',
|
||||
(20, 30): 'Channel.alert',
|
||||
(20, 40): 'Channel.close',
|
||||
(20, 41): 'Channel.close_ok',
|
||||
(30, 10): 'Channel.access_request',
|
||||
(30, 11): 'Channel.access_request_ok',
|
||||
(40, 10): 'Channel.exchange_declare',
|
||||
(40, 11): 'Channel.exchange_declare_ok',
|
||||
(40, 20): 'Channel.exchange_delete',
|
||||
(40, 21): 'Channel.exchange_delete_ok',
|
||||
(50, 10): 'Channel.queue_declare',
|
||||
(50, 11): 'Channel.queue_declare_ok',
|
||||
(50, 20): 'Channel.queue_bind',
|
||||
(50, 21): 'Channel.queue_bind_ok',
|
||||
(50, 30): 'Channel.queue_purge',
|
||||
(50, 31): 'Channel.queue_purge_ok',
|
||||
(50, 40): 'Channel.queue_delete',
|
||||
(50, 41): 'Channel.queue_delete_ok',
|
||||
(60, 10): 'Channel.basic_qos',
|
||||
(60, 11): 'Channel.basic_qos_ok',
|
||||
(60, 20): 'Channel.basic_consume',
|
||||
(60, 21): 'Channel.basic_consume_ok',
|
||||
(60, 30): 'Channel.basic_cancel',
|
||||
(60, 31): 'Channel.basic_cancel_ok',
|
||||
(60, 40): 'Channel.basic_publish',
|
||||
(60, 50): 'Channel.basic_return',
|
||||
(60, 60): 'Channel.basic_deliver',
|
||||
(60, 70): 'Channel.basic_get',
|
||||
(60, 71): 'Channel.basic_get_ok',
|
||||
(60, 72): 'Channel.basic_get_empty',
|
||||
(60, 80): 'Channel.basic_ack',
|
||||
(60, 90): 'Channel.basic_reject',
|
||||
(60, 100): 'Channel.basic_recover',
|
||||
(90, 10): 'Channel.tx_select',
|
||||
(90, 11): 'Channel.tx_select_ok',
|
||||
(90, 20): 'Channel.tx_commit',
|
||||
(90, 21): 'Channel.tx_commit_ok',
|
||||
(90, 30): 'Channel.tx_rollback',
|
||||
(90, 31): 'Channel.tx_rollback_ok',
|
||||
}
|
|
@ -1,261 +0,0 @@
|
|||
"""
|
||||
Convert between frames and higher-level AMQP methods
|
||||
|
||||
"""
|
||||
# Copyright (C) 2007-2008 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
|
||||
from Queue import Empty, Queue
|
||||
from struct import pack, unpack
|
||||
|
||||
try:
|
||||
bytes
|
||||
except NameError:
|
||||
# Python 2.5 and lower
|
||||
bytes = str
|
||||
|
||||
try:
|
||||
from collections import defaultdict
|
||||
except:
|
||||
class defaultdict(dict):
|
||||
"""
|
||||
Mini-implementation of collections.defaultdict that
|
||||
appears in Python 2.5 and up.
|
||||
|
||||
"""
|
||||
def __init__(self, default_factory):
|
||||
dict.__init__(self)
|
||||
self.default_factory = default_factory
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return dict.__getitem__(self, key)
|
||||
except KeyError:
|
||||
result = self.default_factory()
|
||||
dict.__setitem__(self, key, result)
|
||||
return result
|
||||
|
||||
|
||||
from basic_message import Message
|
||||
from exceptions import *
|
||||
from serialization import AMQPReader
|
||||
|
||||
__all__ = [
|
||||
'MethodReader',
|
||||
]
|
||||
|
||||
#
|
||||
# MethodReader needs to know which methods are supposed
|
||||
# to be followed by content headers and bodies.
|
||||
#
|
||||
_CONTENT_METHODS = [
|
||||
(60, 50), # Basic.return
|
||||
(60, 60), # Basic.deliver
|
||||
(60, 71), # Basic.get_ok
|
||||
]
|
||||
|
||||
|
||||
class _PartialMessage(object):
|
||||
"""
|
||||
Helper class to build up a multi-frame method.
|
||||
|
||||
"""
|
||||
def __init__(self, method_sig, args):
|
||||
self.method_sig = method_sig
|
||||
self.args = args
|
||||
self.msg = Message()
|
||||
self.body_parts = []
|
||||
self.body_received = 0
|
||||
self.body_size = None
|
||||
self.complete = False
|
||||
|
||||
|
||||
def add_header(self, payload):
|
||||
class_id, weight, self.body_size = unpack('>HHQ', payload[:12])
|
||||
self.msg._load_properties(payload[12:])
|
||||
self.complete = (self.body_size == 0)
|
||||
|
||||
|
||||
def add_payload(self, payload):
|
||||
self.body_parts.append(payload)
|
||||
self.body_received += len(payload)
|
||||
|
||||
if self.body_received == self.body_size:
|
||||
self.msg.body = bytes().join(self.body_parts)
|
||||
self.complete = True
|
||||
|
||||
|
||||
class MethodReader(object):
|
||||
"""
|
||||
Helper class to receive frames from the broker, combine them if
|
||||
necessary with content-headers and content-bodies into complete methods.
|
||||
|
||||
Normally a method is represented as a tuple containing
|
||||
(channel, method_sig, args, content).
|
||||
|
||||
In the case of a framing error, an AMQPConnectionException is placed
|
||||
in the queue.
|
||||
|
||||
In the case of unexpected frames, a tuple made up of
|
||||
(channel, AMQPChannelException) is placed in the queue.
|
||||
|
||||
"""
|
||||
def __init__(self, source):
|
||||
self.source = source
|
||||
self.queue = Queue()
|
||||
self.running = False
|
||||
self.partial_messages = {}
|
||||
# For each channel, which type is expected next
|
||||
self.expected_types = defaultdict(lambda:1)
|
||||
|
||||
|
||||
def _next_method(self):
|
||||
"""
|
||||
Read the next method from the source, once one complete method has
|
||||
been assembled it is placed in the internal queue.
|
||||
|
||||
"""
|
||||
while self.queue.empty():
|
||||
try:
|
||||
frame_type, channel, payload = self.source.read_frame()
|
||||
except Exception, e:
|
||||
#
|
||||
# Connection was closed? Framing Error?
|
||||
#
|
||||
self.queue.put(e)
|
||||
break
|
||||
|
||||
if self.expected_types[channel] != frame_type:
|
||||
self.queue.put((
|
||||
channel,
|
||||
Exception('Received frame type %s while expecting type: %s' %
|
||||
(frame_type, self.expected_types[channel])
|
||||
)
|
||||
))
|
||||
elif frame_type == 1:
|
||||
self._process_method_frame(channel, payload)
|
||||
elif frame_type == 2:
|
||||
self._process_content_header(channel, payload)
|
||||
elif frame_type == 3:
|
||||
self._process_content_body(channel, payload)
|
||||
|
||||
|
||||
def _process_method_frame(self, channel, payload):
|
||||
"""
|
||||
Process Method frames
|
||||
|
||||
"""
|
||||
method_sig = unpack('>HH', payload[:4])
|
||||
args = AMQPReader(payload[4:])
|
||||
|
||||
if method_sig in _CONTENT_METHODS:
|
||||
#
|
||||
# Save what we've got so far and wait for the content-header
|
||||
#
|
||||
self.partial_messages[channel] = _PartialMessage(method_sig, args)
|
||||
self.expected_types[channel] = 2
|
||||
else:
|
||||
self.queue.put((channel, method_sig, args, None))
|
||||
|
||||
|
||||
def _process_content_header(self, channel, payload):
|
||||
"""
|
||||
Process Content Header frames
|
||||
|
||||
"""
|
||||
partial = self.partial_messages[channel]
|
||||
partial.add_header(payload)
|
||||
|
||||
if partial.complete:
|
||||
#
|
||||
# a bodyless message, we're done
|
||||
#
|
||||
self.queue.put((channel, partial.method_sig, partial.args, partial.msg))
|
||||
del self.partial_messages[channel]
|
||||
self.expected_types[channel] = 1
|
||||
else:
|
||||
#
|
||||
# wait for the content-body
|
||||
#
|
||||
self.expected_types[channel] = 3
|
||||
|
||||
|
||||
def _process_content_body(self, channel, payload):
|
||||
"""
|
||||
Process Content Body frames
|
||||
|
||||
"""
|
||||
partial = self.partial_messages[channel]
|
||||
partial.add_payload(payload)
|
||||
if partial.complete:
|
||||
#
|
||||
# Stick the message in the queue and go back to
|
||||
# waiting for method frames
|
||||
#
|
||||
self.queue.put((channel, partial.method_sig, partial.args, partial.msg))
|
||||
del self.partial_messages[channel]
|
||||
self.expected_types[channel] = 1
|
||||
|
||||
|
||||
def read_method(self):
|
||||
"""
|
||||
Read a method from the peer.
|
||||
|
||||
"""
|
||||
self._next_method()
|
||||
m = self.queue.get()
|
||||
if isinstance(m, Exception):
|
||||
raise m
|
||||
return m
|
||||
|
||||
|
||||
class MethodWriter(object):
|
||||
"""
|
||||
Convert AMQP methods into AMQP frames and send them out
|
||||
to the peer.
|
||||
|
||||
"""
|
||||
def __init__(self, dest, frame_max):
|
||||
self.dest = dest
|
||||
self.frame_max = frame_max
|
||||
|
||||
|
||||
def write_method(self, channel, method_sig, args, content=None):
|
||||
payload = pack('>HH', method_sig[0], method_sig[1]) + args
|
||||
|
||||
if content:
|
||||
# do this early, so we can raise an exception if there's a
|
||||
# problem with the content properties, before sending the
|
||||
# first frame
|
||||
body = content.body
|
||||
if isinstance(body, unicode):
|
||||
coding = content.properties.get('content_encoding', None)
|
||||
if coding is None:
|
||||
coding = content.properties['content_encoding'] = 'UTF-8'
|
||||
|
||||
body = body.encode(coding)
|
||||
properties = content._serialize_properties()
|
||||
|
||||
self.dest.write_frame(1, channel, payload)
|
||||
|
||||
if content:
|
||||
payload = pack('>HHQ', method_sig[0], 0, len(body)) + properties
|
||||
|
||||
self.dest.write_frame(2, channel, payload)
|
||||
|
||||
chunk_size = self.frame_max - 8
|
||||
for i in xrange(0, len(body), chunk_size):
|
||||
self.dest.write_frame(3, channel, body[i:i+chunk_size])
|
|
@ -1,541 +0,0 @@
|
|||
"""
|
||||
Convert between bytestreams and higher-level AMQP types.
|
||||
|
||||
2007-11-05 Barry Pederson <bp@barryp.org>
|
||||
|
||||
"""
|
||||
# Copyright (C) 2007 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
|
||||
import string
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from struct import pack, unpack
|
||||
from time import mktime
|
||||
|
||||
IS_PY3K = sys.version_info[0] >= 3
|
||||
|
||||
if IS_PY3K:
|
||||
def byte(n):
|
||||
return bytes([n])
|
||||
else:
|
||||
byte = chr
|
||||
|
||||
try:
|
||||
from io import BytesIO
|
||||
except:
|
||||
# Python 2.5 and lower
|
||||
try:
|
||||
from cStringIO import StringIO as BytesIO
|
||||
except:
|
||||
from StringIO import StringIO as BytesIO
|
||||
|
||||
try:
|
||||
bytes
|
||||
except NameError:
|
||||
# Python 2.5 and lower
|
||||
bytes = str
|
||||
|
||||
|
||||
class AMQPReader(object):
|
||||
"""
|
||||
Read higher-level AMQP types from a bytestream.
|
||||
|
||||
"""
|
||||
def __init__(self, source):
|
||||
"""
|
||||
Source should be either a file-like object with a read() method, or
|
||||
a plain (non-unicode) string.
|
||||
|
||||
"""
|
||||
if isinstance(source, bytes):
|
||||
self.input = BytesIO(source)
|
||||
elif hasattr(source, 'read'):
|
||||
self.input = source
|
||||
else:
|
||||
raise ValueError('AMQPReader needs a file-like object or plain string')
|
||||
|
||||
self.bitcount = self.bits = 0
|
||||
|
||||
|
||||
def close(self):
|
||||
self.input.close()
|
||||
|
||||
|
||||
def read(self, n):
|
||||
"""
|
||||
Read n bytes.
|
||||
|
||||
"""
|
||||
self.bitcount = self.bits = 0
|
||||
return self.input.read(n)
|
||||
|
||||
|
||||
def read_bit(self):
|
||||
"""
|
||||
Read a single boolean value.
|
||||
|
||||
"""
|
||||
if not self.bitcount:
|
||||
self.bits = ord(self.input.read(1))
|
||||
self.bitcount = 8
|
||||
result = (self.bits & 1) == 1
|
||||
self.bits >>= 1
|
||||
self.bitcount -= 1
|
||||
return result
|
||||
|
||||
|
||||
def read_octet(self):
|
||||
"""
|
||||
Read one byte, return as an integer
|
||||
|
||||
"""
|
||||
self.bitcount = self.bits = 0
|
||||
return unpack('B', self.input.read(1))[0]
|
||||
|
||||
|
||||
def read_short(self):
|
||||
"""
|
||||
Read an unsigned 16-bit integer
|
||||
|
||||
"""
|
||||
self.bitcount = self.bits = 0
|
||||
return unpack('>H', self.input.read(2))[0]
|
||||
|
||||
|
||||
def read_long(self):
|
||||
"""
|
||||
Read an unsigned 32-bit integer
|
||||
|
||||
"""
|
||||
self.bitcount = self.bits = 0
|
||||
return unpack('>I', self.input.read(4))[0]
|
||||
|
||||
|
||||
def read_longlong(self):
|
||||
"""
|
||||
Read an unsigned 64-bit integer
|
||||
|
||||
"""
|
||||
self.bitcount = self.bits = 0
|
||||
return unpack('>Q', self.input.read(8))[0]
|
||||
|
||||
|
||||
def read_shortstr(self):
|
||||
"""
|
||||
Read a short string that's stored in up to 255 bytes.
|
||||
|
||||
The encoding isn't specified in the AMQP spec, so
|
||||
assume it's utf-8
|
||||
|
||||
"""
|
||||
self.bitcount = self.bits = 0
|
||||
slen = unpack('B', self.input.read(1))[0]
|
||||
return self.input.read(slen).decode('utf-8')
|
||||
|
||||
|
||||
def read_longstr(self):
|
||||
"""
|
||||
Read a string that's up to 2**32 bytes.
|
||||
|
||||
The encoding isn't specified in the AMQP spec, so
|
||||
assume it's utf-8
|
||||
|
||||
"""
|
||||
self.bitcount = self.bits = 0
|
||||
slen = unpack('>I', self.input.read(4))[0]
|
||||
return self.input.read(slen).decode('utf-8')
|
||||
|
||||
|
||||
def read_table(self):
|
||||
"""
|
||||
Read an AMQP table, and return as a Python dictionary.
|
||||
|
||||
"""
|
||||
self.bitcount = self.bits = 0
|
||||
tlen = unpack('>I', self.input.read(4))[0]
|
||||
table_data = AMQPReader(self.input.read(tlen))
|
||||
result = {}
|
||||
while table_data.input.tell() < tlen:
|
||||
name = table_data.read_shortstr()
|
||||
ftype = ord(table_data.input.read(1))
|
||||
if ftype == 83: # 'S'
|
||||
val = table_data.read_longstr()
|
||||
elif ftype == 73: # 'I'
|
||||
val = unpack('>i', table_data.input.read(4))[0]
|
||||
elif ftype == 68: # 'D'
|
||||
d = table_data.read_octet()
|
||||
n = unpack('>i', table_data.input.read(4))[0]
|
||||
val = Decimal(n) / Decimal(10 ** d)
|
||||
elif ftype == 84: # 'T'
|
||||
val = table_data.read_timestamp()
|
||||
elif ftype == 70: # 'F'
|
||||
val = table_data.read_table() # recurse
|
||||
else:
|
||||
raise ValueError('Unknown table item type: %s' % repr(ftype))
|
||||
result[name] = val
|
||||
return result
|
||||
|
||||
|
||||
def read_timestamp(self):
|
||||
"""
|
||||
Read and AMQP timestamp, which is a 64-bit integer representing
|
||||
seconds since the Unix epoch in 1-second resolution. Return as
|
||||
a Python datetime.datetime object, expressed as localtime.
|
||||
|
||||
"""
|
||||
return datetime.fromtimestamp(self.read_longlong())
|
||||
|
||||
|
||||
class AMQPWriter(object):
|
||||
"""
|
||||
Convert higher-level AMQP types to bytestreams.
|
||||
|
||||
"""
|
||||
def __init__(self, dest=None):
|
||||
"""
|
||||
dest may be a file-type object (with a write() method). If None
|
||||
then a BytesIO is created, and the contents can be accessed with
|
||||
this class's getvalue() method.
|
||||
|
||||
"""
|
||||
if dest is None:
|
||||
self.out = BytesIO()
|
||||
else:
|
||||
self.out = dest
|
||||
|
||||
self.bits = []
|
||||
self.bitcount = 0
|
||||
|
||||
|
||||
def _flushbits(self):
|
||||
if self.bits:
|
||||
for b in self.bits:
|
||||
self.out.write(pack('B', b))
|
||||
self.bits = []
|
||||
self.bitcount = 0
|
||||
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Pass through if possible to any file-like destinations.
|
||||
|
||||
"""
|
||||
if hasattr(self.out, 'close'):
|
||||
self.out.close()
|
||||
|
||||
|
||||
def flush(self):
|
||||
"""
|
||||
Pass through if possible to any file-like destinations.
|
||||
|
||||
"""
|
||||
if hasattr(self.out, 'flush'):
|
||||
self.out.flush()
|
||||
|
||||
|
||||
def getvalue(self):
|
||||
"""
|
||||
Get what's been encoded so far if we're working with a BytesIO.
|
||||
|
||||
"""
|
||||
self._flushbits()
|
||||
return self.out.getvalue()
|
||||
|
||||
|
||||
def write(self, s):
|
||||
"""
|
||||
Write a plain Python string with no special encoding in Python 2.x,
|
||||
or bytes in Python 3.x
|
||||
|
||||
"""
|
||||
self._flushbits()
|
||||
self.out.write(s)
|
||||
|
||||
|
||||
def write_bit(self, b):
|
||||
"""
|
||||
Write a boolean value.
|
||||
|
||||
"""
|
||||
if b:
|
||||
b = 1
|
||||
else:
|
||||
b = 0
|
||||
shift = self.bitcount % 8
|
||||
if shift == 0:
|
||||
self.bits.append(0)
|
||||
self.bits[-1] |= (b << shift)
|
||||
self.bitcount += 1
|
||||
|
||||
|
||||
def write_octet(self, n):
|
||||
"""
|
||||
Write an integer as an unsigned 8-bit value.
|
||||
|
||||
"""
|
||||
if (n < 0) or (n > 255):
|
||||
raise ValueError('Octet out of range 0..255')
|
||||
self._flushbits()
|
||||
self.out.write(pack('B', n))
|
||||
|
||||
|
||||
def write_short(self, n):
|
||||
"""
|
||||
Write an integer as an unsigned 16-bit value.
|
||||
|
||||
"""
|
||||
if (n < 0) or (n > 65535):
|
||||
raise ValueError('Octet out of range 0..65535')
|
||||
self._flushbits()
|
||||
self.out.write(pack('>H', n))
|
||||
|
||||
|
||||
def write_long(self, n):
|
||||
"""
|
||||
Write an integer as an unsigned2 32-bit value.
|
||||
|
||||
"""
|
||||
if (n < 0) or (n >= (2**32)):
|
||||
raise ValueError('Octet out of range 0..2**31-1')
|
||||
self._flushbits()
|
||||
self.out.write(pack('>I', n))
|
||||
|
||||
|
||||
def write_longlong(self, n):
|
||||
"""
|
||||
Write an integer as an unsigned 64-bit value.
|
||||
|
||||
"""
|
||||
if (n < 0) or (n >= (2**64)):
|
||||
raise ValueError('Octet out of range 0..2**64-1')
|
||||
self._flushbits()
|
||||
self.out.write(pack('>Q', n))
|
||||
|
||||
|
||||
def write_shortstr(self, s):
|
||||
"""
|
||||
Write a string up to 255 bytes long (after any encoding).
|
||||
|
||||
If passed a unicode string, encode with UTF-8.
|
||||
|
||||
"""
|
||||
self._flushbits()
|
||||
if isinstance(s, unicode):
|
||||
s = s.encode('utf-8')
|
||||
if len(s) > 255:
|
||||
raise ValueError('String too long')
|
||||
self.write_octet(len(s))
|
||||
self.out.write(s)
|
||||
|
||||
|
||||
def write_longstr(self, s):
|
||||
"""
|
||||
Write a string up to 2**32 bytes long after encoding.
|
||||
|
||||
If passed a unicode string, encode as UTF-8.
|
||||
|
||||
"""
|
||||
self._flushbits()
|
||||
if isinstance(s, unicode):
|
||||
s = s.encode('utf-8')
|
||||
self.write_long(len(s))
|
||||
self.out.write(s)
|
||||
|
||||
|
||||
def write_table(self, d):
|
||||
"""
|
||||
Write out a Python dictionary made of up string keys, and values
|
||||
that are strings, signed integers, Decimal, datetime.datetime, or
|
||||
sub-dictionaries following the same constraints.
|
||||
|
||||
"""
|
||||
self._flushbits()
|
||||
table_data = AMQPWriter()
|
||||
for k, v in d.items():
|
||||
table_data.write_shortstr(k)
|
||||
if isinstance(v, basestring):
|
||||
if isinstance(v, unicode):
|
||||
v = v.encode('utf-8')
|
||||
table_data.write(byte(83)) # 'S'
|
||||
table_data.write_longstr(v)
|
||||
elif isinstance(v, (int, long)):
|
||||
table_data.write(byte(73)) # 'I'
|
||||
table_data.write(pack('>i', v))
|
||||
elif isinstance(v, Decimal):
|
||||
table_data.write(byte(68)) # 'D'
|
||||
sign, digits, exponent = v.as_tuple()
|
||||
v = 0
|
||||
for d in digits:
|
||||
v = (v * 10) + d
|
||||
if sign:
|
||||
v = -v
|
||||
table_data.write_octet(-exponent)
|
||||
table_data.write(pack('>i', v))
|
||||
elif isinstance(v, datetime):
|
||||
table_data.write(byte(84)) # 'T'
|
||||
table_data.write_timestamp(v)
|
||||
## FIXME: timezone ?
|
||||
elif isinstance(v, dict):
|
||||
table_data.write(byte(70)) # 'F'
|
||||
table_data.write_table(v)
|
||||
else:
|
||||
raise ValueError('%s not serializable in AMQP' % repr(v))
|
||||
table_data = table_data.getvalue()
|
||||
self.write_long(len(table_data))
|
||||
self.out.write(table_data)
|
||||
|
||||
|
||||
def write_timestamp(self, v):
|
||||
"""
|
||||
Write out a Python datetime.datetime object as a 64-bit integer
|
||||
representing seconds since the Unix epoch.
|
||||
|
||||
"""
|
||||
self.out.write(pack('>q', long(mktime(v.timetuple()))))
|
||||
|
||||
|
||||
class GenericContent(object):
|
||||
"""
|
||||
Abstract base class for AMQP content. Subclasses should
|
||||
override the PROPERTIES attribute.
|
||||
|
||||
"""
|
||||
PROPERTIES = [
|
||||
('dummy', 'shortstr'),
|
||||
]
|
||||
|
||||
def __init__(self, **props):
|
||||
"""
|
||||
Save the properties appropriate to this AMQP content type
|
||||
in a 'properties' dictionary.
|
||||
|
||||
"""
|
||||
d = {}
|
||||
for propname, _ in self.PROPERTIES:
|
||||
if propname in props:
|
||||
d[propname] = props[propname]
|
||||
# FIXME: should we ignore unknown properties?
|
||||
|
||||
self.properties = d
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
Check if this object has the same properties as another
|
||||
content object.
|
||||
|
||||
"""
|
||||
return hasattr(other, 'properties') \
|
||||
and (self.properties == other.properties)
|
||||
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""
|
||||
Look for additional properties in the 'properties'
|
||||
dictionary, and if present - the 'delivery_info'
|
||||
dictionary.
|
||||
|
||||
"""
|
||||
if name == '__setstate__':
|
||||
# Allows pickling/unpickling to work
|
||||
raise AttributeError('__setstate__')
|
||||
|
||||
if name in self.properties:
|
||||
return self.properties[name]
|
||||
|
||||
if ('delivery_info' in self.__dict__) \
|
||||
and (name in self.delivery_info):
|
||||
return self.delivery_info[name]
|
||||
|
||||
raise AttributeError(name)
|
||||
|
||||
|
||||
def __ne__(self, other):
|
||||
"""
|
||||
Just return the opposite of __eq__
|
||||
|
||||
"""
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
def _load_properties(self, raw_bytes):
|
||||
"""
|
||||
Given the raw bytes containing the property-flags and property-list
|
||||
from a content-frame-header, parse and insert into a dictionary
|
||||
stored in this object as an attribute named 'properties'.
|
||||
|
||||
"""
|
||||
r = AMQPReader(raw_bytes)
|
||||
|
||||
#
|
||||
# Read 16-bit shorts until we get one with a low bit set to zero
|
||||
#
|
||||
flags = []
|
||||
while True:
|
||||
flag_bits = r.read_short()
|
||||
flags.append(flag_bits)
|
||||
if flag_bits & 1 == 0:
|
||||
break
|
||||
|
||||
shift = 0
|
||||
d = {}
|
||||
for key, proptype in self.PROPERTIES:
|
||||
if shift == 0:
|
||||
if not flags:
|
||||
break
|
||||
flag_bits, flags = flags[0], flags[1:]
|
||||
shift = 15
|
||||
if flag_bits & (1 << shift):
|
||||
d[key] = getattr(r, 'read_' + proptype)()
|
||||
shift -= 1
|
||||
|
||||
self.properties = d
|
||||
|
||||
|
||||
def _serialize_properties(self):
|
||||
"""
|
||||
serialize the 'properties' attribute (a dictionary) into
|
||||
the raw bytes making up a set of property flags and a
|
||||
property list, suitable for putting into a content frame header.
|
||||
|
||||
"""
|
||||
shift = 15
|
||||
flag_bits = 0
|
||||
flags = []
|
||||
raw_bytes = AMQPWriter()
|
||||
for key, proptype in self.PROPERTIES:
|
||||
val = self.properties.get(key, None)
|
||||
if val is not None:
|
||||
if shift == 0:
|
||||
flags.append(flag_bits)
|
||||
flag_bits = 0
|
||||
shift = 15
|
||||
|
||||
flag_bits |= (1 << shift)
|
||||
if proptype != 'bit':
|
||||
getattr(raw_bytes, 'write_' + proptype)(val)
|
||||
|
||||
shift -= 1
|
||||
|
||||
flags.append(flag_bits)
|
||||
result = AMQPWriter()
|
||||
for flag_bits in flags:
|
||||
result.write_short(flag_bits)
|
||||
result.write(raw_bytes.getvalue())
|
||||
|
||||
return result.getvalue()
|
|
@ -1,281 +0,0 @@
|
|||
"""
|
||||
Read/Write AMQP frames over network transports.
|
||||
|
||||
2009-01-14 Barry Pederson <bp@barryp.org>
|
||||
|
||||
"""
|
||||
# Copyright (C) 2009 Barry Pederson <bp@barryp.org>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
|
||||
import re
|
||||
import socket
|
||||
|
||||
#
|
||||
# See if Python 2.6+ SSL support is available
|
||||
#
|
||||
try:
|
||||
import ssl
|
||||
HAVE_PY26_SSL = True
|
||||
except:
|
||||
HAVE_PY26_SSL = False
|
||||
|
||||
try:
|
||||
bytes
|
||||
except:
|
||||
# Python 2.5 and lower
|
||||
bytes = str
|
||||
|
||||
from struct import pack, unpack
|
||||
|
||||
AMQP_PORT = 5672
|
||||
|
||||
# Yes, Advanced Message Queuing Protocol Protocol is redundant
|
||||
AMQP_PROTOCOL_HEADER = 'AMQP\x01\x01\x09\x01'.encode('latin_1')
|
||||
|
||||
# Match things like: [fe80::1]:5432, from RFC 2732
|
||||
IPV6_LITERAL = re.compile(r'\[([\.0-9a-f:]+)\](?::(\d+))?')
|
||||
|
||||
class _AbstractTransport(object):
|
||||
"""
|
||||
Common superclass for TCP and SSL transports
|
||||
|
||||
"""
|
||||
def __init__(self, host, connect_timeout):
|
||||
msg = 'socket.getaddrinfo() for %s returned an empty list' % host
|
||||
port = AMQP_PORT
|
||||
|
||||
m = IPV6_LITERAL.match(host)
|
||||
if m:
|
||||
host = m.group(1)
|
||||
if m.group(2):
|
||||
port = int(m.group(2))
|
||||
else:
|
||||
if ':' in host:
|
||||
host, port = host.rsplit(':', 1)
|
||||
port = int(port)
|
||||
|
||||
self.sock = None
|
||||
for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.SOL_TCP):
|
||||
af, socktype, proto, canonname, sa = res
|
||||
try:
|
||||
self.sock = socket.socket(af, socktype, proto)
|
||||
self.sock.settimeout(connect_timeout)
|
||||
self.sock.connect(sa)
|
||||
except socket.error, msg:
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
continue
|
||||
break
|
||||
|
||||
if not self.sock:
|
||||
# Didn't connect, return the most recent error message
|
||||
raise socket.error, msg
|
||||
|
||||
self.sock.settimeout(None)
|
||||
self.sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
|
||||
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
|
||||
self._setup_transport()
|
||||
|
||||
self._write(AMQP_PROTOCOL_HEADER)
|
||||
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
|
||||
def _read(self, n):
|
||||
"""
|
||||
Read exactly n bytes from the peer
|
||||
|
||||
"""
|
||||
raise NotImplementedError('Must be overriden in subclass')
|
||||
|
||||
|
||||
def _setup_transport(self):
|
||||
"""
|
||||
Do any additional initialization of the class (used
|
||||
by the subclasses).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def _shutdown_transport(self):
|
||||
"""
|
||||
Do any preliminary work in shutting down the connection.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def _write(self, s):
|
||||
"""
|
||||
Completely write a string to the peer.
|
||||
|
||||
"""
|
||||
raise NotImplementedError('Must be overriden in subclass')
|
||||
|
||||
|
||||
def close(self):
|
||||
if self.sock is not None:
|
||||
self._shutdown_transport()
|
||||
# Call shutdown first to make sure that pending messages
|
||||
# reach the AMQP broker if the program exits after
|
||||
# calling this method.
|
||||
self.sock.shutdown(socket.SHUT_RDWR)
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
|
||||
|
||||
def read_frame(self):
|
||||
"""
|
||||
Read an AMQP frame.
|
||||
|
||||
"""
|
||||
frame_type, channel, size = unpack('>BHI', self._read(7))
|
||||
payload = self._read(size)
|
||||
ch = ord(self._read(1))
|
||||
if ch == 206: # '\xce'
|
||||
return frame_type, channel, payload
|
||||
else:
|
||||
raise Exception('Framing Error, received 0x%02x while expecting 0xce' % ch)
|
||||
|
||||
|
||||
def write_frame(self, frame_type, channel, payload):
|
||||
"""
|
||||
Write out an AMQP frame.
|
||||
|
||||
"""
|
||||
size = len(payload)
|
||||
self._write(pack('>BHI%dsB' % size,
|
||||
frame_type, channel, size, payload, 0xce))
|
||||
|
||||
|
||||
class SSLTransport(_AbstractTransport):
|
||||
"""
|
||||
Transport that works over SSL
|
||||
|
||||
"""
|
||||
def __init__(self, host, connect_timeout, ssl):
|
||||
if isinstance(ssl, dict):
|
||||
self.sslopts = ssl
|
||||
|
||||
self.sslobj = None
|
||||
|
||||
super(SSLTransport, self).__init__(host, connect_timeout)
|
||||
|
||||
|
||||
def _setup_transport(self):
|
||||
"""
|
||||
Wrap the socket in an SSL object, either the
|
||||
new Python 2.6 version, or the older Python 2.5 and
|
||||
lower version.
|
||||
|
||||
"""
|
||||
if HAVE_PY26_SSL:
|
||||
if hasattr(self, 'sslopts'):
|
||||
self.sslobj = ssl.wrap_socket(self.sock, **self.sslopts)
|
||||
else:
|
||||
self.sslobj = ssl.wrap_socket(self.sock)
|
||||
self.sslobj.do_handshake()
|
||||
else:
|
||||
self.sslobj = socket.ssl(self.sock)
|
||||
|
||||
|
||||
def _shutdown_transport(self):
|
||||
"""
|
||||
Unwrap a Python 2.6 SSL socket, so we can call shutdown()
|
||||
|
||||
"""
|
||||
if HAVE_PY26_SSL and (self.sslobj is not None):
|
||||
self.sock = self.sslobj.unwrap()
|
||||
self.sslobj = None
|
||||
|
||||
|
||||
def _read(self, n):
|
||||
"""
|
||||
It seems that SSL Objects read() method may not supply as much
|
||||
as you're asking for, at least with extremely large messages.
|
||||
somewhere > 16K - found this in the test_channel.py test_large
|
||||
unittest.
|
||||
|
||||
"""
|
||||
result = self.sslobj.read(n)
|
||||
|
||||
while len(result) < n:
|
||||
s = self.sslobj.read(n - len(result))
|
||||
if not s:
|
||||
raise IOError('Socket closed')
|
||||
result += s
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _write(self, s):
|
||||
"""
|
||||
Write a string out to the SSL socket fully.
|
||||
|
||||
"""
|
||||
while s:
|
||||
n = self.sslobj.write(s)
|
||||
if not n:
|
||||
raise IOError('Socket closed')
|
||||
s = s[n:]
|
||||
|
||||
|
||||
class TCPTransport(_AbstractTransport):
|
||||
"""
|
||||
Transport that deals directly with TCP socket.
|
||||
|
||||
"""
|
||||
def _setup_transport(self):
|
||||
"""
|
||||
Setup to _write() directly to the socket, and
|
||||
do our own buffered reads.
|
||||
|
||||
"""
|
||||
self._write = self.sock.sendall
|
||||
self._read_buffer = bytes()
|
||||
|
||||
|
||||
def _read(self, n):
|
||||
"""
|
||||
Read exactly n bytes from the socket
|
||||
|
||||
"""
|
||||
while len(self._read_buffer) < n:
|
||||
s = self.sock.recv(65536)
|
||||
if not s:
|
||||
raise IOError('Socket closed')
|
||||
self._read_buffer += s
|
||||
|
||||
result = self._read_buffer[:n]
|
||||
self._read_buffer = self._read_buffer[n:]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def create_transport(host, connect_timeout, ssl=False):
|
||||
"""
|
||||
Given a few parameters from the Connection constructor,
|
||||
select and create a subclass of _AbstractTransport.
|
||||
|
||||
"""
|
||||
if ssl:
|
||||
return SSLTransport(host, connect_timeout, ssl)
|
||||
else:
|
||||
return TCPTransport(host, connect_timeout)
|
|
@ -1,85 +0,0 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: anyjson
|
||||
Version: 0.3.3
|
||||
Summary: Wraps the best available JSON implementation available in a common interface
|
||||
Home-page: http://bitbucket.org/runeh/anyjson/
|
||||
Author: Rune Halvorsen
|
||||
Author-email: runefh@gmail.com
|
||||
License: BSD
|
||||
Description: ##############################
|
||||
anyjson - JSON library wrapper
|
||||
##############################
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Anyjson loads whichever is the fastest JSON module installed and provides
|
||||
a uniform API regardless of which JSON implementation is used.
|
||||
|
||||
Originally part of carrot (http://github.com/ask/carrot/)
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
To serialize a python object to a JSON string, call the `serialize` function:
|
||||
|
||||
>>> import anyjson
|
||||
>>> anyjson.serialize(["test", 1, {"foo": 3.141592}, "bar"])
|
||||
'["test", 1, {"foo": 3.141592}, "bar"]'
|
||||
|
||||
Conversion the other way is done with the `deserialize` call.
|
||||
|
||||
>>> anyjson.deserialize("""["test", 1, {"foo": 3.141592}, "bar"]""")
|
||||
['test', 1, {'foo': 3.1415920000000002}, 'bar']
|
||||
|
||||
Regardless of the JSON implementation used, the exceptions will be the same.
|
||||
This means that trying to serialize something not compatible with JSON
|
||||
raises a TypeError:
|
||||
|
||||
>>> anyjson.serialize([object()])
|
||||
Traceback (most recent call last):
|
||||
<snipped traceback>
|
||||
TypeError: object is not JSON encodable
|
||||
|
||||
And deserializing a JSON string with invalid JSON raises a ValueError:
|
||||
|
||||
>>> anyjson.deserialize("""['missing square brace!""")
|
||||
Traceback (most recent call last):
|
||||
<snipped traceback>
|
||||
ValueError: cannot parse JSON description
|
||||
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
The module is maintaned by Rune F. Halvorsen <runefh@gmail.com>.
|
||||
The project resides at http://bitbucket.org/runeh/anyjson . Bugs and feature
|
||||
requests can be submitted there. Patches are also very welcome.
|
||||
|
||||
Changelog
|
||||
---------
|
||||
|
||||
See CHANGELOG file
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
see the LICENSE file
|
||||
|
||||
Keywords: json
|
||||
Platform: any
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.4
|
||||
Classifier: Programming Language :: Python :: 2.5
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.1
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Programming Language :: Python :: Implementation :: Jython
|
|
@ -1,15 +0,0 @@
|
|||
CHANGELOG
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
README
|
||||
setup.cfg
|
||||
setup.py
|
||||
anyjson/__init__.py
|
||||
anyjson.egg-info/PKG-INFO
|
||||
anyjson.egg-info/SOURCES.txt
|
||||
anyjson.egg-info/dependency_links.txt
|
||||
anyjson.egg-info/not-zip-safe
|
||||
anyjson.egg-info/top_level.txt
|
||||
tests/benchmark.py
|
||||
tests/test_implementations.py
|
||||
tests/test_implementations.pyc
|
|
@ -1,8 +0,0 @@
|
|||
../anyjson/__init__.py
|
||||
../anyjson/__init__.pyc
|
||||
./
|
||||
top_level.txt
|
||||
SOURCES.txt
|
||||
not-zip-safe
|
||||
PKG-INFO
|
||||
dependency_links.txt
|
|
@ -1 +0,0 @@
|
|||
anyjson
|
|
@ -1,142 +0,0 @@
|
|||
"""Wraps the best available JSON implementation available in a common
|
||||
interface"""
|
||||
|
||||
import sys
|
||||
|
||||
VERSION = (0, 3, 3)
|
||||
__version__ = ".".join(map(str, VERSION[0:3])) + "".join(VERSION[3:])
|
||||
__author__ = "Rune Halvorsen"
|
||||
__contact__ = "runefh@gmail.com"
|
||||
__homepage__ = "http://bitbucket.org/runeh/anyjson/"
|
||||
__docformat__ = "restructuredtext"
|
||||
|
||||
# -eof meta-
|
||||
|
||||
#: The json implementation object. This is probably not useful to you,
|
||||
#: except to get the name of the implementation in use. The name is
|
||||
#: available through ``implementation.name``.
|
||||
implementation = None
|
||||
|
||||
# json.loads does not support buffer() objects,
|
||||
# so we load() and StringIO instead, and it won't copy.
|
||||
if sys.version_info[0] == 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
try:
|
||||
from cStringIO import StringIO # noqa
|
||||
except ImportError:
|
||||
from StringIO import StringIO # noqa
|
||||
|
||||
#: List of known json modules, and the names of their loads/dumps
|
||||
#: methods, as well as the exceptions they throw. Exception can be either
|
||||
#: an exception class or a string.
|
||||
_modules = [("yajl", "dumps", TypeError, "loads", ValueError, "load"),
|
||||
("jsonlib2", "write", "WriteError", "read", "ReadError", None),
|
||||
("jsonlib", "write", "WriteError", "read", "ReadError", None),
|
||||
("simplejson", "dumps", TypeError, "loads", ValueError, "load"),
|
||||
("json", "dumps", TypeError, "loads", ValueError, "load"),
|
||||
("django.utils.simplejson", "dumps", TypeError, "loads", ValueError, "load"),
|
||||
("cjson", "encode", "EncodeError", "decode", "DecodeError", None)
|
||||
]
|
||||
|
||||
_fields = ("modname", "encoder", "encerror",
|
||||
"decoder", "decerror", "filedecoder")
|
||||
|
||||
|
||||
class _JsonImplementation(object):
|
||||
"""Incapsulates a JSON implementation"""
|
||||
|
||||
def __init__(self, modspec):
|
||||
modinfo = dict(zip(_fields, modspec))
|
||||
|
||||
if modinfo["modname"] == "cjson":
|
||||
import warnings
|
||||
warnings.warn("cjson is deprecated! See http://pypi.python.org/pypi/python-cjson/1.0.5", DeprecationWarning)
|
||||
|
||||
# No try block. We want importerror to end up at caller
|
||||
module = self._attempt_load(modinfo["modname"])
|
||||
|
||||
self.implementation = modinfo["modname"]
|
||||
self._encode = getattr(module, modinfo["encoder"])
|
||||
self._decode = getattr(module, modinfo["decoder"])
|
||||
fdec = modinfo["filedecoder"]
|
||||
self._filedecode = fdec and getattr(module, fdec)
|
||||
self._encode_error = modinfo["encerror"]
|
||||
self._decode_error = modinfo["decerror"]
|
||||
|
||||
if isinstance(modinfo["encerror"], basestring):
|
||||
self._encode_error = getattr(module, modinfo["encerror"])
|
||||
if isinstance(modinfo["decerror"], basestring):
|
||||
self._decode_error = getattr(module, modinfo["decerror"])
|
||||
|
||||
self.name = modinfo["modname"]
|
||||
|
||||
def __repr__(self):
|
||||
return "<_JsonImplementation instance using %s>" % self.name
|
||||
|
||||
def _attempt_load(self, modname):
|
||||
"""Attempt to load module name modname, returning it on success,
|
||||
throwing ImportError if module couldn't be imported"""
|
||||
__import__(modname)
|
||||
return sys.modules[modname]
|
||||
|
||||
def dumps(self, data):
|
||||
"""Serialize the datastructure to json. Returns a string. Raises
|
||||
TypeError if the object could not be serialized."""
|
||||
try:
|
||||
return self._encode(data)
|
||||
except self._encode_error, exc:
|
||||
raise TypeError, TypeError(*exc.args), sys.exc_info()[2]
|
||||
serialize = dumps
|
||||
|
||||
def loads(self, s):
|
||||
"""deserialize the string to python data types. Raises
|
||||
ValueError if the string could not be parsed."""
|
||||
# uses StringIO to support buffer objects.
|
||||
try:
|
||||
if self._filedecode and not isinstance(s, basestring):
|
||||
return self._filedecode(StringIO(s))
|
||||
return self._decode(s)
|
||||
except self._decode_error, exc:
|
||||
raise ValueError, ValueError(*exc.args), sys.exc_info()[2]
|
||||
deserialize = loads
|
||||
|
||||
|
||||
def force_implementation(modname):
|
||||
"""Forces anyjson to use a specific json module if it's available"""
|
||||
global implementation
|
||||
for name, spec in [(e[0], e) for e in _modules]:
|
||||
if name == modname:
|
||||
implementation = _JsonImplementation(spec)
|
||||
return
|
||||
raise ImportError("No module named: %s" % modname)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# If run as a script, we do nothing but print an error message.
|
||||
# We do NOT try to load a compatible module because that may throw an
|
||||
# exception, which renders the package uninstallable with easy_install
|
||||
# (It trys to execfile the script when installing, to make sure it works)
|
||||
print "Running anyjson as a stand alone script is not supported"
|
||||
sys.exit(1)
|
||||
else:
|
||||
for modspec in _modules:
|
||||
try:
|
||||
implementation = _JsonImplementation(modspec)
|
||||
break
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
raise ImportError("No supported JSON module found")
|
||||
|
||||
|
||||
def loads(value):
|
||||
"""Serialize the object to JSON."""
|
||||
return implementation.loads(value)
|
||||
deserialize = loads # compat
|
||||
|
||||
|
||||
def dumps(value):
|
||||
"""Deserialize JSON-encoded object to a Python object."""
|
||||
return implementation.dumps(value)
|
||||
serialize = dumps
|
|
@ -1,14 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2008—2012 Andy Mikhailenko
|
||||
#
|
||||
# This file is part of django-autoslug.
|
||||
#
|
||||
# django-autoslug is free software under terms of the GNU Lesser
|
||||
# General Public License version 3 (LGPLv3) as published by the Free
|
||||
# Software Foundation. See the file README for copying conditions.
|
||||
#
|
||||
|
||||
from fields import AutoSlugField
|
||||
|
||||
__all__ = ['AutoSlugField']
|
|
@ -1,244 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2008—2012 Andy Mikhailenko
|
||||
#
|
||||
# This file is part of django-autoslug.
|
||||
#
|
||||
# django-autoslug is free software under terms of the GNU Lesser
|
||||
# General Public License version 3 (LGPLv3) as published by the Free
|
||||
# Software Foundation. See the file README for copying conditions.
|
||||
#
|
||||
|
||||
# python
|
||||
from warnings import warn
|
||||
|
||||
# django
|
||||
from django.db.models.fields import SlugField
|
||||
|
||||
# 3rd-party
|
||||
try:
|
||||
from south.modelsinspector import introspector
|
||||
except ImportError:
|
||||
introspector = lambda self: [], {}
|
||||
|
||||
# this app
|
||||
from autoslug.settings import slugify
|
||||
import utils
|
||||
|
||||
|
||||
__all__ = ['AutoSlugField']
|
||||
|
||||
SLUG_INDEX_SEPARATOR = '-' # the "-" in "foo-2"
|
||||
|
||||
|
||||
class AutoSlugField(SlugField):
|
||||
"""
|
||||
AutoSlugField is an extended SlugField able to automatically resolve name
|
||||
clashes.
|
||||
|
||||
AutoSlugField can also perform the following tasks on save:
|
||||
|
||||
- populate itself from another field (using `populate_from`),
|
||||
- use custom `slugify` function (using `slugify` or :doc:`settings`), and
|
||||
- preserve uniqueness of the value (using `unique` or `unique_with`).
|
||||
|
||||
None of the tasks is mandatory, i.e. you can have auto-populated non-unique
|
||||
fields, manually entered unique ones (absolutely unique or within a given
|
||||
date) or both.
|
||||
|
||||
Uniqueness is preserved by checking if the slug is unique with given constraints
|
||||
(`unique_with`) or globally (`unique`) and adding a number to the slug to make
|
||||
it unique.
|
||||
|
||||
:param always_update: boolean: if True, the slug is updated each time the
|
||||
model instance is saved. Use with care because `cool URIs don't
|
||||
change`_ (and the slug is usually a part of object's URI). Note that
|
||||
even if the field is editable, any manual changes will be lost when
|
||||
this option is activated.
|
||||
:param populate_from: string or callable: if string is given, it is considered
|
||||
as the name of attribute from which to fill the slug. If callable is given,
|
||||
it should accept `instance` parameter and return a value to fill the slug
|
||||
with.
|
||||
:param sep: string: if defined, overrides default separator for automatically
|
||||
incremented slug index (i.e. the "-" in "foo-2").
|
||||
:param slugify: callable: if defined, overrides `AUTOSLUG_SLUGIFY_FUNCTION`
|
||||
defined in :doc:`settings`.
|
||||
:param unique: boolean: ensure total slug uniqueness (unless more precise
|
||||
`unique_with` is defined).
|
||||
:param unique_with: string or tuple of strings: name or names of attributes
|
||||
to check for "partial uniqueness", i.e. there will not be two objects
|
||||
with identical slugs if these objects share the same values of given
|
||||
attributes. For instance, ``unique_with='pub_date'`` tells AutoSlugField
|
||||
to enforce slug uniqueness of all items published on given date. The
|
||||
slug, however, may reappear on another date. If more than one field is
|
||||
given, e.g. ``unique_with=('pub_date', 'author')``, then the same slug may
|
||||
reappear within a day or within some author's articles but never within
|
||||
a day for the same author. Foreign keys are also supported, i.e. not only
|
||||
`unique_with='author'` will do, but also `unique_with='author__name'`.
|
||||
|
||||
.. _cool URIs don't change: http://w3.org/Provider/Style/URI.html
|
||||
|
||||
.. note:: always place any slug attribute *after* attributes referenced
|
||||
by it (i.e. those from which you wish to `populate_from` or check
|
||||
`unique_with`). The reasoning is that autosaved dates and other such
|
||||
fields must be already processed before using them in the AutoSlugField.
|
||||
|
||||
Example usage::
|
||||
|
||||
from django.db import models
|
||||
from autoslug import AutoSlugField
|
||||
|
||||
class Article(models.Model):
|
||||
'''An article with title, date and slug. The slug is not totally
|
||||
unique but there will be no two articles with the same slug within
|
||||
any month.
|
||||
'''
|
||||
title = models.CharField(max_length=200)
|
||||
pub_date = models.DateField(auto_now_add=True)
|
||||
slug = AutoSlugField(populate_from='title', unique_with='pub_date__month')
|
||||
|
||||
|
||||
More options::
|
||||
|
||||
# slugify but allow non-unique slugs
|
||||
slug = AutoSlugField()
|
||||
|
||||
# globally unique, silently fix on conflict ("foo" --> "foo-1".."foo-n")
|
||||
slug = AutoSlugField(unique=True)
|
||||
|
||||
# autoslugify value from attribute named "title"; editable defaults to False
|
||||
slug = AutoSlugField(populate_from='title')
|
||||
|
||||
# same as above but force editable=True
|
||||
slug = AutoSlugField(populate_from='title', editable=True)
|
||||
|
||||
# ensure that slug is unique with given date (not globally)
|
||||
slug = AutoSlugField(unique_with='pub_date')
|
||||
|
||||
# ensure that slug is unique with given date AND category
|
||||
slug = AutoSlugField(unique_with=('pub_date','category'))
|
||||
|
||||
# ensure that slug in unique with an external object
|
||||
# assuming that author=ForeignKey(Author)
|
||||
slug = AutoSlugField(unique_with='author')
|
||||
|
||||
# ensure that slug in unique with a subset of external objects (by lookups)
|
||||
# assuming that author=ForeignKey(Author)
|
||||
slug = AutoSlugField(unique_with='author__name')
|
||||
|
||||
# mix above-mentioned behaviour bits
|
||||
slug = AutoSlugField(populate_from='title', unique_with='pub_date')
|
||||
|
||||
# minimum date granularity is shifted from day to month
|
||||
slug = AutoSlugField(populate_from='title', unique_with='pub_date__month')
|
||||
|
||||
# autoslugify value from a dynamic attribute (i.e. a method)
|
||||
slug = AutoSlugField(populate_from='get_full_name')
|
||||
|
||||
# autoslugify value from a custom callable
|
||||
# (ex. usage: user profile models)
|
||||
slug = AutoSlugField(populate_from=lambda instance: instance.user.get_full_name())
|
||||
|
||||
# specify model manager for looking up slugs shared by subclasses
|
||||
|
||||
class Article(models.Model):
|
||||
'''An article with title, date and slug. The slug is not totally
|
||||
unique but there will be no two articles with the same slug within
|
||||
any month.
|
||||
'''
|
||||
objects = models.Manager()
|
||||
title = models.CharField(max_length=200)
|
||||
slug = AutoSlugField(populate_from='title', unique_with='pub_date__month', manager=objects)
|
||||
|
||||
class NewsArticle(Article):
|
||||
pass
|
||||
|
||||
# autoslugify value using custom `slugify` function
|
||||
from autoslug.settings import slugify as default_slugify
|
||||
def custom_slugify(value):
|
||||
return default_slugify(value).replace('-', '_')
|
||||
slug = AutoSlugField(slugify=custom_slugify)
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['max_length'] = kwargs.get('max_length', 50)
|
||||
|
||||
# autopopulated slug is not editable unless told so
|
||||
self.populate_from = kwargs.pop('populate_from', None)
|
||||
if self.populate_from:
|
||||
kwargs.setdefault('editable', False)
|
||||
|
||||
# unique_with value can be string or tuple
|
||||
self.unique_with = kwargs.pop('unique_with', ())
|
||||
if isinstance(self.unique_with, basestring):
|
||||
self.unique_with = (self.unique_with,)
|
||||
|
||||
self.slugify = kwargs.pop('slugify', slugify)
|
||||
assert hasattr(self.slugify, '__call__')
|
||||
|
||||
self.index_sep = kwargs.pop('sep', SLUG_INDEX_SEPARATOR)
|
||||
|
||||
# backward compatibility
|
||||
if kwargs.get('unique_with_date'):
|
||||
warn('Using unique_with_date="foo" in AutoSlugField is deprecated, '
|
||||
'use unique_with=("foo",) instead.', DeprecationWarning)
|
||||
self.unique_with += (kwargs['unique_with_date'],)
|
||||
|
||||
if self.unique_with:
|
||||
# we will do "manual" granular check below
|
||||
kwargs['unique'] = False
|
||||
|
||||
# Set db_index=True unless it's been set manually.
|
||||
if 'db_index' not in kwargs:
|
||||
kwargs['db_index'] = True
|
||||
|
||||
# When using model inheritence, set manager to search for matching
|
||||
# slug values
|
||||
self.manager = kwargs.pop('manager', None)
|
||||
|
||||
self.always_update = kwargs.pop('always_update', False)
|
||||
super(SlugField, self).__init__(*args, **kwargs)
|
||||
|
||||
def pre_save(self, instance, add):
|
||||
|
||||
# get currently entered slug
|
||||
value = self.value_from_object(instance)
|
||||
|
||||
manager = self.manager
|
||||
|
||||
# autopopulate
|
||||
if self.always_update or (self.populate_from and not value):
|
||||
value = utils.get_prepopulated_value(self, instance)
|
||||
|
||||
if __debug__ and not value:
|
||||
print 'Failed to populate slug %s.%s from %s' % \
|
||||
(instance._meta.object_name, self.name, self.populate_from)
|
||||
|
||||
slug = self.slugify(value)
|
||||
|
||||
if not slug:
|
||||
# no incoming value, use model name
|
||||
slug = instance._meta.module_name
|
||||
|
||||
assert slug, 'slug is defined before trying to ensure uniqueness'
|
||||
|
||||
slug = utils.crop_slug(self, slug)
|
||||
|
||||
# ensure the slug is unique (if required)
|
||||
if self.unique or self.unique_with:
|
||||
slug = utils.generate_unique_slug(self, instance, slug, manager)
|
||||
|
||||
assert slug, 'value is filled before saving'
|
||||
|
||||
# make the updated slug available as instance attribute
|
||||
setattr(instance, self.name, slug)
|
||||
|
||||
return slug
|
||||
|
||||
def south_field_triple(self):
|
||||
"Returns a suitable description of this field for South."
|
||||
args, kwargs = introspector(self)
|
||||
kwargs.update({
|
||||
'populate_from': 'None' if callable(self.populate_from) else repr(self.populate_from),
|
||||
'unique_with': repr(self.unique_with)
|
||||
})
|
||||
return ('autoslug.fields.AutoSlugField', args, kwargs)
|
|
@ -1,74 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2008—2012 Andy Mikhailenko
|
||||
#
|
||||
# This file is part of django-autoslug.
|
||||
#
|
||||
# django-autoslug is free software under terms of the GNU Lesser
|
||||
# General Public License version 3 (LGPLv3) as published by the Free
|
||||
# Software Foundation. See the file README for copying conditions.
|
||||
#
|
||||
"""
|
||||
Django settings that affect django-autoslug:
|
||||
|
||||
`AUTOSLUG_SLUGIFY_FUNCTION`
|
||||
Allows to define a custom slugifying function.
|
||||
|
||||
The function can be repsesented as string or callable, e.g.::
|
||||
|
||||
# custom function, path as string:
|
||||
AUTOSLUG_SLUGIFY_FUNCTION = 'some_app.slugify_func'
|
||||
|
||||
# custom function, callable:
|
||||
AUTOSLUG_SLUGIFY_FUNCTION = some_app.slugify_func
|
||||
|
||||
# custom function, defined inline:
|
||||
AUTOSLUG_SLUGIFY_FUNCTION = lambda slug: 'can i haz %s?' % slug
|
||||
|
||||
If no value is given, default value is used.
|
||||
|
||||
Default value is one of these depending on availability in given order:
|
||||
|
||||
* `unidecode.unidecode()` if Unidecode_ is available;
|
||||
* `pytils.translit.slugify()` if pytils_ is available;
|
||||
* `django.template.defaultfilters.slugify()` bundled with Django.
|
||||
|
||||
django-autoslug also ships a couple of slugify functions that use
|
||||
the translitcodec_ Python library, e.g.::
|
||||
|
||||
# using as many characters as needed to make a natural replacement
|
||||
AUTOSLUG_SLUGIFY_FUNCTION = 'autoslug.utils.translit_long'
|
||||
|
||||
# using the minimum number of characters to make a replacement
|
||||
AUTOSLUG_SLUGIFY_FUNCTION = 'autoslug.utils.translit_short'
|
||||
|
||||
# only performing single character replacements
|
||||
AUTOSLUG_SLUGIFY_FUNCTION = 'autoslug.utils.translit_one'
|
||||
|
||||
.. _Unidecode: http://pypi.python.org/pypi/Unidecode
|
||||
.. _pytils: http://pypi.python.org/pypi/pytils
|
||||
.. _translitcodec: http://pypi.python.org/pypi/translitcodec
|
||||
|
||||
"""
|
||||
from django.conf import settings
|
||||
|
||||
# use custom slugifying function if any
|
||||
slugify = getattr(settings, 'AUTOSLUG_SLUGIFY_FUNCTION', None)
|
||||
|
||||
if not slugify:
|
||||
try:
|
||||
# i18n-friendly approach
|
||||
from unidecode import unidecode
|
||||
slugify = lambda s: unidecode(s).replace(' ', '-')
|
||||
except ImportError:
|
||||
try:
|
||||
# Cyrillic transliteration (primarily Russian)
|
||||
from pytils.translit import slugify
|
||||
except ImportError:
|
||||
# fall back to Django's default method
|
||||
slugify = 'django.template.defaultfilters.slugify'
|
||||
|
||||
# find callable by string
|
||||
if isinstance(slugify, str):
|
||||
from django.core.urlresolvers import get_callable
|
||||
slugify = get_callable(slugify)
|
|
@ -1,349 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2008—2012 Andy Mikhailenko
|
||||
#
|
||||
# This file is part of django-autoslug.
|
||||
#
|
||||
# django-autoslug is free software under terms of the GNU Lesser
|
||||
# General Public License version 3 (LGPLv3) as published by the Free
|
||||
# Software Foundation. See the file README for copying conditions.
|
||||
#
|
||||
|
||||
# python
|
||||
import datetime
|
||||
|
||||
# django
|
||||
from django.db.models import Model, CharField, DateField, ForeignKey, Manager
|
||||
|
||||
# this app
|
||||
from autoslug.settings import slugify as default_slugify
|
||||
from autoslug import AutoSlugField
|
||||
|
||||
|
||||
class SimpleModel(Model):
|
||||
"""
|
||||
>>> a = SimpleModel(name='test')
|
||||
>>> a.save()
|
||||
>>> a.slug
|
||||
'simplemodel'
|
||||
"""
|
||||
name = CharField(max_length=200)
|
||||
slug = AutoSlugField()
|
||||
|
||||
|
||||
class ModelWithUniqueSlug(Model):
|
||||
"""
|
||||
>>> greeting = 'Hello world!'
|
||||
>>> a = ModelWithUniqueSlug(name=greeting)
|
||||
>>> a.save()
|
||||
>>> a.slug
|
||||
u'hello-world'
|
||||
>>> b = ModelWithUniqueSlug(name=greeting)
|
||||
>>> b.save()
|
||||
>>> b.slug
|
||||
u'hello-world-2'
|
||||
"""
|
||||
name = CharField(max_length=200)
|
||||
slug = AutoSlugField(populate_from='name', unique=True)
|
||||
|
||||
|
||||
class ModelWithUniqueSlugFK(Model):
|
||||
"""
|
||||
>>> sm1 = SimpleModel.objects.create(name='test')
|
||||
>>> sm2 = SimpleModel.objects.create(name='test')
|
||||
>>> sm3 = SimpleModel.objects.create(name='test2')
|
||||
>>> greeting = 'Hello world!'
|
||||
>>> a = ModelWithUniqueSlugFK.objects.create(name=greeting, simple_model=sm1)
|
||||
>>> a.slug
|
||||
u'hello-world'
|
||||
>>> b = ModelWithUniqueSlugFK.objects.create(name=greeting, simple_model=sm2)
|
||||
>>> b.slug
|
||||
u'hello-world-2'
|
||||
>>> c = ModelWithUniqueSlugFK.objects.create(name=greeting, simple_model=sm3)
|
||||
>>> c.slug
|
||||
u'hello-world'
|
||||
>>> d = ModelWithUniqueSlugFK.objects.create(name=greeting, simple_model=sm1)
|
||||
>>> d.slug
|
||||
u'hello-world-3'
|
||||
>>> sm3.name = 'test'
|
||||
>>> sm3.save()
|
||||
>>> c.slug
|
||||
u'hello-world'
|
||||
>>> c.save()
|
||||
>>> c.slug
|
||||
u'hello-world-4'
|
||||
"""
|
||||
name = CharField(max_length=200)
|
||||
simple_model = ForeignKey(SimpleModel)
|
||||
slug = AutoSlugField(populate_from='name', unique_with='simple_model__name')
|
||||
|
||||
|
||||
class ModelWithUniqueSlugDate(Model):
|
||||
"""
|
||||
>>> a = ModelWithUniqueSlugDate(slug='test', date=datetime.date(2009,9,9))
|
||||
>>> b = ModelWithUniqueSlugDate(slug='test', date=datetime.date(2009,9,9))
|
||||
>>> c = ModelWithUniqueSlugDate(slug='test', date=datetime.date(2009,9,10))
|
||||
>>> for m in a,b,c:
|
||||
... m.save()
|
||||
>>> a.slug
|
||||
u'test'
|
||||
>>> b.slug
|
||||
u'test-2'
|
||||
>>> c.slug
|
||||
u'test'
|
||||
"""
|
||||
date = DateField()
|
||||
slug = AutoSlugField(unique_with='date')
|
||||
|
||||
|
||||
class ModelWithUniqueSlugDay(Model): # same as ...Date, just more explicit
|
||||
"""
|
||||
>>> a = ModelWithUniqueSlugDay(slug='test', date=datetime.date(2009, 9, 9))
|
||||
>>> b = ModelWithUniqueSlugDay(slug='test', date=datetime.date(2009, 9, 9))
|
||||
>>> c = ModelWithUniqueSlugDay(slug='test', date=datetime.date(2009, 9, 10))
|
||||
>>> for m in a,b,c:
|
||||
... m.save()
|
||||
>>> a.slug
|
||||
u'test'
|
||||
>>> b.slug
|
||||
u'test-2'
|
||||
>>> c.slug
|
||||
u'test'
|
||||
"""
|
||||
date = DateField()
|
||||
slug = AutoSlugField(unique_with='date__day')
|
||||
|
||||
|
||||
class ModelWithUniqueSlugMonth(Model):
|
||||
"""
|
||||
>>> a = ModelWithUniqueSlugMonth(slug='test', date=datetime.date(2009, 9, 9))
|
||||
>>> b = ModelWithUniqueSlugMonth(slug='test', date=datetime.date(2009, 9, 10))
|
||||
>>> c = ModelWithUniqueSlugMonth(slug='test', date=datetime.date(2009, 10, 9))
|
||||
>>> for m in a,b,c:
|
||||
... m.save()
|
||||
>>> a.slug
|
||||
u'test'
|
||||
>>> b.slug
|
||||
u'test-2'
|
||||
>>> c.slug
|
||||
u'test'
|
||||
"""
|
||||
date = DateField()
|
||||
slug = AutoSlugField(unique_with='date__month')
|
||||
|
||||
|
||||
class ModelWithUniqueSlugYear(Model):
|
||||
"""
|
||||
>>> a = ModelWithUniqueSlugYear(slug='test', date=datetime.date(2009, 9, 9))
|
||||
>>> b = ModelWithUniqueSlugYear(slug='test', date=datetime.date(2009, 10, 9))
|
||||
>>> c = ModelWithUniqueSlugYear(slug='test', date=datetime.date(2010, 9, 9))
|
||||
>>> for m in a,b,c:
|
||||
... m.save()
|
||||
>>> a.slug
|
||||
u'test'
|
||||
>>> b.slug
|
||||
u'test-2'
|
||||
>>> c.slug
|
||||
u'test'
|
||||
"""
|
||||
date = DateField()
|
||||
slug = AutoSlugField(unique_with='date__year')
|
||||
|
||||
|
||||
class ModelWithLongName(Model):
|
||||
"""
|
||||
>>> long_name = 'x' * 250
|
||||
>>> a = ModelWithLongName(name=long_name)
|
||||
>>> a.save()
|
||||
>>> len(a.slug) # original slug is cropped by field length
|
||||
50
|
||||
"""
|
||||
name = CharField(max_length=200)
|
||||
slug = AutoSlugField(populate_from='name')
|
||||
|
||||
|
||||
class ModelWithLongNameUnique(Model):
|
||||
"""
|
||||
>>> long_name = 'x' * 250
|
||||
>>> a = ModelWithLongNameUnique(name=long_name)
|
||||
>>> a.save()
|
||||
>>> len(a.slug) # original slug is cropped by field length
|
||||
50
|
||||
>>> b = ModelWithLongNameUnique(name=long_name)
|
||||
>>> b.save()
|
||||
>>> b.slug[-3:] # uniqueness is forced
|
||||
u'x-2'
|
||||
>>> len(b.slug) # slug is cropped
|
||||
50
|
||||
"""
|
||||
name = CharField(max_length=200)
|
||||
slug = AutoSlugField(populate_from='name', unique=True)
|
||||
|
||||
|
||||
class ModelWithCallable(Model):
|
||||
"""
|
||||
>>> a = ModelWithCallable.objects.create(name='larch')
|
||||
>>> a.slug
|
||||
u'the-larch'
|
||||
"""
|
||||
name = CharField(max_length=200)
|
||||
slug = AutoSlugField(populate_from=lambda instance: u'the %s' % instance.name)
|
||||
|
||||
|
||||
class ModelWithCallableAttr(Model):
|
||||
"""
|
||||
>>> a = ModelWithCallableAttr.objects.create(name='albatross')
|
||||
>>> a.slug
|
||||
u'spam-albatross-and-spam'
|
||||
"""
|
||||
name = CharField(max_length=200)
|
||||
slug = AutoSlugField(populate_from='get_name')
|
||||
|
||||
def get_name(self):
|
||||
return u'spam, %s and spam' % self.name
|
||||
|
||||
|
||||
class ModelWithCustomPrimaryKey(Model):
|
||||
"""
|
||||
# just check if models are created without exceptions
|
||||
>>> a = ModelWithCustomPrimaryKey.objects.create(custom_primary_key='a',
|
||||
... name='name used in slug')
|
||||
>>> b = ModelWithCustomPrimaryKey.objects.create(custom_primary_key='b',
|
||||
... name='name used in slug')
|
||||
>>> a.slug
|
||||
u'name-used-in-slug'
|
||||
"""
|
||||
custom_primary_key = CharField(primary_key=True, max_length=1)
|
||||
name = CharField(max_length=200)
|
||||
slug = AutoSlugField(populate_from='name', unique=True)
|
||||
|
||||
|
||||
custom_slugify = lambda value: default_slugify(value).replace('-', '_')
|
||||
class ModelWithCustomSlugifier(Model):
|
||||
"""
|
||||
>>> a = ModelWithCustomSlugifier.objects.create(slug='hello world!')
|
||||
>>> b = ModelWithCustomSlugifier.objects.create(slug='hello world!')
|
||||
>>> b.slug
|
||||
u'hello_world-2'
|
||||
"""
|
||||
slug = AutoSlugField(unique=True, slugify=custom_slugify)
|
||||
|
||||
|
||||
class ModelWithCustomSeparator(Model):
|
||||
"""
|
||||
>>> a = ModelWithCustomSeparator.objects.create(slug='hello world!')
|
||||
>>> b = ModelWithCustomSeparator.objects.create(slug='hello world!')
|
||||
>>> b.slug
|
||||
u'hello-world_2'
|
||||
"""
|
||||
slug = AutoSlugField(unique=True, sep='_')
|
||||
|
||||
|
||||
class ModelWithReferenceToItself(Model):
|
||||
"""
|
||||
>>> a = ModelWithReferenceToItself(slug='test')
|
||||
>>> a.save()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Attribute ModelWithReferenceToItself.slug references itself \
|
||||
in `unique_with`. Please use "unique=True" for this case.
|
||||
"""
|
||||
slug = AutoSlugField(unique_with='slug')
|
||||
|
||||
|
||||
class ModelWithWrongReferencedField(Model):
|
||||
"""
|
||||
>>> a = ModelWithWrongReferencedField(slug='test')
|
||||
>>> a.save()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Could not find attribute ModelWithWrongReferencedField.wrong_field \
|
||||
referenced by ModelWithWrongReferencedField.slug (see constraint `unique_with`)
|
||||
"""
|
||||
slug = AutoSlugField(unique_with='wrong_field')
|
||||
|
||||
|
||||
class ModelWithWrongLookupInUniqueWith(Model):
|
||||
"""
|
||||
>>> a = ModelWithWrongLookupInUniqueWith(name='test', slug='test')
|
||||
>>> a.save()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Could not resolve lookup "name__foo" in `unique_with` of \
|
||||
ModelWithWrongLookupInUniqueWith.slug
|
||||
"""
|
||||
slug = AutoSlugField(unique_with='name__foo')
|
||||
name = CharField(max_length=10)
|
||||
|
||||
|
||||
class ModelWithWrongFieldOrder(Model):
|
||||
"""
|
||||
>>> a = ModelWithWrongFieldOrder(slug='test')
|
||||
>>> a.save()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Could not check uniqueness of ModelWithWrongFieldOrder.slug with \
|
||||
respect to ModelWithWrongFieldOrder.date because the latter is empty. Please \
|
||||
ensure that "slug" is declared *after* all fields listed in unique_with.
|
||||
"""
|
||||
slug = AutoSlugField(unique_with='date')
|
||||
date = DateField(blank=False, null=False)
|
||||
|
||||
|
||||
class ModelWithAcceptableEmptyDependency(Model):
|
||||
"""
|
||||
>>> model = ModelWithAcceptableEmptyDependency
|
||||
>>> instances = [model.objects.create(slug='hello') for x in range(0,2)]
|
||||
>>> [x.slug for x in model.objects.all()]
|
||||
[u'hello', u'hello-2']
|
||||
"""
|
||||
date = DateField(blank=True, null=True)
|
||||
slug = AutoSlugField(unique_with='date')
|
||||
|
||||
|
||||
class ModelWithAutoUpdateEnabled(Model):
|
||||
"""
|
||||
>>> a = ModelWithAutoUpdateEnabled(name='My name')
|
||||
>>> a.save()
|
||||
>>> a.slug
|
||||
u'my-name'
|
||||
>>> a.name = 'My new name'
|
||||
>>> a.save()
|
||||
>>> a.slug
|
||||
u'my-new-name'
|
||||
"""
|
||||
name = CharField(max_length=200)
|
||||
slug = AutoSlugField(populate_from='name', always_update=True)
|
||||
|
||||
|
||||
class ModelWithSlugSpaceSharedIntegrityError(ModelWithUniqueSlug):
|
||||
"""
|
||||
>>> a = ModelWithUniqueSlug(name='My name')
|
||||
>>> a.save()
|
||||
>>> b = ModelWithSlugSpaceSharedIntegrityError(name='My name')
|
||||
>>> b.save()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
IntegrityError: column slug is not unique
|
||||
"""
|
||||
|
||||
|
||||
class SharedSlugSpace(Model):
|
||||
objects = Manager()
|
||||
name = CharField(max_length=200)
|
||||
# ensure that any subclasses use the base model's manager for testing
|
||||
# slug uniqueness
|
||||
slug = AutoSlugField(populate_from='name', unique=True, manager=objects)
|
||||
|
||||
|
||||
class ModelWithSlugSpaceShared(SharedSlugSpace):
|
||||
"""
|
||||
>>> a = SharedSlugSpace(name='My name')
|
||||
>>> a.save()
|
||||
>>> a.slug
|
||||
u'my-name'
|
||||
>>> b = ModelWithSlugSpaceShared(name='My name')
|
||||
>>> b.save()
|
||||
>>> b.slug
|
||||
u'my-name-2'
|
||||
"""
|
|
@ -1,176 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2008—2012 Andy Mikhailenko
|
||||
#
|
||||
# This file is part of django-autoslug.
|
||||
#
|
||||
# django-autoslug is free software under terms of the GNU Lesser
|
||||
# General Public License version 3 (LGPLv3) as published by the Free
|
||||
# Software Foundation. See the file README for copying conditions.
|
||||
#
|
||||
|
||||
# django
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.models.fields import FieldDoesNotExist, DateField
|
||||
|
||||
|
||||
def get_prepopulated_value(field, instance):
|
||||
"""
|
||||
Returns preliminary value based on `populate_from`.
|
||||
"""
|
||||
if hasattr(field.populate_from, '__call__'):
|
||||
# AutoSlugField(populate_from=lambda instance: ...)
|
||||
return field.populate_from(instance)
|
||||
else:
|
||||
# AutoSlugField(populate_from='foo')
|
||||
attr = getattr(instance, field.populate_from)
|
||||
return callable(attr) and attr() or attr
|
||||
|
||||
|
||||
def generate_unique_slug(field, instance, slug, manager):
|
||||
"""
|
||||
Generates unique slug by adding a number to given value until no model
|
||||
instance can be found with such slug. If ``unique_with`` (a tuple of field
|
||||
names) was specified for the field, all these fields are included together
|
||||
in the query when looking for a "rival" model instance.
|
||||
"""
|
||||
|
||||
original_slug = slug = crop_slug(field, slug)
|
||||
|
||||
default_lookups = tuple(get_uniqueness_lookups(field, instance, field.unique_with))
|
||||
|
||||
index = 1
|
||||
|
||||
if not manager:
|
||||
manager = type(instance).objects
|
||||
|
||||
|
||||
# keep changing the slug until it is unique
|
||||
while True:
|
||||
# find instances with same slug
|
||||
lookups = dict(default_lookups, **{field.name: slug})
|
||||
rivals = manager.filter(**lookups).exclude(pk=instance.pk)
|
||||
|
||||
if not rivals:
|
||||
# the slug is unique, no model uses it
|
||||
return slug
|
||||
|
||||
# the slug is not unique; change once more
|
||||
index += 1
|
||||
|
||||
# ensure the resulting string is not too long
|
||||
tail_length = len(field.index_sep) + len(str(index))
|
||||
combined_length = len(original_slug) + tail_length
|
||||
if field.max_length < combined_length:
|
||||
original_slug = original_slug[:field.max_length - tail_length]
|
||||
|
||||
# re-generate the slug
|
||||
data = dict(slug=original_slug, sep=field.index_sep, index=index)
|
||||
slug = '%(slug)s%(sep)s%(index)d' % data
|
||||
|
||||
# ...next iteration...
|
||||
|
||||
|
||||
def get_uniqueness_lookups(field, instance, unique_with):
|
||||
"""
|
||||
Returns a dict'able tuple of lookups to ensure uniqueness of a slug.
|
||||
"""
|
||||
for original_lookup_name in unique_with:
|
||||
if '__' in original_lookup_name:
|
||||
field_name, inner_lookup = original_lookup_name.split('__', 1)
|
||||
else:
|
||||
field_name, inner_lookup = original_lookup_name, None
|
||||
|
||||
try:
|
||||
other_field = instance._meta.get_field(field_name)
|
||||
except FieldDoesNotExist:
|
||||
raise ValueError('Could not find attribute %s.%s referenced'
|
||||
' by %s.%s (see constraint `unique_with`)'
|
||||
% (instance._meta.object_name, field_name,
|
||||
instance._meta.object_name, field.name))
|
||||
|
||||
if field == other_field:
|
||||
raise ValueError('Attribute %s.%s references itself in `unique_with`.'
|
||||
' Please use "unique=True" for this case.'
|
||||
% (instance._meta.object_name, field_name))
|
||||
|
||||
value = getattr(instance, field_name)
|
||||
if not value:
|
||||
if other_field.blank:
|
||||
break
|
||||
raise ValueError('Could not check uniqueness of %s.%s with'
|
||||
' respect to %s.%s because the latter is empty.'
|
||||
' Please ensure that "%s" is declared *after*'
|
||||
' all fields listed in unique_with.'
|
||||
% (instance._meta.object_name, field.name,
|
||||
instance._meta.object_name, field_name,
|
||||
field.name))
|
||||
if isinstance(other_field, DateField): # DateTimeField is a DateField subclass
|
||||
inner_lookup = inner_lookup or 'day'
|
||||
|
||||
if '__' in inner_lookup:
|
||||
raise ValueError('The `unique_with` constraint in %s.%s'
|
||||
' is set to "%s", but AutoSlugField only'
|
||||
' accepts one level of nesting for dates'
|
||||
' (e.g. "date__month").'
|
||||
% (instance._meta.object_name, field.name,
|
||||
original_lookup_name))
|
||||
|
||||
parts = ['year', 'month', 'day']
|
||||
try:
|
||||
granularity = parts.index(inner_lookup) + 1
|
||||
except ValueError:
|
||||
raise ValueError('expected one of %s, got "%s" in "%s"'
|
||||
% (parts, inner_lookup, original_lookup_name))
|
||||
else:
|
||||
for part in parts[:granularity]:
|
||||
lookup = '%s__%s' % (field_name, part)
|
||||
yield lookup, getattr(value, part)
|
||||
else:
|
||||
# TODO: this part should be documented as it involves recursion
|
||||
if inner_lookup:
|
||||
if not hasattr(value, '_meta'):
|
||||
raise ValueError('Could not resolve lookup "%s" in `unique_with` of %s.%s'
|
||||
% (original_lookup_name, instance._meta.object_name, field.name))
|
||||
for inner_name, inner_value in get_uniqueness_lookups(field, value, [inner_lookup]):
|
||||
yield original_lookup_name, inner_value
|
||||
else:
|
||||
yield field_name, value
|
||||
|
||||
|
||||
def crop_slug(field, slug):
|
||||
if field.max_length < len(slug):
|
||||
return slug[:field.max_length]
|
||||
return slug
|
||||
|
||||
|
||||
try:
|
||||
import translitcodec
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
import re
|
||||
PUNCT_RE = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')
|
||||
|
||||
def translitcodec_slugify(codec):
|
||||
def _slugify(value, delim=u'-', encoding=''):
|
||||
"""
|
||||
Generates an ASCII-only slug.
|
||||
|
||||
Borrowed from http://flask.pocoo.org/snippets/5/
|
||||
"""
|
||||
if encoding:
|
||||
encoder = "%s/%s" % (codec, encoding)
|
||||
else:
|
||||
encoder = codec
|
||||
result = []
|
||||
for word in PUNCT_RE.split(value.lower()):
|
||||
word = word.encode(encoder)
|
||||
if word:
|
||||
result.append(word)
|
||||
return unicode(delim.join(result))
|
||||
return _slugify
|
||||
|
||||
translit_long = translitcodec_slugify("translit/long")
|
||||
translit_short = translitcodec_slugify("translit/short")
|
||||
translit_one = translitcodec_slugify("translit/one")
|
|
@ -1,339 +0,0 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: celery
|
||||
Version: 2.4.0
|
||||
Summary: Distributed Task Queue
|
||||
Home-page: http://celeryproject.org
|
||||
Author: Ask Solem
|
||||
Author-email: ask@celeryproject.org
|
||||
License: BSD
|
||||
Description: =================================
|
||||
celery - Distributed Task Queue
|
||||
=================================
|
||||
|
||||
.. image:: http://cloud.github.com/downloads/ask/celery/celery_128.png
|
||||
|
||||
:Version: 2.4.0
|
||||
:Web: http://celeryproject.org/
|
||||
:Download: http://pypi.python.org/pypi/celery/
|
||||
:Source: http://github.com/ask/celery/
|
||||
:Keywords: task queue, job queue, asynchronous, rabbitmq, amqp, redis,
|
||||
python, webhooks, queue, distributed
|
||||
|
||||
--
|
||||
|
||||
.. _celery-synopsis:
|
||||
|
||||
Celery is an open source asynchronous task queue/job queue based on
|
||||
distributed message passing. It is focused on real-time operation,
|
||||
but supports scheduling as well.
|
||||
|
||||
The execution units, called tasks, are executed concurrently on one or
|
||||
more worker nodes using multiprocessing, `Eventlet`_ or `gevent`_. Tasks can
|
||||
execute asynchronously (in the background) or synchronously
|
||||
(wait until ready).
|
||||
|
||||
Celery is used in production systems to process millions of tasks a day.
|
||||
|
||||
Celery is written in Python, but the protocol can be implemented in any
|
||||
language. It can also `operate with other languages using webhooks`_.
|
||||
|
||||
The recommended message broker is `RabbitMQ`_, but `limited support`_ for
|
||||
`Redis`_, `Beanstalk`_, `MongoDB`_, `CouchDB`_ and
|
||||
databases (using `SQLAlchemy`_ or the `Django ORM`_) is also available.
|
||||
|
||||
|
||||
Celery is easy to integrate with `Django`_, `Pylons`_ and `Flask`_, using
|
||||
the `django-celery`_, `celery-pylons`_ and `Flask-Celery`_ add-on packages.
|
||||
|
||||
.. _`RabbitMQ`: http://www.rabbitmq.com/
|
||||
.. _`Redis`: http://code.google.com/p/redis/
|
||||
.. _`SQLAlchemy`: http://www.sqlalchemy.org/
|
||||
.. _`Django`: http://djangoproject.com/
|
||||
.. _`Django ORM`: http://djangoproject.com/
|
||||
.. _`Eventlet`: http://eventlet.net/
|
||||
.. _`gevent`: http://gevent.org/
|
||||
.. _`Beanstalk`: http://kr.github.com/beanstalkd/
|
||||
.. _`MongoDB`: http://mongodb.org/
|
||||
.. _`CouchDB`: http://couchdb.apache.org/
|
||||
.. _`Pylons`: http://pylonshq.com/
|
||||
.. _`Flask`: http://flask.pocoo.org/
|
||||
.. _`django-celery`: http://pypi.python.org/pypi/django-celery
|
||||
.. _`celery-pylons`: http://pypi.python.org/pypi/celery-pylons
|
||||
.. _`Flask-Celery`: http://github.com/ask/flask-celery/
|
||||
.. _`operate with other languages using webhooks`:
|
||||
http://ask.github.com/celery/userguide/remote-tasks.html
|
||||
.. _`limited support`:
|
||||
http://kombu.readthedocs.org/en/latest/introduction.html#transport-comparison
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
.. _celery-overview:
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
This is a high level overview of the architecture.
|
||||
|
||||
.. image:: http://cloud.github.com/downloads/ask/celery/Celery-Overview-v4.jpg
|
||||
|
||||
The broker delivers tasks to the worker nodes.
|
||||
A worker node is a networked machine running `celeryd`. This can be one or
|
||||
more machines depending on the workload.
|
||||
|
||||
The result of the task can be stored for later retrieval (called its
|
||||
"tombstone").
|
||||
|
||||
.. _celery-example:
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
You probably want to see some code by now, so here's an example task
|
||||
adding two numbers:
|
||||
::
|
||||
|
||||
from celery.task import task
|
||||
|
||||
@task
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
You can execute the task in the background, or wait for it to finish::
|
||||
|
||||
>>> result = add.delay(4, 4)
|
||||
>>> result.wait() # wait for and return the result
|
||||
8
|
||||
|
||||
Simple!
|
||||
|
||||
.. _celery-features:
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Messaging | Supported brokers include `RabbitMQ`_, `Redis`_, |
|
||||
| | `Beanstalk`_, `MongoDB`_, `CouchDB`_, and popular |
|
||||
| | SQL databases. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Fault-tolerant | Excellent configurable error recovery when using |
|
||||
| | `RabbitMQ`, ensures your tasks are never lost. |
|
||||
| | scenarios, and your tasks will never be lost. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Distributed | Runs on one or more machines. Supports |
|
||||
| | broker `clustering`_ and `HA`_ when used in |
|
||||
| | combination with `RabbitMQ`_. You can set up new |
|
||||
| | workers without central configuration (e.g. use |
|
||||
| | your grandma's laptop to help if the queue is |
|
||||
| | temporarily congested). |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Concurrency | Concurrency is achieved by using multiprocessing, |
|
||||
| | `Eventlet`_, `gevent` or a mix of these. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Scheduling | Supports recurring tasks like cron, or specifying |
|
||||
| | an exact date or countdown for when after the task |
|
||||
| | should be executed. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Latency | Low latency means you are able to execute tasks |
|
||||
| | *while the user is waiting*. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Return Values | Task return values can be saved to the selected |
|
||||
| | result store backend. You can wait for the result, |
|
||||
| | retrieve it later, or ignore it. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Result Stores | Database, `MongoDB`_, `Redis`_, `Tokyo Tyrant`, |
|
||||
| | `Cassandra`, or `AMQP`_ (message notification). |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Webhooks | Your tasks can also be HTTP callbacks, enabling |
|
||||
| | cross-language communication. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Rate limiting | Supports rate limiting by using the token bucket |
|
||||
| | algorithm, which accounts for bursts of traffic. |
|
||||
| | Rate limits can be set for each task type, or |
|
||||
| | globally for all. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Routing | Using AMQP's flexible routing model you can route |
|
||||
| | tasks to different workers, or select different |
|
||||
| | message topologies, by configuration or even at |
|
||||
| | runtime. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Remote-control | Worker nodes can be controlled from remote by |
|
||||
| | using broadcast messaging. A range of built-in |
|
||||
| | commands exist in addition to the ability to |
|
||||
| | easily define your own. (AMQP/Redis only) |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Monitoring | You can capture everything happening with the |
|
||||
| | workers in real-time by subscribing to events. |
|
||||
| | A real-time web monitor is in development. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Serialization | Supports Pickle, JSON, YAML, or easily defined |
|
||||
| | custom schemes. One task invocation can have a |
|
||||
| | different scheme than another. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Tracebacks | Errors and tracebacks are stored and can be |
|
||||
| | investigated after the fact. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| UUID | Every task has an UUID (Universally Unique |
|
||||
| | Identifier), which is the task id used to query |
|
||||
| | task status and return value. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Retries | Tasks can be retried if they fail, with |
|
||||
| | configurable maximum number of retries, and delays |
|
||||
| | between each retry. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Task Sets | A Task set is a task consisting of several |
|
||||
| | sub-tasks. You can find out how many, or if all |
|
||||
| | of the sub-tasks has been executed, and even |
|
||||
| | retrieve the results in order. Progress bars, |
|
||||
| | anyone? |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Made for Web | You can query status and results via URLs, |
|
||||
| | enabling the ability to poll task status using |
|
||||
| | Ajax. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Error Emails | Can be configured to send emails to the |
|
||||
| | administrators when tasks fails. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
|
||||
|
||||
.. _`clustering`: http://www.rabbitmq.com/clustering.html
|
||||
.. _`HA`: http://www.rabbitmq.com/pacemaker.html
|
||||
.. _`AMQP`: http://www.amqp.org/
|
||||
.. _`Stomp`: http://stomp.codehaus.org/
|
||||
.. _`Tokyo Tyrant`: http://tokyocabinet.sourceforge.net/
|
||||
|
||||
.. _celery-documentation:
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
The `latest documentation`_ with user guides, tutorials and API reference
|
||||
is hosted at Github.
|
||||
|
||||
.. _`latest documentation`: http://ask.github.com/celery/
|
||||
|
||||
.. _celery-installation:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
You can install Celery either via the Python Package Index (PyPI)
|
||||
or from source.
|
||||
|
||||
To install using `pip`,::
|
||||
|
||||
$ pip install Celery
|
||||
|
||||
To install using `easy_install`,::
|
||||
|
||||
$ easy_install Celery
|
||||
|
||||
.. _celery-installing-from-source:
|
||||
|
||||
Downloading and installing from source
|
||||
--------------------------------------
|
||||
|
||||
Download the latest version of Celery from
|
||||
http://pypi.python.org/pypi/celery/
|
||||
|
||||
You can install it by doing the following,::
|
||||
|
||||
$ tar xvfz celery-0.0.0.tar.gz
|
||||
$ cd celery-0.0.0
|
||||
$ python setup.py build
|
||||
# python setup.py install # as root
|
||||
|
||||
.. _celery-installing-from-git:
|
||||
|
||||
Using the development version
|
||||
-----------------------------
|
||||
|
||||
You can clone the repository by doing the following::
|
||||
|
||||
$ git clone git://github.com/ask/celery.git
|
||||
|
||||
.. _getting-help:
|
||||
|
||||
Getting Help
|
||||
============
|
||||
|
||||
.. _mailing-list:
|
||||
|
||||
Mailing list
|
||||
------------
|
||||
|
||||
For discussions about the usage, development, and future of celery,
|
||||
please join the `celery-users`_ mailing list.
|
||||
|
||||
.. _`celery-users`: http://groups.google.com/group/celery-users/
|
||||
|
||||
.. _irc-channel:
|
||||
|
||||
IRC
|
||||
---
|
||||
|
||||
Come chat with us on IRC. The `#celery`_ channel is located at the `Freenode`_
|
||||
network.
|
||||
|
||||
.. _`#celery`: irc://irc.freenode.net/celery
|
||||
.. _`Freenode`: http://freenode.net
|
||||
|
||||
.. _bug-tracker:
|
||||
|
||||
Bug tracker
|
||||
===========
|
||||
|
||||
If you have any suggestions, bug reports or annoyances please report them
|
||||
to our issue tracker at http://github.com/ask/celery/issues/
|
||||
|
||||
.. _wiki:
|
||||
|
||||
Wiki
|
||||
====
|
||||
|
||||
http://wiki.github.com/ask/celery/
|
||||
|
||||
.. _contributing-short:
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
Development of `celery` happens at Github: http://github.com/ask/celery
|
||||
|
||||
You are highly encouraged to participate in the development
|
||||
of `celery`. If you don't like Github (for some reason) you're welcome
|
||||
to send regular patches.
|
||||
|
||||
Be sure to also read the `Contributing to Celery`_ section in the
|
||||
documentation.
|
||||
|
||||
.. _`Contributing to Celery`: http://ask.github.com/celery/contributing.html
|
||||
|
||||
.. _license:
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
This software is licensed under the `New BSD License`. See the ``LICENSE``
|
||||
file in the top distribution directory for the full license text.
|
||||
|
||||
.. # vim: syntax=rst expandtab tabstop=4 shiftwidth=4 shiftround
|
||||
|
||||
|
||||
Platform: any
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Environment :: No Input/Output (Daemon)
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Topic :: Communications
|
||||
Classifier: Topic :: System :: Distributed Computing
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.5
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
|
@ -1,414 +0,0 @@
|
|||
AUTHORS
|
||||
Changelog
|
||||
FAQ
|
||||
INSTALL
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
README
|
||||
README.rst
|
||||
THANKS
|
||||
TODO
|
||||
setup.cfg
|
||||
setup.py
|
||||
celery/__init__.py
|
||||
celery/beat.py
|
||||
celery/conf.py
|
||||
celery/datastructures.py
|
||||
celery/decorators.py
|
||||
celery/exceptions.py
|
||||
celery/local.py
|
||||
celery/log.py
|
||||
celery/messaging.py
|
||||
celery/platforms.py
|
||||
celery/registry.py
|
||||
celery/result.py
|
||||
celery/routes.py
|
||||
celery/schedules.py
|
||||
celery/signals.py
|
||||
celery/states.py
|
||||
celery.egg-info/PKG-INFO
|
||||
celery.egg-info/SOURCES.txt
|
||||
celery.egg-info/dependency_links.txt
|
||||
celery.egg-info/entry_points.txt
|
||||
celery.egg-info/not-zip-safe
|
||||
celery.egg-info/requires.txt
|
||||
celery.egg-info/top_level.txt
|
||||
celery/app/__init__.py
|
||||
celery/app/amqp.py
|
||||
celery/app/base.py
|
||||
celery/app/defaults.py
|
||||
celery/app/task/__init__.py
|
||||
celery/apps/__init__.py
|
||||
celery/apps/beat.py
|
||||
celery/apps/worker.py
|
||||
celery/backends/__init__.py
|
||||
celery/backends/amqp.py
|
||||
celery/backends/base.py
|
||||
celery/backends/cache.py
|
||||
celery/backends/cassandra.py
|
||||
celery/backends/database.py
|
||||
celery/backends/mongodb.py
|
||||
celery/backends/pyredis.py
|
||||
celery/backends/redis.py
|
||||
celery/backends/tyrant.py
|
||||
celery/bin/__init__.py
|
||||
celery/bin/base.py
|
||||
celery/bin/camqadm.py
|
||||
celery/bin/celerybeat.py
|
||||
celery/bin/celeryctl.py
|
||||
celery/bin/celeryd.py
|
||||
celery/bin/celeryd_detach.py
|
||||
celery/bin/celeryd_multi.py
|
||||
celery/bin/celeryev.py
|
||||
celery/concurrency/__init__.py
|
||||
celery/concurrency/base.py
|
||||
celery/concurrency/eventlet.py
|
||||
celery/concurrency/gevent.py
|
||||
celery/concurrency/solo.py
|
||||
celery/concurrency/threads.py
|
||||
celery/concurrency/processes/__init__.py
|
||||
celery/concurrency/processes/_win.py
|
||||
celery/concurrency/processes/pool.py
|
||||
celery/contrib/__init__.py
|
||||
celery/contrib/abortable.py
|
||||
celery/contrib/batches.py
|
||||
celery/contrib/rdb.py
|
||||
celery/db/__init__.py
|
||||
celery/db/a805d4bd.py
|
||||
celery/db/dfd042c7.py
|
||||
celery/db/models.py
|
||||
celery/db/session.py
|
||||
celery/events/__init__.py
|
||||
celery/events/cursesmon.py
|
||||
celery/events/dumper.py
|
||||
celery/events/snapshot.py
|
||||
celery/events/state.py
|
||||
celery/execute/__init__.py
|
||||
celery/execute/trace.py
|
||||
celery/loaders/__init__.py
|
||||
celery/loaders/app.py
|
||||
celery/loaders/base.py
|
||||
celery/loaders/default.py
|
||||
celery/task/__init__.py
|
||||
celery/task/base.py
|
||||
celery/task/chords.py
|
||||
celery/task/control.py
|
||||
celery/task/http.py
|
||||
celery/task/schedules.py
|
||||
celery/task/sets.py
|
||||
celery/tests/__init__.py
|
||||
celery/tests/compat.py
|
||||
celery/tests/config.py
|
||||
celery/tests/utils.py
|
||||
celery/tests/functional/__init__.py
|
||||
celery/tests/functional/case.py
|
||||
celery/tests/functional/tasks.py
|
||||
celery/tests/test_app/__init__.py
|
||||
celery/tests/test_app/test_app_amqp.py
|
||||
celery/tests/test_app/test_app_defaults.py
|
||||
celery/tests/test_app/test_beat.py
|
||||
celery/tests/test_app/test_celery.py
|
||||
celery/tests/test_app/test_loaders.py
|
||||
celery/tests/test_app/test_log.py
|
||||
celery/tests/test_app/test_routes.py
|
||||
celery/tests/test_backends/__init__.py
|
||||
celery/tests/test_backends/test_amqp.py
|
||||
celery/tests/test_backends/test_base.py
|
||||
celery/tests/test_backends/test_cache.py
|
||||
celery/tests/test_backends/test_database.py
|
||||
celery/tests/test_backends/test_pyredis_compat.py
|
||||
celery/tests/test_backends/test_redis.py
|
||||
celery/tests/test_backends/test_redis_unit.py
|
||||
celery/tests/test_backends/test_tyrant.py
|
||||
celery/tests/test_bin/__init__.py
|
||||
celery/tests/test_bin/test_celerybeat.py
|
||||
celery/tests/test_bin/test_celeryd.py
|
||||
celery/tests/test_bin/test_celeryev.py
|
||||
celery/tests/test_compat/__init__.py
|
||||
celery/tests/test_compat/test_decorators.py
|
||||
celery/tests/test_compat/test_messaging.py
|
||||
celery/tests/test_concurrency/__init__.py
|
||||
celery/tests/test_concurrency/test_concurrency_eventlet.py
|
||||
celery/tests/test_concurrency/test_concurrency_processes.py
|
||||
celery/tests/test_concurrency/test_concurrency_solo.py
|
||||
celery/tests/test_concurrency/test_pool.py
|
||||
celery/tests/test_events/__init__.py
|
||||
celery/tests/test_events/test_events_cursesmon.py
|
||||
celery/tests/test_events/test_events_snapshot.py
|
||||
celery/tests/test_events/test_events_state.py
|
||||
celery/tests/test_slow/__init__.py
|
||||
celery/tests/test_slow/test_buckets.py
|
||||
celery/tests/test_task/__init__.py
|
||||
celery/tests/test_task/test_chord.py
|
||||
celery/tests/test_task/test_context.py
|
||||
celery/tests/test_task/test_execute_trace.py
|
||||
celery/tests/test_task/test_registry.py
|
||||
celery/tests/test_task/test_result.py
|
||||
celery/tests/test_task/test_states.py
|
||||
celery/tests/test_task/test_task_abortable.py
|
||||
celery/tests/test_task/test_task_builtins.py
|
||||
celery/tests/test_task/test_task_control.py
|
||||
celery/tests/test_task/test_task_http.py
|
||||
celery/tests/test_task/test_task_sets.py
|
||||
celery/tests/test_utils/__init__.py
|
||||
celery/tests/test_utils/test_datastructures.py
|
||||
celery/tests/test_utils/test_pickle.py
|
||||
celery/tests/test_utils/test_serialization.py
|
||||
celery/tests/test_utils/test_timer2.py
|
||||
celery/tests/test_utils/test_utils_encoding.py
|
||||
celery/tests/test_utils/test_utils_info.py
|
||||
celery/tests/test_utils/test_utils_timeutils.py
|
||||
celery/tests/test_worker/__init__.py
|
||||
celery/tests/test_worker/test_worker_autoscale.py
|
||||
celery/tests/test_worker/test_worker_control.py
|
||||
celery/tests/test_worker/test_worker_heartbeat.py
|
||||
celery/tests/test_worker/test_worker_job.py
|
||||
celery/tests/test_worker/test_worker_mediator.py
|
||||
celery/tests/test_worker/test_worker_revoke.py
|
||||
celery/tests/test_worker/test_worker_state.py
|
||||
celery/utils/__init__.py
|
||||
celery/utils/compat.py
|
||||
celery/utils/encoding.py
|
||||
celery/utils/functional.py
|
||||
celery/utils/mail.py
|
||||
celery/utils/patch.py
|
||||
celery/utils/serialization.py
|
||||
celery/utils/term.py
|
||||
celery/utils/timer2.py
|
||||
celery/utils/timeutils.py
|
||||
celery/utils/dispatch/__init__.py
|
||||
celery/utils/dispatch/saferef.py
|
||||
celery/utils/dispatch/signal.py
|
||||
celery/worker/__init__.py
|
||||
celery/worker/autoscale.py
|
||||
celery/worker/buckets.py
|
||||
celery/worker/consumer.py
|
||||
celery/worker/heartbeat.py
|
||||
celery/worker/job.py
|
||||
celery/worker/mediator.py
|
||||
celery/worker/state.py
|
||||
celery/worker/control/__init__.py
|
||||
celery/worker/control/builtins.py
|
||||
celery/worker/control/registry.py
|
||||
contrib/centos/celeryd.init
|
||||
contrib/centos/celeryd.sysconfig
|
||||
contrib/debian/README.rst
|
||||
contrib/debian/init.d-deprecated/celerybeat
|
||||
contrib/debian/init.d-deprecated/celeryd
|
||||
contrib/debian/init.d-deprecated/celeryevcam
|
||||
contrib/generic-init.d/celerybeat
|
||||
contrib/generic-init.d/celeryd
|
||||
contrib/generic-init.d/celeryevcam
|
||||
contrib/logtools/find-unprocessed-tasks-debug.sh
|
||||
contrib/logtools/find-unprocessed-tasks.sh
|
||||
contrib/logtools/periodic-task-runtimes.sh
|
||||
contrib/mac/org.celeryq.celerybeat.plist
|
||||
contrib/mac/org.celeryq.celeryd.plist
|
||||
contrib/mac/org.celeryq.celerymon.plist
|
||||
contrib/mac/watch-workers.applescript
|
||||
contrib/release/core-modules.txt
|
||||
contrib/release/doc4allmods
|
||||
contrib/release/flakeplus.py
|
||||
contrib/release/py3k-run-tests
|
||||
contrib/release/removepyc.sh
|
||||
contrib/release/sphinx-to-rst.py
|
||||
contrib/release/verify-reference-index.sh
|
||||
contrib/release/verify_config_reference.py
|
||||
contrib/supervisord/celerybeat.conf
|
||||
contrib/supervisord/celeryd.conf
|
||||
contrib/supervisord/supervisord.conf
|
||||
docs/Makefile
|
||||
docs/changelog.rst
|
||||
docs/community.rst
|
||||
docs/conf.py
|
||||
docs/configuration.rst
|
||||
docs/contributing.rst
|
||||
docs/faq.rst
|
||||
docs/index.rst
|
||||
docs/.static/.keep
|
||||
docs/.templates/page.html
|
||||
docs/.templates/sidebarintro.html
|
||||
docs/.templates/sidebarlogo.html
|
||||
docs/_ext/applyxrefs.py
|
||||
docs/_ext/celerydocs.py
|
||||
docs/_ext/literals_to_xrefs.py
|
||||
docs/_theme/celery/theme.conf
|
||||
docs/_theme/celery/static/celery.css_t
|
||||
docs/cookbook/daemonizing.rst
|
||||
docs/cookbook/index.rst
|
||||
docs/cookbook/tasks.rst
|
||||
docs/getting-started/broker-installation.rst
|
||||
docs/getting-started/first-steps-with-celery.rst
|
||||
docs/getting-started/index.rst
|
||||
docs/getting-started/introduction.rst
|
||||
docs/getting-started/resources.rst
|
||||
docs/images/Celery-Overview-v4.jpg
|
||||
docs/images/Celery1.0-inside-worker.jpg
|
||||
docs/images/celery-broker-worker-nodes.jpg
|
||||
docs/images/celery-broker-worker-relationship.jpg
|
||||
docs/images/celery-icon-128.png
|
||||
docs/images/celery-icon-32.png
|
||||
docs/images/celery-icon-64.png
|
||||
docs/images/celery-worker-bindings.jpg
|
||||
docs/images/celery_128.png
|
||||
docs/images/celery_512.png
|
||||
docs/images/celery_favicon_128.png
|
||||
docs/images/celeryevshotsm.jpg
|
||||
docs/images/djangoceleryadmin2.jpg
|
||||
docs/images/favicon.ico
|
||||
docs/images/favicon.png
|
||||
docs/includes/installation.txt
|
||||
docs/includes/introduction.txt
|
||||
docs/includes/resources.txt
|
||||
docs/internals/app-overview.rst
|
||||
docs/internals/deprecation.rst
|
||||
docs/internals/index.rst
|
||||
docs/internals/protocol.rst
|
||||
docs/internals/worker.rst
|
||||
docs/internals/reference/celery.backends.amqp.rst
|
||||
docs/internals/reference/celery.backends.base.rst
|
||||
docs/internals/reference/celery.backends.cache.rst
|
||||
docs/internals/reference/celery.backends.cassandra.rst
|
||||
docs/internals/reference/celery.backends.database.rst
|
||||
docs/internals/reference/celery.backends.mongodb.rst
|
||||
docs/internals/reference/celery.backends.redis.rst
|
||||
docs/internals/reference/celery.backends.rst
|
||||
docs/internals/reference/celery.backends.tyrant.rst
|
||||
docs/internals/reference/celery.beat.rst
|
||||
docs/internals/reference/celery.concurrency.base.rst
|
||||
docs/internals/reference/celery.concurrency.eventlet.rst
|
||||
docs/internals/reference/celery.concurrency.gevent.rst
|
||||
docs/internals/reference/celery.concurrency.processes.pool.rst
|
||||
docs/internals/reference/celery.concurrency.processes.rst
|
||||
docs/internals/reference/celery.concurrency.rst
|
||||
docs/internals/reference/celery.concurrency.solo.rst
|
||||
docs/internals/reference/celery.concurrency.threads.rst
|
||||
docs/internals/reference/celery.datastructures.rst
|
||||
docs/internals/reference/celery.db.models.rst
|
||||
docs/internals/reference/celery.db.session.rst
|
||||
docs/internals/reference/celery.events.cursesmon.rst
|
||||
docs/internals/reference/celery.events.dumper.rst
|
||||
docs/internals/reference/celery.events.snapshot.rst
|
||||
docs/internals/reference/celery.execute.trace.rst
|
||||
docs/internals/reference/celery.log.rst
|
||||
docs/internals/reference/celery.platforms.rst
|
||||
docs/internals/reference/celery.routes.rst
|
||||
docs/internals/reference/celery.utils.compat.rst
|
||||
docs/internals/reference/celery.utils.dispatch.rst
|
||||
docs/internals/reference/celery.utils.dispatch.saferef.rst
|
||||
docs/internals/reference/celery.utils.dispatch.signal.rst
|
||||
docs/internals/reference/celery.utils.encoding.rst
|
||||
docs/internals/reference/celery.utils.functional.rst
|
||||
docs/internals/reference/celery.utils.patch.rst
|
||||
docs/internals/reference/celery.utils.rst
|
||||
docs/internals/reference/celery.utils.serialization.rst
|
||||
docs/internals/reference/celery.utils.term.rst
|
||||
docs/internals/reference/celery.utils.timer2.rst
|
||||
docs/internals/reference/celery.utils.timeutils.rst
|
||||
docs/internals/reference/celery.worker.autoscale.rst
|
||||
docs/internals/reference/celery.worker.buckets.rst
|
||||
docs/internals/reference/celery.worker.consumer.rst
|
||||
docs/internals/reference/celery.worker.heartbeat.rst
|
||||
docs/internals/reference/celery.worker.job.rst
|
||||
docs/internals/reference/celery.worker.mediator.rst
|
||||
docs/internals/reference/celery.worker.rst
|
||||
docs/internals/reference/celery.worker.state.rst
|
||||
docs/internals/reference/index.rst
|
||||
docs/reference/celery.app.amqp.rst
|
||||
docs/reference/celery.app.defaults.rst
|
||||
docs/reference/celery.app.rst
|
||||
docs/reference/celery.app.task.rst
|
||||
docs/reference/celery.apps.beat.rst
|
||||
docs/reference/celery.apps.worker.rst
|
||||
docs/reference/celery.bin.base.rst
|
||||
docs/reference/celery.bin.camqadm.rst
|
||||
docs/reference/celery.bin.celerybeat.rst
|
||||
docs/reference/celery.bin.celeryctl.rst
|
||||
docs/reference/celery.bin.celeryd.rst
|
||||
docs/reference/celery.bin.celeryd_multi.rst
|
||||
docs/reference/celery.bin.celeryev.rst
|
||||
docs/reference/celery.contrib.abortable.rst
|
||||
docs/reference/celery.contrib.batches.rst
|
||||
docs/reference/celery.contrib.rdb.rst
|
||||
docs/reference/celery.events.rst
|
||||
docs/reference/celery.events.state.rst
|
||||
docs/reference/celery.exceptions.rst
|
||||
docs/reference/celery.loaders.app.rst
|
||||
docs/reference/celery.loaders.base.rst
|
||||
docs/reference/celery.loaders.default.rst
|
||||
docs/reference/celery.loaders.rst
|
||||
docs/reference/celery.registry.rst
|
||||
docs/reference/celery.result.rst
|
||||
docs/reference/celery.schedules.rst
|
||||
docs/reference/celery.signals.rst
|
||||
docs/reference/celery.states.rst
|
||||
docs/reference/celery.task.base.rst
|
||||
docs/reference/celery.task.chords.rst
|
||||
docs/reference/celery.task.control.rst
|
||||
docs/reference/celery.task.http.rst
|
||||
docs/reference/celery.task.rst
|
||||
docs/reference/celery.task.sets.rst
|
||||
docs/reference/celery.utils.mail.rst
|
||||
docs/reference/index.rst
|
||||
docs/releases/1.0/announcement.rst
|
||||
docs/slidesource/slide-example1-result.py
|
||||
docs/slidesource/slide-example1.py
|
||||
docs/templates/readme.txt
|
||||
docs/tutorials/clickcounter.rst
|
||||
docs/tutorials/debugging.rst
|
||||
docs/tutorials/index.rst
|
||||
docs/tutorials/otherqueues.rst
|
||||
docs/userguide/executing.rst
|
||||
docs/userguide/index.rst
|
||||
docs/userguide/monitoring.rst
|
||||
docs/userguide/optimizing.rst
|
||||
docs/userguide/overview.rst
|
||||
docs/userguide/periodic-tasks.rst
|
||||
docs/userguide/remote-tasks.rst
|
||||
docs/userguide/routing.rst
|
||||
docs/userguide/signals.rst
|
||||
docs/userguide/tasks.rst
|
||||
docs/userguide/tasksets.rst
|
||||
docs/userguide/workers.rst
|
||||
docs/userguide/concurrency/eventlet.rst
|
||||
docs/userguide/concurrency/index.rst
|
||||
examples/README.rst
|
||||
examples/app/myapp.py
|
||||
examples/celery_http_gateway/README.rst
|
||||
examples/celery_http_gateway/__init__.py
|
||||
examples/celery_http_gateway/manage.py
|
||||
examples/celery_http_gateway/settings.py
|
||||
examples/celery_http_gateway/urls.py
|
||||
examples/eventlet/README.rst
|
||||
examples/eventlet/bulk_task_producer.py
|
||||
examples/eventlet/celeryconfig.py
|
||||
examples/eventlet/tasks.py
|
||||
examples/eventlet/webcrawler.py
|
||||
examples/gevent/celeryconfig.py
|
||||
examples/gevent/tasks.py
|
||||
examples/httpexample/README.rst
|
||||
examples/httpexample/__init__.py
|
||||
examples/httpexample/manage.py
|
||||
examples/httpexample/settings.py
|
||||
examples/httpexample/urls.py
|
||||
examples/httpexample/views.py
|
||||
examples/pythonproject/demoapp/README.rst
|
||||
examples/pythonproject/demoapp/__init__.py
|
||||
examples/pythonproject/demoapp/celeryconfig.py
|
||||
examples/pythonproject/demoapp/tasks.py
|
||||
examples/pythonproject/demoapp/test.py
|
||||
funtests/setup.py
|
||||
funtests/bench/worker.py
|
||||
funtests/suite/__init__.py
|
||||
funtests/suite/config.py
|
||||
funtests/suite/test_basic.py
|
||||
funtests/suite/test_leak.py
|
||||
requirements/default-py3k.txt
|
||||
requirements/default.txt
|
||||
requirements/docs.txt
|
||||
requirements/pkgutils.txt
|
||||
requirements/py25.txt
|
||||
requirements/py26.txt
|
||||
requirements/test-py3k.txt
|
||||
requirements/test-pypy.txt
|
||||
requirements/test.txt
|
|
@ -1,8 +0,0 @@
|
|||
[console_scripts]
|
||||
celeryctl = celery.bin.celeryctl:main
|
||||
celeryd = celery.bin.celeryd:main
|
||||
camqadm = celery.bin.camqadm:main
|
||||
celeryev = celery.bin.celeryev:main
|
||||
celeryd-multi = celery.bin.celeryd_multi:main
|
||||
celerybeat = celery.bin.celerybeat:main
|
||||
|
|
@ -1,360 +0,0 @@
|
|||
../celery/conf.py
|
||||
../celery/states.py
|
||||
../celery/decorators.py
|
||||
../celery/local.py
|
||||
../celery/exceptions.py
|
||||
../celery/messaging.py
|
||||
../celery/schedules.py
|
||||
../celery/routes.py
|
||||
../celery/__init__.py
|
||||
../celery/platforms.py
|
||||
../celery/signals.py
|
||||
../celery/beat.py
|
||||
../celery/result.py
|
||||
../celery/registry.py
|
||||
../celery/log.py
|
||||
../celery/datastructures.py
|
||||
../celery/worker/mediator.py
|
||||
../celery/worker/buckets.py
|
||||
../celery/worker/state.py
|
||||
../celery/worker/heartbeat.py
|
||||
../celery/worker/__init__.py
|
||||
../celery/worker/job.py
|
||||
../celery/worker/consumer.py
|
||||
../celery/worker/autoscale.py
|
||||
../celery/contrib/batches.py
|
||||
../celery/contrib/abortable.py
|
||||
../celery/contrib/__init__.py
|
||||
../celery/contrib/rdb.py
|
||||
../celery/backends/cassandra.py
|
||||
../celery/backends/cache.py
|
||||
../celery/backends/amqp.py
|
||||
../celery/backends/pyredis.py
|
||||
../celery/backends/redis.py
|
||||
../celery/backends/tyrant.py
|
||||
../celery/backends/base.py
|
||||
../celery/backends/__init__.py
|
||||
../celery/backends/database.py
|
||||
../celery/backends/mongodb.py
|
||||
../celery/utils/timer2.py
|
||||
../celery/utils/encoding.py
|
||||
../celery/utils/functional.py
|
||||
../celery/utils/mail.py
|
||||
../celery/utils/__init__.py
|
||||
../celery/utils/term.py
|
||||
../celery/utils/compat.py
|
||||
../celery/utils/serialization.py
|
||||
../celery/utils/patch.py
|
||||
../celery/utils/timeutils.py
|
||||
../celery/events/state.py
|
||||
../celery/events/dumper.py
|
||||
../celery/events/cursesmon.py
|
||||
../celery/events/snapshot.py
|
||||
../celery/events/__init__.py
|
||||
../celery/execute/trace.py
|
||||
../celery/execute/__init__.py
|
||||
../celery/apps/worker.py
|
||||
../celery/apps/__init__.py
|
||||
../celery/apps/beat.py
|
||||
../celery/db/dfd042c7.py
|
||||
../celery/db/a805d4bd.py
|
||||
../celery/db/session.py
|
||||
../celery/db/__init__.py
|
||||
../celery/db/models.py
|
||||
../celery/bin/celeryev.py
|
||||
../celery/bin/celeryd_detach.py
|
||||
../celery/bin/camqadm.py
|
||||
../celery/bin/base.py
|
||||
../celery/bin/__init__.py
|
||||
../celery/bin/celeryd_multi.py
|
||||
../celery/bin/celerybeat.py
|
||||
../celery/bin/celeryctl.py
|
||||
../celery/bin/celeryd.py
|
||||
../celery/tests/config.py
|
||||
../celery/tests/utils.py
|
||||
../celery/tests/__init__.py
|
||||
../celery/tests/compat.py
|
||||
../celery/task/chords.py
|
||||
../celery/task/sets.py
|
||||
../celery/task/http.py
|
||||
../celery/task/schedules.py
|
||||
../celery/task/control.py
|
||||
../celery/task/base.py
|
||||
../celery/task/__init__.py
|
||||
../celery/concurrency/solo.py
|
||||
../celery/concurrency/gevent.py
|
||||
../celery/concurrency/base.py
|
||||
../celery/concurrency/__init__.py
|
||||
../celery/concurrency/threads.py
|
||||
../celery/concurrency/eventlet.py
|
||||
../celery/app/amqp.py
|
||||
../celery/app/base.py
|
||||
../celery/app/__init__.py
|
||||
../celery/app/defaults.py
|
||||
../celery/loaders/base.py
|
||||
../celery/loaders/__init__.py
|
||||
../celery/loaders/app.py
|
||||
../celery/loaders/default.py
|
||||
../celery/worker/control/builtins.py
|
||||
../celery/worker/control/__init__.py
|
||||
../celery/worker/control/registry.py
|
||||
../celery/utils/dispatch/__init__.py
|
||||
../celery/utils/dispatch/signal.py
|
||||
../celery/utils/dispatch/saferef.py
|
||||
../celery/tests/test_utils/test_timer2.py
|
||||
../celery/tests/test_utils/test_pickle.py
|
||||
../celery/tests/test_utils/test_utils_encoding.py
|
||||
../celery/tests/test_utils/test_utils_timeutils.py
|
||||
../celery/tests/test_utils/test_datastructures.py
|
||||
../celery/tests/test_utils/test_serialization.py
|
||||
../celery/tests/test_utils/__init__.py
|
||||
../celery/tests/test_utils/test_utils_info.py
|
||||
../celery/tests/test_worker/test_worker_job.py
|
||||
../celery/tests/test_worker/test_worker_heartbeat.py
|
||||
../celery/tests/test_worker/test_worker_state.py
|
||||
../celery/tests/test_worker/test_worker_autoscale.py
|
||||
../celery/tests/test_worker/test_worker_mediator.py
|
||||
../celery/tests/test_worker/test_worker_revoke.py
|
||||
../celery/tests/test_worker/__init__.py
|
||||
../celery/tests/test_worker/test_worker_control.py
|
||||
../celery/tests/test_compat/test_messaging.py
|
||||
../celery/tests/test_compat/__init__.py
|
||||
../celery/tests/test_compat/test_decorators.py
|
||||
../celery/tests/functional/case.py
|
||||
../celery/tests/functional/tasks.py
|
||||
../celery/tests/functional/__init__.py
|
||||
../celery/tests/test_backends/test_redis_unit.py
|
||||
../celery/tests/test_backends/test_base.py
|
||||
../celery/tests/test_backends/test_cache.py
|
||||
../celery/tests/test_backends/test_redis.py
|
||||
../celery/tests/test_backends/test_amqp.py
|
||||
../celery/tests/test_backends/test_tyrant.py
|
||||
../celery/tests/test_backends/test_database.py
|
||||
../celery/tests/test_backends/__init__.py
|
||||
../celery/tests/test_backends/test_pyredis_compat.py
|
||||
../celery/tests/test_concurrency/test_concurrency_solo.py
|
||||
../celery/tests/test_concurrency/test_concurrency_eventlet.py
|
||||
../celery/tests/test_concurrency/__init__.py
|
||||
../celery/tests/test_concurrency/test_concurrency_processes.py
|
||||
../celery/tests/test_concurrency/test_pool.py
|
||||
../celery/tests/test_events/test_events_state.py
|
||||
../celery/tests/test_events/test_events_cursesmon.py
|
||||
../celery/tests/test_events/test_events_snapshot.py
|
||||
../celery/tests/test_events/__init__.py
|
||||
../celery/tests/test_slow/test_buckets.py
|
||||
../celery/tests/test_slow/__init__.py
|
||||
../celery/tests/test_bin/test_celeryev.py
|
||||
../celery/tests/test_bin/test_celeryd.py
|
||||
../celery/tests/test_bin/__init__.py
|
||||
../celery/tests/test_bin/test_celerybeat.py
|
||||
../celery/tests/test_task/test_execute_trace.py
|
||||
../celery/tests/test_task/test_result.py
|
||||
../celery/tests/test_task/test_task_http.py
|
||||
../celery/tests/test_task/test_task_abortable.py
|
||||
../celery/tests/test_task/test_task_builtins.py
|
||||
../celery/tests/test_task/test_states.py
|
||||
../celery/tests/test_task/__init__.py
|
||||
../celery/tests/test_task/test_chord.py
|
||||
../celery/tests/test_task/test_registry.py
|
||||
../celery/tests/test_task/test_context.py
|
||||
../celery/tests/test_task/test_task_control.py
|
||||
../celery/tests/test_task/test_task_sets.py
|
||||
../celery/tests/test_app/test_app_amqp.py
|
||||
../celery/tests/test_app/test_routes.py
|
||||
../celery/tests/test_app/test_app_defaults.py
|
||||
../celery/tests/test_app/__init__.py
|
||||
../celery/tests/test_app/test_loaders.py
|
||||
../celery/tests/test_app/test_log.py
|
||||
../celery/tests/test_app/test_beat.py
|
||||
../celery/tests/test_app/test_celery.py
|
||||
../celery/concurrency/processes/pool.py
|
||||
../celery/concurrency/processes/__init__.py
|
||||
../celery/concurrency/processes/_win.py
|
||||
../celery/app/task/__init__.py
|
||||
../celery/conf.pyc
|
||||
../celery/states.pyc
|
||||
../celery/decorators.pyc
|
||||
../celery/local.pyc
|
||||
../celery/exceptions.pyc
|
||||
../celery/messaging.pyc
|
||||
../celery/schedules.pyc
|
||||
../celery/routes.pyc
|
||||
../celery/__init__.pyc
|
||||
../celery/platforms.pyc
|
||||
../celery/signals.pyc
|
||||
../celery/beat.pyc
|
||||
../celery/result.pyc
|
||||
../celery/registry.pyc
|
||||
../celery/log.pyc
|
||||
../celery/datastructures.pyc
|
||||
../celery/worker/mediator.pyc
|
||||
../celery/worker/buckets.pyc
|
||||
../celery/worker/state.pyc
|
||||
../celery/worker/heartbeat.pyc
|
||||
../celery/worker/__init__.pyc
|
||||
../celery/worker/job.pyc
|
||||
../celery/worker/consumer.pyc
|
||||
../celery/worker/autoscale.pyc
|
||||
../celery/contrib/batches.pyc
|
||||
../celery/contrib/abortable.pyc
|
||||
../celery/contrib/__init__.pyc
|
||||
../celery/contrib/rdb.pyc
|
||||
../celery/backends/cassandra.pyc
|
||||
../celery/backends/cache.pyc
|
||||
../celery/backends/amqp.pyc
|
||||
../celery/backends/pyredis.pyc
|
||||
../celery/backends/redis.pyc
|
||||
../celery/backends/tyrant.pyc
|
||||
../celery/backends/base.pyc
|
||||
../celery/backends/__init__.pyc
|
||||
../celery/backends/database.pyc
|
||||
../celery/backends/mongodb.pyc
|
||||
../celery/utils/timer2.pyc
|
||||
../celery/utils/encoding.pyc
|
||||
../celery/utils/functional.pyc
|
||||
../celery/utils/mail.pyc
|
||||
../celery/utils/__init__.pyc
|
||||
../celery/utils/term.pyc
|
||||
../celery/utils/compat.pyc
|
||||
../celery/utils/serialization.pyc
|
||||
../celery/utils/patch.pyc
|
||||
../celery/utils/timeutils.pyc
|
||||
../celery/events/state.pyc
|
||||
../celery/events/dumper.pyc
|
||||
../celery/events/cursesmon.pyc
|
||||
../celery/events/snapshot.pyc
|
||||
../celery/events/__init__.pyc
|
||||
../celery/execute/trace.pyc
|
||||
../celery/execute/__init__.pyc
|
||||
../celery/apps/worker.pyc
|
||||
../celery/apps/__init__.pyc
|
||||
../celery/apps/beat.pyc
|
||||
../celery/db/dfd042c7.pyc
|
||||
../celery/db/a805d4bd.pyc
|
||||
../celery/db/session.pyc
|
||||
../celery/db/__init__.pyc
|
||||
../celery/db/models.pyc
|
||||
../celery/bin/celeryev.pyc
|
||||
../celery/bin/celeryd_detach.pyc
|
||||
../celery/bin/camqadm.pyc
|
||||
../celery/bin/base.pyc
|
||||
../celery/bin/__init__.pyc
|
||||
../celery/bin/celeryd_multi.pyc
|
||||
../celery/bin/celerybeat.pyc
|
||||
../celery/bin/celeryctl.pyc
|
||||
../celery/bin/celeryd.pyc
|
||||
../celery/tests/config.pyc
|
||||
../celery/tests/utils.pyc
|
||||
../celery/tests/__init__.pyc
|
||||
../celery/tests/compat.pyc
|
||||
../celery/task/chords.pyc
|
||||
../celery/task/sets.pyc
|
||||
../celery/task/http.pyc
|
||||
../celery/task/schedules.pyc
|
||||
../celery/task/control.pyc
|
||||
../celery/task/base.pyc
|
||||
../celery/task/__init__.pyc
|
||||
../celery/concurrency/solo.pyc
|
||||
../celery/concurrency/gevent.pyc
|
||||
../celery/concurrency/base.pyc
|
||||
../celery/concurrency/__init__.pyc
|
||||
../celery/concurrency/threads.pyc
|
||||
../celery/concurrency/eventlet.pyc
|
||||
../celery/app/amqp.pyc
|
||||
../celery/app/base.pyc
|
||||
../celery/app/__init__.pyc
|
||||
../celery/app/defaults.pyc
|
||||
../celery/loaders/base.pyc
|
||||
../celery/loaders/__init__.pyc
|
||||
../celery/loaders/app.pyc
|
||||
../celery/loaders/default.pyc
|
||||
../celery/worker/control/builtins.pyc
|
||||
../celery/worker/control/__init__.pyc
|
||||
../celery/worker/control/registry.pyc
|
||||
../celery/utils/dispatch/__init__.pyc
|
||||
../celery/utils/dispatch/signal.pyc
|
||||
../celery/utils/dispatch/saferef.pyc
|
||||
../celery/tests/test_utils/test_timer2.pyc
|
||||
../celery/tests/test_utils/test_pickle.pyc
|
||||
../celery/tests/test_utils/test_utils_encoding.pyc
|
||||
../celery/tests/test_utils/test_utils_timeutils.pyc
|
||||
../celery/tests/test_utils/test_datastructures.pyc
|
||||
../celery/tests/test_utils/test_serialization.pyc
|
||||
../celery/tests/test_utils/__init__.pyc
|
||||
../celery/tests/test_utils/test_utils_info.pyc
|
||||
../celery/tests/test_worker/test_worker_job.pyc
|
||||
../celery/tests/test_worker/test_worker_heartbeat.pyc
|
||||
../celery/tests/test_worker/test_worker_state.pyc
|
||||
../celery/tests/test_worker/test_worker_autoscale.pyc
|
||||
../celery/tests/test_worker/test_worker_mediator.pyc
|
||||
../celery/tests/test_worker/test_worker_revoke.pyc
|
||||
../celery/tests/test_worker/__init__.pyc
|
||||
../celery/tests/test_worker/test_worker_control.pyc
|
||||
../celery/tests/test_compat/test_messaging.pyc
|
||||
../celery/tests/test_compat/__init__.pyc
|
||||
../celery/tests/test_compat/test_decorators.pyc
|
||||
../celery/tests/functional/case.pyc
|
||||
../celery/tests/functional/tasks.pyc
|
||||
../celery/tests/functional/__init__.pyc
|
||||
../celery/tests/test_backends/test_redis_unit.pyc
|
||||
../celery/tests/test_backends/test_base.pyc
|
||||
../celery/tests/test_backends/test_cache.pyc
|
||||
../celery/tests/test_backends/test_redis.pyc
|
||||
../celery/tests/test_backends/test_amqp.pyc
|
||||
../celery/tests/test_backends/test_tyrant.pyc
|
||||
../celery/tests/test_backends/test_database.pyc
|
||||
../celery/tests/test_backends/__init__.pyc
|
||||
../celery/tests/test_backends/test_pyredis_compat.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_solo.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_eventlet.pyc
|
||||
../celery/tests/test_concurrency/__init__.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_processes.pyc
|
||||
../celery/tests/test_concurrency/test_pool.pyc
|
||||
../celery/tests/test_events/test_events_state.pyc
|
||||
../celery/tests/test_events/test_events_cursesmon.pyc
|
||||
../celery/tests/test_events/test_events_snapshot.pyc
|
||||
../celery/tests/test_events/__init__.pyc
|
||||
../celery/tests/test_slow/test_buckets.pyc
|
||||
../celery/tests/test_slow/__init__.pyc
|
||||
../celery/tests/test_bin/test_celeryev.pyc
|
||||
../celery/tests/test_bin/test_celeryd.pyc
|
||||
../celery/tests/test_bin/__init__.pyc
|
||||
../celery/tests/test_bin/test_celerybeat.pyc
|
||||
../celery/tests/test_task/test_execute_trace.pyc
|
||||
../celery/tests/test_task/test_result.pyc
|
||||
../celery/tests/test_task/test_task_http.pyc
|
||||
../celery/tests/test_task/test_task_abortable.pyc
|
||||
../celery/tests/test_task/test_task_builtins.pyc
|
||||
../celery/tests/test_task/test_states.pyc
|
||||
../celery/tests/test_task/__init__.pyc
|
||||
../celery/tests/test_task/test_chord.pyc
|
||||
../celery/tests/test_task/test_registry.pyc
|
||||
../celery/tests/test_task/test_context.pyc
|
||||
../celery/tests/test_task/test_task_control.pyc
|
||||
../celery/tests/test_task/test_task_sets.pyc
|
||||
../celery/tests/test_app/test_app_amqp.pyc
|
||||
../celery/tests/test_app/test_routes.pyc
|
||||
../celery/tests/test_app/test_app_defaults.pyc
|
||||
../celery/tests/test_app/__init__.pyc
|
||||
../celery/tests/test_app/test_loaders.pyc
|
||||
../celery/tests/test_app/test_log.pyc
|
||||
../celery/tests/test_app/test_beat.pyc
|
||||
../celery/tests/test_app/test_celery.pyc
|
||||
../celery/concurrency/processes/pool.pyc
|
||||
../celery/concurrency/processes/__init__.pyc
|
||||
../celery/concurrency/processes/_win.pyc
|
||||
../celery/app/task/__init__.pyc
|
||||
./
|
||||
top_level.txt
|
||||
SOURCES.txt
|
||||
not-zip-safe
|
||||
entry_points.txt
|
||||
PKG-INFO
|
||||
requires.txt
|
||||
dependency_links.txt
|
||||
../../../bin/celeryctl
|
||||
../../../bin/celeryd
|
||||
../../../bin/camqadm
|
||||
../../../bin/celeryev
|
||||
../../../bin/celeryd-multi
|
||||
../../../bin/celerybeat
|
|
@ -1,5 +0,0 @@
|
|||
importlib
|
||||
anyjson>=0.3.1
|
||||
kombu>=1.4.3,<3.0.0
|
||||
python-dateutil>=1.5.0,<2.0.0
|
||||
ordereddict
|
|
@ -1 +0,0 @@
|
|||
celery
|
|
@ -1,393 +0,0 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: celery
|
||||
Version: 2.5.0
|
||||
Summary: Distributed Task Queue
|
||||
Home-page: http://celeryproject.org
|
||||
Author: Ask Solem
|
||||
Author-email: ask@celeryproject.org
|
||||
License: BSD
|
||||
Description: =================================
|
||||
celery - Distributed Task Queue
|
||||
=================================
|
||||
|
||||
.. image:: http://cloud.github.com/downloads/ask/celery/celery_128.png
|
||||
|
||||
:Version: 2.5.0
|
||||
:Web: http://celeryproject.org/
|
||||
:Download: http://pypi.python.org/pypi/celery/
|
||||
:Source: http://github.com/ask/celery/
|
||||
:Keywords: task queue, job queue, asynchronous, rabbitmq, amqp, redis,
|
||||
python, webhooks, queue, distributed
|
||||
|
||||
--
|
||||
|
||||
.. _celery-synopsis:
|
||||
|
||||
Celery is an open source asynchronous task queue/job queue based on
|
||||
distributed message passing. It is focused on real-time operation,
|
||||
but supports scheduling as well.
|
||||
|
||||
The execution units, called tasks, are executed concurrently on one or
|
||||
more worker nodes using multiprocessing, `Eventlet`_ or `gevent`_. Tasks can
|
||||
execute asynchronously (in the background) or synchronously
|
||||
(wait until ready).
|
||||
|
||||
Celery is used in production systems to process millions of tasks a day.
|
||||
|
||||
Celery is written in Python, but the protocol can be implemented in any
|
||||
language. It can also `operate with other languages using webhooks`_.
|
||||
There's also `RCelery` for the Ruby programming language, and a `PHP client`.
|
||||
|
||||
The recommended message broker is `RabbitMQ`_, but support for
|
||||
`Redis`_, `MongoDB`_, Beanstalk`_, `Amazon SQS`_, `CouchDB`_ and
|
||||
databases (using `SQLAlchemy`_ or the `Django ORM`_) is also available.
|
||||
|
||||
|
||||
Celery is easy to integrate with `Django`_, `Pylons`_ `Flask`_, and `web2py`_, using
|
||||
the `django-celery`_, `celery-pylons`_ and `Flask-Celery`_ add-on packages.
|
||||
But Celery is only Python, and the integration packages is used mostly for
|
||||
convenience, Celery has also been successfully used with other frameworks and
|
||||
libraries, like `Pyramid`_ and `Bottle`_.
|
||||
|
||||
.. _`RCelery`: http://leapfrogdevelopment.github.com/rcelery/
|
||||
.. _`PHP client`: https://github.com/gjedeer/celery-php
|
||||
.. _`RabbitMQ`: http://www.rabbitmq.com/
|
||||
.. _`Redis`: http://code.google.com/p/redis/
|
||||
.. _`SQLAlchemy`: http://www.sqlalchemy.org/
|
||||
.. _`Django`: http://djangoproject.com/
|
||||
.. _`Django ORM`: http://djangoproject.com/
|
||||
.. _`Eventlet`: http://eventlet.net/
|
||||
.. _`gevent`: http://gevent.org/
|
||||
.. _`Beanstalk`: http://kr.github.com/beanstalkd/
|
||||
.. _`MongoDB`: http://mongodb.org/
|
||||
.. _`CouchDB`: http://couchdb.apache.org/
|
||||
.. _`Amazon SQS`: http://aws.amazon.com/sqs/
|
||||
.. _`Pylons`: http://pylonshq.com/
|
||||
.. _`Flask`: http://flask.pocoo.org/
|
||||
.. _`web2py`: http://web2py.com/
|
||||
.. _`Bottle`: http://bottlepy.org/
|
||||
.. _`Pyramid`: http://docs.pylonsproject.org/en/latest/docs/pyramid.html
|
||||
.. _`django-celery`: http://pypi.python.org/pypi/django-celery
|
||||
.. _`celery-pylons`: http://pypi.python.org/pypi/celery-pylons
|
||||
.. _`Flask-Celery`: http://github.com/ask/flask-celery/
|
||||
.. _`web2py-celery`: http://code.google.com/p/web2py-celery/
|
||||
.. _`operate with other languages using webhooks`:
|
||||
http://ask.github.com/celery/userguide/remote-tasks.html
|
||||
.. _`limited support`:
|
||||
http://kombu.readthedocs.org/en/latest/introduction.html#transport-comparison
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
.. _celery-overview:
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
This is a high level overview of the architecture.
|
||||
|
||||
.. image:: http://cloud.github.com/downloads/ask/celery/Celery-Overview-v4.jpg
|
||||
|
||||
The broker delivers tasks to the worker nodes.
|
||||
A worker node is a networked machine running `celeryd`. This can be one or
|
||||
more machines depending on the workload.
|
||||
|
||||
The result of the task can be stored for later retrieval (called its
|
||||
"tombstone").
|
||||
|
||||
.. _celery-example:
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
You probably want to see some code by now, so here's an example task
|
||||
adding two numbers:
|
||||
::
|
||||
|
||||
from celery.task import task
|
||||
|
||||
@task
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
You can execute the task in the background, or wait for it to finish::
|
||||
|
||||
>>> result = add.delay(4, 4)
|
||||
>>> result.wait() # wait for and return the result
|
||||
8
|
||||
|
||||
Simple!
|
||||
|
||||
.. _celery-features:
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Messaging | Supported brokers include `RabbitMQ`_, `Redis`_, |
|
||||
| | `Beanstalk`_, `MongoDB`_, `CouchDB`_, and popular |
|
||||
| | SQL databases. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Fault-tolerant | Excellent configurable error recovery when using |
|
||||
| | `RabbitMQ`, ensures your tasks are never lost. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Distributed | Runs on one or more machines. Supports |
|
||||
| | broker `clustering`_ and `HA`_ when used in |
|
||||
| | combination with `RabbitMQ`_. You can set up new |
|
||||
| | workers without central configuration (e.g. use |
|
||||
| | your grandma's laptop to help if the queue is |
|
||||
| | temporarily congested). |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Concurrency | Concurrency is achieved by using multiprocessing, |
|
||||
| | `Eventlet`_, `gevent` or a mix of these. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Scheduling | Supports recurring tasks like cron, or specifying |
|
||||
| | an exact date or countdown for when after the task |
|
||||
| | should be executed. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Latency | Low latency means you are able to execute tasks |
|
||||
| | *while the user is waiting*. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Return Values | Task return values can be saved to the selected |
|
||||
| | result store backend. You can wait for the result, |
|
||||
| | retrieve it later, or ignore it. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Result Stores | Database, `MongoDB`_, `Redis`_, `Tokyo Tyrant`, |
|
||||
| | `Cassandra`, or `AMQP`_ (message notification). |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Webhooks | Your tasks can also be HTTP callbacks, enabling |
|
||||
| | cross-language communication. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Rate limiting | Supports rate limiting by using the token bucket |
|
||||
| | algorithm, which accounts for bursts of traffic. |
|
||||
| | Rate limits can be set for each task type, or |
|
||||
| | globally for all. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Routing | Using AMQP's flexible routing model you can route |
|
||||
| | tasks to different workers, or select different |
|
||||
| | message topologies, by configuration or even at |
|
||||
| | runtime. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Remote-control | Worker nodes can be controlled from remote by |
|
||||
| | using broadcast messaging. A range of built-in |
|
||||
| | commands exist in addition to the ability to |
|
||||
| | easily define your own. (AMQP/Redis only) |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Monitoring | You can capture everything happening with the |
|
||||
| | workers in real-time by subscribing to events. |
|
||||
| | A real-time web monitor is in development. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Serialization | Supports Pickle, JSON, YAML, or easily defined |
|
||||
| | custom schemes. One task invocation can have a |
|
||||
| | different scheme than another. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Tracebacks | Errors and tracebacks are stored and can be |
|
||||
| | investigated after the fact. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| UUID | Every task has an UUID (Universally Unique |
|
||||
| | Identifier), which is the task id used to query |
|
||||
| | task status and return value. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Retries | Tasks can be retried if they fail, with |
|
||||
| | configurable maximum number of retries, and delays |
|
||||
| | between each retry. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Task Sets | A Task set is a task consisting of several |
|
||||
| | sub-tasks. You can find out how many, or if all |
|
||||
| | of the sub-tasks has been executed, and even |
|
||||
| | retrieve the results in order. Progress bars, |
|
||||
| | anyone? |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Made for Web | You can query status and results via URLs, |
|
||||
| | enabling the ability to poll task status using |
|
||||
| | Ajax. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Error Emails | Can be configured to send emails to the |
|
||||
| | administrators when tasks fails. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
|
||||
|
||||
.. _`clustering`: http://www.rabbitmq.com/clustering.html
|
||||
.. _`HA`: http://www.rabbitmq.com/pacemaker.html
|
||||
.. _`AMQP`: http://www.amqp.org/
|
||||
.. _`Stomp`: http://stomp.codehaus.org/
|
||||
.. _`Tokyo Tyrant`: http://tokyocabinet.sourceforge.net/
|
||||
|
||||
.. _celery-documentation:
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
The `latest documentation`_ with user guides, tutorials and API reference
|
||||
is hosted at Github.
|
||||
|
||||
.. _`latest documentation`: http://ask.github.com/celery/
|
||||
|
||||
.. _celery-installation:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
You can install Celery either via the Python Package Index (PyPI)
|
||||
or from source.
|
||||
|
||||
To install using `pip`,::
|
||||
|
||||
$ pip install -U Celery
|
||||
|
||||
To install using `easy_install`,::
|
||||
|
||||
$ easy_install -U Celery
|
||||
|
||||
Bundles
|
||||
-------
|
||||
|
||||
Celery also defines a group of bundles that can be used
|
||||
to install Celery and the dependencies for a given feature.
|
||||
|
||||
The following bundles are available:
|
||||
|
||||
:`celery-with-redis`_:
|
||||
for using Redis as a broker.
|
||||
|
||||
:`celery-with-mongodb`_:
|
||||
for using MongoDB as a broker.
|
||||
|
||||
:`django-celery-with-redis`_:
|
||||
for Django, and using Redis as a broker.
|
||||
|
||||
:`django-celery-with-mongodb`_:
|
||||
for Django, and using MongoDB as a broker.
|
||||
|
||||
:`bundle-celery`_:
|
||||
convenience bundle installing *Celery* and related packages.
|
||||
|
||||
.. _`celery-with-redis`:
|
||||
http://pypi.python.org/pypi/celery-with-redis/
|
||||
.. _`celery-with-mongodb`:
|
||||
http://pypi.python.org/pypi/celery-with-mongdb/
|
||||
.. _`django-celery-with-redis`:
|
||||
http://pypi.python.org/pypi/django-celery-with-redis/
|
||||
.. _`django-celery-with-mongodb`:
|
||||
http://pypi.python.org/pypi/django-celery-with-mongdb/
|
||||
.. _`bundle-celery`:
|
||||
http://pypi.python.org/pypi/bundle-celery/
|
||||
|
||||
.. _celery-installing-from-source:
|
||||
|
||||
Downloading and installing from source
|
||||
--------------------------------------
|
||||
|
||||
Download the latest version of Celery from
|
||||
http://pypi.python.org/pypi/celery/
|
||||
|
||||
You can install it by doing the following,::
|
||||
|
||||
$ tar xvfz celery-0.0.0.tar.gz
|
||||
$ cd celery-0.0.0
|
||||
$ python setup.py build
|
||||
# python setup.py install # as root
|
||||
|
||||
.. _celery-installing-from-git:
|
||||
|
||||
Using the development version
|
||||
-----------------------------
|
||||
|
||||
You can clone the repository by doing the following::
|
||||
|
||||
$ git clone git://github.com/ask/celery.git
|
||||
|
||||
.. _getting-help:
|
||||
|
||||
Getting Help
|
||||
============
|
||||
|
||||
.. _mailing-list:
|
||||
|
||||
Mailing list
|
||||
------------
|
||||
|
||||
For discussions about the usage, development, and future of celery,
|
||||
please join the `celery-users`_ mailing list.
|
||||
|
||||
.. _`celery-users`: http://groups.google.com/group/celery-users/
|
||||
|
||||
.. _irc-channel:
|
||||
|
||||
IRC
|
||||
---
|
||||
|
||||
Come chat with us on IRC. The `#celery`_ channel is located at the `Freenode`_
|
||||
network.
|
||||
|
||||
.. _`#celery`: irc://irc.freenode.net/celery
|
||||
.. _`Freenode`: http://freenode.net
|
||||
|
||||
.. _bug-tracker:
|
||||
|
||||
Bug tracker
|
||||
===========
|
||||
|
||||
If you have any suggestions, bug reports or annoyances please report them
|
||||
to our issue tracker at http://github.com/ask/celery/issues/
|
||||
|
||||
.. _wiki:
|
||||
|
||||
Wiki
|
||||
====
|
||||
|
||||
http://wiki.github.com/ask/celery/
|
||||
|
||||
.. _contributing-short:
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
Development of `celery` happens at Github: http://github.com/ask/celery
|
||||
|
||||
You are highly encouraged to participate in the development
|
||||
of `celery`. If you don't like Github (for some reason) you're welcome
|
||||
to send regular patches.
|
||||
|
||||
Be sure to also read the `Contributing to Celery`_ section in the
|
||||
documentation.
|
||||
|
||||
.. _`Contributing to Celery`: http://ask.github.com/celery/contributing.html
|
||||
|
||||
.. _license:
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
This software is licensed under the `New BSD License`. See the ``LICENSE``
|
||||
file in the top distribution directory for the full license text.
|
||||
|
||||
.. # vim: syntax=rst expandtab tabstop=4 shiftwidth=4 shiftround
|
||||
|
||||
|
||||
Platform: any
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Topic :: System :: Distributed Computing
|
||||
Classifier: Topic :: Software Development :: Object Brokering
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: Intended Audience :: Science/Research
|
||||
Classifier: Intended Audience :: Financial and Insurance Industry
|
||||
Classifier: Intended Audience :: Healthcare Industry
|
||||
Classifier: Environment :: No Input/Output (Daemon)
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.5
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.2
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Programming Language :: Python :: Implementation :: Jython
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Operating System :: Microsoft :: Windows
|
||||
Classifier: Operating System :: MacOS :: MacOS X
|
|
@ -1,465 +0,0 @@
|
|||
AUTHORS
|
||||
Changelog
|
||||
FAQ
|
||||
INSTALL
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
README
|
||||
README.rst
|
||||
THANKS
|
||||
TODO
|
||||
setup.cfg
|
||||
setup.py
|
||||
celery/__init__.py
|
||||
celery/abstract.py
|
||||
celery/actors.py
|
||||
celery/beat.py
|
||||
celery/conf.py
|
||||
celery/datastructures.py
|
||||
celery/decorators.py
|
||||
celery/exceptions.py
|
||||
celery/local.py
|
||||
celery/log.py
|
||||
celery/messaging.py
|
||||
celery/platforms.py
|
||||
celery/registry.py
|
||||
celery/result.py
|
||||
celery/routes.py
|
||||
celery/schedules.py
|
||||
celery/signals.py
|
||||
celery/states.py
|
||||
celery.egg-info/PKG-INFO
|
||||
celery.egg-info/SOURCES.txt
|
||||
celery.egg-info/dependency_links.txt
|
||||
celery.egg-info/entry_points.txt
|
||||
celery.egg-info/not-zip-safe
|
||||
celery.egg-info/requires.txt
|
||||
celery.egg-info/top_level.txt
|
||||
celery/app/__init__.py
|
||||
celery/app/abstract.py
|
||||
celery/app/amqp.py
|
||||
celery/app/annotations.py
|
||||
celery/app/base.py
|
||||
celery/app/defaults.py
|
||||
celery/app/task/__init__.py
|
||||
celery/apps/__init__.py
|
||||
celery/apps/beat.py
|
||||
celery/apps/worker.py
|
||||
celery/backends/__init__.py
|
||||
celery/backends/amqp.py
|
||||
celery/backends/base.py
|
||||
celery/backends/cache.py
|
||||
celery/backends/cassandra.py
|
||||
celery/backends/database.py
|
||||
celery/backends/mongodb.py
|
||||
celery/backends/pyredis.py
|
||||
celery/backends/redis.py
|
||||
celery/backends/tyrant.py
|
||||
celery/bin/__init__.py
|
||||
celery/bin/base.py
|
||||
celery/bin/camqadm.py
|
||||
celery/bin/celerybeat.py
|
||||
celery/bin/celeryctl.py
|
||||
celery/bin/celeryd.py
|
||||
celery/bin/celeryd_detach.py
|
||||
celery/bin/celeryd_multi.py
|
||||
celery/bin/celeryev.py
|
||||
celery/concurrency/__init__.py
|
||||
celery/concurrency/base.py
|
||||
celery/concurrency/eventlet.py
|
||||
celery/concurrency/gevent.py
|
||||
celery/concurrency/solo.py
|
||||
celery/concurrency/threads.py
|
||||
celery/concurrency/processes/__init__.py
|
||||
celery/concurrency/processes/_win.py
|
||||
celery/concurrency/processes/forking.py
|
||||
celery/concurrency/processes/pool.py
|
||||
celery/concurrency/processes/process.py
|
||||
celery/contrib/__init__.py
|
||||
celery/contrib/abortable.py
|
||||
celery/contrib/batches.py
|
||||
celery/contrib/bundles.py
|
||||
celery/contrib/migrate.py
|
||||
celery/contrib/rdb.py
|
||||
celery/db/__init__.py
|
||||
celery/db/a805d4bd.py
|
||||
celery/db/dfd042c7.py
|
||||
celery/db/models.py
|
||||
celery/db/session.py
|
||||
celery/events/__init__.py
|
||||
celery/events/cursesmon.py
|
||||
celery/events/dumper.py
|
||||
celery/events/snapshot.py
|
||||
celery/events/state.py
|
||||
celery/execute/__init__.py
|
||||
celery/execute/trace.py
|
||||
celery/loaders/__init__.py
|
||||
celery/loaders/app.py
|
||||
celery/loaders/base.py
|
||||
celery/loaders/default.py
|
||||
celery/security/__init__.py
|
||||
celery/security/certificate.py
|
||||
celery/security/key.py
|
||||
celery/security/serialization.py
|
||||
celery/task/__init__.py
|
||||
celery/task/base.py
|
||||
celery/task/chords.py
|
||||
celery/task/control.py
|
||||
celery/task/http.py
|
||||
celery/task/schedules.py
|
||||
celery/task/sets.py
|
||||
celery/tests/__init__.py
|
||||
celery/tests/compat.py
|
||||
celery/tests/config.py
|
||||
celery/tests/utils.py
|
||||
celery/tests/functional/__init__.py
|
||||
celery/tests/functional/case.py
|
||||
celery/tests/functional/tasks.py
|
||||
celery/tests/test_app/__init__.py
|
||||
celery/tests/test_app/test_actors.py
|
||||
celery/tests/test_app/test_annotations.py
|
||||
celery/tests/test_app/test_app_amqp.py
|
||||
celery/tests/test_app/test_app_defaults.py
|
||||
celery/tests/test_app/test_beat.py
|
||||
celery/tests/test_app/test_celery.py
|
||||
celery/tests/test_app/test_loaders.py
|
||||
celery/tests/test_app/test_log.py
|
||||
celery/tests/test_app/test_routes.py
|
||||
celery/tests/test_backends/__init__.py
|
||||
celery/tests/test_backends/test_amqp.py
|
||||
celery/tests/test_backends/test_base.py
|
||||
celery/tests/test_backends/test_cache.py
|
||||
celery/tests/test_backends/test_database.py
|
||||
celery/tests/test_backends/test_mongodb.py
|
||||
celery/tests/test_backends/test_pyredis_compat.py
|
||||
celery/tests/test_backends/test_redis.py
|
||||
celery/tests/test_backends/test_redis_unit.py
|
||||
celery/tests/test_backends/test_tyrant.py
|
||||
celery/tests/test_bin/__init__.py
|
||||
celery/tests/test_bin/test_celerybeat.py
|
||||
celery/tests/test_bin/test_celeryd.py
|
||||
celery/tests/test_bin/test_celeryev.py
|
||||
celery/tests/test_compat/__init__.py
|
||||
celery/tests/test_compat/test_decorators.py
|
||||
celery/tests/test_compat/test_messaging.py
|
||||
celery/tests/test_concurrency/__init__.py
|
||||
celery/tests/test_concurrency/test_concurrency_eventlet.py
|
||||
celery/tests/test_concurrency/test_concurrency_gevent.py
|
||||
celery/tests/test_concurrency/test_concurrency_processes.py
|
||||
celery/tests/test_concurrency/test_concurrency_solo.py
|
||||
celery/tests/test_concurrency/test_pool.py
|
||||
celery/tests/test_events/__init__.py
|
||||
celery/tests/test_events/test_events_cursesmon.py
|
||||
celery/tests/test_events/test_events_snapshot.py
|
||||
celery/tests/test_events/test_events_state.py
|
||||
celery/tests/test_security/__init__.py
|
||||
celery/tests/test_security/case.py
|
||||
celery/tests/test_security/test_certificate.py
|
||||
celery/tests/test_security/test_key.py
|
||||
celery/tests/test_security/test_serialization.py
|
||||
celery/tests/test_slow/__init__.py
|
||||
celery/tests/test_slow/test_buckets.py
|
||||
celery/tests/test_task/__init__.py
|
||||
celery/tests/test_task/test_chord.py
|
||||
celery/tests/test_task/test_context.py
|
||||
celery/tests/test_task/test_execute_trace.py
|
||||
celery/tests/test_task/test_registry.py
|
||||
celery/tests/test_task/test_result.py
|
||||
celery/tests/test_task/test_states.py
|
||||
celery/tests/test_task/test_task_abortable.py
|
||||
celery/tests/test_task/test_task_builtins.py
|
||||
celery/tests/test_task/test_task_control.py
|
||||
celery/tests/test_task/test_task_http.py
|
||||
celery/tests/test_task/test_task_sets.py
|
||||
celery/tests/test_utils/__init__.py
|
||||
celery/tests/test_utils/test_datastructures.py
|
||||
celery/tests/test_utils/test_pickle.py
|
||||
celery/tests/test_utils/test_serialization.py
|
||||
celery/tests/test_utils/test_timer2.py
|
||||
celery/tests/test_utils/test_utils_encoding.py
|
||||
celery/tests/test_utils/test_utils_info.py
|
||||
celery/tests/test_utils/test_utils_timeutils.py
|
||||
celery/tests/test_worker/__init__.py
|
||||
celery/tests/test_worker/test_bootsteps.py
|
||||
celery/tests/test_worker/test_worker_autoscale.py
|
||||
celery/tests/test_worker/test_worker_control.py
|
||||
celery/tests/test_worker/test_worker_heartbeat.py
|
||||
celery/tests/test_worker/test_worker_job.py
|
||||
celery/tests/test_worker/test_worker_mediator.py
|
||||
celery/tests/test_worker/test_worker_revoke.py
|
||||
celery/tests/test_worker/test_worker_state.py
|
||||
celery/utils/__init__.py
|
||||
celery/utils/compat.py
|
||||
celery/utils/encoding.py
|
||||
celery/utils/functional.py
|
||||
celery/utils/mail.py
|
||||
celery/utils/patch.py
|
||||
celery/utils/serialization.py
|
||||
celery/utils/term.py
|
||||
celery/utils/threads.py
|
||||
celery/utils/timer2.py
|
||||
celery/utils/timeutils.py
|
||||
celery/utils/dispatch/__init__.py
|
||||
celery/utils/dispatch/saferef.py
|
||||
celery/utils/dispatch/signal.py
|
||||
celery/worker/__init__.py
|
||||
celery/worker/autoreload.py
|
||||
celery/worker/autoscale.py
|
||||
celery/worker/buckets.py
|
||||
celery/worker/consumer.py
|
||||
celery/worker/control.py
|
||||
celery/worker/heartbeat.py
|
||||
celery/worker/job.py
|
||||
celery/worker/mediator.py
|
||||
celery/worker/state.py
|
||||
celery/worker/strategy.py
|
||||
contrib/bundles/generate.py
|
||||
contrib/centos/celeryd.init
|
||||
contrib/centos/celeryd.sysconfig
|
||||
contrib/debian/README.rst
|
||||
contrib/debian/init.d-deprecated/celerybeat
|
||||
contrib/debian/init.d-deprecated/celeryd
|
||||
contrib/debian/init.d-deprecated/celeryevcam
|
||||
contrib/generic-init.d/celerybeat
|
||||
contrib/generic-init.d/celeryd
|
||||
contrib/generic-init.d/celeryevcam
|
||||
contrib/logtools/find-unprocessed-tasks-debug.sh
|
||||
contrib/logtools/find-unprocessed-tasks.sh
|
||||
contrib/logtools/periodic-task-runtimes.sh
|
||||
contrib/mac/org.celeryq.celerybeat.plist
|
||||
contrib/mac/org.celeryq.celeryd.plist
|
||||
contrib/mac/org.celeryq.celerymon.plist
|
||||
contrib/mac/watch-workers.applescript
|
||||
contrib/release/attribution.py
|
||||
contrib/release/bump_version.py
|
||||
contrib/release/core-modules.txt
|
||||
contrib/release/doc4allmods
|
||||
contrib/release/flakeplus.py
|
||||
contrib/release/py3k-run-tests
|
||||
contrib/release/removepyc.sh
|
||||
contrib/release/sphinx-to-rst.py
|
||||
contrib/release/verify-reference-index.sh
|
||||
contrib/release/verify_config_reference.py
|
||||
contrib/supervisord/celerybeat.conf
|
||||
contrib/supervisord/celeryd.conf
|
||||
contrib/supervisord/supervisord.conf
|
||||
docs/Makefile
|
||||
docs/changelog.rst
|
||||
docs/community.rst
|
||||
docs/conf.py
|
||||
docs/configuration.rst
|
||||
docs/contributing.rst
|
||||
docs/faq.rst
|
||||
docs/index.rst
|
||||
docs/whatsnew-2.5.rst
|
||||
docs/.static/.keep
|
||||
docs/.templates/page.html
|
||||
docs/.templates/sidebarintro.html
|
||||
docs/.templates/sidebarlogo.html
|
||||
docs/_ext/applyxrefs.py
|
||||
docs/_ext/celerydocs.py
|
||||
docs/_ext/literals_to_xrefs.py
|
||||
docs/_theme/celery/theme.conf
|
||||
docs/_theme/celery/static/celery.css_t
|
||||
docs/cookbook/daemonizing.rst
|
||||
docs/cookbook/index.rst
|
||||
docs/cookbook/tasks.rst
|
||||
docs/getting-started/first-steps-with-celery.rst
|
||||
docs/getting-started/index.rst
|
||||
docs/getting-started/introduction.rst
|
||||
docs/getting-started/resources.rst
|
||||
docs/getting-started/brokers/beanstalk.rst
|
||||
docs/getting-started/brokers/couchdb.rst
|
||||
docs/getting-started/brokers/django.rst
|
||||
docs/getting-started/brokers/index.rst
|
||||
docs/getting-started/brokers/mongodb.rst
|
||||
docs/getting-started/brokers/rabbitmq.rst
|
||||
docs/getting-started/brokers/redis.rst
|
||||
docs/getting-started/brokers/sqlalchemy.rst
|
||||
docs/images/Celery-Overview-v4.jpg
|
||||
docs/images/Celery1.0-inside-worker.jpg
|
||||
docs/images/celery-broker-worker-nodes.jpg
|
||||
docs/images/celery-broker-worker-relationship.jpg
|
||||
docs/images/celery-icon-128.png
|
||||
docs/images/celery-icon-32.png
|
||||
docs/images/celery-icon-64.png
|
||||
docs/images/celery-worker-bindings.jpg
|
||||
docs/images/celery_128.png
|
||||
docs/images/celery_512.png
|
||||
docs/images/celery_favicon_128.png
|
||||
docs/images/celeryevshotsm.jpg
|
||||
docs/images/djangoceleryadmin2.jpg
|
||||
docs/images/favicon.ico
|
||||
docs/images/favicon.png
|
||||
docs/includes/installation.txt
|
||||
docs/includes/introduction.txt
|
||||
docs/includes/resources.txt
|
||||
docs/internals/app-overview.rst
|
||||
docs/internals/deprecation.rst
|
||||
docs/internals/guide.rst
|
||||
docs/internals/index.rst
|
||||
docs/internals/protocol.rst
|
||||
docs/internals/worker.rst
|
||||
docs/internals/reference/celery.abstract.rst
|
||||
docs/internals/reference/celery.app.abstract.rst
|
||||
docs/internals/reference/celery.app.annotations.rst
|
||||
docs/internals/reference/celery.backends.amqp.rst
|
||||
docs/internals/reference/celery.backends.base.rst
|
||||
docs/internals/reference/celery.backends.cache.rst
|
||||
docs/internals/reference/celery.backends.cassandra.rst
|
||||
docs/internals/reference/celery.backends.database.rst
|
||||
docs/internals/reference/celery.backends.mongodb.rst
|
||||
docs/internals/reference/celery.backends.redis.rst
|
||||
docs/internals/reference/celery.backends.rst
|
||||
docs/internals/reference/celery.backends.tyrant.rst
|
||||
docs/internals/reference/celery.beat.rst
|
||||
docs/internals/reference/celery.concurrency.base.rst
|
||||
docs/internals/reference/celery.concurrency.eventlet.rst
|
||||
docs/internals/reference/celery.concurrency.gevent.rst
|
||||
docs/internals/reference/celery.concurrency.processes.pool.rst
|
||||
docs/internals/reference/celery.concurrency.processes.rst
|
||||
docs/internals/reference/celery.concurrency.rst
|
||||
docs/internals/reference/celery.concurrency.solo.rst
|
||||
docs/internals/reference/celery.concurrency.threads.rst
|
||||
docs/internals/reference/celery.datastructures.rst
|
||||
docs/internals/reference/celery.db.models.rst
|
||||
docs/internals/reference/celery.db.session.rst
|
||||
docs/internals/reference/celery.events.cursesmon.rst
|
||||
docs/internals/reference/celery.events.dumper.rst
|
||||
docs/internals/reference/celery.events.snapshot.rst
|
||||
docs/internals/reference/celery.execute.trace.rst
|
||||
docs/internals/reference/celery.log.rst
|
||||
docs/internals/reference/celery.platforms.rst
|
||||
docs/internals/reference/celery.routes.rst
|
||||
docs/internals/reference/celery.security.certificate.rst
|
||||
docs/internals/reference/celery.security.key.rst
|
||||
docs/internals/reference/celery.security.serialization.rst
|
||||
docs/internals/reference/celery.utils.compat.rst
|
||||
docs/internals/reference/celery.utils.dispatch.rst
|
||||
docs/internals/reference/celery.utils.dispatch.saferef.rst
|
||||
docs/internals/reference/celery.utils.dispatch.signal.rst
|
||||
docs/internals/reference/celery.utils.encoding.rst
|
||||
docs/internals/reference/celery.utils.functional.rst
|
||||
docs/internals/reference/celery.utils.patch.rst
|
||||
docs/internals/reference/celery.utils.rst
|
||||
docs/internals/reference/celery.utils.serialization.rst
|
||||
docs/internals/reference/celery.utils.term.rst
|
||||
docs/internals/reference/celery.utils.threads.rst
|
||||
docs/internals/reference/celery.utils.timer2.rst
|
||||
docs/internals/reference/celery.utils.timeutils.rst
|
||||
docs/internals/reference/celery.worker.autoreload.rst
|
||||
docs/internals/reference/celery.worker.autoscale.rst
|
||||
docs/internals/reference/celery.worker.buckets.rst
|
||||
docs/internals/reference/celery.worker.consumer.rst
|
||||
docs/internals/reference/celery.worker.heartbeat.rst
|
||||
docs/internals/reference/celery.worker.job.rst
|
||||
docs/internals/reference/celery.worker.mediator.rst
|
||||
docs/internals/reference/celery.worker.rst
|
||||
docs/internals/reference/celery.worker.state.rst
|
||||
docs/internals/reference/celery.worker.strategy.rst
|
||||
docs/internals/reference/index.rst
|
||||
docs/reference/celery.actors.rst
|
||||
docs/reference/celery.app.amqp.rst
|
||||
docs/reference/celery.app.defaults.rst
|
||||
docs/reference/celery.app.rst
|
||||
docs/reference/celery.app.task.rst
|
||||
docs/reference/celery.apps.beat.rst
|
||||
docs/reference/celery.apps.worker.rst
|
||||
docs/reference/celery.bin.base.rst
|
||||
docs/reference/celery.bin.camqadm.rst
|
||||
docs/reference/celery.bin.celerybeat.rst
|
||||
docs/reference/celery.bin.celeryctl.rst
|
||||
docs/reference/celery.bin.celeryd.rst
|
||||
docs/reference/celery.bin.celeryd_multi.rst
|
||||
docs/reference/celery.bin.celeryev.rst
|
||||
docs/reference/celery.contrib.abortable.rst
|
||||
docs/reference/celery.contrib.batches.rst
|
||||
docs/reference/celery.contrib.migrate.rst
|
||||
docs/reference/celery.contrib.rdb.rst
|
||||
docs/reference/celery.events.rst
|
||||
docs/reference/celery.events.state.rst
|
||||
docs/reference/celery.exceptions.rst
|
||||
docs/reference/celery.loaders.app.rst
|
||||
docs/reference/celery.loaders.base.rst
|
||||
docs/reference/celery.loaders.default.rst
|
||||
docs/reference/celery.loaders.rst
|
||||
docs/reference/celery.registry.rst
|
||||
docs/reference/celery.result.rst
|
||||
docs/reference/celery.schedules.rst
|
||||
docs/reference/celery.security.rst
|
||||
docs/reference/celery.signals.rst
|
||||
docs/reference/celery.states.rst
|
||||
docs/reference/celery.task.base.rst
|
||||
docs/reference/celery.task.chords.rst
|
||||
docs/reference/celery.task.control.rst
|
||||
docs/reference/celery.task.http.rst
|
||||
docs/reference/celery.task.rst
|
||||
docs/reference/celery.task.sets.rst
|
||||
docs/reference/celery.utils.mail.rst
|
||||
docs/reference/index.rst
|
||||
docs/releases/1.0/announcement.rst
|
||||
docs/sec/CELERYSA-0001.txt
|
||||
docs/slidesource/slide-example1-result.py
|
||||
docs/slidesource/slide-example1.py
|
||||
docs/templates/readme.txt
|
||||
docs/tutorials/clickcounter.rst
|
||||
docs/tutorials/debugging.rst
|
||||
docs/tutorials/index.rst
|
||||
docs/tutorials/otherqueues.rst
|
||||
docs/userguide/executing.rst
|
||||
docs/userguide/index.rst
|
||||
docs/userguide/monitoring.rst
|
||||
docs/userguide/optimizing.rst
|
||||
docs/userguide/overview.rst
|
||||
docs/userguide/periodic-tasks.rst
|
||||
docs/userguide/remote-tasks.rst
|
||||
docs/userguide/routing.rst
|
||||
docs/userguide/security.rst
|
||||
docs/userguide/signals.rst
|
||||
docs/userguide/tasks.rst
|
||||
docs/userguide/tasksets.rst
|
||||
docs/userguide/workers.rst
|
||||
docs/userguide/concurrency/eventlet.rst
|
||||
docs/userguide/concurrency/index.rst
|
||||
examples/README.rst
|
||||
examples/app/myapp.py
|
||||
examples/celery_http_gateway/README.rst
|
||||
examples/celery_http_gateway/__init__.py
|
||||
examples/celery_http_gateway/manage.py
|
||||
examples/celery_http_gateway/settings.py
|
||||
examples/celery_http_gateway/urls.py
|
||||
examples/eventlet/README.rst
|
||||
examples/eventlet/bulk_task_producer.py
|
||||
examples/eventlet/celeryconfig.py
|
||||
examples/eventlet/tasks.py
|
||||
examples/eventlet/webcrawler.py
|
||||
examples/gevent/celeryconfig.py
|
||||
examples/gevent/tasks.py
|
||||
examples/httpexample/README.rst
|
||||
examples/httpexample/__init__.py
|
||||
examples/httpexample/manage.py
|
||||
examples/httpexample/settings.py
|
||||
examples/httpexample/urls.py
|
||||
examples/httpexample/views.py
|
||||
examples/pythonproject/demoapp/README.rst
|
||||
examples/pythonproject/demoapp/__init__.py
|
||||
examples/pythonproject/demoapp/celeryconfig.py
|
||||
examples/pythonproject/demoapp/tasks.py
|
||||
examples/pythonproject/demoapp/test.py
|
||||
examples/resultgraph/tasks.py
|
||||
funtests/setup.py
|
||||
funtests/benchmarks/bench_worker.py
|
||||
funtests/suite/__init__.py
|
||||
funtests/suite/config.py
|
||||
funtests/suite/test_basic.py
|
||||
funtests/suite/test_leak.py
|
||||
requirements/default-py3k.txt
|
||||
requirements/default.txt
|
||||
requirements/docs.txt
|
||||
requirements/pkgutils.txt
|
||||
requirements/py25.txt
|
||||
requirements/py26.txt
|
||||
requirements/security.txt
|
||||
requirements/test-py3k.txt
|
||||
requirements/test-pypy.txt
|
||||
requirements/test.txt
|
|
@ -1,11 +0,0 @@
|
|||
[console_scripts]
|
||||
celeryctl = celery.bin.celeryctl:main
|
||||
celeryd = celery.bin.celeryd:main
|
||||
camqadm = celery.bin.camqadm:main
|
||||
celeryev = celery.bin.celeryev:main
|
||||
celeryd-multi = celery.bin.celeryd_multi:main
|
||||
celerybeat = celery.bin.celerybeat:main
|
||||
|
||||
[bundle.bundles]
|
||||
celery = celery.contrib.bundles:bundles
|
||||
|
|
@ -1,406 +0,0 @@
|
|||
../celery/conf.py
|
||||
../celery/abstract.py
|
||||
../celery/states.py
|
||||
../celery/decorators.py
|
||||
../celery/local.py
|
||||
../celery/exceptions.py
|
||||
../celery/messaging.py
|
||||
../celery/schedules.py
|
||||
../celery/routes.py
|
||||
../celery/__init__.py
|
||||
../celery/platforms.py
|
||||
../celery/signals.py
|
||||
../celery/beat.py
|
||||
../celery/result.py
|
||||
../celery/registry.py
|
||||
../celery/log.py
|
||||
../celery/actors.py
|
||||
../celery/datastructures.py
|
||||
../celery/worker/mediator.py
|
||||
../celery/worker/buckets.py
|
||||
../celery/worker/state.py
|
||||
../celery/worker/heartbeat.py
|
||||
../celery/worker/strategy.py
|
||||
../celery/worker/control.py
|
||||
../celery/worker/__init__.py
|
||||
../celery/worker/job.py
|
||||
../celery/worker/consumer.py
|
||||
../celery/worker/autoscale.py
|
||||
../celery/worker/autoreload.py
|
||||
../celery/contrib/batches.py
|
||||
../celery/contrib/abortable.py
|
||||
../celery/contrib/__init__.py
|
||||
../celery/contrib/migrate.py
|
||||
../celery/contrib/rdb.py
|
||||
../celery/contrib/bundles.py
|
||||
../celery/backends/cassandra.py
|
||||
../celery/backends/cache.py
|
||||
../celery/backends/amqp.py
|
||||
../celery/backends/pyredis.py
|
||||
../celery/backends/redis.py
|
||||
../celery/backends/tyrant.py
|
||||
../celery/backends/base.py
|
||||
../celery/backends/__init__.py
|
||||
../celery/backends/database.py
|
||||
../celery/backends/mongodb.py
|
||||
../celery/utils/timer2.py
|
||||
../celery/utils/encoding.py
|
||||
../celery/utils/functional.py
|
||||
../celery/utils/mail.py
|
||||
../celery/utils/__init__.py
|
||||
../celery/utils/term.py
|
||||
../celery/utils/threads.py
|
||||
../celery/utils/compat.py
|
||||
../celery/utils/serialization.py
|
||||
../celery/utils/patch.py
|
||||
../celery/utils/timeutils.py
|
||||
../celery/events/state.py
|
||||
../celery/events/dumper.py
|
||||
../celery/events/cursesmon.py
|
||||
../celery/events/snapshot.py
|
||||
../celery/events/__init__.py
|
||||
../celery/execute/trace.py
|
||||
../celery/execute/__init__.py
|
||||
../celery/apps/worker.py
|
||||
../celery/apps/__init__.py
|
||||
../celery/apps/beat.py
|
||||
../celery/db/dfd042c7.py
|
||||
../celery/db/a805d4bd.py
|
||||
../celery/db/session.py
|
||||
../celery/db/__init__.py
|
||||
../celery/db/models.py
|
||||
../celery/bin/celeryev.py
|
||||
../celery/bin/celeryd_detach.py
|
||||
../celery/bin/camqadm.py
|
||||
../celery/bin/base.py
|
||||
../celery/bin/__init__.py
|
||||
../celery/bin/celeryd_multi.py
|
||||
../celery/bin/celerybeat.py
|
||||
../celery/bin/celeryctl.py
|
||||
../celery/bin/celeryd.py
|
||||
../celery/security/key.py
|
||||
../celery/security/certificate.py
|
||||
../celery/security/__init__.py
|
||||
../celery/security/serialization.py
|
||||
../celery/tests/config.py
|
||||
../celery/tests/utils.py
|
||||
../celery/tests/__init__.py
|
||||
../celery/tests/compat.py
|
||||
../celery/task/chords.py
|
||||
../celery/task/sets.py
|
||||
../celery/task/http.py
|
||||
../celery/task/schedules.py
|
||||
../celery/task/control.py
|
||||
../celery/task/base.py
|
||||
../celery/task/__init__.py
|
||||
../celery/concurrency/solo.py
|
||||
../celery/concurrency/gevent.py
|
||||
../celery/concurrency/base.py
|
||||
../celery/concurrency/__init__.py
|
||||
../celery/concurrency/threads.py
|
||||
../celery/concurrency/eventlet.py
|
||||
../celery/app/abstract.py
|
||||
../celery/app/amqp.py
|
||||
../celery/app/base.py
|
||||
../celery/app/__init__.py
|
||||
../celery/app/defaults.py
|
||||
../celery/app/annotations.py
|
||||
../celery/loaders/base.py
|
||||
../celery/loaders/__init__.py
|
||||
../celery/loaders/app.py
|
||||
../celery/loaders/default.py
|
||||
../celery/utils/dispatch/__init__.py
|
||||
../celery/utils/dispatch/signal.py
|
||||
../celery/utils/dispatch/saferef.py
|
||||
../celery/tests/test_utils/test_timer2.py
|
||||
../celery/tests/test_utils/test_pickle.py
|
||||
../celery/tests/test_utils/test_utils_encoding.py
|
||||
../celery/tests/test_utils/test_utils_timeutils.py
|
||||
../celery/tests/test_utils/test_datastructures.py
|
||||
../celery/tests/test_utils/test_serialization.py
|
||||
../celery/tests/test_utils/__init__.py
|
||||
../celery/tests/test_utils/test_utils_info.py
|
||||
../celery/tests/test_worker/test_worker_job.py
|
||||
../celery/tests/test_worker/test_worker_heartbeat.py
|
||||
../celery/tests/test_worker/test_worker_state.py
|
||||
../celery/tests/test_worker/test_worker_autoscale.py
|
||||
../celery/tests/test_worker/test_worker_mediator.py
|
||||
../celery/tests/test_worker/test_worker_revoke.py
|
||||
../celery/tests/test_worker/test_bootsteps.py
|
||||
../celery/tests/test_worker/__init__.py
|
||||
../celery/tests/test_worker/test_worker_control.py
|
||||
../celery/tests/test_compat/test_messaging.py
|
||||
../celery/tests/test_compat/__init__.py
|
||||
../celery/tests/test_compat/test_decorators.py
|
||||
../celery/tests/functional/case.py
|
||||
../celery/tests/functional/tasks.py
|
||||
../celery/tests/functional/__init__.py
|
||||
../celery/tests/test_backends/test_mongodb.py
|
||||
../celery/tests/test_backends/test_redis_unit.py
|
||||
../celery/tests/test_backends/test_base.py
|
||||
../celery/tests/test_backends/test_cache.py
|
||||
../celery/tests/test_backends/test_redis.py
|
||||
../celery/tests/test_backends/test_amqp.py
|
||||
../celery/tests/test_backends/test_tyrant.py
|
||||
../celery/tests/test_backends/test_database.py
|
||||
../celery/tests/test_backends/__init__.py
|
||||
../celery/tests/test_backends/test_pyredis_compat.py
|
||||
../celery/tests/test_concurrency/test_concurrency_solo.py
|
||||
../celery/tests/test_concurrency/test_concurrency_eventlet.py
|
||||
../celery/tests/test_concurrency/__init__.py
|
||||
../celery/tests/test_concurrency/test_concurrency_processes.py
|
||||
../celery/tests/test_concurrency/test_concurrency_gevent.py
|
||||
../celery/tests/test_concurrency/test_pool.py
|
||||
../celery/tests/test_events/test_events_state.py
|
||||
../celery/tests/test_events/test_events_cursesmon.py
|
||||
../celery/tests/test_events/test_events_snapshot.py
|
||||
../celery/tests/test_events/__init__.py
|
||||
../celery/tests/test_slow/test_buckets.py
|
||||
../celery/tests/test_slow/__init__.py
|
||||
../celery/tests/test_bin/test_celeryev.py
|
||||
../celery/tests/test_bin/test_celeryd.py
|
||||
../celery/tests/test_bin/__init__.py
|
||||
../celery/tests/test_bin/test_celerybeat.py
|
||||
../celery/tests/test_security/case.py
|
||||
../celery/tests/test_security/test_key.py
|
||||
../celery/tests/test_security/test_serialization.py
|
||||
../celery/tests/test_security/__init__.py
|
||||
../celery/tests/test_security/test_certificate.py
|
||||
../celery/tests/test_task/test_execute_trace.py
|
||||
../celery/tests/test_task/test_result.py
|
||||
../celery/tests/test_task/test_task_http.py
|
||||
../celery/tests/test_task/test_task_abortable.py
|
||||
../celery/tests/test_task/test_task_builtins.py
|
||||
../celery/tests/test_task/test_states.py
|
||||
../celery/tests/test_task/__init__.py
|
||||
../celery/tests/test_task/test_chord.py
|
||||
../celery/tests/test_task/test_registry.py
|
||||
../celery/tests/test_task/test_context.py
|
||||
../celery/tests/test_task/test_task_control.py
|
||||
../celery/tests/test_task/test_task_sets.py
|
||||
../celery/tests/test_app/test_app_amqp.py
|
||||
../celery/tests/test_app/test_routes.py
|
||||
../celery/tests/test_app/test_annotations.py
|
||||
../celery/tests/test_app/test_app_defaults.py
|
||||
../celery/tests/test_app/test_actors.py
|
||||
../celery/tests/test_app/__init__.py
|
||||
../celery/tests/test_app/test_loaders.py
|
||||
../celery/tests/test_app/test_log.py
|
||||
../celery/tests/test_app/test_beat.py
|
||||
../celery/tests/test_app/test_celery.py
|
||||
../celery/concurrency/processes/pool.py
|
||||
../celery/concurrency/processes/process.py
|
||||
../celery/concurrency/processes/__init__.py
|
||||
../celery/concurrency/processes/forking.py
|
||||
../celery/concurrency/processes/_win.py
|
||||
../celery/app/task/__init__.py
|
||||
../celery/conf.pyc
|
||||
../celery/abstract.pyc
|
||||
../celery/states.pyc
|
||||
../celery/decorators.pyc
|
||||
../celery/local.pyc
|
||||
../celery/exceptions.pyc
|
||||
../celery/messaging.pyc
|
||||
../celery/schedules.pyc
|
||||
../celery/routes.pyc
|
||||
../celery/__init__.pyc
|
||||
../celery/platforms.pyc
|
||||
../celery/signals.pyc
|
||||
../celery/beat.pyc
|
||||
../celery/result.pyc
|
||||
../celery/registry.pyc
|
||||
../celery/log.pyc
|
||||
../celery/actors.pyc
|
||||
../celery/datastructures.pyc
|
||||
../celery/worker/mediator.pyc
|
||||
../celery/worker/buckets.pyc
|
||||
../celery/worker/state.pyc
|
||||
../celery/worker/heartbeat.pyc
|
||||
../celery/worker/strategy.pyc
|
||||
../celery/worker/control.pyc
|
||||
../celery/worker/__init__.pyc
|
||||
../celery/worker/job.pyc
|
||||
../celery/worker/consumer.pyc
|
||||
../celery/worker/autoscale.pyc
|
||||
../celery/worker/autoreload.pyc
|
||||
../celery/contrib/batches.pyc
|
||||
../celery/contrib/abortable.pyc
|
||||
../celery/contrib/__init__.pyc
|
||||
../celery/contrib/migrate.pyc
|
||||
../celery/contrib/rdb.pyc
|
||||
../celery/contrib/bundles.pyc
|
||||
../celery/backends/cassandra.pyc
|
||||
../celery/backends/cache.pyc
|
||||
../celery/backends/amqp.pyc
|
||||
../celery/backends/pyredis.pyc
|
||||
../celery/backends/redis.pyc
|
||||
../celery/backends/tyrant.pyc
|
||||
../celery/backends/base.pyc
|
||||
../celery/backends/__init__.pyc
|
||||
../celery/backends/database.pyc
|
||||
../celery/backends/mongodb.pyc
|
||||
../celery/utils/timer2.pyc
|
||||
../celery/utils/encoding.pyc
|
||||
../celery/utils/functional.pyc
|
||||
../celery/utils/mail.pyc
|
||||
../celery/utils/__init__.pyc
|
||||
../celery/utils/term.pyc
|
||||
../celery/utils/threads.pyc
|
||||
../celery/utils/compat.pyc
|
||||
../celery/utils/serialization.pyc
|
||||
../celery/utils/patch.pyc
|
||||
../celery/utils/timeutils.pyc
|
||||
../celery/events/state.pyc
|
||||
../celery/events/dumper.pyc
|
||||
../celery/events/cursesmon.pyc
|
||||
../celery/events/snapshot.pyc
|
||||
../celery/events/__init__.pyc
|
||||
../celery/execute/trace.pyc
|
||||
../celery/execute/__init__.pyc
|
||||
../celery/apps/worker.pyc
|
||||
../celery/apps/__init__.pyc
|
||||
../celery/apps/beat.pyc
|
||||
../celery/db/dfd042c7.pyc
|
||||
../celery/db/a805d4bd.pyc
|
||||
../celery/db/session.pyc
|
||||
../celery/db/__init__.pyc
|
||||
../celery/db/models.pyc
|
||||
../celery/bin/celeryev.pyc
|
||||
../celery/bin/celeryd_detach.pyc
|
||||
../celery/bin/camqadm.pyc
|
||||
../celery/bin/base.pyc
|
||||
../celery/bin/__init__.pyc
|
||||
../celery/bin/celeryd_multi.pyc
|
||||
../celery/bin/celerybeat.pyc
|
||||
../celery/bin/celeryctl.pyc
|
||||
../celery/bin/celeryd.pyc
|
||||
../celery/security/key.pyc
|
||||
../celery/security/certificate.pyc
|
||||
../celery/security/__init__.pyc
|
||||
../celery/security/serialization.pyc
|
||||
../celery/tests/config.pyc
|
||||
../celery/tests/utils.pyc
|
||||
../celery/tests/__init__.pyc
|
||||
../celery/tests/compat.pyc
|
||||
../celery/task/chords.pyc
|
||||
../celery/task/sets.pyc
|
||||
../celery/task/http.pyc
|
||||
../celery/task/schedules.pyc
|
||||
../celery/task/control.pyc
|
||||
../celery/task/base.pyc
|
||||
../celery/task/__init__.pyc
|
||||
../celery/concurrency/solo.pyc
|
||||
../celery/concurrency/gevent.pyc
|
||||
../celery/concurrency/base.pyc
|
||||
../celery/concurrency/__init__.pyc
|
||||
../celery/concurrency/threads.pyc
|
||||
../celery/concurrency/eventlet.pyc
|
||||
../celery/app/abstract.pyc
|
||||
../celery/app/amqp.pyc
|
||||
../celery/app/base.pyc
|
||||
../celery/app/__init__.pyc
|
||||
../celery/app/defaults.pyc
|
||||
../celery/app/annotations.pyc
|
||||
../celery/loaders/base.pyc
|
||||
../celery/loaders/__init__.pyc
|
||||
../celery/loaders/app.pyc
|
||||
../celery/loaders/default.pyc
|
||||
../celery/utils/dispatch/__init__.pyc
|
||||
../celery/utils/dispatch/signal.pyc
|
||||
../celery/utils/dispatch/saferef.pyc
|
||||
../celery/tests/test_utils/test_timer2.pyc
|
||||
../celery/tests/test_utils/test_pickle.pyc
|
||||
../celery/tests/test_utils/test_utils_encoding.pyc
|
||||
../celery/tests/test_utils/test_utils_timeutils.pyc
|
||||
../celery/tests/test_utils/test_datastructures.pyc
|
||||
../celery/tests/test_utils/test_serialization.pyc
|
||||
../celery/tests/test_utils/__init__.pyc
|
||||
../celery/tests/test_utils/test_utils_info.pyc
|
||||
../celery/tests/test_worker/test_worker_job.pyc
|
||||
../celery/tests/test_worker/test_worker_heartbeat.pyc
|
||||
../celery/tests/test_worker/test_worker_state.pyc
|
||||
../celery/tests/test_worker/test_worker_autoscale.pyc
|
||||
../celery/tests/test_worker/test_worker_mediator.pyc
|
||||
../celery/tests/test_worker/test_worker_revoke.pyc
|
||||
../celery/tests/test_worker/test_bootsteps.pyc
|
||||
../celery/tests/test_worker/__init__.pyc
|
||||
../celery/tests/test_worker/test_worker_control.pyc
|
||||
../celery/tests/test_compat/test_messaging.pyc
|
||||
../celery/tests/test_compat/__init__.pyc
|
||||
../celery/tests/test_compat/test_decorators.pyc
|
||||
../celery/tests/functional/case.pyc
|
||||
../celery/tests/functional/tasks.pyc
|
||||
../celery/tests/functional/__init__.pyc
|
||||
../celery/tests/test_backends/test_mongodb.pyc
|
||||
../celery/tests/test_backends/test_redis_unit.pyc
|
||||
../celery/tests/test_backends/test_base.pyc
|
||||
../celery/tests/test_backends/test_cache.pyc
|
||||
../celery/tests/test_backends/test_redis.pyc
|
||||
../celery/tests/test_backends/test_amqp.pyc
|
||||
../celery/tests/test_backends/test_tyrant.pyc
|
||||
../celery/tests/test_backends/test_database.pyc
|
||||
../celery/tests/test_backends/__init__.pyc
|
||||
../celery/tests/test_backends/test_pyredis_compat.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_solo.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_eventlet.pyc
|
||||
../celery/tests/test_concurrency/__init__.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_processes.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_gevent.pyc
|
||||
../celery/tests/test_concurrency/test_pool.pyc
|
||||
../celery/tests/test_events/test_events_state.pyc
|
||||
../celery/tests/test_events/test_events_cursesmon.pyc
|
||||
../celery/tests/test_events/test_events_snapshot.pyc
|
||||
../celery/tests/test_events/__init__.pyc
|
||||
../celery/tests/test_slow/test_buckets.pyc
|
||||
../celery/tests/test_slow/__init__.pyc
|
||||
../celery/tests/test_bin/test_celeryev.pyc
|
||||
../celery/tests/test_bin/test_celeryd.pyc
|
||||
../celery/tests/test_bin/__init__.pyc
|
||||
../celery/tests/test_bin/test_celerybeat.pyc
|
||||
../celery/tests/test_security/case.pyc
|
||||
../celery/tests/test_security/test_key.pyc
|
||||
../celery/tests/test_security/test_serialization.pyc
|
||||
../celery/tests/test_security/__init__.pyc
|
||||
../celery/tests/test_security/test_certificate.pyc
|
||||
../celery/tests/test_task/test_execute_trace.pyc
|
||||
../celery/tests/test_task/test_result.pyc
|
||||
../celery/tests/test_task/test_task_http.pyc
|
||||
../celery/tests/test_task/test_task_abortable.pyc
|
||||
../celery/tests/test_task/test_task_builtins.pyc
|
||||
../celery/tests/test_task/test_states.pyc
|
||||
../celery/tests/test_task/__init__.pyc
|
||||
../celery/tests/test_task/test_chord.pyc
|
||||
../celery/tests/test_task/test_registry.pyc
|
||||
../celery/tests/test_task/test_context.pyc
|
||||
../celery/tests/test_task/test_task_control.pyc
|
||||
../celery/tests/test_task/test_task_sets.pyc
|
||||
../celery/tests/test_app/test_app_amqp.pyc
|
||||
../celery/tests/test_app/test_routes.pyc
|
||||
../celery/tests/test_app/test_annotations.pyc
|
||||
../celery/tests/test_app/test_app_defaults.pyc
|
||||
../celery/tests/test_app/test_actors.pyc
|
||||
../celery/tests/test_app/__init__.pyc
|
||||
../celery/tests/test_app/test_loaders.pyc
|
||||
../celery/tests/test_app/test_log.pyc
|
||||
../celery/tests/test_app/test_beat.pyc
|
||||
../celery/tests/test_app/test_celery.pyc
|
||||
../celery/concurrency/processes/pool.pyc
|
||||
../celery/concurrency/processes/process.pyc
|
||||
../celery/concurrency/processes/__init__.pyc
|
||||
../celery/concurrency/processes/forking.pyc
|
||||
../celery/concurrency/processes/_win.pyc
|
||||
../celery/app/task/__init__.pyc
|
||||
./
|
||||
top_level.txt
|
||||
SOURCES.txt
|
||||
not-zip-safe
|
||||
entry_points.txt
|
||||
PKG-INFO
|
||||
requires.txt
|
||||
dependency_links.txt
|
||||
../../../bin/celeryctl
|
||||
../../../bin/celeryd
|
||||
../../../bin/camqadm
|
||||
../../../bin/celeryev
|
||||
../../../bin/celeryd-multi
|
||||
../../../bin/celerybeat
|
|
@ -1,5 +0,0 @@
|
|||
importlib
|
||||
anyjson>=0.3.1
|
||||
kombu>=2.1.1,<3.0
|
||||
python-dateutil>=1.5.0,<2.0.0
|
||||
ordereddict
|
|
@ -1 +0,0 @@
|
|||
celery
|
|
@ -1,365 +0,0 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: celery
|
||||
Version: 2.5.5
|
||||
Summary: Distributed Task Queue
|
||||
Home-page: http://celeryproject.org
|
||||
Author: Ask Solem
|
||||
Author-email: ask@celeryproject.org
|
||||
License: BSD
|
||||
Description: =================================
|
||||
celery - Distributed Task Queue
|
||||
=================================
|
||||
|
||||
.. image:: http://cloud.github.com/downloads/ask/celery/celery_128.png
|
||||
|
||||
:Version: 2.5.5
|
||||
:Web: http://celeryproject.org/
|
||||
:Download: http://pypi.python.org/pypi/celery/
|
||||
:Source: http://github.com/celery/celery/
|
||||
:Keywords: task queue, job queue, asynchronous, rabbitmq, amqp, redis,
|
||||
python, webhooks, queue, distributed
|
||||
|
||||
--
|
||||
|
||||
Celery is an open source asynchronous task queue/job queue based on
|
||||
distributed message passing.
|
||||
|
||||
It is focused on real-time operation, but supports scheduling as well.
|
||||
|
||||
The execution units, called tasks, are executed concurrently on one or
|
||||
more worker nodes using multiprocessing, `Eventlet`_ or `gevent`_. Tasks can
|
||||
execute asynchronously (in the background) or synchronously
|
||||
(wait until ready).
|
||||
|
||||
Celery is used in production systems to process millions of tasks every hour.
|
||||
|
||||
Celery is written in Python, but the protocol can be implemented in any
|
||||
language. It can also `operate with other languages using webhooks`_.
|
||||
There's also `RCelery`_ for the Ruby programming language, and a `PHP client`_.
|
||||
|
||||
The recommended message broker is `RabbitMQ`_, but support for
|
||||
`Redis`_, `MongoDB`_, `Beanstalk`_, `Amazon SQS`_, `CouchDB`_ and
|
||||
databases (using `SQLAlchemy`_ or the `Django ORM`_) is also available.
|
||||
|
||||
Celery is easy to integrate with web frameworks, some of which even have
|
||||
integration packages:
|
||||
|
||||
+-----------------+------------------------+
|
||||
| `Django`_ | `django-celery`_ |
|
||||
+-----------------+------------------------+
|
||||
| `Pyramid`_ | `pyramid_celery`_ |
|
||||
+-----------------+------------------------+
|
||||
| `Pylons`_ | `celery-pylons`_ |
|
||||
+-----------------+------------------------+
|
||||
| `Flask`_ | `flask-celery`_ |
|
||||
+-----------------+------------------------+
|
||||
| `web2py`_ | `web2py-celery`_ |
|
||||
+-----------------+------------------------+
|
||||
|
||||
.. _`RCelery`: http://leapfrogdevelopment.github.com/rcelery/
|
||||
.. _`PHP client`: https://github.com/gjedeer/celery-php
|
||||
.. _`RabbitMQ`: http://www.rabbitmq.com/
|
||||
.. _`Redis`: http://code.google.com/p/redis/
|
||||
.. _`SQLAlchemy`: http://www.sqlalchemy.org/
|
||||
.. _`Django`: http://djangoproject.com/
|
||||
.. _`Django ORM`: http://djangoproject.com/
|
||||
.. _`Eventlet`: http://eventlet.net/
|
||||
.. _`gevent`: http://gevent.org/
|
||||
.. _`Beanstalk`: http://kr.github.com/beanstalkd/
|
||||
.. _`MongoDB`: http://mongodb.org/
|
||||
.. _`CouchDB`: http://couchdb.apache.org/
|
||||
.. _`Amazon SQS`: http://aws.amazon.com/sqs/
|
||||
.. _`Pylons`: http://pylonshq.com/
|
||||
.. _`Flask`: http://flask.pocoo.org/
|
||||
.. _`web2py`: http://web2py.com/
|
||||
.. _`Pyramid`: http://docs.pylonsproject.org/en/latest/docs/pyramid.html
|
||||
.. _`pyramid_celery`: http://pypi.python.org/pypi/pyramid_celery/
|
||||
.. _`django-celery`: http://pypi.python.org/pypi/django-celery
|
||||
.. _`celery-pylons`: http://pypi.python.org/pypi/celery-pylons
|
||||
.. _`flask-celery`: http://github.com/celery/flask-celery/
|
||||
.. _`web2py-celery`: http://code.google.com/p/web2py-celery/
|
||||
.. _`operate with other languages using webhooks`:
|
||||
http://celery.github.com/celery/userguide/remote-tasks.html
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
This is a high level overview of the architecture.
|
||||
|
||||
.. image:: http://cloud.github.com/downloads/ask/celery/Celery-Overview-v4.jpg
|
||||
|
||||
The broker delivers tasks to the worker nodes.
|
||||
A worker node is a networked machine running `celeryd`. This can be one or
|
||||
more machines depending on the workload.
|
||||
|
||||
The result of the task can be stored for later retrieval (called its
|
||||
"tombstone").
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
You probably want to see some code by now, so here's an example task
|
||||
adding two numbers:
|
||||
::
|
||||
|
||||
from celery.task import task
|
||||
|
||||
@task
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
You can execute the task in the background, or wait for it to finish::
|
||||
|
||||
>>> result = add.delay(4, 4)
|
||||
>>> result.wait() # wait for and return the result
|
||||
8
|
||||
|
||||
Simple!
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Messaging | Supported brokers include `RabbitMQ`_, `Redis`_, |
|
||||
| | `Beanstalk`_, `MongoDB`_, `CouchDB`_, and popular |
|
||||
| | SQL databases. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Fault-tolerant | Excellent configurable error recovery when using |
|
||||
| | `RabbitMQ`, ensures your tasks are never lost. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Distributed | Runs on one or more machines. Supports |
|
||||
| | broker `clustering`_ and `HA`_ when used in |
|
||||
| | combination with `RabbitMQ`_. You can set up new |
|
||||
| | workers without central configuration (e.g. use |
|
||||
| | your grandma's laptop to help if the queue is |
|
||||
| | temporarily congested). |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Concurrency | Concurrency is achieved by using multiprocessing, |
|
||||
| | `Eventlet`_, `gevent` or a mix of these. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Scheduling | Supports recurring tasks like cron, or specifying |
|
||||
| | an exact date or countdown for when after the task |
|
||||
| | should be executed. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Latency | Low latency means you are able to execute tasks |
|
||||
| | *while the user is waiting*. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Return Values | Task return values can be saved to the selected |
|
||||
| | result store backend. You can wait for the result, |
|
||||
| | retrieve it later, or ignore it. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Result Stores | Database, `MongoDB`_, `Redis`_, |
|
||||
| | `Cassandra`, or `AMQP`_ (message notification). |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Webhooks | Your tasks can also be HTTP callbacks, enabling |
|
||||
| | cross-language communication. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Rate limiting | Supports rate limiting by using the token bucket |
|
||||
| | algorithm, which accounts for bursts of traffic. |
|
||||
| | Rate limits can be set for each task type, or |
|
||||
| | globally for all. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Routing | Using AMQP's flexible routing model you can route |
|
||||
| | tasks to different workers, or select different |
|
||||
| | message topologies, by configuration or even at |
|
||||
| | runtime. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Remote-control | Worker nodes can be controlled from remote by |
|
||||
| | using broadcast messaging. A range of built-in |
|
||||
| | commands exist in addition to the ability to |
|
||||
| | easily define your own. (AMQP/Redis only) |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Monitoring | You can capture everything happening with the |
|
||||
| | workers in real-time by subscribing to events. |
|
||||
| | A real-time web monitor is in development. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Serialization | Supports Pickle, JSON, YAML, or easily defined |
|
||||
| | custom schemes. One task invocation can have a |
|
||||
| | different scheme than another. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Tracebacks | Errors and tracebacks are stored and can be |
|
||||
| | investigated after the fact. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| UUID | Every task has an UUID (Universally Unique |
|
||||
| | Identifier), which is the task id used to query |
|
||||
| | task status and return value. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Retries | Tasks can be retried if they fail, with |
|
||||
| | configurable maximum number of retries, and delays |
|
||||
| | between each retry. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Task Sets | A Task set is a task consisting of several |
|
||||
| | sub-tasks. You can find out how many, or if all |
|
||||
| | of the sub-tasks has been executed, and even |
|
||||
| | retrieve the results in order. Progress bars, |
|
||||
| | anyone? |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Made for Web | You can query status and results via URLs, |
|
||||
| | enabling the ability to poll task status using |
|
||||
| | Ajax. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
| Error Emails | Can be configured to send emails to the |
|
||||
| | administrators when tasks fails. |
|
||||
+-----------------+----------------------------------------------------+
|
||||
|
||||
|
||||
.. _`clustering`: http://www.rabbitmq.com/clustering.html
|
||||
.. _`HA`: http://www.rabbitmq.com/pacemaker.html
|
||||
.. _`AMQP`: http://www.amqp.org/
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
Documentation for the production version can be found here:
|
||||
|
||||
http://docs.celeryproject.org/en/latest
|
||||
|
||||
and the documentation for the development version can be found here:
|
||||
|
||||
http://celery.github.com/celery/
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
You can install Celery either via the Python Package Index (PyPI)
|
||||
or from source.
|
||||
|
||||
To install using `pip`,::
|
||||
|
||||
$ pip install -U Celery
|
||||
|
||||
To install using `easy_install`,::
|
||||
|
||||
$ easy_install -U Celery
|
||||
|
||||
Bundles
|
||||
-------
|
||||
|
||||
Celery also defines a group of bundles that can be used
|
||||
to install Celery and the dependencies for a given feature.
|
||||
|
||||
The following bundles are available:
|
||||
|
||||
:`celery-with-redis`_:
|
||||
for using Redis as a broker.
|
||||
|
||||
:`celery-with-mongodb`_:
|
||||
for using MongoDB as a broker.
|
||||
|
||||
:`django-celery-with-redis`_:
|
||||
for Django, and using Redis as a broker.
|
||||
|
||||
:`django-celery-with-mongodb`_:
|
||||
for Django, and using MongoDB as a broker.
|
||||
|
||||
:`bundle-celery`_:
|
||||
convenience bundle installing *Celery* and related packages.
|
||||
|
||||
.. _`celery-with-redis`:
|
||||
http://pypi.python.org/pypi/celery-with-redis/
|
||||
.. _`celery-with-mongodb`:
|
||||
http://pypi.python.org/pypi/celery-with-mongdb/
|
||||
.. _`django-celery-with-redis`:
|
||||
http://pypi.python.org/pypi/django-celery-with-redis/
|
||||
.. _`django-celery-with-mongodb`:
|
||||
http://pypi.python.org/pypi/django-celery-with-mongdb/
|
||||
.. _`bundle-celery`:
|
||||
http://pypi.python.org/pypi/bundle-celery/
|
||||
|
||||
Downloading and installing from source
|
||||
--------------------------------------
|
||||
|
||||
Download the latest version of Celery from
|
||||
http://pypi.python.org/pypi/celery/
|
||||
|
||||
You can install it by doing the following,::
|
||||
|
||||
$ tar xvfz celery-0.0.0.tar.gz
|
||||
$ cd celery-0.0.0
|
||||
$ python setup.py build
|
||||
# python setup.py install # as root
|
||||
|
||||
Using the development version
|
||||
-----------------------------
|
||||
|
||||
You can clone the repository by doing the following::
|
||||
|
||||
$ git clone git://github.com/celery/celery.git
|
||||
|
||||
|
||||
Getting Help
|
||||
============
|
||||
|
||||
|
||||
Mailing list
|
||||
------------
|
||||
|
||||
For discussions about the usage, development, and future of celery,
|
||||
please join the `celery-users`_ mailing list.
|
||||
|
||||
.. _`celery-users`: http://groups.google.com/group/celery-users/
|
||||
|
||||
|
||||
IRC
|
||||
---
|
||||
|
||||
Come chat with us on IRC. The **#celery** channel is located at the `Freenode`_
|
||||
network.
|
||||
|
||||
.. _`Freenode`: http://freenode.net
|
||||
|
||||
|
||||
Bug tracker
|
||||
===========
|
||||
|
||||
If you have any suggestions, bug reports or annoyances please report them
|
||||
to our issue tracker at http://github.com/celery/celery/issues/
|
||||
|
||||
Wiki
|
||||
====
|
||||
|
||||
http://wiki.github.com/celery/celery/
|
||||
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
Development of `celery` happens at Github: http://github.com/celery/celery
|
||||
|
||||
You are highly encouraged to participate in the development
|
||||
of `celery`. If you don't like Github (for some reason) you're welcome
|
||||
to send regular patches.
|
||||
|
||||
Be sure to also read the `Contributing to Celery`_ section in the
|
||||
documentation.
|
||||
|
||||
.. _`Contributing to Celery`: http://celery.github.com/celery/contributing.html
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
This software is licensed under the `New BSD License`. See the ``LICENSE``
|
||||
file in the top distribution directory for the full license text.
|
||||
|
||||
.. # vim: syntax=rst expandtab tabstop=4 shiftwidth=4 shiftround
|
||||
|
||||
|
||||
Platform: any
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Topic :: System :: Distributed Computing
|
||||
Classifier: Topic :: Software Development :: Object Brokering
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.5
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.2
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Programming Language :: Python :: Implementation :: Jython
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Operating System :: Microsoft :: Windows
|
||||
Classifier: Operating System :: MacOS :: MacOS X
|
|
@ -1,468 +0,0 @@
|
|||
AUTHORS
|
||||
Changelog
|
||||
FAQ
|
||||
INSTALL
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
README
|
||||
README.rst
|
||||
THANKS
|
||||
TODO
|
||||
setup.cfg
|
||||
setup.py
|
||||
celery/__init__.py
|
||||
celery/abstract.py
|
||||
celery/actors.py
|
||||
celery/beat.py
|
||||
celery/conf.py
|
||||
celery/datastructures.py
|
||||
celery/decorators.py
|
||||
celery/exceptions.py
|
||||
celery/local.py
|
||||
celery/log.py
|
||||
celery/messaging.py
|
||||
celery/platforms.py
|
||||
celery/registry.py
|
||||
celery/result.py
|
||||
celery/routes.py
|
||||
celery/schedules.py
|
||||
celery/signals.py
|
||||
celery/states.py
|
||||
celery.egg-info/PKG-INFO
|
||||
celery.egg-info/SOURCES.txt
|
||||
celery.egg-info/dependency_links.txt
|
||||
celery.egg-info/entry_points.txt
|
||||
celery.egg-info/not-zip-safe
|
||||
celery.egg-info/requires.txt
|
||||
celery.egg-info/top_level.txt
|
||||
celery/app/__init__.py
|
||||
celery/app/abstract.py
|
||||
celery/app/amqp.py
|
||||
celery/app/annotations.py
|
||||
celery/app/base.py
|
||||
celery/app/defaults.py
|
||||
celery/app/task/__init__.py
|
||||
celery/apps/__init__.py
|
||||
celery/apps/beat.py
|
||||
celery/apps/worker.py
|
||||
celery/backends/__init__.py
|
||||
celery/backends/amqp.py
|
||||
celery/backends/base.py
|
||||
celery/backends/cache.py
|
||||
celery/backends/cassandra.py
|
||||
celery/backends/database.py
|
||||
celery/backends/mongodb.py
|
||||
celery/backends/pyredis.py
|
||||
celery/backends/redis.py
|
||||
celery/backends/tyrant.py
|
||||
celery/bin/__init__.py
|
||||
celery/bin/base.py
|
||||
celery/bin/camqadm.py
|
||||
celery/bin/celerybeat.py
|
||||
celery/bin/celeryctl.py
|
||||
celery/bin/celeryd.py
|
||||
celery/bin/celeryd_detach.py
|
||||
celery/bin/celeryd_multi.py
|
||||
celery/bin/celeryev.py
|
||||
celery/concurrency/__init__.py
|
||||
celery/concurrency/base.py
|
||||
celery/concurrency/eventlet.py
|
||||
celery/concurrency/gevent.py
|
||||
celery/concurrency/solo.py
|
||||
celery/concurrency/threads.py
|
||||
celery/concurrency/processes/__init__.py
|
||||
celery/concurrency/processes/_win.py
|
||||
celery/concurrency/processes/forking.py
|
||||
celery/concurrency/processes/pool.py
|
||||
celery/concurrency/processes/process.py
|
||||
celery/contrib/__init__.py
|
||||
celery/contrib/abortable.py
|
||||
celery/contrib/batches.py
|
||||
celery/contrib/bundles.py
|
||||
celery/contrib/migrate.py
|
||||
celery/contrib/rdb.py
|
||||
celery/db/__init__.py
|
||||
celery/db/a805d4bd.py
|
||||
celery/db/dfd042c7.py
|
||||
celery/db/models.py
|
||||
celery/db/session.py
|
||||
celery/events/__init__.py
|
||||
celery/events/cursesmon.py
|
||||
celery/events/dumper.py
|
||||
celery/events/snapshot.py
|
||||
celery/events/state.py
|
||||
celery/execute/__init__.py
|
||||
celery/execute/trace.py
|
||||
celery/loaders/__init__.py
|
||||
celery/loaders/app.py
|
||||
celery/loaders/base.py
|
||||
celery/loaders/default.py
|
||||
celery/security/__init__.py
|
||||
celery/security/certificate.py
|
||||
celery/security/key.py
|
||||
celery/security/serialization.py
|
||||
celery/task/__init__.py
|
||||
celery/task/base.py
|
||||
celery/task/chords.py
|
||||
celery/task/control.py
|
||||
celery/task/http.py
|
||||
celery/task/schedules.py
|
||||
celery/task/sets.py
|
||||
celery/tests/__init__.py
|
||||
celery/tests/compat.py
|
||||
celery/tests/config.py
|
||||
celery/tests/utils.py
|
||||
celery/tests/functional/__init__.py
|
||||
celery/tests/functional/case.py
|
||||
celery/tests/functional/tasks.py
|
||||
celery/tests/test_app/__init__.py
|
||||
celery/tests/test_app/test_actors.py
|
||||
celery/tests/test_app/test_annotations.py
|
||||
celery/tests/test_app/test_app_amqp.py
|
||||
celery/tests/test_app/test_app_defaults.py
|
||||
celery/tests/test_app/test_beat.py
|
||||
celery/tests/test_app/test_celery.py
|
||||
celery/tests/test_app/test_loaders.py
|
||||
celery/tests/test_app/test_log.py
|
||||
celery/tests/test_app/test_routes.py
|
||||
celery/tests/test_backends/__init__.py
|
||||
celery/tests/test_backends/test_amqp.py
|
||||
celery/tests/test_backends/test_base.py
|
||||
celery/tests/test_backends/test_cache.py
|
||||
celery/tests/test_backends/test_database.py
|
||||
celery/tests/test_backends/test_mongodb.py
|
||||
celery/tests/test_backends/test_pyredis_compat.py
|
||||
celery/tests/test_backends/test_redis.py
|
||||
celery/tests/test_backends/test_redis_unit.py
|
||||
celery/tests/test_backends/test_tyrant.py
|
||||
celery/tests/test_bin/__init__.py
|
||||
celery/tests/test_bin/test_celerybeat.py
|
||||
celery/tests/test_bin/test_celeryd.py
|
||||
celery/tests/test_bin/test_celeryev.py
|
||||
celery/tests/test_compat/__init__.py
|
||||
celery/tests/test_compat/test_decorators.py
|
||||
celery/tests/test_compat/test_messaging.py
|
||||
celery/tests/test_concurrency/__init__.py
|
||||
celery/tests/test_concurrency/test_concurrency_eventlet.py
|
||||
celery/tests/test_concurrency/test_concurrency_gevent.py
|
||||
celery/tests/test_concurrency/test_concurrency_processes.py
|
||||
celery/tests/test_concurrency/test_concurrency_solo.py
|
||||
celery/tests/test_concurrency/test_pool.py
|
||||
celery/tests/test_events/__init__.py
|
||||
celery/tests/test_events/test_events_cursesmon.py
|
||||
celery/tests/test_events/test_events_snapshot.py
|
||||
celery/tests/test_events/test_events_state.py
|
||||
celery/tests/test_security/__init__.py
|
||||
celery/tests/test_security/case.py
|
||||
celery/tests/test_security/test_certificate.py
|
||||
celery/tests/test_security/test_key.py
|
||||
celery/tests/test_security/test_serialization.py
|
||||
celery/tests/test_slow/__init__.py
|
||||
celery/tests/test_slow/test_buckets.py
|
||||
celery/tests/test_task/__init__.py
|
||||
celery/tests/test_task/test_chord.py
|
||||
celery/tests/test_task/test_context.py
|
||||
celery/tests/test_task/test_execute_trace.py
|
||||
celery/tests/test_task/test_registry.py
|
||||
celery/tests/test_task/test_result.py
|
||||
celery/tests/test_task/test_states.py
|
||||
celery/tests/test_task/test_task_abortable.py
|
||||
celery/tests/test_task/test_task_builtins.py
|
||||
celery/tests/test_task/test_task_control.py
|
||||
celery/tests/test_task/test_task_http.py
|
||||
celery/tests/test_task/test_task_sets.py
|
||||
celery/tests/test_utils/__init__.py
|
||||
celery/tests/test_utils/test_datastructures.py
|
||||
celery/tests/test_utils/test_pickle.py
|
||||
celery/tests/test_utils/test_serialization.py
|
||||
celery/tests/test_utils/test_timer2.py
|
||||
celery/tests/test_utils/test_utils_encoding.py
|
||||
celery/tests/test_utils/test_utils_info.py
|
||||
celery/tests/test_utils/test_utils_timeutils.py
|
||||
celery/tests/test_worker/__init__.py
|
||||
celery/tests/test_worker/test_bootsteps.py
|
||||
celery/tests/test_worker/test_worker_autoscale.py
|
||||
celery/tests/test_worker/test_worker_control.py
|
||||
celery/tests/test_worker/test_worker_heartbeat.py
|
||||
celery/tests/test_worker/test_worker_job.py
|
||||
celery/tests/test_worker/test_worker_mediator.py
|
||||
celery/tests/test_worker/test_worker_revoke.py
|
||||
celery/tests/test_worker/test_worker_state.py
|
||||
celery/utils/__init__.py
|
||||
celery/utils/compat.py
|
||||
celery/utils/encoding.py
|
||||
celery/utils/functional.py
|
||||
celery/utils/mail.py
|
||||
celery/utils/patch.py
|
||||
celery/utils/serialization.py
|
||||
celery/utils/term.py
|
||||
celery/utils/threads.py
|
||||
celery/utils/timer2.py
|
||||
celery/utils/timeutils.py
|
||||
celery/utils/dispatch/__init__.py
|
||||
celery/utils/dispatch/saferef.py
|
||||
celery/utils/dispatch/signal.py
|
||||
celery/worker/__init__.py
|
||||
celery/worker/autoreload.py
|
||||
celery/worker/autoscale.py
|
||||
celery/worker/buckets.py
|
||||
celery/worker/consumer.py
|
||||
celery/worker/control.py
|
||||
celery/worker/heartbeat.py
|
||||
celery/worker/job.py
|
||||
celery/worker/mediator.py
|
||||
celery/worker/state.py
|
||||
celery/worker/strategy.py
|
||||
contrib/bundles/generate.py
|
||||
contrib/centos/celeryd.init
|
||||
contrib/centos/celeryd.sysconfig
|
||||
contrib/debian/README.rst
|
||||
contrib/debian/init.d-deprecated/celerybeat
|
||||
contrib/debian/init.d-deprecated/celeryd
|
||||
contrib/debian/init.d-deprecated/celeryevcam
|
||||
contrib/generic-init.d/celerybeat
|
||||
contrib/generic-init.d/celeryd
|
||||
contrib/generic-init.d/celeryevcam
|
||||
contrib/logtools/find-unprocessed-tasks-debug.sh
|
||||
contrib/logtools/find-unprocessed-tasks.sh
|
||||
contrib/logtools/periodic-task-runtimes.sh
|
||||
contrib/mac/org.celeryq.celerybeat.plist
|
||||
contrib/mac/org.celeryq.celeryd.plist
|
||||
contrib/mac/org.celeryq.celerymon.plist
|
||||
contrib/mac/watch-workers.applescript
|
||||
contrib/release/attribution.py
|
||||
contrib/release/bump_version.py
|
||||
contrib/release/core-modules.txt
|
||||
contrib/release/doc4allmods
|
||||
contrib/release/py3k-run-tests
|
||||
contrib/release/removepyc.sh
|
||||
contrib/release/sphinx-to-rst.py
|
||||
contrib/release/verify-reference-index.sh
|
||||
contrib/release/verify_config_reference.py
|
||||
contrib/supervisord/celerybeat.conf
|
||||
contrib/supervisord/celeryd.conf
|
||||
contrib/supervisord/supervisord.conf
|
||||
docs/Makefile
|
||||
docs/changelog.rst
|
||||
docs/community.rst
|
||||
docs/conf.py
|
||||
docs/configuration.rst
|
||||
docs/contributing.rst
|
||||
docs/faq.rst
|
||||
docs/index.rst
|
||||
docs/whatsnew-2.5.rst
|
||||
docs/.static/.keep
|
||||
docs/.templates/page.html
|
||||
docs/.templates/sidebarintro.html
|
||||
docs/.templates/sidebarlogo.html
|
||||
docs/_ext/applyxrefs.py
|
||||
docs/_ext/celerydocs.py
|
||||
docs/_ext/literals_to_xrefs.py
|
||||
docs/_theme/celery/theme.conf
|
||||
docs/_theme/celery/static/celery.css_t
|
||||
docs/cookbook/daemonizing.rst
|
||||
docs/cookbook/index.rst
|
||||
docs/cookbook/tasks.rst
|
||||
docs/django/first-steps-with-django.rst
|
||||
docs/django/index.rst
|
||||
docs/django/unit-testing.rst
|
||||
docs/getting-started/first-steps-with-celery.rst
|
||||
docs/getting-started/index.rst
|
||||
docs/getting-started/introduction.rst
|
||||
docs/getting-started/resources.rst
|
||||
docs/getting-started/brokers/beanstalk.rst
|
||||
docs/getting-started/brokers/couchdb.rst
|
||||
docs/getting-started/brokers/django.rst
|
||||
docs/getting-started/brokers/index.rst
|
||||
docs/getting-started/brokers/mongodb.rst
|
||||
docs/getting-started/brokers/rabbitmq.rst
|
||||
docs/getting-started/brokers/redis.rst
|
||||
docs/getting-started/brokers/sqlalchemy.rst
|
||||
docs/images/Celery-Overview-v4.jpg
|
||||
docs/images/Celery1.0-inside-worker.jpg
|
||||
docs/images/celery-broker-worker-nodes.jpg
|
||||
docs/images/celery-broker-worker-relationship.jpg
|
||||
docs/images/celery-icon-128.png
|
||||
docs/images/celery-icon-32.png
|
||||
docs/images/celery-icon-64.png
|
||||
docs/images/celery-worker-bindings.jpg
|
||||
docs/images/celery_128.png
|
||||
docs/images/celery_512.png
|
||||
docs/images/celery_favicon_128.png
|
||||
docs/images/celeryevshotsm.jpg
|
||||
docs/images/djangoceleryadmin2.jpg
|
||||
docs/images/favicon.ico
|
||||
docs/images/favicon.png
|
||||
docs/includes/installation.txt
|
||||
docs/includes/introduction.txt
|
||||
docs/includes/resources.txt
|
||||
docs/internals/app-overview.rst
|
||||
docs/internals/deprecation.rst
|
||||
docs/internals/guide.rst
|
||||
docs/internals/index.rst
|
||||
docs/internals/protocol.rst
|
||||
docs/internals/worker.rst
|
||||
docs/internals/reference/celery.abstract.rst
|
||||
docs/internals/reference/celery.app.abstract.rst
|
||||
docs/internals/reference/celery.app.annotations.rst
|
||||
docs/internals/reference/celery.backends.amqp.rst
|
||||
docs/internals/reference/celery.backends.base.rst
|
||||
docs/internals/reference/celery.backends.cache.rst
|
||||
docs/internals/reference/celery.backends.cassandra.rst
|
||||
docs/internals/reference/celery.backends.database.rst
|
||||
docs/internals/reference/celery.backends.mongodb.rst
|
||||
docs/internals/reference/celery.backends.redis.rst
|
||||
docs/internals/reference/celery.backends.rst
|
||||
docs/internals/reference/celery.backends.tyrant.rst
|
||||
docs/internals/reference/celery.beat.rst
|
||||
docs/internals/reference/celery.concurrency.base.rst
|
||||
docs/internals/reference/celery.concurrency.eventlet.rst
|
||||
docs/internals/reference/celery.concurrency.gevent.rst
|
||||
docs/internals/reference/celery.concurrency.processes.pool.rst
|
||||
docs/internals/reference/celery.concurrency.processes.rst
|
||||
docs/internals/reference/celery.concurrency.rst
|
||||
docs/internals/reference/celery.concurrency.solo.rst
|
||||
docs/internals/reference/celery.concurrency.threads.rst
|
||||
docs/internals/reference/celery.datastructures.rst
|
||||
docs/internals/reference/celery.db.models.rst
|
||||
docs/internals/reference/celery.db.session.rst
|
||||
docs/internals/reference/celery.events.cursesmon.rst
|
||||
docs/internals/reference/celery.events.dumper.rst
|
||||
docs/internals/reference/celery.events.snapshot.rst
|
||||
docs/internals/reference/celery.execute.trace.rst
|
||||
docs/internals/reference/celery.log.rst
|
||||
docs/internals/reference/celery.platforms.rst
|
||||
docs/internals/reference/celery.routes.rst
|
||||
docs/internals/reference/celery.security.certificate.rst
|
||||
docs/internals/reference/celery.security.key.rst
|
||||
docs/internals/reference/celery.security.serialization.rst
|
||||
docs/internals/reference/celery.utils.compat.rst
|
||||
docs/internals/reference/celery.utils.dispatch.rst
|
||||
docs/internals/reference/celery.utils.dispatch.saferef.rst
|
||||
docs/internals/reference/celery.utils.dispatch.signal.rst
|
||||
docs/internals/reference/celery.utils.encoding.rst
|
||||
docs/internals/reference/celery.utils.functional.rst
|
||||
docs/internals/reference/celery.utils.patch.rst
|
||||
docs/internals/reference/celery.utils.rst
|
||||
docs/internals/reference/celery.utils.serialization.rst
|
||||
docs/internals/reference/celery.utils.term.rst
|
||||
docs/internals/reference/celery.utils.threads.rst
|
||||
docs/internals/reference/celery.utils.timer2.rst
|
||||
docs/internals/reference/celery.utils.timeutils.rst
|
||||
docs/internals/reference/celery.worker.autoreload.rst
|
||||
docs/internals/reference/celery.worker.autoscale.rst
|
||||
docs/internals/reference/celery.worker.buckets.rst
|
||||
docs/internals/reference/celery.worker.consumer.rst
|
||||
docs/internals/reference/celery.worker.heartbeat.rst
|
||||
docs/internals/reference/celery.worker.job.rst
|
||||
docs/internals/reference/celery.worker.mediator.rst
|
||||
docs/internals/reference/celery.worker.rst
|
||||
docs/internals/reference/celery.worker.state.rst
|
||||
docs/internals/reference/celery.worker.strategy.rst
|
||||
docs/internals/reference/index.rst
|
||||
docs/reference/celery.actors.rst
|
||||
docs/reference/celery.app.amqp.rst
|
||||
docs/reference/celery.app.defaults.rst
|
||||
docs/reference/celery.app.rst
|
||||
docs/reference/celery.app.task.rst
|
||||
docs/reference/celery.apps.beat.rst
|
||||
docs/reference/celery.apps.worker.rst
|
||||
docs/reference/celery.bin.base.rst
|
||||
docs/reference/celery.bin.camqadm.rst
|
||||
docs/reference/celery.bin.celerybeat.rst
|
||||
docs/reference/celery.bin.celeryctl.rst
|
||||
docs/reference/celery.bin.celeryd.rst
|
||||
docs/reference/celery.bin.celeryd_multi.rst
|
||||
docs/reference/celery.bin.celeryev.rst
|
||||
docs/reference/celery.contrib.abortable.rst
|
||||
docs/reference/celery.contrib.batches.rst
|
||||
docs/reference/celery.contrib.migrate.rst
|
||||
docs/reference/celery.contrib.rdb.rst
|
||||
docs/reference/celery.events.rst
|
||||
docs/reference/celery.events.state.rst
|
||||
docs/reference/celery.exceptions.rst
|
||||
docs/reference/celery.loaders.app.rst
|
||||
docs/reference/celery.loaders.base.rst
|
||||
docs/reference/celery.loaders.default.rst
|
||||
docs/reference/celery.loaders.rst
|
||||
docs/reference/celery.registry.rst
|
||||
docs/reference/celery.result.rst
|
||||
docs/reference/celery.schedules.rst
|
||||
docs/reference/celery.security.rst
|
||||
docs/reference/celery.signals.rst
|
||||
docs/reference/celery.states.rst
|
||||
docs/reference/celery.task.base.rst
|
||||
docs/reference/celery.task.chords.rst
|
||||
docs/reference/celery.task.control.rst
|
||||
docs/reference/celery.task.http.rst
|
||||
docs/reference/celery.task.rst
|
||||
docs/reference/celery.task.sets.rst
|
||||
docs/reference/celery.utils.mail.rst
|
||||
docs/reference/index.rst
|
||||
docs/releases/1.0/announcement.rst
|
||||
docs/sec/CELERYSA-0001.txt
|
||||
docs/slidesource/slide-example1-result.py
|
||||
docs/slidesource/slide-example1.py
|
||||
docs/templates/readme.txt
|
||||
docs/tutorials/clickcounter.rst
|
||||
docs/tutorials/debugging.rst
|
||||
docs/tutorials/index.rst
|
||||
docs/tutorials/otherqueues.rst
|
||||
docs/userguide/executing.rst
|
||||
docs/userguide/index.rst
|
||||
docs/userguide/monitoring.rst
|
||||
docs/userguide/optimizing.rst
|
||||
docs/userguide/overview.rst
|
||||
docs/userguide/periodic-tasks.rst
|
||||
docs/userguide/remote-tasks.rst
|
||||
docs/userguide/routing.rst
|
||||
docs/userguide/security.rst
|
||||
docs/userguide/signals.rst
|
||||
docs/userguide/tasks.rst
|
||||
docs/userguide/tasksets.rst
|
||||
docs/userguide/workers.rst
|
||||
docs/userguide/concurrency/eventlet.rst
|
||||
docs/userguide/concurrency/index.rst
|
||||
examples/README.rst
|
||||
examples/app/myapp.py
|
||||
examples/celery_http_gateway/README.rst
|
||||
examples/celery_http_gateway/__init__.py
|
||||
examples/celery_http_gateway/manage.py
|
||||
examples/celery_http_gateway/settings.py
|
||||
examples/celery_http_gateway/tasks.py
|
||||
examples/celery_http_gateway/urls.py
|
||||
examples/eventlet/README.rst
|
||||
examples/eventlet/bulk_task_producer.py
|
||||
examples/eventlet/celeryconfig.py
|
||||
examples/eventlet/tasks.py
|
||||
examples/eventlet/webcrawler.py
|
||||
examples/gevent/celeryconfig.py
|
||||
examples/gevent/tasks.py
|
||||
examples/httpexample/README.rst
|
||||
examples/httpexample/__init__.py
|
||||
examples/httpexample/manage.py
|
||||
examples/httpexample/settings.py
|
||||
examples/httpexample/urls.py
|
||||
examples/httpexample/views.py
|
||||
examples/pythonproject/demoapp/README.rst
|
||||
examples/pythonproject/demoapp/__init__.py
|
||||
examples/pythonproject/demoapp/celeryconfig.py
|
||||
examples/pythonproject/demoapp/tasks.py
|
||||
examples/pythonproject/demoapp/test.py
|
||||
examples/resultgraph/tasks.py
|
||||
funtests/setup.py
|
||||
funtests/benchmarks/bench_worker.py
|
||||
funtests/suite/__init__.py
|
||||
funtests/suite/config.py
|
||||
funtests/suite/test_basic.py
|
||||
funtests/suite/test_leak.py
|
||||
requirements/default-py3k.txt
|
||||
requirements/default.txt
|
||||
requirements/docs.txt
|
||||
requirements/pkgutils.txt
|
||||
requirements/py25.txt
|
||||
requirements/py26.txt
|
||||
requirements/security.txt
|
||||
requirements/test-py3k.txt
|
||||
requirements/test-pypy.txt
|
||||
requirements/test.txt
|
|
@ -1,11 +0,0 @@
|
|||
[console_scripts]
|
||||
celeryctl = celery.bin.celeryctl:main
|
||||
celeryd = celery.bin.celeryd:main
|
||||
camqadm = celery.bin.camqadm:main
|
||||
celeryev = celery.bin.celeryev:main
|
||||
celeryd-multi = celery.bin.celeryd_multi:main
|
||||
celerybeat = celery.bin.celerybeat:main
|
||||
|
||||
[bundle.bundles]
|
||||
celery = celery.contrib.bundles:bundles
|
||||
|
|
@ -1,406 +0,0 @@
|
|||
../celery/conf.py
|
||||
../celery/abstract.py
|
||||
../celery/states.py
|
||||
../celery/decorators.py
|
||||
../celery/local.py
|
||||
../celery/exceptions.py
|
||||
../celery/messaging.py
|
||||
../celery/schedules.py
|
||||
../celery/routes.py
|
||||
../celery/__init__.py
|
||||
../celery/platforms.py
|
||||
../celery/signals.py
|
||||
../celery/beat.py
|
||||
../celery/result.py
|
||||
../celery/registry.py
|
||||
../celery/log.py
|
||||
../celery/actors.py
|
||||
../celery/datastructures.py
|
||||
../celery/worker/mediator.py
|
||||
../celery/worker/buckets.py
|
||||
../celery/worker/state.py
|
||||
../celery/worker/heartbeat.py
|
||||
../celery/worker/strategy.py
|
||||
../celery/worker/control.py
|
||||
../celery/worker/__init__.py
|
||||
../celery/worker/job.py
|
||||
../celery/worker/consumer.py
|
||||
../celery/worker/autoscale.py
|
||||
../celery/worker/autoreload.py
|
||||
../celery/contrib/batches.py
|
||||
../celery/contrib/abortable.py
|
||||
../celery/contrib/__init__.py
|
||||
../celery/contrib/migrate.py
|
||||
../celery/contrib/rdb.py
|
||||
../celery/contrib/bundles.py
|
||||
../celery/backends/cassandra.py
|
||||
../celery/backends/cache.py
|
||||
../celery/backends/amqp.py
|
||||
../celery/backends/pyredis.py
|
||||
../celery/backends/redis.py
|
||||
../celery/backends/tyrant.py
|
||||
../celery/backends/base.py
|
||||
../celery/backends/__init__.py
|
||||
../celery/backends/database.py
|
||||
../celery/backends/mongodb.py
|
||||
../celery/utils/timer2.py
|
||||
../celery/utils/encoding.py
|
||||
../celery/utils/functional.py
|
||||
../celery/utils/mail.py
|
||||
../celery/utils/__init__.py
|
||||
../celery/utils/term.py
|
||||
../celery/utils/threads.py
|
||||
../celery/utils/compat.py
|
||||
../celery/utils/serialization.py
|
||||
../celery/utils/patch.py
|
||||
../celery/utils/timeutils.py
|
||||
../celery/events/state.py
|
||||
../celery/events/dumper.py
|
||||
../celery/events/cursesmon.py
|
||||
../celery/events/snapshot.py
|
||||
../celery/events/__init__.py
|
||||
../celery/execute/trace.py
|
||||
../celery/execute/__init__.py
|
||||
../celery/apps/worker.py
|
||||
../celery/apps/__init__.py
|
||||
../celery/apps/beat.py
|
||||
../celery/db/dfd042c7.py
|
||||
../celery/db/a805d4bd.py
|
||||
../celery/db/session.py
|
||||
../celery/db/__init__.py
|
||||
../celery/db/models.py
|
||||
../celery/bin/celeryev.py
|
||||
../celery/bin/celeryd_detach.py
|
||||
../celery/bin/camqadm.py
|
||||
../celery/bin/base.py
|
||||
../celery/bin/__init__.py
|
||||
../celery/bin/celeryd_multi.py
|
||||
../celery/bin/celerybeat.py
|
||||
../celery/bin/celeryctl.py
|
||||
../celery/bin/celeryd.py
|
||||
../celery/security/key.py
|
||||
../celery/security/certificate.py
|
||||
../celery/security/__init__.py
|
||||
../celery/security/serialization.py
|
||||
../celery/tests/config.py
|
||||
../celery/tests/utils.py
|
||||
../celery/tests/__init__.py
|
||||
../celery/tests/compat.py
|
||||
../celery/task/chords.py
|
||||
../celery/task/sets.py
|
||||
../celery/task/http.py
|
||||
../celery/task/schedules.py
|
||||
../celery/task/control.py
|
||||
../celery/task/base.py
|
||||
../celery/task/__init__.py
|
||||
../celery/concurrency/solo.py
|
||||
../celery/concurrency/gevent.py
|
||||
../celery/concurrency/base.py
|
||||
../celery/concurrency/__init__.py
|
||||
../celery/concurrency/threads.py
|
||||
../celery/concurrency/eventlet.py
|
||||
../celery/app/abstract.py
|
||||
../celery/app/amqp.py
|
||||
../celery/app/base.py
|
||||
../celery/app/__init__.py
|
||||
../celery/app/defaults.py
|
||||
../celery/app/annotations.py
|
||||
../celery/loaders/base.py
|
||||
../celery/loaders/__init__.py
|
||||
../celery/loaders/app.py
|
||||
../celery/loaders/default.py
|
||||
../celery/utils/dispatch/__init__.py
|
||||
../celery/utils/dispatch/signal.py
|
||||
../celery/utils/dispatch/saferef.py
|
||||
../celery/tests/test_utils/test_timer2.py
|
||||
../celery/tests/test_utils/test_pickle.py
|
||||
../celery/tests/test_utils/test_utils_encoding.py
|
||||
../celery/tests/test_utils/test_utils_timeutils.py
|
||||
../celery/tests/test_utils/test_datastructures.py
|
||||
../celery/tests/test_utils/test_serialization.py
|
||||
../celery/tests/test_utils/__init__.py
|
||||
../celery/tests/test_utils/test_utils_info.py
|
||||
../celery/tests/test_worker/test_worker_job.py
|
||||
../celery/tests/test_worker/test_worker_heartbeat.py
|
||||
../celery/tests/test_worker/test_worker_state.py
|
||||
../celery/tests/test_worker/test_worker_autoscale.py
|
||||
../celery/tests/test_worker/test_worker_mediator.py
|
||||
../celery/tests/test_worker/test_worker_revoke.py
|
||||
../celery/tests/test_worker/test_bootsteps.py
|
||||
../celery/tests/test_worker/__init__.py
|
||||
../celery/tests/test_worker/test_worker_control.py
|
||||
../celery/tests/test_compat/test_messaging.py
|
||||
../celery/tests/test_compat/__init__.py
|
||||
../celery/tests/test_compat/test_decorators.py
|
||||
../celery/tests/functional/case.py
|
||||
../celery/tests/functional/tasks.py
|
||||
../celery/tests/functional/__init__.py
|
||||
../celery/tests/test_backends/test_mongodb.py
|
||||
../celery/tests/test_backends/test_redis_unit.py
|
||||
../celery/tests/test_backends/test_base.py
|
||||
../celery/tests/test_backends/test_cache.py
|
||||
../celery/tests/test_backends/test_redis.py
|
||||
../celery/tests/test_backends/test_amqp.py
|
||||
../celery/tests/test_backends/test_tyrant.py
|
||||
../celery/tests/test_backends/test_database.py
|
||||
../celery/tests/test_backends/__init__.py
|
||||
../celery/tests/test_backends/test_pyredis_compat.py
|
||||
../celery/tests/test_concurrency/test_concurrency_solo.py
|
||||
../celery/tests/test_concurrency/test_concurrency_eventlet.py
|
||||
../celery/tests/test_concurrency/__init__.py
|
||||
../celery/tests/test_concurrency/test_concurrency_processes.py
|
||||
../celery/tests/test_concurrency/test_concurrency_gevent.py
|
||||
../celery/tests/test_concurrency/test_pool.py
|
||||
../celery/tests/test_events/test_events_state.py
|
||||
../celery/tests/test_events/test_events_cursesmon.py
|
||||
../celery/tests/test_events/test_events_snapshot.py
|
||||
../celery/tests/test_events/__init__.py
|
||||
../celery/tests/test_slow/test_buckets.py
|
||||
../celery/tests/test_slow/__init__.py
|
||||
../celery/tests/test_bin/test_celeryev.py
|
||||
../celery/tests/test_bin/test_celeryd.py
|
||||
../celery/tests/test_bin/__init__.py
|
||||
../celery/tests/test_bin/test_celerybeat.py
|
||||
../celery/tests/test_security/case.py
|
||||
../celery/tests/test_security/test_key.py
|
||||
../celery/tests/test_security/test_serialization.py
|
||||
../celery/tests/test_security/__init__.py
|
||||
../celery/tests/test_security/test_certificate.py
|
||||
../celery/tests/test_task/test_execute_trace.py
|
||||
../celery/tests/test_task/test_result.py
|
||||
../celery/tests/test_task/test_task_http.py
|
||||
../celery/tests/test_task/test_task_abortable.py
|
||||
../celery/tests/test_task/test_task_builtins.py
|
||||
../celery/tests/test_task/test_states.py
|
||||
../celery/tests/test_task/__init__.py
|
||||
../celery/tests/test_task/test_chord.py
|
||||
../celery/tests/test_task/test_registry.py
|
||||
../celery/tests/test_task/test_context.py
|
||||
../celery/tests/test_task/test_task_control.py
|
||||
../celery/tests/test_task/test_task_sets.py
|
||||
../celery/tests/test_app/test_app_amqp.py
|
||||
../celery/tests/test_app/test_routes.py
|
||||
../celery/tests/test_app/test_annotations.py
|
||||
../celery/tests/test_app/test_app_defaults.py
|
||||
../celery/tests/test_app/test_actors.py
|
||||
../celery/tests/test_app/__init__.py
|
||||
../celery/tests/test_app/test_loaders.py
|
||||
../celery/tests/test_app/test_log.py
|
||||
../celery/tests/test_app/test_beat.py
|
||||
../celery/tests/test_app/test_celery.py
|
||||
../celery/concurrency/processes/pool.py
|
||||
../celery/concurrency/processes/process.py
|
||||
../celery/concurrency/processes/__init__.py
|
||||
../celery/concurrency/processes/forking.py
|
||||
../celery/concurrency/processes/_win.py
|
||||
../celery/app/task/__init__.py
|
||||
../celery/conf.pyc
|
||||
../celery/abstract.pyc
|
||||
../celery/states.pyc
|
||||
../celery/decorators.pyc
|
||||
../celery/local.pyc
|
||||
../celery/exceptions.pyc
|
||||
../celery/messaging.pyc
|
||||
../celery/schedules.pyc
|
||||
../celery/routes.pyc
|
||||
../celery/__init__.pyc
|
||||
../celery/platforms.pyc
|
||||
../celery/signals.pyc
|
||||
../celery/beat.pyc
|
||||
../celery/result.pyc
|
||||
../celery/registry.pyc
|
||||
../celery/log.pyc
|
||||
../celery/actors.pyc
|
||||
../celery/datastructures.pyc
|
||||
../celery/worker/mediator.pyc
|
||||
../celery/worker/buckets.pyc
|
||||
../celery/worker/state.pyc
|
||||
../celery/worker/heartbeat.pyc
|
||||
../celery/worker/strategy.pyc
|
||||
../celery/worker/control.pyc
|
||||
../celery/worker/__init__.pyc
|
||||
../celery/worker/job.pyc
|
||||
../celery/worker/consumer.pyc
|
||||
../celery/worker/autoscale.pyc
|
||||
../celery/worker/autoreload.pyc
|
||||
../celery/contrib/batches.pyc
|
||||
../celery/contrib/abortable.pyc
|
||||
../celery/contrib/__init__.pyc
|
||||
../celery/contrib/migrate.pyc
|
||||
../celery/contrib/rdb.pyc
|
||||
../celery/contrib/bundles.pyc
|
||||
../celery/backends/cassandra.pyc
|
||||
../celery/backends/cache.pyc
|
||||
../celery/backends/amqp.pyc
|
||||
../celery/backends/pyredis.pyc
|
||||
../celery/backends/redis.pyc
|
||||
../celery/backends/tyrant.pyc
|
||||
../celery/backends/base.pyc
|
||||
../celery/backends/__init__.pyc
|
||||
../celery/backends/database.pyc
|
||||
../celery/backends/mongodb.pyc
|
||||
../celery/utils/timer2.pyc
|
||||
../celery/utils/encoding.pyc
|
||||
../celery/utils/functional.pyc
|
||||
../celery/utils/mail.pyc
|
||||
../celery/utils/__init__.pyc
|
||||
../celery/utils/term.pyc
|
||||
../celery/utils/threads.pyc
|
||||
../celery/utils/compat.pyc
|
||||
../celery/utils/serialization.pyc
|
||||
../celery/utils/patch.pyc
|
||||
../celery/utils/timeutils.pyc
|
||||
../celery/events/state.pyc
|
||||
../celery/events/dumper.pyc
|
||||
../celery/events/cursesmon.pyc
|
||||
../celery/events/snapshot.pyc
|
||||
../celery/events/__init__.pyc
|
||||
../celery/execute/trace.pyc
|
||||
../celery/execute/__init__.pyc
|
||||
../celery/apps/worker.pyc
|
||||
../celery/apps/__init__.pyc
|
||||
../celery/apps/beat.pyc
|
||||
../celery/db/dfd042c7.pyc
|
||||
../celery/db/a805d4bd.pyc
|
||||
../celery/db/session.pyc
|
||||
../celery/db/__init__.pyc
|
||||
../celery/db/models.pyc
|
||||
../celery/bin/celeryev.pyc
|
||||
../celery/bin/celeryd_detach.pyc
|
||||
../celery/bin/camqadm.pyc
|
||||
../celery/bin/base.pyc
|
||||
../celery/bin/__init__.pyc
|
||||
../celery/bin/celeryd_multi.pyc
|
||||
../celery/bin/celerybeat.pyc
|
||||
../celery/bin/celeryctl.pyc
|
||||
../celery/bin/celeryd.pyc
|
||||
../celery/security/key.pyc
|
||||
../celery/security/certificate.pyc
|
||||
../celery/security/__init__.pyc
|
||||
../celery/security/serialization.pyc
|
||||
../celery/tests/config.pyc
|
||||
../celery/tests/utils.pyc
|
||||
../celery/tests/__init__.pyc
|
||||
../celery/tests/compat.pyc
|
||||
../celery/task/chords.pyc
|
||||
../celery/task/sets.pyc
|
||||
../celery/task/http.pyc
|
||||
../celery/task/schedules.pyc
|
||||
../celery/task/control.pyc
|
||||
../celery/task/base.pyc
|
||||
../celery/task/__init__.pyc
|
||||
../celery/concurrency/solo.pyc
|
||||
../celery/concurrency/gevent.pyc
|
||||
../celery/concurrency/base.pyc
|
||||
../celery/concurrency/__init__.pyc
|
||||
../celery/concurrency/threads.pyc
|
||||
../celery/concurrency/eventlet.pyc
|
||||
../celery/app/abstract.pyc
|
||||
../celery/app/amqp.pyc
|
||||
../celery/app/base.pyc
|
||||
../celery/app/__init__.pyc
|
||||
../celery/app/defaults.pyc
|
||||
../celery/app/annotations.pyc
|
||||
../celery/loaders/base.pyc
|
||||
../celery/loaders/__init__.pyc
|
||||
../celery/loaders/app.pyc
|
||||
../celery/loaders/default.pyc
|
||||
../celery/utils/dispatch/__init__.pyc
|
||||
../celery/utils/dispatch/signal.pyc
|
||||
../celery/utils/dispatch/saferef.pyc
|
||||
../celery/tests/test_utils/test_timer2.pyc
|
||||
../celery/tests/test_utils/test_pickle.pyc
|
||||
../celery/tests/test_utils/test_utils_encoding.pyc
|
||||
../celery/tests/test_utils/test_utils_timeutils.pyc
|
||||
../celery/tests/test_utils/test_datastructures.pyc
|
||||
../celery/tests/test_utils/test_serialization.pyc
|
||||
../celery/tests/test_utils/__init__.pyc
|
||||
../celery/tests/test_utils/test_utils_info.pyc
|
||||
../celery/tests/test_worker/test_worker_job.pyc
|
||||
../celery/tests/test_worker/test_worker_heartbeat.pyc
|
||||
../celery/tests/test_worker/test_worker_state.pyc
|
||||
../celery/tests/test_worker/test_worker_autoscale.pyc
|
||||
../celery/tests/test_worker/test_worker_mediator.pyc
|
||||
../celery/tests/test_worker/test_worker_revoke.pyc
|
||||
../celery/tests/test_worker/test_bootsteps.pyc
|
||||
../celery/tests/test_worker/__init__.pyc
|
||||
../celery/tests/test_worker/test_worker_control.pyc
|
||||
../celery/tests/test_compat/test_messaging.pyc
|
||||
../celery/tests/test_compat/__init__.pyc
|
||||
../celery/tests/test_compat/test_decorators.pyc
|
||||
../celery/tests/functional/case.pyc
|
||||
../celery/tests/functional/tasks.pyc
|
||||
../celery/tests/functional/__init__.pyc
|
||||
../celery/tests/test_backends/test_mongodb.pyc
|
||||
../celery/tests/test_backends/test_redis_unit.pyc
|
||||
../celery/tests/test_backends/test_base.pyc
|
||||
../celery/tests/test_backends/test_cache.pyc
|
||||
../celery/tests/test_backends/test_redis.pyc
|
||||
../celery/tests/test_backends/test_amqp.pyc
|
||||
../celery/tests/test_backends/test_tyrant.pyc
|
||||
../celery/tests/test_backends/test_database.pyc
|
||||
../celery/tests/test_backends/__init__.pyc
|
||||
../celery/tests/test_backends/test_pyredis_compat.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_solo.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_eventlet.pyc
|
||||
../celery/tests/test_concurrency/__init__.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_processes.pyc
|
||||
../celery/tests/test_concurrency/test_concurrency_gevent.pyc
|
||||
../celery/tests/test_concurrency/test_pool.pyc
|
||||
../celery/tests/test_events/test_events_state.pyc
|
||||
../celery/tests/test_events/test_events_cursesmon.pyc
|
||||
../celery/tests/test_events/test_events_snapshot.pyc
|
||||
../celery/tests/test_events/__init__.pyc
|
||||
../celery/tests/test_slow/test_buckets.pyc
|
||||
../celery/tests/test_slow/__init__.pyc
|
||||
../celery/tests/test_bin/test_celeryev.pyc
|
||||
../celery/tests/test_bin/test_celeryd.pyc
|
||||
../celery/tests/test_bin/__init__.pyc
|
||||
../celery/tests/test_bin/test_celerybeat.pyc
|
||||
../celery/tests/test_security/case.pyc
|
||||
../celery/tests/test_security/test_key.pyc
|
||||
../celery/tests/test_security/test_serialization.pyc
|
||||
../celery/tests/test_security/__init__.pyc
|
||||
../celery/tests/test_security/test_certificate.pyc
|
||||
../celery/tests/test_task/test_execute_trace.pyc
|
||||
../celery/tests/test_task/test_result.pyc
|
||||
../celery/tests/test_task/test_task_http.pyc
|
||||
../celery/tests/test_task/test_task_abortable.pyc
|
||||
../celery/tests/test_task/test_task_builtins.pyc
|
||||
../celery/tests/test_task/test_states.pyc
|
||||
../celery/tests/test_task/__init__.pyc
|
||||
../celery/tests/test_task/test_chord.pyc
|
||||
../celery/tests/test_task/test_registry.pyc
|
||||
../celery/tests/test_task/test_context.pyc
|
||||
../celery/tests/test_task/test_task_control.pyc
|
||||
../celery/tests/test_task/test_task_sets.pyc
|
||||
../celery/tests/test_app/test_app_amqp.pyc
|
||||
../celery/tests/test_app/test_routes.pyc
|
||||
../celery/tests/test_app/test_annotations.pyc
|
||||
../celery/tests/test_app/test_app_defaults.pyc
|
||||
../celery/tests/test_app/test_actors.pyc
|
||||
../celery/tests/test_app/__init__.pyc
|
||||
../celery/tests/test_app/test_loaders.pyc
|
||||
../celery/tests/test_app/test_log.pyc
|
||||
../celery/tests/test_app/test_beat.pyc
|
||||
../celery/tests/test_app/test_celery.pyc
|
||||
../celery/concurrency/processes/pool.pyc
|
||||
../celery/concurrency/processes/process.pyc
|
||||
../celery/concurrency/processes/__init__.pyc
|
||||
../celery/concurrency/processes/forking.pyc
|
||||
../celery/concurrency/processes/_win.pyc
|
||||
../celery/app/task/__init__.pyc
|
||||
./
|
||||
top_level.txt
|
||||
SOURCES.txt
|
||||
not-zip-safe
|
||||
entry_points.txt
|
||||
PKG-INFO
|
||||
requires.txt
|
||||
dependency_links.txt
|
||||
../../../bin/celeryctl
|
||||
../../../bin/celeryd
|
||||
../../../bin/camqadm
|
||||
../../../bin/celeryev
|
||||
../../../bin/celeryd-multi
|
||||
../../../bin/celerybeat
|
|
@ -1,5 +0,0 @@
|
|||
importlib
|
||||
anyjson>=0.3.1
|
||||
kombu>=2.1.8,<2.2.0
|
||||
python-dateutil>=1.5,<2.0
|
||||
ordereddict
|
|
@ -1 +0,0 @@
|
|||
celery
|
|
@ -1,35 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Distributed Task Queue"""
|
||||
# :copyright: (c) 2009 - 2012 by Ask Solem.
|
||||
# :license: BSD, see LICENSE for more details.
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
VERSION = (2, 5, 5)
|
||||
__version__ = ".".join(map(str, VERSION[0:3])) + "".join(VERSION[3:])
|
||||
__author__ = "Ask Solem"
|
||||
__contact__ = "ask@celeryproject.org"
|
||||
__homepage__ = "http://celeryproject.org"
|
||||
__docformat__ = "restructuredtext"
|
||||
|
||||
# -eof meta-
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info < (2, 5):
|
||||
raise Exception(
|
||||
"Python 2.4 is not supported by this version. "
|
||||
"Please use Celery versions 2.1.x or earlier.")
|
||||
|
||||
from .local import Proxy
|
||||
|
||||
|
||||
def Celery(*args, **kwargs):
|
||||
from .app import App
|
||||
return App(*args, **kwargs)
|
||||
|
||||
|
||||
def _get_current_app():
|
||||
from .app import current_app
|
||||
return current_app()
|
||||
current_app = Proxy(_get_current_app)
|
|
@ -1,210 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
celery.abstract
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Implements components and boot-steps.
|
||||
|
||||
:copyright: (c) 2009 - 2012 by Ask Solem.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from collections import defaultdict
|
||||
from importlib import import_module
|
||||
|
||||
from .datastructures import DependencyGraph
|
||||
from .utils import instantiate
|
||||
|
||||
|
||||
class Namespace(object):
|
||||
"""A namespace containing components.
|
||||
|
||||
Every component must belong to a namespace.
|
||||
|
||||
When component classes are created they are added to the
|
||||
mapping of unclaimed components. The components will be
|
||||
claimed when the namespace they belong to is created.
|
||||
|
||||
:keyword name: Set the name of this namespace.
|
||||
:keyword app: Set the Celery app for this namespace.
|
||||
|
||||
"""
|
||||
name = None
|
||||
_unclaimed = defaultdict(dict)
|
||||
_started_count = 0
|
||||
|
||||
def __init__(self, name=None, app=None, logger=None):
|
||||
self.app = app
|
||||
self.name = name or self.name
|
||||
self.logger = logger or self.app.log.get_default_logger()
|
||||
self.services = []
|
||||
|
||||
def modules(self):
|
||||
"""Subclasses can override this to return a
|
||||
list of modules to import before components are claimed."""
|
||||
return []
|
||||
|
||||
def load_modules(self):
|
||||
"""Will load the component modules this namespace depends on."""
|
||||
for m in self.modules():
|
||||
self.import_module(m)
|
||||
|
||||
def apply(self, parent, **kwargs):
|
||||
"""Apply the components in this namespace to an object.
|
||||
|
||||
This will apply the ``__init__`` and ``include`` methods
|
||||
of each components with the object as argument.
|
||||
|
||||
For ``StartStopComponents`` the services created
|
||||
will also be added the the objects ``components`` attribute.
|
||||
|
||||
"""
|
||||
self._debug("Loading modules.")
|
||||
self.load_modules()
|
||||
self._debug("Claiming components.")
|
||||
self.components = self._claim()
|
||||
self._debug("Building boot step graph.")
|
||||
self.boot_steps = [self.bind_component(name, parent, **kwargs)
|
||||
for name in self._finalize_boot_steps()]
|
||||
self._debug("New boot order: %r", [c.name for c in self.boot_steps])
|
||||
|
||||
for component in self.boot_steps:
|
||||
component.include(parent)
|
||||
return self
|
||||
|
||||
def bind_component(self, name, parent, **kwargs):
|
||||
"""Bind component to parent object and this namespace."""
|
||||
comp = self[name](parent, **kwargs)
|
||||
comp.namespace = self
|
||||
return comp
|
||||
|
||||
def import_module(self, module):
|
||||
return import_module(module)
|
||||
|
||||
def __getitem__(self, name):
|
||||
return self.components[name]
|
||||
|
||||
def _find_last(self):
|
||||
for C in self.components.itervalues():
|
||||
if C.last:
|
||||
return C
|
||||
|
||||
def _finalize_boot_steps(self):
|
||||
G = self.graph = DependencyGraph((C.name, C.requires)
|
||||
for C in self.components.itervalues())
|
||||
last = self._find_last()
|
||||
if last:
|
||||
for obj in G:
|
||||
if obj != last.name:
|
||||
G.add_edge(last.name, obj)
|
||||
return G.topsort()
|
||||
|
||||
def _claim(self):
|
||||
return self._unclaimed[self.name]
|
||||
|
||||
def _debug(self, msg, *args):
|
||||
return self.logger.debug("[%s] " + msg,
|
||||
*(self.name.capitalize(), ) + args)
|
||||
|
||||
|
||||
class ComponentType(type):
|
||||
"""Metaclass for components."""
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
abstract = attrs.pop("abstract", False)
|
||||
if not abstract:
|
||||
try:
|
||||
cname = attrs["name"]
|
||||
except KeyError:
|
||||
raise NotImplementedError("Components must be named")
|
||||
namespace = attrs.get("namespace", None)
|
||||
if not namespace:
|
||||
attrs["namespace"], _, attrs["name"] = cname.partition('.')
|
||||
cls = super(ComponentType, cls).__new__(cls, name, bases, attrs)
|
||||
if not abstract:
|
||||
Namespace._unclaimed[cls.namespace][cls.name] = cls
|
||||
return cls
|
||||
|
||||
|
||||
class Component(object):
|
||||
"""A component.
|
||||
|
||||
The :meth:`__init__` method is called when the component
|
||||
is bound to a parent object, and can as such be used
|
||||
to initialize attributes in the parent object at
|
||||
parent instantiation-time.
|
||||
|
||||
"""
|
||||
__metaclass__ = ComponentType
|
||||
|
||||
#: The name of the component, or the namespace
|
||||
#: and the name of the component separated by dot.
|
||||
name = None
|
||||
|
||||
#: List of component names this component depends on.
|
||||
#: Note that the dependencies must be in the same namespace.
|
||||
requires = ()
|
||||
|
||||
#: can be used to specify the namespace,
|
||||
#: if the name does not include it.
|
||||
namespace = None
|
||||
|
||||
#: if set the component will not be registered,
|
||||
#: but can be used as a component base class.
|
||||
abstract = True
|
||||
|
||||
#: Optional obj created by the :meth:`create` method.
|
||||
#: This is used by StartStopComponents to keep the
|
||||
#: original service object.
|
||||
obj = None
|
||||
|
||||
#: This flag is reserved for the workers Consumer,
|
||||
#: since it is required to always be started last.
|
||||
#: There can only be one object marked with lsat
|
||||
#: in every namespace.
|
||||
last = False
|
||||
|
||||
#: This provides the default for :meth:`include_if`.
|
||||
enabled = True
|
||||
|
||||
def __init__(self, parent, **kwargs):
|
||||
pass
|
||||
|
||||
def create(self, parent):
|
||||
"""Create the component."""
|
||||
pass
|
||||
|
||||
def include_if(self, parent):
|
||||
"""An optional predicate that decided whether this
|
||||
component should be created."""
|
||||
return self.enabled
|
||||
|
||||
def instantiate(self, qualname, *args, **kwargs):
|
||||
return instantiate(qualname, *args, **kwargs)
|
||||
|
||||
def include(self, parent):
|
||||
if self.include_if(parent):
|
||||
self.obj = self.create(parent)
|
||||
return True
|
||||
|
||||
|
||||
class StartStopComponent(Component):
|
||||
abstract = True
|
||||
terminable = False
|
||||
|
||||
def start(self):
|
||||
return self.obj.start()
|
||||
|
||||
def stop(self):
|
||||
return self.obj.stop()
|
||||
|
||||
def terminate(self):
|
||||
if self.terminable:
|
||||
return self.obj.terminate()
|
||||
return self.obj.stop()
|
||||
|
||||
def include(self, parent):
|
||||
if super(StartStopComponent, self).include(parent):
|
||||
parent.components.append(self.obj)
|
|
@ -1,30 +0,0 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from celery.app import app_or_default
|
||||
|
||||
import cl
|
||||
import cl.presence
|
||||
|
||||
|
||||
def construct(cls, instance, connection=None, *args, **kwargs):
|
||||
app = instance.app = app_or_default(kwargs.pop("app", None))
|
||||
super(cls, instance).__init__(connection or app.broker_connection(),
|
||||
*args, **kwargs)
|
||||
|
||||
|
||||
class Actor(cl.Actor):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
construct(Actor, self, *args, **kwargs)
|
||||
|
||||
|
||||
class Agent(cl.Agent):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
construct(Agent, self, *args, **kwargs)
|
||||
|
||||
|
||||
class AwareAgent(cl.presence.AwareAgent):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
construct(AwareAgent, self, *args, **kwargs)
|
|
@ -1,294 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
celery.app
|
||||
~~~~~~~~~~
|
||||
|
||||
Celery Application.
|
||||
|
||||
:copyright: (c) 2009 - 2012 by Ask Solem.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
import threading
|
||||
|
||||
from .. import registry
|
||||
from ..utils import cached_property, instantiate
|
||||
|
||||
from .annotations import (
|
||||
_first_match, _first_match_any,
|
||||
prepare as prepare_annotations
|
||||
)
|
||||
from .base import BaseApp
|
||||
|
||||
|
||||
class _TLS(threading.local):
|
||||
#: Apps with the :attr:`~celery.app.base.BaseApp.set_as_current` attribute
|
||||
#: sets this, so it will always contain the last instantiated app,
|
||||
#: and is the default app returned by :func:`app_or_default`.
|
||||
current_app = None
|
||||
|
||||
#: The currently executing task.
|
||||
current_task = None
|
||||
_tls = _TLS()
|
||||
|
||||
|
||||
class AppPickler(object):
|
||||
"""Default application pickler/unpickler."""
|
||||
|
||||
def __call__(self, cls, *args):
|
||||
kwargs = self.build_kwargs(*args)
|
||||
app = self.construct(cls, **kwargs)
|
||||
self.prepare(app, **kwargs)
|
||||
return app
|
||||
|
||||
def prepare(self, app, **kwargs):
|
||||
app.conf.update(kwargs["changes"])
|
||||
|
||||
def build_kwargs(self, *args):
|
||||
return self.build_standard_kwargs(*args)
|
||||
|
||||
def build_standard_kwargs(self, main, changes, loader, backend, amqp,
|
||||
events, log, control, accept_magic_kwargs):
|
||||
return dict(main=main, loader=loader, backend=backend, amqp=amqp,
|
||||
changes=changes, events=events, log=log, control=control,
|
||||
set_as_current=False,
|
||||
accept_magic_kwargs=accept_magic_kwargs)
|
||||
|
||||
def construct(self, cls, **kwargs):
|
||||
return cls(**kwargs)
|
||||
|
||||
|
||||
def _unpickle_app(cls, pickler, *args):
|
||||
return pickler()(cls, *args)
|
||||
|
||||
|
||||
class App(BaseApp):
|
||||
"""Celery Application.
|
||||
|
||||
:param main: Name of the main module if running as `__main__`.
|
||||
:keyword loader: The loader class, or the name of the loader class to use.
|
||||
Default is :class:`celery.loaders.app.AppLoader`.
|
||||
:keyword backend: The result store backend class, or the name of the
|
||||
backend class to use. Default is the value of the
|
||||
:setting:`CELERY_RESULT_BACKEND` setting.
|
||||
:keyword amqp: AMQP object or class name.
|
||||
:keyword events: Events object or class name.
|
||||
:keyword log: Log object or class name.
|
||||
:keyword control: Control object or class name.
|
||||
:keyword set_as_current: Make this the global current app.
|
||||
|
||||
"""
|
||||
Pickler = AppPickler
|
||||
|
||||
def set_current(self):
|
||||
"""Make this the current app for this thread."""
|
||||
_tls.current_app = self
|
||||
|
||||
def on_init(self):
|
||||
if self.set_as_current:
|
||||
self.set_current()
|
||||
|
||||
def create_task_cls(self):
|
||||
"""Creates a base task class using default configuration
|
||||
taken from this app."""
|
||||
conf = self.conf
|
||||
|
||||
from .task import BaseTask
|
||||
|
||||
class Task(BaseTask):
|
||||
abstract = True
|
||||
app = self
|
||||
backend = self.backend
|
||||
exchange_type = conf.CELERY_DEFAULT_EXCHANGE_TYPE
|
||||
delivery_mode = conf.CELERY_DEFAULT_DELIVERY_MODE
|
||||
send_error_emails = conf.CELERY_SEND_TASK_ERROR_EMAILS
|
||||
error_whitelist = conf.CELERY_TASK_ERROR_WHITELIST
|
||||
serializer = conf.CELERY_TASK_SERIALIZER
|
||||
rate_limit = conf.CELERY_DEFAULT_RATE_LIMIT
|
||||
track_started = conf.CELERY_TRACK_STARTED
|
||||
acks_late = conf.CELERY_ACKS_LATE
|
||||
ignore_result = conf.CELERY_IGNORE_RESULT
|
||||
store_errors_even_if_ignored = \
|
||||
conf.CELERY_STORE_ERRORS_EVEN_IF_IGNORED
|
||||
accept_magic_kwargs = self.accept_magic_kwargs
|
||||
Task.__doc__ = BaseTask.__doc__
|
||||
|
||||
return Task
|
||||
|
||||
def Worker(self, **kwargs):
|
||||
"""Create new :class:`~celery.apps.worker.Worker` instance."""
|
||||
return instantiate("celery.apps.worker:Worker", app=self, **kwargs)
|
||||
|
||||
def WorkController(self, **kwargs):
|
||||
return instantiate("celery.worker:WorkController", app=self, **kwargs)
|
||||
|
||||
def Beat(self, **kwargs):
|
||||
"""Create new :class:`~celery.apps.beat.Beat` instance."""
|
||||
return instantiate("celery.apps.beat:Beat", app=self, **kwargs)
|
||||
|
||||
def TaskSet(self, *args, **kwargs):
|
||||
"""Create new :class:`~celery.task.sets.TaskSet`."""
|
||||
return instantiate("celery.task.sets:TaskSet",
|
||||
app=self, *args, **kwargs)
|
||||
|
||||
def worker_main(self, argv=None):
|
||||
"""Run :program:`celeryd` using `argv`. Uses :data:`sys.argv`
|
||||
if `argv` is not specified."""
|
||||
return instantiate("celery.bin.celeryd:WorkerCommand", app=self) \
|
||||
.execute_from_commandline(argv)
|
||||
|
||||
def task(self, *args, **options):
|
||||
"""Decorator to create a task class out of any callable.
|
||||
|
||||
**Examples:**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@task()
|
||||
def refresh_feed(url):
|
||||
return Feed.objects.get(url=url).refresh()
|
||||
|
||||
with setting extra options and using retry.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from celery.task import current
|
||||
|
||||
@task(exchange="feeds")
|
||||
def refresh_feed(url):
|
||||
try:
|
||||
return Feed.objects.get(url=url).refresh()
|
||||
except socket.error, exc:
|
||||
current.retry(exc=exc)
|
||||
|
||||
Calling the resulting task::
|
||||
|
||||
>>> refresh_feed("http://example.com/rss") # Regular
|
||||
<Feed: http://example.com/rss>
|
||||
>>> refresh_feed.delay("http://example.com/rss") # Async
|
||||
<AsyncResult: 8998d0f4-da0b-4669-ba03-d5ab5ac6ad5d>
|
||||
|
||||
"""
|
||||
|
||||
def inner_create_task_cls(**options):
|
||||
|
||||
def _create_task_cls(fun):
|
||||
base = options.pop("base", None) or self.Task
|
||||
|
||||
T = type(fun.__name__, (base, ), dict({
|
||||
"app": self,
|
||||
"accept_magic_kwargs": False,
|
||||
"run": staticmethod(fun),
|
||||
"__doc__": fun.__doc__,
|
||||
"__module__": fun.__module__}, **options))()
|
||||
return registry.tasks[T.name] # global instance.
|
||||
|
||||
return _create_task_cls
|
||||
|
||||
if len(args) == 1 and callable(args[0]):
|
||||
return inner_create_task_cls(**options)(*args)
|
||||
return inner_create_task_cls(**options)
|
||||
|
||||
def annotate_task(self, task):
|
||||
if self.annotations:
|
||||
match = _first_match(self.annotations, task)
|
||||
for attr, value in (match or {}).iteritems():
|
||||
setattr(task, attr, value)
|
||||
match_any = _first_match_any(self.annotations)
|
||||
for attr, value in (match_any or {}).iteritems():
|
||||
setattr(task, attr, value)
|
||||
|
||||
@cached_property
|
||||
def Task(self):
|
||||
"""Default Task base class for this application."""
|
||||
return self.create_task_cls()
|
||||
|
||||
@cached_property
|
||||
def annotations(self):
|
||||
return prepare_annotations(self.conf.CELERY_ANNOTATIONS)
|
||||
|
||||
def __repr__(self):
|
||||
return "<Celery: %s:0x%x>" % (self.main or "__main__", id(self), )
|
||||
|
||||
def __reduce__(self):
|
||||
# Reduce only pickles the configuration changes,
|
||||
# so the default configuration doesn't have to be passed
|
||||
# between processes.
|
||||
return (_unpickle_app, (self.__class__, self.Pickler)
|
||||
+ self.__reduce_args__())
|
||||
|
||||
def __reduce_args__(self):
|
||||
return (self.main,
|
||||
self.conf.changes,
|
||||
self.loader_cls,
|
||||
self.backend_cls,
|
||||
self.amqp_cls,
|
||||
self.events_cls,
|
||||
self.log_cls,
|
||||
self.control_cls,
|
||||
self.accept_magic_kwargs)
|
||||
|
||||
|
||||
#: The "default" loader is the default loader used by old applications.
|
||||
default_loader = os.environ.get("CELERY_LOADER") or "default"
|
||||
|
||||
#: Global fallback app instance.
|
||||
default_app = App("default", loader=default_loader,
|
||||
set_as_current=False,
|
||||
accept_magic_kwargs=True)
|
||||
|
||||
|
||||
def current_app():
|
||||
return getattr(_tls, "current_app", None) or default_app
|
||||
|
||||
|
||||
def current_task():
|
||||
return getattr(_tls, "current_task", None)
|
||||
|
||||
|
||||
def _app_or_default(app=None):
|
||||
"""Returns the app provided or the default app if none.
|
||||
|
||||
The environment variable :envvar:`CELERY_TRACE_APP` is used to
|
||||
trace app leaks. When enabled an exception is raised if there
|
||||
is no active app.
|
||||
|
||||
"""
|
||||
if app is None:
|
||||
return getattr(_tls, "current_app", None) or default_app
|
||||
return app
|
||||
|
||||
|
||||
def _app_or_default_trace(app=None): # pragma: no cover
|
||||
from traceback import print_stack
|
||||
from multiprocessing import current_process
|
||||
if app is None:
|
||||
if getattr(_tls, "current_app", None):
|
||||
print("-- RETURNING TO CURRENT APP --") # noqa+
|
||||
print_stack()
|
||||
return _tls.current_app
|
||||
if current_process()._name == "MainProcess":
|
||||
raise Exception("DEFAULT APP")
|
||||
print("-- RETURNING TO DEFAULT APP --") # noqa+
|
||||
print_stack()
|
||||
return default_app
|
||||
return app
|
||||
|
||||
|
||||
def enable_trace():
|
||||
global app_or_default
|
||||
app_or_default = _app_or_default_trace
|
||||
|
||||
|
||||
def disable_trace():
|
||||
global app_or_default
|
||||
app_or_default = _app_or_default
|
||||
|
||||
|
||||
app_or_default = _app_or_default
|
||||
if os.environ.get("CELERY_TRACE_APP"): # pragma: no cover
|
||||
enable_trace()
|
|
@ -1,55 +0,0 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
|
||||
class from_config(object):
|
||||
|
||||
def __init__(self, key=None):
|
||||
self.key = key
|
||||
|
||||
def get_key(self, attr):
|
||||
return attr if self.key is None else self.key
|
||||
|
||||
|
||||
class _configurated(type):
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
attrs["__confopts__"] = dict((attr, spec.get_key(attr))
|
||||
for attr, spec in attrs.iteritems()
|
||||
if isinstance(spec, from_config))
|
||||
inherit_from = attrs.get("inherit_confopts", ())
|
||||
for subcls in bases:
|
||||
try:
|
||||
attrs["__confopts__"].update(subcls.__confopts__)
|
||||
except AttributeError:
|
||||
pass
|
||||
for subcls in inherit_from:
|
||||
attrs["__confopts__"].update(subcls.__confopts__)
|
||||
attrs = dict((k, v if not isinstance(v, from_config) else None)
|
||||
for k, v in attrs.iteritems())
|
||||
return super(_configurated, cls).__new__(cls, name, bases, attrs)
|
||||
|
||||
|
||||
class configurated(object):
|
||||
__metaclass__ = _configurated
|
||||
|
||||
def setup_defaults(self, kwargs, namespace="celery"):
|
||||
confopts = self.__confopts__
|
||||
app, find = self.app, self.app.conf.find_value_for_key
|
||||
|
||||
for attr, keyname in confopts.iteritems():
|
||||
try:
|
||||
value = kwargs[attr]
|
||||
except KeyError:
|
||||
value = find(keyname, namespace)
|
||||
else:
|
||||
if value is None:
|
||||
value = find(keyname, namespace)
|
||||
setattr(self, attr, value)
|
||||
|
||||
for attr_name, attr_value in kwargs.iteritems():
|
||||
if attr_name not in confopts and attr_value is not None:
|
||||
setattr(self, attr_name, attr_value)
|
||||
|
||||
def confopts_as_dict(self):
|
||||
return dict((key, getattr(self, key))
|
||||
for key in self.__confopts__.iterkeys())
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче