Merge branch 'develop' of https://github.com/SiCKRAGETV/SickRage into branch-tntvillage_provider
5
.gitignore
vendored
@ -37,6 +37,10 @@ tests/failed.db
|
|||||||
*.sw?
|
*.sw?
|
||||||
Session.vim
|
Session.vim
|
||||||
.ropeproject/*
|
.ropeproject/*
|
||||||
|
*.iml
|
||||||
|
.idea
|
||||||
|
*.ipr
|
||||||
|
.settings/*
|
||||||
|
|
||||||
# OS generated files #
|
# OS generated files #
|
||||||
######################
|
######################
|
||||||
@ -48,7 +52,6 @@ ehthumbs.db
|
|||||||
Thumbs.db
|
Thumbs.db
|
||||||
.directory
|
.directory
|
||||||
*~
|
*~
|
||||||
/.idea/
|
|
||||||
*.torrent
|
*.torrent
|
||||||
|
|
||||||
# Unrar Executable #
|
# Unrar Executable #
|
||||||
|
@ -50,6 +50,10 @@ sys.path.insert(1, os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib'
|
|||||||
if sys.hexversion >= 0x020600F0:
|
if sys.hexversion >= 0x020600F0:
|
||||||
from multiprocessing import freeze_support # @UnresolvedImport
|
from multiprocessing import freeze_support # @UnresolvedImport
|
||||||
|
|
||||||
|
if sys.version_info >= (2, 7, 9):
|
||||||
|
import ssl
|
||||||
|
ssl._create_default_https_context = ssl._create_unverified_context
|
||||||
|
|
||||||
import locale
|
import locale
|
||||||
import datetime
|
import datetime
|
||||||
import threading
|
import threading
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
.country-flag {
|
.country-flag {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 11px;
|
height: 11px;
|
||||||
background:url(images/country-flags.png) no-repeat
|
background:url(../images/country-flags.png) no-repeat
|
||||||
}
|
}
|
||||||
|
|
||||||
.country-flag.flag-ad {background-position: -16px 0}
|
.country-flag.flag-ad {background-position: -16px 0}
|
||||||
|
BIN
gui/slick/images/anidb24.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 1.8 KiB |
BIN
gui/slick/images/network/eo.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
gui/slick/images/network/max.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
gui/slick/images/network/npo 1.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
gui/slick/images/network/npo 2.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
gui/slick/images/network/npo 3.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
gui/slick/images/network/nps.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
gui/slick/images/network/ntr.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
gui/slick/images/network/quest.png
Normal file
After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 5.0 KiB |
BIN
gui/slick/images/network/sbs 9.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
gui/slick/images/network/tvi.png
Normal file
After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 2.7 KiB |
BIN
gui/slick/images/providers/alpharatio.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
BIN
gui/slick/images/providers/oldpiratebay.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
gui/slick/images/providers/rarbg.png
Normal file
After Width: | Height: | Size: 488 B |
BIN
gui/slick/images/providers/shazbat.png
Normal file
After Width: | Height: | Size: 853 B |
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
<div id="core-component-group1" class="tab-pane active component-group">
|
<div id="core-component-group1" class="tab-pane active component-group">
|
||||||
<div class="component-group-desc">
|
<div class="component-group-desc">
|
||||||
<img class="notifier-icon" src="$sbRoot/images/providers/anidb.gif" alt="AniDB" title="AniDB" width="24" height="24" />
|
<img class="notifier-icon" src="$sbRoot/images/anidb24.png" alt="AniDB" title="AniDB" width="24" height="24" />
|
||||||
<h3><a href="<%= anon_url('http://anidb.info') %>" onclick="window.open(this.href, '_blank'); return false;">AniDB</a></h3>
|
<h3><a href="<%= anon_url('http://anidb.info') %>" onclick="window.open(this.href, '_blank'); return false;">AniDB</a></h3>
|
||||||
<p>AniDB is non-profit database of anime information that is freely open to the public</p>
|
<p>AniDB is non-profit database of anime information that is freely open to the public</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -63,6 +63,16 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="field-pair">
|
||||||
|
<label for="showupdate_hour">
|
||||||
|
<span class="component-title">When to update shows</span>
|
||||||
|
<span class="component-desc">
|
||||||
|
<input type="text" name="showupdate_hour" id="showupdate_hour" value="$sickbeard.SHOWUPDATE_HOUR" class="form-control input-sm input75" />
|
||||||
|
<p>with information such as next air dates, show ended, etc. Use 15 for 3pm, 4 for 4am etc. Anything over 23 or under 0 will be set to 0 (12am)</p>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="field-pair">
|
<div class="field-pair">
|
||||||
<label for="update_shows_on_start">
|
<label for="update_shows_on_start">
|
||||||
<span class="component-title">Update shows on startup</span>
|
<span class="component-title">Update shows on startup</span>
|
||||||
|
@ -1375,30 +1375,39 @@
|
|||||||
<span class="component-title">Trakt username</span>
|
<span class="component-title">Trakt username</span>
|
||||||
<input type="text" name="trakt_username" id="trakt_username" value="$sickbeard.TRAKT_USERNAME" class="form-control input-sm input250" />
|
<input type="text" name="trakt_username" id="trakt_username" value="$sickbeard.TRAKT_USERNAME" class="form-control input-sm input250" />
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<p>
|
||||||
<span class="component-title"> </span>
|
|
||||||
<span class="component-desc">username of your Trakt account.</span>
|
<span class="component-desc">username of your Trakt account.</span>
|
||||||
</label>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-pair">
|
<div class="field-pair">
|
||||||
<label for="trakt_password">
|
<label for="trakt_password">
|
||||||
<span class="component-title">Trakt password</span>
|
<span class="component-title">Trakt password</span>
|
||||||
<input type="password" name="trakt_password" id="trakt_password" value="$sickbeard.TRAKT_PASSWORD" class="form-control input-sm input250" />
|
<input type="password" name="trakt_password" id="trakt_password" value="$sickbeard.TRAKT_PASSWORD" class="form-control input-sm input250" />
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<p>
|
||||||
<span class="component-title"> </span>
|
|
||||||
<span class="component-desc">password of your Trakt account.</span>
|
<span class="component-desc">password of your Trakt account.</span>
|
||||||
</label>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-pair">
|
<div class="field-pair">
|
||||||
<label for="trakt_disable_ssl_verify">
|
<label for="trakt_disable_ssl_verify">
|
||||||
<span class="component-title">Disable SSL Verification:</span>
|
<span class="component-title">Disable SSL Verification:</span>
|
||||||
<span class="component-desc">
|
<span class="component-desc">
|
||||||
<input type="checkbox" class="enabler" name="trakt_disable_ssl_verify" id="trakt_disable_ssl_verify" #if $sickbeard.TRAKT_DISABLE_SSL_VERIFY then "checked=\"checked\"" else ""# />
|
<input type="checkbox" class="enabler" name="trakt_disable_ssl_verify" id="trakt_disable_ssl_verify" #if $sickbeard.TRAKT_DISABLE_SSL_VERIFY then "checked=\"checked\"" else ""# />
|
||||||
<p>Disable SSL certificate verification on systems with broken SSL implementations, like the QNAP NAS.</p>
|
<p>Disable SSL certificate verification for broken SSL installs (like QNAP NAS)</p>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field-pair">
|
||||||
|
<label for="trakt_timeout">
|
||||||
|
<span class="component-title">API Timeout:</span>
|
||||||
|
<input type="text" name="trakt_timeout" id="trakt_timeout" value="$sickbeard.TRAKT_TIMEOUT" class="form-control input-sm input75" />
|
||||||
|
</label>
|
||||||
|
<p>
|
||||||
|
<span class="component-desc">
|
||||||
|
Seconds to wait for Trakt API to respond. (Use 0 to wait forever)
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<div class="field-pair">
|
<div class="field-pair">
|
||||||
<label for="trakt_default_indexer">
|
<label for="trakt_default_indexer">
|
||||||
<span class="component-title">Default indexer:</span>
|
<span class="component-title">Default indexer:</span>
|
||||||
|
@ -449,7 +449,6 @@
|
|||||||
<input type="text" name="torrent_host" id="torrent_host" value="$sickbeard.TORRENT_HOST" class="form-control input-sm input350" />
|
<input type="text" name="torrent_host" id="torrent_host" value="$sickbeard.TORRENT_HOST" class="form-control input-sm input350" />
|
||||||
<div class="clear-left">
|
<div class="clear-left">
|
||||||
<p id="host_desc_torrent">URL to your torrent client (e.g. http://localhost:8000/)</p>
|
<p id="host_desc_torrent">URL to your torrent client (e.g. http://localhost:8000/)</p>
|
||||||
<p id="host_desc_rtorrent" style="display:none"><b>Note:</b> <i>rTorrent</i> client URLs use e.g. scgi://localhost:5000/</p>
|
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
@ -467,12 +466,29 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="field-pair" id="torrent_auth_type">
|
||||||
|
<label>
|
||||||
|
<span class="component-title">Http Authentication</span>
|
||||||
|
<span class="component-desc">
|
||||||
|
<select name="torrent_auth_type" id="torrent_auth_type" class="form-control input-sm">
|
||||||
|
#set $http_authtype = {'none': "None", 'basic': "Basic", 'digest': "Digest"}
|
||||||
|
#for $authvalue,$authname in $http_authtype.items():
|
||||||
|
#set $selected = $html_selected if $sickbeard.TORRENT_AUTH_TYPE == $authvalue else ''
|
||||||
|
<option value="$authvalue"$selected>$authname</option>
|
||||||
|
#end for
|
||||||
|
</select>
|
||||||
|
<p></p>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="field-pair" id="torrent_verify_cert_option">
|
<div class="field-pair" id="torrent_verify_cert_option">
|
||||||
<label for="torrent_verify_cert">
|
<label for="torrent_verify_cert">
|
||||||
<span class="component-title">Verify certificate</span>
|
<span class="component-title">Verify certificate</span>
|
||||||
<span class="component-desc">
|
<span class="component-desc">
|
||||||
<input type="checkbox" name="torrent_verify_cert" class="enabler" id="torrent_verify_cert" <%= html_checked if sickbeard.TORRENT_VERIFY_CERT == True else '' %>/>
|
<input type="checkbox" name="torrent_verify_cert" class="enabler" id="torrent_verify_cert" <%= html_checked if sickbeard.TORRENT_VERIFY_CERT == True else '' %>/>
|
||||||
<p>disable if you get "Deluge: Authentication Error" in your log</p>
|
<p id="torrent_verify_deluge">disable if you get "Deluge: Authentication Error" in your log</p>
|
||||||
|
<p id="torrent_verify_rtorrent">Verify SSL certificates for HTTPS requests</p>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -379,7 +379,7 @@
|
|||||||
#if ($sickbeard.DISPLAY_FILESIZE == True):
|
#if ($sickbeard.DISPLAY_FILESIZE == True):
|
||||||
style="min-width: 190px"
|
style="min-width: 190px"
|
||||||
#end if
|
#end if
|
||||||
>>Name</th>
|
>Name</th>
|
||||||
#if ($sickbeard.DISPLAY_FILESIZE == True):
|
#if ($sickbeard.DISPLAY_FILESIZE == True):
|
||||||
<th class="col-ep">Filesize</th>
|
<th class="col-ep">Filesize</th>
|
||||||
#end if
|
#end if
|
||||||
@ -508,9 +508,11 @@
|
|||||||
#if $sickbeard.USE_SUBTITLES and $show.subtitles:
|
#if $sickbeard.USE_SUBTITLES and $show.subtitles:
|
||||||
<td class="col-subtitles" align="center">
|
<td class="col-subtitles" align="center">
|
||||||
#if $epResult["subtitles"]:
|
#if $epResult["subtitles"]:
|
||||||
#for $sub_lang in subliminal.language.language_list([x.strip() for x in $epResult["subtitles"].split(',')]):
|
#for $sub_lang in subliminal.language.language_list([x.strip() for x in $epResult["subtitles"].split(',') if x != ""]):
|
||||||
#if sub_lang.alpha2 != ""
|
#if sub_lang.alpha2 != ""
|
||||||
<img src="$sbRoot/images/flags/${sub_lang.alpha2}.png" width="16" height="11" alt="${sub_lang}" />
|
<img src="$sbRoot/images/flags/${sub_lang.alpha2}.png" width="16" height="11" alt="${sub_lang}" />
|
||||||
|
#else
|
||||||
|
<img src="$sbRoot/images/flags/unknown.png" width="16" height="11" alt="Unknown" />
|
||||||
#end if
|
#end if
|
||||||
#end for
|
#end for
|
||||||
#end if
|
#end if
|
||||||
|
@ -131,7 +131,11 @@
|
|||||||
<td class="tvShow" width="35%"><a href="$sbRoot/home/displayShow?show=$hItem["showid"]#season-$hItem["season"]">$hItem["show_name"] - <%="S%02i" % int(hItem["season"])+"E%02i" % int(hItem["episode"]) %>#if "proper" in $hItem["resource"].lower() or "repack" in $hItem["resource"].lower() then ' <span class="quality Proper">Proper</span>' else ""#</a></td>
|
<td class="tvShow" width="35%"><a href="$sbRoot/home/displayShow?show=$hItem["showid"]#season-$hItem["season"]">$hItem["show_name"] - <%="S%02i" % int(hItem["season"])+"E%02i" % int(hItem["episode"]) %>#if "proper" in $hItem["resource"].lower() or "repack" in $hItem["resource"].lower() then ' <span class="quality Proper">Proper</span>' else ""#</a></td>
|
||||||
<td align="center" #if $curStatus == SUBTITLED then 'class="subtitles_column"' else ''#>
|
<td align="center" #if $curStatus == SUBTITLED then 'class="subtitles_column"' else ''#>
|
||||||
#if $curStatus == SUBTITLED:
|
#if $curStatus == SUBTITLED:
|
||||||
<img width="16" height="11" style="vertical-align:middle;" src="$sbRoot/images/flags/<%= hItem["resource"][len(hItem["resource"])-6:len(hItem["resource"])-4]+'.png'%>">
|
#if $sickbeard.SUBTITLES_MULTI:
|
||||||
|
<img width="16" height="11" style="vertical-align:middle;" src="$sbRoot/images/flags/<%= hItem["resource"][len(hItem["resource"])-6:len(hItem["resource"])-4]+'.png'%>" onError="this.onerror=null;this.src='$sbRoot/images/flags/unknown.png';">
|
||||||
|
#else
|
||||||
|
<img width="16" height="11" style="vertical-align:middle;" src="$sbRoot/images/flags/unknown.png">
|
||||||
|
#end if
|
||||||
#end if
|
#end if
|
||||||
<span style="cursor: help; vertical-align:middle;" title="$os.path.basename($hItem["resource"])">$statusStrings[$curStatus]</span>
|
<span style="cursor: help; vertical-align:middle;" title="$os.path.basename($hItem["resource"])">$statusStrings[$curStatus]</span>
|
||||||
</td>
|
</td>
|
||||||
|
@ -104,7 +104,8 @@
|
|||||||
filter_columnFilters: false,
|
filter_columnFilters: false,
|
||||||
filter_reset: '.resetshows'
|
filter_reset: '.resetshows'
|
||||||
},
|
},
|
||||||
sortStable: true
|
sortStable: true,
|
||||||
|
sortAppend: [[1,0]]
|
||||||
});
|
});
|
||||||
|
|
||||||
\$("#showListTableAnime:has(tbody tr)").tablesorter({
|
\$("#showListTableAnime:has(tbody tr)").tablesorter({
|
||||||
@ -126,12 +127,15 @@
|
|||||||
filter_columnFilters: false,
|
filter_columnFilters: false,
|
||||||
filter_reset: '.resetanime'
|
filter_reset: '.resetanime'
|
||||||
},
|
},
|
||||||
sortStable: true
|
sortStable: true,
|
||||||
|
sortAppend: [[1,0]]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (\$("#showListTableShows").find("tbody").find("tr").size() > 0)
|
||||||
\$.tablesorter.filter.bindSearch( "#showListTableShows", \$('.search') );
|
\$.tablesorter.filter.bindSearch( "#showListTableShows", \$('.search') );
|
||||||
|
|
||||||
#if $sickbeard.ANIME_SPLIT_HOME:
|
#if $sickbeard.ANIME_SPLIT_HOME:
|
||||||
|
if (\$("#showListTableAnime").find("tbody").find("tr").size() > 0)
|
||||||
\$.tablesorter.filter.bindSearch( "#showListTableAnime", \$('.search') );
|
\$.tablesorter.filter.bindSearch( "#showListTableAnime", \$('.search') );
|
||||||
#end if
|
#end if
|
||||||
|
|
||||||
@ -403,7 +407,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name))
|
|||||||
<td class="show-table">
|
<td class="show-table">
|
||||||
#if $layout != 'simple':
|
#if $layout != 'simple':
|
||||||
#if $curShow.network:
|
#if $curShow.network:
|
||||||
<img class="show-network-image" src="$sbRoot/images/network/${curShow.network.replace(u"\u00C9",'e').lower()}.png" alt="$curShow.network" title="$curShow.network" />
|
<img class="show-network-image" src="$sbRoot/images/network/${curShow.network.replace(u"\u00C9",'e').replace(u"\u00E9",'e').lower()}.png" alt="$curShow.network" title="$curShow.network" />
|
||||||
#else:
|
#else:
|
||||||
<img class="show-network-image" src="$sbRoot/images/network/nonetwork.png" alt="No Network" title="No Network" />
|
<img class="show-network-image" src="$sbRoot/images/network/nonetwork.png" alt="No Network" title="No Network" />
|
||||||
#end if
|
#end if
|
||||||
@ -561,7 +565,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name))
|
|||||||
#if $layout != 'simple':
|
#if $layout != 'simple':
|
||||||
<td align="center">
|
<td align="center">
|
||||||
#if $curShow.network:
|
#if $curShow.network:
|
||||||
<img id="network" width="54" height="27" src="$sbRoot/images/network/${curShow.network.replace(u"\u00C9",'e').lower()}.png" alt="$curShow.network" title="$curShow.network" />
|
<img id="network" width="54" height="27" src="$sbRoot/images/network/${curShow.network.replace(u"\u00C9",'e').replace(u"\u00E9",'e').lower()}.png" alt="$curShow.network" title="$curShow.network" />
|
||||||
#else:
|
#else:
|
||||||
<img id="network" width="54" height="27" src="$sbRoot/images/network/nonetwork.png" alt="No Network" title="No Network" />
|
<img id="network" width="54" height="27" src="$sbRoot/images/network/nonetwork.png" alt="No Network" title="No Network" />
|
||||||
#end if
|
#end if
|
||||||
|
@ -25,7 +25,3 @@
|
|||||||
<input class="btn" type="button" id="defaultRootDir" value="Set as Default *" />
|
<input class="btn" type="button" id="defaultRootDir" value="Set as Default *" />
|
||||||
</div>
|
</div>
|
||||||
<input type="text" style="display: none" id="rootDirText" />
|
<input type="text" style="display: none" id="rootDirText" />
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
document.getElementById("rootDirs").selectedIndex = "0"
|
|
||||||
</script>
|
|
||||||
|
@ -46,22 +46,25 @@
|
|||||||
#end if
|
#end if
|
||||||
#set $totalWanted = 0
|
#set $totalWanted = 0
|
||||||
#set $totalQual = 0
|
#set $totalQual = 0
|
||||||
|
#set $totalSnatched = 0
|
||||||
|
|
||||||
#for $curShow in $sickbeard.showList:
|
#for $curShow in $sickbeard.showList:
|
||||||
#set $totalWanted = $totalWanted + $showCounts[$curShow.indexerid][$Overview.WANTED]
|
#set $totalWanted = $totalWanted + $showCounts[$curShow.indexerid][$Overview.WANTED]
|
||||||
#set $totalQual = $totalQual + $showCounts[$curShow.indexerid][$Overview.QUAL]
|
#set $totalQual = $totalQual + $showCounts[$curShow.indexerid][$Overview.QUAL]
|
||||||
|
#set $totalSnatched = $totalSnatched + $showCounts[$curShow.indexerid][$Overview.SNATCHED]
|
||||||
#end for
|
#end for
|
||||||
|
|
||||||
<div class="h2footer pull-right">
|
<div class="h2footer pull-right">
|
||||||
<span class="listing-key wanted">Wanted: <b>$totalWanted</b></span>
|
<span class="listing-key wanted">Wanted: <b>$totalWanted</b></span>
|
||||||
<span class="listing-key qual">Low Quality: <b>$totalQual</b></span>
|
<span class="listing-key qual">Low Quality: <b>$totalQual</b></span>
|
||||||
|
<span class="listing-key snatched">Snatched: <b>$totalSnatched</b></span>
|
||||||
</div><br/>
|
</div><br/>
|
||||||
|
|
||||||
<div class="float-left">
|
<div class="float-left">
|
||||||
Jump to Show
|
Jump to Show
|
||||||
<select id="pickShow" class="form-control form-control-inline input-sm">
|
<select id="pickShow" class="form-control form-control-inline input-sm">
|
||||||
#for $curShow in sorted($sickbeard.showList, key = operator.attrgetter('name')):
|
#for $curShow in sorted($sickbeard.showList, key = operator.attrgetter('name')):
|
||||||
#if $showCounts[$curShow.indexerid][$Overview.QUAL] + $showCounts[$curShow.indexerid][$Overview.WANTED] != 0:
|
#if $showCounts[$curShow.indexerid][$Overview.QUAL] + $showCounts[$curShow.indexerid][$Overview.WANTED] + $showCounts[$curShow.indexerid][$Overview.SNATCHED] != 0:
|
||||||
<option value="$curShow.indexerid">$curShow.name</option>
|
<option value="$curShow.indexerid">$curShow.name</option>
|
||||||
#end if
|
#end if
|
||||||
#end for
|
#end for
|
||||||
@ -72,7 +75,7 @@ Jump to Show
|
|||||||
|
|
||||||
#for $curShow in sorted($sickbeard.showList, key = operator.attrgetter('name')):
|
#for $curShow in sorted($sickbeard.showList, key = operator.attrgetter('name')):
|
||||||
|
|
||||||
#if $showCounts[$curShow.indexerid][$Overview.QUAL] + $showCounts[$curShow.indexerid][$Overview.WANTED] == 0:
|
#if $showCounts[$curShow.indexerid][$Overview.QUAL] + $showCounts[$curShow.indexerid][$Overview.WANTED] + $showCounts[$curShow.indexerid][$Overview.SNATCHED] == 0:
|
||||||
#continue
|
#continue
|
||||||
#end if
|
#end if
|
||||||
|
|
||||||
@ -82,6 +85,7 @@ Jump to Show
|
|||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<span class="listing-key wanted">Wanted: <b>$showCounts[$curShow.indexerid][$Overview.WANTED]</b></span>
|
<span class="listing-key wanted">Wanted: <b>$showCounts[$curShow.indexerid][$Overview.WANTED]</b></span>
|
||||||
<span class="listing-key qual">Low Quality: <b>$showCounts[$curShow.indexerid][$Overview.QUAL]</b></span>
|
<span class="listing-key qual">Low Quality: <b>$showCounts[$curShow.indexerid][$Overview.QUAL]</b></span>
|
||||||
|
<span class="listing-key snatched">Snatched: <b>$showCounts[$curShow.indexerid][$Overview.SNATCHED]</b></span>
|
||||||
<a class="btn btn-inline forceBacklog" href="$sbRoot/manage/backlogShow?indexer_id=$curShow.indexerid"><i class="icon-play-circle icon-white"></i> Force Backlog</a>
|
<a class="btn btn-inline forceBacklog" href="$sbRoot/manage/backlogShow?indexer_id=$curShow.indexerid"><i class="icon-play-circle icon-white"></i> Force Backlog</a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -97,7 +101,7 @@ Jump to Show
|
|||||||
#continue
|
#continue
|
||||||
#end try
|
#end try
|
||||||
|
|
||||||
#if $overview not in ($Overview.QUAL, $Overview.WANTED):
|
#if $overview not in ($Overview.QUAL, $Overview.WANTED, $Overview.SNATCHED):
|
||||||
#continue
|
#continue
|
||||||
#end if
|
#end if
|
||||||
|
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
$.each(subtitles,function(index, language){
|
$.each(subtitles,function(index, language){
|
||||||
if (language != "" && language != "und") {
|
if (language != "" && language != "und") {
|
||||||
if (index != subtitles.length - 1) {
|
if (index != subtitles.length - 1) {
|
||||||
subtitles_td.append($("<img/>").attr({"src": sbRoot+"/images/flags/"+language+".png", "alt": language, "width": 16, "height": 11}).css({'padding-right' : '6px','padding-bottom' : '4px'}));
|
subtitles_td.append($("<img/>").attr({"src": sbRoot+"/images/flags/"+language+".png", "alt": language, "width": 16, "height": 11}));
|
||||||
} else {
|
} else {
|
||||||
subtitles_td.append($("<img/>").attr({"src": sbRoot+"/images/flags/"+language+".png", "alt": language, "width": 16, "height": 11}).css({'padding-bottom' : '4px'}));
|
subtitles_td.append($("<img/>").attr({"src": sbRoot+"/images/flags/"+language+".png", "alt": language, "width": 16, "height": 11}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -102,7 +102,7 @@ $(document).ready(function(){
|
|||||||
$('#boxcar2_accesstoken').removeClass('warning');
|
$('#boxcar2_accesstoken').removeClass('warning');
|
||||||
$(this).prop('disabled', true);
|
$(this).prop('disabled', true);
|
||||||
$('#testBoxcar2-result').html(loading);
|
$('#testBoxcar2-result').html(loading);
|
||||||
$.get(sbRoot + '/home/testBoxcar2', {'accessToken': boxcar2_accesstoken})
|
$.get(sbRoot + '/home/testBoxcar2', {'accesstoken': boxcar2_accesstoken})
|
||||||
.done(function (data) {
|
.done(function (data) {
|
||||||
$('#testBoxcar2-result').html(data);
|
$('#testBoxcar2-result').html(data);
|
||||||
$('#testBoxcar2').prop('disabled', false);
|
$('#testBoxcar2').prop('disabled', false);
|
||||||
@ -426,20 +426,25 @@ $(document).ready(function(){
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var current_pushbullet_device = $("#pushbullet_device").val();
|
|
||||||
$.get(sbRoot + "/home/getPushbulletDevices", {'api': pushbullet_api},
|
$.get(sbRoot + "/home/getPushbulletDevices", {'api': pushbullet_api},
|
||||||
function (data) {
|
function (data) {
|
||||||
var devices = jQuery.parseJSON(data).devices;
|
var devices = jQuery.parseJSON(data).devices;
|
||||||
|
var current_pushbullet_device = $("#pushbullet_device").val();
|
||||||
$("#pushbullet_device_list").html('');
|
$("#pushbullet_device_list").html('');
|
||||||
for (var i = 0; i < devices.length; i++) {
|
for (var i = 0; i < devices.length; i++) {
|
||||||
if(devices[i].active == true) {
|
if(devices[i].active == true) {
|
||||||
if(current_pushbullet_device == devices[i].iden) {
|
if(current_pushbullet_device == devices[i].iden) {
|
||||||
$("#pushbullet_device_list").append('<option value="'+devices[i].iden+'" selected>' + devices[i].nickname + '</option>')
|
$("#pushbullet_device_list").append('<option value="'+devices[i].iden+'" selected>' + devices[i].nickname + '</option>');
|
||||||
} else {
|
} else {
|
||||||
$("#pushbullet_device_list").append('<option value="'+devices[i].iden+'">' + devices[i].nickname + '</option>')
|
$("#pushbullet_device_list").append('<option value="'+devices[i].iden+'">' + devices[i].nickname + '</option>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (current_pushbullet_device == "") {
|
||||||
|
$("#pushbullet_device_list").prepend('<option value="" selected>All devices</option>');
|
||||||
|
} else {
|
||||||
|
$("#pushbullet_device_list").prepend('<option value="">All devices</option>');
|
||||||
|
}
|
||||||
if(msg) {
|
if(msg) {
|
||||||
$('#testPushbullet-result').html(msg);
|
$('#testPushbullet-result').html(msg);
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ $(document).ready(function(){
|
|||||||
$(this).getCategories(isDefault, data);
|
$(this).getCategories(isDefault, data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
updateNewznabCaps( null, data );
|
$(this).updateNewznabCaps( null, data );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,9 @@ $(document).ready(function(){
|
|||||||
$(host_desc_rtorrent).hide();
|
$(host_desc_rtorrent).hide();
|
||||||
$(host_desc_torrent).show();
|
$(host_desc_torrent).show();
|
||||||
$(torrent_verify_cert_option).hide();
|
$(torrent_verify_cert_option).hide();
|
||||||
|
$(torrent_verify_deluge).hide();
|
||||||
|
$(torrent_verify_rtorrent).hide();
|
||||||
|
$(torrent_auth_type).hide();
|
||||||
$(torrent_path_option).show();
|
$(torrent_path_option).show();
|
||||||
$(torrent_path_option).find('.fileBrowser').show();
|
$(torrent_path_option).find('.fileBrowser').show();
|
||||||
$(torrent_seed_time_option).hide();
|
$(torrent_seed_time_option).hide();
|
||||||
@ -83,6 +86,7 @@ $(document).ready(function(){
|
|||||||
client = 'uTorrent';
|
client = 'uTorrent';
|
||||||
$(torrent_path_option).hide();
|
$(torrent_path_option).hide();
|
||||||
$(torrent_seed_time_option).show();
|
$(torrent_seed_time_option).show();
|
||||||
|
$('#host_desc_torrent').text('URL to your uTorrent client (e.g. http://localhost:8000)');
|
||||||
} else if ('transmission' == selectedProvider){
|
} else if ('transmission' == selectedProvider){
|
||||||
client = 'Transmission';
|
client = 'Transmission';
|
||||||
$(torrent_seed_time_option).show();
|
$(torrent_seed_time_option).show();
|
||||||
@ -90,12 +94,16 @@ $(document).ready(function(){
|
|||||||
$(torrent_label_option).hide();
|
$(torrent_label_option).hide();
|
||||||
$(torrent_label_anime_option).hide();
|
$(torrent_label_anime_option).hide();
|
||||||
$(torrent_rpcurl_option).show();
|
$(torrent_rpcurl_option).show();
|
||||||
|
$('#host_desc_torrent').text('URL to your Transmission client (e.g. http://localhost:9091)');
|
||||||
//$('#directory_title').text(client + directory);
|
//$('#directory_title').text(client + directory);
|
||||||
} else if ('deluge' == selectedProvider){
|
} else if ('deluge' == selectedProvider){
|
||||||
client = 'Deluge';
|
client = 'Deluge';
|
||||||
$(torrent_verify_cert_option).show();
|
$(torrent_verify_cert_option).show();
|
||||||
|
$(torrent_verify_deluge).show();
|
||||||
|
$(torrent_verify_rtorrent).hide();
|
||||||
$(label_warning_deluge).show();
|
$(label_warning_deluge).show();
|
||||||
$(label_anime_warning_deluge).show();
|
$(label_anime_warning_deluge).show();
|
||||||
|
$('#host_desc_torrent').text('URL to your Deluge client (e.g. http://localhost:8112)');
|
||||||
//$('#directory_title').text(client + directory);
|
//$('#directory_title').text(client + directory);
|
||||||
} else if ('download_station' == selectedProvider){
|
} else if ('download_station' == selectedProvider){
|
||||||
client = 'Synology DS';
|
client = 'Synology DS';
|
||||||
@ -103,13 +111,17 @@ $(document).ready(function(){
|
|||||||
$(torrent_label_anime_option).hide();
|
$(torrent_label_anime_option).hide();
|
||||||
$('#torrent_paused_option').hide();
|
$('#torrent_paused_option').hide();
|
||||||
$(torrent_path_option).find('.fileBrowser').hide();
|
$(torrent_path_option).find('.fileBrowser').hide();
|
||||||
|
$('#host_desc_torrent').text('URL to your Synology DS client (e.g. http://localhost:5000)');
|
||||||
//$('#directory_title').text(client + directory);
|
//$('#directory_title').text(client + directory);
|
||||||
$(path_synology).show();
|
$(path_synology).show();
|
||||||
} else if ('rtorrent' == selectedProvider){
|
} else if ('rtorrent' == selectedProvider){
|
||||||
client = 'rTorrent';
|
client = 'rTorrent';
|
||||||
$(host_desc_torrent).hide();
|
|
||||||
$(host_desc_rtorrent).show();
|
|
||||||
$(torrent_paused_option).hide();
|
$(torrent_paused_option).hide();
|
||||||
|
$('#host_desc_torrent').text('URL to your rTorrent client (e.g. scgi://localhost:5000 </br> or https://localhost/rutorrent/plugins/httprpc/action.php)');
|
||||||
|
$(torrent_verify_cert_option).show();
|
||||||
|
$(torrent_verify_deluge).hide();
|
||||||
|
$(torrent_verify_rtorrent).show();
|
||||||
|
$(torrent_auth_type).show();
|
||||||
//$('#directory_title').text(client + directory);
|
//$('#directory_title').text(client + directory);
|
||||||
}
|
}
|
||||||
$('#host_title').text(client + host);
|
$('#host_title').text(client + host);
|
||||||
|
@ -51,7 +51,7 @@ $(document).ready(function () {
|
|||||||
},
|
},
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
var firstResult = true;
|
var firstResult = true;
|
||||||
var resultStr = '<fieldset>\n<legend>Search Results:</legend>\n';
|
var resultStr = '<fieldset>\n<legend class="legendStep">Search Results:</legend>\n';
|
||||||
var checked = '';
|
var checked = '';
|
||||||
|
|
||||||
if (data.results.length === 0) {
|
if (data.results.length === 0) {
|
||||||
@ -68,7 +68,7 @@ $(document).ready(function () {
|
|||||||
var whichSeries = obj.join('|');
|
var whichSeries = obj.join('|');
|
||||||
|
|
||||||
|
|
||||||
resultStr += '<input type="radio" id="whichSeries" name="whichSeries" value="' + whichSeries + '"' + checked + ' /> ';
|
resultStr += '<input type="radio" id="whichSeries" name="whichSeries" value="' + whichSeries.replace(/"/g, "") + '"' + checked + ' /> ';
|
||||||
if (data.langid && data.langid != "") {
|
if (data.langid && data.langid != "") {
|
||||||
resultStr += '<a href="' + anonURL + obj[2] + obj[3] + '&lid=' + data.langid + '" onclick=\"window.open(this.href, \'_blank\'); return false;\" ><b>' + obj[4] + '</b></a>';
|
resultStr += '<a href="' + anonURL + obj[2] + obj[3] + '&lid=' + data.langid + '" onclick=\"window.open(this.href, \'_blank\'); return false;\" ><b>' + obj[4] + '</b></a>';
|
||||||
} else {
|
} else {
|
||||||
|
@ -144,7 +144,7 @@ case "$1" in
|
|||||||
stop_sickbeard
|
stop_sickbeard
|
||||||
sleep 2
|
sleep 2
|
||||||
start_sickbeard
|
start_sickbeard
|
||||||
return $?
|
exit $?
|
||||||
;;
|
;;
|
||||||
status)
|
status)
|
||||||
status_of_proc -p "$PID_FILE" "$DAEMON" "$DESC"
|
status_of_proc -p "$PID_FILE" "$DAEMON" "$DESC"
|
||||||
|
@ -58,7 +58,11 @@ class CacheControlAdapter(HTTPAdapter):
|
|||||||
response = cached_response
|
response = cached_response
|
||||||
else:
|
else:
|
||||||
# try to cache the response
|
# try to cache the response
|
||||||
|
try:
|
||||||
self.controller.cache_response(request, response)
|
self.controller.cache_response(request, response)
|
||||||
|
except Exception as e:
|
||||||
|
# Failed to cache the results
|
||||||
|
pass
|
||||||
|
|
||||||
resp = super(CacheControlAdapter, self).build_response(
|
resp = super(CacheControlAdapter, self).build_response(
|
||||||
request, response
|
request, response
|
||||||
|
@ -5,6 +5,7 @@ import os
|
|||||||
|
|
||||||
from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout,
|
from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout,
|
||||||
AlreadyLocked)
|
AlreadyLocked)
|
||||||
|
import errno
|
||||||
|
|
||||||
class LinkLockFile(LockBase):
|
class LinkLockFile(LockBase):
|
||||||
"""Lock access to a file using atomic property of link(2).
|
"""Lock access to a file using atomic property of link(2).
|
||||||
@ -28,7 +29,9 @@ class LinkLockFile(LockBase):
|
|||||||
# Try and create a hard link to it.
|
# Try and create a hard link to it.
|
||||||
try:
|
try:
|
||||||
os.link(self.unique_name, self.lock_file)
|
os.link(self.unique_name, self.lock_file)
|
||||||
except OSError:
|
except OSError as e:
|
||||||
|
if e.errno == errno.ENOSYS:
|
||||||
|
raise LockFailed("%s" % e.strerror)
|
||||||
# Link creation failed. Maybe we've double-locked?
|
# Link creation failed. Maybe we've double-locked?
|
||||||
nlinks = os.stat(self.unique_name).st_nlink
|
nlinks = os.stat(self.unique_name).st_nlink
|
||||||
if nlinks == 2:
|
if nlinks == 2:
|
||||||
|
@ -13,7 +13,7 @@ Requests is an HTTP library, written in Python, for human beings. Basic GET
|
|||||||
usage:
|
usage:
|
||||||
|
|
||||||
>>> import requests
|
>>> import requests
|
||||||
>>> r = requests.get('http://python.org')
|
>>> r = requests.get('https://www.python.org')
|
||||||
>>> r.status_code
|
>>> r.status_code
|
||||||
200
|
200
|
||||||
>>> 'Python is a programming language' in r.content
|
>>> 'Python is a programming language' in r.content
|
||||||
@ -22,7 +22,7 @@ usage:
|
|||||||
... or POST:
|
... or POST:
|
||||||
|
|
||||||
>>> payload = dict(key1='value1', key2='value2')
|
>>> payload = dict(key1='value1', key2='value2')
|
||||||
>>> r = requests.post("http://httpbin.org/post", data=payload)
|
>>> r = requests.post('http://httpbin.org/post', data=payload)
|
||||||
>>> print(r.text)
|
>>> print(r.text)
|
||||||
{
|
{
|
||||||
...
|
...
|
||||||
@ -36,17 +36,17 @@ usage:
|
|||||||
The other HTTP methods are supported - see `requests.api`. Full documentation
|
The other HTTP methods are supported - see `requests.api`. Full documentation
|
||||||
is at <http://python-requests.org>.
|
is at <http://python-requests.org>.
|
||||||
|
|
||||||
:copyright: (c) 2014 by Kenneth Reitz.
|
:copyright: (c) 2015 by Kenneth Reitz.
|
||||||
:license: Apache 2.0, see LICENSE for more details.
|
:license: Apache 2.0, see LICENSE for more details.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__title__ = 'requests'
|
__title__ = 'requests'
|
||||||
__version__ = '2.3.0'
|
__version__ = '2.5.1'
|
||||||
__build__ = 0x020300
|
__build__ = 0x020501
|
||||||
__author__ = 'Kenneth Reitz'
|
__author__ = 'Kenneth Reitz'
|
||||||
__license__ = 'Apache 2.0'
|
__license__ = 'Apache 2.0'
|
||||||
__copyright__ = 'Copyright 2014 Kenneth Reitz'
|
__copyright__ = 'Copyright 2015 Kenneth Reitz'
|
||||||
|
|
||||||
# Attempt to enable urllib3's SNI support, if possible
|
# Attempt to enable urllib3's SNI support, if possible
|
||||||
try:
|
try:
|
||||||
|
@ -9,23 +9,27 @@ and maintain connections.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
import copy
|
|
||||||
|
|
||||||
from .models import Response
|
from .models import Response
|
||||||
|
from .packages.urllib3 import Retry
|
||||||
from .packages.urllib3.poolmanager import PoolManager, proxy_from_url
|
from .packages.urllib3.poolmanager import PoolManager, proxy_from_url
|
||||||
from .packages.urllib3.response import HTTPResponse
|
from .packages.urllib3.response import HTTPResponse
|
||||||
from .packages.urllib3.util import Timeout as TimeoutSauce
|
from .packages.urllib3.util import Timeout as TimeoutSauce
|
||||||
from .compat import urlparse, basestring, urldefrag, unquote
|
from .compat import urlparse, basestring
|
||||||
from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers,
|
from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers,
|
||||||
except_on_missing_scheme, get_auth_from_url)
|
prepend_scheme_if_needed, get_auth_from_url, urldefragauth)
|
||||||
from .structures import CaseInsensitiveDict
|
from .structures import CaseInsensitiveDict
|
||||||
from .packages.urllib3.exceptions import MaxRetryError
|
from .packages.urllib3.exceptions import ConnectTimeoutError
|
||||||
from .packages.urllib3.exceptions import TimeoutError
|
|
||||||
from .packages.urllib3.exceptions import SSLError as _SSLError
|
|
||||||
from .packages.urllib3.exceptions import HTTPError as _HTTPError
|
from .packages.urllib3.exceptions import HTTPError as _HTTPError
|
||||||
|
from .packages.urllib3.exceptions import MaxRetryError
|
||||||
from .packages.urllib3.exceptions import ProxyError as _ProxyError
|
from .packages.urllib3.exceptions import ProxyError as _ProxyError
|
||||||
|
from .packages.urllib3.exceptions import ProtocolError
|
||||||
|
from .packages.urllib3.exceptions import ReadTimeoutError
|
||||||
|
from .packages.urllib3.exceptions import SSLError as _SSLError
|
||||||
|
from .packages.urllib3.exceptions import ResponseError
|
||||||
from .cookies import extract_cookies_to_jar
|
from .cookies import extract_cookies_to_jar
|
||||||
from .exceptions import ConnectionError, Timeout, SSLError, ProxyError
|
from .exceptions import (ConnectionError, ConnectTimeout, ReadTimeout, SSLError,
|
||||||
|
ProxyError, RetryError)
|
||||||
from .auth import _basic_auth_str
|
from .auth import _basic_auth_str
|
||||||
|
|
||||||
DEFAULT_POOLBLOCK = False
|
DEFAULT_POOLBLOCK = False
|
||||||
@ -57,13 +61,17 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
:param pool_connections: The number of urllib3 connection pools to cache.
|
:param pool_connections: The number of urllib3 connection pools to cache.
|
||||||
:param pool_maxsize: The maximum number of connections to save in the pool.
|
:param pool_maxsize: The maximum number of connections to save in the pool.
|
||||||
:param int max_retries: The maximum number of retries each connection
|
:param int max_retries: The maximum number of retries each connection
|
||||||
should attempt. Note, this applies only to failed connections and
|
should attempt. Note, this applies only to failed DNS lookups, socket
|
||||||
timeouts, never to requests where the server returns a response.
|
connections and connection timeouts, never to requests where data has
|
||||||
|
made it to the server. By default, Requests does not retry failed
|
||||||
|
connections. If you need granular control over the conditions under
|
||||||
|
which we retry a request, import urllib3's ``Retry`` class and pass
|
||||||
|
that instead.
|
||||||
:param pool_block: Whether the connection pool should block for connections.
|
:param pool_block: Whether the connection pool should block for connections.
|
||||||
|
|
||||||
Usage::
|
Usage::
|
||||||
|
|
||||||
>>> import lib.requests
|
>>> import requests
|
||||||
>>> s = requests.Session()
|
>>> s = requests.Session()
|
||||||
>>> a = requests.adapters.HTTPAdapter(max_retries=3)
|
>>> a = requests.adapters.HTTPAdapter(max_retries=3)
|
||||||
>>> s.mount('http://', a)
|
>>> s.mount('http://', a)
|
||||||
@ -74,7 +82,10 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
def __init__(self, pool_connections=DEFAULT_POOLSIZE,
|
def __init__(self, pool_connections=DEFAULT_POOLSIZE,
|
||||||
pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES,
|
pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES,
|
||||||
pool_block=DEFAULT_POOLBLOCK):
|
pool_block=DEFAULT_POOLBLOCK):
|
||||||
self.max_retries = max_retries
|
if max_retries == DEFAULT_RETRIES:
|
||||||
|
self.max_retries = Retry(0, read=False)
|
||||||
|
else:
|
||||||
|
self.max_retries = Retry.from_int(max_retries)
|
||||||
self.config = {}
|
self.config = {}
|
||||||
self.proxy_manager = {}
|
self.proxy_manager = {}
|
||||||
|
|
||||||
@ -102,14 +113,17 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
self.init_poolmanager(self._pool_connections, self._pool_maxsize,
|
self.init_poolmanager(self._pool_connections, self._pool_maxsize,
|
||||||
block=self._pool_block)
|
block=self._pool_block)
|
||||||
|
|
||||||
def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK):
|
def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs):
|
||||||
"""Initializes a urllib3 PoolManager. This method should not be called
|
"""Initializes a urllib3 PoolManager.
|
||||||
from user code, and is only exposed for use when subclassing the
|
|
||||||
|
This method should not be called from user code, and is only
|
||||||
|
exposed for use when subclassing the
|
||||||
:class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
|
:class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
|
||||||
|
|
||||||
:param connections: The number of urllib3 connection pools to cache.
|
:param connections: The number of urllib3 connection pools to cache.
|
||||||
:param maxsize: The maximum number of connections to save in the pool.
|
:param maxsize: The maximum number of connections to save in the pool.
|
||||||
:param block: Block when no free connections are available.
|
:param block: Block when no free connections are available.
|
||||||
|
:param pool_kwargs: Extra keyword arguments used to initialize the Pool Manager.
|
||||||
"""
|
"""
|
||||||
# save these values for pickling
|
# save these values for pickling
|
||||||
self._pool_connections = connections
|
self._pool_connections = connections
|
||||||
@ -117,7 +131,30 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
self._pool_block = block
|
self._pool_block = block
|
||||||
|
|
||||||
self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize,
|
self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize,
|
||||||
block=block)
|
block=block, strict=True, **pool_kwargs)
|
||||||
|
|
||||||
|
def proxy_manager_for(self, proxy, **proxy_kwargs):
|
||||||
|
"""Return urllib3 ProxyManager for the given proxy.
|
||||||
|
|
||||||
|
This method should not be called from user code, and is only
|
||||||
|
exposed for use when subclassing the
|
||||||
|
:class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
|
||||||
|
|
||||||
|
:param proxy: The proxy to return a urllib3 ProxyManager for.
|
||||||
|
:param proxy_kwargs: Extra keyword arguments used to configure the Proxy Manager.
|
||||||
|
:returns: ProxyManager
|
||||||
|
"""
|
||||||
|
if not proxy in self.proxy_manager:
|
||||||
|
proxy_headers = self.proxy_headers(proxy)
|
||||||
|
self.proxy_manager[proxy] = proxy_from_url(
|
||||||
|
proxy,
|
||||||
|
proxy_headers=proxy_headers,
|
||||||
|
num_pools=self._pool_connections,
|
||||||
|
maxsize=self._pool_maxsize,
|
||||||
|
block=self._pool_block,
|
||||||
|
**proxy_kwargs)
|
||||||
|
|
||||||
|
return self.proxy_manager[proxy]
|
||||||
|
|
||||||
def cert_verify(self, conn, url, verify, cert):
|
def cert_verify(self, conn, url, verify, cert):
|
||||||
"""Verify a SSL certificate. This method should not be called from user
|
"""Verify a SSL certificate. This method should not be called from user
|
||||||
@ -204,18 +241,9 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
proxy = proxies.get(urlparse(url.lower()).scheme)
|
proxy = proxies.get(urlparse(url.lower()).scheme)
|
||||||
|
|
||||||
if proxy:
|
if proxy:
|
||||||
except_on_missing_scheme(proxy)
|
proxy = prepend_scheme_if_needed(proxy, 'http')
|
||||||
proxy_headers = self.proxy_headers(proxy)
|
proxy_manager = self.proxy_manager_for(proxy)
|
||||||
|
conn = proxy_manager.connection_from_url(url)
|
||||||
if not proxy in self.proxy_manager:
|
|
||||||
self.proxy_manager[proxy] = proxy_from_url(
|
|
||||||
proxy,
|
|
||||||
proxy_headers=proxy_headers,
|
|
||||||
num_pools=self._pool_connections,
|
|
||||||
maxsize=self._pool_maxsize,
|
|
||||||
block=self._pool_block)
|
|
||||||
|
|
||||||
conn = self.proxy_manager[proxy].connection_from_url(url)
|
|
||||||
else:
|
else:
|
||||||
# Only scheme should be lower case
|
# Only scheme should be lower case
|
||||||
parsed = urlparse(url)
|
parsed = urlparse(url)
|
||||||
@ -250,7 +278,7 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
proxy = proxies.get(scheme)
|
proxy = proxies.get(scheme)
|
||||||
|
|
||||||
if proxy and scheme != 'https':
|
if proxy and scheme != 'https':
|
||||||
url, _ = urldefrag(request.url)
|
url = urldefragauth(request.url)
|
||||||
else:
|
else:
|
||||||
url = request.path_url
|
url = request.path_url
|
||||||
|
|
||||||
@ -297,7 +325,10 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
|
|
||||||
:param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
|
:param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
|
||||||
:param stream: (optional) Whether to stream the request content.
|
:param stream: (optional) Whether to stream the request content.
|
||||||
:param timeout: (optional) The timeout on the request.
|
:param timeout: (optional) How long to wait for the server to send
|
||||||
|
data before giving up, as a float, or a (`connect timeout, read
|
||||||
|
timeout <user/advanced.html#timeouts>`_) tuple.
|
||||||
|
:type timeout: float or tuple
|
||||||
:param verify: (optional) Whether to verify SSL certificates.
|
:param verify: (optional) Whether to verify SSL certificates.
|
||||||
:param cert: (optional) Any user-provided SSL certificate to be trusted.
|
:param cert: (optional) Any user-provided SSL certificate to be trusted.
|
||||||
:param proxies: (optional) The proxies dictionary to apply to the request.
|
:param proxies: (optional) The proxies dictionary to apply to the request.
|
||||||
@ -311,6 +342,17 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
|
|
||||||
chunked = not (request.body is None or 'Content-Length' in request.headers)
|
chunked = not (request.body is None or 'Content-Length' in request.headers)
|
||||||
|
|
||||||
|
if isinstance(timeout, tuple):
|
||||||
|
try:
|
||||||
|
connect, read = timeout
|
||||||
|
timeout = TimeoutSauce(connect=connect, read=read)
|
||||||
|
except ValueError as e:
|
||||||
|
# this may raise a string formatting error.
|
||||||
|
err = ("Invalid timeout {0}. Pass a (connect, read) "
|
||||||
|
"timeout tuple, or a single float to set "
|
||||||
|
"both timeouts to the same value".format(timeout))
|
||||||
|
raise ValueError(err)
|
||||||
|
else:
|
||||||
timeout = TimeoutSauce(connect=timeout, read=timeout)
|
timeout = TimeoutSauce(connect=timeout, read=timeout)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -369,10 +411,16 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
# All is well, return the connection to the pool.
|
# All is well, return the connection to the pool.
|
||||||
conn._put_conn(low_conn)
|
conn._put_conn(low_conn)
|
||||||
|
|
||||||
except socket.error as sockerr:
|
except (ProtocolError, socket.error) as err:
|
||||||
raise ConnectionError(sockerr, request=request)
|
raise ConnectionError(err, request=request)
|
||||||
|
|
||||||
except MaxRetryError as e:
|
except MaxRetryError as e:
|
||||||
|
if isinstance(e.reason, ConnectTimeoutError):
|
||||||
|
raise ConnectTimeout(e, request=request)
|
||||||
|
|
||||||
|
if isinstance(e.reason, ResponseError):
|
||||||
|
raise RetryError(e, request=request)
|
||||||
|
|
||||||
raise ConnectionError(e, request=request)
|
raise ConnectionError(e, request=request)
|
||||||
|
|
||||||
except _ProxyError as e:
|
except _ProxyError as e:
|
||||||
@ -381,14 +429,9 @@ class HTTPAdapter(BaseAdapter):
|
|||||||
except (_SSLError, _HTTPError) as e:
|
except (_SSLError, _HTTPError) as e:
|
||||||
if isinstance(e, _SSLError):
|
if isinstance(e, _SSLError):
|
||||||
raise SSLError(e, request=request)
|
raise SSLError(e, request=request)
|
||||||
elif isinstance(e, TimeoutError):
|
elif isinstance(e, ReadTimeoutError):
|
||||||
raise Timeout(e, request=request)
|
raise ReadTimeout(e, request=request)
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
r = self.build_response(request, resp)
|
return self.build_response(request, resp)
|
||||||
|
|
||||||
if not stream:
|
|
||||||
r.content
|
|
||||||
|
|
||||||
return r
|
|
||||||
|
@ -22,12 +22,17 @@ def request(method, url, **kwargs):
|
|||||||
:param url: URL for the new :class:`Request` object.
|
:param url: URL for the new :class:`Request` object.
|
||||||
:param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
|
:param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
|
||||||
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
||||||
|
:param json: (optional) json data to send in the body of the :class:`Request`.
|
||||||
:param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
|
:param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
|
||||||
:param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
|
:param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
|
||||||
:param files: (optional) Dictionary of 'name': file-like-objects (or {'name': ('filename', fileobj)}) for multipart encoding upload.
|
:param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': ('filename', fileobj)}``) for multipart encoding upload.
|
||||||
:param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
|
:param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
|
||||||
:param timeout: (optional) Float describing the timeout of the request in seconds.
|
:param timeout: (optional) How long to wait for the server to send data
|
||||||
|
before giving up, as a float, or a (`connect timeout, read timeout
|
||||||
|
<user/advanced.html#timeouts>`_) tuple.
|
||||||
|
:type timeout: float or tuple
|
||||||
:param allow_redirects: (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed.
|
:param allow_redirects: (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed.
|
||||||
|
:type allow_redirects: bool
|
||||||
:param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
|
:param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
|
||||||
:param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided.
|
:param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided.
|
||||||
:param stream: (optional) if ``False``, the response content will be immediately downloaded.
|
:param stream: (optional) if ``False``, the response content will be immediately downloaded.
|
||||||
@ -41,7 +46,12 @@ def request(method, url, **kwargs):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
session = sessions.Session()
|
session = sessions.Session()
|
||||||
return session.request(method=method, url=url, **kwargs)
|
response = session.request(method=method, url=url, **kwargs)
|
||||||
|
# By explicitly closing the session, we avoid leaving sockets open which
|
||||||
|
# can trigger a ResourceWarning in some cases, and look like a memory leak
|
||||||
|
# in others.
|
||||||
|
session.close()
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
def get(url, **kwargs):
|
def get(url, **kwargs):
|
||||||
@ -77,15 +87,16 @@ def head(url, **kwargs):
|
|||||||
return request('head', url, **kwargs)
|
return request('head', url, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def post(url, data=None, **kwargs):
|
def post(url, data=None, json=None, **kwargs):
|
||||||
"""Sends a POST request. Returns :class:`Response` object.
|
"""Sends a POST request. Returns :class:`Response` object.
|
||||||
|
|
||||||
:param url: URL for the new :class:`Request` object.
|
:param url: URL for the new :class:`Request` object.
|
||||||
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
||||||
|
:param json: (optional) json data to send in the body of the :class:`Request`.
|
||||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return request('post', url, data=data, **kwargs)
|
return request('post', url, data=data, json=json, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def put(url, data=None, **kwargs):
|
def put(url, data=None, **kwargs):
|
||||||
|
@ -16,7 +16,8 @@ from base64 import b64encode
|
|||||||
|
|
||||||
from .compat import urlparse, str
|
from .compat import urlparse, str
|
||||||
from .cookies import extract_cookies_to_jar
|
from .cookies import extract_cookies_to_jar
|
||||||
from .utils import parse_dict_header
|
from .utils import parse_dict_header, to_native_string
|
||||||
|
from .status_codes import codes
|
||||||
|
|
||||||
CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded'
|
CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded'
|
||||||
CONTENT_TYPE_MULTI_PART = 'multipart/form-data'
|
CONTENT_TYPE_MULTI_PART = 'multipart/form-data'
|
||||||
@ -25,7 +26,11 @@ CONTENT_TYPE_MULTI_PART = 'multipart/form-data'
|
|||||||
def _basic_auth_str(username, password):
|
def _basic_auth_str(username, password):
|
||||||
"""Returns a Basic Auth string."""
|
"""Returns a Basic Auth string."""
|
||||||
|
|
||||||
return 'Basic ' + b64encode(('%s:%s' % (username, password)).encode('latin1')).strip().decode('latin1')
|
authstr = 'Basic ' + to_native_string(
|
||||||
|
b64encode(('%s:%s' % (username, password)).encode('latin1')).strip()
|
||||||
|
)
|
||||||
|
|
||||||
|
return authstr
|
||||||
|
|
||||||
|
|
||||||
class AuthBase(object):
|
class AuthBase(object):
|
||||||
@ -62,6 +67,7 @@ class HTTPDigestAuth(AuthBase):
|
|||||||
self.nonce_count = 0
|
self.nonce_count = 0
|
||||||
self.chal = {}
|
self.chal = {}
|
||||||
self.pos = None
|
self.pos = None
|
||||||
|
self.num_401_calls = 1
|
||||||
|
|
||||||
def build_digest_header(self, method, url):
|
def build_digest_header(self, method, url):
|
||||||
|
|
||||||
@ -146,6 +152,11 @@ class HTTPDigestAuth(AuthBase):
|
|||||||
|
|
||||||
return 'Digest %s' % (base)
|
return 'Digest %s' % (base)
|
||||||
|
|
||||||
|
def handle_redirect(self, r, **kwargs):
|
||||||
|
"""Reset num_401_calls counter on redirects."""
|
||||||
|
if r.is_redirect:
|
||||||
|
self.num_401_calls = 1
|
||||||
|
|
||||||
def handle_401(self, r, **kwargs):
|
def handle_401(self, r, **kwargs):
|
||||||
"""Takes the given response and tries digest-auth, if needed."""
|
"""Takes the given response and tries digest-auth, if needed."""
|
||||||
|
|
||||||
@ -158,7 +169,7 @@ class HTTPDigestAuth(AuthBase):
|
|||||||
|
|
||||||
if 'digest' in s_auth.lower() and num_401_calls < 2:
|
if 'digest' in s_auth.lower() and num_401_calls < 2:
|
||||||
|
|
||||||
setattr(self, 'num_401_calls', num_401_calls + 1)
|
self.num_401_calls += 1
|
||||||
pat = re.compile(r'digest ', flags=re.IGNORECASE)
|
pat = re.compile(r'digest ', flags=re.IGNORECASE)
|
||||||
self.chal = parse_dict_header(pat.sub('', s_auth, count=1))
|
self.chal = parse_dict_header(pat.sub('', s_auth, count=1))
|
||||||
|
|
||||||
@ -178,7 +189,7 @@ class HTTPDigestAuth(AuthBase):
|
|||||||
|
|
||||||
return _r
|
return _r
|
||||||
|
|
||||||
setattr(self, 'num_401_calls', 1)
|
self.num_401_calls = 1
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def __call__(self, r):
|
def __call__(self, r):
|
||||||
@ -188,6 +199,11 @@ class HTTPDigestAuth(AuthBase):
|
|||||||
try:
|
try:
|
||||||
self.pos = r.body.tell()
|
self.pos = r.body.tell()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
# In the case of HTTPDigestAuth being reused and the body of
|
||||||
|
# the previous request was a file-like object, pos has the
|
||||||
|
# file position of the previous body. Ensure it's set to
|
||||||
|
# None.
|
||||||
|
self.pos = None
|
||||||
r.register_hook('response', self.handle_401)
|
r.register_hook('response', self.handle_401)
|
||||||
|
r.register_hook('response', self.handle_redirect)
|
||||||
return r
|
return r
|
||||||
|
@ -11,10 +11,11 @@ If you are packaging Requests, e.g., for a Linux distribution or a managed
|
|||||||
environment, you can change the definition of where() to return a separately
|
environment, you can change the definition of where() to return a separately
|
||||||
packaged CA bundle.
|
packaged CA bundle.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
|
try:
|
||||||
|
from certifi import where
|
||||||
|
except ImportError:
|
||||||
def where():
|
def where():
|
||||||
"""Return the preferred certificate bundle."""
|
"""Return the preferred certificate bundle."""
|
||||||
# vendored bundle inside Requests
|
# vendored bundle inside Requests
|
||||||
|
@ -75,7 +75,9 @@ is_solaris = ('solar==' in str(sys.platform).lower()) # Complete guess.
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
import simplejson as json
|
import simplejson as json
|
||||||
except ImportError:
|
except (ImportError, SyntaxError):
|
||||||
|
# simplejson does not support Python 3.2, it throws a SyntaxError
|
||||||
|
# because of u'...' Unicode literals.
|
||||||
import json
|
import json
|
||||||
|
|
||||||
# ---------
|
# ---------
|
||||||
@ -90,7 +92,6 @@ if is_py2:
|
|||||||
from Cookie import Morsel
|
from Cookie import Morsel
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
from .packages.urllib3.packages.ordered_dict import OrderedDict
|
from .packages.urllib3.packages.ordered_dict import OrderedDict
|
||||||
from httplib import IncompleteRead
|
|
||||||
|
|
||||||
builtin_str = str
|
builtin_str = str
|
||||||
bytes = str
|
bytes = str
|
||||||
@ -106,7 +107,6 @@ elif is_py3:
|
|||||||
from http.cookies import Morsel
|
from http.cookies import Morsel
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from http.client import IncompleteRead
|
|
||||||
|
|
||||||
builtin_str = str
|
builtin_str = str
|
||||||
str = str
|
str = str
|
||||||
|
@ -157,26 +157,28 @@ class CookieConflictError(RuntimeError):
|
|||||||
|
|
||||||
|
|
||||||
class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
|
class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
|
||||||
"""Compatibility class; is a cookielib.CookieJar, but exposes a dict interface.
|
"""Compatibility class; is a cookielib.CookieJar, but exposes a dict
|
||||||
|
interface.
|
||||||
|
|
||||||
This is the CookieJar we create by default for requests and sessions that
|
This is the CookieJar we create by default for requests and sessions that
|
||||||
don't specify one, since some clients may expect response.cookies and
|
don't specify one, since some clients may expect response.cookies and
|
||||||
session.cookies to support dict operations.
|
session.cookies to support dict operations.
|
||||||
|
|
||||||
Don't use the dict interface internally; it's just for compatibility with
|
Requests does not use the dict interface internally; it's just for
|
||||||
with external client code. All `requests` code should work out of the box
|
compatibility with external client code. All requests code should work
|
||||||
with externally provided instances of CookieJar, e.g., LWPCookieJar and
|
out of the box with externally provided instances of ``CookieJar``, e.g.
|
||||||
FileCookieJar.
|
``LWPCookieJar`` and ``FileCookieJar``.
|
||||||
|
|
||||||
Caution: dictionary operations that are normally O(1) may be O(n).
|
|
||||||
|
|
||||||
Unlike a regular CookieJar, this class is pickleable.
|
Unlike a regular CookieJar, this class is pickleable.
|
||||||
"""
|
|
||||||
|
|
||||||
|
.. warning:: dictionary operations that are normally O(1) may be O(n).
|
||||||
|
"""
|
||||||
def get(self, name, default=None, domain=None, path=None):
|
def get(self, name, default=None, domain=None, path=None):
|
||||||
"""Dict-like get() that also supports optional domain and path args in
|
"""Dict-like get() that also supports optional domain and path args in
|
||||||
order to resolve naming collisions from using one cookie jar over
|
order to resolve naming collisions from using one cookie jar over
|
||||||
multiple domains. Caution: operation is O(n), not O(1)."""
|
multiple domains.
|
||||||
|
|
||||||
|
.. warning:: operation is O(n), not O(1)."""
|
||||||
try:
|
try:
|
||||||
return self._find_no_duplicates(name, domain, path)
|
return self._find_no_duplicates(name, domain, path)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -199,37 +201,38 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
|
|||||||
return c
|
return c
|
||||||
|
|
||||||
def iterkeys(self):
|
def iterkeys(self):
|
||||||
"""Dict-like iterkeys() that returns an iterator of names of cookies from the jar.
|
"""Dict-like iterkeys() that returns an iterator of names of cookies
|
||||||
See itervalues() and iteritems()."""
|
from the jar. See itervalues() and iteritems()."""
|
||||||
for cookie in iter(self):
|
for cookie in iter(self):
|
||||||
yield cookie.name
|
yield cookie.name
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
"""Dict-like keys() that returns a list of names of cookies from the jar.
|
"""Dict-like keys() that returns a list of names of cookies from the
|
||||||
See values() and items()."""
|
jar. See values() and items()."""
|
||||||
return list(self.iterkeys())
|
return list(self.iterkeys())
|
||||||
|
|
||||||
def itervalues(self):
|
def itervalues(self):
|
||||||
"""Dict-like itervalues() that returns an iterator of values of cookies from the jar.
|
"""Dict-like itervalues() that returns an iterator of values of cookies
|
||||||
See iterkeys() and iteritems()."""
|
from the jar. See iterkeys() and iteritems()."""
|
||||||
for cookie in iter(self):
|
for cookie in iter(self):
|
||||||
yield cookie.value
|
yield cookie.value
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
"""Dict-like values() that returns a list of values of cookies from the jar.
|
"""Dict-like values() that returns a list of values of cookies from the
|
||||||
See keys() and items()."""
|
jar. See keys() and items()."""
|
||||||
return list(self.itervalues())
|
return list(self.itervalues())
|
||||||
|
|
||||||
def iteritems(self):
|
def iteritems(self):
|
||||||
"""Dict-like iteritems() that returns an iterator of name-value tuples from the jar.
|
"""Dict-like iteritems() that returns an iterator of name-value tuples
|
||||||
See iterkeys() and itervalues()."""
|
from the jar. See iterkeys() and itervalues()."""
|
||||||
for cookie in iter(self):
|
for cookie in iter(self):
|
||||||
yield cookie.name, cookie.value
|
yield cookie.name, cookie.value
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
"""Dict-like items() that returns a list of name-value tuples from the jar.
|
"""Dict-like items() that returns a list of name-value tuples from the
|
||||||
See keys() and values(). Allows client-code to call "dict(RequestsCookieJar)
|
jar. See keys() and values(). Allows client-code to call
|
||||||
and get a vanilla python dict of key value pairs."""
|
``dict(RequestsCookieJar)`` and get a vanilla python dict of key value
|
||||||
|
pairs."""
|
||||||
return list(self.iteritems())
|
return list(self.iteritems())
|
||||||
|
|
||||||
def list_domains(self):
|
def list_domains(self):
|
||||||
@ -259,8 +262,9 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
|
|||||||
return False # there is only one domain in jar
|
return False # there is only one domain in jar
|
||||||
|
|
||||||
def get_dict(self, domain=None, path=None):
|
def get_dict(self, domain=None, path=None):
|
||||||
"""Takes as an argument an optional domain and path and returns a plain old
|
"""Takes as an argument an optional domain and path and returns a plain
|
||||||
Python dict of name-value pairs of cookies that meet the requirements."""
|
old Python dict of name-value pairs of cookies that meet the
|
||||||
|
requirements."""
|
||||||
dictionary = {}
|
dictionary = {}
|
||||||
for cookie in iter(self):
|
for cookie in iter(self):
|
||||||
if (domain is None or cookie.domain == domain) and (path is None
|
if (domain is None or cookie.domain == domain) and (path is None
|
||||||
@ -269,21 +273,24 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
|
|||||||
return dictionary
|
return dictionary
|
||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
"""Dict-like __getitem__() for compatibility with client code. Throws exception
|
"""Dict-like __getitem__() for compatibility with client code. Throws
|
||||||
if there are more than one cookie with name. In that case, use the more
|
exception if there are more than one cookie with name. In that case,
|
||||||
explicit get() method instead. Caution: operation is O(n), not O(1)."""
|
use the more explicit get() method instead.
|
||||||
|
|
||||||
|
.. warning:: operation is O(n), not O(1)."""
|
||||||
|
|
||||||
return self._find_no_duplicates(name)
|
return self._find_no_duplicates(name)
|
||||||
|
|
||||||
def __setitem__(self, name, value):
|
def __setitem__(self, name, value):
|
||||||
"""Dict-like __setitem__ for compatibility with client code. Throws exception
|
"""Dict-like __setitem__ for compatibility with client code. Throws
|
||||||
if there is already a cookie of that name in the jar. In that case, use the more
|
exception if there is already a cookie of that name in the jar. In that
|
||||||
explicit set() method instead."""
|
case, use the more explicit set() method instead."""
|
||||||
|
|
||||||
self.set(name, value)
|
self.set(name, value)
|
||||||
|
|
||||||
def __delitem__(self, name):
|
def __delitem__(self, name):
|
||||||
"""Deletes a cookie given a name. Wraps cookielib.CookieJar's remove_cookie_by_name()."""
|
"""Deletes a cookie given a name. Wraps ``cookielib.CookieJar``'s
|
||||||
|
``remove_cookie_by_name()``."""
|
||||||
remove_cookie_by_name(self, name)
|
remove_cookie_by_name(self, name)
|
||||||
|
|
||||||
def set_cookie(self, cookie, *args, **kwargs):
|
def set_cookie(self, cookie, *args, **kwargs):
|
||||||
@ -300,10 +307,11 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
|
|||||||
super(RequestsCookieJar, self).update(other)
|
super(RequestsCookieJar, self).update(other)
|
||||||
|
|
||||||
def _find(self, name, domain=None, path=None):
|
def _find(self, name, domain=None, path=None):
|
||||||
"""Requests uses this method internally to get cookie values. Takes as args name
|
"""Requests uses this method internally to get cookie values. Takes as
|
||||||
and optional domain and path. Returns a cookie.value. If there are conflicting cookies,
|
args name and optional domain and path. Returns a cookie.value. If
|
||||||
_find arbitrarily chooses one. See _find_no_duplicates if you want an exception thrown
|
there are conflicting cookies, _find arbitrarily chooses one. See
|
||||||
if there are conflicting cookies."""
|
_find_no_duplicates if you want an exception thrown if there are
|
||||||
|
conflicting cookies."""
|
||||||
for cookie in iter(self):
|
for cookie in iter(self):
|
||||||
if cookie.name == name:
|
if cookie.name == name:
|
||||||
if domain is None or cookie.domain == domain:
|
if domain is None or cookie.domain == domain:
|
||||||
@ -313,10 +321,11 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
|
|||||||
raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path))
|
raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path))
|
||||||
|
|
||||||
def _find_no_duplicates(self, name, domain=None, path=None):
|
def _find_no_duplicates(self, name, domain=None, path=None):
|
||||||
"""__get_item__ and get call _find_no_duplicates -- never used in Requests internally.
|
"""Both ``__get_item__`` and ``get`` call this function: it's never
|
||||||
Takes as args name and optional domain and path. Returns a cookie.value.
|
used elsewhere in Requests. Takes as args name and optional domain and
|
||||||
Throws KeyError if cookie is not found and CookieConflictError if there are
|
path. Returns a cookie.value. Throws KeyError if cookie is not found
|
||||||
multiple cookies that match name and optionally domain and path."""
|
and CookieConflictError if there are multiple cookies that match name
|
||||||
|
and optionally domain and path."""
|
||||||
toReturn = None
|
toReturn = None
|
||||||
for cookie in iter(self):
|
for cookie in iter(self):
|
||||||
if cookie.name == name:
|
if cookie.name == name:
|
||||||
|
@ -44,7 +44,23 @@ class SSLError(ConnectionError):
|
|||||||
|
|
||||||
|
|
||||||
class Timeout(RequestException):
|
class Timeout(RequestException):
|
||||||
"""The request timed out."""
|
"""The request timed out.
|
||||||
|
|
||||||
|
Catching this error will catch both
|
||||||
|
:exc:`~requests.exceptions.ConnectTimeout` and
|
||||||
|
:exc:`~requests.exceptions.ReadTimeout` errors.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectTimeout(ConnectionError, Timeout):
|
||||||
|
"""The request timed out while trying to connect to the remote server.
|
||||||
|
|
||||||
|
Requests that produced this error are safe to retry.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class ReadTimeout(Timeout):
|
||||||
|
"""The server did not send any data in the allotted amount of time."""
|
||||||
|
|
||||||
|
|
||||||
class URLRequired(RequestException):
|
class URLRequired(RequestException):
|
||||||
@ -73,3 +89,11 @@ class ChunkedEncodingError(RequestException):
|
|||||||
|
|
||||||
class ContentDecodingError(RequestException, BaseHTTPError):
|
class ContentDecodingError(RequestException, BaseHTTPError):
|
||||||
"""Failed to decode response content"""
|
"""Failed to decode response content"""
|
||||||
|
|
||||||
|
|
||||||
|
class StreamConsumedError(RequestException, TypeError):
|
||||||
|
"""The content for this response was already consumed"""
|
||||||
|
|
||||||
|
|
||||||
|
class RetryError(RequestException):
|
||||||
|
"""Custom retries logic failed"""
|
||||||
|
@ -19,17 +19,18 @@ from .cookies import cookiejar_from_dict, get_cookie_header
|
|||||||
from .packages.urllib3.fields import RequestField
|
from .packages.urllib3.fields import RequestField
|
||||||
from .packages.urllib3.filepost import encode_multipart_formdata
|
from .packages.urllib3.filepost import encode_multipart_formdata
|
||||||
from .packages.urllib3.util import parse_url
|
from .packages.urllib3.util import parse_url
|
||||||
from .packages.urllib3.exceptions import DecodeError
|
from .packages.urllib3.exceptions import (
|
||||||
|
DecodeError, ReadTimeoutError, ProtocolError, LocationParseError)
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
HTTPError, RequestException, MissingSchema, InvalidURL,
|
HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError,
|
||||||
ChunkedEncodingError, ContentDecodingError)
|
ContentDecodingError, ConnectionError, StreamConsumedError)
|
||||||
from .utils import (
|
from .utils import (
|
||||||
guess_filename, get_auth_from_url, requote_uri,
|
guess_filename, get_auth_from_url, requote_uri,
|
||||||
stream_decode_response_unicode, to_key_val_list, parse_header_links,
|
stream_decode_response_unicode, to_key_val_list, parse_header_links,
|
||||||
iter_slices, guess_json_utf, super_len, to_native_string)
|
iter_slices, guess_json_utf, super_len, to_native_string)
|
||||||
from .compat import (
|
from .compat import (
|
||||||
cookielib, urlunparse, urlsplit, urlencode, str, bytes, StringIO,
|
cookielib, urlunparse, urlsplit, urlencode, str, bytes, StringIO,
|
||||||
is_py2, chardet, json, builtin_str, basestring, IncompleteRead)
|
is_py2, chardet, json, builtin_str, basestring)
|
||||||
from .status_codes import codes
|
from .status_codes import codes
|
||||||
|
|
||||||
#: The set of HTTP status codes that indicate an automatically
|
#: The set of HTTP status codes that indicate an automatically
|
||||||
@ -38,12 +39,15 @@ REDIRECT_STATI = (
|
|||||||
codes.moved, # 301
|
codes.moved, # 301
|
||||||
codes.found, # 302
|
codes.found, # 302
|
||||||
codes.other, # 303
|
codes.other, # 303
|
||||||
codes.temporary_moved, # 307
|
codes.temporary_redirect, # 307
|
||||||
|
codes.permanent_redirect, # 308
|
||||||
)
|
)
|
||||||
DEFAULT_REDIRECT_LIMIT = 30
|
DEFAULT_REDIRECT_LIMIT = 30
|
||||||
CONTENT_CHUNK_SIZE = 10 * 1024
|
CONTENT_CHUNK_SIZE = 10 * 1024
|
||||||
ITER_CHUNK_SIZE = 512
|
ITER_CHUNK_SIZE = 512
|
||||||
|
|
||||||
|
json_dumps = json.dumps
|
||||||
|
|
||||||
|
|
||||||
class RequestEncodingMixin(object):
|
class RequestEncodingMixin(object):
|
||||||
@property
|
@property
|
||||||
@ -187,7 +191,8 @@ class Request(RequestHooksMixin):
|
|||||||
:param url: URL to send.
|
:param url: URL to send.
|
||||||
:param headers: dictionary of headers to send.
|
:param headers: dictionary of headers to send.
|
||||||
:param files: dictionary of {filename: fileobject} files to multipart upload.
|
:param files: dictionary of {filename: fileobject} files to multipart upload.
|
||||||
:param data: the body to attach the request. If a dictionary is provided, form-encoding will take place.
|
:param data: the body to attach to the request. If a dictionary is provided, form-encoding will take place.
|
||||||
|
:param json: json for the body to attach to the request (if data is not specified).
|
||||||
:param params: dictionary of URL parameters to append to the URL.
|
:param params: dictionary of URL parameters to append to the URL.
|
||||||
:param auth: Auth handler or (user, pass) tuple.
|
:param auth: Auth handler or (user, pass) tuple.
|
||||||
:param cookies: dictionary or CookieJar of cookies to attach to this request.
|
:param cookies: dictionary or CookieJar of cookies to attach to this request.
|
||||||
@ -210,7 +215,8 @@ class Request(RequestHooksMixin):
|
|||||||
params=None,
|
params=None,
|
||||||
auth=None,
|
auth=None,
|
||||||
cookies=None,
|
cookies=None,
|
||||||
hooks=None):
|
hooks=None,
|
||||||
|
json=None):
|
||||||
|
|
||||||
# Default empty dicts for dict params.
|
# Default empty dicts for dict params.
|
||||||
data = [] if data is None else data
|
data = [] if data is None else data
|
||||||
@ -228,6 +234,7 @@ class Request(RequestHooksMixin):
|
|||||||
self.headers = headers
|
self.headers = headers
|
||||||
self.files = files
|
self.files = files
|
||||||
self.data = data
|
self.data = data
|
||||||
|
self.json = json
|
||||||
self.params = params
|
self.params = params
|
||||||
self.auth = auth
|
self.auth = auth
|
||||||
self.cookies = cookies
|
self.cookies = cookies
|
||||||
@ -244,6 +251,7 @@ class Request(RequestHooksMixin):
|
|||||||
headers=self.headers,
|
headers=self.headers,
|
||||||
files=self.files,
|
files=self.files,
|
||||||
data=self.data,
|
data=self.data,
|
||||||
|
json=self.json,
|
||||||
params=self.params,
|
params=self.params,
|
||||||
auth=self.auth,
|
auth=self.auth,
|
||||||
cookies=self.cookies,
|
cookies=self.cookies,
|
||||||
@ -287,14 +295,15 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
|||||||
self.hooks = default_hooks()
|
self.hooks = default_hooks()
|
||||||
|
|
||||||
def prepare(self, method=None, url=None, headers=None, files=None,
|
def prepare(self, method=None, url=None, headers=None, files=None,
|
||||||
data=None, params=None, auth=None, cookies=None, hooks=None):
|
data=None, params=None, auth=None, cookies=None, hooks=None,
|
||||||
|
json=None):
|
||||||
"""Prepares the entire request with the given parameters."""
|
"""Prepares the entire request with the given parameters."""
|
||||||
|
|
||||||
self.prepare_method(method)
|
self.prepare_method(method)
|
||||||
self.prepare_url(url, params)
|
self.prepare_url(url, params)
|
||||||
self.prepare_headers(headers)
|
self.prepare_headers(headers)
|
||||||
self.prepare_cookies(cookies)
|
self.prepare_cookies(cookies)
|
||||||
self.prepare_body(data, files)
|
self.prepare_body(data, files, json)
|
||||||
self.prepare_auth(auth, url)
|
self.prepare_auth(auth, url)
|
||||||
# Note that prepare_auth must be last to enable authentication schemes
|
# Note that prepare_auth must be last to enable authentication schemes
|
||||||
# such as OAuth to work on a fully prepared request.
|
# such as OAuth to work on a fully prepared request.
|
||||||
@ -309,8 +318,8 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
|||||||
p = PreparedRequest()
|
p = PreparedRequest()
|
||||||
p.method = self.method
|
p.method = self.method
|
||||||
p.url = self.url
|
p.url = self.url
|
||||||
p.headers = self.headers.copy()
|
p.headers = self.headers.copy() if self.headers is not None else None
|
||||||
p._cookies = self._cookies.copy()
|
p._cookies = self._cookies.copy() if self._cookies is not None else None
|
||||||
p.body = self.body
|
p.body = self.body
|
||||||
p.hooks = self.hooks
|
p.hooks = self.hooks
|
||||||
return p
|
return p
|
||||||
@ -324,21 +333,27 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
|||||||
def prepare_url(self, url, params):
|
def prepare_url(self, url, params):
|
||||||
"""Prepares the given HTTP URL."""
|
"""Prepares the given HTTP URL."""
|
||||||
#: Accept objects that have string representations.
|
#: Accept objects that have string representations.
|
||||||
try:
|
#: We're unable to blindy call unicode/str functions
|
||||||
url = unicode(url)
|
#: as this will include the bytestring indicator (b'')
|
||||||
except NameError:
|
#: on python 3.x.
|
||||||
# We're on Python 3.
|
#: https://github.com/kennethreitz/requests/pull/2238
|
||||||
url = str(url)
|
if isinstance(url, bytes):
|
||||||
except UnicodeDecodeError:
|
url = url.decode('utf8')
|
||||||
pass
|
else:
|
||||||
|
url = unicode(url) if is_py2 else str(url)
|
||||||
|
|
||||||
# Don't do any URL preparation for oddball schemes
|
# Don't do any URL preparation for non-HTTP schemes like `mailto`,
|
||||||
|
# `data` etc to work around exceptions from `url_parse`, which
|
||||||
|
# handles RFC 3986 only.
|
||||||
if ':' in url and not url.lower().startswith('http'):
|
if ':' in url and not url.lower().startswith('http'):
|
||||||
self.url = url
|
self.url = url
|
||||||
return
|
return
|
||||||
|
|
||||||
# Support for unicode domain names and paths.
|
# Support for unicode domain names and paths.
|
||||||
|
try:
|
||||||
scheme, auth, host, port, path, query, fragment = parse_url(url)
|
scheme, auth, host, port, path, query, fragment = parse_url(url)
|
||||||
|
except LocationParseError as e:
|
||||||
|
raise InvalidURL(*e.args)
|
||||||
|
|
||||||
if not scheme:
|
if not scheme:
|
||||||
raise MissingSchema("Invalid URL {0!r}: No schema supplied. "
|
raise MissingSchema("Invalid URL {0!r}: No schema supplied. "
|
||||||
@ -395,7 +410,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
|||||||
else:
|
else:
|
||||||
self.headers = CaseInsensitiveDict()
|
self.headers = CaseInsensitiveDict()
|
||||||
|
|
||||||
def prepare_body(self, data, files):
|
def prepare_body(self, data, files, json=None):
|
||||||
"""Prepares the given HTTP body data."""
|
"""Prepares the given HTTP body data."""
|
||||||
|
|
||||||
# Check if file, fo, generator, iterator.
|
# Check if file, fo, generator, iterator.
|
||||||
@ -406,11 +421,13 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
|||||||
content_type = None
|
content_type = None
|
||||||
length = None
|
length = None
|
||||||
|
|
||||||
|
if json is not None:
|
||||||
|
content_type = 'application/json'
|
||||||
|
body = json_dumps(json)
|
||||||
|
|
||||||
is_stream = all([
|
is_stream = all([
|
||||||
hasattr(data, '__iter__'),
|
hasattr(data, '__iter__'),
|
||||||
not isinstance(data, basestring),
|
not isinstance(data, (basestring, list, tuple, dict))
|
||||||
not isinstance(data, list),
|
|
||||||
not isinstance(data, dict)
|
|
||||||
])
|
])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -433,9 +450,9 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
|||||||
if files:
|
if files:
|
||||||
(body, content_type) = self._encode_files(files, data)
|
(body, content_type) = self._encode_files(files, data)
|
||||||
else:
|
else:
|
||||||
if data:
|
if data and json is None:
|
||||||
body = self._encode_params(data)
|
body = self._encode_params(data)
|
||||||
if isinstance(data, str) or isinstance(data, builtin_str) or hasattr(data, 'read'):
|
if isinstance(data, basestring) or hasattr(data, 'read'):
|
||||||
content_type = None
|
content_type = None
|
||||||
else:
|
else:
|
||||||
content_type = 'application/x-www-form-urlencoded'
|
content_type = 'application/x-www-form-urlencoded'
|
||||||
@ -443,7 +460,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
|||||||
self.prepare_content_length(body)
|
self.prepare_content_length(body)
|
||||||
|
|
||||||
# Add content-type if it wasn't explicitly provided.
|
# Add content-type if it wasn't explicitly provided.
|
||||||
if (content_type) and (not 'content-type' in self.headers):
|
if content_type and ('content-type' not in self.headers):
|
||||||
self.headers['Content-Type'] = content_type
|
self.headers['Content-Type'] = content_type
|
||||||
|
|
||||||
self.body = body
|
self.body = body
|
||||||
@ -457,7 +474,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
|||||||
l = super_len(body)
|
l = super_len(body)
|
||||||
if l:
|
if l:
|
||||||
self.headers['Content-Length'] = builtin_str(l)
|
self.headers['Content-Length'] = builtin_str(l)
|
||||||
elif self.method not in ('GET', 'HEAD'):
|
elif (self.method not in ('GET', 'HEAD')) and (self.headers.get('Content-Length') is None):
|
||||||
self.headers['Content-Length'] = '0'
|
self.headers['Content-Length'] = '0'
|
||||||
|
|
||||||
def prepare_auth(self, auth, url=''):
|
def prepare_auth(self, auth, url=''):
|
||||||
@ -558,6 +575,10 @@ class Response(object):
|
|||||||
#: and the arrival of the response (as a timedelta)
|
#: and the arrival of the response (as a timedelta)
|
||||||
self.elapsed = datetime.timedelta(0)
|
self.elapsed = datetime.timedelta(0)
|
||||||
|
|
||||||
|
#: The :class:`PreparedRequest <PreparedRequest>` object to which this
|
||||||
|
#: is a response.
|
||||||
|
self.request = None
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
# Consume everything; accessing the content attribute makes
|
# Consume everything; accessing the content attribute makes
|
||||||
# sure the content has been fully read.
|
# sure the content has been fully read.
|
||||||
@ -596,7 +617,7 @@ class Response(object):
|
|||||||
def ok(self):
|
def ok(self):
|
||||||
try:
|
try:
|
||||||
self.raise_for_status()
|
self.raise_for_status()
|
||||||
except RequestException:
|
except HTTPError:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -607,6 +628,11 @@ class Response(object):
|
|||||||
"""
|
"""
|
||||||
return ('location' in self.headers and self.status_code in REDIRECT_STATI)
|
return ('location' in self.headers and self.status_code in REDIRECT_STATI)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_permanent_redirect(self):
|
||||||
|
"""True if this Response one of the permanant versions of redirect"""
|
||||||
|
return ('location' in self.headers and self.status_code in (codes.moved_permanently, codes.permanent_redirect))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def apparent_encoding(self):
|
def apparent_encoding(self):
|
||||||
"""The apparent encoding, provided by the chardet library"""
|
"""The apparent encoding, provided by the chardet library"""
|
||||||
@ -618,21 +644,22 @@ class Response(object):
|
|||||||
large responses. The chunk size is the number of bytes it should
|
large responses. The chunk size is the number of bytes it should
|
||||||
read into memory. This is not necessarily the length of each item
|
read into memory. This is not necessarily the length of each item
|
||||||
returned as decoding can take place.
|
returned as decoding can take place.
|
||||||
"""
|
|
||||||
if self._content_consumed:
|
|
||||||
# simulate reading small chunks of the content
|
|
||||||
return iter_slices(self._content, chunk_size)
|
|
||||||
|
|
||||||
|
If decode_unicode is True, content will be decoded using the best
|
||||||
|
available encoding based on the response.
|
||||||
|
"""
|
||||||
def generate():
|
def generate():
|
||||||
try:
|
try:
|
||||||
# Special case for urllib3.
|
# Special case for urllib3.
|
||||||
try:
|
try:
|
||||||
for chunk in self.raw.stream(chunk_size, decode_content=True):
|
for chunk in self.raw.stream(chunk_size, decode_content=True):
|
||||||
yield chunk
|
yield chunk
|
||||||
except IncompleteRead as e:
|
except ProtocolError as e:
|
||||||
raise ChunkedEncodingError(e)
|
raise ChunkedEncodingError(e)
|
||||||
except DecodeError as e:
|
except DecodeError as e:
|
||||||
raise ContentDecodingError(e)
|
raise ContentDecodingError(e)
|
||||||
|
except ReadTimeoutError as e:
|
||||||
|
raise ConnectionError(e)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# Standard file-like object.
|
# Standard file-like object.
|
||||||
while True:
|
while True:
|
||||||
@ -643,14 +670,21 @@ class Response(object):
|
|||||||
|
|
||||||
self._content_consumed = True
|
self._content_consumed = True
|
||||||
|
|
||||||
gen = generate()
|
if self._content_consumed and isinstance(self._content, bool):
|
||||||
|
raise StreamConsumedError()
|
||||||
|
# simulate reading small chunks of the content
|
||||||
|
reused_chunks = iter_slices(self._content, chunk_size)
|
||||||
|
|
||||||
|
stream_chunks = generate()
|
||||||
|
|
||||||
|
chunks = reused_chunks if self._content_consumed else stream_chunks
|
||||||
|
|
||||||
if decode_unicode:
|
if decode_unicode:
|
||||||
gen = stream_decode_response_unicode(gen, self)
|
chunks = stream_decode_response_unicode(chunks, self)
|
||||||
|
|
||||||
return gen
|
return chunks
|
||||||
|
|
||||||
def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=None):
|
def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=None, delimiter=None):
|
||||||
"""Iterates over the response data, one line at a time. When
|
"""Iterates over the response data, one line at a time. When
|
||||||
stream=True is set on the request, this avoids reading the
|
stream=True is set on the request, this avoids reading the
|
||||||
content at once into memory for large responses.
|
content at once into memory for large responses.
|
||||||
@ -662,6 +696,10 @@ class Response(object):
|
|||||||
|
|
||||||
if pending is not None:
|
if pending is not None:
|
||||||
chunk = pending + chunk
|
chunk = pending + chunk
|
||||||
|
|
||||||
|
if delimiter:
|
||||||
|
lines = chunk.split(delimiter)
|
||||||
|
else:
|
||||||
lines = chunk.splitlines()
|
lines = chunk.splitlines()
|
||||||
|
|
||||||
if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]:
|
if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]:
|
||||||
@ -793,8 +831,8 @@ class Response(object):
|
|||||||
raise HTTPError(http_error_msg, response=self)
|
raise HTTPError(http_error_msg, response=self)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Closes the underlying file descriptor and releases the connection
|
"""Releases the connection back to the pool. Once this method has been
|
||||||
back to the pool.
|
called the underlying ``raw`` object must not be accessed again.
|
||||||
|
|
||||||
*Note: Should not normally need to be called explicitly.*
|
*Note: Should not normally need to be called explicitly.*
|
||||||
"""
|
"""
|
||||||
|
@ -1,3 +1,95 @@
|
|||||||
|
"""
|
||||||
|
Copyright (c) Donald Stufft, pip, and individual contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from . import urllib3
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class VendorAlias(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._vendor_name = __name__
|
||||||
|
self._vendor_pkg = self._vendor_name + "."
|
||||||
|
|
||||||
|
def find_module(self, fullname, path=None):
|
||||||
|
if fullname.startswith(self._vendor_pkg):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def load_module(self, name):
|
||||||
|
# Ensure that this only works for the vendored name
|
||||||
|
if not name.startswith(self._vendor_pkg):
|
||||||
|
raise ImportError(
|
||||||
|
"Cannot import %s, must be a subpackage of '%s'." % (
|
||||||
|
name, self._vendor_name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check to see if we already have this item in sys.modules, if we do
|
||||||
|
# then simply return that.
|
||||||
|
if name in sys.modules:
|
||||||
|
return sys.modules[name]
|
||||||
|
|
||||||
|
# Check to see if we can import the vendor name
|
||||||
|
try:
|
||||||
|
# We do this dance here because we want to try and import this
|
||||||
|
# module without hitting a recursion error because of a bunch of
|
||||||
|
# VendorAlias instances on sys.meta_path
|
||||||
|
real_meta_path = sys.meta_path[:]
|
||||||
|
try:
|
||||||
|
sys.meta_path = [
|
||||||
|
m for m in sys.meta_path
|
||||||
|
if not isinstance(m, VendorAlias)
|
||||||
|
]
|
||||||
|
__import__(name)
|
||||||
|
module = sys.modules[name]
|
||||||
|
finally:
|
||||||
|
# Re-add any additions to sys.meta_path that were made while
|
||||||
|
# during the import we just did, otherwise things like
|
||||||
|
# requests.packages.urllib3.poolmanager will fail.
|
||||||
|
for m in sys.meta_path:
|
||||||
|
if m not in real_meta_path:
|
||||||
|
real_meta_path.append(m)
|
||||||
|
|
||||||
|
# Restore sys.meta_path with any new items.
|
||||||
|
sys.meta_path = real_meta_path
|
||||||
|
except ImportError:
|
||||||
|
# We can't import the vendor name, so we'll try to import the
|
||||||
|
# "real" name.
|
||||||
|
real_name = name[len(self._vendor_pkg):]
|
||||||
|
try:
|
||||||
|
__import__(real_name)
|
||||||
|
module = sys.modules[real_name]
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError("No module named '%s'" % (name,))
|
||||||
|
|
||||||
|
# If we've gotten here we've found the module we're looking for, either
|
||||||
|
# as part of our vendored package, or as the real name, so we'll add
|
||||||
|
# it to sys.modules as the vendored name so that we don't have to do
|
||||||
|
# the lookup again.
|
||||||
|
sys.modules[name] = module
|
||||||
|
|
||||||
|
# Finally, return the loaded module
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
sys.meta_path.append(VendorAlias())
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
# 02110-1301 USA
|
# 02110-1301 USA
|
||||||
######################### END LICENSE BLOCK #########################
|
######################### END LICENSE BLOCK #########################
|
||||||
|
|
||||||
__version__ = "2.2.1"
|
__version__ = "2.3.0"
|
||||||
from sys import version_info
|
from sys import version_info
|
||||||
|
|
||||||
|
|
||||||
|
64
lib/requests/packages/chardet/chardetect.py
Normal file → Executable file
@ -12,34 +12,68 @@ Example::
|
|||||||
If no paths are provided, it takes its input from stdin.
|
If no paths are provided, it takes its input from stdin.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from io import open
|
|
||||||
from sys import argv, stdin
|
|
||||||
|
|
||||||
|
from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
from io import open
|
||||||
|
|
||||||
|
from chardet import __version__
|
||||||
from chardet.universaldetector import UniversalDetector
|
from chardet.universaldetector import UniversalDetector
|
||||||
|
|
||||||
|
|
||||||
def description_of(file, name='stdin'):
|
def description_of(lines, name='stdin'):
|
||||||
"""Return a string describing the probable encoding of a file."""
|
"""
|
||||||
|
Return a string describing the probable encoding of a file or
|
||||||
|
list of strings.
|
||||||
|
|
||||||
|
:param lines: The lines to get the encoding of.
|
||||||
|
:type lines: Iterable of bytes
|
||||||
|
:param name: Name of file or collection of lines
|
||||||
|
:type name: str
|
||||||
|
"""
|
||||||
u = UniversalDetector()
|
u = UniversalDetector()
|
||||||
for line in file:
|
for line in lines:
|
||||||
u.feed(line)
|
u.feed(line)
|
||||||
u.close()
|
u.close()
|
||||||
result = u.result
|
result = u.result
|
||||||
if result['encoding']:
|
if result['encoding']:
|
||||||
return '%s: %s with confidence %s' % (name,
|
return '{0}: {1} with confidence {2}'.format(name, result['encoding'],
|
||||||
result['encoding'],
|
|
||||||
result['confidence'])
|
result['confidence'])
|
||||||
else:
|
else:
|
||||||
return '%s: no result' % name
|
return '{0}: no result'.format(name)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main(argv=None):
|
||||||
if len(argv) <= 1:
|
'''
|
||||||
print(description_of(stdin))
|
Handles command line arguments and gets things started.
|
||||||
else:
|
|
||||||
for path in argv[1:]:
|
:param argv: List of arguments, as if specified on the command-line.
|
||||||
with open(path, 'rb') as f:
|
If None, ``sys.argv[1:]`` is used instead.
|
||||||
print(description_of(f, path))
|
:type argv: list of str
|
||||||
|
'''
|
||||||
|
# Get command line arguments
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Takes one or more file paths and reports their detected \
|
||||||
|
encodings",
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||||
|
conflict_handler='resolve')
|
||||||
|
parser.add_argument('input',
|
||||||
|
help='File whose encoding we would like to determine.',
|
||||||
|
type=argparse.FileType('rb'), nargs='*',
|
||||||
|
default=[sys.stdin])
|
||||||
|
parser.add_argument('--version', action='version',
|
||||||
|
version='%(prog)s {0}'.format(__version__))
|
||||||
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
|
for f in args.input:
|
||||||
|
if f.isatty():
|
||||||
|
print("You are running chardetect interactively. Press " +
|
||||||
|
"CTRL-D twice at the start of a blank line to signal the " +
|
||||||
|
"end of your input. If you want help, run chardetect " +
|
||||||
|
"--help\n", file=sys.stderr)
|
||||||
|
print(description_of(f, f.name))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -177,6 +177,12 @@ class JapaneseContextAnalysis:
|
|||||||
return -1, 1
|
return -1, 1
|
||||||
|
|
||||||
class SJISContextAnalysis(JapaneseContextAnalysis):
|
class SJISContextAnalysis(JapaneseContextAnalysis):
|
||||||
|
def __init__(self):
|
||||||
|
self.charset_name = "SHIFT_JIS"
|
||||||
|
|
||||||
|
def get_charset_name(self):
|
||||||
|
return self.charset_name
|
||||||
|
|
||||||
def get_order(self, aBuf):
|
def get_order(self, aBuf):
|
||||||
if not aBuf:
|
if not aBuf:
|
||||||
return -1, 1
|
return -1, 1
|
||||||
@ -184,6 +190,8 @@ class SJISContextAnalysis(JapaneseContextAnalysis):
|
|||||||
first_char = wrap_ord(aBuf[0])
|
first_char = wrap_ord(aBuf[0])
|
||||||
if ((0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC)):
|
if ((0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC)):
|
||||||
charLen = 2
|
charLen = 2
|
||||||
|
if (first_char == 0x87) or (0xFA <= first_char <= 0xFC):
|
||||||
|
self.charset_name = "CP932"
|
||||||
else:
|
else:
|
||||||
charLen = 1
|
charLen = 1
|
||||||
|
|
||||||
|
@ -129,11 +129,11 @@ class Latin1Prober(CharSetProber):
|
|||||||
if total < 0.01:
|
if total < 0.01:
|
||||||
confidence = 0.0
|
confidence = 0.0
|
||||||
else:
|
else:
|
||||||
confidence = ((self._mFreqCounter[3] / total)
|
confidence = ((self._mFreqCounter[3] - self._mFreqCounter[1] * 20.0)
|
||||||
- (self._mFreqCounter[1] * 20.0 / total))
|
/ total)
|
||||||
if confidence < 0.0:
|
if confidence < 0.0:
|
||||||
confidence = 0.0
|
confidence = 0.0
|
||||||
# lower the confidence of latin1 so that other more accurate
|
# lower the confidence of latin1 so that other more accurate
|
||||||
# detector can take priority.
|
# detector can take priority.
|
||||||
confidence = confidence * 0.5
|
confidence = confidence * 0.73
|
||||||
return confidence
|
return confidence
|
||||||
|
@ -353,7 +353,7 @@ SJIS_cls = (
|
|||||||
2,2,2,2,2,2,2,2, # 68 - 6f
|
2,2,2,2,2,2,2,2, # 68 - 6f
|
||||||
2,2,2,2,2,2,2,2, # 70 - 77
|
2,2,2,2,2,2,2,2, # 70 - 77
|
||||||
2,2,2,2,2,2,2,1, # 78 - 7f
|
2,2,2,2,2,2,2,1, # 78 - 7f
|
||||||
3,3,3,3,3,3,3,3, # 80 - 87
|
3,3,3,3,3,2,2,3, # 80 - 87
|
||||||
3,3,3,3,3,3,3,3, # 88 - 8f
|
3,3,3,3,3,3,3,3, # 88 - 8f
|
||||||
3,3,3,3,3,3,3,3, # 90 - 97
|
3,3,3,3,3,3,3,3, # 90 - 97
|
||||||
3,3,3,3,3,3,3,3, # 98 - 9f
|
3,3,3,3,3,3,3,3, # 98 - 9f
|
||||||
@ -369,9 +369,8 @@ SJIS_cls = (
|
|||||||
2,2,2,2,2,2,2,2, # d8 - df
|
2,2,2,2,2,2,2,2, # d8 - df
|
||||||
3,3,3,3,3,3,3,3, # e0 - e7
|
3,3,3,3,3,3,3,3, # e0 - e7
|
||||||
3,3,3,3,3,4,4,4, # e8 - ef
|
3,3,3,3,3,4,4,4, # e8 - ef
|
||||||
4,4,4,4,4,4,4,4, # f0 - f7
|
3,3,3,3,3,3,3,3, # f0 - f7
|
||||||
4,4,4,4,4,0,0,0 # f8 - ff
|
3,3,3,3,3,0,0,0) # f8 - ff
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
SJIS_st = (
|
SJIS_st = (
|
||||||
@ -571,5 +570,3 @@ UTF8SMModel = {'classTable': UTF8_cls,
|
|||||||
'stateTable': UTF8_st,
|
'stateTable': UTF8_st,
|
||||||
'charLenTable': UTF8CharLenTable,
|
'charLenTable': UTF8CharLenTable,
|
||||||
'name': 'UTF-8'}
|
'name': 'UTF-8'}
|
||||||
|
|
||||||
# flake8: noqa
|
|
||||||
|
@ -47,7 +47,7 @@ class SJISProber(MultiByteCharSetProber):
|
|||||||
self._mContextAnalyzer.reset()
|
self._mContextAnalyzer.reset()
|
||||||
|
|
||||||
def get_charset_name(self):
|
def get_charset_name(self):
|
||||||
return "SHIFT_JIS"
|
return self._mContextAnalyzer.get_charset_name()
|
||||||
|
|
||||||
def feed(self, aBuf):
|
def feed(self, aBuf):
|
||||||
aLen = len(aBuf)
|
aLen = len(aBuf)
|
||||||
|
@ -71,9 +71,9 @@ class UniversalDetector:
|
|||||||
|
|
||||||
if not self._mGotData:
|
if not self._mGotData:
|
||||||
# If the data starts with BOM, we know it is UTF
|
# If the data starts with BOM, we know it is UTF
|
||||||
if aBuf[:3] == codecs.BOM:
|
if aBuf[:3] == codecs.BOM_UTF8:
|
||||||
# EF BB BF UTF-8 with BOM
|
# EF BB BF UTF-8 with BOM
|
||||||
self.result = {'encoding': "UTF-8", 'confidence': 1.0}
|
self.result = {'encoding': "UTF-8-SIG", 'confidence': 1.0}
|
||||||
elif aBuf[:4] == codecs.BOM_UTF32_LE:
|
elif aBuf[:4] == codecs.BOM_UTF32_LE:
|
||||||
# FF FE 00 00 UTF-32, little-endian BOM
|
# FF FE 00 00 UTF-32, little-endian BOM
|
||||||
self.result = {'encoding': "UTF-32LE", 'confidence': 1.0}
|
self.result = {'encoding': "UTF-32LE", 'confidence': 1.0}
|
||||||
|