├── .gitattributes ├── .gitignore ├── LICENSE ├── MovieGrabber.py ├── README.md ├── certs ├── host.cert └── host.key ├── configs └── .gitignore ├── db └── .gitignore ├── images ├── icon │ ├── favicon.ico │ ├── ignore.gif │ ├── imdb.gif │ ├── nfo.gif │ ├── post.gif │ ├── purge.gif │ ├── torrent.gif │ └── usenet.gif ├── logo │ └── moviegrabber.gif └── posters │ └── thumbnails │ ├── default │ └── default.jpg │ └── history │ └── .gitignore ├── interfaces └── classic │ └── templates │ ├── cache.manifest │ ├── config.tmpl │ ├── config_directories.tmpl │ ├── config_general.tmpl │ ├── config_imdb.tmpl │ ├── config_notification.tmpl │ ├── config_post.tmpl │ ├── config_scheduling.tmpl │ ├── config_switches.tmpl │ ├── config_torrent.tmpl │ ├── config_usenet.tmpl │ ├── history.tmpl │ ├── home.tmpl │ ├── inc_bottom.tmpl │ ├── inc_cmenu.tmpl │ ├── inc_top.tmpl │ ├── queue.tmpl │ ├── restart.tmpl │ └── static │ ├── javascript │ ├── checkbox.js │ └── dropdown.js │ └── stylesheets │ ├── colorschemes │ ├── black.css │ ├── classic.css │ ├── darkblue.css │ ├── green.css │ ├── lightblue.css │ ├── red.css │ └── white-black.css │ ├── default.css │ └── defaultcolors.css ├── lib ├── .gitignore ├── __init__.py ├── moviegrabber │ └── __init__.py └── site-packages │ ├── Cheetah │ ├── CacheRegion.py │ ├── CacheStore.py │ ├── CheetahWrapper.py │ ├── Compiler.py │ ├── DirectiveAnalyzer.py │ ├── Django.py │ ├── DummyTransaction.py │ ├── ErrorCatchers.py │ ├── FileUtils.py │ ├── Filters.py │ ├── ImportHooks.py │ ├── ImportManager.py │ ├── Macros │ │ ├── I18n.py │ │ └── __init__.py │ ├── NameMapper.py │ ├── Parser.py │ ├── Servlet.py │ ├── SettingsManager.py │ ├── SourceReader.py │ ├── Template.py │ ├── TemplateCmdLineIface.py │ ├── Templates │ │ ├── SkeletonPage.py │ │ ├── SkeletonPage.tmpl │ │ ├── _SkeletonPage.py │ │ └── __init__.py │ ├── Tests │ │ ├── Analyzer.py │ │ ├── CheetahWrapper.py │ │ ├── Cheps.py │ │ ├── Filters.py │ │ ├── Misc.py │ │ ├── NameMapper.py │ │ ├── Parser.py │ │ ├── Performance.py │ │ ├── Regressions.py │ │ ├── SyntaxAndOutput.py │ │ ├── Template.py │ │ ├── Test.py │ │ ├── Unicode.py │ │ ├── __init__.py │ │ └── xmlrunner.py │ ├── Tools │ │ ├── CGITemplate.py │ │ ├── MondoReport.py │ │ ├── MondoReportDoc.txt │ │ ├── RecursiveNull.py │ │ ├── SiteHierarchy.py │ │ └── __init__.py │ ├── Unspecified.py │ ├── Utils │ │ ├── Indenter.py │ │ ├── Misc.py │ │ ├── WebInputMixin.py │ │ ├── __init__.py │ │ ├── htmlDecode.py │ │ ├── htmlEncode.py │ │ └── statprof.py │ ├── Version.py │ ├── __init__.py │ └── convertTmplPathToModuleName.py │ ├── __init__.py │ ├── argparse.py │ ├── bs4 │ ├── __init__.py │ ├── builder │ │ ├── __init__.py │ │ ├── _html5lib.py │ │ ├── _htmlparser.py │ │ └── _lxml.py │ ├── dammit.py │ ├── diagnose.py │ ├── element.py │ ├── testing.py │ └── tests │ │ ├── __init__.py │ │ ├── test_builder_registry.py │ │ ├── test_docs.py │ │ ├── test_html5lib.py │ │ ├── test_htmlparser.py │ │ ├── test_lxml.py │ │ ├── test_soup.py │ │ └── test_tree.py │ ├── cherrypy │ ├── LICENSE.txt │ ├── __init__.py │ ├── _cpchecker.py │ ├── _cpcompat.py │ ├── _cpconfig.py │ ├── _cpdispatch.py │ ├── _cperror.py │ ├── _cplogging.py │ ├── _cpmodpy.py │ ├── _cpnative_server.py │ ├── _cpreqbody.py │ ├── _cprequest.py │ ├── _cpserver.py │ ├── _cpthreadinglocal.py │ ├── _cptools.py │ ├── _cptree.py │ ├── _cpwsgi.py │ ├── _cpwsgi_server.py │ ├── cherryd │ ├── favicon.ico │ ├── lib │ │ ├── __init__.py │ │ ├── auth.py │ │ ├── auth_basic.py │ │ ├── auth_digest.py │ │ ├── caching.py │ │ ├── covercp.py │ │ ├── cpstats.py │ │ ├── cptools.py │ │ ├── encoding.py │ │ ├── gctools.py │ │ ├── http.py │ │ ├── httpauth.py │ │ ├── httputil.py │ │ ├── jsontools.py │ │ ├── profiler.py │ │ ├── reprconf.py │ │ ├── sessions.py │ │ ├── static.py │ │ └── xmlrpcutil.py │ ├── process │ │ ├── __init__.py │ │ ├── plugins.py │ │ ├── servers.py │ │ ├── win32.py │ │ └── wspbus.py │ ├── scaffold │ │ ├── __init__.py │ │ ├── example.conf │ │ ├── site.conf │ │ └── static │ │ │ └── made_with_cherrypy_small.png │ ├── test │ │ ├── __init__.py │ │ ├── _test_decorators.py │ │ ├── _test_states_demo.py │ │ ├── benchmark.py │ │ ├── checkerdemo.py │ │ ├── helper.py │ │ ├── logtest.py │ │ ├── modfastcgi.py │ │ ├── modfcgid.py │ │ ├── modpy.py │ │ ├── modwsgi.py │ │ ├── sessiondemo.py │ │ ├── static │ │ │ ├── dirback.jpg │ │ │ └── index.html │ │ ├── style.css │ │ ├── test.pem │ │ ├── test_auth_basic.py │ │ ├── test_auth_digest.py │ │ ├── test_bus.py │ │ ├── test_caching.py │ │ ├── test_config.py │ │ ├── test_config_server.py │ │ ├── test_conn.py │ │ ├── test_core.py │ │ ├── test_dynamicobjectmapping.py │ │ ├── test_encoding.py │ │ ├── test_etags.py │ │ ├── test_http.py │ │ ├── test_httpauth.py │ │ ├── test_httplib.py │ │ ├── test_json.py │ │ ├── test_logging.py │ │ ├── test_mime.py │ │ ├── test_misc_tools.py │ │ ├── test_objectmapping.py │ │ ├── test_proxy.py │ │ ├── test_refleaks.py │ │ ├── test_request_obj.py │ │ ├── test_routes.py │ │ ├── test_session.py │ │ ├── test_sessionauthenticate.py │ │ ├── test_states.py │ │ ├── test_static.py │ │ ├── test_tools.py │ │ ├── test_tutorials.py │ │ ├── test_virtualhost.py │ │ ├── test_wsgi_ns.py │ │ ├── test_wsgi_vhost.py │ │ ├── test_wsgiapps.py │ │ ├── test_xmlrpc.py │ │ └── webtest.py │ ├── tutorial │ │ ├── README.txt │ │ ├── __init__.py │ │ ├── bonus-sqlobject.py │ │ ├── custom_error.html │ │ ├── pdf_file.pdf │ │ ├── tut01_helloworld.py │ │ ├── tut02_expose_methods.py │ │ ├── tut03_get_and_post.py │ │ ├── tut04_complex_site.py │ │ ├── tut05_derived_objects.py │ │ ├── tut06_default_method.py │ │ ├── tut07_sessions.py │ │ ├── tut08_generators_and_yield.py │ │ ├── tut09_files.py │ │ ├── tut10_http_errors.py │ │ └── tutorial.conf │ └── wsgiserver │ │ ├── __init__.py │ │ ├── ssl_builtin.py │ │ ├── ssl_pyopenssl.py │ │ └── wsgiserver2.py │ └── sqlalchemy │ ├── __init__.py │ ├── connectors │ ├── __init__.py │ ├── mxodbc.py │ ├── mysqldb.py │ ├── pyodbc.py │ └── zxJDBC.py │ ├── databases │ └── __init__.py │ ├── dialects │ ├── __init__.py │ ├── drizzle │ │ ├── __init__.py │ │ ├── base.py │ │ └── mysqldb.py │ ├── firebird │ │ ├── __init__.py │ │ ├── base.py │ │ ├── fdb.py │ │ └── kinterbasdb.py │ ├── mssql │ │ ├── __init__.py │ │ ├── adodbapi.py │ │ ├── base.py │ │ ├── information_schema.py │ │ ├── mxodbc.py │ │ ├── pymssql.py │ │ ├── pyodbc.py │ │ └── zxjdbc.py │ ├── mysql │ │ ├── __init__.py │ │ ├── base.py │ │ ├── cymysql.py │ │ ├── gaerdbms.py │ │ ├── mysqlconnector.py │ │ ├── mysqldb.py │ │ ├── oursql.py │ │ ├── pymysql.py │ │ ├── pyodbc.py │ │ └── zxjdbc.py │ ├── oracle │ │ ├── __init__.py │ │ ├── base.py │ │ ├── cx_oracle.py │ │ └── zxjdbc.py │ ├── postgres.py │ ├── postgresql │ │ ├── __init__.py │ │ ├── base.py │ │ ├── constraints.py │ │ ├── hstore.py │ │ ├── json.py │ │ ├── pg8000.py │ │ ├── psycopg2.py │ │ ├── pypostgresql.py │ │ ├── ranges.py │ │ └── zxjdbc.py │ ├── sqlite │ │ ├── __init__.py │ │ ├── base.py │ │ └── pysqlite.py │ └── sybase │ │ ├── __init__.py │ │ ├── base.py │ │ ├── mxodbc.py │ │ ├── pyodbc.py │ │ └── pysybase.py │ ├── engine │ ├── __init__.py │ ├── base.py │ ├── default.py │ ├── interfaces.py │ ├── reflection.py │ ├── result.py │ ├── strategies.py │ ├── threadlocal.py │ ├── url.py │ └── util.py │ ├── event │ ├── __init__.py │ ├── api.py │ ├── attr.py │ ├── base.py │ ├── legacy.py │ └── registry.py │ ├── events.py │ ├── exc.py │ ├── ext │ ├── __init__.py │ ├── associationproxy.py │ ├── automap.py │ ├── compiler.py │ ├── declarative │ │ ├── __init__.py │ │ ├── api.py │ │ ├── base.py │ │ └── clsregistry.py │ ├── horizontal_shard.py │ ├── hybrid.py │ ├── instrumentation.py │ ├── mutable.py │ ├── orderinglist.py │ └── serializer.py │ ├── inspection.py │ ├── interfaces.py │ ├── log.py │ ├── orm │ ├── __init__.py │ ├── attributes.py │ ├── base.py │ ├── collections.py │ ├── dependency.py │ ├── deprecated_interfaces.py │ ├── descriptor_props.py │ ├── dynamic.py │ ├── evaluator.py │ ├── events.py │ ├── exc.py │ ├── identity.py │ ├── instrumentation.py │ ├── interfaces.py │ ├── loading.py │ ├── mapper.py │ ├── path_registry.py │ ├── persistence.py │ ├── properties.py │ ├── query.py │ ├── relationships.py │ ├── scoping.py │ ├── session.py │ ├── state.py │ ├── strategies.py │ ├── strategy_options.py │ ├── sync.py │ ├── unitofwork.py │ └── util.py │ ├── pool.py │ ├── processors.py │ ├── schema.py │ ├── sql │ ├── __init__.py │ ├── annotation.py │ ├── base.py │ ├── compiler.py │ ├── ddl.py │ ├── default_comparator.py │ ├── dml.py │ ├── elements.py │ ├── expression.py │ ├── functions.py │ ├── naming.py │ ├── operators.py │ ├── schema.py │ ├── selectable.py │ ├── sqltypes.py │ ├── type_api.py │ ├── util.py │ └── visitors.py │ ├── testing │ ├── __init__.py │ ├── assertions.py │ ├── assertsql.py │ ├── config.py │ ├── engines.py │ ├── entities.py │ ├── exclusions.py │ ├── fixtures.py │ ├── mock.py │ ├── pickleable.py │ ├── plugin │ │ ├── __init__.py │ │ ├── noseplugin.py │ │ ├── plugin_base.py │ │ └── pytestplugin.py │ ├── profiling.py │ ├── requirements.py │ ├── runner.py │ ├── schema.py │ ├── suite │ │ ├── __init__.py │ │ ├── test_ddl.py │ │ ├── test_insert.py │ │ ├── test_reflection.py │ │ ├── test_results.py │ │ ├── test_select.py │ │ ├── test_sequence.py │ │ ├── test_types.py │ │ └── test_update_delete.py │ ├── util.py │ └── warnings.py │ ├── types.py │ └── util │ ├── __init__.py │ ├── _collections.py │ ├── compat.py │ ├── deprecations.py │ ├── langhelpers.py │ ├── queue.py │ └── topological.py ├── logs └── .gitignore ├── plugins └── unraid │ ├── README.txt │ ├── moviegrabber-32bit.plg │ └── moviegrabber-64bit.plg └── scripts ├── init.d └── moviegrabber.sh └── init.systemd └── moviegrabber.service /.gitattributes: -------------------------------------------------------------------------------- 1 | # Define the default behavior where GitHub attempts to detect the file type and set the line endings correctly 2 | * text=auto 3 | 4 | # Define line endings to be unix (LF) for GitHub files 5 | .gitattributes text eol=lf 6 | .gitignore text eol=lf 7 | .gitconfig text eol=lf 8 | LICENSE text eol=lf 9 | *.md text eol=lf 10 | 11 | # Define line endings to be unix (LF) for source code 12 | *.php text eol=lf 13 | *.css text eol=lf 14 | *.sass text eol=lf 15 | *.scss text eol=lf 16 | *.less text eol=lf 17 | *.styl text eol=lf 18 | *.js text eol=lf 19 | *.coffee text eol=lf 20 | *.json text eol=lf 21 | *.htm text eol=lf 22 | *.html text eol=lf 23 | *.xml text eol=lf 24 | *.svg text eol=lf 25 | *.txt text eol=lf 26 | *.ini text eol=lf 27 | *.inc text eol=lf 28 | *.pl text eol=lf 29 | *.rb text eol=lf 30 | *.py text eol=lf 31 | *.scm text eol=lf 32 | *.sql text eol=lf 33 | *.sh text eol=lf 34 | *.bat text eol=lf 35 | *.txt text eol=lf 36 | *.tmpl text eol=lf 37 | Dockerfile text eol=lf 38 | 39 | # Define binary files to be excluded from modification 40 | *.png binary 41 | *.jpg binary 42 | *.jpeg binary 43 | *.gif binary 44 | *.ico binary 45 | *.flv binary 46 | *.fla binary 47 | *.swf binary 48 | *.gz binary 49 | *.tar binary 50 | *.rar binary 51 | *.zip binary 52 | *.7z binary 53 | *.egg binary 54 | *.ttf binary 55 | *.eot binary 56 | *.woff binary 57 | *.pyc binary 58 | *.pdf binary 59 | *.db binary 60 | *.xz binary 61 | *.whl binary 62 | *.pex binary -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore comments file 2 | todo.txt 3 | # Ignore pycharms project files 4 | .idea 5 | # Ignore compiled Python scripts 6 | *.pyc 7 | # Ignore virtualenv environment 8 | venv 9 | 10 | # Ignore all log files 11 | *.log 12 | -------------------------------------------------------------------------------- /certs/host.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICWDCCAcGgAwIBAgIJAI/3fsTORREJMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV 3 | BAYTAlVLMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX 4 | aWRnaXRzIFB0eSBMdGQwHhcNMTExMDEwMDk1ODA3WhcNMjExMDA3MDk1ODA3WjBF 5 | MQswCQYDVQQGEwJVSzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 6 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB 7 | gQCtFdVHN2TnugRmx36bJ/zdI+H6a34YlvUgL5KGYVun8saNJIzvLdM1KN2gciQJ 8 | UPxMVorm9ca3kiG3M4N247DcNQyExR2ItsxVw42I3e2rtu+rNUbzObA9ZiJ1RyXV 9 | /5UA7FjJ8OgHw2M/zHjVN28VbTM471y6X55pU0e3ZkhUawIDAQABo1AwTjAdBgNV 10 | HQ4EFgQULsx8ebnew30soa80BBfbtNhGln8wHwYDVR0jBBgwFoAULsx8ebnew30s 11 | oa80BBfbtNhGln8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBagTWm 12 | j5SPKu3pTbsf0A+B5pHkVo+akn1VYh5ZSW+zQaXk2m4J+qsYUKsUuTLK2g+qwipY 13 | VFNvqZXnHUqhJS8r8SBCYTP2dizSJA+YjzZaW1BtucOi503xnECM33JAJ0KHOVVn 14 | ANvpr9XesaiO+L61IGYOkGsqbbfAW+kTia5agw== 15 | -----END CERTIFICATE----- 16 | -------------------------------------------------------------------------------- /certs/host.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXAIBAAKBgQCtFdVHN2TnugRmx36bJ/zdI+H6a34YlvUgL5KGYVun8saNJIzv 3 | LdM1KN2gciQJUPxMVorm9ca3kiG3M4N247DcNQyExR2ItsxVw42I3e2rtu+rNUbz 4 | ObA9ZiJ1RyXV/5UA7FjJ8OgHw2M/zHjVN28VbTM471y6X55pU0e3ZkhUawIDAQAB 5 | AoGBAJ6poPTDhrAVCOvee+Rm55kfx4ry9og7+UAj28FrhcWS+wdvNfIao73bVC47 6 | 82TG5EBmJLZLHnowbs+tXRmi5v+zfDjOEmbHEeX8x4teo8luQNij+nCOaZt/Wysm 7 | A75rL2jmYY5imbCViOz176CiQkiS+hOtJNK1v1dN0r62mQPhAkEA1VJ0dH1odGSF 8 | Ty4rt0wkufEM2ESvR0s6GxMgqmV13vcDKy0SceQwc7bd655h+4AqPNPVwLaXYSUg 9 | 7EewBS5XBwJBAM+2mjMobo7mpGYQruPIpTwNOx+VEoeQWbDKY7nrmZdG9W3PVEau 10 | Qt50Gxyt1Qw6jXye+KdgitJaNIXXzNc9+n0CQGGi98JJlAGR8KIpE8E1jKm+do6W 11 | AVO0TsgNnSngfm6qyDx+yK5wLu0HidNKDra6Fpr4qiEmcWr5P3Rl616zswkCQGwa 12 | IM6XMFL2/oCQFjU+a6CBUk/xiZ88JTG5Y4WTdHAi4gCwcrAGaY7U5ndakRK4NoKx 13 | Sb/yos0vXT57PYSYIRECQBl49LLlLxF0hNEWC304F3kwb8LXeImQ7431hUj3nI4y 14 | W4u+CDTAHMxvFx7bZf1xOavdrYeVAhv+T5SIOs7fwOQ= 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /configs/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /db/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /images/icon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/images/icon/favicon.ico -------------------------------------------------------------------------------- /images/icon/ignore.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/images/icon/ignore.gif -------------------------------------------------------------------------------- /images/icon/imdb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/images/icon/imdb.gif -------------------------------------------------------------------------------- /images/icon/nfo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/images/icon/nfo.gif -------------------------------------------------------------------------------- /images/icon/post.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/images/icon/post.gif -------------------------------------------------------------------------------- /images/icon/purge.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/images/icon/purge.gif -------------------------------------------------------------------------------- /images/icon/torrent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/images/icon/torrent.gif -------------------------------------------------------------------------------- /images/icon/usenet.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/images/icon/usenet.gif -------------------------------------------------------------------------------- /images/logo/moviegrabber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/images/logo/moviegrabber.gif -------------------------------------------------------------------------------- /images/posters/thumbnails/default/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/images/posters/thumbnails/default/default.jpg -------------------------------------------------------------------------------- /images/posters/thumbnails/history/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /interfaces/classic/templates/cache.manifest: -------------------------------------------------------------------------------- 1 | CACHE MANIFEST 2 | 3 | # Explicitly cached 'master entries'. 4 | CACHE: 5 | 6 | # Resources that require the user to be online. 7 | NETWORK: 8 | * -------------------------------------------------------------------------------- /interfaces/classic/templates/config.tmpl: -------------------------------------------------------------------------------- 1 | #set global $statpath="../.." 2 | #set global $topmenu="config" 3 | #set global $submenu="" 4 | #include $templates_dir + "/inc_top.tmpl" 5 | #include $templates_dir + "/inc_cmenu.tmpl" 6 | 7 |
8 | 9 |

Configuration

10 | 11 | This section allows you to define the settings for MovieGrabber. 12 | 13 |
14 |
15 | 16 |
17 | 18 | #include $templates_dir + "/inc_bottom.tmpl" -------------------------------------------------------------------------------- /interfaces/classic/templates/config_scheduling.tmpl: -------------------------------------------------------------------------------- 1 | #set global $statpath="../.." 2 | #set global $topmenu="config" 3 | #set global $submenu="scheduling" 4 | #include $templates_dir + "/inc_top.tmpl" 5 | #include $templates_dir + "/inc_cmenu.tmpl" 6 | 7 |
8 | 9 |

Scheduling

10 | 11 |
12 | 13 |
14 | MovieGrabber Schedule 15 | 16 | (?)Run Every:
17 | Define how often to run MovieGrabber.
18 | 19 | hour(s): 20 | 29 | 30 | minute(s): 31 | 50 | 51 |
52 |
53 | 54 |
55 | 56 |
57 | Post Processing Schedule 58 | 59 | (?)Run Every:
60 | Define how often to run post processing.
61 | 62 | hour(s): 63 | 72 | 73 | minute(s): 74 | 83 | 84 |
85 |
86 | 87 |
88 | 89 |
90 | 91 |
92 |
93 | 94 | 95 | 96 |
97 | 98 | #include $templates_dir + "/inc_bottom.tmpl" 99 | -------------------------------------------------------------------------------- /interfaces/classic/templates/inc_bottom.tmpl: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /interfaces/classic/templates/inc_cmenu.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | General | 10 | 11 | General | 12 | 13 | 14 | 15 | Switches | 16 | 17 | Switches | 18 | 19 | 20 | 21 | Folders | 22 | 23 | Folders | 24 | 25 | 26 | 27 | IMDB | 28 | 29 | IMDB | 30 | 31 | 32 | 33 | Usenet | 34 | 35 | Usenet | 36 | 37 | 38 | 39 | Torrent | 40 | 41 | Torrent | 42 | 43 | 44 | 45 | Post Processing | 46 | 47 | Post Processing | 48 | 49 | 50 | 51 | Notification | 52 | 53 | Notification | 54 | 55 | 56 | 57 | Scheduling 58 | 59 | Scheduling 60 | 61 | 62 | -------------------------------------------------------------------------------- /interfaces/classic/templates/inc_top.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $title 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

MovieGrabber ver $local_version$strapline

22 | 23 | 24 | 25 | 26 | 27 | Home | 28 | 29 | Home | 30 | 31 | 32 | 33 | Queue | 34 | 35 | Queue | 36 | 37 | 38 | 39 | History | 40 | 41 | History | 42 | 43 | 44 | 45 | Configuration 46 | 47 | Configuration 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /interfaces/classic/templates/restart.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /interfaces/classic/templates/static/javascript/checkbox.js: -------------------------------------------------------------------------------- 1 | function checkbox_checked(queue_release_checkbox_id,queue_purge_checkbox_id) 2 | { 3 | if (document.getElementById(queue_release_checkbox_id).checked == true) 4 | { 5 | document.getElementById(queue_purge_checkbox_id).checked = true; 6 | } 7 | else 8 | { 9 | document.getElementById(queue_purge_checkbox_id).checked = false; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /interfaces/classic/templates/static/javascript/dropdown.js: -------------------------------------------------------------------------------- 1 | function dynamic_dropdown(post_config_dropdown1_id,post_config_dropdown2_id) 2 | { 3 | var dropdown1 = document.getElementById(post_config_dropdown1_id); 4 | var dropdown1_value = dropdown1.options[dropdown1.selectedIndex].value; 5 | 6 | var dropdown2 = document.getElementById(post_config_dropdown2_id); 7 | var dropdown2_value = dropdown2.options[dropdown2.selectedIndex].value; 8 | 9 | if (dropdown1_value == "filename") { 10 | dropdown2.options.add(new Option("equal to")); 11 | dropdown2.options.add(new Option("not equal to")); 12 | } 13 | 14 | if (dropdown1_value == "extension") { 15 | selbox.options[selbox.options.length] = new 16 | Option('equal to','extension_equal_to'); 17 | selbox.options[selbox.options.length] = new 18 | Option('not equal to','extension_not_equal_to'); 19 | } 20 | 21 | if (dropdown1_value == "size") { 22 | selbox.options[selbox.options.length] = new 23 | Option('equal to','size_equal_to'); 24 | selbox.options[selbox.options.length] = new 25 | Option('not equal to','size_not_equal_to'); 26 | selbox.options[selbox.options.length] = new 27 | Option('greater than','size_greater_than'); 28 | selbox.options[selbox.options.length] = new 29 | Option('less than','size_less_than'); 30 | } 31 | 32 | if (dropdown1_value == "genre") { 33 | selbox.options[selbox.options.length] = new 34 | Option('equal to','genre_equal_to'); 35 | selbox.options[selbox.options.length] = new 36 | Option('not equal to','genre_not_equal_to'); 37 | } 38 | 39 | if (dropdown1_value == "certificate") { 40 | selbox.options[selbox.options.length] = new 41 | Option('equal to','certificate_equal_to'); 42 | selbox.options[selbox.options.length] = new 43 | Option('not equal to','certificate_not_equal_to'); 44 | selbox.options[selbox.options.length] = new 45 | Option('greater than','certificate_greater_than'); 46 | selbox.options[selbox.options.length] = new 47 | Option('less than','certificate_less_than'); 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /interfaces/classic/templates/static/stylesheets/colorschemes/black.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #3a3a3a; 3 | color: #888; 4 | } 5 | 6 | a { 7 | color: #000; 8 | } 9 | 10 | input, select { 11 | background-color:#232323; 12 | border-color:#3a3a3a; 13 | color:white; 14 | } 15 | 16 | legend { 17 | color: #ccc; 18 | } 19 | 20 | fieldset.EntryFieldSet { 21 | color: #ccc; 22 | border-color:#3a3a3a; 23 | } 24 | 25 | .MainMenu a { 26 | color: #4e4e4e; 27 | } 28 | 29 | .SubMenu a { 30 | color: #ccc; 31 | } 32 | 33 | a:hover { 34 | background-color: #f5f5f5; 35 | color:black; 36 | } 37 | 38 | a{color:white;} 39 | 40 | a.current:hover { 41 | background-color: #ccc; 42 | } 43 | 44 | .blockWithBorder { 45 | border-color: #b5b5b5; 46 | background-color: #eeeeee; 47 | } 48 | 49 | .MainMenu { 50 | background-color: #232323; 51 | 52 | } 53 | .SubMenu { 54 | background-color: #000; 55 | } 56 | 57 | table { 58 | color: white; 59 | } 60 | 61 | th { 62 | background: #000; 63 | color: white; 64 | } 65 | 66 | h1 { 67 | border-bottom: 1px solid #4e4e4e; 68 | } 69 | 70 | #catchfrase { 71 | color: white; 72 | } 73 | .footer { 74 | background-color: #232323; 75 | border-top: 1px solid #000; 76 | color:#4e4e4e; 77 | } 78 | 79 | .SubMenu, .blockWithBorder , a.current, th { 80 | background-color: #000; 81 | color:white; 82 | } 83 | 84 | a.current { 85 | color: #777; 86 | background-color: #000; 87 | 88 | } 89 | 90 | tr.even, tr.odd, .history_queue_details, .history_queue_poster, .history_queue_details_resize, .post_processing_div_tr { 91 | background-color: #111; 92 | color:white; 93 | } 94 | 95 | tr.evenLine, tr.oddLine { 96 | background-color: #232323; 97 | color:#666; 98 | } 99 | 100 | #first, #second, #third { 101 | color: #000; 102 | } 103 | 104 | a.current:hover, a:hover { 105 | background-color: black; 106 | color:white 107 | } 108 | 109 | a.remove{color:#888} -------------------------------------------------------------------------------- /interfaces/classic/templates/static/stylesheets/colorschemes/classic.css: -------------------------------------------------------------------------------- 1 | .SubMenu, .blockWithBorder , a.current, tr.even, tr.odd, .history_queue_details, .history_queue_poster, .history_queue_details_resize, .post_processing_div_tr{ 2 | background-color: #b5b5b5; 3 | color:black; 4 | } 5 | 6 | .SubMenu{ 7 | border: 1px solid #b5b5b5; 8 | } 9 | 10 | .MainMenu { 11 | display: block; 12 | border-width: 1px; 13 | border-style: solid; 14 | border-color: #b5b5b5; 15 | background-color: #eeeeee; 16 | padding: 5px; 17 | } 18 | 19 | .SubMenu a { 20 | font-weight: bold; 21 | color: #000000; 22 | text-decoration: none; 23 | } 24 | 25 | body{ 26 | color: #808080; 27 | } 28 | 29 | th { 30 | background: #b5b5b5; 31 | color: white; 32 | font-weight: bold; 33 | } 34 | 35 | tr.even{ 36 | background-color: #cdf; 37 | } 38 | 39 | tr.evenLine { 40 | background-color: #eee; 41 | } 42 | 43 | tr.odd { 44 | background-color: #99bbff; 45 | } 46 | 47 | tr.oddLine { 48 | background-color: #f8f8f8; 49 | } 50 | 51 | #third { 52 | color: #808080; 53 | } 54 | 55 | #first, legend{ 56 | color:#c32ee4; 57 | } 58 | 59 | #second{ 60 | color:#99bbff; 61 | } 62 | 63 | a.current:hover, a:hover { 64 | background-color: black; 65 | color:white 66 | } 67 | 68 | .SubMenu a.current{ 69 | color:white; 70 | } 71 | 72 | a{ 73 | color:black; 74 | } 75 | 76 | td > a, td > a { 77 | color:white; 78 | } 79 | 80 | a.remove { 81 | color:black; 82 | } 83 | -------------------------------------------------------------------------------- /interfaces/classic/templates/static/stylesheets/colorschemes/darkblue.css: -------------------------------------------------------------------------------- 1 | .SubMenu, .blockWithBorder , a.current, tr.even, tr.odd, .history_queue_details, .history_queue_poster, .history_queue_details_resize, .post_processing_div_tr{ 2 | background-color: #44577c; 3 | color:white; 4 | } 5 | 6 | th { 7 | background-color: #333; 8 | color:white; 9 | } 10 | 11 | #first, #third { 12 | color: #44577c; 13 | } 14 | 15 | .SubMenu a.current { 16 | color:#ccc; 17 | } 18 | a.current:hover, a:hover { 19 | background-color: black; 20 | color:white 21 | } 22 | 23 | td > a, td > a { 24 | color:white; 25 | } 26 | 27 | a.remove { 28 | color:black; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /interfaces/classic/templates/static/stylesheets/colorschemes/green.css: -------------------------------------------------------------------------------- 1 | .SubMenu, .blockWithBorder , a.current, tr.even, tr.odd, .history_queue_details, .history_queue_poster, .history_queue_details_resize, .post_processing_div_tr{ 2 | background-color: #3f7c78; 3 | color:white; 4 | } 5 | 6 | #first, #third { 7 | color: #3f7c78; 8 | } 9 | 10 | th{ 11 | background-color: #333; 12 | color:white; 13 | } 14 | 15 | .SubMenu a.current { 16 | color:#444; 17 | } 18 | a.current:hover, a:hover { 19 | background-color: black; 20 | color:white 21 | } 22 | 23 | td > a, td > a { 24 | color:white; 25 | } 26 | 27 | a.remove { 28 | color:black; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /interfaces/classic/templates/static/stylesheets/colorschemes/lightblue.css: -------------------------------------------------------------------------------- 1 | .SubMenu, .blockWithBorder , a.current, tr.even, tr.odd, .history_queue_details, .history_queue_poster, .history_queue_details_resize, .post_processing_div_tr{ 2 | background-color: #5ca5ff; 3 | color:white; 4 | } 5 | 6 | #first, #third { 7 | color: #5ca5ff; 8 | } 9 | 10 | th { 11 | background-color: #000; 12 | color:white; 13 | } 14 | 15 | .SubMenu a.current { 16 | color:black; 17 | } 18 | 19 | a.current:hover, a:hover { 20 | background-color: black; 21 | color:white 22 | } 23 | 24 | td > a, td > a { 25 | color:white; 26 | } 27 | 28 | a.remove { 29 | color:black; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /interfaces/classic/templates/static/stylesheets/colorschemes/red.css: -------------------------------------------------------------------------------- 1 | .SubMenu, .blockWithBorder , a.current, tr.even, tr.odd, .history_queue_details, .history_queue_poster, .history_queue_details_resize, .post_processing_div_tr{ 2 | background-color: #CC0033; 3 | color:white; 4 | } 5 | 6 | th { 7 | background-color: #333; 8 | color:white; 9 | } 10 | 11 | #first, #third { 12 | color: #CC0033; 13 | } 14 | 15 | .SubMenu a.current { 16 | color:black; 17 | } 18 | 19 | a.current:hover, a:hover { 20 | background-color: black; 21 | color:white 22 | } 23 | 24 | td > a, td > a { 25 | color:white; 26 | } 27 | 28 | a.remove { 29 | color:black; 30 | } 31 | -------------------------------------------------------------------------------- /interfaces/classic/templates/static/stylesheets/colorschemes/white-black.css: -------------------------------------------------------------------------------- 1 | .SubMenu, .blockWithBorder , a.current, .history_queue_details, .history_queue_poster, .history_queue_details_resize, .post_processing_div_tr{ 2 | background-color: #4e4e4e; 3 | color:white; 4 | } 5 | 6 | th { 7 | background-color: #333; 8 | color:white; 9 | } 10 | 11 | #first, #third { 12 | color: #4e4e4e; 13 | } 14 | 15 | .SubMenu a.current { 16 | color:#ccc; 17 | } 18 | 19 | a.current:hover, a:hover { 20 | background-color: black; 21 | color:white 22 | } 23 | 24 | td > a, td > a { 25 | color:white; 26 | } 27 | 28 | a.remove { 29 | color:black; 30 | } -------------------------------------------------------------------------------- /interfaces/classic/templates/static/stylesheets/defaultcolors.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fff; 3 | color: #000; 4 | } 5 | 6 | a { 7 | color: #000; 8 | } 9 | 10 | input, select { 11 | 12 | } 13 | legend { 14 | color: #000; 15 | } 16 | 17 | fieldset.EntryFieldSet { 18 | border-color:#3a3a3a; 19 | } 20 | .MainMenu a { 21 | color: #4e4e4e; 22 | } 23 | 24 | .SubMenu a { 25 | color: #f5f5f5; 26 | } 27 | a:hover { 28 | background-color: #ccc; 29 | color:black; 30 | } 31 | 32 | a.current { 33 | color: #ccc; 34 | background-color: #000; 35 | 36 | } 37 | 38 | 39 | .blockWithBorder { 40 | border-color: #b5b5b5; 41 | background-color: #eeeeee; 42 | } 43 | 44 | .MainMenu { 45 | background-color: #f5f5f5; 46 | 47 | } 48 | .SubMenu { 49 | background-color: #000; 50 | } 51 | 52 | table { 53 | 54 | } 55 | 56 | th { 57 | background: #fff; 58 | 59 | } 60 | 61 | tr.even{ 62 | background-color: #222222; 63 | color:white; 64 | } 65 | 66 | tr.evenLine { 67 | background-color: #f5f5f5; 68 | } 69 | 70 | tr.odd { 71 | background-color: #222222; 72 | color:white; 73 | } 74 | 75 | tr.oddLine { 76 | background-color: #f5f5f5; 77 | } 78 | 79 | h1 { 80 | border-bottom: 1px solid #4e4e4e; 81 | } 82 | 83 | #first { 84 | color: black; 85 | } 86 | 87 | #second { 88 | color: black; 89 | } 90 | 91 | #catchfrase { 92 | color: black; 93 | } 94 | .footer { 95 | background-color: #f5f5f5; 96 | border-top: 1px solid #000; 97 | color:#4e4e4e; 98 | } 99 | 100 | #progressBar { 101 | background-color: #cdf; 102 | border: 1px solid blue; 103 | } 104 | 105 | #percentageBar { 106 | background-color: #9bf; 107 | } 108 | 109 | .queuelink{color:black;} 110 | 111 | .SubMenu, .blockWithBorder , a.current, tr.even, tr.odd{ 112 | background-color: #44577c; 113 | color:white; 114 | } 115 | 116 | th { 117 | background-color: #333; 118 | color:white; 119 | } 120 | #first, #third { 121 | color: #44577c; 122 | } 123 | 124 | a.current:hover, a:hover { 125 | background-color: black; 126 | color:white 127 | } 128 | 129 | td > a, td > a { 130 | color:white; 131 | } 132 | 133 | a.remove { 134 | color:black; 135 | } 136 | 137 | .feedEnabled{color:green;} 138 | .feedDisabled{color:red;} 139 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore comments file 2 | todo.txt 3 | *.pyc -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/lib/__init__.py -------------------------------------------------------------------------------- /lib/moviegrabber/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/lib/moviegrabber/__init__.py -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/DirectiveAnalyzer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import pprint 5 | 6 | try: 7 | from functools import reduce 8 | except ImportError: 9 | # Assume we have reduce 10 | pass 11 | 12 | from Cheetah import Parser 13 | from Cheetah import Compiler 14 | from Cheetah import Template 15 | 16 | class Analyzer(Parser.Parser): 17 | def __init__(self, *args, **kwargs): 18 | self.calls = {} 19 | super(Analyzer, self).__init__(*args, **kwargs) 20 | 21 | def eatDirective(self): 22 | directive = self.matchDirective() 23 | try: 24 | self.calls[directive] += 1 25 | except KeyError: 26 | self.calls[directive] = 1 27 | super(Analyzer, self).eatDirective() 28 | 29 | class AnalysisCompiler(Compiler.ModuleCompiler): 30 | parserClass = Analyzer 31 | 32 | 33 | def analyze(source): 34 | klass = Template.Template.compile(source, compilerClass=AnalysisCompiler) 35 | return klass._CHEETAH_compilerInstance._parser.calls 36 | 37 | def main_file(f): 38 | fd = open(f, 'r') 39 | try: 40 | print u'>>> Analyzing %s' % f 41 | calls = analyze(fd.read()) 42 | return calls 43 | finally: 44 | fd.close() 45 | 46 | 47 | def _find_templates(directory, suffix): 48 | for root, dirs, files in os.walk(directory): 49 | for f in files: 50 | if not f.endswith(suffix): 51 | continue 52 | yield root + os.path.sep + f 53 | 54 | def _analyze_templates(iterable): 55 | for template in iterable: 56 | yield main_file(template) 57 | 58 | def main_dir(opts): 59 | results = _analyze_templates(_find_templates(opts.dir, opts.suffix)) 60 | totals = {} 61 | for series in results: 62 | if not series: 63 | continue 64 | for k, v in series.iteritems(): 65 | try: 66 | totals[k] += v 67 | except KeyError: 68 | totals[k] = v 69 | return totals 70 | 71 | 72 | def main(): 73 | from optparse import OptionParser 74 | op = OptionParser() 75 | op.add_option('-f', '--file', dest='file', default=None, 76 | help='Specify a single file to analyze') 77 | op.add_option('-d', '--dir', dest='dir', default=None, 78 | help='Specify a directory of templates to analyze') 79 | op.add_option('--suffix', default='tmpl', dest='suffix', 80 | help='Specify a custom template file suffix for the -d option (default: "tmpl")') 81 | opts, args = op.parse_args() 82 | 83 | if not opts.file and not opts.dir: 84 | op.print_help() 85 | return 86 | 87 | results = None 88 | if opts.file: 89 | results = main_file(opts.file) 90 | if opts.dir: 91 | results = main_dir(opts) 92 | 93 | pprint.pprint(results) 94 | 95 | 96 | if __name__ == '__main__': 97 | main() 98 | 99 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Django.py: -------------------------------------------------------------------------------- 1 | import Cheetah.Template 2 | 3 | def render(template_file, **kwargs): 4 | ''' 5 | Cheetah.Django.render() takes the template filename 6 | (the filename should be a file in your Django 7 | TEMPLATE_DIRS) 8 | 9 | Any additional keyword arguments are passed into the 10 | template are propogated into the template's searchList 11 | ''' 12 | import django.http 13 | import django.template.loader 14 | source, loader = django.template.loader.find_template_source(template_file) 15 | t = Cheetah.Template.Template(source, searchList=[kwargs]) 16 | return django.http.HttpResponse(t.__str__()) 17 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/ErrorCatchers.py: -------------------------------------------------------------------------------- 1 | # $Id: ErrorCatchers.py,v 1.7 2005/01/03 19:59:07 tavis_rudd Exp $ 2 | """ErrorCatcher class for Cheetah Templates 3 | 4 | Meta-Data 5 | ================================================================================ 6 | Author: Tavis Rudd 7 | Version: $Revision: 1.7 $ 8 | Start Date: 2001/08/01 9 | Last Revision Date: $Date: 2005/01/03 19:59:07 $ 10 | """ 11 | __author__ = "Tavis Rudd " 12 | __revision__ = "$Revision: 1.7 $"[11:-2] 13 | 14 | import time 15 | from Cheetah.NameMapper import NotFound 16 | 17 | class Error(Exception): 18 | pass 19 | 20 | class ErrorCatcher: 21 | _exceptionsToCatch = (NotFound,) 22 | 23 | def __init__(self, templateObj): 24 | pass 25 | 26 | def exceptions(self): 27 | return self._exceptionsToCatch 28 | 29 | def warn(self, exc_val, code, rawCode, lineCol): 30 | return rawCode 31 | ## make an alias 32 | Echo = ErrorCatcher 33 | 34 | class BigEcho(ErrorCatcher): 35 | def warn(self, exc_val, code, rawCode, lineCol): 36 | return "="*15 + "<" + rawCode + " could not be found>" + "="*15 37 | 38 | class KeyError(ErrorCatcher): 39 | def warn(self, exc_val, code, rawCode, lineCol): 40 | raise KeyError("no '%s' in this Template Object's Search List" % rawCode) 41 | 42 | class ListErrors(ErrorCatcher): 43 | """Accumulate a list of errors.""" 44 | _timeFormat = "%c" 45 | 46 | def __init__(self, templateObj): 47 | ErrorCatcher.__init__(self, templateObj) 48 | self._errors = [] 49 | 50 | def warn(self, exc_val, code, rawCode, lineCol): 51 | dict = locals().copy() 52 | del dict['self'] 53 | dict['time'] = time.strftime(self._timeFormat, 54 | time.localtime(time.time())) 55 | self._errors.append(dict) 56 | return rawCode 57 | 58 | def listErrors(self): 59 | """Return the list of errors.""" 60 | return self._errors 61 | 62 | 63 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Macros/I18n.py: -------------------------------------------------------------------------------- 1 | import gettext 2 | _ = gettext.gettext 3 | class I18n(object): 4 | def __init__(self, parser): 5 | pass 6 | 7 | ## junk I'm playing with to test the macro framework 8 | # def parseArgs(self, parser, startPos): 9 | # parser.getWhiteSpace() 10 | # args = parser.getExpression(useNameMapper=False, 11 | # pyTokensToBreakAt=[':']).strip() 12 | # return args 13 | # 14 | # def convertArgStrToDict(self, args, parser=None, startPos=None): 15 | # def getArgs(*pargs, **kws): 16 | # return pargs, kws 17 | # exec 'positionalArgs, kwArgs = getArgs(%(args)s)'%locals() 18 | # return kwArgs 19 | 20 | def __call__(self, 21 | src, # aka message, 22 | plural=None, 23 | n=None, # should be a string representing the name of the 24 | # '$var' rather than $var itself 25 | id=None, 26 | domain=None, 27 | source=None, 28 | target=None, 29 | comment=None, 30 | 31 | # args that are automatically supplied by the parser when the 32 | # macro is called: 33 | parser=None, 34 | macros=None, 35 | isShortForm=False, 36 | EOLCharsInShortForm=None, 37 | startPos=None, 38 | endPos=None, 39 | ): 40 | """This is just a stub at this time. 41 | 42 | plural = the plural form of the message 43 | n = a sized argument to distinguish between single and plural forms 44 | 45 | id = msgid in the translation catalog 46 | domain = translation domain 47 | source = source lang 48 | target = a specific target lang 49 | comment = a comment to the translation team 50 | 51 | See the following for some ideas 52 | http://www.zope.org/DevHome/Wikis/DevSite/Projects/ComponentArchitecture/ZPTInternationalizationSupport 53 | 54 | Other notes: 55 | - There is no need to replicate the i18n:name attribute from plone / PTL, 56 | as cheetah placeholders serve the same purpose 57 | 58 | 59 | """ 60 | 61 | #print macros['i18n'] 62 | src = _(src) 63 | if isShortForm and endPos 20 | 21 | 22 | #block writeHeadTag 23 | 24 | $title 25 | $metaTags 26 | $stylesheetTags 27 | $javascriptTags 28 | 29 | #end block writeHeadTag 30 | 31 | #end cache header 32 | ################# 33 | 34 | $bodyTag 35 | 36 | #block writeBody 37 | This skeleton page has no flesh. Its body needs to be implemented. 38 | #end block writeBody 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Templates/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tests/Analyzer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import unittest 4 | 5 | from Cheetah import DirectiveAnalyzer 6 | 7 | 8 | class AnalyzerTests(unittest.TestCase): 9 | def test_set(self): 10 | template = ''' 11 | #set $foo = "bar" 12 | Hello ${foo}! 13 | ''' 14 | calls = DirectiveAnalyzer.analyze(template) 15 | self.assertEquals(1, calls.get('set')) 16 | 17 | def test_compilersettings(self): 18 | template = ''' 19 | #compiler-settings 20 | useNameMapper = False 21 | #end compiler-settings 22 | ''' 23 | calls = DirectiveAnalyzer.analyze(template) 24 | self.assertEquals(1, calls.get('compiler-settings')) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | 30 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tests/Cheps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import unittest 4 | 5 | import Cheetah 6 | import Cheetah.Parser 7 | import Cheetah.Template 8 | 9 | class Chep_2_Conditionalized_Import_Behavior(unittest.TestCase): 10 | def test_ModuleLevelImport(self): 11 | ''' Verify module level (traditional) import behavior ''' 12 | pass 13 | 14 | def test_InlineImport(self): 15 | ''' Verify (new) inline import behavior works ''' 16 | template = ''' 17 | #def funky($s) 18 | #try 19 | #import urllib 20 | #except ImportError 21 | #pass 22 | #end try 23 | #return urllib.quote($s) 24 | #end def 25 | ''' 26 | try: 27 | template = Cheetah.Template.Template.compile(template) 28 | except Cheetah.Parser.ParseError, ex: 29 | self.fail('Failed to properly generate code %s' % ex) 30 | template = template() 31 | rc = tepmlate.funky('abc def') 32 | assert rc == 'abc+def' 33 | 34 | def test_LegacyMode(self): 35 | ''' Verify disabling of CHEP #2 works ''' 36 | pass 37 | 38 | if __name__ == '__main__': 39 | unittest.main() 40 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tests/Filters.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import unittest 5 | 6 | import Cheetah.Template 7 | import Cheetah.Filters 8 | 9 | majorVer, minorVer = sys.version_info[0], sys.version_info[1] 10 | versionTuple = (majorVer, minorVer) 11 | 12 | class BasicMarkdownFilterTest(unittest.TestCase): 13 | ''' 14 | Test that our markdown filter works 15 | ''' 16 | def test_BasicHeader(self): 17 | template = ''' 18 | #from Cheetah.Filters import Markdown 19 | #transform Markdown 20 | $foo 21 | 22 | Header 23 | ====== 24 | ''' 25 | expected = '''

bar

26 |

Header

''' 27 | try: 28 | template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}]) 29 | template = str(template) 30 | assert template == expected 31 | except ImportError, ex: 32 | print('>>> We probably failed to import markdown, bummer %s' % ex) 33 | return 34 | except Exception, ex: 35 | if ex.__class__.__name__ == 'MarkdownException' and majorVer == 2 and minorVer < 5: 36 | print('>>> NOTE: Support for the Markdown filter will be broken for you. Markdown says: %s' % ex) 37 | return 38 | raise 39 | 40 | 41 | class BasicCodeHighlighterFilterTest(unittest.TestCase): 42 | ''' 43 | Test that our code highlighter filter works 44 | ''' 45 | def test_Python(self): 46 | template = ''' 47 | #from Cheetah.Filters import CodeHighlighter 48 | #transform CodeHighlighter 49 | 50 | def foo(self): 51 | return '$foo' 52 | ''' 53 | template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}]) 54 | template = str(template) 55 | assert template, (template, 'We should have some content here...') 56 | 57 | def test_Html(self): 58 | template = ''' 59 | #from Cheetah.Filters import CodeHighlighter 60 | #transform CodeHighlighter 61 | 62 | $foo 63 | ''' 64 | template = Cheetah.Template.Template(template, searchList=[{'foo' : 'bar'}]) 65 | template = str(template) 66 | assert template, (template, 'We should have some content here...') 67 | 68 | 69 | if __name__ == '__main__': 70 | unittest.main() 71 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tests/Misc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import unittest 4 | 5 | from Cheetah import SettingsManager 6 | 7 | 8 | class SettingsManagerTests(unittest.TestCase): 9 | def test_mergeDictionaries(self): 10 | left = {'foo' : 'bar', 'abc' : {'a' : 1, 'b' : 2, 'c' : (3,)}} 11 | right = {'xyz' : (10, 9)} 12 | expect = {'xyz': (10, 9), 'foo': 'bar', 'abc': {'a': 1, 'c': (3,), 'b': 2}} 13 | 14 | result = SettingsManager.mergeNestedDictionaries(left, right) 15 | self.assertEquals(result, expect) 16 | 17 | 18 | if __name__ == '__main__': 19 | unittest.main() 20 | 21 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tests/Parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import unittest 4 | 5 | from Cheetah import Parser 6 | 7 | class ArgListTest(unittest.TestCase): 8 | def setUp(self): 9 | super(ArgListTest, self).setUp() 10 | self.al = Parser.ArgList() 11 | 12 | def test_merge1(self): 13 | ''' 14 | Testing the ArgList case results from Template.Preprocessors.test_complexUsage 15 | ''' 16 | self.al.add_argument('arg') 17 | expect = [('arg', None)] 18 | 19 | self.assertEquals(expect, self.al.merge()) 20 | 21 | def test_merge2(self): 22 | ''' 23 | Testing the ArgList case results from SyntaxAndOutput.BlockDirective.test4 24 | ''' 25 | self.al.add_argument('a') 26 | self.al.add_default('999') 27 | self.al.next() 28 | self.al.add_argument('b') 29 | self.al.add_default('444') 30 | 31 | expect = [(u'a', u'999'), (u'b', u'444')] 32 | 33 | self.assertEquals(expect, self.al.merge()) 34 | 35 | 36 | 37 | def test_merge3(self): 38 | ''' 39 | Testing the ArgList case results from SyntaxAndOutput.BlockDirective.test13 40 | ''' 41 | self.al.add_argument('arg') 42 | self.al.add_default("'This is my block'") 43 | expect = [('arg', "'This is my block'")] 44 | 45 | self.assertEquals(expect, self.al.merge()) 46 | 47 | if __name__ == '__main__': 48 | unittest.main() 49 | 50 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tests/SyntaxAndOutput.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/lib/site-packages/Cheetah/Tests/SyntaxAndOutput.py -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tests/Test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Core module of Cheetah's Unit-testing framework 4 | 5 | TODO 6 | ================================================================================ 7 | # combo tests 8 | # negative test cases for expected exceptions 9 | # black-box vs clear-box testing 10 | # do some tests that run the Template for long enough to check that the refresh code works 11 | ''' 12 | 13 | import sys 14 | import unittest 15 | 16 | from Cheetah.Tests import SyntaxAndOutput 17 | from Cheetah.Tests import NameMapper 18 | from Cheetah.Tests import Misc 19 | from Cheetah.Tests import Filters 20 | from Cheetah.Tests import Template 21 | from Cheetah.Tests import Cheps 22 | from Cheetah.Tests import Parser 23 | from Cheetah.Tests import Regressions 24 | from Cheetah.Tests import Unicode 25 | from Cheetah.Tests import CheetahWrapper 26 | from Cheetah.Tests import Analyzer 27 | 28 | SyntaxAndOutput.install_eols() 29 | 30 | suites = [ 31 | unittest.findTestCases(SyntaxAndOutput), 32 | unittest.findTestCases(NameMapper), 33 | unittest.findTestCases(Filters), 34 | unittest.findTestCases(Template), 35 | #unittest.findTestCases(Cheps), 36 | unittest.findTestCases(Regressions), 37 | unittest.findTestCases(Unicode), 38 | unittest.findTestCases(Misc), 39 | unittest.findTestCases(Parser), 40 | unittest.findTestCases(Analyzer), 41 | ] 42 | 43 | if not sys.platform.startswith('java'): 44 | suites.append(unittest.findTestCases(CheetahWrapper)) 45 | 46 | if __name__ == '__main__': 47 | runner = unittest.TextTestRunner() 48 | if 'xml' in sys.argv: 49 | import xmlrunner 50 | runner = xmlrunner.XMLTestRunner(filename='Cheetah-Tests.xml') 51 | 52 | results = runner.run(unittest.TestSuite(suites)) 53 | 54 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tests/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tools/CGITemplate.py: -------------------------------------------------------------------------------- 1 | # $Id: CGITemplate.py,v 1.6 2006/01/29 02:09:59 tavis_rudd Exp $ 2 | """A subclass of Cheetah.Template for use in CGI scripts. 3 | 4 | Usage in a template: 5 | #extends Cheetah.Tools.CGITemplate 6 | #implements respond 7 | $cgiHeaders#slurp 8 | 9 | Usage in a template inheriting a Python class: 10 | 1. The template 11 | #extends MyPythonClass 12 | #implements respond 13 | $cgiHeaders#slurp 14 | 15 | 2. The Python class 16 | from Cheetah.Tools import CGITemplate 17 | class MyPythonClass(CGITemplate): 18 | def cgiHeadersHook(self): 19 | return "Content-Type: text/html; charset=koi8-r\n\n" 20 | 21 | To read GET/POST variables, use the .webInput method defined in 22 | Cheetah.Utils.WebInputMixin (available in all templates without importing 23 | anything), use Python's 'cgi' module, or make your own arrangements. 24 | 25 | This class inherits from Cheetah.Template to make it usable in Cheetah's 26 | single-inheritance model. 27 | 28 | 29 | Meta-Data 30 | ================================================================================ 31 | Author: Mike Orr 32 | License: This software is released for unlimited distribution under the 33 | terms of the MIT license. See the LICENSE file. 34 | Version: $Revision: 1.6 $ 35 | Start Date: 2001/10/03 36 | Last Revision Date: $Date: 2006/01/29 02:09:59 $ 37 | """ 38 | __author__ = "Mike Orr " 39 | __revision__ = "$Revision: 1.6 $"[11:-2] 40 | 41 | import os 42 | from Cheetah.Template import Template 43 | 44 | class CGITemplate(Template): 45 | """Methods useful in CGI scripts. 46 | 47 | Any class that inherits this mixin must also inherit Cheetah.Servlet. 48 | """ 49 | 50 | 51 | def cgiHeaders(self): 52 | """Outputs the CGI headers if this is a CGI script. 53 | 54 | Usage: $cgiHeaders#slurp 55 | Override .cgiHeadersHook() if you want to customize the headers. 56 | """ 57 | if self.isCgi(): 58 | return self.cgiHeadersHook() 59 | 60 | 61 | 62 | def cgiHeadersHook(self): 63 | """Override if you want to customize the CGI headers. 64 | """ 65 | return "Content-type: text/html\n\n" 66 | 67 | 68 | def isCgi(self): 69 | """Is this a CGI script? 70 | """ 71 | env = 'REQUEST_METHOD' in os.environ 72 | wk = self._CHEETAH__isControlledByWebKit 73 | return env and not wk 74 | 75 | 76 | 77 | # vim: shiftwidth=4 tabstop=4 expandtab 78 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tools/RecursiveNull.py: -------------------------------------------------------------------------------- 1 | """ 2 | Nothing, but in a friendly way. Good for filling in for objects you want to 3 | hide. If $form.f1 is a RecursiveNull object, then 4 | $form.f1.anything["you"].might("use") will resolve to the empty string. 5 | 6 | This module was contributed by Ian Bicking. 7 | """ 8 | 9 | class RecursiveNull(object): 10 | def __getattr__(self, attr): 11 | return self 12 | def __getitem__(self, item): 13 | return self 14 | def __call__(self, *args, **kwargs): 15 | return self 16 | def __str__(self): 17 | return '' 18 | def __repr__(self): 19 | return '' 20 | def __nonzero__(self): 21 | return 0 22 | def __eq__(self, x): 23 | if x: 24 | return False 25 | return True 26 | def __ne__(self, x): 27 | return x and True or False 28 | 29 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Tools/__init__.py: -------------------------------------------------------------------------------- 1 | """This package contains classes, functions, objects and packages contributed 2 | by Cheetah users. They are not used by Cheetah itself. There is no 3 | guarantee that this directory will be included in Cheetah releases, that 4 | these objects will remain here forever, or that they will remain 5 | backward-compatible. 6 | """ 7 | 8 | # vim: shiftwidth=5 tabstop=5 expandtab 9 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Unspecified.py: -------------------------------------------------------------------------------- 1 | try: 2 | from ds.sys.Unspecified import Unspecified 3 | except ImportError: 4 | class _Unspecified: 5 | def __repr__(self): 6 | return 'Unspecified' 7 | def __str__(self): 8 | return 'Unspecified' 9 | Unspecified = _Unspecified() 10 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Utils/Misc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Miscellaneous functions/objects used by Cheetah but also useful standalone. 4 | """ 5 | import os # Used in mkdirsWithPyInitFile. 6 | import sys # Used in die. 7 | 8 | ################################################## 9 | ## MISCELLANEOUS FUNCTIONS 10 | 11 | def die(reason): 12 | sys.stderr.write(reason + '\n') 13 | sys.exit(1) 14 | 15 | def useOrRaise(thing, errmsg=''): 16 | """Raise 'thing' if it's a subclass of Exception. Otherwise return it. 17 | 18 | Called by: Cheetah.Servlet.cgiImport() 19 | """ 20 | if isinstance(thing, type) and issubclass(thing, Exception): 21 | raise thing(errmsg) 22 | return thing 23 | 24 | 25 | def checkKeywords(dic, legalKeywords, what='argument'): 26 | """Verify no illegal keyword arguments were passed to a function. 27 | 28 | in : dic, dictionary (**kw in the calling routine). 29 | legalKeywords, list of strings, the keywords that are allowed. 30 | what, string, suffix for error message (see function source). 31 | out: None. 32 | exc: TypeError if 'dic' contains a key not in 'legalKeywords'. 33 | called by: Cheetah.Template.__init__() 34 | """ 35 | # XXX legalKeywords could be a set when sets get added to Python. 36 | for k in dic.keys(): # Can be dic.iterkeys() if Python >= 2.2. 37 | if k not in legalKeywords: 38 | raise TypeError("'%s' is not a valid %s" % (k, what)) 39 | 40 | 41 | def removeFromList(list_, *elements): 42 | """Save as list_.remove(each element) but don't raise an error if 43 | element is missing. Modifies 'list_' in place! Returns None. 44 | """ 45 | for elm in elements: 46 | try: 47 | list_.remove(elm) 48 | except ValueError: 49 | pass 50 | 51 | 52 | def mkdirsWithPyInitFiles(path): 53 | """Same as os.makedirs (mkdir 'path' and all missing parent directories) 54 | but also puts a Python '__init__.py' file in every directory it 55 | creates. Does nothing (without creating an '__init__.py' file) if the 56 | directory already exists. 57 | """ 58 | dir, fil = os.path.split(path) 59 | if dir and not os.path.exists(dir): 60 | mkdirsWithPyInitFiles(dir) 61 | if not os.path.exists(path): 62 | os.mkdir(path) 63 | init = os.path.join(path, "__init__.py") 64 | f = open(init, 'w') # Open and close to produce empty file. 65 | f.close() 66 | 67 | # vim: shiftwidth=4 tabstop=4 expandtab 68 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Utils/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Utils/htmlDecode.py: -------------------------------------------------------------------------------- 1 | """This is a copy of the htmlDecode function in Webware. 2 | 3 | @@TR: It implemented more efficiently. 4 | 5 | """ 6 | 7 | from Cheetah.Utils.htmlEncode import htmlCodesReversed 8 | 9 | def htmlDecode(s, codes=htmlCodesReversed): 10 | """ Returns the ASCII decoded version of the given HTML string. This does 11 | NOT remove normal HTML tags like

. It is the inverse of htmlEncode().""" 12 | for code in codes: 13 | s = s.replace(code[1], code[0]) 14 | return s 15 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Utils/htmlEncode.py: -------------------------------------------------------------------------------- 1 | """This is a copy of the htmlEncode function in Webware. 2 | 3 | 4 | @@TR: It implemented more efficiently. 5 | 6 | """ 7 | htmlCodes = [ 8 | ['&', '&'], 9 | ['<', '<'], 10 | ['>', '>'], 11 | ['"', '"'], 12 | ] 13 | htmlCodesReversed = htmlCodes[:] 14 | htmlCodesReversed.reverse() 15 | 16 | def htmlEncode(s, codes=htmlCodes): 17 | """ Returns the HTML encoded version of the given string. This is useful to 18 | display a plain ASCII text string on a web page.""" 19 | for code in codes: 20 | s = s.replace(code[0], code[1]) 21 | return s 22 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/Version.py: -------------------------------------------------------------------------------- 1 | Version = '2.4.4' 2 | VersionTuple = (2, 4, 4, 'development', 0) 3 | 4 | MinCompatibleVersion = '2.0rc6' 5 | MinCompatibleVersionTuple = (2, 0, 0, 'candidate', 6) 6 | 7 | #### 8 | def convertVersionStringToTuple(s): 9 | versionNum = [0, 0, 0] 10 | releaseType = 'final' 11 | releaseTypeSubNum = 0 12 | if s.find('a')!=-1: 13 | num, releaseTypeSubNum = s.split('a') 14 | releaseType = 'alpha' 15 | elif s.find('b')!=-1: 16 | num, releaseTypeSubNum = s.split('b') 17 | releaseType = 'beta' 18 | elif s.find('rc')!=-1: 19 | num, releaseTypeSubNum = s.split('rc') 20 | releaseType = 'candidate' 21 | else: 22 | num = s 23 | num = num.split('.') 24 | for i in range(len(num)): 25 | versionNum[i] = int(num[i]) 26 | if len(versionNum)<3: 27 | versionNum += [0] 28 | releaseTypeSubNum = int(releaseTypeSubNum) 29 | 30 | return tuple(versionNum+[releaseType, releaseTypeSubNum]) 31 | 32 | 33 | if __name__ == '__main__': 34 | c = convertVersionStringToTuple 35 | print(c('2.0a1')) 36 | print(c('2.0b1')) 37 | print(c('2.0rc1')) 38 | print(c('2.0')) 39 | print(c('2.0.2')) 40 | 41 | 42 | assert c('0.9.19b1') < c('0.9.19') 43 | assert c('0.9b1') < c('0.9.19') 44 | 45 | assert c('2.0a2') > c('2.0a1') 46 | assert c('2.0b1') > c('2.0a2') 47 | assert c('2.0b2') > c('2.0b1') 48 | assert c('2.0b2') == c('2.0b2') 49 | 50 | assert c('2.0rc1') > c('2.0b1') 51 | assert c('2.0rc2') > c('2.0rc1') 52 | assert c('2.0rc2') > c('2.0b1') 53 | 54 | assert c('2.0') > c('2.0a1') 55 | assert c('2.0') > c('2.0b1') 56 | assert c('2.0') > c('2.0rc1') 57 | assert c('2.0.1') > c('2.0') 58 | assert c('2.0rc1') > c('2.0b1') 59 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Cheetah is an open source template engine and code generation tool. 3 | 4 | It can be used standalone or combined with other tools and frameworks. Web 5 | development is its principle use, but Cheetah is very flexible and is also being 6 | used to generate C++ game code, Java, sql, form emails and even Python code. 7 | 8 | Homepage 9 | http://www.cheetahtemplate.org/ 10 | 11 | Documentation 12 | http://cheetahtemplate.org/learn.html 13 | 14 | Mailing list 15 | cheetahtemplate-discuss@lists.sourceforge.net 16 | Subscribe at 17 | http://lists.sourceforge.net/lists/listinfo/cheetahtemplate-discuss 18 | ''' 19 | 20 | from Version import * 21 | -------------------------------------------------------------------------------- /lib/site-packages/Cheetah/convertTmplPathToModuleName.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import string 3 | 4 | letters = None 5 | try: 6 | letters = string.ascii_letters 7 | except AttributeError: 8 | letters = string.letters 9 | 10 | l = ['_'] * 256 11 | for c in string.digits + letters: 12 | l[ord(c)] = c 13 | _pathNameTransChars = ''.join(l) 14 | del l, c 15 | 16 | def convertTmplPathToModuleName(tmplPath, 17 | _pathNameTransChars=_pathNameTransChars, 18 | splitdrive=os.path.splitdrive, 19 | ): 20 | return splitdrive(tmplPath)[1].translate(_pathNameTransChars) 21 | -------------------------------------------------------------------------------- /lib/site-packages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/lib/site-packages/__init__.py -------------------------------------------------------------------------------- /lib/site-packages/bs4/tests/__init__.py: -------------------------------------------------------------------------------- 1 | "The beautifulsoup tests." 2 | -------------------------------------------------------------------------------- /lib/site-packages/bs4/tests/test_docs.py: -------------------------------------------------------------------------------- 1 | "Test harness for doctests." 2 | 3 | # pylint: disable-msg=E0611,W0142 4 | 5 | __metaclass__ = type 6 | __all__ = [ 7 | 'additional_tests', 8 | ] 9 | 10 | import atexit 11 | import doctest 12 | import os 13 | #from pkg_resources import ( 14 | # resource_filename, resource_exists, resource_listdir, cleanup_resources) 15 | import unittest 16 | 17 | DOCTEST_FLAGS = ( 18 | doctest.ELLIPSIS | 19 | doctest.NORMALIZE_WHITESPACE | 20 | doctest.REPORT_NDIFF) 21 | 22 | 23 | # def additional_tests(): 24 | # "Run the doc tests (README.txt and docs/*, if any exist)" 25 | # doctest_files = [ 26 | # os.path.abspath(resource_filename('bs4', 'README.txt'))] 27 | # if resource_exists('bs4', 'docs'): 28 | # for name in resource_listdir('bs4', 'docs'): 29 | # if name.endswith('.txt'): 30 | # doctest_files.append( 31 | # os.path.abspath( 32 | # resource_filename('bs4', 'docs/%s' % name))) 33 | # kwargs = dict(module_relative=False, optionflags=DOCTEST_FLAGS) 34 | # atexit.register(cleanup_resources) 35 | # return unittest.TestSuite(( 36 | # doctest.DocFileSuite(*doctest_files, **kwargs))) 37 | -------------------------------------------------------------------------------- /lib/site-packages/bs4/tests/test_html5lib.py: -------------------------------------------------------------------------------- 1 | """Tests to ensure that the html5lib tree builder generates good trees.""" 2 | 3 | import warnings 4 | 5 | try: 6 | from bs4.builder import HTML5TreeBuilder 7 | HTML5LIB_PRESENT = True 8 | except ImportError, e: 9 | HTML5LIB_PRESENT = False 10 | from bs4.element import SoupStrainer 11 | from bs4.testing import ( 12 | HTML5TreeBuilderSmokeTest, 13 | SoupTest, 14 | skipIf, 15 | ) 16 | 17 | @skipIf( 18 | not HTML5LIB_PRESENT, 19 | "html5lib seems not to be present, not testing its tree builder.") 20 | class HTML5LibBuilderSmokeTest(SoupTest, HTML5TreeBuilderSmokeTest): 21 | """See ``HTML5TreeBuilderSmokeTest``.""" 22 | 23 | @property 24 | def default_builder(self): 25 | return HTML5TreeBuilder() 26 | 27 | def test_soupstrainer(self): 28 | # The html5lib tree builder does not support SoupStrainers. 29 | strainer = SoupStrainer("b") 30 | markup = "

A bold statement.

" 31 | with warnings.catch_warnings(record=True) as w: 32 | soup = self.soup(markup, parse_only=strainer) 33 | self.assertEqual( 34 | soup.decode(), self.document_for(markup)) 35 | 36 | self.assertTrue( 37 | "the html5lib tree builder doesn't support parse_only" in 38 | str(w[0].message)) 39 | 40 | def test_correctly_nested_tables(self): 41 | """html5lib inserts tags where other parsers don't.""" 42 | markup = ('' 43 | '' 44 | "') 48 | 49 | self.assertSoupEquals( 50 | markup, 51 | '
Here's another table:" 45 | '' 46 | '' 47 | '
foo
Here\'s another table:' 52 | '
foo
' 53 | '
') 54 | 55 | self.assertSoupEquals( 56 | "" 57 | "" 58 | "
Foo
Bar
Baz
") 59 | 60 | def test_xml_declaration_followed_by_doctype(self): 61 | markup = ''' 62 | 63 | 64 | 65 | 66 | 67 |

foo

68 | 69 | ''' 70 | soup = self.soup(markup) 71 | # Verify that we can reach the

tag; this means the tree is connected. 72 | self.assertEqual(b"

foo

", soup.p.encode()) 73 | 74 | def test_reparented_markup(self): 75 | markup = '

foo

\n

bar

' 76 | soup = self.soup(markup) 77 | self.assertEqual(u"

foo

\n

bar

", soup.body.decode()) 78 | self.assertEqual(2, len(soup.find_all('p'))) 79 | 80 | 81 | def test_reparented_markup_ends_with_whitespace(self): 82 | markup = '

foo

\n

bar

\n' 83 | soup = self.soup(markup) 84 | self.assertEqual(u"

foo

\n

bar

\n", soup.body.decode()) 85 | self.assertEqual(2, len(soup.find_all('p'))) 86 | -------------------------------------------------------------------------------- /lib/site-packages/bs4/tests/test_htmlparser.py: -------------------------------------------------------------------------------- 1 | """Tests to ensure that the html.parser tree builder generates good 2 | trees.""" 3 | 4 | from bs4.testing import SoupTest, HTMLTreeBuilderSmokeTest 5 | from bs4.builder import HTMLParserTreeBuilder 6 | 7 | class HTMLParserTreeBuilderSmokeTest(SoupTest, HTMLTreeBuilderSmokeTest): 8 | 9 | @property 10 | def default_builder(self): 11 | return HTMLParserTreeBuilder() 12 | 13 | def test_namespaced_system_doctype(self): 14 | # html.parser can't handle namespaced doctypes, so skip this one. 15 | pass 16 | 17 | def test_namespaced_public_doctype(self): 18 | # html.parser can't handle namespaced doctypes, so skip this one. 19 | pass 20 | -------------------------------------------------------------------------------- /lib/site-packages/bs4/tests/test_lxml.py: -------------------------------------------------------------------------------- 1 | """Tests to ensure that the lxml tree builder generates good trees.""" 2 | 3 | import re 4 | import warnings 5 | 6 | try: 7 | import lxml.etree 8 | LXML_PRESENT = True 9 | LXML_VERSION = lxml.etree.LXML_VERSION 10 | except ImportError, e: 11 | LXML_PRESENT = False 12 | LXML_VERSION = (0,) 13 | 14 | if LXML_PRESENT: 15 | from bs4.builder import LXMLTreeBuilder, LXMLTreeBuilderForXML 16 | 17 | from bs4 import ( 18 | BeautifulSoup, 19 | BeautifulStoneSoup, 20 | ) 21 | from bs4.element import Comment, Doctype, SoupStrainer 22 | from bs4.testing import skipIf 23 | from bs4.tests import test_htmlparser 24 | from bs4.testing import ( 25 | HTMLTreeBuilderSmokeTest, 26 | XMLTreeBuilderSmokeTest, 27 | SoupTest, 28 | skipIf, 29 | ) 30 | 31 | @skipIf( 32 | not LXML_PRESENT, 33 | "lxml seems not to be present, not testing its tree builder.") 34 | class LXMLTreeBuilderSmokeTest(SoupTest, HTMLTreeBuilderSmokeTest): 35 | """See ``HTMLTreeBuilderSmokeTest``.""" 36 | 37 | @property 38 | def default_builder(self): 39 | return LXMLTreeBuilder() 40 | 41 | def test_out_of_range_entity(self): 42 | self.assertSoupEquals( 43 | "

foo�bar

", "

foobar

") 44 | self.assertSoupEquals( 45 | "

foo�bar

", "

foobar

") 46 | self.assertSoupEquals( 47 | "

foo�bar

", "

foobar

") 48 | 49 | # In lxml < 2.3.5, an empty doctype causes a segfault. Skip this 50 | # test if an old version of lxml is installed. 51 | 52 | @skipIf( 53 | not LXML_PRESENT or LXML_VERSION < (2,3,5,0), 54 | "Skipping doctype test for old version of lxml to avoid segfault.") 55 | def test_empty_doctype(self): 56 | soup = self.soup("") 57 | doctype = soup.contents[0] 58 | self.assertEqual("", doctype.strip()) 59 | 60 | def test_beautifulstonesoup_is_xml_parser(self): 61 | # Make sure that the deprecated BSS class uses an xml builder 62 | # if one is installed. 63 | with warnings.catch_warnings(record=True) as w: 64 | soup = BeautifulStoneSoup("") 65 | self.assertEqual(u"", unicode(soup.b)) 66 | self.assertTrue("BeautifulStoneSoup class is deprecated" in str(w[0].message)) 67 | 68 | def test_real_xhtml_document(self): 69 | """lxml strips the XML definition from an XHTML doc, which is fine.""" 70 | markup = b""" 71 | 72 | 73 | Hello. 74 | Goodbye. 75 | """ 76 | soup = self.soup(markup) 77 | self.assertEqual( 78 | soup.encode("utf-8").replace(b"\n", b''), 79 | markup.replace(b'\n', b'').replace( 80 | b'', b'')) 81 | 82 | 83 | @skipIf( 84 | not LXML_PRESENT, 85 | "lxml seems not to be present, not testing its XML tree builder.") 86 | class LXMLXMLTreeBuilderSmokeTest(SoupTest, XMLTreeBuilderSmokeTest): 87 | """See ``HTMLTreeBuilderSmokeTest``.""" 88 | 89 | @property 90 | def default_builder(self): 91 | return LXMLTreeBuilderForXML() 92 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004-2011, CherryPy Team (team@cherrypy.org) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | * Neither the name of the CherryPy Team nor the names of its contributors 13 | may be used to endorse or promote products derived from this software 14 | without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/_cpwsgi_server.py: -------------------------------------------------------------------------------- 1 | """WSGI server interface (see PEP 333). This adds some CP-specific bits to 2 | the framework-agnostic wsgiserver package. 3 | """ 4 | import sys 5 | 6 | import cherrypy 7 | from cherrypy import wsgiserver 8 | 9 | 10 | class CPWSGIServer(wsgiserver.CherryPyWSGIServer): 11 | """Wrapper for wsgiserver.CherryPyWSGIServer. 12 | 13 | wsgiserver has been designed to not reference CherryPy in any way, 14 | so that it can be used in other frameworks and applications. Therefore, 15 | we wrap it here, so we can set our own mount points from cherrypy.tree 16 | and apply some attributes from config -> cherrypy.server -> wsgiserver. 17 | """ 18 | 19 | def __init__(self, server_adapter=cherrypy.server): 20 | self.server_adapter = server_adapter 21 | self.max_request_header_size = self.server_adapter.max_request_header_size or 0 22 | self.max_request_body_size = self.server_adapter.max_request_body_size or 0 23 | 24 | server_name = (self.server_adapter.socket_host or 25 | self.server_adapter.socket_file or 26 | None) 27 | 28 | self.wsgi_version = self.server_adapter.wsgi_version 29 | s = wsgiserver.CherryPyWSGIServer 30 | s.__init__(self, server_adapter.bind_addr, cherrypy.tree, 31 | self.server_adapter.thread_pool, 32 | server_name, 33 | max = self.server_adapter.thread_pool_max, 34 | request_queue_size = self.server_adapter.socket_queue_size, 35 | timeout = self.server_adapter.socket_timeout, 36 | shutdown_timeout = self.server_adapter.shutdown_timeout, 37 | ) 38 | self.protocol = self.server_adapter.protocol_version 39 | self.nodelay = self.server_adapter.nodelay 40 | 41 | if sys.version_info >= (3, 0): 42 | ssl_module = self.server_adapter.ssl_module or 'builtin' 43 | else: 44 | ssl_module = self.server_adapter.ssl_module or 'pyopenssl' 45 | if self.server_adapter.ssl_context: 46 | adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module) 47 | self.ssl_adapter = adapter_class( 48 | self.server_adapter.ssl_certificate, 49 | self.server_adapter.ssl_private_key, 50 | self.server_adapter.ssl_certificate_chain) 51 | self.ssl_adapter.context = self.server_adapter.ssl_context 52 | elif self.server_adapter.ssl_certificate: 53 | adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module) 54 | self.ssl_adapter = adapter_class( 55 | self.server_adapter.ssl_certificate, 56 | self.server_adapter.ssl_private_key, 57 | self.server_adapter.ssl_certificate_chain) 58 | 59 | self.stats['Enabled'] = getattr(self.server_adapter, 'statistics', False) 60 | 61 | def error_log(self, msg="", level=20, traceback=False): 62 | cherrypy.engine.log(msg, level, traceback) 63 | 64 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/lib/site-packages/cherrypy/favicon.ico -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/lib/__init__.py: -------------------------------------------------------------------------------- 1 | """CherryPy Library""" 2 | 3 | # Deprecated in CherryPy 3.2 -- remove in CherryPy 3.3 4 | from cherrypy.lib.reprconf import unrepr, modules, attributes 5 | 6 | class file_generator(object): 7 | """Yield the given input (a file object) in chunks (default 64k). (Core)""" 8 | 9 | def __init__(self, input, chunkSize=65536): 10 | self.input = input 11 | self.chunkSize = chunkSize 12 | 13 | def __iter__(self): 14 | return self 15 | 16 | def __next__(self): 17 | chunk = self.input.read(self.chunkSize) 18 | if chunk: 19 | return chunk 20 | else: 21 | if hasattr(self.input, 'close'): 22 | self.input.close() 23 | raise StopIteration() 24 | next = __next__ 25 | 26 | def file_generator_limited(fileobj, count, chunk_size=65536): 27 | """Yield the given file object in chunks, stopping after `count` 28 | bytes has been emitted. Default chunk size is 64kB. (Core) 29 | """ 30 | remaining = count 31 | while remaining > 0: 32 | chunk = fileobj.read(min(chunk_size, remaining)) 33 | chunklen = len(chunk) 34 | if chunklen == 0: 35 | return 36 | remaining -= chunklen 37 | yield chunk 38 | 39 | def set_vary_header(response, header_name): 40 | "Add a Vary header to a response" 41 | varies = response.headers.get("Vary", "") 42 | varies = [x.strip() for x in varies.split(",") if x.strip()] 43 | if header_name not in varies: 44 | varies.append(header_name) 45 | response.headers['Vary'] = ", ".join(varies) 46 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/lib/http.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | warnings.warn('cherrypy.lib.http has been deprecated and will be removed ' 3 | 'in CherryPy 3.3 use cherrypy.lib.httputil instead.', 4 | DeprecationWarning) 5 | 6 | from cherrypy.lib.httputil import * 7 | 8 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/lib/xmlrpcutil.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import cherrypy 4 | from cherrypy._cpcompat import ntob 5 | 6 | def get_xmlrpclib(): 7 | try: 8 | import xmlrpc.client as x 9 | except ImportError: 10 | import xmlrpclib as x 11 | return x 12 | 13 | def process_body(): 14 | """Return (params, method) from request body.""" 15 | try: 16 | return get_xmlrpclib().loads(cherrypy.request.body.read()) 17 | except Exception: 18 | return ('ERROR PARAMS', ), 'ERRORMETHOD' 19 | 20 | 21 | def patched_path(path): 22 | """Return 'path', doctored for RPC.""" 23 | if not path.endswith('/'): 24 | path += '/' 25 | if path.startswith('/RPC2/'): 26 | # strip the first /rpc2 27 | path = path[5:] 28 | return path 29 | 30 | 31 | def _set_response(body): 32 | # The XML-RPC spec (http://www.xmlrpc.com/spec) says: 33 | # "Unless there's a lower-level error, always return 200 OK." 34 | # Since Python's xmlrpclib interprets a non-200 response 35 | # as a "Protocol Error", we'll just return 200 every time. 36 | response = cherrypy.response 37 | response.status = '200 OK' 38 | response.body = ntob(body, 'utf-8') 39 | response.headers['Content-Type'] = 'text/xml' 40 | response.headers['Content-Length'] = len(body) 41 | 42 | 43 | def respond(body, encoding='utf-8', allow_none=0): 44 | xmlrpclib = get_xmlrpclib() 45 | if not isinstance(body, xmlrpclib.Fault): 46 | body = (body,) 47 | _set_response(xmlrpclib.dumps(body, methodresponse=1, 48 | encoding=encoding, 49 | allow_none=allow_none)) 50 | 51 | def on_error(*args, **kwargs): 52 | body = str(sys.exc_info()[1]) 53 | xmlrpclib = get_xmlrpclib() 54 | _set_response(xmlrpclib.dumps(xmlrpclib.Fault(1, body))) 55 | 56 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/process/__init__.py: -------------------------------------------------------------------------------- 1 | """Site container for an HTTP server. 2 | 3 | A Web Site Process Bus object is used to connect applications, servers, 4 | and frameworks with site-wide services such as daemonization, process 5 | reload, signal handling, drop privileges, PID file management, logging 6 | for all of these, and many more. 7 | 8 | The 'plugins' module defines a few abstract and concrete services for 9 | use with the bus. Some use tool-specific channels; see the documentation 10 | for each class. 11 | """ 12 | 13 | from cherrypy.process.wspbus import bus 14 | from cherrypy.process import plugins, servers 15 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/scaffold/__init__.py: -------------------------------------------------------------------------------- 1 | """, a CherryPy application. 2 | 3 | Use this as a base for creating new CherryPy applications. When you want 4 | to make a new app, copy and paste this folder to some other location 5 | (maybe site-packages) and rename it to the name of your project, 6 | then tweak as desired. 7 | 8 | Even before any tweaking, this should serve a few demonstration pages. 9 | Change to this directory and run: 10 | 11 | ../cherryd -c site.conf 12 | 13 | """ 14 | 15 | import cherrypy 16 | from cherrypy import tools, url 17 | 18 | import os 19 | local_dir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 20 | 21 | 22 | class Root: 23 | 24 | _cp_config = {'tools.log_tracebacks.on': True, 25 | } 26 | 27 | def index(self): 28 | return """ 29 | Try some other path, 30 | or a default path.
31 | Or, just look at the pretty picture:
32 | 33 | """ % (url("other"), url("else"), 34 | url("files/made_with_cherrypy_small.png")) 35 | index.exposed = True 36 | 37 | def default(self, *args, **kwargs): 38 | return "args: %s kwargs: %s" % (args, kwargs) 39 | default.exposed = True 40 | 41 | def other(self, a=2, b='bananas', c=None): 42 | cherrypy.response.headers['Content-Type'] = 'text/plain' 43 | if c is None: 44 | return "Have %d %s." % (int(a), b) 45 | else: 46 | return "Have %d %s, %s." % (int(a), b, c) 47 | other.exposed = True 48 | 49 | files = cherrypy.tools.staticdir.handler( 50 | section="/files", 51 | dir=os.path.join(local_dir, "static"), 52 | # Ignore .php files, etc. 53 | match=r'\.(css|gif|html?|ico|jpe?g|js|png|swf|xml)$', 54 | ) 55 | 56 | 57 | root = Root() 58 | 59 | # Uncomment the following to use your own favicon instead of CP's default. 60 | #favicon_path = os.path.join(local_dir, "favicon.ico") 61 | #root.favicon_ico = tools.staticfile.handler(filename=favicon_path) 62 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/scaffold/example.conf: -------------------------------------------------------------------------------- 1 | [/] 2 | log.error_file: "error.log" 3 | log.access_file: "access.log" -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/scaffold/site.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | # Uncomment this when you're done developing 3 | #environment: "production" 4 | 5 | server.socket_host: "0.0.0.0" 6 | server.socket_port: 8088 7 | 8 | # Uncomment the following lines to run on HTTPS at the same time 9 | #server.2.socket_host: "0.0.0.0" 10 | #server.2.socket_port: 8433 11 | #server.2.ssl_certificate: '../test/test.pem' 12 | #server.2.ssl_private_key: '../test/test.pem' 13 | 14 | tree.myapp: cherrypy.Application(scaffold.root, "/", "example.conf") 15 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/scaffold/static/made_with_cherrypy_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/lib/site-packages/cherrypy/scaffold/static/made_with_cherrypy_small.png -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/__init__.py: -------------------------------------------------------------------------------- 1 | """Regression test suite for CherryPy. 2 | 3 | Run 'nosetests -s test/' to exercise all tests. 4 | 5 | The '-s' flag instructs nose to output stdout messages, wihch is crucial to 6 | the 'interactive' mode of webtest.py. If you run these tests without the '-s' 7 | flag, don't be surprised if the test seems to hang: it's waiting for your 8 | interactive input. 9 | """ 10 | 11 | import os 12 | import sys 13 | 14 | def newexit(): 15 | os._exit(1) 16 | 17 | def setup(): 18 | # We want to monkey patch sys.exit so that we can get some 19 | # information about where exit is being called. 20 | newexit._old = sys.exit 21 | sys.exit = newexit 22 | 23 | def teardown(): 24 | try: 25 | sys.exit = sys.exit._old 26 | except AttributeError: 27 | sys.exit = sys._exit 28 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/_test_decorators.py: -------------------------------------------------------------------------------- 1 | """Test module for the @-decorator syntax, which is version-specific""" 2 | 3 | from cherrypy import expose, tools 4 | from cherrypy._cpcompat import ntob 5 | 6 | 7 | class ExposeExamples(object): 8 | 9 | @expose 10 | def no_call(self): 11 | return "Mr E. R. Bradshaw" 12 | 13 | @expose() 14 | def call_empty(self): 15 | return "Mrs. B.J. Smegma" 16 | 17 | @expose("call_alias") 18 | def nesbitt(self): 19 | return "Mr Nesbitt" 20 | 21 | @expose(["alias1", "alias2"]) 22 | def andrews(self): 23 | return "Mr Ken Andrews" 24 | 25 | @expose(alias="alias3") 26 | def watson(self): 27 | return "Mr. and Mrs. Watson" 28 | 29 | 30 | class ToolExamples(object): 31 | 32 | @expose 33 | @tools.response_headers(headers=[('Content-Type', 'application/data')]) 34 | def blah(self): 35 | yield ntob("blah") 36 | # This is here to demonstrate that _cp_config = {...} overwrites 37 | # the _cp_config attribute added by the Tool decorator. You have 38 | # to write _cp_config[k] = v or _cp_config.update(...) instead. 39 | blah._cp_config['response.stream'] = True 40 | 41 | 42 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/_test_states_demo.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import time 4 | starttime = time.time() 5 | 6 | import cherrypy 7 | 8 | 9 | class Root: 10 | 11 | def index(self): 12 | return "Hello World" 13 | index.exposed = True 14 | 15 | def mtimes(self): 16 | return repr(cherrypy.engine.publish("Autoreloader", "mtimes")) 17 | mtimes.exposed = True 18 | 19 | def pid(self): 20 | return str(os.getpid()) 21 | pid.exposed = True 22 | 23 | def start(self): 24 | return repr(starttime) 25 | start.exposed = True 26 | 27 | def exit(self): 28 | # This handler might be called before the engine is STARTED if an 29 | # HTTP worker thread handles it before the HTTP server returns 30 | # control to engine.start. We avoid that race condition here 31 | # by waiting for the Bus to be STARTED. 32 | cherrypy.engine.wait(state=cherrypy.engine.states.STARTED) 33 | cherrypy.engine.exit() 34 | exit.exposed = True 35 | 36 | 37 | def unsub_sig(): 38 | cherrypy.log("unsubsig: %s" % cherrypy.config.get('unsubsig', False)) 39 | if cherrypy.config.get('unsubsig', False): 40 | cherrypy.log("Unsubscribing the default cherrypy signal handler") 41 | cherrypy.engine.signal_handler.unsubscribe() 42 | try: 43 | from signal import signal, SIGTERM 44 | except ImportError: 45 | pass 46 | else: 47 | def old_term_handler(signum=None, frame=None): 48 | cherrypy.log("I am an old SIGTERM handler.") 49 | sys.exit(0) 50 | cherrypy.log("Subscribing the new one.") 51 | signal(SIGTERM, old_term_handler) 52 | cherrypy.engine.subscribe('start', unsub_sig, priority=100) 53 | 54 | 55 | def starterror(): 56 | if cherrypy.config.get('starterror', False): 57 | zerodiv = 1 / 0 58 | cherrypy.engine.subscribe('start', starterror, priority=6) 59 | 60 | def log_test_case_name(): 61 | if cherrypy.config.get('test_case_name', False): 62 | cherrypy.log("STARTED FROM: %s" % cherrypy.config.get('test_case_name')) 63 | cherrypy.engine.subscribe('start', log_test_case_name, priority=6) 64 | 65 | 66 | cherrypy.tree.mount(Root(), '/', {'/': {}}) 67 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/checkerdemo.py: -------------------------------------------------------------------------------- 1 | """Demonstration app for cherrypy.checker. 2 | 3 | This application is intentionally broken and badly designed. 4 | To demonstrate the output of the CherryPy Checker, simply execute 5 | this module. 6 | """ 7 | 8 | import os 9 | import cherrypy 10 | thisdir = os.path.dirname(os.path.abspath(__file__)) 11 | 12 | class Root: 13 | pass 14 | 15 | if __name__ == '__main__': 16 | conf = {'/base': {'tools.staticdir.root': thisdir, 17 | # Obsolete key. 18 | 'throw_errors': True, 19 | }, 20 | # This entry should be OK. 21 | '/base/static': {'tools.staticdir.on': True, 22 | 'tools.staticdir.dir': 'static'}, 23 | # Warn on missing folder. 24 | '/base/js': {'tools.staticdir.on': True, 25 | 'tools.staticdir.dir': 'js'}, 26 | # Warn on dir with an abs path even though we provide root. 27 | '/base/static2': {'tools.staticdir.on': True, 28 | 'tools.staticdir.dir': '/static'}, 29 | # Warn on dir with a relative path with no root. 30 | '/static3': {'tools.staticdir.on': True, 31 | 'tools.staticdir.dir': 'static'}, 32 | # Warn on unknown namespace 33 | '/unknown': {'toobles.gzip.on': True}, 34 | # Warn special on cherrypy..* 35 | '/cpknown': {'cherrypy.tools.encode.on': True}, 36 | # Warn on mismatched types 37 | '/conftype': {'request.show_tracebacks': 14}, 38 | # Warn on unknown tool. 39 | '/web': {'tools.unknown.on': True}, 40 | # Warn on server.* in app config. 41 | '/app1': {'server.socket_host': '0.0.0.0'}, 42 | # Warn on 'localhost' 43 | 'global': {'server.socket_host': 'localhost'}, 44 | # Warn on '[name]' 45 | '[/extra_brackets]': {}, 46 | } 47 | cherrypy.quickstart(Root(), config=conf) 48 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/static/dirback.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/lib/site-packages/cherrypy/test/static/dirback.jpg -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/static/index.html: -------------------------------------------------------------------------------- 1 | Hello, world 2 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/style.css: -------------------------------------------------------------------------------- 1 | Dummy stylesheet 2 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/test.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXAIBAAKBgQDBKo554mzIMY+AByUNpaUOP9bJnQ7ZLQe9XgHwoLJR4VzpyZZZ 3 | R9L4WtImEew05FY3Izerfm3MN3+MC0tJ6yQU9sOiU3vBW6RrLIMlfKsnRwBRZ0Kn 4 | da+O6xldVSosu8Ev3z9VZ94iC/ZgKzrH7Mjj/U8/MQO7RBS/LAqee8bFNQIDAQAB 5 | AoGAWOCF0ZrWxn3XMucWq2LNwPKqlvVGwbIwX3cDmX22zmnM4Fy6arXbYh4XlyCj 6 | 9+ofqRrxIFz5k/7tFriTmZ0xag5+Jdx+Kwg0/twiP7XCNKipFogwe1Hznw8OFAoT 7 | enKBdj2+/n2o0Bvo/tDB59m9L/538d46JGQUmJlzMyqYikECQQDyoq+8CtMNvE18 8 | 8VgHcR/KtApxWAjj4HpaHYL637ATjThetUZkW92mgDgowyplthusxdNqhHWyv7E8 9 | tWNdYErZAkEAy85ShTR0M5aWmrE7o0r0SpWInAkNBH9aXQRRARFYsdBtNfRu6I0i 10 | 0lvU9wiu3eF57FMEC86yViZ5UBnQfTu7vQJAVesj/Zt7pwaCDfdMa740OsxMUlyR 11 | MVhhGx4OLpYdPJ8qUecxGQKq13XZ7R1HGyNEY4bd2X80Smq08UFuATfC6QJAH8UB 12 | yBHtKz2GLIcELOg6PIYizW/7v3+6rlVF60yw7sb2vzpjL40QqIn4IKoR2DSVtOkb 13 | 8FtAIX3N21aq0VrGYQJBAIPiaEc2AZ8Bq2GC4F3wOz/BxJ/izvnkiotR12QK4fh5 14 | yjZMhTjWCas5zwHR5PDjlD88AWGDMsZ1PicD4348xJQ= 15 | -----END RSA PRIVATE KEY----- 16 | -----BEGIN CERTIFICATE----- 17 | MIIDxTCCAy6gAwIBAgIJAI18BD7eQxlGMA0GCSqGSIb3DQEBBAUAMIGeMQswCQYD 18 | VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTESMBAGA1UEBxMJU2FuIERpZWdv 19 | MRkwFwYDVQQKExBDaGVycnlQeSBQcm9qZWN0MREwDwYDVQQLEwhkZXYtdGVzdDEW 20 | MBQGA1UEAxMNQ2hlcnJ5UHkgVGVhbTEgMB4GCSqGSIb3DQEJARYRcmVtaUBjaGVy 21 | cnlweS5vcmcwHhcNMDYwOTA5MTkyMDIwWhcNMzQwMTI0MTkyMDIwWjCBnjELMAkG 22 | A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVNhbiBEaWVn 23 | bzEZMBcGA1UEChMQQ2hlcnJ5UHkgUHJvamVjdDERMA8GA1UECxMIZGV2LXRlc3Qx 24 | FjAUBgNVBAMTDUNoZXJyeVB5IFRlYW0xIDAeBgkqhkiG9w0BCQEWEXJlbWlAY2hl 25 | cnJ5cHkub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBKo554mzIMY+A 26 | ByUNpaUOP9bJnQ7ZLQe9XgHwoLJR4VzpyZZZR9L4WtImEew05FY3Izerfm3MN3+M 27 | C0tJ6yQU9sOiU3vBW6RrLIMlfKsnRwBRZ0Knda+O6xldVSosu8Ev3z9VZ94iC/Zg 28 | KzrH7Mjj/U8/MQO7RBS/LAqee8bFNQIDAQABo4IBBzCCAQMwHQYDVR0OBBYEFDIQ 29 | 2feb71tVZCWpU0qJ/Tw+wdtoMIHTBgNVHSMEgcswgciAFDIQ2feb71tVZCWpU0qJ 30 | /Tw+wdtooYGkpIGhMIGeMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5p 31 | YTESMBAGA1UEBxMJU2FuIERpZWdvMRkwFwYDVQQKExBDaGVycnlQeSBQcm9qZWN0 32 | MREwDwYDVQQLEwhkZXYtdGVzdDEWMBQGA1UEAxMNQ2hlcnJ5UHkgVGVhbTEgMB4G 33 | CSqGSIb3DQEJARYRcmVtaUBjaGVycnlweS5vcmeCCQCNfAQ+3kMZRjAMBgNVHRME 34 | BTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAL7AAQz7IePV48ZTAFHKr88ntPALsL5S 35 | 8vHCZPNMevNkLTj3DYUw2BcnENxMjm1kou2F2BkvheBPNZKIhc6z4hAml3ed1xa2 36 | D7w6e6OTcstdK/+KrPDDHeOP1dhMWNs2JE1bNlfF1LiXzYKSXpe88eCKjCXsCT/T 37 | NluCaWQys3MS 38 | -----END CERTIFICATE----- 39 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/test_auth_basic.py: -------------------------------------------------------------------------------- 1 | # This file is part of CherryPy 2 | # -*- coding: utf-8 -*- 3 | # vim:ts=4:sw=4:expandtab:fileencoding=utf-8 4 | 5 | import cherrypy 6 | from cherrypy._cpcompat import md5, ntob 7 | from cherrypy.lib import auth_basic 8 | from cherrypy.test import helper 9 | 10 | 11 | class BasicAuthTest(helper.CPWebCase): 12 | 13 | def setup_server(): 14 | class Root: 15 | def index(self): 16 | return "This is public." 17 | index.exposed = True 18 | 19 | class BasicProtected: 20 | def index(self): 21 | return "Hello %s, you've been authorized." % cherrypy.request.login 22 | index.exposed = True 23 | 24 | class BasicProtected2: 25 | def index(self): 26 | return "Hello %s, you've been authorized." % cherrypy.request.login 27 | index.exposed = True 28 | 29 | userpassdict = {'xuser' : 'xpassword'} 30 | userhashdict = {'xuser' : md5(ntob('xpassword')).hexdigest()} 31 | 32 | def checkpasshash(realm, user, password): 33 | p = userhashdict.get(user) 34 | return p and p == md5(ntob(password)).hexdigest() or False 35 | 36 | conf = {'/basic': {'tools.auth_basic.on': True, 37 | 'tools.auth_basic.realm': 'wonderland', 38 | 'tools.auth_basic.checkpassword': auth_basic.checkpassword_dict(userpassdict)}, 39 | '/basic2': {'tools.auth_basic.on': True, 40 | 'tools.auth_basic.realm': 'wonderland', 41 | 'tools.auth_basic.checkpassword': checkpasshash}, 42 | } 43 | 44 | root = Root() 45 | root.basic = BasicProtected() 46 | root.basic2 = BasicProtected2() 47 | cherrypy.tree.mount(root, config=conf) 48 | setup_server = staticmethod(setup_server) 49 | 50 | def testPublic(self): 51 | self.getPage("/") 52 | self.assertStatus('200 OK') 53 | self.assertHeader('Content-Type', 'text/html;charset=utf-8') 54 | self.assertBody('This is public.') 55 | 56 | def testBasic(self): 57 | self.getPage("/basic/") 58 | self.assertStatus(401) 59 | self.assertHeader('WWW-Authenticate', 'Basic realm="wonderland"') 60 | 61 | self.getPage('/basic/', [('Authorization', 'Basic eHVzZXI6eHBhc3N3b3JX')]) 62 | self.assertStatus(401) 63 | 64 | self.getPage('/basic/', [('Authorization', 'Basic eHVzZXI6eHBhc3N3b3Jk')]) 65 | self.assertStatus('200 OK') 66 | self.assertBody("Hello xuser, you've been authorized.") 67 | 68 | def testBasic2(self): 69 | self.getPage("/basic2/") 70 | self.assertStatus(401) 71 | self.assertHeader('WWW-Authenticate', 'Basic realm="wonderland"') 72 | 73 | self.getPage('/basic2/', [('Authorization', 'Basic eHVzZXI6eHBhc3N3b3JX')]) 74 | self.assertStatus(401) 75 | 76 | self.getPage('/basic2/', [('Authorization', 'Basic eHVzZXI6eHBhc3N3b3Jk')]) 77 | self.assertStatus('200 OK') 78 | self.assertBody("Hello xuser, you've been authorized.") 79 | 80 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/test_httplib.py: -------------------------------------------------------------------------------- 1 | """Tests for cherrypy/lib/httputil.py.""" 2 | 3 | import unittest 4 | from cherrypy.lib import httputil 5 | 6 | 7 | class UtilityTests(unittest.TestCase): 8 | 9 | def test_urljoin(self): 10 | # Test all slash+atom combinations for SCRIPT_NAME and PATH_INFO 11 | self.assertEqual(httputil.urljoin("/sn/", "/pi/"), "/sn/pi/") 12 | self.assertEqual(httputil.urljoin("/sn/", "/pi"), "/sn/pi") 13 | self.assertEqual(httputil.urljoin("/sn/", "/"), "/sn/") 14 | self.assertEqual(httputil.urljoin("/sn/", ""), "/sn/") 15 | self.assertEqual(httputil.urljoin("/sn", "/pi/"), "/sn/pi/") 16 | self.assertEqual(httputil.urljoin("/sn", "/pi"), "/sn/pi") 17 | self.assertEqual(httputil.urljoin("/sn", "/"), "/sn/") 18 | self.assertEqual(httputil.urljoin("/sn", ""), "/sn") 19 | self.assertEqual(httputil.urljoin("/", "/pi/"), "/pi/") 20 | self.assertEqual(httputil.urljoin("/", "/pi"), "/pi") 21 | self.assertEqual(httputil.urljoin("/", "/"), "/") 22 | self.assertEqual(httputil.urljoin("/", ""), "/") 23 | self.assertEqual(httputil.urljoin("", "/pi/"), "/pi/") 24 | self.assertEqual(httputil.urljoin("", "/pi"), "/pi") 25 | self.assertEqual(httputil.urljoin("", "/"), "/") 26 | self.assertEqual(httputil.urljoin("", ""), "/") 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/test_json.py: -------------------------------------------------------------------------------- 1 | import cherrypy 2 | from cherrypy.test import helper 3 | 4 | from cherrypy._cpcompat import json 5 | 6 | class JsonTest(helper.CPWebCase): 7 | def setup_server(): 8 | class Root(object): 9 | def plain(self): 10 | return 'hello' 11 | plain.exposed = True 12 | 13 | def json_string(self): 14 | return 'hello' 15 | json_string.exposed = True 16 | json_string._cp_config = {'tools.json_out.on': True} 17 | 18 | def json_list(self): 19 | return ['a', 'b', 42] 20 | json_list.exposed = True 21 | json_list._cp_config = {'tools.json_out.on': True} 22 | 23 | def json_dict(self): 24 | return {'answer': 42} 25 | json_dict.exposed = True 26 | json_dict._cp_config = {'tools.json_out.on': True} 27 | 28 | def json_post(self): 29 | if cherrypy.request.json == [13, 'c']: 30 | return 'ok' 31 | else: 32 | return 'nok' 33 | json_post.exposed = True 34 | json_post._cp_config = {'tools.json_in.on': True} 35 | 36 | root = Root() 37 | cherrypy.tree.mount(root) 38 | setup_server = staticmethod(setup_server) 39 | 40 | def test_json_output(self): 41 | if json is None: 42 | self.skip("json not found ") 43 | return 44 | 45 | self.getPage("/plain") 46 | self.assertBody("hello") 47 | 48 | self.getPage("/json_string") 49 | self.assertBody('"hello"') 50 | 51 | self.getPage("/json_list") 52 | self.assertBody('["a", "b", 42]') 53 | 54 | self.getPage("/json_dict") 55 | self.assertBody('{"answer": 42}') 56 | 57 | def test_json_input(self): 58 | if json is None: 59 | self.skip("json not found ") 60 | return 61 | 62 | body = '[13, "c"]' 63 | headers = [('Content-Type', 'application/json'), 64 | ('Content-Length', str(len(body)))] 65 | self.getPage("/json_post", method="POST", headers=headers, body=body) 66 | self.assertBody('ok') 67 | 68 | body = '[13, "c"]' 69 | headers = [('Content-Type', 'text/plain'), 70 | ('Content-Length', str(len(body)))] 71 | self.getPage("/json_post", method="POST", headers=headers, body=body) 72 | self.assertStatus(415, 'Expected an application/json content type') 73 | 74 | body = '[13, -]' 75 | headers = [('Content-Type', 'application/json'), 76 | ('Content-Length', str(len(body)))] 77 | self.getPage("/json_post", method="POST", headers=headers, body=body) 78 | self.assertStatus(400, 'Invalid JSON document') 79 | 80 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/test_refleaks.py: -------------------------------------------------------------------------------- 1 | """Tests for refleaks.""" 2 | 3 | from cherrypy._cpcompat import HTTPConnection, HTTPSConnection, ntob 4 | import threading 5 | 6 | import cherrypy 7 | 8 | 9 | data = object() 10 | 11 | 12 | from cherrypy.test import helper 13 | 14 | 15 | class ReferenceTests(helper.CPWebCase): 16 | 17 | def setup_server(): 18 | 19 | class Root: 20 | def index(self, *args, **kwargs): 21 | cherrypy.request.thing = data 22 | return "Hello world!" 23 | index.exposed = True 24 | 25 | cherrypy.tree.mount(Root()) 26 | setup_server = staticmethod(setup_server) 27 | 28 | def test_threadlocal_garbage(self): 29 | success = [] 30 | 31 | def getpage(): 32 | host = '%s:%s' % (self.interface(), self.PORT) 33 | if self.scheme == 'https': 34 | c = HTTPSConnection(host) 35 | else: 36 | c = HTTPConnection(host) 37 | try: 38 | c.putrequest('GET', '/') 39 | c.endheaders() 40 | response = c.getresponse() 41 | body = response.read() 42 | self.assertEqual(response.status, 200) 43 | self.assertEqual(body, ntob("Hello world!")) 44 | finally: 45 | c.close() 46 | success.append(True) 47 | 48 | ITERATIONS = 25 49 | ts = [] 50 | for _ in range(ITERATIONS): 51 | t = threading.Thread(target=getpage) 52 | ts.append(t) 53 | t.start() 54 | 55 | for t in ts: 56 | t.join() 57 | 58 | self.assertEqual(len(success), ITERATIONS) 59 | 60 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/test_routes.py: -------------------------------------------------------------------------------- 1 | import os 2 | curdir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 3 | 4 | import cherrypy 5 | 6 | from cherrypy.test import helper 7 | import nose 8 | 9 | class RoutesDispatchTest(helper.CPWebCase): 10 | 11 | def setup_server(): 12 | 13 | try: 14 | import routes 15 | except ImportError: 16 | raise nose.SkipTest('Install routes to test RoutesDispatcher code') 17 | 18 | class Dummy: 19 | def index(self): 20 | return "I said good day!" 21 | 22 | class City: 23 | 24 | def __init__(self, name): 25 | self.name = name 26 | self.population = 10000 27 | 28 | def index(self, **kwargs): 29 | return "Welcome to %s, pop. %s" % (self.name, self.population) 30 | index._cp_config = {'tools.response_headers.on': True, 31 | 'tools.response_headers.headers': [('Content-Language', 'en-GB')]} 32 | 33 | def update(self, **kwargs): 34 | self.population = kwargs['pop'] 35 | return "OK" 36 | 37 | d = cherrypy.dispatch.RoutesDispatcher() 38 | d.connect(action='index', name='hounslow', route='/hounslow', 39 | controller=City('Hounslow')) 40 | d.connect(name='surbiton', route='/surbiton', controller=City('Surbiton'), 41 | action='index', conditions=dict(method=['GET'])) 42 | d.mapper.connect('/surbiton', controller='surbiton', 43 | action='update', conditions=dict(method=['POST'])) 44 | d.connect('main', ':action', controller=Dummy()) 45 | 46 | conf = {'/': {'request.dispatch': d}} 47 | cherrypy.tree.mount(root=None, config=conf) 48 | setup_server = staticmethod(setup_server) 49 | 50 | def test_Routes_Dispatch(self): 51 | self.getPage("/hounslow") 52 | self.assertStatus("200 OK") 53 | self.assertBody("Welcome to Hounslow, pop. 10000") 54 | 55 | self.getPage("/foo") 56 | self.assertStatus("404 Not Found") 57 | 58 | self.getPage("/surbiton") 59 | self.assertStatus("200 OK") 60 | self.assertBody("Welcome to Surbiton, pop. 10000") 61 | 62 | self.getPage("/surbiton", method="POST", body="pop=1327") 63 | self.assertStatus("200 OK") 64 | self.assertBody("OK") 65 | self.getPage("/surbiton") 66 | self.assertStatus("200 OK") 67 | self.assertHeader("Content-Language", "en-GB") 68 | self.assertBody("Welcome to Surbiton, pop. 1327") 69 | 70 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/test_sessionauthenticate.py: -------------------------------------------------------------------------------- 1 | import cherrypy 2 | from cherrypy.test import helper 3 | 4 | 5 | class SessionAuthenticateTest(helper.CPWebCase): 6 | 7 | def setup_server(): 8 | 9 | def check(username, password): 10 | # Dummy check_username_and_password function 11 | if username != 'test' or password != 'password': 12 | return 'Wrong login/password' 13 | 14 | def augment_params(): 15 | # A simple tool to add some things to request.params 16 | # This is to check to make sure that session_auth can handle request 17 | # params (ticket #780) 18 | cherrypy.request.params["test"] = "test" 19 | 20 | cherrypy.tools.augment_params = cherrypy.Tool('before_handler', 21 | augment_params, None, priority=30) 22 | 23 | class Test: 24 | 25 | _cp_config = {'tools.sessions.on': True, 26 | 'tools.session_auth.on': True, 27 | 'tools.session_auth.check_username_and_password': check, 28 | 'tools.augment_params.on': True, 29 | } 30 | 31 | def index(self, **kwargs): 32 | return "Hi %s, you are logged in" % cherrypy.request.login 33 | index.exposed = True 34 | 35 | cherrypy.tree.mount(Test()) 36 | setup_server = staticmethod(setup_server) 37 | 38 | 39 | def testSessionAuthenticate(self): 40 | # request a page and check for login form 41 | self.getPage('/') 42 | self.assertInBody('
') 43 | 44 | # setup credentials 45 | login_body = 'username=test&password=password&from_page=/' 46 | 47 | # attempt a login 48 | self.getPage('/do_login', method='POST', body=login_body) 49 | self.assertStatus((302, 303)) 50 | 51 | # get the page now that we are logged in 52 | self.getPage('/', self.cookies) 53 | self.assertBody('Hi test, you are logged in') 54 | 55 | # do a logout 56 | self.getPage('/do_logout', self.cookies, method='POST') 57 | self.assertStatus((302, 303)) 58 | 59 | # verify we are logged out 60 | self.getPage('/', self.cookies) 61 | self.assertInBody('') 62 | 63 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/test_wsgi_ns.py: -------------------------------------------------------------------------------- 1 | import cherrypy 2 | from cherrypy._cpcompat import ntob 3 | from cherrypy.test import helper 4 | 5 | 6 | class WSGI_Namespace_Test(helper.CPWebCase): 7 | 8 | def setup_server(): 9 | 10 | class WSGIResponse(object): 11 | 12 | def __init__(self, appresults): 13 | self.appresults = appresults 14 | self.iter = iter(appresults) 15 | 16 | def __iter__(self): 17 | return self 18 | 19 | def next(self): 20 | return self.iter.next() 21 | def __next__(self): 22 | return next(self.iter) 23 | 24 | def close(self): 25 | if hasattr(self.appresults, "close"): 26 | self.appresults.close() 27 | 28 | 29 | class ChangeCase(object): 30 | 31 | def __init__(self, app, to=None): 32 | self.app = app 33 | self.to = to 34 | 35 | def __call__(self, environ, start_response): 36 | res = self.app(environ, start_response) 37 | class CaseResults(WSGIResponse): 38 | def next(this): 39 | return getattr(this.iter.next(), self.to)() 40 | def __next__(this): 41 | return getattr(next(this.iter), self.to)() 42 | return CaseResults(res) 43 | 44 | class Replacer(object): 45 | 46 | def __init__(self, app, map={}): 47 | self.app = app 48 | self.map = map 49 | 50 | def __call__(self, environ, start_response): 51 | res = self.app(environ, start_response) 52 | class ReplaceResults(WSGIResponse): 53 | def next(this): 54 | line = this.iter.next() 55 | for k, v in self.map.iteritems(): 56 | line = line.replace(k, v) 57 | return line 58 | def __next__(this): 59 | line = next(this.iter) 60 | for k, v in self.map.items(): 61 | line = line.replace(k, v) 62 | return line 63 | return ReplaceResults(res) 64 | 65 | class Root(object): 66 | 67 | def index(self): 68 | return "HellO WoRlD!" 69 | index.exposed = True 70 | 71 | 72 | root_conf = {'wsgi.pipeline': [('replace', Replacer)], 73 | 'wsgi.replace.map': {ntob('L'): ntob('X'), 74 | ntob('l'): ntob('r')}, 75 | } 76 | 77 | app = cherrypy.Application(Root()) 78 | app.wsgiapp.pipeline.append(('changecase', ChangeCase)) 79 | app.wsgiapp.config['changecase'] = {'to': 'upper'} 80 | cherrypy.tree.mount(app, config={'/': root_conf}) 81 | setup_server = staticmethod(setup_server) 82 | 83 | 84 | def test_pipeline(self): 85 | if not cherrypy.server.httpserver: 86 | return self.skip() 87 | 88 | self.getPage("/") 89 | # If body is "HEXXO WORXD!", the middleware was applied out of order. 90 | self.assertBody("HERRO WORRD!") 91 | 92 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/test/test_wsgi_vhost.py: -------------------------------------------------------------------------------- 1 | import cherrypy 2 | from cherrypy.test import helper 3 | 4 | 5 | class WSGI_VirtualHost_Test(helper.CPWebCase): 6 | 7 | def setup_server(): 8 | 9 | class ClassOfRoot(object): 10 | 11 | def __init__(self, name): 12 | self.name = name 13 | 14 | def index(self): 15 | return "Welcome to the %s website!" % self.name 16 | index.exposed = True 17 | 18 | 19 | default = cherrypy.Application(None) 20 | 21 | domains = {} 22 | for year in range(1997, 2008): 23 | app = cherrypy.Application(ClassOfRoot('Class of %s' % year)) 24 | domains['www.classof%s.example' % year] = app 25 | 26 | cherrypy.tree.graft(cherrypy._cpwsgi.VirtualHost(default, domains)) 27 | setup_server = staticmethod(setup_server) 28 | 29 | def test_welcome(self): 30 | if not cherrypy.server.using_wsgi: 31 | return self.skip("skipped (not using WSGI)... ") 32 | 33 | for year in range(1997, 2008): 34 | self.getPage("/", headers=[('Host', 'www.classof%s.example' % year)]) 35 | self.assertBody("Welcome to the Class of %s website!" % year) 36 | 37 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/README.txt: -------------------------------------------------------------------------------- 1 | CherryPy Tutorials 2 | ------------------------------------------------------------------------ 3 | 4 | This is a series of tutorials explaining how to develop dynamic web 5 | applications using CherryPy. A couple of notes: 6 | 7 | - Each of these tutorials builds on the ones before it. If you're 8 | new to CherryPy, we recommend you start with 01_helloworld.py and 9 | work your way upwards. :) 10 | 11 | - In most of these tutorials, you will notice that all output is done 12 | by returning normal Python strings, often using simple Python 13 | variable substitution. In most real-world applications, you will 14 | probably want to use a separate template package (like Cheetah, 15 | CherryTemplate or XML/XSL). 16 | 17 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | # This is used in test_config to test unrepr of "from A import B" 3 | thing2 = object() -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/custom_error.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 403 Unauthorized 7 | 8 | 9 |

You can't do that!

10 |

%(message)s

11 |

This is a custom error page that is read from a file.

12 |

%(traceback)s
13 | 14 | 15 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/pdf_file.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/lib/site-packages/cherrypy/tutorial/pdf_file.pdf -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/tut01_helloworld.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tutorial - Hello World 3 | 4 | The most basic (working) CherryPy application possible. 5 | """ 6 | 7 | # Import CherryPy global namespace 8 | import cherrypy 9 | 10 | class HelloWorld: 11 | """ Sample request handler class. """ 12 | 13 | def index(self): 14 | # CherryPy will call this method for the root URI ("/") and send 15 | # its return value to the client. Because this is tutorial 16 | # lesson number 01, we'll just send something really simple. 17 | # How about... 18 | return "Hello world!" 19 | 20 | # Expose the index method through the web. CherryPy will never 21 | # publish methods that don't have the exposed attribute set to True. 22 | index.exposed = True 23 | 24 | 25 | import os.path 26 | tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf') 27 | 28 | if __name__ == '__main__': 29 | # CherryPy always starts with app.root when trying to map request URIs 30 | # to objects, so we need to mount a request handler root. A request 31 | # to '/' will be mapped to HelloWorld().index(). 32 | cherrypy.quickstart(HelloWorld(), config=tutconf) 33 | else: 34 | # This branch is for the test suite; you can ignore it. 35 | cherrypy.tree.mount(HelloWorld(), config=tutconf) 36 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/tut02_expose_methods.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tutorial - Multiple methods 3 | 4 | This tutorial shows you how to link to other methods of your request 5 | handler. 6 | """ 7 | 8 | import cherrypy 9 | 10 | class HelloWorld: 11 | 12 | def index(self): 13 | # Let's link to another method here. 14 | return 'We have an important message for you!' 15 | index.exposed = True 16 | 17 | def showMessage(self): 18 | # Here's the important message! 19 | return "Hello world!" 20 | showMessage.exposed = True 21 | 22 | import os.path 23 | tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf') 24 | 25 | if __name__ == '__main__': 26 | # CherryPy always starts with app.root when trying to map request URIs 27 | # to objects, so we need to mount a request handler root. A request 28 | # to '/' will be mapped to HelloWorld().index(). 29 | cherrypy.quickstart(HelloWorld(), config=tutconf) 30 | else: 31 | # This branch is for the test suite; you can ignore it. 32 | cherrypy.tree.mount(HelloWorld(), config=tutconf) 33 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/tut03_get_and_post.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tutorial - Passing variables 3 | 4 | This tutorial shows you how to pass GET/POST variables to methods. 5 | """ 6 | 7 | import cherrypy 8 | 9 | 10 | class WelcomePage: 11 | 12 | def index(self): 13 | # Ask for the user's name. 14 | return ''' 15 | 16 | What is your name? 17 | 18 | 19 |
''' 20 | index.exposed = True 21 | 22 | def greetUser(self, name = None): 23 | # CherryPy passes all GET and POST variables as method parameters. 24 | # It doesn't make a difference where the variables come from, how 25 | # large their contents are, and so on. 26 | # 27 | # You can define default parameter values as usual. In this 28 | # example, the "name" parameter defaults to None so we can check 29 | # if a name was actually specified. 30 | 31 | if name: 32 | # Greet the user! 33 | return "Hey %s, what's up?" % name 34 | else: 35 | if name is None: 36 | # No name was specified 37 | return 'Please enter your name here.' 38 | else: 39 | return 'No, really, enter your name here.' 40 | greetUser.exposed = True 41 | 42 | 43 | import os.path 44 | tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf') 45 | 46 | if __name__ == '__main__': 47 | # CherryPy always starts with app.root when trying to map request URIs 48 | # to objects, so we need to mount a request handler root. A request 49 | # to '/' will be mapped to HelloWorld().index(). 50 | cherrypy.quickstart(WelcomePage(), config=tutconf) 51 | else: 52 | # This branch is for the test suite; you can ignore it. 53 | cherrypy.tree.mount(WelcomePage(), config=tutconf) 54 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/tut05_derived_objects.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tutorial - Object inheritance 3 | 4 | You are free to derive your request handler classes from any base 5 | class you wish. In most real-world applications, you will probably 6 | want to create a central base class used for all your pages, which takes 7 | care of things like printing a common page header and footer. 8 | """ 9 | 10 | import cherrypy 11 | 12 | 13 | class Page: 14 | # Store the page title in a class attribute 15 | title = 'Untitled Page' 16 | 17 | def header(self): 18 | return ''' 19 | 20 | 21 | %s 22 | 23 | 24 |

%s

25 | ''' % (self.title, self.title) 26 | 27 | def footer(self): 28 | return ''' 29 | 30 | 31 | ''' 32 | 33 | # Note that header and footer don't get their exposed attributes 34 | # set to True. This isn't necessary since the user isn't supposed 35 | # to call header or footer directly; instead, we'll call them from 36 | # within the actually exposed handler methods defined in this 37 | # class' subclasses. 38 | 39 | 40 | class HomePage(Page): 41 | # Different title for this page 42 | title = 'Tutorial 5' 43 | 44 | def __init__(self): 45 | # create a subpage 46 | self.another = AnotherPage() 47 | 48 | def index(self): 49 | # Note that we call the header and footer methods inherited 50 | # from the Page class! 51 | return self.header() + ''' 52 |

53 | Isn't this exciting? There's 54 | another page, too! 55 |

56 | ''' + self.footer() 57 | index.exposed = True 58 | 59 | 60 | class AnotherPage(Page): 61 | title = 'Another Page' 62 | 63 | def index(self): 64 | return self.header() + ''' 65 |

66 | And this is the amazing second page! 67 |

68 | ''' + self.footer() 69 | index.exposed = True 70 | 71 | 72 | import os.path 73 | tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf') 74 | 75 | if __name__ == '__main__': 76 | # CherryPy always starts with app.root when trying to map request URIs 77 | # to objects, so we need to mount a request handler root. A request 78 | # to '/' will be mapped to HelloWorld().index(). 79 | cherrypy.quickstart(HomePage(), config=tutconf) 80 | else: 81 | # This branch is for the test suite; you can ignore it. 82 | cherrypy.tree.mount(HomePage(), config=tutconf) 83 | 84 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/tut06_default_method.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tutorial - The default method 3 | 4 | Request handler objects can implement a method called "default" that 5 | is called when no other suitable method/object could be found. 6 | Essentially, if CherryPy2 can't find a matching request handler object 7 | for the given request URI, it will use the default method of the object 8 | located deepest on the URI path. 9 | 10 | Using this mechanism you can easily simulate virtual URI structures 11 | by parsing the extra URI string, which you can access through 12 | cherrypy.request.virtualPath. 13 | 14 | The application in this tutorial simulates an URI structure looking 15 | like /users/. Since the bit will not be found (as 16 | there are no matching methods), it is handled by the default method. 17 | """ 18 | 19 | import cherrypy 20 | 21 | 22 | class UsersPage: 23 | 24 | def index(self): 25 | # Since this is just a stupid little example, we'll simply 26 | # display a list of links to random, made-up users. In a real 27 | # application, this could be generated from a database result set. 28 | return ''' 29 | Remi Delon
30 | Hendrik Mans
31 | Lorenzo Lamas
32 | ''' 33 | index.exposed = True 34 | 35 | def default(self, user): 36 | # Here we react depending on the virtualPath -- the part of the 37 | # path that could not be mapped to an object method. In a real 38 | # application, we would probably do some database lookups here 39 | # instead of the silly if/elif/else construct. 40 | if user == 'remi': 41 | out = "Remi Delon, CherryPy lead developer" 42 | elif user == 'hendrik': 43 | out = "Hendrik Mans, CherryPy co-developer & crazy German" 44 | elif user == 'lorenzo': 45 | out = "Lorenzo Lamas, famous actor and singer!" 46 | else: 47 | out = "Unknown user. :-(" 48 | 49 | return '%s (back)' % out 50 | default.exposed = True 51 | 52 | 53 | import os.path 54 | tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf') 55 | 56 | if __name__ == '__main__': 57 | # CherryPy always starts with app.root when trying to map request URIs 58 | # to objects, so we need to mount a request handler root. A request 59 | # to '/' will be mapped to HelloWorld().index(). 60 | cherrypy.quickstart(UsersPage(), config=tutconf) 61 | else: 62 | # This branch is for the test suite; you can ignore it. 63 | cherrypy.tree.mount(UsersPage(), config=tutconf) 64 | 65 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/tut07_sessions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tutorial - Sessions 3 | 4 | Storing session data in CherryPy applications is very easy: cherrypy 5 | provides a dictionary called "session" that represents the session 6 | data for the current user. If you use RAM based sessions, you can store 7 | any kind of object into that dictionary; otherwise, you are limited to 8 | objects that can be pickled. 9 | """ 10 | 11 | import cherrypy 12 | 13 | 14 | class HitCounter: 15 | 16 | _cp_config = {'tools.sessions.on': True} 17 | 18 | def index(self): 19 | # Increase the silly hit counter 20 | count = cherrypy.session.get('count', 0) + 1 21 | 22 | # Store the new value in the session dictionary 23 | cherrypy.session['count'] = count 24 | 25 | # And display a silly hit count message! 26 | return ''' 27 | During your current session, you've viewed this 28 | page %s times! Your life is a patio of fun! 29 | ''' % count 30 | index.exposed = True 31 | 32 | 33 | import os.path 34 | tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf') 35 | 36 | if __name__ == '__main__': 37 | # CherryPy always starts with app.root when trying to map request URIs 38 | # to objects, so we need to mount a request handler root. A request 39 | # to '/' will be mapped to HelloWorld().index(). 40 | cherrypy.quickstart(HitCounter(), config=tutconf) 41 | else: 42 | # This branch is for the test suite; you can ignore it. 43 | cherrypy.tree.mount(HitCounter(), config=tutconf) 44 | 45 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/tut08_generators_and_yield.py: -------------------------------------------------------------------------------- 1 | """ 2 | Bonus Tutorial: Using generators to return result bodies 3 | 4 | Instead of returning a complete result string, you can use the yield 5 | statement to return one result part after another. This may be convenient 6 | in situations where using a template package like CherryPy or Cheetah 7 | would be overkill, and messy string concatenation too uncool. ;-) 8 | """ 9 | 10 | import cherrypy 11 | 12 | 13 | class GeneratorDemo: 14 | 15 | def header(self): 16 | return "

Generators rule!

" 17 | 18 | def footer(self): 19 | return "" 20 | 21 | def index(self): 22 | # Let's make up a list of users for presentation purposes 23 | users = ['Remi', 'Carlos', 'Hendrik', 'Lorenzo Lamas'] 24 | 25 | # Every yield line adds one part to the total result body. 26 | yield self.header() 27 | yield "

List of users:

" 28 | 29 | for user in users: 30 | yield "%s
" % user 31 | 32 | yield self.footer() 33 | index.exposed = True 34 | 35 | 36 | import os.path 37 | tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf') 38 | 39 | if __name__ == '__main__': 40 | # CherryPy always starts with app.root when trying to map request URIs 41 | # to objects, so we need to mount a request handler root. A request 42 | # to '/' will be mapped to HelloWorld().index(). 43 | cherrypy.quickstart(GeneratorDemo(), config=tutconf) 44 | else: 45 | # This branch is for the test suite; you can ignore it. 46 | cherrypy.tree.mount(GeneratorDemo(), config=tutconf) 47 | 48 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/tut10_http_errors.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Tutorial: HTTP errors 4 | 5 | HTTPError is used to return an error response to the client. 6 | CherryPy has lots of options regarding how such errors are 7 | logged, displayed, and formatted. 8 | 9 | """ 10 | 11 | import os 12 | localDir = os.path.dirname(__file__) 13 | curpath = os.path.normpath(os.path.join(os.getcwd(), localDir)) 14 | 15 | import cherrypy 16 | 17 | 18 | class HTTPErrorDemo(object): 19 | 20 | # Set a custom response for 403 errors. 21 | _cp_config = {'error_page.403' : os.path.join(curpath, "custom_error.html")} 22 | 23 | def index(self): 24 | # display some links that will result in errors 25 | tracebacks = cherrypy.request.show_tracebacks 26 | if tracebacks: 27 | trace = 'off' 28 | else: 29 | trace = 'on' 30 | 31 | return """ 32 | 33 |

Toggle tracebacks %s

34 |

Click me; I'm a broken link!

35 |

Use a custom error page from a file.

36 |

These errors are explicitly raised by the application:

37 | 43 |

You can also set the response body 44 | when you raise an error.

45 | 46 | """ % trace 47 | index.exposed = True 48 | 49 | def toggleTracebacks(self): 50 | # simple function to toggle tracebacks on and off 51 | tracebacks = cherrypy.request.show_tracebacks 52 | cherrypy.config.update({'request.show_tracebacks': not tracebacks}) 53 | 54 | # redirect back to the index 55 | raise cherrypy.HTTPRedirect('/') 56 | toggleTracebacks.exposed = True 57 | 58 | def error(self, code): 59 | # raise an error based on the get query 60 | raise cherrypy.HTTPError(status = code) 61 | error.exposed = True 62 | 63 | def messageArg(self): 64 | message = ("If you construct an HTTPError with a 'message' " 65 | "argument, it wil be placed on the error page " 66 | "(underneath the status line by default).") 67 | raise cherrypy.HTTPError(500, message=message) 68 | messageArg.exposed = True 69 | 70 | 71 | import os.path 72 | tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf') 73 | 74 | if __name__ == '__main__': 75 | # CherryPy always starts with app.root when trying to map request URIs 76 | # to objects, so we need to mount a request handler root. A request 77 | # to '/' will be mapped to HelloWorld().index(). 78 | cherrypy.quickstart(HTTPErrorDemo(), config=tutconf) 79 | else: 80 | # This branch is for the test suite; you can ignore it. 81 | cherrypy.tree.mount(HTTPErrorDemo(), config=tutconf) 82 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/tutorial/tutorial.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | server.socket_host = "127.0.0.1" 3 | server.socket_port = 8080 4 | server.thread_pool = 10 5 | -------------------------------------------------------------------------------- /lib/site-packages/cherrypy/wsgiserver/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['HTTPRequest', 'HTTPConnection', 'HTTPServer', 2 | 'SizeCheckWrapper', 'KnownLengthRFile', 'ChunkedRFile', 3 | 'MaxSizeExceeded', 'NoSSLError', 'FatalSSLAlert', 4 | 'WorkerThread', 'ThreadPool', 'SSLAdapter', 5 | 'CherryPyWSGIServer', 6 | 'Gateway', 'WSGIGateway', 'WSGIGateway_10', 'WSGIGateway_u0', 7 | 'WSGIPathInfoDispatcher', 'get_ssl_adapter_class'] 8 | 9 | import sys 10 | if sys.version_info < (3, 0): 11 | from wsgiserver2 import * 12 | else: 13 | # Le sigh. Boo for backward-incompatible syntax. 14 | exec('from .wsgiserver3 import *') 15 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/__init__.py: -------------------------------------------------------------------------------- 1 | # sqlalchemy/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | 8 | from .sql import ( 9 | alias, 10 | and_, 11 | asc, 12 | between, 13 | bindparam, 14 | case, 15 | cast, 16 | collate, 17 | delete, 18 | desc, 19 | distinct, 20 | except_, 21 | except_all, 22 | exists, 23 | extract, 24 | false, 25 | func, 26 | insert, 27 | intersect, 28 | intersect_all, 29 | join, 30 | literal, 31 | literal_column, 32 | modifier, 33 | not_, 34 | null, 35 | or_, 36 | outerjoin, 37 | outparam, 38 | over, 39 | select, 40 | subquery, 41 | text, 42 | true, 43 | tuple_, 44 | type_coerce, 45 | union, 46 | union_all, 47 | update, 48 | ) 49 | 50 | from .types import ( 51 | BIGINT, 52 | BINARY, 53 | BLOB, 54 | BOOLEAN, 55 | BigInteger, 56 | Binary, 57 | Boolean, 58 | CHAR, 59 | CLOB, 60 | DATE, 61 | DATETIME, 62 | DECIMAL, 63 | Date, 64 | DateTime, 65 | Enum, 66 | FLOAT, 67 | Float, 68 | INT, 69 | INTEGER, 70 | Integer, 71 | Interval, 72 | LargeBinary, 73 | NCHAR, 74 | NVARCHAR, 75 | NUMERIC, 76 | Numeric, 77 | PickleType, 78 | REAL, 79 | SMALLINT, 80 | SmallInteger, 81 | String, 82 | TEXT, 83 | TIME, 84 | TIMESTAMP, 85 | Text, 86 | Time, 87 | TypeDecorator, 88 | Unicode, 89 | UnicodeText, 90 | VARBINARY, 91 | VARCHAR, 92 | ) 93 | 94 | 95 | from .schema import ( 96 | CheckConstraint, 97 | Column, 98 | ColumnDefault, 99 | Constraint, 100 | DefaultClause, 101 | FetchedValue, 102 | ForeignKey, 103 | ForeignKeyConstraint, 104 | Index, 105 | MetaData, 106 | PassiveDefault, 107 | PrimaryKeyConstraint, 108 | Sequence, 109 | Table, 110 | ThreadLocalMetaData, 111 | UniqueConstraint, 112 | DDL, 113 | ) 114 | 115 | 116 | from .inspection import inspect 117 | from .engine import create_engine, engine_from_config 118 | 119 | __version__ = '0.9.4' 120 | 121 | def __go(lcls): 122 | global __all__ 123 | 124 | from . import events 125 | from . import util as _sa_util 126 | 127 | import inspect as _inspect 128 | 129 | __all__ = sorted(name for name, obj in lcls.items() 130 | if not (name.startswith('_') or _inspect.ismodule(obj))) 131 | 132 | _sa_util.dependencies.resolve_all("sqlalchemy") 133 | __go(locals()) -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/connectors/__init__.py: -------------------------------------------------------------------------------- 1 | # connectors/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | 8 | class Connector(object): 9 | pass 10 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/connectors/zxJDBC.py: -------------------------------------------------------------------------------- 1 | # connectors/zxJDBC.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | import sys 8 | from . import Connector 9 | 10 | 11 | class ZxJDBCConnector(Connector): 12 | driver = 'zxjdbc' 13 | 14 | supports_sane_rowcount = False 15 | supports_sane_multi_rowcount = False 16 | 17 | supports_unicode_binds = True 18 | supports_unicode_statements = sys.version > '2.5.0+' 19 | description_encoding = None 20 | default_paramstyle = 'qmark' 21 | 22 | jdbc_db_name = None 23 | jdbc_driver_name = None 24 | 25 | @classmethod 26 | def dbapi(cls): 27 | from com.ziclix.python.sql import zxJDBC 28 | return zxJDBC 29 | 30 | def _driver_kwargs(self): 31 | """Return kw arg dict to be sent to connect().""" 32 | return {} 33 | 34 | def _create_jdbc_url(self, url): 35 | """Create a JDBC url from a :class:`~sqlalchemy.engine.url.URL`""" 36 | return 'jdbc:%s://%s%s/%s' % (self.jdbc_db_name, url.host, 37 | url.port is not None 38 | and ':%s' % url.port or '', 39 | url.database) 40 | 41 | def create_connect_args(self, url): 42 | opts = self._driver_kwargs() 43 | opts.update(url.query) 44 | return [ 45 | [self._create_jdbc_url(url), 46 | url.username, url.password, 47 | self.jdbc_driver_name], 48 | opts] 49 | 50 | def is_disconnect(self, e, connection, cursor): 51 | if not isinstance(e, self.dbapi.ProgrammingError): 52 | return False 53 | e = str(e) 54 | return 'connection is closed' in e or 'cursor is closed' in e 55 | 56 | def _get_server_version_info(self, connection): 57 | # use connection.connection.dbversion, and parse appropriately 58 | # to get a tuple 59 | raise NotImplementedError() 60 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/databases/__init__.py: -------------------------------------------------------------------------------- 1 | # databases/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """Include imports from the sqlalchemy.dialects package for backwards 8 | compatibility with pre 0.6 versions. 9 | 10 | """ 11 | from ..dialects.sqlite import base as sqlite 12 | from ..dialects.postgresql import base as postgresql 13 | postgres = postgresql 14 | from ..dialects.mysql import base as mysql 15 | from ..dialects.drizzle import base as drizzle 16 | from ..dialects.oracle import base as oracle 17 | from ..dialects.firebird import base as firebird 18 | from ..dialects.mssql import base as mssql 19 | from ..dialects.sybase import base as sybase 20 | 21 | 22 | __all__ = ( 23 | 'drizzle', 24 | 'firebird', 25 | 'mssql', 26 | 'mysql', 27 | 'postgresql', 28 | 'sqlite', 29 | 'oracle', 30 | 'sybase', 31 | ) 32 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/__init__.py: -------------------------------------------------------------------------------- 1 | # dialects/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | __all__ = ( 8 | 'drizzle', 9 | 'firebird', 10 | 'mssql', 11 | 'mysql', 12 | 'oracle', 13 | 'postgresql', 14 | 'sqlite', 15 | 'sybase', 16 | ) 17 | 18 | from .. import util 19 | 20 | def _auto_fn(name): 21 | """default dialect importer. 22 | 23 | plugs into the :class:`.PluginLoader` 24 | as a first-hit system. 25 | 26 | """ 27 | if "." in name: 28 | dialect, driver = name.split(".") 29 | else: 30 | dialect = name 31 | driver = "base" 32 | try: 33 | module = __import__('sqlalchemy.dialects.%s' % (dialect, )).dialects 34 | except ImportError: 35 | return None 36 | 37 | module = getattr(module, dialect) 38 | if hasattr(module, driver): 39 | module = getattr(module, driver) 40 | return lambda: module.dialect 41 | else: 42 | return None 43 | 44 | registry = util.PluginLoader("sqlalchemy.dialects", auto_fn=_auto_fn) 45 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/drizzle/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.dialects.drizzle import base, mysqldb 2 | 3 | base.dialect = mysqldb.dialect 4 | 5 | from sqlalchemy.dialects.drizzle.base import \ 6 | BIGINT, BINARY, BLOB, \ 7 | BOOLEAN, CHAR, DATE, \ 8 | DATETIME, DECIMAL, DOUBLE, \ 9 | ENUM, FLOAT, INTEGER, \ 10 | NUMERIC, REAL, TEXT, \ 11 | TIME, TIMESTAMP, VARBINARY, \ 12 | VARCHAR, dialect 13 | 14 | __all__ = ( 15 | 'BIGINT', 'BINARY', 'BLOB', 16 | 'BOOLEAN', 'CHAR', 'DATE', 17 | 'DATETIME', 'DECIMAL', 'DOUBLE', 18 | 'ENUM', 'FLOAT', 'INTEGER', 19 | 'NUMERIC', 'REAL', 'TEXT', 20 | 'TIME', 'TIMESTAMP', 'VARBINARY', 21 | 'VARCHAR', 'dialect' 22 | ) 23 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/drizzle/mysqldb.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. dialect:: drizzle+mysqldb 3 | :name: MySQL-Python 4 | :dbapi: mysqldb 5 | :connectstring: drizzle+mysqldb://:@[:]/ 6 | :url: http://sourceforge.net/projects/mysql-python 7 | 8 | 9 | """ 10 | 11 | from sqlalchemy.dialects.drizzle.base import ( 12 | DrizzleDialect, 13 | DrizzleExecutionContext, 14 | DrizzleCompiler, 15 | DrizzleIdentifierPreparer) 16 | from sqlalchemy.connectors.mysqldb import ( 17 | MySQLDBExecutionContext, 18 | MySQLDBCompiler, 19 | MySQLDBIdentifierPreparer, 20 | MySQLDBConnector) 21 | 22 | 23 | class DrizzleExecutionContext_mysqldb(MySQLDBExecutionContext, 24 | DrizzleExecutionContext): 25 | pass 26 | 27 | 28 | class DrizzleCompiler_mysqldb(MySQLDBCompiler, DrizzleCompiler): 29 | pass 30 | 31 | 32 | class DrizzleIdentifierPreparer_mysqldb(MySQLDBIdentifierPreparer, 33 | DrizzleIdentifierPreparer): 34 | pass 35 | 36 | 37 | class DrizzleDialect_mysqldb(MySQLDBConnector, DrizzleDialect): 38 | execution_ctx_cls = DrizzleExecutionContext_mysqldb 39 | statement_compiler = DrizzleCompiler_mysqldb 40 | preparer = DrizzleIdentifierPreparer_mysqldb 41 | 42 | def _detect_charset(self, connection): 43 | """Sniff out the character set in use for connection results.""" 44 | 45 | return 'utf8' 46 | 47 | 48 | dialect = DrizzleDialect_mysqldb 49 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/firebird/__init__.py: -------------------------------------------------------------------------------- 1 | # firebird/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from sqlalchemy.dialects.firebird import base, kinterbasdb, fdb 8 | 9 | base.dialect = fdb.dialect 10 | 11 | from sqlalchemy.dialects.firebird.base import \ 12 | SMALLINT, BIGINT, FLOAT, FLOAT, DATE, TIME, \ 13 | TEXT, NUMERIC, FLOAT, TIMESTAMP, VARCHAR, CHAR, BLOB,\ 14 | dialect 15 | 16 | __all__ = ( 17 | 'SMALLINT', 'BIGINT', 'FLOAT', 'FLOAT', 'DATE', 'TIME', 18 | 'TEXT', 'NUMERIC', 'FLOAT', 'TIMESTAMP', 'VARCHAR', 'CHAR', 'BLOB', 19 | 'dialect' 20 | ) 21 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/mssql/__init__.py: -------------------------------------------------------------------------------- 1 | # mssql/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from sqlalchemy.dialects.mssql import base, pyodbc, adodbapi, \ 8 | pymssql, zxjdbc, mxodbc 9 | 10 | base.dialect = pyodbc.dialect 11 | 12 | from sqlalchemy.dialects.mssql.base import \ 13 | INTEGER, BIGINT, SMALLINT, TINYINT, VARCHAR, NVARCHAR, CHAR, \ 14 | NCHAR, TEXT, NTEXT, DECIMAL, NUMERIC, FLOAT, DATETIME,\ 15 | DATETIME2, DATETIMEOFFSET, DATE, TIME, SMALLDATETIME, \ 16 | BINARY, VARBINARY, BIT, REAL, IMAGE, TIMESTAMP,\ 17 | MONEY, SMALLMONEY, UNIQUEIDENTIFIER, SQL_VARIANT, dialect 18 | 19 | 20 | __all__ = ( 21 | 'INTEGER', 'BIGINT', 'SMALLINT', 'TINYINT', 'VARCHAR', 'NVARCHAR', 'CHAR', 22 | 'NCHAR', 'TEXT', 'NTEXT', 'DECIMAL', 'NUMERIC', 'FLOAT', 'DATETIME', 23 | 'DATETIME2', 'DATETIMEOFFSET', 'DATE', 'TIME', 'SMALLDATETIME', 24 | 'BINARY', 'VARBINARY', 'BIT', 'REAL', 'IMAGE', 'TIMESTAMP', 25 | 'MONEY', 'SMALLMONEY', 'UNIQUEIDENTIFIER', 'SQL_VARIANT', 'dialect' 26 | ) 27 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/mssql/adodbapi.py: -------------------------------------------------------------------------------- 1 | # mssql/adodbapi.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """ 8 | .. dialect:: mssql+adodbapi 9 | :name: adodbapi 10 | :dbapi: adodbapi 11 | :connectstring: mssql+adodbapi://:@ 12 | :url: http://adodbapi.sourceforge.net/ 13 | 14 | .. note:: 15 | 16 | The adodbapi dialect is not implemented SQLAlchemy versions 0.6 and 17 | above at this time. 18 | 19 | """ 20 | import datetime 21 | from sqlalchemy import types as sqltypes, util 22 | from sqlalchemy.dialects.mssql.base import MSDateTime, MSDialect 23 | import sys 24 | 25 | 26 | class MSDateTime_adodbapi(MSDateTime): 27 | def result_processor(self, dialect, coltype): 28 | def process(value): 29 | # adodbapi will return datetimes with empty time 30 | # values as datetime.date() objects. 31 | # Promote them back to full datetime.datetime() 32 | if type(value) is datetime.date: 33 | return datetime.datetime(value.year, value.month, value.day) 34 | return value 35 | return process 36 | 37 | 38 | class MSDialect_adodbapi(MSDialect): 39 | supports_sane_rowcount = True 40 | supports_sane_multi_rowcount = True 41 | supports_unicode = sys.maxunicode == 65535 42 | supports_unicode_statements = True 43 | driver = 'adodbapi' 44 | 45 | @classmethod 46 | def import_dbapi(cls): 47 | import adodbapi as module 48 | return module 49 | 50 | colspecs = util.update_copy( 51 | MSDialect.colspecs, 52 | { 53 | sqltypes.DateTime: MSDateTime_adodbapi 54 | } 55 | ) 56 | 57 | def create_connect_args(self, url): 58 | keys = url.query 59 | 60 | connectors = ["Provider=SQLOLEDB"] 61 | if 'port' in keys: 62 | connectors.append("Data Source=%s, %s" % 63 | (keys.get("host"), keys.get("port"))) 64 | else: 65 | connectors.append("Data Source=%s" % keys.get("host")) 66 | connectors.append("Initial Catalog=%s" % keys.get("database")) 67 | user = keys.get("user") 68 | if user: 69 | connectors.append("User Id=%s" % user) 70 | connectors.append("Password=%s" % keys.get("password", "")) 71 | else: 72 | connectors.append("Integrated Security=SSPI") 73 | return [[";".join(connectors)], {}] 74 | 75 | def is_disconnect(self, e, connection, cursor): 76 | return isinstance(e, self.dbapi.adodbapi.DatabaseError) and \ 77 | "'connection failure'" in str(e) 78 | 79 | dialect = MSDialect_adodbapi 80 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/mssql/pymssql.py: -------------------------------------------------------------------------------- 1 | # mssql/pymssql.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """ 8 | .. dialect:: mssql+pymssql 9 | :name: pymssql 10 | :dbapi: pymssql 11 | :connectstring: mssql+pymssql://:@?charset=utf8 12 | :url: http://pymssql.org/ 13 | 14 | pymssql is a Python module that provides a Python DBAPI interface around 15 | `FreeTDS `_. Compatible builds are available for 16 | Linux, MacOSX and Windows platforms. 17 | 18 | """ 19 | from .base import MSDialect 20 | from ... import types as sqltypes, util, processors 21 | import re 22 | 23 | 24 | class _MSNumeric_pymssql(sqltypes.Numeric): 25 | def result_processor(self, dialect, type_): 26 | if not self.asdecimal: 27 | return processors.to_float 28 | else: 29 | return sqltypes.Numeric.result_processor(self, dialect, type_) 30 | 31 | 32 | class MSDialect_pymssql(MSDialect): 33 | supports_sane_rowcount = False 34 | driver = 'pymssql' 35 | 36 | colspecs = util.update_copy( 37 | MSDialect.colspecs, 38 | { 39 | sqltypes.Numeric: _MSNumeric_pymssql, 40 | sqltypes.Float: sqltypes.Float, 41 | } 42 | ) 43 | 44 | @classmethod 45 | def dbapi(cls): 46 | module = __import__('pymssql') 47 | # pymmsql doesn't have a Binary method. we use string 48 | # TODO: monkeypatching here is less than ideal 49 | module.Binary = lambda x: x if hasattr(x, 'decode') else str(x) 50 | 51 | client_ver = tuple(int(x) for x in module.__version__.split(".")) 52 | if client_ver < (1, ): 53 | util.warn("The pymssql dialect expects at least " 54 | "the 1.0 series of the pymssql DBAPI.") 55 | return module 56 | 57 | def __init__(self, **params): 58 | super(MSDialect_pymssql, self).__init__(**params) 59 | self.use_scope_identity = True 60 | 61 | def _get_server_version_info(self, connection): 62 | vers = connection.scalar("select @@version") 63 | m = re.match( 64 | r"Microsoft SQL Server.*? - (\d+).(\d+).(\d+).(\d+)", vers) 65 | if m: 66 | return tuple(int(x) for x in m.group(1, 2, 3, 4)) 67 | else: 68 | return None 69 | 70 | def create_connect_args(self, url): 71 | opts = url.translate_connect_args(username='user') 72 | opts.update(url.query) 73 | port = opts.pop('port', None) 74 | if port and 'host' in opts: 75 | opts['host'] = "%s:%s" % (opts['host'], port) 76 | return [[], opts] 77 | 78 | def is_disconnect(self, e, connection, cursor): 79 | for msg in ( 80 | "Adaptive Server connection timed out", 81 | "Net-Lib error during Connection reset by peer", 82 | "message 20003", # connection timeout 83 | "Error 10054", 84 | "Not connected to any MS SQL server", 85 | "Connection is closed" 86 | ): 87 | if msg in str(e): 88 | return True 89 | else: 90 | return False 91 | 92 | dialect = MSDialect_pymssql 93 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/mssql/zxjdbc.py: -------------------------------------------------------------------------------- 1 | # mssql/zxjdbc.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """ 8 | .. dialect:: mssql+zxjdbc 9 | :name: zxJDBC for Jython 10 | :dbapi: zxjdbc 11 | :connectstring: mssql+zxjdbc://user:pass@host:port/dbname[?key=value&key=value...] 12 | :driverurl: http://jtds.sourceforge.net/ 13 | 14 | 15 | """ 16 | from ...connectors.zxJDBC import ZxJDBCConnector 17 | from .base import MSDialect, MSExecutionContext 18 | from ... import engine 19 | 20 | 21 | class MSExecutionContext_zxjdbc(MSExecutionContext): 22 | 23 | _embedded_scope_identity = False 24 | 25 | def pre_exec(self): 26 | super(MSExecutionContext_zxjdbc, self).pre_exec() 27 | # scope_identity after the fact returns null in jTDS so we must 28 | # embed it 29 | if self._select_lastrowid and self.dialect.use_scope_identity: 30 | self._embedded_scope_identity = True 31 | self.statement += "; SELECT scope_identity()" 32 | 33 | def post_exec(self): 34 | if self._embedded_scope_identity: 35 | while True: 36 | try: 37 | row = self.cursor.fetchall()[0] 38 | break 39 | except self.dialect.dbapi.Error: 40 | self.cursor.nextset() 41 | self._lastrowid = int(row[0]) 42 | 43 | if (self.isinsert or self.isupdate or self.isdelete) and \ 44 | self.compiled.returning: 45 | self._result_proxy = engine.FullyBufferedResultProxy(self) 46 | 47 | if self._enable_identity_insert: 48 | table = self.dialect.identifier_preparer.format_table( 49 | self.compiled.statement.table) 50 | self.cursor.execute("SET IDENTITY_INSERT %s OFF" % table) 51 | 52 | 53 | class MSDialect_zxjdbc(ZxJDBCConnector, MSDialect): 54 | jdbc_db_name = 'jtds:sqlserver' 55 | jdbc_driver_name = 'net.sourceforge.jtds.jdbc.Driver' 56 | 57 | execution_ctx_cls = MSExecutionContext_zxjdbc 58 | 59 | def _get_server_version_info(self, connection): 60 | return tuple( 61 | int(x) 62 | for x in connection.connection.dbversion.split('.') 63 | ) 64 | 65 | dialect = MSDialect_zxjdbc 66 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/mysql/__init__.py: -------------------------------------------------------------------------------- 1 | # mysql/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from . import base, mysqldb, oursql, \ 8 | pyodbc, zxjdbc, mysqlconnector, pymysql,\ 9 | gaerdbms, cymysql 10 | 11 | # default dialect 12 | base.dialect = mysqldb.dialect 13 | 14 | from .base import \ 15 | BIGINT, BINARY, BIT, BLOB, BOOLEAN, CHAR, DATE, DATETIME, \ 16 | DECIMAL, DOUBLE, ENUM, DECIMAL,\ 17 | FLOAT, INTEGER, INTEGER, LONGBLOB, LONGTEXT, MEDIUMBLOB, \ 18 | MEDIUMINT, MEDIUMTEXT, NCHAR, \ 19 | NVARCHAR, NUMERIC, SET, SMALLINT, REAL, TEXT, TIME, TIMESTAMP, \ 20 | TINYBLOB, TINYINT, TINYTEXT,\ 21 | VARBINARY, VARCHAR, YEAR, dialect 22 | 23 | __all__ = ( 24 | 'BIGINT', 'BINARY', 'BIT', 'BLOB', 'BOOLEAN', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'DOUBLE', 25 | 'ENUM', 'DECIMAL', 'FLOAT', 'INTEGER', 'INTEGER', 'LONGBLOB', 'LONGTEXT', 'MEDIUMBLOB', 'MEDIUMINT', 26 | 'MEDIUMTEXT', 'NCHAR', 'NVARCHAR', 'NUMERIC', 'SET', 'SMALLINT', 'REAL', 'TEXT', 'TIME', 'TIMESTAMP', 27 | 'TINYBLOB', 'TINYINT', 'TINYTEXT', 'VARBINARY', 'VARCHAR', 'YEAR', 'dialect' 28 | ) 29 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/mysql/cymysql.py: -------------------------------------------------------------------------------- 1 | # mysql/cymysql.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """ 8 | 9 | .. dialect:: mysql+cymysql 10 | :name: CyMySQL 11 | :dbapi: cymysql 12 | :connectstring: mysql+cymysql://:@/[?] 13 | :url: https://github.com/nakagami/CyMySQL 14 | 15 | """ 16 | import re 17 | 18 | from .mysqldb import MySQLDialect_mysqldb 19 | from .base import (BIT, MySQLDialect) 20 | from ... import util 21 | 22 | class _cymysqlBIT(BIT): 23 | def result_processor(self, dialect, coltype): 24 | """Convert a MySQL's 64 bit, variable length binary string to a long. 25 | """ 26 | 27 | def process(value): 28 | if value is not None: 29 | v = 0 30 | for i in util.iterbytes(value): 31 | v = v << 8 | i 32 | return v 33 | return value 34 | return process 35 | 36 | 37 | class MySQLDialect_cymysql(MySQLDialect_mysqldb): 38 | driver = 'cymysql' 39 | 40 | description_encoding = None 41 | supports_sane_rowcount = True 42 | supports_sane_multi_rowcount = False 43 | supports_unicode_statements = True 44 | 45 | colspecs = util.update_copy( 46 | MySQLDialect.colspecs, 47 | { 48 | BIT: _cymysqlBIT, 49 | } 50 | ) 51 | 52 | @classmethod 53 | def dbapi(cls): 54 | return __import__('cymysql') 55 | 56 | def _get_server_version_info(self, connection): 57 | dbapi_con = connection.connection 58 | version = [] 59 | r = re.compile('[.\-]') 60 | for n in r.split(dbapi_con.server_version): 61 | try: 62 | version.append(int(n)) 63 | except ValueError: 64 | version.append(n) 65 | return tuple(version) 66 | 67 | def _detect_charset(self, connection): 68 | return connection.connection.charset 69 | 70 | def _extract_error_code(self, exception): 71 | return exception.errno 72 | 73 | def is_disconnect(self, e, connection, cursor): 74 | if isinstance(e, self.dbapi.OperationalError): 75 | return self._extract_error_code(e) in \ 76 | (2006, 2013, 2014, 2045, 2055) 77 | elif isinstance(e, self.dbapi.InterfaceError): 78 | # if underlying connection is closed, 79 | # this is the error you get 80 | return True 81 | else: 82 | return False 83 | 84 | dialect = MySQLDialect_cymysql 85 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/mysql/gaerdbms.py: -------------------------------------------------------------------------------- 1 | # mysql/gaerdbms.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | """ 7 | .. dialect:: mysql+gaerdbms 8 | :name: Google Cloud SQL 9 | :dbapi: rdbms 10 | :connectstring: mysql+gaerdbms:///?instance= 11 | :url: https://developers.google.com/appengine/docs/python/cloud-sql/developers-guide 12 | 13 | This dialect is based primarily on the :mod:`.mysql.mysqldb` dialect with minimal 14 | changes. 15 | 16 | .. versionadded:: 0.7.8 17 | 18 | 19 | Pooling 20 | ------- 21 | 22 | Google App Engine connections appear to be randomly recycled, 23 | so the dialect does not pool connections. The :class:`.NullPool` 24 | implementation is installed within the :class:`.Engine` by 25 | default. 26 | 27 | """ 28 | 29 | import os 30 | 31 | from .mysqldb import MySQLDialect_mysqldb 32 | from ...pool import NullPool 33 | import re 34 | 35 | 36 | def _is_dev_environment(): 37 | return os.environ.get('SERVER_SOFTWARE', '').startswith('Development/') 38 | 39 | 40 | class MySQLDialect_gaerdbms(MySQLDialect_mysqldb): 41 | 42 | @classmethod 43 | def dbapi(cls): 44 | # from django: 45 | # http://code.google.com/p/googleappengine/source/ 46 | # browse/trunk/python/google/storage/speckle/ 47 | # python/django/backend/base.py#118 48 | # see also [ticket:2649] 49 | # see also http://stackoverflow.com/q/14224679/34549 50 | from google.appengine.api import apiproxy_stub_map 51 | 52 | if _is_dev_environment(): 53 | from google.appengine.api import rdbms_mysqldb 54 | return rdbms_mysqldb 55 | elif apiproxy_stub_map.apiproxy.GetStub('rdbms'): 56 | from google.storage.speckle.python.api import rdbms_apiproxy 57 | return rdbms_apiproxy 58 | else: 59 | from google.storage.speckle.python.api import rdbms_googleapi 60 | return rdbms_googleapi 61 | 62 | @classmethod 63 | def get_pool_class(cls, url): 64 | # Cloud SQL connections die at any moment 65 | return NullPool 66 | 67 | def create_connect_args(self, url): 68 | opts = url.translate_connect_args() 69 | if not _is_dev_environment(): 70 | # 'dsn' and 'instance' are because we are skipping 71 | # the traditional google.api.rdbms wrapper 72 | opts['dsn'] = '' 73 | opts['instance'] = url.query['instance'] 74 | return [], opts 75 | 76 | def _extract_error_code(self, exception): 77 | match = re.compile(r"^(\d+)L?:|^\((\d+)L?,").match(str(exception)) 78 | # The rdbms api will wrap then re-raise some types of errors 79 | # making this regex return no matches. 80 | code = match.group(1) or match.group(2) if match else None 81 | if code: 82 | return int(code) 83 | 84 | dialect = MySQLDialect_gaerdbms 85 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/mysql/pymysql.py: -------------------------------------------------------------------------------- 1 | # mysql/pymysql.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """ 8 | 9 | .. dialect:: mysql+pymysql 10 | :name: PyMySQL 11 | :dbapi: pymysql 12 | :connectstring: mysql+pymysql://:@/[?] 13 | :url: http://code.google.com/p/pymysql/ 14 | 15 | MySQL-Python Compatibility 16 | -------------------------- 17 | 18 | The pymysql DBAPI is a pure Python port of the MySQL-python (MySQLdb) driver, 19 | and targets 100% compatibility. Most behavioral notes for MySQL-python apply to 20 | the pymysql driver as well. 21 | 22 | """ 23 | 24 | from .mysqldb import MySQLDialect_mysqldb 25 | from ...util import py3k 26 | 27 | class MySQLDialect_pymysql(MySQLDialect_mysqldb): 28 | driver = 'pymysql' 29 | 30 | description_encoding = None 31 | if py3k: 32 | supports_unicode_statements = True 33 | 34 | 35 | @classmethod 36 | def dbapi(cls): 37 | return __import__('pymysql') 38 | 39 | if py3k: 40 | def _extract_error_code(self, exception): 41 | if isinstance(exception.args[0], Exception): 42 | exception = exception.args[0] 43 | return exception.args[0] 44 | 45 | dialect = MySQLDialect_pymysql 46 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/mysql/pyodbc.py: -------------------------------------------------------------------------------- 1 | # mysql/pyodbc.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """ 8 | 9 | 10 | .. dialect:: mysql+pyodbc 11 | :name: PyODBC 12 | :dbapi: pyodbc 13 | :connectstring: mysql+pyodbc://:@ 14 | :url: http://pypi.python.org/pypi/pyodbc/ 15 | 16 | 17 | Limitations 18 | ----------- 19 | 20 | The mysql-pyodbc dialect is subject to unresolved character encoding issues 21 | which exist within the current ODBC drivers available. 22 | (see http://code.google.com/p/pyodbc/issues/detail?id=25). Consider usage 23 | of OurSQL, MySQLdb, or MySQL-connector/Python. 24 | 25 | """ 26 | 27 | from .base import MySQLDialect, MySQLExecutionContext 28 | from ...connectors.pyodbc import PyODBCConnector 29 | from ... import util 30 | import re 31 | 32 | 33 | class MySQLExecutionContext_pyodbc(MySQLExecutionContext): 34 | 35 | def get_lastrowid(self): 36 | cursor = self.create_cursor() 37 | cursor.execute("SELECT LAST_INSERT_ID()") 38 | lastrowid = cursor.fetchone()[0] 39 | cursor.close() 40 | return lastrowid 41 | 42 | 43 | class MySQLDialect_pyodbc(PyODBCConnector, MySQLDialect): 44 | supports_unicode_statements = False 45 | execution_ctx_cls = MySQLExecutionContext_pyodbc 46 | 47 | pyodbc_driver_name = "MySQL" 48 | 49 | def __init__(self, **kw): 50 | # deal with http://code.google.com/p/pyodbc/issues/detail?id=25 51 | kw.setdefault('convert_unicode', True) 52 | super(MySQLDialect_pyodbc, self).__init__(**kw) 53 | 54 | def _detect_charset(self, connection): 55 | """Sniff out the character set in use for connection results.""" 56 | 57 | # Prefer 'character_set_results' for the current connection over the 58 | # value in the driver. SET NAMES or individual variable SETs will 59 | # change the charset without updating the driver's view of the world. 60 | # 61 | # If it's decided that issuing that sort of SQL leaves you SOL, then 62 | # this can prefer the driver value. 63 | rs = connection.execute("SHOW VARIABLES LIKE 'character_set%%'") 64 | opts = dict([(row[0], row[1]) for row in self._compat_fetchall(rs)]) 65 | for key in ('character_set_connection', 'character_set'): 66 | if opts.get(key, None): 67 | return opts[key] 68 | 69 | util.warn("Could not detect the connection character set. Assuming latin1.") 70 | return 'latin1' 71 | 72 | def _extract_error_code(self, exception): 73 | m = re.compile(r"\((\d+)\)").search(str(exception.args)) 74 | c = m.group(1) 75 | if c: 76 | return int(c) 77 | else: 78 | return None 79 | 80 | dialect = MySQLDialect_pyodbc 81 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/oracle/__init__.py: -------------------------------------------------------------------------------- 1 | # oracle/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from sqlalchemy.dialects.oracle import base, cx_oracle, zxjdbc 8 | 9 | base.dialect = cx_oracle.dialect 10 | 11 | from sqlalchemy.dialects.oracle.base import \ 12 | VARCHAR, NVARCHAR, CHAR, DATE, NUMBER,\ 13 | BLOB, BFILE, CLOB, NCLOB, TIMESTAMP, RAW,\ 14 | FLOAT, DOUBLE_PRECISION, LONG, dialect, INTERVAL,\ 15 | VARCHAR2, NVARCHAR2, ROWID, dialect 16 | 17 | 18 | __all__ = ( 19 | 'VARCHAR', 'NVARCHAR', 'CHAR', 'DATE', 'NUMBER', 20 | 'BLOB', 'BFILE', 'CLOB', 'NCLOB', 'TIMESTAMP', 'RAW', 21 | 'FLOAT', 'DOUBLE_PRECISION', 'LONG', 'dialect', 'INTERVAL', 22 | 'VARCHAR2', 'NVARCHAR2', 'ROWID' 23 | ) 24 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/postgres.py: -------------------------------------------------------------------------------- 1 | # dialects/postgres.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | # backwards compat with the old name 8 | from sqlalchemy.util import warn_deprecated 9 | 10 | warn_deprecated( 11 | "The SQLAlchemy PostgreSQL dialect has been renamed from 'postgres' to 'postgresql'. " 12 | "The new URL format is postgresql[+driver]://:@/" 13 | ) 14 | 15 | from sqlalchemy.dialects.postgresql import * 16 | from sqlalchemy.dialects.postgresql import base 17 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/postgresql/__init__.py: -------------------------------------------------------------------------------- 1 | # postgresql/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from . import base, psycopg2, pg8000, pypostgresql, zxjdbc 8 | 9 | base.dialect = psycopg2.dialect 10 | 11 | from .base import \ 12 | INTEGER, BIGINT, SMALLINT, VARCHAR, CHAR, TEXT, NUMERIC, FLOAT, REAL, \ 13 | INET, CIDR, UUID, BIT, MACADDR, DOUBLE_PRECISION, TIMESTAMP, TIME, \ 14 | DATE, BYTEA, BOOLEAN, INTERVAL, ARRAY, ENUM, dialect, array, Any, All, \ 15 | TSVECTOR 16 | from .constraints import ExcludeConstraint 17 | from .hstore import HSTORE, hstore 18 | from .json import JSON, JSONElement 19 | from .ranges import INT4RANGE, INT8RANGE, NUMRANGE, DATERANGE, TSRANGE, \ 20 | TSTZRANGE 21 | 22 | __all__ = ( 23 | 'INTEGER', 'BIGINT', 'SMALLINT', 'VARCHAR', 'CHAR', 'TEXT', 'NUMERIC', 24 | 'FLOAT', 'REAL', 'INET', 'CIDR', 'UUID', 'BIT', 'MACADDR', 25 | 'DOUBLE_PRECISION', 'TIMESTAMP', 'TIME', 'DATE', 'BYTEA', 'BOOLEAN', 26 | 'INTERVAL', 'ARRAY', 'ENUM', 'dialect', 'Any', 'All', 'array', 'HSTORE', 27 | 'hstore', 'INT4RANGE', 'INT8RANGE', 'NUMRANGE', 'DATERANGE', 28 | 'TSRANGE', 'TSTZRANGE', 'json', 'JSON', 'JSONElement' 29 | ) 30 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/postgresql/constraints.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013-2014 the SQLAlchemy authors and contributors 2 | # 3 | # This module is part of SQLAlchemy and is released under 4 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 5 | from sqlalchemy.schema import ColumnCollectionConstraint 6 | from sqlalchemy.sql import expression 7 | 8 | class ExcludeConstraint(ColumnCollectionConstraint): 9 | """A table-level EXCLUDE constraint. 10 | 11 | Defines an EXCLUDE constraint as described in the `postgres 12 | documentation`__. 13 | 14 | __ http://www.postgresql.org/docs/9.0/static/sql-createtable.html#SQL-CREATETABLE-EXCLUDE 15 | """ 16 | 17 | __visit_name__ = 'exclude_constraint' 18 | 19 | where = None 20 | 21 | def __init__(self, *elements, **kw): 22 | """ 23 | :param \*elements: 24 | A sequence of two tuples of the form ``(column, operator)`` where 25 | column must be a column name or Column object and operator must 26 | be a string containing the operator to use. 27 | 28 | :param name: 29 | Optional, the in-database name of this constraint. 30 | 31 | :param deferrable: 32 | Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when 33 | issuing DDL for this constraint. 34 | 35 | :param initially: 36 | Optional string. If set, emit INITIALLY when issuing DDL 37 | for this constraint. 38 | 39 | :param using: 40 | Optional string. If set, emit USING when issuing DDL 41 | for this constraint. Defaults to 'gist'. 42 | 43 | :param where: 44 | Optional string. If set, emit WHERE when issuing DDL 45 | for this constraint. 46 | 47 | """ 48 | ColumnCollectionConstraint.__init__( 49 | self, 50 | *[col for col, op in elements], 51 | name=kw.get('name'), 52 | deferrable=kw.get('deferrable'), 53 | initially=kw.get('initially') 54 | ) 55 | self.operators = {} 56 | for col_or_string, op in elements: 57 | name = getattr(col_or_string, 'name', col_or_string) 58 | self.operators[name] = op 59 | self.using = kw.get('using', 'gist') 60 | where = kw.get('where') 61 | if where: 62 | self.where = expression._literal_as_text(where) 63 | 64 | def copy(self, **kw): 65 | elements = [(col, self.operators[col]) 66 | for col in self.columns.keys()] 67 | c = self.__class__(*elements, 68 | name=self.name, 69 | deferrable=self.deferrable, 70 | initially=self.initially) 71 | c.dispatch._update(self.dispatch) 72 | return c 73 | 74 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/postgresql/pypostgresql.py: -------------------------------------------------------------------------------- 1 | # postgresql/pypostgresql.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """ 8 | .. dialect:: postgresql+pypostgresql 9 | :name: py-postgresql 10 | :dbapi: pypostgresql 11 | :connectstring: postgresql+pypostgresql://user:password@host:port/dbname[?key=value&key=value...] 12 | :url: http://python.projects.pgfoundry.org/ 13 | 14 | 15 | """ 16 | from ... import util 17 | from ... import types as sqltypes 18 | from .base import PGDialect, PGExecutionContext 19 | from ... import processors 20 | 21 | 22 | class PGNumeric(sqltypes.Numeric): 23 | def bind_processor(self, dialect): 24 | return processors.to_str 25 | 26 | def result_processor(self, dialect, coltype): 27 | if self.asdecimal: 28 | return None 29 | else: 30 | return processors.to_float 31 | 32 | 33 | class PGExecutionContext_pypostgresql(PGExecutionContext): 34 | pass 35 | 36 | 37 | class PGDialect_pypostgresql(PGDialect): 38 | driver = 'pypostgresql' 39 | 40 | supports_unicode_statements = True 41 | supports_unicode_binds = True 42 | description_encoding = None 43 | default_paramstyle = 'pyformat' 44 | 45 | # requires trunk version to support sane rowcounts 46 | # TODO: use dbapi version information to set this flag appropriately 47 | supports_sane_rowcount = True 48 | supports_sane_multi_rowcount = False 49 | 50 | execution_ctx_cls = PGExecutionContext_pypostgresql 51 | colspecs = util.update_copy( 52 | PGDialect.colspecs, 53 | { 54 | sqltypes.Numeric: PGNumeric, 55 | 56 | # prevents PGNumeric from being used 57 | sqltypes.Float: sqltypes.Float, 58 | } 59 | ) 60 | 61 | @classmethod 62 | def dbapi(cls): 63 | from postgresql.driver import dbapi20 64 | return dbapi20 65 | 66 | def create_connect_args(self, url): 67 | opts = url.translate_connect_args(username='user') 68 | if 'port' in opts: 69 | opts['port'] = int(opts['port']) 70 | else: 71 | opts['port'] = 5432 72 | opts.update(url.query) 73 | return ([], opts) 74 | 75 | def is_disconnect(self, e, connection, cursor): 76 | return "connection is closed" in str(e) 77 | 78 | dialect = PGDialect_pypostgresql 79 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/postgresql/zxjdbc.py: -------------------------------------------------------------------------------- 1 | # postgresql/zxjdbc.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """ 8 | .. dialect:: postgresql+zxjdbc 9 | :name: zxJDBC for Jython 10 | :dbapi: zxjdbc 11 | :connectstring: postgresql+zxjdbc://scott:tiger@localhost/db 12 | :driverurl: http://jdbc.postgresql.org/ 13 | 14 | 15 | """ 16 | from ...connectors.zxJDBC import ZxJDBCConnector 17 | from .base import PGDialect, PGExecutionContext 18 | 19 | 20 | class PGExecutionContext_zxjdbc(PGExecutionContext): 21 | 22 | def create_cursor(self): 23 | cursor = self._dbapi_connection.cursor() 24 | cursor.datahandler = self.dialect.DataHandler(cursor.datahandler) 25 | return cursor 26 | 27 | 28 | class PGDialect_zxjdbc(ZxJDBCConnector, PGDialect): 29 | jdbc_db_name = 'postgresql' 30 | jdbc_driver_name = 'org.postgresql.Driver' 31 | 32 | execution_ctx_cls = PGExecutionContext_zxjdbc 33 | 34 | supports_native_decimal = True 35 | 36 | def __init__(self, *args, **kwargs): 37 | super(PGDialect_zxjdbc, self).__init__(*args, **kwargs) 38 | from com.ziclix.python.sql.handler import PostgresqlDataHandler 39 | self.DataHandler = PostgresqlDataHandler 40 | 41 | def _get_server_version_info(self, connection): 42 | parts = connection.connection.dbversion.split('.') 43 | return tuple(int(x) for x in parts) 44 | 45 | dialect = PGDialect_zxjdbc 46 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/sqlite/__init__.py: -------------------------------------------------------------------------------- 1 | # sqlite/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from sqlalchemy.dialects.sqlite import base, pysqlite 8 | 9 | # default dialect 10 | base.dialect = pysqlite.dialect 11 | 12 | from sqlalchemy.dialects.sqlite.base import ( 13 | BLOB, BOOLEAN, CHAR, DATE, DATETIME, DECIMAL, FLOAT, INTEGER, REAL, 14 | NUMERIC, SMALLINT, TEXT, TIME, TIMESTAMP, VARCHAR, dialect, 15 | ) 16 | 17 | __all__ = ('BLOB', 'BOOLEAN', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 18 | 'FLOAT', 'INTEGER', 'NUMERIC', 'SMALLINT', 'TEXT', 'TIME', 19 | 'TIMESTAMP', 'VARCHAR', 'REAL', 'dialect') 20 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/sybase/__init__.py: -------------------------------------------------------------------------------- 1 | # sybase/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from sqlalchemy.dialects.sybase import base, pysybase, pyodbc 8 | 9 | # default dialect 10 | base.dialect = pyodbc.dialect 11 | 12 | from .base import CHAR, VARCHAR, TIME, NCHAR, NVARCHAR,\ 13 | TEXT, DATE, DATETIME, FLOAT, NUMERIC,\ 14 | BIGINT, INT, INTEGER, SMALLINT, BINARY,\ 15 | VARBINARY, UNITEXT, UNICHAR, UNIVARCHAR,\ 16 | IMAGE, BIT, MONEY, SMALLMONEY, TINYINT,\ 17 | dialect 18 | 19 | 20 | __all__ = ( 21 | 'CHAR', 'VARCHAR', 'TIME', 'NCHAR', 'NVARCHAR', 22 | 'TEXT', 'DATE', 'DATETIME', 'FLOAT', 'NUMERIC', 23 | 'BIGINT', 'INT', 'INTEGER', 'SMALLINT', 'BINARY', 24 | 'VARBINARY', 'UNITEXT', 'UNICHAR', 'UNIVARCHAR', 25 | 'IMAGE', 'BIT', 'MONEY', 'SMALLMONEY', 'TINYINT', 26 | 'dialect' 27 | ) 28 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/sybase/mxodbc.py: -------------------------------------------------------------------------------- 1 | # sybase/mxodbc.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | """ 7 | 8 | .. dialect:: sybase+mxodbc 9 | :name: mxODBC 10 | :dbapi: mxodbc 11 | :connectstring: sybase+mxodbc://:@ 12 | :url: http://www.egenix.com/ 13 | 14 | .. note:: 15 | 16 | This dialect is a stub only and is likely non functional at this time. 17 | 18 | 19 | """ 20 | from sqlalchemy.dialects.sybase.base import SybaseDialect 21 | from sqlalchemy.dialects.sybase.base import SybaseExecutionContext 22 | from sqlalchemy.connectors.mxodbc import MxODBCConnector 23 | 24 | 25 | class SybaseExecutionContext_mxodbc(SybaseExecutionContext): 26 | pass 27 | 28 | 29 | class SybaseDialect_mxodbc(MxODBCConnector, SybaseDialect): 30 | execution_ctx_cls = SybaseExecutionContext_mxodbc 31 | 32 | dialect = SybaseDialect_mxodbc 33 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/dialects/sybase/pyodbc.py: -------------------------------------------------------------------------------- 1 | # sybase/pyodbc.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """ 8 | .. dialect:: sybase+pyodbc 9 | :name: PyODBC 10 | :dbapi: pyodbc 11 | :connectstring: sybase+pyodbc://:@[/] 12 | :url: http://pypi.python.org/pypi/pyodbc/ 13 | 14 | 15 | Unicode Support 16 | --------------- 17 | 18 | The pyodbc driver currently supports usage of these Sybase types with 19 | Unicode or multibyte strings:: 20 | 21 | CHAR 22 | NCHAR 23 | NVARCHAR 24 | TEXT 25 | VARCHAR 26 | 27 | Currently *not* supported are:: 28 | 29 | UNICHAR 30 | UNITEXT 31 | UNIVARCHAR 32 | 33 | """ 34 | 35 | from sqlalchemy.dialects.sybase.base import SybaseDialect,\ 36 | SybaseExecutionContext 37 | from sqlalchemy.connectors.pyodbc import PyODBCConnector 38 | from sqlalchemy import types as sqltypes, processors 39 | import decimal 40 | 41 | 42 | class _SybNumeric_pyodbc(sqltypes.Numeric): 43 | """Turns Decimals with adjusted() < -6 into floats. 44 | 45 | It's not yet known how to get decimals with many 46 | significant digits or very large adjusted() into Sybase 47 | via pyodbc. 48 | 49 | """ 50 | 51 | def bind_processor(self, dialect): 52 | super_process = super(_SybNumeric_pyodbc, self).\ 53 | bind_processor(dialect) 54 | 55 | def process(value): 56 | if self.asdecimal and \ 57 | isinstance(value, decimal.Decimal): 58 | 59 | if value.adjusted() < -6: 60 | return processors.to_float(value) 61 | 62 | if super_process: 63 | return super_process(value) 64 | else: 65 | return value 66 | return process 67 | 68 | 69 | class SybaseExecutionContext_pyodbc(SybaseExecutionContext): 70 | def set_ddl_autocommit(self, connection, value): 71 | if value: 72 | connection.autocommit = True 73 | else: 74 | connection.autocommit = False 75 | 76 | 77 | class SybaseDialect_pyodbc(PyODBCConnector, SybaseDialect): 78 | execution_ctx_cls = SybaseExecutionContext_pyodbc 79 | 80 | colspecs = { 81 | sqltypes.Numeric: _SybNumeric_pyodbc, 82 | } 83 | 84 | dialect = SybaseDialect_pyodbc 85 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/engine/util.py: -------------------------------------------------------------------------------- 1 | # engine/util.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from .. import util 8 | 9 | def connection_memoize(key): 10 | """Decorator, memoize a function in a connection.info stash. 11 | 12 | Only applicable to functions which take no arguments other than a 13 | connection. The memo will be stored in ``connection.info[key]``. 14 | """ 15 | 16 | @util.decorator 17 | def decorated(fn, self, connection): 18 | connection = connection.connect() 19 | try: 20 | return connection.info[key] 21 | except KeyError: 22 | connection.info[key] = val = fn(self, connection) 23 | return val 24 | 25 | return decorated 26 | 27 | 28 | def py_fallback(): 29 | def _distill_params(multiparams, params): 30 | """Given arguments from the calling form *multiparams, **params, 31 | return a list of bind parameter structures, usually a list of 32 | dictionaries. 33 | 34 | In the case of 'raw' execution which accepts positional parameters, 35 | it may be a list of tuples or lists. 36 | 37 | """ 38 | 39 | if not multiparams: 40 | if params: 41 | return [params] 42 | else: 43 | return [] 44 | elif len(multiparams) == 1: 45 | zero = multiparams[0] 46 | if isinstance(zero, (list, tuple)): 47 | if not zero or hasattr(zero[0], '__iter__') and \ 48 | not hasattr(zero[0], 'strip'): 49 | # execute(stmt, [{}, {}, {}, ...]) 50 | # execute(stmt, [(), (), (), ...]) 51 | return zero 52 | else: 53 | # execute(stmt, ("value", "value")) 54 | return [zero] 55 | elif hasattr(zero, 'keys'): 56 | # execute(stmt, {"key":"value"}) 57 | return [zero] 58 | else: 59 | # execute(stmt, "value") 60 | return [[zero]] 61 | else: 62 | if hasattr(multiparams[0], '__iter__') and \ 63 | not hasattr(multiparams[0], 'strip'): 64 | return multiparams 65 | else: 66 | return [multiparams] 67 | 68 | return locals() 69 | try: 70 | from sqlalchemy.cutils import _distill_params 71 | except ImportError: 72 | globals().update(py_fallback()) 73 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/event/__init__.py: -------------------------------------------------------------------------------- 1 | # event/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from .api import CANCEL, NO_RETVAL, listen, listens_for, remove, contains 8 | from .base import Events, dispatcher 9 | from .attr import RefCollection 10 | from .legacy import _legacy_signature 11 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/ext/__init__.py: -------------------------------------------------------------------------------- 1 | # ext/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/schema.py: -------------------------------------------------------------------------------- 1 | # schema.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """Compatiblity namespace for sqlalchemy.sql.schema and related. 8 | 9 | """ 10 | 11 | from .sql.base import ( 12 | SchemaVisitor 13 | ) 14 | 15 | 16 | from .sql.schema import ( 17 | CheckConstraint, 18 | Column, 19 | ColumnDefault, 20 | Constraint, 21 | DefaultClause, 22 | DefaultGenerator, 23 | FetchedValue, 24 | ForeignKey, 25 | ForeignKeyConstraint, 26 | Index, 27 | MetaData, 28 | PassiveDefault, 29 | PrimaryKeyConstraint, 30 | SchemaItem, 31 | Sequence, 32 | Table, 33 | ThreadLocalMetaData, 34 | UniqueConstraint, 35 | _get_table_key, 36 | ColumnCollectionConstraint, 37 | ) 38 | 39 | 40 | from .sql.naming import conv 41 | 42 | 43 | from .sql.ddl import ( 44 | DDL, 45 | CreateTable, 46 | DropTable, 47 | CreateSequence, 48 | DropSequence, 49 | CreateIndex, 50 | DropIndex, 51 | CreateSchema, 52 | DropSchema, 53 | _DropView, 54 | CreateColumn, 55 | AddConstraint, 56 | DropConstraint, 57 | DDLBase, 58 | DDLElement, 59 | _CreateDropBase, 60 | _DDLCompiles 61 | ) 62 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/sql/__init__.py: -------------------------------------------------------------------------------- 1 | # sql/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from .expression import ( 8 | Alias, 9 | ClauseElement, 10 | ColumnCollection, 11 | ColumnElement, 12 | CompoundSelect, 13 | Delete, 14 | FromClause, 15 | Insert, 16 | Join, 17 | Select, 18 | Selectable, 19 | TableClause, 20 | Update, 21 | alias, 22 | and_, 23 | asc, 24 | between, 25 | bindparam, 26 | case, 27 | cast, 28 | collate, 29 | column, 30 | delete, 31 | desc, 32 | distinct, 33 | except_, 34 | except_all, 35 | exists, 36 | extract, 37 | false, 38 | False_, 39 | func, 40 | insert, 41 | intersect, 42 | intersect_all, 43 | join, 44 | label, 45 | literal, 46 | literal_column, 47 | modifier, 48 | not_, 49 | null, 50 | or_, 51 | outerjoin, 52 | outparam, 53 | over, 54 | select, 55 | subquery, 56 | table, 57 | text, 58 | true, 59 | True_, 60 | tuple_, 61 | type_coerce, 62 | union, 63 | union_all, 64 | update, 65 | ) 66 | 67 | from .visitors import ClauseVisitor 68 | 69 | def __go(lcls): 70 | global __all__ 71 | from .. import util as _sa_util 72 | 73 | import inspect as _inspect 74 | 75 | __all__ = sorted(name for name, obj in lcls.items() 76 | if not (name.startswith('_') or _inspect.ismodule(obj))) 77 | 78 | from .annotation import _prepare_annotations, Annotated 79 | from .elements import AnnotatedColumnElement, ClauseList 80 | from .selectable import AnnotatedFromClause 81 | _prepare_annotations(ColumnElement, AnnotatedColumnElement) 82 | _prepare_annotations(FromClause, AnnotatedFromClause) 83 | _prepare_annotations(ClauseList, Annotated) 84 | 85 | _sa_util.dependencies.resolve_all("sqlalchemy.sql") 86 | 87 | from . import naming 88 | 89 | __go(locals()) 90 | 91 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/__init__.py: -------------------------------------------------------------------------------- 1 | # testing/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | 8 | from .warnings import testing_warn, assert_warnings, resetwarnings 9 | 10 | from . import config 11 | 12 | from .exclusions import db_spec, _is_excluded, fails_if, skip_if, future,\ 13 | fails_on, fails_on_everything_except, skip, only_on, exclude, \ 14 | against as _against, _server_version, only_if 15 | 16 | 17 | def against(*queries): 18 | return _against(config._current, *queries) 19 | 20 | from .assertions import emits_warning, emits_warning_on, uses_deprecated, \ 21 | eq_, ne_, is_, is_not_, startswith_, assert_raises, \ 22 | assert_raises_message, AssertsCompiledSQL, ComparesTables, \ 23 | AssertsExecutionResults, expect_deprecated 24 | 25 | from .util import run_as_contextmanager, rowset, fail, provide_metadata, adict 26 | 27 | crashes = skip 28 | 29 | from .config import db 30 | from .config import requirements as requires 31 | 32 | from . import mock -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/config.py: -------------------------------------------------------------------------------- 1 | # testing/config.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | import collections 8 | 9 | requirements = None 10 | db = None 11 | db_url = None 12 | db_opts = None 13 | file_config = None 14 | 15 | _current = None 16 | 17 | class Config(object): 18 | def __init__(self, db, db_opts, options, file_config): 19 | self.db = db 20 | self.db_opts = db_opts 21 | self.options = options 22 | self.file_config = file_config 23 | 24 | _stack = collections.deque() 25 | _configs = {} 26 | 27 | @classmethod 28 | def register(cls, db, db_opts, options, file_config, namespace): 29 | """add a config as one of the global configs. 30 | 31 | If there are no configs set up yet, this config also 32 | gets set as the "_current". 33 | """ 34 | cfg = Config(db, db_opts, options, file_config) 35 | 36 | global _current 37 | if not _current: 38 | cls.set_as_current(cfg, namespace) 39 | cls._configs[cfg.db.name] = cfg 40 | cls._configs[(cfg.db.name, cfg.db.dialect)] = cfg 41 | cls._configs[cfg.db] = cfg 42 | 43 | @classmethod 44 | def set_as_current(cls, config, namespace): 45 | global db, _current, db_url 46 | _current = config 47 | db_url = config.db.url 48 | namespace.db = db = config.db 49 | 50 | @classmethod 51 | def push_engine(cls, db, namespace): 52 | assert _current, "Can't push without a default Config set up" 53 | cls.push( 54 | Config(db, _current.db_opts, _current.options, _current.file_config), 55 | namespace 56 | ) 57 | 58 | @classmethod 59 | def push(cls, config, namespace): 60 | cls._stack.append(_current) 61 | cls.set_as_current(config, namespace) 62 | 63 | @classmethod 64 | def reset(cls, namespace): 65 | if cls._stack: 66 | cls.set_as_current(cls._stack[0], namespace) 67 | cls._stack.clear() 68 | 69 | @classmethod 70 | def all_configs(cls): 71 | for cfg in set(cls._configs.values()): 72 | yield cfg 73 | 74 | @classmethod 75 | def all_dbs(cls): 76 | for cfg in cls.all_configs(): 77 | yield cfg.db 78 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/mock.py: -------------------------------------------------------------------------------- 1 | # testing/mock.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """Import stub for mock library. 8 | """ 9 | from __future__ import absolute_import 10 | from ..util import py33 11 | 12 | if py33: 13 | from unittest.mock import MagicMock, Mock, call, patch 14 | else: 15 | try: 16 | from mock import MagicMock, Mock, call, patch 17 | except ImportError: 18 | raise ImportError( 19 | "SQLAlchemy's test suite requires the " 20 | "'mock' library as of 0.8.2.") 21 | 22 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/pickleable.py: -------------------------------------------------------------------------------- 1 | # testing/pickleable.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """Classes used in pickling tests, need to be at the module level for 8 | unpickling. 9 | """ 10 | 11 | from . import fixtures 12 | 13 | 14 | class User(fixtures.ComparableEntity): 15 | pass 16 | 17 | 18 | class Order(fixtures.ComparableEntity): 19 | pass 20 | 21 | 22 | class Dingaling(fixtures.ComparableEntity): 23 | pass 24 | 25 | 26 | class EmailUser(User): 27 | pass 28 | 29 | 30 | class Address(fixtures.ComparableEntity): 31 | pass 32 | 33 | 34 | # TODO: these are kind of arbitrary.... 35 | class Child1(fixtures.ComparableEntity): 36 | pass 37 | 38 | 39 | class Child2(fixtures.ComparableEntity): 40 | pass 41 | 42 | 43 | class Parent(fixtures.ComparableEntity): 44 | pass 45 | 46 | 47 | class Screen(object): 48 | 49 | def __init__(self, obj, parent=None): 50 | self.obj = obj 51 | self.parent = parent 52 | 53 | 54 | class Foo(object): 55 | 56 | def __init__(self, moredata): 57 | self.data = 'im data' 58 | self.stuff = 'im stuff' 59 | self.moredata = moredata 60 | 61 | __hash__ = object.__hash__ 62 | 63 | def __eq__(self, other): 64 | return other.data == self.data and \ 65 | other.stuff == self.stuff and \ 66 | other.moredata == self.moredata 67 | 68 | 69 | class Bar(object): 70 | 71 | def __init__(self, x, y): 72 | self.x = x 73 | self.y = y 74 | 75 | __hash__ = object.__hash__ 76 | 77 | def __eq__(self, other): 78 | return other.__class__ is self.__class__ and \ 79 | other.x == self.x and \ 80 | other.y == self.y 81 | 82 | def __str__(self): 83 | return "Bar(%d, %d)" % (self.x, self.y) 84 | 85 | 86 | class OldSchool: 87 | 88 | def __init__(self, x, y): 89 | self.x = x 90 | self.y = y 91 | 92 | def __eq__(self, other): 93 | return other.__class__ is self.__class__ and \ 94 | other.x == self.x and \ 95 | other.y == self.y 96 | 97 | 98 | class OldSchoolWithoutCompare: 99 | 100 | def __init__(self, x, y): 101 | self.x = x 102 | self.y = y 103 | 104 | 105 | class BarWithoutCompare(object): 106 | 107 | def __init__(self, x, y): 108 | self.x = x 109 | self.y = y 110 | 111 | def __str__(self): 112 | return "Bar(%d, %d)" % (self.x, self.y) 113 | 114 | 115 | class NotComparable(object): 116 | 117 | def __init__(self, data): 118 | self.data = data 119 | 120 | def __hash__(self): 121 | return id(self) 122 | 123 | def __eq__(self, other): 124 | return NotImplemented 125 | 126 | def __ne__(self, other): 127 | return NotImplemented 128 | 129 | 130 | class BrokenComparable(object): 131 | 132 | def __init__(self, data): 133 | self.data = data 134 | 135 | def __hash__(self): 136 | return id(self) 137 | 138 | def __eq__(self, other): 139 | raise NotImplementedError 140 | 141 | def __ne__(self, other): 142 | raise NotImplementedError 143 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/plugin/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binhex/moviegrabber/f7c737ce3b6dcae003d89cf386a8b729c20d86ad/lib/site-packages/sqlalchemy/testing/plugin/__init__.py -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/plugin/noseplugin.py: -------------------------------------------------------------------------------- 1 | # plugin/noseplugin.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """Enhance nose with extra options and behaviors for running SQLAlchemy tests. 8 | 9 | Must be run via ./sqla_nose.py so that it is imported in the expected 10 | way (e.g. as a package-less import). 11 | 12 | """ 13 | 14 | import os 15 | 16 | from nose.plugins import Plugin 17 | fixtures = None 18 | 19 | # no package imports yet! this prevents us from tripping coverage 20 | # too soon. 21 | import imp 22 | path = os.path.join(os.path.dirname(__file__), "plugin_base.py") 23 | plugin_base = imp.load_source("plugin_base", path) 24 | 25 | 26 | class NoseSQLAlchemy(Plugin): 27 | enabled = True 28 | 29 | name = 'sqla_testing' 30 | score = 100 31 | 32 | def options(self, parser, env=os.environ): 33 | Plugin.options(self, parser, env) 34 | opt = parser.add_option 35 | 36 | def make_option(name, **kw): 37 | callback_ = kw.pop("callback", None) 38 | if callback_: 39 | def wrap_(option, opt_str, value, parser): 40 | callback_(opt_str, value, parser) 41 | kw["callback"] = wrap_ 42 | opt(name, **kw) 43 | 44 | plugin_base.setup_options(make_option) 45 | plugin_base.read_config() 46 | 47 | def configure(self, options, conf): 48 | super(NoseSQLAlchemy, self).configure(options, conf) 49 | plugin_base.pre_begin(options) 50 | 51 | plugin_base.set_coverage_flag(options.enable_plugin_coverage) 52 | 53 | global fixtures 54 | from sqlalchemy.testing import fixtures 55 | 56 | def begin(self): 57 | plugin_base.post_begin() 58 | 59 | def describeTest(self, test): 60 | return "" 61 | 62 | def wantFunction(self, fn): 63 | if fn.__module__ is None: 64 | return False 65 | if fn.__module__.startswith('sqlalchemy.testing'): 66 | return False 67 | 68 | def wantClass(self, cls): 69 | return plugin_base.want_class(cls) 70 | 71 | def beforeTest(self, test): 72 | plugin_base.before_test(test, 73 | test.test.cls.__module__, 74 | test.test.cls, test.test.method.__name__) 75 | 76 | def afterTest(self, test): 77 | plugin_base.after_test(test) 78 | 79 | def startContext(self, ctx): 80 | if not isinstance(ctx, type) \ 81 | or not issubclass(ctx, fixtures.TestBase): 82 | return 83 | plugin_base.start_test_class(ctx) 84 | 85 | def stopContext(self, ctx): 86 | if not isinstance(ctx, type) \ 87 | or not issubclass(ctx, fixtures.TestBase): 88 | return 89 | plugin_base.stop_test_class(ctx) 90 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/runner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # testing/runner.py 3 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 4 | # 5 | # This module is part of SQLAlchemy and is released under 6 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 7 | """ 8 | Nose test runner module. 9 | 10 | This script is a front-end to "nosetests" which 11 | installs SQLAlchemy's testing plugin into the local environment. 12 | 13 | The script is intended to be used by third-party dialects and extensions 14 | that run within SQLAlchemy's testing framework. The runner can 15 | be invoked via:: 16 | 17 | python -m sqlalchemy.testing.runner 18 | 19 | The script is then essentially the same as the "nosetests" script, including 20 | all of the usual Nose options. The test environment requires that a 21 | setup.cfg is locally present including various required options. 22 | 23 | Note that when using this runner, Nose's "coverage" plugin will not be 24 | able to provide coverage for SQLAlchemy itself, since SQLAlchemy is 25 | imported into sys.modules before coverage is started. The special 26 | script sqla_nose.py is provided as a top-level script which loads the 27 | plugin in a special (somewhat hacky) way so that coverage against 28 | SQLAlchemy itself is possible. 29 | 30 | """ 31 | 32 | from sqlalchemy.testing.plugin.noseplugin import NoseSQLAlchemy 33 | 34 | import nose 35 | 36 | 37 | def main(): 38 | nose.main(addplugins=[NoseSQLAlchemy()]) 39 | 40 | def setup_py_test(): 41 | """Runner to use for the 'test_suite' entry of your setup.py. 42 | 43 | Prevents any name clash shenanigans from the command line 44 | argument "test" that the "setup.py test" command sends 45 | to nose. 46 | 47 | """ 48 | nose.main(addplugins=[NoseSQLAlchemy()], argv=['runner']) 49 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/suite/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from sqlalchemy.testing.suite.test_ddl import * 3 | from sqlalchemy.testing.suite.test_insert import * 4 | from sqlalchemy.testing.suite.test_sequence import * 5 | from sqlalchemy.testing.suite.test_select import * 6 | from sqlalchemy.testing.suite.test_results import * 7 | from sqlalchemy.testing.suite.test_update_delete import * 8 | from sqlalchemy.testing.suite.test_reflection import * 9 | from sqlalchemy.testing.suite.test_types import * 10 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/suite/test_ddl.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from .. import fixtures, config, util 4 | from ..config import requirements 5 | from ..assertions import eq_ 6 | 7 | from sqlalchemy import Table, Column, Integer, String 8 | 9 | 10 | class TableDDLTest(fixtures.TestBase): 11 | __backend__ = True 12 | 13 | def _simple_fixture(self): 14 | return Table('test_table', self.metadata, 15 | Column('id', Integer, primary_key=True, autoincrement=False), 16 | Column('data', String(50)) 17 | ) 18 | 19 | def _underscore_fixture(self): 20 | return Table('_test_table', self.metadata, 21 | Column('id', Integer, primary_key=True, autoincrement=False), 22 | Column('_data', String(50)) 23 | ) 24 | 25 | def _simple_roundtrip(self, table): 26 | with config.db.begin() as conn: 27 | conn.execute(table.insert().values((1, 'some data'))) 28 | result = conn.execute(table.select()) 29 | eq_( 30 | result.first(), 31 | (1, 'some data') 32 | ) 33 | 34 | @requirements.create_table 35 | @util.provide_metadata 36 | def test_create_table(self): 37 | table = self._simple_fixture() 38 | table.create( 39 | config.db, checkfirst=False 40 | ) 41 | self._simple_roundtrip(table) 42 | 43 | @requirements.drop_table 44 | @util.provide_metadata 45 | def test_drop_table(self): 46 | table = self._simple_fixture() 47 | table.create( 48 | config.db, checkfirst=False 49 | ) 50 | table.drop( 51 | config.db, checkfirst=False 52 | ) 53 | 54 | @requirements.create_table 55 | @util.provide_metadata 56 | def test_underscore_names(self): 57 | table = self._underscore_fixture() 58 | table.create( 59 | config.db, checkfirst=False 60 | ) 61 | self._simple_roundtrip(table) 62 | 63 | __all__ = ('TableDDLTest', ) 64 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/suite/test_select.py: -------------------------------------------------------------------------------- 1 | from .. import fixtures, config 2 | from ..assertions import eq_ 3 | 4 | from sqlalchemy import util 5 | from sqlalchemy import Integer, String, select, func 6 | 7 | from ..schema import Table, Column 8 | 9 | 10 | class OrderByLabelTest(fixtures.TablesTest): 11 | """Test the dialect sends appropriate ORDER BY expressions when 12 | labels are used. 13 | 14 | This essentially exercises the "supports_simple_order_by_label" 15 | setting. 16 | 17 | """ 18 | __backend__ = True 19 | 20 | @classmethod 21 | def define_tables(cls, metadata): 22 | Table("some_table", metadata, 23 | Column('id', Integer, primary_key=True), 24 | Column('x', Integer), 25 | Column('y', Integer), 26 | Column('q', String(50)), 27 | Column('p', String(50)) 28 | ) 29 | 30 | @classmethod 31 | def insert_data(cls): 32 | config.db.execute( 33 | cls.tables.some_table.insert(), 34 | [ 35 | {"id": 1, "x": 1, "y": 2, "q": "q1", "p": "p3"}, 36 | {"id": 2, "x": 2, "y": 3, "q": "q2", "p": "p2"}, 37 | {"id": 3, "x": 3, "y": 4, "q": "q3", "p": "p1"}, 38 | ] 39 | ) 40 | 41 | def _assert_result(self, select, result): 42 | eq_( 43 | config.db.execute(select).fetchall(), 44 | result 45 | ) 46 | 47 | def test_plain(self): 48 | table = self.tables.some_table 49 | lx = table.c.x.label('lx') 50 | self._assert_result( 51 | select([lx]).order_by(lx), 52 | [(1, ), (2, ), (3, )] 53 | ) 54 | 55 | def test_composed_int(self): 56 | table = self.tables.some_table 57 | lx = (table.c.x + table.c.y).label('lx') 58 | self._assert_result( 59 | select([lx]).order_by(lx), 60 | [(3, ), (5, ), (7, )] 61 | ) 62 | 63 | def test_composed_multiple(self): 64 | table = self.tables.some_table 65 | lx = (table.c.x + table.c.y).label('lx') 66 | ly = (func.lower(table.c.q) + table.c.p).label('ly') 67 | self._assert_result( 68 | select([lx, ly]).order_by(lx, ly.desc()), 69 | [(3, util.u('q1p3')), (5, util.u('q2p2')), (7, util.u('q3p1'))] 70 | ) 71 | 72 | def test_plain_desc(self): 73 | table = self.tables.some_table 74 | lx = table.c.x.label('lx') 75 | self._assert_result( 76 | select([lx]).order_by(lx.desc()), 77 | [(3, ), (2, ), (1, )] 78 | ) 79 | 80 | def test_composed_int_desc(self): 81 | table = self.tables.some_table 82 | lx = (table.c.x + table.c.y).label('lx') 83 | self._assert_result( 84 | select([lx]).order_by(lx.desc()), 85 | [(7, ), (5, ), (3, )] 86 | ) 87 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/suite/test_update_delete.py: -------------------------------------------------------------------------------- 1 | from .. import fixtures, config 2 | from ..assertions import eq_ 3 | 4 | from sqlalchemy import Integer, String 5 | from ..schema import Table, Column 6 | 7 | 8 | class SimpleUpdateDeleteTest(fixtures.TablesTest): 9 | run_deletes = 'each' 10 | __backend__ = True 11 | 12 | @classmethod 13 | def define_tables(cls, metadata): 14 | Table('plain_pk', metadata, 15 | Column('id', Integer, primary_key=True), 16 | Column('data', String(50)) 17 | ) 18 | 19 | @classmethod 20 | def insert_data(cls): 21 | config.db.execute( 22 | cls.tables.plain_pk.insert(), 23 | [ 24 | {"id":1, "data":"d1"}, 25 | {"id":2, "data":"d2"}, 26 | {"id":3, "data":"d3"}, 27 | ] 28 | ) 29 | 30 | def test_update(self): 31 | t = self.tables.plain_pk 32 | r = config.db.execute( 33 | t.update().where(t.c.id == 2), 34 | data="d2_new" 35 | ) 36 | assert not r.is_insert 37 | assert not r.returns_rows 38 | 39 | eq_( 40 | config.db.execute(t.select().order_by(t.c.id)).fetchall(), 41 | [ 42 | (1, "d1"), 43 | (2, "d2_new"), 44 | (3, "d3") 45 | ] 46 | ) 47 | 48 | def test_delete(self): 49 | t = self.tables.plain_pk 50 | r = config.db.execute( 51 | t.delete().where(t.c.id == 2) 52 | ) 53 | assert not r.is_insert 54 | assert not r.returns_rows 55 | eq_( 56 | config.db.execute(t.select().order_by(t.c.id)).fetchall(), 57 | [ 58 | (1, "d1"), 59 | (3, "d3") 60 | ] 61 | ) 62 | 63 | __all__ = ('SimpleUpdateDeleteTest', ) 64 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/testing/warnings.py: -------------------------------------------------------------------------------- 1 | # testing/warnings.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from __future__ import absolute_import 8 | 9 | import warnings 10 | from .. import exc as sa_exc 11 | from .. import util 12 | import re 13 | 14 | def testing_warn(msg, stacklevel=3): 15 | """Replaces sqlalchemy.util.warn during tests.""" 16 | 17 | filename = "sqlalchemy.testing.warnings" 18 | lineno = 1 19 | if isinstance(msg, util.string_types): 20 | warnings.warn_explicit(msg, sa_exc.SAWarning, filename, lineno) 21 | else: 22 | warnings.warn_explicit(msg, filename, lineno) 23 | 24 | 25 | def resetwarnings(): 26 | """Reset warning behavior to testing defaults.""" 27 | 28 | util.warn = util.langhelpers.warn = testing_warn 29 | 30 | warnings.filterwarnings('ignore', 31 | category=sa_exc.SAPendingDeprecationWarning) 32 | warnings.filterwarnings('error', category=sa_exc.SADeprecationWarning) 33 | warnings.filterwarnings('error', category=sa_exc.SAWarning) 34 | 35 | 36 | def assert_warnings(fn, warnings, regex=False): 37 | """Assert that each of the given warnings are emitted by fn.""" 38 | 39 | from .assertions import eq_, emits_warning 40 | 41 | canary = [] 42 | orig_warn = util.warn 43 | 44 | def capture_warnings(*args, **kw): 45 | orig_warn(*args, **kw) 46 | popwarn = warnings.pop(0) 47 | canary.append(popwarn) 48 | if regex: 49 | assert re.match(popwarn, args[0]) 50 | else: 51 | eq_(args[0], popwarn) 52 | util.warn = util.langhelpers.warn = capture_warnings 53 | 54 | result = emits_warning()(fn)() 55 | assert canary, "No warning was emitted" 56 | return result 57 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/types.py: -------------------------------------------------------------------------------- 1 | # types.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """Compatiblity namespace for sqlalchemy.sql.types. 8 | 9 | """ 10 | 11 | __all__ = ['TypeEngine', 'TypeDecorator', 'UserDefinedType', 12 | 'INT', 'CHAR', 'VARCHAR', 'NCHAR', 'NVARCHAR', 'TEXT', 'Text', 13 | 'FLOAT', 'NUMERIC', 'REAL', 'DECIMAL', 'TIMESTAMP', 'DATETIME', 14 | 'CLOB', 'BLOB', 'BINARY', 'VARBINARY', 'BOOLEAN', 'BIGINT', 15 | 'SMALLINT', 'INTEGER', 'DATE', 'TIME', 'String', 'Integer', 16 | 'SmallInteger', 'BigInteger', 'Numeric', 'Float', 'DateTime', 17 | 'Date', 'Time', 'LargeBinary', 'Binary', 'Boolean', 'Unicode', 18 | 'Concatenable', 'UnicodeText', 'PickleType', 'Interval', 'Enum'] 19 | 20 | from .sql.type_api import ( 21 | adapt_type, 22 | TypeEngine, 23 | TypeDecorator, 24 | Variant, 25 | to_instance, 26 | UserDefinedType 27 | ) 28 | from .sql.sqltypes import ( 29 | BIGINT, 30 | BINARY, 31 | BLOB, 32 | BOOLEAN, 33 | BigInteger, 34 | Binary, 35 | _Binary, 36 | Boolean, 37 | CHAR, 38 | CLOB, 39 | Concatenable, 40 | DATE, 41 | DATETIME, 42 | DECIMAL, 43 | Date, 44 | DateTime, 45 | Enum, 46 | FLOAT, 47 | Float, 48 | INT, 49 | INTEGER, 50 | Integer, 51 | Interval, 52 | LargeBinary, 53 | NCHAR, 54 | NVARCHAR, 55 | NullType, 56 | NULLTYPE, 57 | NUMERIC, 58 | Numeric, 59 | PickleType, 60 | REAL, 61 | SchemaType, 62 | SMALLINT, 63 | SmallInteger, 64 | String, 65 | STRINGTYPE, 66 | TEXT, 67 | TIME, 68 | TIMESTAMP, 69 | Text, 70 | Time, 71 | Unicode, 72 | UnicodeText, 73 | VARBINARY, 74 | VARCHAR, 75 | _type_map 76 | ) 77 | 78 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/util/__init__.py: -------------------------------------------------------------------------------- 1 | # util/__init__.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from .compat import callable, cmp, reduce, \ 8 | threading, py3k, py33, py2k, jython, pypy, cpython, win32, \ 9 | pickle, dottedgetter, parse_qsl, namedtuple, next, reraise, \ 10 | raise_from_cause, text_type, string_types, int_types, binary_type, \ 11 | quote_plus, with_metaclass, print_, itertools_filterfalse, u, ue, b,\ 12 | unquote_plus, unquote, b64decode, b64encode, byte_buffer, itertools_filter,\ 13 | iterbytes, StringIO, inspect_getargspec 14 | 15 | from ._collections import KeyedTuple, ImmutableContainer, immutabledict, \ 16 | Properties, OrderedProperties, ImmutableProperties, OrderedDict, \ 17 | OrderedSet, IdentitySet, OrderedIdentitySet, column_set, \ 18 | column_dict, ordered_column_set, populate_column_dict, unique_list, \ 19 | UniqueAppender, PopulateDict, EMPTY_SET, to_list, to_set, \ 20 | to_column_set, update_copy, flatten_iterator, \ 21 | LRUCache, ScopedRegistry, ThreadLocalRegistry, WeakSequence, \ 22 | coerce_generator_arg 23 | 24 | from .langhelpers import iterate_attributes, class_hierarchy, \ 25 | portable_instancemethod, unbound_method_to_callable, \ 26 | getargspec_init, format_argspec_init, format_argspec_plus, \ 27 | get_func_kwargs, get_cls_kwargs, decorator, as_interface, \ 28 | memoized_property, memoized_instancemethod, md5_hex, \ 29 | group_expirable_memoized_property, dependencies, decode_slice, \ 30 | monkeypatch_proxied_specials, asbool, bool_or_str, coerce_kw_type,\ 31 | duck_type_collection, assert_arg_type, symbol, dictlike_iteritems,\ 32 | classproperty, set_creation_order, warn_exception, warn, NoneType,\ 33 | constructor_copy, methods_equivalent, chop_traceback, asint,\ 34 | generic_repr, counter, PluginLoader, hybridmethod, safe_reraise,\ 35 | get_callable_argspec, only_once 36 | 37 | from .deprecations import warn_deprecated, warn_pending_deprecation, \ 38 | deprecated, pending_deprecation, inject_docstring_text 39 | 40 | # things that used to be not always available, 41 | # but are now as of current support Python versions 42 | from collections import defaultdict 43 | from functools import partial 44 | from functools import update_wrapper 45 | from contextlib import contextmanager 46 | -------------------------------------------------------------------------------- /lib/site-packages/sqlalchemy/util/topological.py: -------------------------------------------------------------------------------- 1 | # util/topological.py 2 | # Copyright (C) 2005-2014 the SQLAlchemy authors and contributors 3 | # 4 | # This module is part of SQLAlchemy and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """Topological sorting algorithms.""" 8 | 9 | from ..exc import CircularDependencyError 10 | from .. import util 11 | 12 | __all__ = ['sort', 'sort_as_subsets', 'find_cycles'] 13 | 14 | 15 | def sort_as_subsets(tuples, allitems): 16 | 17 | edges = util.defaultdict(set) 18 | for parent, child in tuples: 19 | edges[child].add(parent) 20 | 21 | todo = set(allitems) 22 | 23 | while todo: 24 | output = set() 25 | for node in list(todo): 26 | if not todo.intersection(edges[node]): 27 | output.add(node) 28 | 29 | if not output: 30 | raise CircularDependencyError( 31 | "Circular dependency detected.", 32 | find_cycles(tuples, allitems), 33 | _gen_edges(edges) 34 | ) 35 | 36 | todo.difference_update(output) 37 | yield output 38 | 39 | 40 | def sort(tuples, allitems): 41 | """sort the given list of items by dependency. 42 | 43 | 'tuples' is a list of tuples representing a partial ordering. 44 | """ 45 | 46 | for set_ in sort_as_subsets(tuples, allitems): 47 | for s in set_: 48 | yield s 49 | 50 | 51 | def find_cycles(tuples, allitems): 52 | # adapted from: 53 | # http://neopythonic.blogspot.com/2009/01/detecting-cycles-in-directed-graph.html 54 | 55 | edges = util.defaultdict(set) 56 | for parent, child in tuples: 57 | edges[parent].add(child) 58 | nodes_to_test = set(edges) 59 | 60 | output = set() 61 | 62 | # we'd like to find all nodes that are 63 | # involved in cycles, so we do the full 64 | # pass through the whole thing for each 65 | # node in the original list. 66 | 67 | # we can go just through parent edge nodes. 68 | # if a node is only a child and never a parent, 69 | # by definition it can't be part of a cycle. same 70 | # if it's not in the edges at all. 71 | for node in nodes_to_test: 72 | stack = [node] 73 | todo = nodes_to_test.difference(stack) 74 | while stack: 75 | top = stack[-1] 76 | for node in edges[top]: 77 | if node in stack: 78 | cyc = stack[stack.index(node):] 79 | todo.difference_update(cyc) 80 | output.update(cyc) 81 | 82 | if node in todo: 83 | stack.append(node) 84 | todo.remove(node) 85 | break 86 | else: 87 | node = stack.pop() 88 | return output 89 | 90 | 91 | def _gen_edges(edges): 92 | return set([ 93 | (right, left) 94 | for left in edges 95 | for right in edges[left] 96 | ]) 97 | -------------------------------------------------------------------------------- /logs/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /plugins/unraid/README.txt: -------------------------------------------------------------------------------- 1 | unRAID Installation 2 | ------------------- 3 | 1. Download the MovieGrabber plugin from SourceForge to \\\flash\config\plugins 4 | 2. Reboot unRAID or telnet into unRAID host and run installplg /boot/config/plugins/ 5 | 3. Go to Settings menu and look for MovieGrabber icon under Network Services 6 | 4. Click on the icon and configure the plugin, and exmple configuration is as follows:- 7 | 8 | Sample Configuration 9 | -------------------- 10 | Enable MovieGrabber = yes 11 | Can be set to no to disable the plugin 12 | 13 | Install Directory = /mnt/cache/.Apps/MovieGrabber 14 | Should be on a persistent drive such as cache drive, do NOT install to flash drive 15 | 16 | IP = 192.168.1.10 17 | Should be the same as your unRAID server 18 | 19 | Port = 9191 20 | Can be any number from 1024 upwards, but must not already be in use by another plugin 21 | 22 | Run as user = nobody 23 | This can be set to a specific user if required but most standard installations will be most suited to setting this to nobody 24 | 25 | Show storage memory usage = yes 26 | Can be set to no to disable memory usage if required 27 | 28 | Changelog 29 | --------- 30 | ver 1.0.3 31 | created 64bit version of moviegrabber plugin for unRAID 6.x series 32 | fixed moviegrabber install to pull download url from sourceforge page 33 | fixed moviegrabber plugin to pull download url from sourceforge page 34 | fixed moviegrabber app version update to pull version from sourceforge page 35 | fixed moviegrabber plugin version update to pull version from sourceforge page 36 | fixed downgrade plugin button not centre aligned 37 | forced utf-8 encoding in plugin to prevent issue with os.walk 38 | 39 | ver 1.0.2 40 | updated openssl package to openssl-0.9.8r-i486-3 (same version as sabnzbd_unplugged) 41 | updated infozip package to infozip-6.0-i486-1 (same version as sabnzbd_unplugged) 42 | updated sqlite package to sqlite-3.7.5-i486-1 (same version as sabnzbd_unplugged) 43 | 44 | ver 1.0.1 45 | fix missing infozip package 46 | 47 | ver 1.0.0 48 | initial release 49 | 50 | Known Issues 51 | ------------ 52 | current moviegrabber version does not work, gets info from moviegrabber using --version flag 53 | check $2 $3 $4 etc and remove if referencing datadir 54 | missing warning about persistent data on reboot -------------------------------------------------------------------------------- /scripts/init.d/moviegrabber.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # /etc/init.d/moviegrabber.sh 3 | 4 | # function that stops the daemon/service 5 | do_start() 6 | { 7 | # create moviegrabber writeable directory for pid file 8 | if [ ! -e /var/run/moviegrabber ]; then 9 | mkdir /var/run/moviegrabber 10 | chown root:users /var/run/moviegrabber 11 | chmod 0777 /var/run/moviegrabber 12 | fi 13 | 14 | # run moviegrabber as root, specifying daemon flag and pid file (used to kill moviegrabber process) 15 | sudo -u root python /home/xxx/Desktop/moviegrabber/MovieGrabber.py --daemon --pidfile /var/run/moviegrabber/moviegrabber.pid& 16 | } 17 | 18 | # function that stops the daemon/service 19 | do_stop() 20 | { 21 | # if moviegrabber not running then return 22 | if [ ! -r /var/run/moviegrabber/moviegrabber.pid ]; then 23 | return 24 | fi 25 | 26 | # kill moviegrabber process by reading pid file 27 | kill $(cat /var/run/moviegrabber/moviegrabber.pid) 28 | sleep 3 29 | 30 | # if pid file exists then delete 31 | if [ -f /var/run/moviegrabber/moviegrabber.pid ]; then 32 | rm /var/run/moviegrabber/moviegrabber.pid 33 | fi 34 | 35 | # wait for pid file to be deleted 36 | while [ -e /var/run/moviegrabber/moviegrabber.pid ]; do 37 | sleep 1 38 | done 39 | } 40 | 41 | case "$1" in 42 | start) 43 | echo "Starting moviegrabber..." 44 | do_start 45 | ;; 46 | 47 | stop) 48 | echo "Stopping moviegrabber..." 49 | do_stop 50 | sleep 1 51 | ;; 52 | 53 | restart) 54 | echo "Restarting moviegrabber..." 55 | do_stop 56 | do_start 57 | ;; 58 | 59 | enable) 60 | echo "Enable autostart of moviegrabber..." 61 | /usr/sbin/update-rc.d moviegrabber.sh defaults 62 | ;; 63 | 64 | disable) 65 | echo "Disable autostart of moviegrabber..." 66 | /usr/sbin/update-rc.d -f moviegrabber.sh remove 67 | ;; 68 | 69 | *) 70 | echo "Usage: /etc/init.d/moviegrabber{start|stop|restart|enable|disable}" 71 | exit 1 72 | ;; 73 | 74 | esac 75 | 76 | exit 0 77 | -------------------------------------------------------------------------------- /scripts/init.systemd/moviegrabber.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=MovieGrabber automated movie downloader 3 | After=network.target 4 | 5 | [Service] 6 | ExecStart=/usr/bin/env python2 /opt/moviegrabber/MovieGrabber.py 7 | User=moviegrabber 8 | Group=moviegrabber 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | --------------------------------------------------------------------------------