143 changed files with 6467 additions and 1248 deletions
@ -1,15 +0,0 @@ |
|||||
<!doctype html> |
|
||||
<html> |
|
||||
<head> |
|
||||
|
|
||||
<script type="text/javascript" src="{{ url_for('web.static', filename='scripts/library/mootools.js') }}"></script> |
|
||||
<script type="text/javascript" src="{{ url_for('web.static', filename='scripts/library/mootools_more.js') }}"></script> |
|
||||
|
|
||||
<script type="text/javascript"> |
|
||||
{{url}} |
|
||||
console.log('test'); |
|
||||
Api.request('') |
|
||||
</script> |
|
||||
</head> |
|
||||
<body></body> |
|
||||
</html> |
|
@ -0,0 +1,6 @@ |
|||||
|
from .main import V1Importer |
||||
|
|
||||
|
def start(): |
||||
|
return V1Importer() |
||||
|
|
||||
|
config = [] |
@ -0,0 +1,30 @@ |
|||||
|
<html> |
||||
|
<head> |
||||
|
<link rel="stylesheet" href="{{ url_for('web.static', filename='style/main.css') }}" type="text/css"> |
||||
|
<link rel="stylesheet" href="{{ url_for('web.static', filename='style/uniform.generic.css') }}" type="text/css"> |
||||
|
<link rel="stylesheet" href="{{ url_for('web.static', filename='style/uniform.css') }}" type="text/css"> |
||||
|
|
||||
|
<script type="text/javascript" src="{{ url_for('web.static', filename='scripts/library/mootools.js') }}"></script> |
||||
|
|
||||
|
<script type="text/javascript"> |
||||
|
|
||||
|
window.addEvent('domready', function(){ |
||||
|
if($('old_db')) |
||||
|
$('old_db').addEvent('change', function(){ |
||||
|
$('form').submit(); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
</head> |
||||
|
<body> |
||||
|
{% if message: %} |
||||
|
{{ message }} |
||||
|
{% else: %} |
||||
|
<form id="form" method="post" enctype="multipart/form-data"> |
||||
|
<input type="file" name="old_db" id="old_db" /> |
||||
|
</form> |
||||
|
{% endif %} |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,56 @@ |
|||||
|
from couchpotato.api import addApiView |
||||
|
from couchpotato.core.event import fireEventAsync |
||||
|
from couchpotato.core.helpers.variable import getImdb |
||||
|
from couchpotato.core.logger import CPLog |
||||
|
from couchpotato.core.plugins.base import Plugin |
||||
|
from couchpotato.environment import Env |
||||
|
from flask.globals import request |
||||
|
from flask.helpers import url_for |
||||
|
import os |
||||
|
|
||||
|
log = CPLog(__name__) |
||||
|
|
||||
|
|
||||
|
class V1Importer(Plugin): |
||||
|
|
||||
|
def __init__(self): |
||||
|
addApiView('v1.import', self.fromOld, methods = ['GET', 'POST']) |
||||
|
|
||||
|
def fromOld(self): |
||||
|
|
||||
|
if request.method != 'POST': |
||||
|
return self.renderTemplate(__file__, 'form.html', url_for = url_for) |
||||
|
|
||||
|
file = request.files['old_db'] |
||||
|
|
||||
|
uploaded_file = os.path.join(Env.get('cache_dir'), 'v1_database.db') |
||||
|
|
||||
|
if os.path.isfile(uploaded_file): |
||||
|
os.remove(uploaded_file) |
||||
|
|
||||
|
file.save(uploaded_file) |
||||
|
|
||||
|
try: |
||||
|
import sqlite3 |
||||
|
conn = sqlite3.connect(uploaded_file) |
||||
|
|
||||
|
wanted = [] |
||||
|
|
||||
|
t = ('want',) |
||||
|
cur = conn.execute('SELECT status, imdb FROM Movie WHERE status=?', t) |
||||
|
for row in cur: |
||||
|
status, imdb = row |
||||
|
if getImdb(imdb): |
||||
|
wanted.append(imdb) |
||||
|
conn.close() |
||||
|
|
||||
|
wanted = set(wanted) |
||||
|
for imdb in wanted: |
||||
|
fireEventAsync('movie.add', {'identifier': imdb}, search_after = False) |
||||
|
|
||||
|
message = 'Successfully imported %s movie(s)' % len(wanted) |
||||
|
except Exception, e: |
||||
|
message = 'Failed: %s' % e |
||||
|
|
||||
|
return self.renderTemplate(__file__, 'form.html', url_for = url_for, message = message) |
||||
|
|
@ -0,0 +1,249 @@ |
|||||
|
Afghanistan|AF|AFG|004|ISO 3166-2:AF |
||||
|
Åland Islands|AX|ALA|248|ISO 3166-2:AX |
||||
|
Albania|AL|ALB|008|ISO 3166-2:AL |
||||
|
Algeria|DZ|DZA|012|ISO 3166-2:DZ |
||||
|
American Samoa|AS|ASM|016|ISO 3166-2:AS |
||||
|
Andorra|AD|AND|020|ISO 3166-2:AD |
||||
|
Angola|AO|AGO|024|ISO 3166-2:AO |
||||
|
Anguilla|AI|AIA|660|ISO 3166-2:AI |
||||
|
Antarctica|AQ|ATA|010|ISO 3166-2:AQ |
||||
|
Antigua and Barbuda|AG|ATG|028|ISO 3166-2:AG |
||||
|
Argentina|AR|ARG|032|ISO 3166-2:AR |
||||
|
Armenia|AM|ARM|051|ISO 3166-2:AM |
||||
|
Aruba|AW|ABW|533|ISO 3166-2:AW |
||||
|
Australia|AU|AUS|036|ISO 3166-2:AU |
||||
|
Austria|AT|AUT|040|ISO 3166-2:AT |
||||
|
Azerbaijan|AZ|AZE|031|ISO 3166-2:AZ |
||||
|
Bahamas|BS|BHS|044|ISO 3166-2:BS |
||||
|
Bahrain|BH|BHR|048|ISO 3166-2:BH |
||||
|
Bangladesh|BD|BGD|050|ISO 3166-2:BD |
||||
|
Barbados|BB|BRB|052|ISO 3166-2:BB |
||||
|
Belarus|BY|BLR|112|ISO 3166-2:BY |
||||
|
Belgium|BE|BEL|056|ISO 3166-2:BE |
||||
|
Belize|BZ|BLZ|084|ISO 3166-2:BZ |
||||
|
Benin|BJ|BEN|204|ISO 3166-2:BJ |
||||
|
Bermuda|BM|BMU|060|ISO 3166-2:BM |
||||
|
Bhutan|BT|BTN|064|ISO 3166-2:BT |
||||
|
Bolivia, Plurinational State of|BO|BOL|068|ISO 3166-2:BO |
||||
|
Bonaire, Sint Eustatius and Saba|BQ|BES|535|ISO 3166-2:BQ |
||||
|
Bosnia and Herzegovina|BA|BIH|070|ISO 3166-2:BA |
||||
|
Botswana|BW|BWA|072|ISO 3166-2:BW |
||||
|
Bouvet Island|BV|BVT|074|ISO 3166-2:BV |
||||
|
Brazil|BR|BRA|076|ISO 3166-2:BR |
||||
|
British Indian Ocean Territory|IO|IOT|086|ISO 3166-2:IO |
||||
|
Brunei Darussalam|BN|BRN|096|ISO 3166-2:BN |
||||
|
Bulgaria|BG|BGR|100|ISO 3166-2:BG |
||||
|
Burkina Faso|BF|BFA|854|ISO 3166-2:BF |
||||
|
Burundi|BI|BDI|108|ISO 3166-2:BI |
||||
|
Cambodia|KH|KHM|116|ISO 3166-2:KH |
||||
|
Cameroon|CM|CMR|120|ISO 3166-2:CM |
||||
|
Canada|CA|CAN|124|ISO 3166-2:CA |
||||
|
Cape Verde|CV|CPV|132|ISO 3166-2:CV |
||||
|
Cayman Islands|KY|CYM|136|ISO 3166-2:KY |
||||
|
Central African Republic|CF|CAF|140|ISO 3166-2:CF |
||||
|
Chad|TD|TCD|148|ISO 3166-2:TD |
||||
|
Chile|CL|CHL|152|ISO 3166-2:CL |
||||
|
China|CN|CHN|156|ISO 3166-2:CN |
||||
|
Christmas Island|CX|CXR|162|ISO 3166-2:CX |
||||
|
Cocos (Keeling) Islands|CC|CCK|166|ISO 3166-2:CC |
||||
|
Colombia|CO|COL|170|ISO 3166-2:CO |
||||
|
Comoros|KM|COM|174|ISO 3166-2:KM |
||||
|
Congo|CG|COG|178|ISO 3166-2:CG |
||||
|
Congo, the Democratic Republic of the|CD|COD|180|ISO 3166-2:CD |
||||
|
Cook Islands|CK|COK|184|ISO 3166-2:CK |
||||
|
Costa Rica|CR|CRI|188|ISO 3166-2:CR |
||||
|
Côte d'Ivoire|CI|CIV|384|ISO 3166-2:CI |
||||
|
Croatia|HR|HRV|191|ISO 3166-2:HR |
||||
|
Cuba|CU|CUB|192|ISO 3166-2:CU |
||||
|
Curaçao|CW|CUW|531|ISO 3166-2:CW |
||||
|
Cyprus|CY|CYP|196|ISO 3166-2:CY |
||||
|
Czech Republic|CZ|CZE|203|ISO 3166-2:CZ |
||||
|
Denmark|DK|DNK|208|ISO 3166-2:DK |
||||
|
Djibouti|DJ|DJI|262|ISO 3166-2:DJ |
||||
|
Dominica|DM|DMA|212|ISO 3166-2:DM |
||||
|
Dominican Republic|DO|DOM|214|ISO 3166-2:DO |
||||
|
Ecuador|EC|ECU|218|ISO 3166-2:EC |
||||
|
Egypt|EG|EGY|818|ISO 3166-2:EG |
||||
|
El Salvador|SV|SLV|222|ISO 3166-2:SV |
||||
|
Equatorial Guinea|GQ|GNQ|226|ISO 3166-2:GQ |
||||
|
Eritrea|ER|ERI|232|ISO 3166-2:ER |
||||
|
Estonia|EE|EST|233|ISO 3166-2:EE |
||||
|
Ethiopia|ET|ETH|231|ISO 3166-2:ET |
||||
|
Falkland Islands (Malvinas|FK|FLK|238|ISO 3166-2:FK |
||||
|
Faroe Islands|FO|FRO|234|ISO 3166-2:FO |
||||
|
Fiji|FJ|FJI|242|ISO 3166-2:FJ |
||||
|
Finland|FI|FIN|246|ISO 3166-2:FI |
||||
|
France|FR|FRA|250|ISO 3166-2:FR |
||||
|
French Guiana|GF|GUF|254|ISO 3166-2:GF |
||||
|
French Polynesia|PF|PYF|258|ISO 3166-2:PF |
||||
|
French Southern Territories|TF|ATF|260|ISO 3166-2:TF |
||||
|
Gabon|GA|GAB|266|ISO 3166-2:GA |
||||
|
Gambia|GM|GMB|270|ISO 3166-2:GM |
||||
|
Georgia|GE|GEO|268|ISO 3166-2:GE |
||||
|
Germany|DE|DEU|276|ISO 3166-2:DE |
||||
|
Ghana|GH|GHA|288|ISO 3166-2:GH |
||||
|
Gibraltar|GI|GIB|292|ISO 3166-2:GI |
||||
|
Greece|GR|GRC|300|ISO 3166-2:GR |
||||
|
Greenland|GL|GRL|304|ISO 3166-2:GL |
||||
|
Grenada|GD|GRD|308|ISO 3166-2:GD |
||||
|
Guadeloupe|GP|GLP|312|ISO 3166-2:GP |
||||
|
Guam|GU|GUM|316|ISO 3166-2:GU |
||||
|
Guatemala|GT|GTM|320|ISO 3166-2:GT |
||||
|
Guernsey|GG|GGY|831|ISO 3166-2:GG |
||||
|
Guinea|GN|GIN|324|ISO 3166-2:GN |
||||
|
Guinea-Bissau|GW|GNB|624|ISO 3166-2:GW |
||||
|
Guyana|GY|GUY|328|ISO 3166-2:GY |
||||
|
Haiti|HT|HTI|332|ISO 3166-2:HT |
||||
|
Heard Island and McDonald Islands|HM|HMD|334|ISO 3166-2:HM |
||||
|
Holy See (Vatican City State|VA|VAT|336|ISO 3166-2:VA |
||||
|
Honduras|HN|HND|340|ISO 3166-2:HN |
||||
|
Hong Kong|HK|HKG|344|ISO 3166-2:HK |
||||
|
Hungary|HU|HUN|348|ISO 3166-2:HU |
||||
|
Iceland|IS|ISL|352|ISO 3166-2:IS |
||||
|
India|IN|IND|356|ISO 3166-2:IN |
||||
|
Indonesia|ID|IDN|360|ISO 3166-2:ID |
||||
|
Iran, Islamic Republic of|IR|IRN|364|ISO 3166-2:IR |
||||
|
Iraq|IQ|IRQ|368|ISO 3166-2:IQ |
||||
|
Ireland|IE|IRL|372|ISO 3166-2:IE |
||||
|
Isle of Man|IM|IMN|833|ISO 3166-2:IM |
||||
|
Israel|IL|ISR|376|ISO 3166-2:IL |
||||
|
Italy|IT|ITA|380|ISO 3166-2:IT |
||||
|
Jamaica|JM|JAM|388|ISO 3166-2:JM |
||||
|
Japan|JP|JPN|392|ISO 3166-2:JP |
||||
|
Jersey|JE|JEY|832|ISO 3166-2:JE |
||||
|
Jordan|JO|JOR|400|ISO 3166-2:JO |
||||
|
Kazakhstan|KZ|KAZ|398|ISO 3166-2:KZ |
||||
|
Kenya|KE|KEN|404|ISO 3166-2:KE |
||||
|
Kiribati|KI|KIR|296|ISO 3166-2:KI |
||||
|
Korea, Democratic People's Republic of|KP|PRK|408|ISO 3166-2:KP |
||||
|
Korea, Republic of|KR|KOR|410|ISO 3166-2:KR |
||||
|
Kuwait|KW|KWT|414|ISO 3166-2:KW |
||||
|
Kyrgyzstan|KG|KGZ|417|ISO 3166-2:KG |
||||
|
Lao People's Democratic Republic|LA|LAO|418|ISO 3166-2:LA |
||||
|
Latvia|LV|LVA|428|ISO 3166-2:LV |
||||
|
Lebanon|LB|LBN|422|ISO 3166-2:LB |
||||
|
Lesotho|LS|LSO|426|ISO 3166-2:LS |
||||
|
Liberia|LR|LBR|430|ISO 3166-2:LR |
||||
|
Libya|LY|LBY|434|ISO 3166-2:LY |
||||
|
Liechtenstein|LI|LIE|438|ISO 3166-2:LI |
||||
|
Lithuania|LT|LTU|440|ISO 3166-2:LT |
||||
|
Luxembourg|LU|LUX|442|ISO 3166-2:LU |
||||
|
Macao|MO|MAC|446|ISO 3166-2:MO |
||||
|
Macedonia, the former Yugoslav Republic of|MK|MKD|807|ISO 3166-2:MK |
||||
|
Madagascar|MG|MDG|450|ISO 3166-2:MG |
||||
|
Malawi|MW|MWI|454|ISO 3166-2:MW |
||||
|
Malaysia|MY|MYS|458|ISO 3166-2:MY |
||||
|
Maldives|MV|MDV|462|ISO 3166-2:MV |
||||
|
Mali|ML|MLI|466|ISO 3166-2:ML |
||||
|
Malta|MT|MLT|470|ISO 3166-2:MT |
||||
|
Marshall Islands|MH|MHL|584|ISO 3166-2:MH |
||||
|
Martinique|MQ|MTQ|474|ISO 3166-2:MQ |
||||
|
Mauritania|MR|MRT|478|ISO 3166-2:MR |
||||
|
Mauritius|MU|MUS|480|ISO 3166-2:MU |
||||
|
Mayotte|YT|MYT|175|ISO 3166-2:YT |
||||
|
Mexico|MX|MEX|484|ISO 3166-2:MX |
||||
|
Micronesia, Federated States of|FM|FSM|583|ISO 3166-2:FM |
||||
|
Moldova, Republic of|MD|MDA|498|ISO 3166-2:MD |
||||
|
Monaco|MC|MCO|492|ISO 3166-2:MC |
||||
|
Mongolia|MN|MNG|496|ISO 3166-2:MN |
||||
|
Montenegro|ME|MNE|499|ISO 3166-2:ME |
||||
|
Montserrat|MS|MSR|500|ISO 3166-2:MS |
||||
|
Morocco|MA|MAR|504|ISO 3166-2:MA |
||||
|
Mozambique|MZ|MOZ|508|ISO 3166-2:MZ |
||||
|
Myanmar|MM|MMR|104|ISO 3166-2:MM |
||||
|
Namibia|NA|NAM|516|ISO 3166-2:NA |
||||
|
Nauru|NR|NRU|520|ISO 3166-2:NR |
||||
|
Nepal|NP|NPL|524|ISO 3166-2:NP |
||||
|
Netherlands|NL|NLD|528|ISO 3166-2:NL |
||||
|
New Caledonia|NC|NCL|540|ISO 3166-2:NC |
||||
|
New Zealand|NZ|NZL|554|ISO 3166-2:NZ |
||||
|
Nicaragua|NI|NIC|558|ISO 3166-2:NI |
||||
|
Niger|NE|NER|562|ISO 3166-2:NE |
||||
|
Nigeria|NG|NGA|566|ISO 3166-2:NG |
||||
|
Niue|NU|NIU|570|ISO 3166-2:NU |
||||
|
Norfolk Island|NF|NFK|574|ISO 3166-2:NF |
||||
|
Northern Mariana Islands|MP|MNP|580|ISO 3166-2:MP |
||||
|
Norway|NO|NOR|578|ISO 3166-2:NO |
||||
|
Oman|OM|OMN|512|ISO 3166-2:OM |
||||
|
Pakistan|PK|PAK|586|ISO 3166-2:PK |
||||
|
Palau|PW|PLW|585|ISO 3166-2:PW |
||||
|
Palestinian Territory, Occupied|PS|PSE|275|ISO 3166-2:PS |
||||
|
Panama|PA|PAN|591|ISO 3166-2:PA |
||||
|
Papua New Guinea|PG|PNG|598|ISO 3166-2:PG |
||||
|
Paraguay|PY|PRY|600|ISO 3166-2:PY |
||||
|
Peru|PE|PER|604|ISO 3166-2:PE |
||||
|
Philippines|PH|PHL|608|ISO 3166-2:PH |
||||
|
Pitcairn|PN|PCN|612|ISO 3166-2:PN |
||||
|
Poland|PL|POL|616|ISO 3166-2:PL |
||||
|
Portugal|PT|PRT|620|ISO 3166-2:PT |
||||
|
Puerto Rico|PR|PRI|630|ISO 3166-2:PR |
||||
|
Qatar|QA|QAT|634|ISO 3166-2:QA |
||||
|
Réunion|RE|REU|638|ISO 3166-2:RE |
||||
|
Romania|RO|ROU|642|ISO 3166-2:RO |
||||
|
Russian Federation|RU|RUS|643|ISO 3166-2:RU |
||||
|
Rwanda|RW|RWA|646|ISO 3166-2:RW |
||||
|
Saint Barthélemy|BL|BLM|652|ISO 3166-2:BL |
||||
|
Saint Helena, Ascension and Tristan da Cunha|SH|SHN|654|ISO 3166-2:SH |
||||
|
Saint Kitts and Nevis|KN|KNA|659|ISO 3166-2:KN |
||||
|
Saint Lucia|LC|LCA|662|ISO 3166-2:LC |
||||
|
Saint Martin (French part|MF|MAF|663|ISO 3166-2:MF |
||||
|
Saint Pierre and Miquelon|PM|SPM|666|ISO 3166-2:PM |
||||
|
Saint Vincent and the Grenadines|VC|VCT|670|ISO 3166-2:VC |
||||
|
Samoa|WS|WSM|882|ISO 3166-2:WS |
||||
|
San Marino|SM|SMR|674|ISO 3166-2:SM |
||||
|
Sao Tome and Principe|ST|STP|678|ISO 3166-2:ST |
||||
|
Saudi Arabia|SA|SAU|682|ISO 3166-2:SA |
||||
|
Senegal|SN|SEN|686|ISO 3166-2:SN |
||||
|
Serbia|RS|SRB|688|ISO 3166-2:RS |
||||
|
Seychelles|SC|SYC|690|ISO 3166-2:SC |
||||
|
Sierra Leone|SL|SLE|694|ISO 3166-2:SL |
||||
|
Singapore|SG|SGP|702|ISO 3166-2:SG |
||||
|
Sint Maarten (Dutch part|SX|SXM|534|ISO 3166-2:SX |
||||
|
Slovakia|SK|SVK|703|ISO 3166-2:SK |
||||
|
Slovenia|SI|SVN|705|ISO 3166-2:SI |
||||
|
Solomon Islands|SB|SLB|090|ISO 3166-2:SB |
||||
|
Somalia|SO|SOM|706|ISO 3166-2:SO |
||||
|
South Africa|ZA|ZAF|710|ISO 3166-2:ZA |
||||
|
South Georgia and the South Sandwich Islands|GS|SGS|239|ISO 3166-2:GS |
||||
|
South Sudan|SS|SSD|728|ISO 3166-2:SS |
||||
|
Spain|ES|ESP|724|ISO 3166-2:ES |
||||
|
Sri Lanka|LK|LKA|144|ISO 3166-2:LK |
||||
|
Sudan|SD|SDN|729|ISO 3166-2:SD |
||||
|
Suriname|SR|SUR|740|ISO 3166-2:SR |
||||
|
Svalbard and Jan Mayen|SJ|SJM|744|ISO 3166-2:SJ |
||||
|
Swaziland|SZ|SWZ|748|ISO 3166-2:SZ |
||||
|
Sweden|SE|SWE|752|ISO 3166-2:SE |
||||
|
Switzerland|CH|CHE|756|ISO 3166-2:CH |
||||
|
Syrian Arab Republic|SY|SYR|760|ISO 3166-2:SY |
||||
|
Taiwan, Province of China|TW|TWN|158|ISO 3166-2:TW |
||||
|
Tajikistan|TJ|TJK|762|ISO 3166-2:TJ |
||||
|
Tanzania, United Republic of|TZ|TZA|834|ISO 3166-2:TZ |
||||
|
Thailand|TH|THA|764|ISO 3166-2:TH |
||||
|
Timor-Leste|TL|TLS|626|ISO 3166-2:TL |
||||
|
Togo|TG|TGO|768|ISO 3166-2:TG |
||||
|
Tokelau|TK|TKL|772|ISO 3166-2:TK |
||||
|
Tonga|TO|TON|776|ISO 3166-2:TO |
||||
|
Trinidad and Tobago|TT|TTO|780|ISO 3166-2:TT |
||||
|
Tunisia|TN|TUN|788|ISO 3166-2:TN |
||||
|
Turkey|TR|TUR|792|ISO 3166-2:TR |
||||
|
Turkmenistan|TM|TKM|795|ISO 3166-2:TM |
||||
|
Turks and Caicos Islands|TC|TCA|796|ISO 3166-2:TC |
||||
|
Tuvalu|TV|TUV|798|ISO 3166-2:TV |
||||
|
Uganda|UG|UGA|800|ISO 3166-2:UG |
||||
|
Ukraine|UA|UKR|804|ISO 3166-2:UA |
||||
|
United Arab Emirates|AE|ARE|784|ISO 3166-2:AE |
||||
|
United Kingdom|GB|GBR|826|ISO 3166-2:GB |
||||
|
United States|US|USA|840|ISO 3166-2:US |
||||
|
United States Minor Outlying Islands|UM|UMI|581|ISO 3166-2:UM |
||||
|
Uruguay|UY|URY|858|ISO 3166-2:UY |
||||
|
Uzbekistan|UZ|UZB|860|ISO 3166-2:UZ |
||||
|
Vanuatu|VU|VUT|548|ISO 3166-2:VU |
||||
|
Venezuela, Bolivarian Republic of|VE|VEN|862|ISO 3166-2:VE |
||||
|
Viet Nam|VN|VNM|704|ISO 3166-2:VN |
||||
|
Virgin Islands, British|VG|VGB|092|ISO 3166-2:VG |
||||
|
Virgin Islands, U.S|VI|VIR|850|ISO 3166-2:VI |
||||
|
Wallis and Futuna|WF|WLF|876|ISO 3166-2:WF |
||||
|
Western Sahara|EH|ESH|732|ISO 3166-2:EH |
||||
|
Yemen|YE|YEM|887|ISO 3166-2:YE |
||||
|
Zambia|ZM|ZMB|894|ISO 3166-2:ZM |
||||
|
Zimbabwe|ZW|ZWE|716|ISO 3166-2:ZW |
@ -0,0 +1,113 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
# -*- coding: utf-8 -*- |
||||
|
# |
||||
|
# GuessIt - A library for guessing information from filenames |
||||
|
# Copyright (c) 2012 Nicolas Wack <wackou@gmail.com> |
||||
|
# |
||||
|
# GuessIt is free software; you can redistribute it and/or modify it under |
||||
|
# the terms of the Lesser GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 3 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# GuessIt is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# Lesser GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the Lesser GNU General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
|
||||
|
from __future__ import unicode_literals |
||||
|
from guessit import fileutils |
||||
|
import logging |
||||
|
|
||||
|
log = logging.getLogger(__name__) |
||||
|
|
||||
|
|
||||
|
# parsed from http://en.wikipedia.org/wiki/ISO_3166-1 |
||||
|
# |
||||
|
# Description of the fields: |
||||
|
# "An English name, an alpha-2 code (when given), |
||||
|
# an alpha-3 code (when given), a numeric code, and an ISO 31666-2 code |
||||
|
# are all separated by pipe (|) characters." |
||||
|
_iso3166_contents = fileutils.load_file_in_same_dir(__file__, |
||||
|
'ISO-3166-1_utf8.txt').decode('utf-8') |
||||
|
|
||||
|
country_matrix = [ l.strip().split('|') |
||||
|
for l in _iso3166_contents.strip().split('\n') ] |
||||
|
|
||||
|
country_matrix += [ [ 'Unknown', 'un', 'unk', '', '' ], |
||||
|
[ 'Latin America', '', 'lat', '', '' ] |
||||
|
] |
||||
|
|
||||
|
country_to_alpha3 = dict((c[0].lower(), c[2].lower()) for c in country_matrix) |
||||
|
country_to_alpha3.update(dict((c[1].lower(), c[2].lower()) for c in country_matrix)) |
||||
|
country_to_alpha3.update(dict((c[2].lower(), c[2].lower()) for c in country_matrix)) |
||||
|
|
||||
|
# add here exceptions / non ISO representations |
||||
|
# Note: remember to put those exceptions in lower-case, they won't work otherwise |
||||
|
country_to_alpha3.update({ 'latinoamérica': 'lat', |
||||
|
'brazilian': 'bra', |
||||
|
'españa': 'esp', |
||||
|
'uk': 'gbr' |
||||
|
}) |
||||
|
|
||||
|
country_alpha3_to_en_name = dict((c[2].lower(), c[0]) for c in country_matrix) |
||||
|
country_alpha3_to_alpha2 = dict((c[2].lower(), c[1].lower()) for c in country_matrix) |
||||
|
|
||||
|
|
||||
|
|
||||
|
class Country(object): |
||||
|
"""This class represents a country. |
||||
|
|
||||
|
You can initialize it with pretty much anything, as it knows conversion |
||||
|
from ISO-3166 2-letter and 3-letter codes, and an English name. |
||||
|
""" |
||||
|
|
||||
|
def __init__(self, country, strict=False): |
||||
|
self.alpha3 = country_to_alpha3.get(country.lower()) |
||||
|
|
||||
|
if self.alpha3 is None and strict: |
||||
|
msg = 'The given string "%s" could not be identified as a country' |
||||
|
raise ValueError(msg % country) |
||||
|
|
||||
|
if self.alpha3 is None: |
||||
|
self.alpha3 = 'unk' |
||||
|
|
||||
|
|
||||
|
@property |
||||
|
def alpha2(self): |
||||
|
return country_alpha3_to_alpha2[self.alpha3] |
||||
|
|
||||
|
@property |
||||
|
def english_name(self): |
||||
|
return country_alpha3_to_en_name[self.alpha3] |
||||
|
|
||||
|
def __hash__(self): |
||||
|
return hash(self.alpha3) |
||||
|
|
||||
|
def __eq__(self, other): |
||||
|
if isinstance(other, Country): |
||||
|
return self.alpha3 == other.alpha3 |
||||
|
|
||||
|
if isinstance(other, basestring): |
||||
|
try: |
||||
|
return self == Country(other) |
||||
|
except ValueError: |
||||
|
return False |
||||
|
|
||||
|
return False |
||||
|
|
||||
|
def __ne__(self, other): |
||||
|
return not self == other |
||||
|
|
||||
|
def __unicode__(self): |
||||
|
return self.english_name |
||||
|
|
||||
|
def __str__(self): |
||||
|
return unicode(self).encode('utf-8') |
||||
|
|
||||
|
def __repr__(self): |
||||
|
return 'Country(%s)' % self.english_name |
||||
|
|
@ -0,0 +1,95 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite |
||||
|
~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
All the unittests of Jinja2. These tests can be executed by |
||||
|
either running run-tests.py using multiple Python versions at |
||||
|
the same time. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import os |
||||
|
import re |
||||
|
import sys |
||||
|
import unittest |
||||
|
from traceback import format_exception |
||||
|
from jinja2 import loaders |
||||
|
|
||||
|
|
||||
|
here = os.path.dirname(os.path.abspath(__file__)) |
||||
|
|
||||
|
dict_loader = loaders.DictLoader({ |
||||
|
'justdict.html': 'FOO' |
||||
|
}) |
||||
|
package_loader = loaders.PackageLoader('jinja2.testsuite.res', 'templates') |
||||
|
filesystem_loader = loaders.FileSystemLoader(here + '/res/templates') |
||||
|
function_loader = loaders.FunctionLoader({'justfunction.html': 'FOO'}.get) |
||||
|
choice_loader = loaders.ChoiceLoader([dict_loader, package_loader]) |
||||
|
prefix_loader = loaders.PrefixLoader({ |
||||
|
'a': filesystem_loader, |
||||
|
'b': dict_loader |
||||
|
}) |
||||
|
|
||||
|
|
||||
|
class JinjaTestCase(unittest.TestCase): |
||||
|
|
||||
|
### use only these methods for testing. If you need standard |
||||
|
### unittest method, wrap them! |
||||
|
|
||||
|
def setup(self): |
||||
|
pass |
||||
|
|
||||
|
def teardown(self): |
||||
|
pass |
||||
|
|
||||
|
def setUp(self): |
||||
|
self.setup() |
||||
|
|
||||
|
def tearDown(self): |
||||
|
self.teardown() |
||||
|
|
||||
|
def assert_equal(self, a, b): |
||||
|
return self.assertEqual(a, b) |
||||
|
|
||||
|
def assert_raises(self, *args, **kwargs): |
||||
|
return self.assertRaises(*args, **kwargs) |
||||
|
|
||||
|
def assert_traceback_matches(self, callback, expected_tb): |
||||
|
try: |
||||
|
callback() |
||||
|
except Exception, e: |
||||
|
tb = format_exception(*sys.exc_info()) |
||||
|
if re.search(expected_tb.strip(), ''.join(tb)) is None: |
||||
|
raise self.fail('Traceback did not match:\n\n%s\nexpected:\n%s' |
||||
|
% (''.join(tb), expected_tb)) |
||||
|
else: |
||||
|
self.fail('Expected exception') |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
from jinja2.testsuite import ext, filters, tests, core_tags, \ |
||||
|
loader, inheritance, imports, lexnparse, security, api, \ |
||||
|
regression, debug, utils, doctests |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(ext.suite()) |
||||
|
suite.addTest(filters.suite()) |
||||
|
suite.addTest(tests.suite()) |
||||
|
suite.addTest(core_tags.suite()) |
||||
|
suite.addTest(loader.suite()) |
||||
|
suite.addTest(inheritance.suite()) |
||||
|
suite.addTest(imports.suite()) |
||||
|
suite.addTest(lexnparse.suite()) |
||||
|
suite.addTest(security.suite()) |
||||
|
suite.addTest(api.suite()) |
||||
|
suite.addTest(regression.suite()) |
||||
|
suite.addTest(debug.suite()) |
||||
|
suite.addTest(utils.suite()) |
||||
|
|
||||
|
# doctests will not run on python 3 currently. Too many issues |
||||
|
# with that, do not test that on that platform. |
||||
|
if sys.version_info < (3, 0): |
||||
|
suite.addTest(doctests.suite()) |
||||
|
|
||||
|
return suite |
@ -0,0 +1,245 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.api |
||||
|
~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Tests the public API and related stuff. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import unittest |
||||
|
|
||||
|
from jinja2.testsuite import JinjaTestCase |
||||
|
|
||||
|
from jinja2 import Environment, Undefined, DebugUndefined, \ |
||||
|
StrictUndefined, UndefinedError, meta, \ |
||||
|
is_undefined, Template, DictLoader |
||||
|
from jinja2.utils import Cycler |
||||
|
|
||||
|
env = Environment() |
||||
|
|
||||
|
|
||||
|
class ExtendedAPITestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_item_and_attribute(self): |
||||
|
from jinja2.sandbox import SandboxedEnvironment |
||||
|
|
||||
|
for env in Environment(), SandboxedEnvironment(): |
||||
|
# the |list is necessary for python3 |
||||
|
tmpl = env.from_string('{{ foo.items()|list }}') |
||||
|
assert tmpl.render(foo={'items': 42}) == "[('items', 42)]" |
||||
|
tmpl = env.from_string('{{ foo|attr("items")()|list }}') |
||||
|
assert tmpl.render(foo={'items': 42}) == "[('items', 42)]" |
||||
|
tmpl = env.from_string('{{ foo["items"] }}') |
||||
|
assert tmpl.render(foo={'items': 42}) == '42' |
||||
|
|
||||
|
def test_finalizer(self): |
||||
|
def finalize_none_empty(value): |
||||
|
if value is None: |
||||
|
value = u'' |
||||
|
return value |
||||
|
env = Environment(finalize=finalize_none_empty) |
||||
|
tmpl = env.from_string('{% for item in seq %}|{{ item }}{% endfor %}') |
||||
|
assert tmpl.render(seq=(None, 1, "foo")) == '||1|foo' |
||||
|
tmpl = env.from_string('<{{ none }}>') |
||||
|
assert tmpl.render() == '<>' |
||||
|
|
||||
|
def test_cycler(self): |
||||
|
items = 1, 2, 3 |
||||
|
c = Cycler(*items) |
||||
|
for item in items + items: |
||||
|
assert c.current == item |
||||
|
assert c.next() == item |
||||
|
c.next() |
||||
|
assert c.current == 2 |
||||
|
c.reset() |
||||
|
assert c.current == 1 |
||||
|
|
||||
|
def test_expressions(self): |
||||
|
expr = env.compile_expression("foo") |
||||
|
assert expr() is None |
||||
|
assert expr(foo=42) == 42 |
||||
|
expr2 = env.compile_expression("foo", undefined_to_none=False) |
||||
|
assert is_undefined(expr2()) |
||||
|
|
||||
|
expr = env.compile_expression("42 + foo") |
||||
|
assert expr(foo=42) == 84 |
||||
|
|
||||
|
def test_template_passthrough(self): |
||||
|
t = Template('Content') |
||||
|
assert env.get_template(t) is t |
||||
|
assert env.select_template([t]) is t |
||||
|
assert env.get_or_select_template([t]) is t |
||||
|
assert env.get_or_select_template(t) is t |
||||
|
|
||||
|
def test_autoescape_autoselect(self): |
||||
|
def select_autoescape(name): |
||||
|
if name is None or '.' not in name: |
||||
|
return False |
||||
|
return name.endswith('.html') |
||||
|
env = Environment(autoescape=select_autoescape, |
||||
|
loader=DictLoader({ |
||||
|
'test.txt': '{{ foo }}', |
||||
|
'test.html': '{{ foo }}' |
||||
|
})) |
||||
|
t = env.get_template('test.txt') |
||||
|
assert t.render(foo='<foo>') == '<foo>' |
||||
|
t = env.get_template('test.html') |
||||
|
assert t.render(foo='<foo>') == '<foo>' |
||||
|
t = env.from_string('{{ foo }}') |
||||
|
assert t.render(foo='<foo>') == '<foo>' |
||||
|
|
||||
|
|
||||
|
class MetaTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_find_undeclared_variables(self): |
||||
|
ast = env.parse('{% set foo = 42 %}{{ bar + foo }}') |
||||
|
x = meta.find_undeclared_variables(ast) |
||||
|
assert x == set(['bar']) |
||||
|
|
||||
|
ast = env.parse('{% set foo = 42 %}{{ bar + foo }}' |
||||
|
'{% macro meh(x) %}{{ x }}{% endmacro %}' |
||||
|
'{% for item in seq %}{{ muh(item) + meh(seq) }}{% endfor %}') |
||||
|
x = meta.find_undeclared_variables(ast) |
||||
|
assert x == set(['bar', 'seq', 'muh']) |
||||
|
|
||||
|
def test_find_refererenced_templates(self): |
||||
|
ast = env.parse('{% extends "layout.html" %}{% include helper %}') |
||||
|
i = meta.find_referenced_templates(ast) |
||||
|
assert i.next() == 'layout.html' |
||||
|
assert i.next() is None |
||||
|
assert list(i) == [] |
||||
|
|
||||
|
ast = env.parse('{% extends "layout.html" %}' |
||||
|
'{% from "test.html" import a, b as c %}' |
||||
|
'{% import "meh.html" as meh %}' |
||||
|
'{% include "muh.html" %}') |
||||
|
i = meta.find_referenced_templates(ast) |
||||
|
assert list(i) == ['layout.html', 'test.html', 'meh.html', 'muh.html'] |
||||
|
|
||||
|
def test_find_included_templates(self): |
||||
|
ast = env.parse('{% include ["foo.html", "bar.html"] %}') |
||||
|
i = meta.find_referenced_templates(ast) |
||||
|
assert list(i) == ['foo.html', 'bar.html'] |
||||
|
|
||||
|
ast = env.parse('{% include ("foo.html", "bar.html") %}') |
||||
|
i = meta.find_referenced_templates(ast) |
||||
|
assert list(i) == ['foo.html', 'bar.html'] |
||||
|
|
||||
|
ast = env.parse('{% include ["foo.html", "bar.html", foo] %}') |
||||
|
i = meta.find_referenced_templates(ast) |
||||
|
assert list(i) == ['foo.html', 'bar.html', None] |
||||
|
|
||||
|
ast = env.parse('{% include ("foo.html", "bar.html", foo) %}') |
||||
|
i = meta.find_referenced_templates(ast) |
||||
|
assert list(i) == ['foo.html', 'bar.html', None] |
||||
|
|
||||
|
|
||||
|
class StreamingTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_basic_streaming(self): |
||||
|
tmpl = env.from_string("<ul>{% for item in seq %}<li>{{ loop.index " |
||||
|
"}} - {{ item }}</li>{%- endfor %}</ul>") |
||||
|
stream = tmpl.stream(seq=range(4)) |
||||
|
self.assert_equal(stream.next(), '<ul>') |
||||
|
self.assert_equal(stream.next(), '<li>1 - 0</li>') |
||||
|
self.assert_equal(stream.next(), '<li>2 - 1</li>') |
||||
|
self.assert_equal(stream.next(), '<li>3 - 2</li>') |
||||
|
self.assert_equal(stream.next(), '<li>4 - 3</li>') |
||||
|
self.assert_equal(stream.next(), '</ul>') |
||||
|
|
||||
|
def test_buffered_streaming(self): |
||||
|
tmpl = env.from_string("<ul>{% for item in seq %}<li>{{ loop.index " |
||||
|
"}} - {{ item }}</li>{%- endfor %}</ul>") |
||||
|
stream = tmpl.stream(seq=range(4)) |
||||
|
stream.enable_buffering(size=3) |
||||
|
self.assert_equal(stream.next(), u'<ul><li>1 - 0</li><li>2 - 1</li>') |
||||
|
self.assert_equal(stream.next(), u'<li>3 - 2</li><li>4 - 3</li></ul>') |
||||
|
|
||||
|
def test_streaming_behavior(self): |
||||
|
tmpl = env.from_string("") |
||||
|
stream = tmpl.stream() |
||||
|
assert not stream.buffered |
||||
|
stream.enable_buffering(20) |
||||
|
assert stream.buffered |
||||
|
stream.disable_buffering() |
||||
|
assert not stream.buffered |
||||
|
|
||||
|
|
||||
|
class UndefinedTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_stopiteration_is_undefined(self): |
||||
|
def test(): |
||||
|
raise StopIteration() |
||||
|
t = Template('A{{ test() }}B') |
||||
|
assert t.render(test=test) == 'AB' |
||||
|
t = Template('A{{ test().missingattribute }}B') |
||||
|
self.assert_raises(UndefinedError, t.render, test=test) |
||||
|
|
||||
|
def test_undefined_and_special_attributes(self): |
||||
|
try: |
||||
|
Undefined('Foo').__dict__ |
||||
|
except AttributeError: |
||||
|
pass |
||||
|
else: |
||||
|
assert False, "Expected actual attribute error" |
||||
|
|
||||
|
def test_default_undefined(self): |
||||
|
env = Environment(undefined=Undefined) |
||||
|
self.assert_equal(env.from_string('{{ missing }}').render(), u'') |
||||
|
self.assert_raises(UndefinedError, |
||||
|
env.from_string('{{ missing.attribute }}').render) |
||||
|
self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]') |
||||
|
self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True') |
||||
|
self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42), '') |
||||
|
self.assert_equal(env.from_string('{{ not missing }}').render(), 'True') |
||||
|
|
||||
|
def test_debug_undefined(self): |
||||
|
env = Environment(undefined=DebugUndefined) |
||||
|
self.assert_equal(env.from_string('{{ missing }}').render(), '{{ missing }}') |
||||
|
self.assert_raises(UndefinedError, |
||||
|
env.from_string('{{ missing.attribute }}').render) |
||||
|
self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]') |
||||
|
self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True') |
||||
|
self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42), |
||||
|
u"{{ no such element: int object['missing'] }}") |
||||
|
self.assert_equal(env.from_string('{{ not missing }}').render(), 'True') |
||||
|
|
||||
|
def test_strict_undefined(self): |
||||
|
env = Environment(undefined=StrictUndefined) |
||||
|
self.assert_raises(UndefinedError, env.from_string('{{ missing }}').render) |
||||
|
self.assert_raises(UndefinedError, env.from_string('{{ missing.attribute }}').render) |
||||
|
self.assert_raises(UndefinedError, env.from_string('{{ missing|list }}').render) |
||||
|
self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True') |
||||
|
self.assert_raises(UndefinedError, env.from_string('{{ foo.missing }}').render, foo=42) |
||||
|
self.assert_raises(UndefinedError, env.from_string('{{ not missing }}').render) |
||||
|
|
||||
|
def test_indexing_gives_undefined(self): |
||||
|
t = Template("{{ var[42].foo }}") |
||||
|
self.assert_raises(UndefinedError, t.render, var=0) |
||||
|
|
||||
|
def test_none_gives_proper_error(self): |
||||
|
try: |
||||
|
Environment().getattr(None, 'split')() |
||||
|
except UndefinedError, e: |
||||
|
assert e.message == "'None' has no attribute 'split'" |
||||
|
else: |
||||
|
assert False, 'expected exception' |
||||
|
|
||||
|
def test_object_repr(self): |
||||
|
try: |
||||
|
Undefined(obj=42, name='upper')() |
||||
|
except UndefinedError, e: |
||||
|
assert e.message == "'int object' has no attribute 'upper'" |
||||
|
else: |
||||
|
assert False, 'expected exception' |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(unittest.makeSuite(ExtendedAPITestCase)) |
||||
|
suite.addTest(unittest.makeSuite(MetaTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(StreamingTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(UndefinedTestCase)) |
||||
|
return suite |
@ -0,0 +1,285 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.core_tags |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Test the core tags like for and if. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import unittest |
||||
|
|
||||
|
from jinja2.testsuite import JinjaTestCase |
||||
|
|
||||
|
from jinja2 import Environment, TemplateSyntaxError, UndefinedError, \ |
||||
|
DictLoader |
||||
|
|
||||
|
env = Environment() |
||||
|
|
||||
|
|
||||
|
class ForLoopTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_simple(self): |
||||
|
tmpl = env.from_string('{% for item in seq %}{{ item }}{% endfor %}') |
||||
|
assert tmpl.render(seq=range(10)) == '0123456789' |
||||
|
|
||||
|
def test_else(self): |
||||
|
tmpl = env.from_string('{% for item in seq %}XXX{% else %}...{% endfor %}') |
||||
|
assert tmpl.render() == '...' |
||||
|
|
||||
|
def test_empty_blocks(self): |
||||
|
tmpl = env.from_string('<{% for item in seq %}{% else %}{% endfor %}>') |
||||
|
assert tmpl.render() == '<>' |
||||
|
|
||||
|
def test_context_vars(self): |
||||
|
tmpl = env.from_string('''{% for item in seq -%} |
||||
|
{{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{ |
||||
|
loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{ |
||||
|
loop.length }}###{% endfor %}''') |
||||
|
one, two, _ = tmpl.render(seq=[0, 1]).split('###') |
||||
|
(one_index, one_index0, one_revindex, one_revindex0, one_first, |
||||
|
one_last, one_length) = one.split('|') |
||||
|
(two_index, two_index0, two_revindex, two_revindex0, two_first, |
||||
|
two_last, two_length) = two.split('|') |
||||
|
|
||||
|
assert int(one_index) == 1 and int(two_index) == 2 |
||||
|
assert int(one_index0) == 0 and int(two_index0) == 1 |
||||
|
assert int(one_revindex) == 2 and int(two_revindex) == 1 |
||||
|
assert int(one_revindex0) == 1 and int(two_revindex0) == 0 |
||||
|
assert one_first == 'True' and two_first == 'False' |
||||
|
assert one_last == 'False' and two_last == 'True' |
||||
|
assert one_length == two_length == '2' |
||||
|
|
||||
|
def test_cycling(self): |
||||
|
tmpl = env.from_string('''{% for item in seq %}{{ |
||||
|
loop.cycle('<1>', '<2>') }}{% endfor %}{% |
||||
|
for item in seq %}{{ loop.cycle(*through) }}{% endfor %}''') |
||||
|
output = tmpl.render(seq=range(4), through=('<1>', '<2>')) |
||||
|
assert output == '<1><2>' * 4 |
||||
|
|
||||
|
def test_scope(self): |
||||
|
tmpl = env.from_string('{% for item in seq %}{% endfor %}{{ item }}') |
||||
|
output = tmpl.render(seq=range(10)) |
||||
|
assert not output |
||||
|
|
||||
|
def test_varlen(self): |
||||
|
def inner(): |
||||
|
for item in range(5): |
||||
|
yield item |
||||
|
tmpl = env.from_string('{% for item in iter %}{{ item }}{% endfor %}') |
||||
|
output = tmpl.render(iter=inner()) |
||||
|
assert output == '01234' |
||||
|
|
||||
|
def test_noniter(self): |
||||
|
tmpl = env.from_string('{% for item in none %}...{% endfor %}') |
||||
|
self.assert_raises(TypeError, tmpl.render) |
||||
|
|
||||
|
def test_recursive(self): |
||||
|
tmpl = env.from_string('''{% for item in seq recursive -%} |
||||
|
[{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] |
||||
|
{%- endfor %}''') |
||||
|
assert tmpl.render(seq=[ |
||||
|
dict(a=1, b=[dict(a=1), dict(a=2)]), |
||||
|
dict(a=2, b=[dict(a=1), dict(a=2)]), |
||||
|
dict(a=3, b=[dict(a='a')]) |
||||
|
]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]' |
||||
|
|
||||
|
def test_looploop(self): |
||||
|
tmpl = env.from_string('''{% for row in table %} |
||||
|
{%- set rowloop = loop -%} |
||||
|
{% for cell in row -%} |
||||
|
[{{ rowloop.index }}|{{ loop.index }}] |
||||
|
{%- endfor %} |
||||
|
{%- endfor %}''') |
||||
|
assert tmpl.render(table=['ab', 'cd']) == '[1|1][1|2][2|1][2|2]' |
||||
|
|
||||
|
def test_reversed_bug(self): |
||||
|
tmpl = env.from_string('{% for i in items %}{{ i }}' |
||||
|
'{% if not loop.last %}' |
||||
|
',{% endif %}{% endfor %}') |
||||
|
assert tmpl.render(items=reversed([3, 2, 1])) == '1,2,3' |
||||
|
|
||||
|
def test_loop_errors(self): |
||||
|
tmpl = env.from_string('''{% for item in [1] if loop.index |
||||
|
== 0 %}...{% endfor %}''') |
||||
|
self.assert_raises(UndefinedError, tmpl.render) |
||||
|
tmpl = env.from_string('''{% for item in [] %}...{% else |
||||
|
%}{{ loop }}{% endfor %}''') |
||||
|
assert tmpl.render() == '' |
||||
|
|
||||
|
def test_loop_filter(self): |
||||
|
tmpl = env.from_string('{% for item in range(10) if item ' |
||||
|
'is even %}[{{ item }}]{% endfor %}') |
||||
|
assert tmpl.render() == '[0][2][4][6][8]' |
||||
|
tmpl = env.from_string(''' |
||||
|
{%- for item in range(10) if item is even %}[{{ |
||||
|
loop.index }}:{{ item }}]{% endfor %}''') |
||||
|
assert tmpl.render() == '[1:0][2:2][3:4][4:6][5:8]' |
||||
|
|
||||
|
def test_loop_unassignable(self): |
||||
|
self.assert_raises(TemplateSyntaxError, env.from_string, |
||||
|
'{% for loop in seq %}...{% endfor %}') |
||||
|
|
||||
|
def test_scoped_special_var(self): |
||||
|
t = env.from_string('{% for s in seq %}[{{ loop.first }}{% for c in s %}' |
||||
|
'|{{ loop.first }}{% endfor %}]{% endfor %}') |
||||
|
assert t.render(seq=('ab', 'cd')) == '[True|True|False][False|True|False]' |
||||
|
|
||||
|
def test_scoped_loop_var(self): |
||||
|
t = env.from_string('{% for x in seq %}{{ loop.first }}' |
||||
|
'{% for y in seq %}{% endfor %}{% endfor %}') |
||||
|
assert t.render(seq='ab') == 'TrueFalse' |
||||
|
t = env.from_string('{% for x in seq %}{% for y in seq %}' |
||||
|
'{{ loop.first }}{% endfor %}{% endfor %}') |
||||
|
assert t.render(seq='ab') == 'TrueFalseTrueFalse' |
||||
|
|
||||
|
def test_recursive_empty_loop_iter(self): |
||||
|
t = env.from_string(''' |
||||
|
{%- for item in foo recursive -%}{%- endfor -%} |
||||
|
''') |
||||
|
assert t.render(dict(foo=[])) == '' |
||||
|
|
||||
|
def test_call_in_loop(self): |
||||
|
t = env.from_string(''' |
||||
|
{%- macro do_something() -%} |
||||
|
[{{ caller() }}] |
||||
|
{%- endmacro %} |
||||
|
|
||||
|
{%- for i in [1, 2, 3] %} |
||||
|
{%- call do_something() -%} |
||||
|
{{ i }} |
||||
|
{%- endcall %} |
||||
|
{%- endfor -%} |
||||
|
''') |
||||
|
assert t.render() == '[1][2][3]' |
||||
|
|
||||
|
def test_scoping_bug(self): |
||||
|
t = env.from_string(''' |
||||
|
{%- for item in foo %}...{{ item }}...{% endfor %} |
||||
|
{%- macro item(a) %}...{{ a }}...{% endmacro %} |
||||
|
{{- item(2) -}} |
||||
|
''') |
||||
|
assert t.render(foo=(1,)) == '...1......2...' |
||||
|
|
||||
|
def test_unpacking(self): |
||||
|
tmpl = env.from_string('{% for a, b, c in [[1, 2, 3]] %}' |
||||
|
'{{ a }}|{{ b }}|{{ c }}{% endfor %}') |
||||
|
assert tmpl.render() == '1|2|3' |
||||
|
|
||||
|
|
||||
|
class IfConditionTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_simple(self): |
||||
|
tmpl = env.from_string('''{% if true %}...{% endif %}''') |
||||
|
assert tmpl.render() == '...' |
||||
|
|
||||
|
def test_elif(self): |
||||
|
tmpl = env.from_string('''{% if false %}XXX{% elif true |
||||
|
%}...{% else %}XXX{% endif %}''') |
||||
|
assert tmpl.render() == '...' |
||||
|
|
||||
|
def test_else(self): |
||||
|
tmpl = env.from_string('{% if false %}XXX{% else %}...{% endif %}') |
||||
|
assert tmpl.render() == '...' |
||||
|
|
||||
|
def test_empty(self): |
||||
|
tmpl = env.from_string('[{% if true %}{% else %}{% endif %}]') |
||||
|
assert tmpl.render() == '[]' |
||||
|
|
||||
|
def test_complete(self): |
||||
|
tmpl = env.from_string('{% if a %}A{% elif b %}B{% elif c == d %}' |
||||
|
'C{% else %}D{% endif %}') |
||||
|
assert tmpl.render(a=0, b=False, c=42, d=42.0) == 'C' |
||||
|
|
||||
|
def test_no_scope(self): |
||||
|
tmpl = env.from_string('{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}') |
||||
|
assert tmpl.render(a=True) == '1' |
||||
|
tmpl = env.from_string('{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}') |
||||
|
assert tmpl.render() == '1' |
||||
|
|
||||
|
|
||||
|
class MacrosTestCase(JinjaTestCase): |
||||
|
env = Environment(trim_blocks=True) |
||||
|
|
||||
|
def test_simple(self): |
||||
|
tmpl = self.env.from_string('''\ |
||||
|
{% macro say_hello(name) %}Hello {{ name }}!{% endmacro %} |
||||
|
{{ say_hello('Peter') }}''') |
||||
|
assert tmpl.render() == 'Hello Peter!' |
||||
|
|
||||
|
def test_scoping(self): |
||||
|
tmpl = self.env.from_string('''\ |
||||
|
{% macro level1(data1) %} |
||||
|
{% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %} |
||||
|
{{ level2('bar') }}{% endmacro %} |
||||
|
{{ level1('foo') }}''') |
||||
|
assert tmpl.render() == 'foo|bar' |
||||
|
|
||||
|
def test_arguments(self): |
||||
|
tmpl = self.env.from_string('''\ |
||||
|
{% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %} |
||||
|
{{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}''') |
||||
|
assert tmpl.render() == '||c|d|a||c|d|a|b|c|d|1|2|3|d' |
||||
|
|
||||
|
def test_varargs(self): |
||||
|
tmpl = self.env.from_string('''\ |
||||
|
{% macro test() %}{{ varargs|join('|') }}{% endmacro %}\ |
||||
|
{{ test(1, 2, 3) }}''') |
||||
|
assert tmpl.render() == '1|2|3' |
||||
|
|
||||
|
def test_simple_call(self): |
||||
|
tmpl = self.env.from_string('''\ |
||||
|
{% macro test() %}[[{{ caller() }}]]{% endmacro %}\ |
||||
|
{% call test() %}data{% endcall %}''') |
||||
|
assert tmpl.render() == '[[data]]' |
||||
|
|
||||
|
def test_complex_call(self): |
||||
|
tmpl = self.env.from_string('''\ |
||||
|
{% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\ |
||||
|
{% call(data) test() %}{{ data }}{% endcall %}''') |
||||
|
assert tmpl.render() == '[[data]]' |
||||
|
|
||||
|
def test_caller_undefined(self): |
||||
|
tmpl = self.env.from_string('''\ |
||||
|
{% set caller = 42 %}\ |
||||
|
{% macro test() %}{{ caller is not defined }}{% endmacro %}\ |
||||
|
{{ test() }}''') |
||||
|
assert tmpl.render() == 'True' |
||||
|
|
||||
|
def test_include(self): |
||||
|
self.env = Environment(loader=DictLoader({'include': |
||||
|
'{% macro test(foo) %}[{{ foo }}]{% endmacro %}'})) |
||||
|
tmpl = self.env.from_string('{% from "include" import test %}{{ test("foo") }}') |
||||
|
assert tmpl.render() == '[foo]' |
||||
|
|
||||
|
def test_macro_api(self): |
||||
|
tmpl = self.env.from_string('{% macro foo(a, b) %}{% endmacro %}' |
||||
|
'{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}' |
||||
|
'{% macro baz() %}{{ caller() }}{% endmacro %}') |
||||
|
assert tmpl.module.foo.arguments == ('a', 'b') |
||||
|
assert tmpl.module.foo.defaults == () |
||||
|
assert tmpl.module.foo.name == 'foo' |
||||
|
assert not tmpl.module.foo.caller |
||||
|
assert not tmpl.module.foo.catch_kwargs |
||||
|
assert not tmpl.module.foo.catch_varargs |
||||
|
assert tmpl.module.bar.arguments == () |
||||
|
assert tmpl.module.bar.defaults == () |
||||
|
assert not tmpl.module.bar.caller |
||||
|
assert tmpl.module.bar.catch_kwargs |
||||
|
assert tmpl.module.bar.catch_varargs |
||||
|
assert tmpl.module.baz.caller |
||||
|
|
||||
|
def test_callself(self): |
||||
|
tmpl = self.env.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|' |
||||
|
'{{ foo(x - 1) }}{% endif %}{% endmacro %}' |
||||
|
'{{ foo(5) }}') |
||||
|
assert tmpl.render() == '5|4|3|2|1' |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(unittest.makeSuite(ForLoopTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(IfConditionTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(MacrosTestCase)) |
||||
|
return suite |
@ -0,0 +1,60 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.debug |
||||
|
~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Tests the debug system. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import sys |
||||
|
import unittest |
||||
|
|
||||
|
from jinja2.testsuite import JinjaTestCase, filesystem_loader |
||||
|
|
||||
|
from jinja2 import Environment, TemplateSyntaxError |
||||
|
|
||||
|
env = Environment(loader=filesystem_loader) |
||||
|
|
||||
|
|
||||
|
class DebugTestCase(JinjaTestCase): |
||||
|
|
||||
|
if sys.version_info[:2] != (2, 4): |
||||
|
def test_runtime_error(self): |
||||
|
def test(): |
||||
|
tmpl.render(fail=lambda: 1 / 0) |
||||
|
tmpl = env.get_template('broken.html') |
||||
|
self.assert_traceback_matches(test, r''' |
||||
|
File ".*?broken.html", line 2, in (top-level template code|<module>) |
||||
|
\{\{ fail\(\) \}\} |
||||
|
File ".*?debug.pyc?", line \d+, in <lambda> |
||||
|
tmpl\.render\(fail=lambda: 1 / 0\) |
||||
|
ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero |
||||
|
''') |
||||
|
|
||||
|
def test_syntax_error(self): |
||||
|
# XXX: the .*? is necessary for python3 which does not hide |
||||
|
# some of the stack frames we don't want to show. Not sure |
||||
|
# what's up with that, but that is not that critical. Should |
||||
|
# be fixed though. |
||||
|
self.assert_traceback_matches(lambda: env.get_template('syntaxerror.html'), r'''(?sm) |
||||
|
File ".*?syntaxerror.html", line 4, in (template|<module>) |
||||
|
\{% endif %\}.*? |
||||
|
(jinja2\.exceptions\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja was looking for the following tags: 'endfor' or 'else'. The innermost block that needs to be closed is 'for'. |
||||
|
''') |
||||
|
|
||||
|
def test_regular_syntax_error(self): |
||||
|
def test(): |
||||
|
raise TemplateSyntaxError('wtf', 42) |
||||
|
self.assert_traceback_matches(test, r''' |
||||
|
File ".*debug.pyc?", line \d+, in test |
||||
|
raise TemplateSyntaxError\('wtf', 42\) |
||||
|
(jinja2\.exceptions\.)?TemplateSyntaxError: wtf |
||||
|
line 42''') |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(unittest.makeSuite(DebugTestCase)) |
||||
|
return suite |
@ -0,0 +1,29 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.doctests |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
The doctests. Collects all tests we want to test from |
||||
|
the Jinja modules. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import unittest |
||||
|
import doctest |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
from jinja2 import utils, sandbox, runtime, meta, loaders, \ |
||||
|
ext, environment, bccache, nodes |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(doctest.DocTestSuite(utils)) |
||||
|
suite.addTest(doctest.DocTestSuite(sandbox)) |
||||
|
suite.addTest(doctest.DocTestSuite(runtime)) |
||||
|
suite.addTest(doctest.DocTestSuite(meta)) |
||||
|
suite.addTest(doctest.DocTestSuite(loaders)) |
||||
|
suite.addTest(doctest.DocTestSuite(ext)) |
||||
|
suite.addTest(doctest.DocTestSuite(environment)) |
||||
|
suite.addTest(doctest.DocTestSuite(bccache)) |
||||
|
suite.addTest(doctest.DocTestSuite(nodes)) |
||||
|
return suite |
@ -0,0 +1,455 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.ext |
||||
|
~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Tests for the extensions. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import re |
||||
|
import unittest |
||||
|
|
||||
|
from jinja2.testsuite import JinjaTestCase |
||||
|
|
||||
|
from jinja2 import Environment, DictLoader, contextfunction, nodes |
||||
|
from jinja2.exceptions import TemplateAssertionError |
||||
|
from jinja2.ext import Extension |
||||
|
from jinja2.lexer import Token, count_newlines |
||||
|
from jinja2.utils import next |
||||
|
|
||||
|
# 2.x / 3.x |
||||
|
try: |
||||
|
from io import BytesIO |
||||
|
except ImportError: |
||||
|
from StringIO import StringIO as BytesIO |
||||
|
|
||||
|
|
||||
|
importable_object = 23 |
||||
|
|
||||
|
_gettext_re = re.compile(r'_\((.*?)\)(?s)') |
||||
|
|
||||
|
|
||||
|
i18n_templates = { |
||||
|
'master.html': '<title>{{ page_title|default(_("missing")) }}</title>' |
||||
|
'{% block body %}{% endblock %}', |
||||
|
'child.html': '{% extends "master.html" %}{% block body %}' |
||||
|
'{% trans %}watch out{% endtrans %}{% endblock %}', |
||||
|
'plural.html': '{% trans user_count %}One user online{% pluralize %}' |
||||
|
'{{ user_count }} users online{% endtrans %}', |
||||
|
'stringformat.html': '{{ _("User: %(num)s")|format(num=user_count) }}' |
||||
|
} |
||||
|
|
||||
|
newstyle_i18n_templates = { |
||||
|
'master.html': '<title>{{ page_title|default(_("missing")) }}</title>' |
||||
|
'{% block body %}{% endblock %}', |
||||
|
'child.html': '{% extends "master.html" %}{% block body %}' |
||||
|
'{% trans %}watch out{% endtrans %}{% endblock %}', |
||||
|
'plural.html': '{% trans user_count %}One user online{% pluralize %}' |
||||
|
'{{ user_count }} users online{% endtrans %}', |
||||
|
'stringformat.html': '{{ _("User: %(num)s", num=user_count) }}', |
||||
|
'ngettext.html': '{{ ngettext("%(num)s apple", "%(num)s apples", apples) }}', |
||||
|
'ngettext_long.html': '{% trans num=apples %}{{ num }} apple{% pluralize %}' |
||||
|
'{{ num }} apples{% endtrans %}', |
||||
|
'transvars1.html': '{% trans %}User: {{ num }}{% endtrans %}', |
||||
|
'transvars2.html': '{% trans num=count %}User: {{ num }}{% endtrans %}', |
||||
|
'transvars3.html': '{% trans count=num %}User: {{ count }}{% endtrans %}', |
||||
|
'novars.html': '{% trans %}%(hello)s{% endtrans %}', |
||||
|
'vars.html': '{% trans %}{{ foo }}%(foo)s{% endtrans %}', |
||||
|
'explicitvars.html': '{% trans foo="42" %}%(foo)s{% endtrans %}' |
||||
|
} |
||||
|
|
||||
|
|
||||
|
languages = { |
||||
|
'de': { |
||||
|
'missing': u'fehlend', |
||||
|
'watch out': u'pass auf', |
||||
|
'One user online': u'Ein Benutzer online', |
||||
|
'%(user_count)s users online': u'%(user_count)s Benutzer online', |
||||
|
'User: %(num)s': u'Benutzer: %(num)s', |
||||
|
'User: %(count)s': u'Benutzer: %(count)s', |
||||
|
'%(num)s apple': u'%(num)s Apfel', |
||||
|
'%(num)s apples': u'%(num)s Äpfel' |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@contextfunction |
||||
|
def gettext(context, string): |
||||
|
language = context.get('LANGUAGE', 'en') |
||||
|
return languages.get(language, {}).get(string, string) |
||||
|
|
||||
|
|
||||
|
@contextfunction |
||||
|
def ngettext(context, s, p, n): |
||||
|
language = context.get('LANGUAGE', 'en') |
||||
|
if n != 1: |
||||
|
return languages.get(language, {}).get(p, p) |
||||
|
return languages.get(language, {}).get(s, s) |
||||
|
|
||||
|
|
||||
|
i18n_env = Environment( |
||||
|
loader=DictLoader(i18n_templates), |
||||
|
extensions=['jinja2.ext.i18n'] |
||||
|
) |
||||
|
i18n_env.globals.update({ |
||||
|
'_': gettext, |
||||
|
'gettext': gettext, |
||||
|
'ngettext': ngettext |
||||
|
}) |
||||
|
|
||||
|
newstyle_i18n_env = Environment( |
||||
|
loader=DictLoader(newstyle_i18n_templates), |
||||
|
extensions=['jinja2.ext.i18n'] |
||||
|
) |
||||
|
newstyle_i18n_env.install_gettext_callables(gettext, ngettext, newstyle=True) |
||||
|
|
||||
|
class TestExtension(Extension): |
||||
|
tags = set(['test']) |
||||
|
ext_attr = 42 |
||||
|
|
||||
|
def parse(self, parser): |
||||
|
return nodes.Output([self.call_method('_dump', [ |
||||
|
nodes.EnvironmentAttribute('sandboxed'), |
||||
|
self.attr('ext_attr'), |
||||
|
nodes.ImportedName(__name__ + '.importable_object'), |
||||
|
nodes.ContextReference() |
||||
|
])]).set_lineno(next(parser.stream).lineno) |
||||
|
|
||||
|
def _dump(self, sandboxed, ext_attr, imported_object, context): |
||||
|
return '%s|%s|%s|%s' % ( |
||||
|
sandboxed, |
||||
|
ext_attr, |
||||
|
imported_object, |
||||
|
context.blocks |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class PreprocessorExtension(Extension): |
||||
|
|
||||
|
def preprocess(self, source, name, filename=None): |
||||
|
return source.replace('[[TEST]]', '({{ foo }})') |
||||
|
|
||||
|
|
||||
|
class StreamFilterExtension(Extension): |
||||
|
|
||||
|
def filter_stream(self, stream): |
||||
|
for token in stream: |
||||
|
if token.type == 'data': |
||||
|
for t in self.interpolate(token): |
||||
|
yield t |
||||
|
else: |
||||
|
yield token |
||||
|
|
||||
|
def interpolate(self, token): |
||||
|
pos = 0 |
||||
|
end = len(token.value) |
||||
|
lineno = token.lineno |
||||
|
while 1: |
||||
|
match = _gettext_re.search(token.value, pos) |
||||
|
if match is None: |
||||
|
break |
||||
|
value = token.value[pos:match.start()] |
||||
|
if value: |
||||
|
yield Token(lineno, 'data', value) |
||||
|
lineno += count_newlines(token.value) |
||||
|
yield Token(lineno, 'variable_begin', None) |
||||
|
yield Token(lineno, 'name', 'gettext') |
||||
|
yield Token(lineno, 'lparen', None) |
||||
|
yield Token(lineno, 'string', match.group(1)) |
||||
|
yield Token(lineno, 'rparen', None) |
||||
|
yield Token(lineno, 'variable_end', None) |
||||
|
pos = match.end() |
||||
|
if pos < end: |
||||
|
yield Token(lineno, 'data', token.value[pos:]) |
||||
|
|
||||
|
|
||||
|
class ExtensionsTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_extend_late(self): |
||||
|
env = Environment() |
||||
|
env.add_extension('jinja2.ext.autoescape') |
||||
|
t = env.from_string('{% autoescape true %}{{ "<test>" }}{% endautoescape %}') |
||||
|
assert t.render() == '<test>' |
||||
|
|
||||
|
def test_loop_controls(self): |
||||
|
env = Environment(extensions=['jinja2.ext.loopcontrols']) |
||||
|
|
||||
|
tmpl = env.from_string(''' |
||||
|
{%- for item in [1, 2, 3, 4] %} |
||||
|
{%- if item % 2 == 0 %}{% continue %}{% endif -%} |
||||
|
{{ item }} |
||||
|
{%- endfor %}''') |
||||
|
assert tmpl.render() == '13' |
||||
|
|
||||
|
tmpl = env.from_string(''' |
||||
|
{%- for item in [1, 2, 3, 4] %} |
||||
|
{%- if item > 2 %}{% break %}{% endif -%} |
||||
|
{{ item }} |
||||
|
{%- endfor %}''') |
||||
|
assert tmpl.render() == '12' |
||||
|
|
||||
|
def test_do(self): |
||||
|
env = Environment(extensions=['jinja2.ext.do']) |
||||
|
tmpl = env.from_string(''' |
||||
|
{%- set items = [] %} |
||||
|
{%- for char in "foo" %} |
||||
|
{%- do items.append(loop.index0 ~ char) %} |
||||
|
{%- endfor %}{{ items|join(', ') }}''') |
||||
|
assert tmpl.render() == '0f, 1o, 2o' |
||||
|
|
||||
|
def test_with(self): |
||||
|
env = Environment(extensions=['jinja2.ext.with_']) |
||||
|
tmpl = env.from_string('''\ |
||||
|
{% with a=42, b=23 -%} |
||||
|
{{ a }} = {{ b }} |
||||
|
{% endwith -%} |
||||
|
{{ a }} = {{ b }}\ |
||||
|
''') |
||||
|
assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] \ |
||||
|
== ['42 = 23', '1 = 2'] |
||||
|
|
||||
|
def test_extension_nodes(self): |
||||
|
env = Environment(extensions=[TestExtension]) |
||||
|
tmpl = env.from_string('{% test %}') |
||||
|
assert tmpl.render() == 'False|42|23|{}' |
||||
|
|
||||
|
def test_identifier(self): |
||||
|
assert TestExtension.identifier == __name__ + '.TestExtension' |
||||
|
|
||||
|
def test_rebinding(self): |
||||
|
original = Environment(extensions=[TestExtension]) |
||||
|
overlay = original.overlay() |
||||
|
for env in original, overlay: |
||||
|
for ext in env.extensions.itervalues(): |
||||
|
assert ext.environment is env |
||||
|
|
||||
|
def test_preprocessor_extension(self): |
||||
|
env = Environment(extensions=[PreprocessorExtension]) |
||||
|
tmpl = env.from_string('{[[TEST]]}') |
||||
|
assert tmpl.render(foo=42) == '{(42)}' |
||||
|
|
||||
|
def test_streamfilter_extension(self): |
||||
|
env = Environment(extensions=[StreamFilterExtension]) |
||||
|
env.globals['gettext'] = lambda x: x.upper() |
||||
|
tmpl = env.from_string('Foo _(bar) Baz') |
||||
|
out = tmpl.render() |
||||
|
assert out == 'Foo BAR Baz' |
||||
|
|
||||
|
def test_extension_ordering(self): |
||||
|
class T1(Extension): |
||||
|
priority = 1 |
||||
|
class T2(Extension): |
||||
|
priority = 2 |
||||
|
env = Environment(extensions=[T1, T2]) |
||||
|
ext = list(env.iter_extensions()) |
||||
|
assert ext[0].__class__ is T1 |
||||
|
assert ext[1].__class__ is T2 |
||||
|
|
||||
|
|
||||
|
class InternationalizationTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_trans(self): |
||||
|
tmpl = i18n_env.get_template('child.html') |
||||
|
assert tmpl.render(LANGUAGE='de') == '<title>fehlend</title>pass auf' |
||||
|
|
||||
|
def test_trans_plural(self): |
||||
|
tmpl = i18n_env.get_template('plural.html') |
||||
|
assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online' |
||||
|
assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online' |
||||
|
|
||||
|
def test_complex_plural(self): |
||||
|
tmpl = i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% ' |
||||
|
'pluralize count %}{{ count }} items{% endtrans %}') |
||||
|
assert tmpl.render() == '2 items' |
||||
|
self.assert_raises(TemplateAssertionError, i18n_env.from_string, |
||||
|
'{% trans foo %}...{% pluralize bar %}...{% endtrans %}') |
||||
|
|
||||
|
def test_trans_stringformatting(self): |
||||
|
tmpl = i18n_env.get_template('stringformat.html') |
||||
|
assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5' |
||||
|
|
||||
|
def test_extract(self): |
||||
|
from jinja2.ext import babel_extract |
||||
|
source = BytesIO(''' |
||||
|
{{ gettext('Hello World') }} |
||||
|
{% trans %}Hello World{% endtrans %} |
||||
|
{% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %} |
||||
|
'''.encode('ascii')) # make python 3 happy |
||||
|
assert list(babel_extract(source, ('gettext', 'ngettext', '_'), [], {})) == [ |
||||
|
(2, 'gettext', u'Hello World', []), |
||||
|
(3, 'gettext', u'Hello World', []), |
||||
|
(4, 'ngettext', (u'%(users)s user', u'%(users)s users', None), []) |
||||
|
] |
||||
|
|
||||
|
def test_comment_extract(self): |
||||
|
from jinja2.ext import babel_extract |
||||
|
source = BytesIO(''' |
||||
|
{# trans first #} |
||||
|
{{ gettext('Hello World') }} |
||||
|
{% trans %}Hello World{% endtrans %}{# trans second #} |
||||
|
{#: third #} |
||||
|
{% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %} |
||||
|
'''.encode('utf-8')) # make python 3 happy |
||||
|
assert list(babel_extract(source, ('gettext', 'ngettext', '_'), ['trans', ':'], {})) == [ |
||||
|
(3, 'gettext', u'Hello World', ['first']), |
||||
|
(4, 'gettext', u'Hello World', ['second']), |
||||
|
(6, 'ngettext', (u'%(users)s user', u'%(users)s users', None), ['third']) |
||||
|
] |
||||
|
|
||||
|
|
||||
|
class NewstyleInternationalizationTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_trans(self): |
||||
|
tmpl = newstyle_i18n_env.get_template('child.html') |
||||
|
assert tmpl.render(LANGUAGE='de') == '<title>fehlend</title>pass auf' |
||||
|
|
||||
|
def test_trans_plural(self): |
||||
|
tmpl = newstyle_i18n_env.get_template('plural.html') |
||||
|
assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online' |
||||
|
assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online' |
||||
|
|
||||
|
def test_complex_plural(self): |
||||
|
tmpl = newstyle_i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% ' |
||||
|
'pluralize count %}{{ count }} items{% endtrans %}') |
||||
|
assert tmpl.render() == '2 items' |
||||
|
self.assert_raises(TemplateAssertionError, i18n_env.from_string, |
||||
|
'{% trans foo %}...{% pluralize bar %}...{% endtrans %}') |
||||
|
|
||||
|
def test_trans_stringformatting(self): |
||||
|
tmpl = newstyle_i18n_env.get_template('stringformat.html') |
||||
|
assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5' |
||||
|
|
||||
|
def test_newstyle_plural(self): |
||||
|
tmpl = newstyle_i18n_env.get_template('ngettext.html') |
||||
|
assert tmpl.render(LANGUAGE='de', apples=1) == '1 Apfel' |
||||
|
assert tmpl.render(LANGUAGE='de', apples=5) == u'5 Äpfel' |
||||
|
|
||||
|
def test_autoescape_support(self): |
||||
|
env = Environment(extensions=['jinja2.ext.autoescape', |
||||
|
'jinja2.ext.i18n']) |
||||
|
env.install_gettext_callables(lambda x: u'<strong>Wert: %(name)s</strong>', |
||||
|
lambda s, p, n: s, newstyle=True) |
||||
|
t = env.from_string('{% autoescape ae %}{{ gettext("foo", name=' |
||||
|
'"<test>") }}{% endautoescape %}') |
||||
|
assert t.render(ae=True) == '<strong>Wert: <test></strong>' |
||||
|
assert t.render(ae=False) == '<strong>Wert: <test></strong>' |
||||
|
|
||||
|
def test_num_used_twice(self): |
||||
|
tmpl = newstyle_i18n_env.get_template('ngettext_long.html') |
||||
|
assert tmpl.render(apples=5, LANGUAGE='de') == u'5 Äpfel' |
||||
|
|
||||
|
def test_num_called_num(self): |
||||
|
source = newstyle_i18n_env.compile(''' |
||||
|
{% trans num=3 %}{{ num }} apple{% pluralize |
||||
|
%}{{ num }} apples{% endtrans %} |
||||
|
''', raw=True) |
||||
|
# quite hacky, but the only way to properly test that. The idea is |
||||
|
# that the generated code does not pass num twice (although that |
||||
|
# would work) for better performance. This only works on the |
||||
|
# newstyle gettext of course |
||||
|
assert re.search(r"l_ngettext, u?'\%\(num\)s apple', u?'\%\(num\)s " |
||||
|
r"apples', 3", source) is not None |
||||
|
|
||||
|
def test_trans_vars(self): |
||||
|
t1 = newstyle_i18n_env.get_template('transvars1.html') |
||||
|
t2 = newstyle_i18n_env.get_template('transvars2.html') |
||||
|
t3 = newstyle_i18n_env.get_template('transvars3.html') |
||||
|
assert t1.render(num=1, LANGUAGE='de') == 'Benutzer: 1' |
||||
|
assert t2.render(count=23, LANGUAGE='de') == 'Benutzer: 23' |
||||
|
assert t3.render(num=42, LANGUAGE='de') == 'Benutzer: 42' |
||||
|
|
||||
|
def test_novars_vars_escaping(self): |
||||
|
t = newstyle_i18n_env.get_template('novars.html') |
||||
|
assert t.render() == '%(hello)s' |
||||
|
t = newstyle_i18n_env.get_template('vars.html') |
||||
|
assert t.render(foo='42') == '42%(foo)s' |
||||
|
t = newstyle_i18n_env.get_template('explicitvars.html') |
||||
|
assert t.render() == '%(foo)s' |
||||
|
|
||||
|
|
||||
|
class AutoEscapeTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_scoped_setting(self): |
||||
|
env = Environment(extensions=['jinja2.ext.autoescape'], |
||||
|
autoescape=True) |
||||
|
tmpl = env.from_string(''' |
||||
|
{{ "<HelloWorld>" }} |
||||
|
{% autoescape false %} |
||||
|
{{ "<HelloWorld>" }} |
||||
|
{% endautoescape %} |
||||
|
{{ "<HelloWorld>" }} |
||||
|
''') |
||||
|
assert tmpl.render().split() == \ |
||||
|
[u'<HelloWorld>', u'<HelloWorld>', u'<HelloWorld>'] |
||||
|
|
||||
|
env = Environment(extensions=['jinja2.ext.autoescape'], |
||||
|
autoescape=False) |
||||
|
tmpl = env.from_string(''' |
||||
|
{{ "<HelloWorld>" }} |
||||
|
{% autoescape true %} |
||||
|
{{ "<HelloWorld>" }} |
||||
|
{% endautoescape %} |
||||
|
{{ "<HelloWorld>" }} |
||||
|
''') |
||||
|
assert tmpl.render().split() == \ |
||||
|
[u'<HelloWorld>', u'<HelloWorld>', u'<HelloWorld>'] |
||||
|
|
||||
|
def test_nonvolatile(self): |
||||
|
env = Environment(extensions=['jinja2.ext.autoescape'], |
||||
|
autoescape=True) |
||||
|
tmpl = env.from_string('{{ {"foo": "<test>"}|xmlattr|escape }}') |
||||
|
assert tmpl.render() == ' foo="<test>"' |
||||
|
tmpl = env.from_string('{% autoescape false %}{{ {"foo": "<test>"}' |
||||
|
'|xmlattr|escape }}{% endautoescape %}') |
||||
|
assert tmpl.render() == ' foo="&lt;test&gt;"' |
||||
|
|
||||
|
def test_volatile(self): |
||||
|
env = Environment(extensions=['jinja2.ext.autoescape'], |
||||
|
autoescape=True) |
||||
|
tmpl = env.from_string('{% autoescape foo %}{{ {"foo": "<test>"}' |
||||
|
'|xmlattr|escape }}{% endautoescape %}') |
||||
|
assert tmpl.render(foo=False) == ' foo="&lt;test&gt;"' |
||||
|
assert tmpl.render(foo=True) == ' foo="<test>"' |
||||
|
|
||||
|
def test_scoping(self): |
||||
|
env = Environment(extensions=['jinja2.ext.autoescape']) |
||||
|
tmpl = env.from_string('{% autoescape true %}{% set x = "<x>" %}{{ x }}' |
||||
|
'{% endautoescape %}{{ x }}{{ "<y>" }}') |
||||
|
assert tmpl.render(x=1) == '<x>1<y>' |
||||
|
|
||||
|
def test_volatile_scoping(self): |
||||
|
env = Environment(extensions=['jinja2.ext.autoescape']) |
||||
|
tmplsource = ''' |
||||
|
{% autoescape val %} |
||||
|
{% macro foo(x) %} |
||||
|
[{{ x }}] |
||||
|
{% endmacro %} |
||||
|
{{ foo().__class__.__name__ }} |
||||
|
{% endautoescape %} |
||||
|
{{ '<testing>' }} |
||||
|
''' |
||||
|
tmpl = env.from_string(tmplsource) |
||||
|
assert tmpl.render(val=True).split()[0] == 'Markup' |
||||
|
assert tmpl.render(val=False).split()[0] == unicode.__name__ |
||||
|
|
||||
|
# looking at the source we should see <testing> there in raw |
||||
|
# (and then escaped as well) |
||||
|
env = Environment(extensions=['jinja2.ext.autoescape']) |
||||
|
pysource = env.compile(tmplsource, raw=True) |
||||
|
assert '<testing>\\n' in pysource |
||||
|
|
||||
|
env = Environment(extensions=['jinja2.ext.autoescape'], |
||||
|
autoescape=True) |
||||
|
pysource = env.compile(tmplsource, raw=True) |
||||
|
assert '<testing>\\n' in pysource |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(unittest.makeSuite(ExtensionsTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(InternationalizationTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(NewstyleInternationalizationTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(AutoEscapeTestCase)) |
||||
|
return suite |
@ -0,0 +1,396 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.filters |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Tests for the jinja filters. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import unittest |
||||
|
from jinja2.testsuite import JinjaTestCase |
||||
|
|
||||
|
from jinja2 import Markup, Environment |
||||
|
|
||||
|
env = Environment() |
||||
|
|
||||
|
|
||||
|
class FilterTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_capitalize(self): |
||||
|
tmpl = env.from_string('{{ "foo bar"|capitalize }}') |
||||
|
assert tmpl.render() == 'Foo bar' |
||||
|
|
||||
|
def test_center(self): |
||||
|
tmpl = env.from_string('{{ "foo"|center(9) }}') |
||||
|
assert tmpl.render() == ' foo ' |
||||
|
|
||||
|
def test_default(self): |
||||
|
tmpl = env.from_string( |
||||
|
"{{ missing|default('no') }}|{{ false|default('no') }}|" |
||||
|
"{{ false|default('no', true) }}|{{ given|default('no') }}" |
||||
|
) |
||||
|
assert tmpl.render(given='yes') == 'no|False|no|yes' |
||||
|
|
||||
|
def test_dictsort(self): |
||||
|
tmpl = env.from_string( |
||||
|
'{{ foo|dictsort }}|' |
||||
|
'{{ foo|dictsort(true) }}|' |
||||
|
'{{ foo|dictsort(false, "value") }}' |
||||
|
) |
||||
|
out = tmpl.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3}) |
||||
|
assert out == ("[('aa', 0), ('AB', 3), ('b', 1), ('c', 2)]|" |
||||
|
"[('AB', 3), ('aa', 0), ('b', 1), ('c', 2)]|" |
||||
|
"[('aa', 0), ('b', 1), ('c', 2), ('AB', 3)]") |
||||
|
|
||||
|
def test_batch(self): |
||||
|
tmpl = env.from_string("{{ foo|batch(3)|list }}|" |
||||
|
"{{ foo|batch(3, 'X')|list }}") |
||||
|
out = tmpl.render(foo=range(10)) |
||||
|
assert out == ("[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|" |
||||
|
"[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]") |
||||
|
|
||||
|
def test_slice(self): |
||||
|
tmpl = env.from_string('{{ foo|slice(3)|list }}|' |
||||
|
'{{ foo|slice(3, "X")|list }}') |
||||
|
out = tmpl.render(foo=range(10)) |
||||
|
assert out == ("[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|" |
||||
|
"[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]") |
||||
|
|
||||
|
def test_escape(self): |
||||
|
tmpl = env.from_string('''{{ '<">&'|escape }}''') |
||||
|
out = tmpl.render() |
||||
|
assert out == '<">&' |
||||
|
|
||||
|
def test_striptags(self): |
||||
|
tmpl = env.from_string('''{{ foo|striptags }}''') |
||||
|
out = tmpl.render(foo=' <p>just a small \n <a href="#">' |
||||
|
'example</a> link</p>\n<p>to a webpage</p> ' |
||||
|
'<!-- <p>and some commented stuff</p> -->') |
||||
|
assert out == 'just a small example link to a webpage' |
||||
|
|
||||
|
def test_filesizeformat(self): |
||||
|
tmpl = env.from_string( |
||||
|
'{{ 100|filesizeformat }}|' |
||||
|
'{{ 1000|filesizeformat }}|' |
||||
|
'{{ 1000000|filesizeformat }}|' |
||||
|
'{{ 1000000000|filesizeformat }}|' |
||||
|
'{{ 1000000000000|filesizeformat }}|' |
||||
|
'{{ 100|filesizeformat(true) }}|' |
||||
|
'{{ 1000|filesizeformat(true) }}|' |
||||
|
'{{ 1000000|filesizeformat(true) }}|' |
||||
|
'{{ 1000000000|filesizeformat(true) }}|' |
||||
|
'{{ 1000000000000|filesizeformat(true) }}' |
||||
|
) |
||||
|
out = tmpl.render() |
||||
|
self.assert_equal(out, ( |
||||
|
'100 Bytes|1.0 kB|1.0 MB|1.0 GB|1.0 TB|100 Bytes|' |
||||
|
'1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB' |
||||
|
)) |
||||
|
|
||||
|
def test_filesizeformat_issue59(self): |
||||
|
tmpl = env.from_string( |
||||
|
'{{ 300|filesizeformat }}|' |
||||
|
'{{ 3000|filesizeformat }}|' |
||||
|
'{{ 3000000|filesizeformat }}|' |
||||
|
'{{ 3000000000|filesizeformat }}|' |
||||
|
'{{ 3000000000000|filesizeformat }}|' |
||||
|
'{{ 300|filesizeformat(true) }}|' |
||||
|
'{{ 3000|filesizeformat(true) }}|' |
||||
|
'{{ 3000000|filesizeformat(true) }}' |
||||
|
) |
||||
|
out = tmpl.render() |
||||
|
self.assert_equal(out, ( |
||||
|
'300 Bytes|3.0 kB|3.0 MB|3.0 GB|3.0 TB|300 Bytes|' |
||||
|
'2.9 KiB|2.9 MiB' |
||||
|
)) |
||||
|
|
||||
|
|
||||
|
def test_first(self): |
||||
|
tmpl = env.from_string('{{ foo|first }}') |
||||
|
out = tmpl.render(foo=range(10)) |
||||
|
assert out == '0' |
||||
|
|
||||
|
def test_float(self): |
||||
|
tmpl = env.from_string('{{ "42"|float }}|' |
||||
|
'{{ "ajsghasjgd"|float }}|' |
||||
|
'{{ "32.32"|float }}') |
||||
|
out = tmpl.render() |
||||
|
assert out == '42.0|0.0|32.32' |
||||
|
|
||||
|
def test_format(self): |
||||
|
tmpl = env.from_string('''{{ "%s|%s"|format("a", "b") }}''') |
||||
|
out = tmpl.render() |
||||
|
assert out == 'a|b' |
||||
|
|
||||
|
def test_indent(self): |
||||
|
tmpl = env.from_string('{{ foo|indent(2) }}|{{ foo|indent(2, true) }}') |
||||
|
text = '\n'.join([' '.join(['foo', 'bar'] * 2)] * 2) |
||||
|
out = tmpl.render(foo=text) |
||||
|
assert out == ('foo bar foo bar\n foo bar foo bar| ' |
||||
|
'foo bar foo bar\n foo bar foo bar') |
||||
|
|
||||
|
def test_int(self): |
||||
|
tmpl = env.from_string('{{ "42"|int }}|{{ "ajsghasjgd"|int }}|' |
||||
|
'{{ "32.32"|int }}') |
||||
|
out = tmpl.render() |
||||
|
assert out == '42|0|32' |
||||
|
|
||||
|
def test_join(self): |
||||
|
tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}') |
||||
|
out = tmpl.render() |
||||
|
assert out == '1|2|3' |
||||
|
|
||||
|
env2 = Environment(autoescape=True) |
||||
|
tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}') |
||||
|
assert tmpl.render() == '<foo><span>foo</span>' |
||||
|
|
||||
|
def test_join_attribute(self): |
||||
|
class User(object): |
||||
|
def __init__(self, username): |
||||
|
self.username = username |
||||
|
tmpl = env.from_string('''{{ users|join(', ', 'username') }}''') |
||||
|
assert tmpl.render(users=map(User, ['foo', 'bar'])) == 'foo, bar' |
||||
|
|
||||
|
def test_last(self): |
||||
|
tmpl = env.from_string('''{{ foo|last }}''') |
||||
|
out = tmpl.render(foo=range(10)) |
||||
|
assert out == '9' |
||||
|
|
||||
|
def test_length(self): |
||||
|
tmpl = env.from_string('''{{ "hello world"|length }}''') |
||||
|
out = tmpl.render() |
||||
|
assert out == '11' |
||||
|
|
||||
|
def test_lower(self): |
||||
|
tmpl = env.from_string('''{{ "FOO"|lower }}''') |
||||
|
out = tmpl.render() |
||||
|
assert out == 'foo' |
||||
|
|
||||
|
def test_pprint(self): |
||||
|
from pprint import pformat |
||||
|
tmpl = env.from_string('''{{ data|pprint }}''') |
||||
|
data = range(1000) |
||||
|
assert tmpl.render(data=data) == pformat(data) |
||||
|
|
||||
|
def test_random(self): |
||||
|
tmpl = env.from_string('''{{ seq|random }}''') |
||||
|
seq = range(100) |
||||
|
for _ in range(10): |
||||
|
assert int(tmpl.render(seq=seq)) in seq |
||||
|
|
||||
|
def test_reverse(self): |
||||
|
tmpl = env.from_string('{{ "foobar"|reverse|join }}|' |
||||
|
'{{ [1, 2, 3]|reverse|list }}') |
||||
|
assert tmpl.render() == 'raboof|[3, 2, 1]' |
||||
|
|
||||
|
def test_string(self): |
||||
|
x = [1, 2, 3, 4, 5] |
||||
|
tmpl = env.from_string('''{{ obj|string }}''') |
||||
|
assert tmpl.render(obj=x) == unicode(x) |
||||
|
|
||||
|
def test_title(self): |
||||
|
tmpl = env.from_string('''{{ "foo bar"|title }}''') |
||||
|
assert tmpl.render() == "Foo Bar" |
||||
|
tmpl = env.from_string('''{{ "foo's bar"|title }}''') |
||||
|
assert tmpl.render() == "Foo's Bar" |
||||
|
tmpl = env.from_string('''{{ "foo bar"|title }}''') |
||||
|
assert tmpl.render() == "Foo Bar" |
||||
|
tmpl = env.from_string('''{{ "f bar f"|title }}''') |
||||
|
assert tmpl.render() == "F Bar F" |
||||
|
tmpl = env.from_string('''{{ "foo-bar"|title }}''') |
||||
|
assert tmpl.render() == "Foo-Bar" |
||||
|
tmpl = env.from_string('''{{ "foo\tbar"|title }}''') |
||||
|
assert tmpl.render() == "Foo\tBar" |
||||
|
|
||||
|
def test_truncate(self): |
||||
|
tmpl = env.from_string( |
||||
|
'{{ data|truncate(15, true, ">>>") }}|' |
||||
|
'{{ data|truncate(15, false, ">>>") }}|' |
||||
|
'{{ smalldata|truncate(15) }}' |
||||
|
) |
||||
|
out = tmpl.render(data='foobar baz bar' * 1000, |
||||
|
smalldata='foobar baz bar') |
||||
|
assert out == 'foobar baz barf>>>|foobar baz >>>|foobar baz bar' |
||||
|
|
||||
|
def test_upper(self): |
||||
|
tmpl = env.from_string('{{ "foo"|upper }}') |
||||
|
assert tmpl.render() == 'FOO' |
||||
|
|
||||
|
def test_urlize(self): |
||||
|
tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}') |
||||
|
assert tmpl.render() == 'foo <a href="http://www.example.com/">'\ |
||||
|
'http://www.example.com/</a> bar' |
||||
|
|
||||
|
def test_wordcount(self): |
||||
|
tmpl = env.from_string('{{ "foo bar baz"|wordcount }}') |
||||
|
assert tmpl.render() == '3' |
||||
|
|
||||
|
def test_block(self): |
||||
|
tmpl = env.from_string('{% filter lower|escape %}<HEHE>{% endfilter %}') |
||||
|
assert tmpl.render() == '<hehe>' |
||||
|
|
||||
|
def test_chaining(self): |
||||
|
tmpl = env.from_string('''{{ ['<foo>', '<bar>']|first|upper|escape }}''') |
||||
|
assert tmpl.render() == '<FOO>' |
||||
|
|
||||
|
def test_sum(self): |
||||
|
tmpl = env.from_string('''{{ [1, 2, 3, 4, 5, 6]|sum }}''') |
||||
|
assert tmpl.render() == '21' |
||||
|
|
||||
|
def test_sum_attributes(self): |
||||
|
tmpl = env.from_string('''{{ values|sum('value') }}''') |
||||
|
assert tmpl.render(values=[ |
||||
|
{'value': 23}, |
||||
|
{'value': 1}, |
||||
|
{'value': 18}, |
||||
|
]) == '42' |
||||
|
|
||||
|
def test_sum_attributes_nested(self): |
||||
|
tmpl = env.from_string('''{{ values|sum('real.value') }}''') |
||||
|
assert tmpl.render(values=[ |
||||
|
{'real': {'value': 23}}, |
||||
|
{'real': {'value': 1}}, |
||||
|
{'real': {'value': 18}}, |
||||
|
]) == '42' |
||||
|
|
||||
|
def test_abs(self): |
||||
|
tmpl = env.from_string('''{{ -1|abs }}|{{ 1|abs }}''') |
||||
|
assert tmpl.render() == '1|1', tmpl.render() |
||||
|
|
||||
|
def test_round_positive(self): |
||||
|
tmpl = env.from_string('{{ 2.7|round }}|{{ 2.1|round }}|' |
||||
|
"{{ 2.1234|round(3, 'floor') }}|" |
||||
|
"{{ 2.1|round(0, 'ceil') }}") |
||||
|
assert tmpl.render() == '3.0|2.0|2.123|3.0', tmpl.render() |
||||
|
|
||||
|
def test_round_negative(self): |
||||
|
tmpl = env.from_string('{{ 21.3|round(-1)}}|' |
||||
|
"{{ 21.3|round(-1, 'ceil')}}|" |
||||
|
"{{ 21.3|round(-1, 'floor')}}") |
||||
|
assert tmpl.render() == '20.0|30.0|20.0',tmpl.render() |
||||
|
|
||||
|
def test_xmlattr(self): |
||||
|
tmpl = env.from_string("{{ {'foo': 42, 'bar': 23, 'fish': none, " |
||||
|
"'spam': missing, 'blub:blub': '<?>'}|xmlattr }}") |
||||
|
out = tmpl.render().split() |
||||
|
assert len(out) == 3 |
||||
|
assert 'foo="42"' in out |
||||
|
assert 'bar="23"' in out |
||||
|
assert 'blub:blub="<?>"' in out |
||||
|
|
||||
|
def test_sort1(self): |
||||
|
tmpl = env.from_string('{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}') |
||||
|
assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]' |
||||
|
|
||||
|
def test_sort2(self): |
||||
|
tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}') |
||||
|
assert tmpl.render() == 'AbcD' |
||||
|
|
||||
|
def test_sort3(self): |
||||
|
tmpl = env.from_string('''{{ ['foo', 'Bar', 'blah']|sort }}''') |
||||
|
assert tmpl.render() == "['Bar', 'blah', 'foo']" |
||||
|
|
||||
|
def test_sort4(self): |
||||
|
class Magic(object): |
||||
|
def __init__(self, value): |
||||
|
self.value = value |
||||
|
def __unicode__(self): |
||||
|
return unicode(self.value) |
||||
|
tmpl = env.from_string('''{{ items|sort(attribute='value')|join }}''') |
||||
|
assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == '1234' |
||||
|
|
||||
|
def test_groupby(self): |
||||
|
tmpl = env.from_string(''' |
||||
|
{%- for grouper, list in [{'foo': 1, 'bar': 2}, |
||||
|
{'foo': 2, 'bar': 3}, |
||||
|
{'foo': 1, 'bar': 1}, |
||||
|
{'foo': 3, 'bar': 4}]|groupby('foo') -%} |
||||
|
{{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}| |
||||
|
{%- endfor %}''') |
||||
|
assert tmpl.render().split('|') == [ |
||||
|
"1: 1, 2: 1, 1", |
||||
|
"2: 2, 3", |
||||
|
"3: 3, 4", |
||||
|
"" |
||||
|
] |
||||
|
|
||||
|
def test_groupby_tuple_index(self): |
||||
|
tmpl = env.from_string(''' |
||||
|
{%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%} |
||||
|
{{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}| |
||||
|
{%- endfor %}''') |
||||
|
assert tmpl.render() == 'a:1:2|b:1|' |
||||
|
|
||||
|
def test_groupby_multidot(self): |
||||
|
class Date(object): |
||||
|
def __init__(self, day, month, year): |
||||
|
self.day = day |
||||
|
self.month = month |
||||
|
self.year = year |
||||
|
class Article(object): |
||||
|
def __init__(self, title, *date): |
||||
|
self.date = Date(*date) |
||||
|
self.title = title |
||||
|
articles = [ |
||||
|
Article('aha', 1, 1, 1970), |
||||
|
Article('interesting', 2, 1, 1970), |
||||
|
Article('really?', 3, 1, 1970), |
||||
|
Article('totally not', 1, 1, 1971) |
||||
|
] |
||||
|
tmpl = env.from_string(''' |
||||
|
{%- for year, list in articles|groupby('date.year') -%} |
||||
|
{{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}| |
||||
|
{%- endfor %}''') |
||||
|
assert tmpl.render(articles=articles).split('|') == [ |
||||
|
'1970[aha][interesting][really?]', |
||||
|
'1971[totally not]', |
||||
|
'' |
||||
|
] |
||||
|
|
||||
|
def test_filtertag(self): |
||||
|
tmpl = env.from_string("{% filter upper|replace('FOO', 'foo') %}" |
||||
|
"foobar{% endfilter %}") |
||||
|
assert tmpl.render() == 'fooBAR' |
||||
|
|
||||
|
def test_replace(self): |
||||
|
env = Environment() |
||||
|
tmpl = env.from_string('{{ string|replace("o", 42) }}') |
||||
|
assert tmpl.render(string='<foo>') == '<f4242>' |
||||
|
env = Environment(autoescape=True) |
||||
|
tmpl = env.from_string('{{ string|replace("o", 42) }}') |
||||
|
assert tmpl.render(string='<foo>') == '<f4242>' |
||||
|
tmpl = env.from_string('{{ string|replace("<", 42) }}') |
||||
|
assert tmpl.render(string='<foo>') == '42foo>' |
||||
|
tmpl = env.from_string('{{ string|replace("o", ">x<") }}') |
||||
|
assert tmpl.render(string=Markup('foo')) == 'f>x<>x<' |
||||
|
|
||||
|
def test_forceescape(self): |
||||
|
tmpl = env.from_string('{{ x|forceescape }}') |
||||
|
assert tmpl.render(x=Markup('<div />')) == u'<div />' |
||||
|
|
||||
|
def test_safe(self): |
||||
|
env = Environment(autoescape=True) |
||||
|
tmpl = env.from_string('{{ "<div>foo</div>"|safe }}') |
||||
|
assert tmpl.render() == '<div>foo</div>' |
||||
|
tmpl = env.from_string('{{ "<div>foo</div>" }}') |
||||
|
assert tmpl.render() == '<div>foo</div>' |
||||
|
|
||||
|
def test_urlencode(self): |
||||
|
env = Environment(autoescape=True) |
||||
|
tmpl = env.from_string('{{ "Hello, world!"|urlencode }}') |
||||
|
assert tmpl.render() == 'Hello%2C%20world%21' |
||||
|
tmpl = env.from_string('{{ o|urlencode }}') |
||||
|
assert tmpl.render(o=u"Hello, world\u203d") == "Hello%2C%20world%E2%80%BD" |
||||
|
assert tmpl.render(o=(("f", 1),)) == "f=1" |
||||
|
assert tmpl.render(o=(('f', 1), ("z", 2))) == "f=1&z=2" |
||||
|
assert tmpl.render(o=((u"\u203d", 1),)) == "%E2%80%BD=1" |
||||
|
assert tmpl.render(o={u"\u203d": 1}) == "%E2%80%BD=1" |
||||
|
assert tmpl.render(o={0: 1}) == "0=1" |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(unittest.makeSuite(FilterTestCase)) |
||||
|
return suite |
@ -0,0 +1,141 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.imports |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Tests the import features (with includes). |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import unittest |
||||
|
|
||||
|
from jinja2.testsuite import JinjaTestCase |
||||
|
|
||||
|
from jinja2 import Environment, DictLoader |
||||
|
from jinja2.exceptions import TemplateNotFound, TemplatesNotFound |
||||
|
|
||||
|
|
||||
|
test_env = Environment(loader=DictLoader(dict( |
||||
|
module='{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}', |
||||
|
header='[{{ foo }}|{{ 23 }}]', |
||||
|
o_printer='({{ o }})' |
||||
|
))) |
||||
|
test_env.globals['bar'] = 23 |
||||
|
|
||||
|
|
||||
|
class ImportsTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_context_imports(self): |
||||
|
t = test_env.from_string('{% import "module" as m %}{{ m.test() }}') |
||||
|
assert t.render(foo=42) == '[|23]' |
||||
|
t = test_env.from_string('{% import "module" as m without context %}{{ m.test() }}') |
||||
|
assert t.render(foo=42) == '[|23]' |
||||
|
t = test_env.from_string('{% import "module" as m with context %}{{ m.test() }}') |
||||
|
assert t.render(foo=42) == '[42|23]' |
||||
|
t = test_env.from_string('{% from "module" import test %}{{ test() }}') |
||||
|
assert t.render(foo=42) == '[|23]' |
||||
|
t = test_env.from_string('{% from "module" import test without context %}{{ test() }}') |
||||
|
assert t.render(foo=42) == '[|23]' |
||||
|
t = test_env.from_string('{% from "module" import test with context %}{{ test() }}') |
||||
|
assert t.render(foo=42) == '[42|23]' |
||||
|
|
||||
|
def test_trailing_comma(self): |
||||
|
test_env.from_string('{% from "foo" import bar, baz with context %}') |
||||
|
test_env.from_string('{% from "foo" import bar, baz, with context %}') |
||||
|
test_env.from_string('{% from "foo" import bar, with context %}') |
||||
|
test_env.from_string('{% from "foo" import bar, with, context %}') |
||||
|
test_env.from_string('{% from "foo" import bar, with with context %}') |
||||
|
|
||||
|
def test_exports(self): |
||||
|
m = test_env.from_string(''' |
||||
|
{% macro toplevel() %}...{% endmacro %} |
||||
|
{% macro __private() %}...{% endmacro %} |
||||
|
{% set variable = 42 %} |
||||
|
{% for item in [1] %} |
||||
|
{% macro notthere() %}{% endmacro %} |
||||
|
{% endfor %} |
||||
|
''').module |
||||
|
assert m.toplevel() == '...' |
||||
|
assert not hasattr(m, '__missing') |
||||
|
assert m.variable == 42 |
||||
|
assert not hasattr(m, 'notthere') |
||||
|
|
||||
|
|
||||
|
class IncludesTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_context_include(self): |
||||
|
t = test_env.from_string('{% include "header" %}') |
||||
|
assert t.render(foo=42) == '[42|23]' |
||||
|
t = test_env.from_string('{% include "header" with context %}') |
||||
|
assert t.render(foo=42) == '[42|23]' |
||||
|
t = test_env.from_string('{% include "header" without context %}') |
||||
|
assert t.render(foo=42) == '[|23]' |
||||
|
|
||||
|
def test_choice_includes(self): |
||||
|
t = test_env.from_string('{% include ["missing", "header"] %}') |
||||
|
assert t.render(foo=42) == '[42|23]' |
||||
|
|
||||
|
t = test_env.from_string('{% include ["missing", "missing2"] ignore missing %}') |
||||
|
assert t.render(foo=42) == '' |
||||
|
|
||||
|
t = test_env.from_string('{% include ["missing", "missing2"] %}') |
||||
|
self.assert_raises(TemplateNotFound, t.render) |
||||
|
try: |
||||
|
t.render() |
||||
|
except TemplatesNotFound, e: |
||||
|
assert e.templates == ['missing', 'missing2'] |
||||
|
assert e.name == 'missing2' |
||||
|
else: |
||||
|
assert False, 'thou shalt raise' |
||||
|
|
||||
|
def test_includes(t, **ctx): |
||||
|
ctx['foo'] = 42 |
||||
|
assert t.render(ctx) == '[42|23]' |
||||
|
|
||||
|
t = test_env.from_string('{% include ["missing", "header"] %}') |
||||
|
test_includes(t) |
||||
|
t = test_env.from_string('{% include x %}') |
||||
|
test_includes(t, x=['missing', 'header']) |
||||
|
t = test_env.from_string('{% include [x, "header"] %}') |
||||
|
test_includes(t, x='missing') |
||||
|
t = test_env.from_string('{% include x %}') |
||||
|
test_includes(t, x='header') |
||||
|
t = test_env.from_string('{% include x %}') |
||||
|
test_includes(t, x='header') |
||||
|
t = test_env.from_string('{% include [x] %}') |
||||
|
test_includes(t, x='header') |
||||
|
|
||||
|
def test_include_ignoring_missing(self): |
||||
|
t = test_env.from_string('{% include "missing" %}') |
||||
|
self.assert_raises(TemplateNotFound, t.render) |
||||
|
for extra in '', 'with context', 'without context': |
||||
|
t = test_env.from_string('{% include "missing" ignore missing ' + |
||||
|
extra + ' %}') |
||||
|
assert t.render() == '' |
||||
|
|
||||
|
def test_context_include_with_overrides(self): |
||||
|
env = Environment(loader=DictLoader(dict( |
||||
|
main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}", |
||||
|
item="{{ item }}" |
||||
|
))) |
||||
|
assert env.get_template("main").render() == "123" |
||||
|
|
||||
|
def test_unoptimized_scopes(self): |
||||
|
t = test_env.from_string(""" |
||||
|
{% macro outer(o) %} |
||||
|
{% macro inner() %} |
||||
|
{% include "o_printer" %} |
||||
|
{% endmacro %} |
||||
|
{{ inner() }} |
||||
|
{% endmacro %} |
||||
|
{{ outer("FOO") }} |
||||
|
""") |
||||
|
assert t.render().strip() == '(FOO)' |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(unittest.makeSuite(ImportsTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(IncludesTestCase)) |
||||
|
return suite |
@ -0,0 +1,227 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.inheritance |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Tests the template inheritance feature. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import unittest |
||||
|
|
||||
|
from jinja2.testsuite import JinjaTestCase |
||||
|
|
||||
|
from jinja2 import Environment, DictLoader |
||||
|
|
||||
|
|
||||
|
LAYOUTTEMPLATE = '''\ |
||||
|
|{% block block1 %}block 1 from layout{% endblock %} |
||||
|
|{% block block2 %}block 2 from layout{% endblock %} |
||||
|
|{% block block3 %} |
||||
|
{% block block4 %}nested block 4 from layout{% endblock %} |
||||
|
{% endblock %}|''' |
||||
|
|
||||
|
LEVEL1TEMPLATE = '''\ |
||||
|
{% extends "layout" %} |
||||
|
{% block block1 %}block 1 from level1{% endblock %}''' |
||||
|
|
||||
|
LEVEL2TEMPLATE = '''\ |
||||
|
{% extends "level1" %} |
||||
|
{% block block2 %}{% block block5 %}nested block 5 from level2{% |
||||
|
endblock %}{% endblock %}''' |
||||
|
|
||||
|
LEVEL3TEMPLATE = '''\ |
||||
|
{% extends "level2" %} |
||||
|
{% block block5 %}block 5 from level3{% endblock %} |
||||
|
{% block block4 %}block 4 from level3{% endblock %} |
||||
|
''' |
||||
|
|
||||
|
LEVEL4TEMPLATE = '''\ |
||||
|
{% extends "level3" %} |
||||
|
{% block block3 %}block 3 from level4{% endblock %} |
||||
|
''' |
||||
|
|
||||
|
WORKINGTEMPLATE = '''\ |
||||
|
{% extends "layout" %} |
||||
|
{% block block1 %} |
||||
|
{% if false %} |
||||
|
{% block block2 %} |
||||
|
this should workd |
||||
|
{% endblock %} |
||||
|
{% endif %} |
||||
|
{% endblock %} |
||||
|
''' |
||||
|
|
||||
|
env = Environment(loader=DictLoader({ |
||||
|
'layout': LAYOUTTEMPLATE, |
||||
|
'level1': LEVEL1TEMPLATE, |
||||
|
'level2': LEVEL2TEMPLATE, |
||||
|
'level3': LEVEL3TEMPLATE, |
||||
|
'level4': LEVEL4TEMPLATE, |
||||
|
'working': WORKINGTEMPLATE |
||||
|
}), trim_blocks=True) |
||||
|
|
||||
|
|
||||
|
class InheritanceTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_layout(self): |
||||
|
tmpl = env.get_template('layout') |
||||
|
assert tmpl.render() == ('|block 1 from layout|block 2 from ' |
||||
|
'layout|nested block 4 from layout|') |
||||
|
|
||||
|
def test_level1(self): |
||||
|
tmpl = env.get_template('level1') |
||||
|
assert tmpl.render() == ('|block 1 from level1|block 2 from ' |
||||
|
'layout|nested block 4 from layout|') |
||||
|
|
||||
|
def test_level2(self): |
||||
|
tmpl = env.get_template('level2') |
||||
|
assert tmpl.render() == ('|block 1 from level1|nested block 5 from ' |
||||
|
'level2|nested block 4 from layout|') |
||||
|
|
||||
|
def test_level3(self): |
||||
|
tmpl = env.get_template('level3') |
||||
|
assert tmpl.render() == ('|block 1 from level1|block 5 from level3|' |
||||
|
'block 4 from level3|') |
||||
|
|
||||
|
def test_level4(sel): |
||||
|
tmpl = env.get_template('level4') |
||||
|
assert tmpl.render() == ('|block 1 from level1|block 5 from ' |
||||
|
'level3|block 3 from level4|') |
||||
|
|
||||
|
def test_super(self): |
||||
|
env = Environment(loader=DictLoader({ |
||||
|
'a': '{% block intro %}INTRO{% endblock %}|' |
||||
|
'BEFORE|{% block data %}INNER{% endblock %}|AFTER', |
||||
|
'b': '{% extends "a" %}{% block data %}({{ ' |
||||
|
'super() }}){% endblock %}', |
||||
|
'c': '{% extends "b" %}{% block intro %}--{{ ' |
||||
|
'super() }}--{% endblock %}\n{% block data ' |
||||
|
'%}[{{ super() }}]{% endblock %}' |
||||
|
})) |
||||
|
tmpl = env.get_template('c') |
||||
|
assert tmpl.render() == '--INTRO--|BEFORE|[(INNER)]|AFTER' |
||||
|
|
||||
|
def test_working(self): |
||||
|
tmpl = env.get_template('working') |
||||
|
|
||||
|
def test_reuse_blocks(self): |
||||
|
tmpl = env.from_string('{{ self.foo() }}|{% block foo %}42' |
||||
|
'{% endblock %}|{{ self.foo() }}') |
||||
|
assert tmpl.render() == '42|42|42' |
||||
|
|
||||
|
def test_preserve_blocks(self): |
||||
|
env = Environment(loader=DictLoader({ |
||||
|
'a': '{% if false %}{% block x %}A{% endblock %}{% endif %}{{ self.x() }}', |
||||
|
'b': '{% extends "a" %}{% block x %}B{{ super() }}{% endblock %}' |
||||
|
})) |
||||
|
tmpl = env.get_template('b') |
||||
|
assert tmpl.render() == 'BA' |
||||
|
|
||||
|
def test_dynamic_inheritance(self): |
||||
|
env = Environment(loader=DictLoader({ |
||||
|
'master1': 'MASTER1{% block x %}{% endblock %}', |
||||
|
'master2': 'MASTER2{% block x %}{% endblock %}', |
||||
|
'child': '{% extends master %}{% block x %}CHILD{% endblock %}' |
||||
|
})) |
||||
|
tmpl = env.get_template('child') |
||||
|
for m in range(1, 3): |
||||
|
assert tmpl.render(master='master%d' % m) == 'MASTER%dCHILD' % m |
||||
|
|
||||
|
def test_multi_inheritance(self): |
||||
|
env = Environment(loader=DictLoader({ |
||||
|
'master1': 'MASTER1{% block x %}{% endblock %}', |
||||
|
'master2': 'MASTER2{% block x %}{% endblock %}', |
||||
|
'child': '''{% if master %}{% extends master %}{% else %}{% extends |
||||
|
'master1' %}{% endif %}{% block x %}CHILD{% endblock %}''' |
||||
|
})) |
||||
|
tmpl = env.get_template('child') |
||||
|
assert tmpl.render(master='master2') == 'MASTER2CHILD' |
||||
|
assert tmpl.render(master='master1') == 'MASTER1CHILD' |
||||
|
assert tmpl.render() == 'MASTER1CHILD' |
||||
|
|
||||
|
def test_scoped_block(self): |
||||
|
env = Environment(loader=DictLoader({ |
||||
|
'master.html': '{% for item in seq %}[{% block item scoped %}' |
||||
|
'{% endblock %}]{% endfor %}' |
||||
|
})) |
||||
|
t = env.from_string('{% extends "master.html" %}{% block item %}' |
||||
|
'{{ item }}{% endblock %}') |
||||
|
assert t.render(seq=range(5)) == '[0][1][2][3][4]' |
||||
|
|
||||
|
def test_super_in_scoped_block(self): |
||||
|
env = Environment(loader=DictLoader({ |
||||
|
'master.html': '{% for item in seq %}[{% block item scoped %}' |
||||
|
'{{ item }}{% endblock %}]{% endfor %}' |
||||
|
})) |
||||
|
t = env.from_string('{% extends "master.html" %}{% block item %}' |
||||
|
'{{ super() }}|{{ item * 2 }}{% endblock %}') |
||||
|
assert t.render(seq=range(5)) == '[0|0][1|2][2|4][3|6][4|8]' |
||||
|
|
||||
|
def test_scoped_block_after_inheritance(self): |
||||
|
env = Environment(loader=DictLoader({ |
||||
|
'layout.html': ''' |
||||
|
{% block useless %}{% endblock %} |
||||
|
''', |
||||
|
'index.html': ''' |
||||
|
{%- extends 'layout.html' %} |
||||
|
{% from 'helpers.html' import foo with context %} |
||||
|
{% block useless %} |
||||
|
{% for x in [1, 2, 3] %} |
||||
|
{% block testing scoped %} |
||||
|
{{ foo(x) }} |
||||
|
{% endblock %} |
||||
|
{% endfor %} |
||||
|
{% endblock %} |
||||
|
''', |
||||
|
'helpers.html': ''' |
||||
|
{% macro foo(x) %}{{ the_foo + x }}{% endmacro %} |
||||
|
''' |
||||
|
})) |
||||
|
rv = env.get_template('index.html').render(the_foo=42).split() |
||||
|
assert rv == ['43', '44', '45'] |
||||
|
|
||||
|
|
||||
|
class BugFixTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_fixed_macro_scoping_bug(self): |
||||
|
assert Environment(loader=DictLoader({ |
||||
|
'test.html': '''\ |
||||
|
{% extends 'details.html' %} |
||||
|
|
||||
|
{% macro my_macro() %} |
||||
|
my_macro |
||||
|
{% endmacro %} |
||||
|
|
||||
|
{% block inner_box %} |
||||
|
{{ my_macro() }} |
||||
|
{% endblock %} |
||||
|
''', |
||||
|
'details.html': '''\ |
||||
|
{% extends 'standard.html' %} |
||||
|
|
||||
|
{% macro my_macro() %} |
||||
|
my_macro |
||||
|
{% endmacro %} |
||||
|
|
||||
|
{% block content %} |
||||
|
{% block outer_box %} |
||||
|
outer_box |
||||
|
{% block inner_box %} |
||||
|
inner_box |
||||
|
{% endblock %} |
||||
|
{% endblock %} |
||||
|
{% endblock %} |
||||
|
''', |
||||
|
'standard.html': ''' |
||||
|
{% block content %} {% endblock %} |
||||
|
''' |
||||
|
})).get_template("test.html").render().split() == [u'outer_box', u'my_macro'] |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(unittest.makeSuite(InheritanceTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(BugFixTestCase)) |
||||
|
return suite |
@ -0,0 +1,387 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.lexnparse |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
All the unittests regarding lexing, parsing and syntax. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import sys |
||||
|
import unittest |
||||
|
|
||||
|
from jinja2.testsuite import JinjaTestCase |
||||
|
|
||||
|
from jinja2 import Environment, Template, TemplateSyntaxError, \ |
||||
|
UndefinedError, nodes |
||||
|
|
||||
|
env = Environment() |
||||
|
|
||||
|
|
||||
|
# how does a string look like in jinja syntax? |
||||
|
if sys.version_info < (3, 0): |
||||
|
def jinja_string_repr(string): |
||||
|
return repr(string)[1:] |
||||
|
else: |
||||
|
jinja_string_repr = repr |
||||
|
|
||||
|
|
||||
|
class LexerTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_raw1(self): |
||||
|
tmpl = env.from_string('{% raw %}foo{% endraw %}|' |
||||
|
'{%raw%}{{ bar }}|{% baz %}{% endraw %}') |
||||
|
assert tmpl.render() == 'foo|{{ bar }}|{% baz %}' |
||||
|
|
||||
|
def test_raw2(self): |
||||
|
tmpl = env.from_string('1 {%- raw -%} 2 {%- endraw -%} 3') |
||||
|
assert tmpl.render() == '123' |
||||
|
|
||||
|
def test_balancing(self): |
||||
|
env = Environment('{%', '%}', '${', '}') |
||||
|
tmpl = env.from_string('''{% for item in seq |
||||
|
%}${{'foo': item}|upper}{% endfor %}''') |
||||
|
assert tmpl.render(seq=range(3)) == "{'FOO': 0}{'FOO': 1}{'FOO': 2}" |
||||
|
|
||||
|
def test_comments(self): |
||||
|
env = Environment('<!--', '-->', '{', '}') |
||||
|
tmpl = env.from_string('''\ |
||||
|
<ul> |
||||
|
<!--- for item in seq --> |
||||
|
<li>{item}</li> |
||||
|
<!--- endfor --> |
||||
|
</ul>''') |
||||
|
assert tmpl.render(seq=range(3)) == ("<ul>\n <li>0</li>\n " |
||||
|
"<li>1</li>\n <li>2</li>\n</ul>") |
||||
|
|
||||
|
def test_string_escapes(self): |
||||
|
for char in u'\0', u'\u2668', u'\xe4', u'\t', u'\r', u'\n': |
||||
|
tmpl = env.from_string('{{ %s }}' % jinja_string_repr(char)) |
||||
|
assert tmpl.render() == char |
||||
|
assert env.from_string('{{ "\N{HOT SPRINGS}" }}').render() == u'\u2668' |
||||
|
|
||||
|
def test_bytefallback(self): |
||||
|
from pprint import pformat |
||||
|
tmpl = env.from_string(u'''{{ 'foo'|pprint }}|{{ 'bär'|pprint }}''') |
||||
|
assert tmpl.render() == pformat('foo') + '|' + pformat(u'bär') |
||||
|
|
||||
|
def test_operators(self): |
||||
|
from jinja2.lexer import operators |
||||
|
for test, expect in operators.iteritems(): |
||||
|
if test in '([{}])': |
||||
|
continue |
||||
|
stream = env.lexer.tokenize('{{ %s }}' % test) |
||||
|
stream.next() |
||||
|
assert stream.current.type == expect |
||||
|
|
||||
|
def test_normalizing(self): |
||||
|
for seq in '\r', '\r\n', '\n': |
||||
|
env = Environment(newline_sequence=seq) |
||||
|
tmpl = env.from_string('1\n2\r\n3\n4\n') |
||||
|
result = tmpl.render() |
||||
|
assert result.replace(seq, 'X') == '1X2X3X4' |
||||
|
|
||||
|
|
||||
|
class ParserTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_php_syntax(self): |
||||
|
env = Environment('<?', '?>', '<?=', '?>', '<!--', '-->') |
||||
|
tmpl = env.from_string('''\ |
||||
|
<!-- I'm a comment, I'm not interesting -->\ |
||||
|
<? for item in seq -?> |
||||
|
<?= item ?> |
||||
|
<?- endfor ?>''') |
||||
|
assert tmpl.render(seq=range(5)) == '01234' |
||||
|
|
||||
|
def test_erb_syntax(self): |
||||
|
env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>') |
||||
|
tmpl = env.from_string('''\ |
||||
|
<%# I'm a comment, I'm not interesting %>\ |
||||
|
<% for item in seq -%> |
||||
|
<%= item %> |
||||
|
<%- endfor %>''') |
||||
|
assert tmpl.render(seq=range(5)) == '01234' |
||||
|
|
||||
|
def test_comment_syntax(self): |
||||
|
env = Environment('<!--', '-->', '${', '}', '<!--#', '-->') |
||||
|
tmpl = env.from_string('''\ |
||||
|
<!--# I'm a comment, I'm not interesting -->\ |
||||
|
<!-- for item in seq ---> |
||||
|
${item} |
||||
|
<!--- endfor -->''') |
||||
|
assert tmpl.render(seq=range(5)) == '01234' |
||||
|
|
||||
|
def test_balancing(self): |
||||
|
tmpl = env.from_string('''{{{'foo':'bar'}.foo}}''') |
||||
|
assert tmpl.render() == 'bar' |
||||
|
|
||||
|
def test_start_comment(self): |
||||
|
tmpl = env.from_string('''{# foo comment |
||||
|
and bar comment #} |
||||
|
{% macro blub() %}foo{% endmacro %} |
||||
|
{{ blub() }}''') |
||||
|
assert tmpl.render().strip() == 'foo' |
||||
|
|
||||
|
def test_line_syntax(self): |
||||
|
env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%') |
||||
|
tmpl = env.from_string('''\ |
||||
|
<%# regular comment %> |
||||
|
% for item in seq: |
||||
|
${item} |
||||
|
% endfor''') |
||||
|
assert [int(x.strip()) for x in tmpl.render(seq=range(5)).split()] == \ |
||||
|
range(5) |
||||
|
|
||||
|
env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##') |
||||
|
tmpl = env.from_string('''\ |
||||
|
<%# regular comment %> |
||||
|
% for item in seq: |
||||
|
${item} ## the rest of the stuff |
||||
|
% endfor''') |
||||
|
assert [int(x.strip()) for x in tmpl.render(seq=range(5)).split()] == \ |
||||
|
range(5) |
||||
|
|
||||
|
def test_line_syntax_priority(self): |
||||
|
# XXX: why is the whitespace there in front of the newline? |
||||
|
env = Environment('{%', '%}', '${', '}', '/*', '*/', '##', '#') |
||||
|
tmpl = env.from_string('''\ |
||||
|
/* ignore me. |
||||
|
I'm a multiline comment */ |
||||
|
## for item in seq: |
||||
|
* ${item} # this is just extra stuff |
||||
|
## endfor''') |
||||
|
assert tmpl.render(seq=[1, 2]).strip() == '* 1\n* 2' |
||||
|
env = Environment('{%', '%}', '${', '}', '/*', '*/', '#', '##') |
||||
|
tmpl = env.from_string('''\ |
||||
|
/* ignore me. |
||||
|
I'm a multiline comment */ |
||||
|
# for item in seq: |
||||
|
* ${item} ## this is just extra stuff |
||||
|
## extra stuff i just want to ignore |
||||
|
# endfor''') |
||||
|
assert tmpl.render(seq=[1, 2]).strip() == '* 1\n\n* 2' |
||||
|
|
||||
|
def test_error_messages(self): |
||||
|
def assert_error(code, expected): |
||||
|
try: |
||||
|
Template(code) |
||||
|
except TemplateSyntaxError, e: |
||||
|
assert str(e) == expected, 'unexpected error message' |
||||
|
else: |
||||
|
assert False, 'that was supposed to be an error' |
||||
|
|
||||
|
assert_error('{% for item in seq %}...{% endif %}', |
||||
|
"Encountered unknown tag 'endif'. Jinja was looking " |
||||
|
"for the following tags: 'endfor' or 'else'. The " |
||||
|
"innermost block that needs to be closed is 'for'.") |
||||
|
assert_error('{% if foo %}{% for item in seq %}...{% endfor %}{% endfor %}', |
||||
|
"Encountered unknown tag 'endfor'. Jinja was looking for " |
||||
|
"the following tags: 'elif' or 'else' or 'endif'. The " |
||||
|
"innermost block that needs to be closed is 'if'.") |
||||
|
assert_error('{% if foo %}', |
||||
|
"Unexpected end of template. Jinja was looking for the " |
||||
|
"following tags: 'elif' or 'else' or 'endif'. The " |
||||
|
"innermost block that needs to be closed is 'if'.") |
||||
|
assert_error('{% for item in seq %}', |
||||
|
"Unexpected end of template. Jinja was looking for the " |
||||
|
"following tags: 'endfor' or 'else'. The innermost block " |
||||
|
"that needs to be closed is 'for'.") |
||||
|
assert_error('{% block foo-bar-baz %}', |
||||
|
"Block names in Jinja have to be valid Python identifiers " |
||||
|
"and may not contain hyphens, use an underscore instead.") |
||||
|
assert_error('{% unknown_tag %}', |
||||
|
"Encountered unknown tag 'unknown_tag'.") |
||||
|
|
||||
|
|
||||
|
class SyntaxTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_call(self): |
||||
|
env = Environment() |
||||
|
env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g |
||||
|
tmpl = env.from_string("{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}") |
||||
|
assert tmpl.render() == 'abdfh' |
||||
|
|
||||
|
def test_slicing(self): |
||||
|
tmpl = env.from_string('{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}') |
||||
|
assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]' |
||||
|
|
||||
|
def test_attr(self): |
||||
|
tmpl = env.from_string("{{ foo.bar }}|{{ foo['bar'] }}") |
||||
|
assert tmpl.render(foo={'bar': 42}) == '42|42' |
||||
|
|
||||
|
def test_subscript(self): |
||||
|
tmpl = env.from_string("{{ foo[0] }}|{{ foo[-1] }}") |
||||
|
assert tmpl.render(foo=[0, 1, 2]) == '0|2' |
||||
|
|
||||
|
def test_tuple(self): |
||||
|
tmpl = env.from_string('{{ () }}|{{ (1,) }}|{{ (1, 2) }}') |
||||
|
assert tmpl.render() == '()|(1,)|(1, 2)' |
||||
|
|
||||
|
def test_math(self): |
||||
|
tmpl = env.from_string('{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}') |
||||
|
assert tmpl.render() == '1.5|8' |
||||
|
|
||||
|
def test_div(self): |
||||
|
tmpl = env.from_string('{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}') |
||||
|
assert tmpl.render() == '1|1.5|1' |
||||
|
|
||||
|
def test_unary(self): |
||||
|
tmpl = env.from_string('{{ +3 }}|{{ -3 }}') |
||||
|
assert tmpl.render() == '3|-3' |
||||
|
|
||||
|
def test_concat(self): |
||||
|
tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}") |
||||
|
assert tmpl.render() == '[1, 2]foo' |
||||
|
|
||||
|
def test_compare(self): |
||||
|
tmpl = env.from_string('{{ 1 > 0 }}|{{ 1 >= 1 }}|{{ 2 < 3 }}|' |
||||
|
'{{ 2 == 2 }}|{{ 1 <= 1 }}') |
||||
|
assert tmpl.render() == 'True|True|True|True|True' |
||||
|
|
||||
|
def test_inop(self): |
||||
|
tmpl = env.from_string('{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}') |
||||
|
assert tmpl.render() == 'True|False' |
||||
|
|
||||
|
def test_literals(self): |
||||
|
tmpl = env.from_string('{{ [] }}|{{ {} }}|{{ () }}') |
||||
|
assert tmpl.render().lower() == '[]|{}|()' |
||||
|
|
||||
|
def test_bool(self): |
||||
|
tmpl = env.from_string('{{ true and false }}|{{ false ' |
||||
|
'or true }}|{{ not false }}') |
||||
|
assert tmpl.render() == 'False|True|True' |
||||
|
|
||||
|
def test_grouping(self): |
||||
|
tmpl = env.from_string('{{ (true and false) or (false and true) and not false }}') |
||||
|
assert tmpl.render() == 'False' |
||||
|
|
||||
|
def test_django_attr(self): |
||||
|
tmpl = env.from_string('{{ [1, 2, 3].0 }}|{{ [[1]].0.0 }}') |
||||
|
assert tmpl.render() == '1|1' |
||||
|
|
||||
|
def test_conditional_expression(self): |
||||
|
tmpl = env.from_string('''{{ 0 if true else 1 }}''') |
||||
|
assert tmpl.render() == '0' |
||||
|
|
||||
|
def test_short_conditional_expression(self): |
||||
|
tmpl = env.from_string('<{{ 1 if false }}>') |
||||
|
assert tmpl.render() == '<>' |
||||
|
|
||||
|
tmpl = env.from_string('<{{ (1 if false).bar }}>') |
||||
|
self.assert_raises(UndefinedError, tmpl.render) |
||||
|
|
||||
|
def test_filter_priority(self): |
||||
|
tmpl = env.from_string('{{ "foo"|upper + "bar"|upper }}') |
||||
|
assert tmpl.render() == 'FOOBAR' |
||||
|
|
||||
|
def test_function_calls(self): |
||||
|
tests = [ |
||||
|
(True, '*foo, bar'), |
||||
|
(True, '*foo, *bar'), |
||||
|
(True, '*foo, bar=42'), |
||||
|
(True, '**foo, *bar'), |
||||
|
(True, '**foo, bar'), |
||||
|
(False, 'foo, bar'), |
||||
|
(False, 'foo, bar=42'), |
||||
|
(False, 'foo, bar=23, *args'), |
||||
|
(False, 'a, b=c, *d, **e'), |
||||
|
(False, '*foo, **bar') |
||||
|
] |
||||
|
for should_fail, sig in tests: |
||||
|
if should_fail: |
||||
|
self.assert_raises(TemplateSyntaxError, |
||||
|
env.from_string, '{{ foo(%s) }}' % sig) |
||||
|
else: |
||||
|
env.from_string('foo(%s)' % sig) |
||||
|
|
||||
|
def test_tuple_expr(self): |
||||
|
for tmpl in [ |
||||
|
'{{ () }}', |
||||
|
'{{ (1, 2) }}', |
||||
|
'{{ (1, 2,) }}', |
||||
|
'{{ 1, }}', |
||||
|
'{{ 1, 2 }}', |
||||
|
'{% for foo, bar in seq %}...{% endfor %}', |
||||
|
'{% for x in foo, bar %}...{% endfor %}', |
||||
|
'{% for x in foo, %}...{% endfor %}' |
||||
|
]: |
||||
|
assert env.from_string(tmpl) |
||||
|
|
||||
|
def test_trailing_comma(self): |
||||
|
tmpl = env.from_string('{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}') |
||||
|
assert tmpl.render().lower() == '(1, 2)|[1, 2]|{1: 2}' |
||||
|
|
||||
|
def test_block_end_name(self): |
||||
|
env.from_string('{% block foo %}...{% endblock foo %}') |
||||
|
self.assert_raises(TemplateSyntaxError, env.from_string, |
||||
|
'{% block x %}{% endblock y %}') |
||||
|
|
||||
|
def test_constant_casing(self): |
||||
|
for const in True, False, None: |
||||
|
tmpl = env.from_string('{{ %s }}|{{ %s }}|{{ %s }}' % ( |
||||
|
str(const), str(const).lower(), str(const).upper() |
||||
|
)) |
||||
|
assert tmpl.render() == '%s|%s|' % (const, const) |
||||
|
|
||||
|
def test_test_chaining(self): |
||||
|
self.assert_raises(TemplateSyntaxError, env.from_string, |
||||
|
'{{ foo is string is sequence }}') |
||||
|
assert env.from_string('{{ 42 is string or 42 is number }}' |
||||
|
).render() == 'True' |
||||
|
|
||||
|
def test_string_concatenation(self): |
||||
|
tmpl = env.from_string('{{ "foo" "bar" "baz" }}') |
||||
|
assert tmpl.render() == 'foobarbaz' |
||||
|
|
||||
|
def test_notin(self): |
||||
|
bar = xrange(100) |
||||
|
tmpl = env.from_string('''{{ not 42 in bar }}''') |
||||
|
assert tmpl.render(bar=bar) == unicode(not 42 in bar) |
||||
|
|
||||
|
def test_implicit_subscribed_tuple(self): |
||||
|
class Foo(object): |
||||
|
def __getitem__(self, x): |
||||
|
return x |
||||
|
t = env.from_string('{{ foo[1, 2] }}') |
||||
|
assert t.render(foo=Foo()) == u'(1, 2)' |
||||
|
|
||||
|
def test_raw2(self): |
||||
|
tmpl = env.from_string('{% raw %}{{ FOO }} and {% BAR %}{% endraw %}') |
||||
|
assert tmpl.render() == '{{ FOO }} and {% BAR %}' |
||||
|
|
||||
|
def test_const(self): |
||||
|
tmpl = env.from_string('{{ true }}|{{ false }}|{{ none }}|' |
||||
|
'{{ none is defined }}|{{ missing is defined }}') |
||||
|
assert tmpl.render() == 'True|False|None|True|False' |
||||
|
|
||||
|
def test_neg_filter_priority(self): |
||||
|
node = env.parse('{{ -1|foo }}') |
||||
|
assert isinstance(node.body[0].nodes[0], nodes.Filter) |
||||
|
assert isinstance(node.body[0].nodes[0].node, nodes.Neg) |
||||
|
|
||||
|
def test_const_assign(self): |
||||
|
constass1 = '''{% set true = 42 %}''' |
||||
|
constass2 = '''{% for none in seq %}{% endfor %}''' |
||||
|
for tmpl in constass1, constass2: |
||||
|
self.assert_raises(TemplateSyntaxError, env.from_string, tmpl) |
||||
|
|
||||
|
def test_localset(self): |
||||
|
tmpl = env.from_string('''{% set foo = 0 %}\ |
||||
|
{% for item in [1, 2] %}{% set foo = 1 %}{% endfor %}\ |
||||
|
{{ foo }}''') |
||||
|
assert tmpl.render() == '0' |
||||
|
|
||||
|
def test_parse_unary(self): |
||||
|
tmpl = env.from_string('{{ -foo["bar"] }}') |
||||
|
assert tmpl.render(foo={'bar': 42}) == '-42' |
||||
|
tmpl = env.from_string('{{ -foo["bar"]|abs }}') |
||||
|
assert tmpl.render(foo={'bar': 42}) == '42' |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(unittest.makeSuite(LexerTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(ParserTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(SyntaxTestCase)) |
||||
|
return suite |
@ -0,0 +1,218 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.loader |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Test the loaders. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import os |
||||
|
import sys |
||||
|
import tempfile |
||||
|
import shutil |
||||
|
import unittest |
||||
|
|
||||
|
from jinja2.testsuite import JinjaTestCase, dict_loader, \ |
||||
|
package_loader, filesystem_loader, function_loader, \ |
||||
|
choice_loader, prefix_loader |
||||
|
|
||||
|
from jinja2 import Environment, loaders |
||||
|
from jinja2.loaders import split_template_path |
||||
|
from jinja2.exceptions import TemplateNotFound |
||||
|
|
||||
|
|
||||
|
class LoaderTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_dict_loader(self): |
||||
|
env = Environment(loader=dict_loader) |
||||
|
tmpl = env.get_template('justdict.html') |
||||
|
assert tmpl.render().strip() == 'FOO' |
||||
|
self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') |
||||
|
|
||||
|
def test_package_loader(self): |
||||
|
env = Environment(loader=package_loader) |
||||
|
tmpl = env.get_template('test.html') |
||||
|
assert tmpl.render().strip() == 'BAR' |
||||
|
self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') |
||||
|
|
||||
|
def test_filesystem_loader(self): |
||||
|
env = Environment(loader=filesystem_loader) |
||||
|
tmpl = env.get_template('test.html') |
||||
|
assert tmpl.render().strip() == 'BAR' |
||||
|
tmpl = env.get_template('foo/test.html') |
||||
|
assert tmpl.render().strip() == 'FOO' |
||||
|
self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') |
||||
|
|
||||
|
def test_choice_loader(self): |
||||
|
env = Environment(loader=choice_loader) |
||||
|
tmpl = env.get_template('justdict.html') |
||||
|
assert tmpl.render().strip() == 'FOO' |
||||
|
tmpl = env.get_template('test.html') |
||||
|
assert tmpl.render().strip() == 'BAR' |
||||
|
self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') |
||||
|
|
||||
|
def test_function_loader(self): |
||||
|
env = Environment(loader=function_loader) |
||||
|
tmpl = env.get_template('justfunction.html') |
||||
|
assert tmpl.render().strip() == 'FOO' |
||||
|
self.assert_raises(TemplateNotFound, env.get_template, 'missing.html') |
||||
|
|
||||
|
def test_prefix_loader(self): |
||||
|
env = Environment(loader=prefix_loader) |
||||
|
tmpl = env.get_template('a/test.html') |
||||
|
assert tmpl.render().strip() == 'BAR' |
||||
|
tmpl = env.get_template('b/justdict.html') |
||||
|
assert tmpl.render().strip() == 'FOO' |
||||
|
self.assert_raises(TemplateNotFound, env.get_template, 'missing') |
||||
|
|
||||
|
def test_caching(self): |
||||
|
changed = False |
||||
|
class TestLoader(loaders.BaseLoader): |
||||
|
def get_source(self, environment, template): |
||||
|
return u'foo', None, lambda: not changed |
||||
|
env = Environment(loader=TestLoader(), cache_size=-1) |
||||
|
tmpl = env.get_template('template') |
||||
|
assert tmpl is env.get_template('template') |
||||
|
changed = True |
||||
|
assert tmpl is not env.get_template('template') |
||||
|
changed = False |
||||
|
|
||||
|
env = Environment(loader=TestLoader(), cache_size=0) |
||||
|
assert env.get_template('template') \ |
||||
|
is not env.get_template('template') |
||||
|
|
||||
|
env = Environment(loader=TestLoader(), cache_size=2) |
||||
|
t1 = env.get_template('one') |
||||
|
t2 = env.get_template('two') |
||||
|
assert t2 is env.get_template('two') |
||||
|
assert t1 is env.get_template('one') |
||||
|
t3 = env.get_template('three') |
||||
|
assert 'one' in env.cache |
||||
|
assert 'two' not in env.cache |
||||
|
assert 'three' in env.cache |
||||
|
|
||||
|
def test_split_template_path(self): |
||||
|
assert split_template_path('foo/bar') == ['foo', 'bar'] |
||||
|
assert split_template_path('./foo/bar') == ['foo', 'bar'] |
||||
|
self.assert_raises(TemplateNotFound, split_template_path, '../foo') |
||||
|
|
||||
|
|
||||
|
class ModuleLoaderTestCase(JinjaTestCase): |
||||
|
archive = None |
||||
|
|
||||
|
def compile_down(self, zip='deflated', py_compile=False): |
||||
|
super(ModuleLoaderTestCase, self).setup() |
||||
|
log = [] |
||||
|
self.reg_env = Environment(loader=prefix_loader) |
||||
|
if zip is not None: |
||||
|
self.archive = tempfile.mkstemp(suffix='.zip')[1] |
||||
|
else: |
||||
|
self.archive = tempfile.mkdtemp() |
||||
|
self.reg_env.compile_templates(self.archive, zip=zip, |
||||
|
log_function=log.append, |
||||
|
py_compile=py_compile) |
||||
|
self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive)) |
||||
|
return ''.join(log) |
||||
|
|
||||
|
def teardown(self): |
||||
|
super(ModuleLoaderTestCase, self).teardown() |
||||
|
if hasattr(self, 'mod_env'): |
||||
|
if os.path.isfile(self.archive): |
||||
|
os.remove(self.archive) |
||||
|
else: |
||||
|
shutil.rmtree(self.archive) |
||||
|
self.archive = None |
||||
|
|
||||
|
def test_log(self): |
||||
|
log = self.compile_down() |
||||
|
assert 'Compiled "a/foo/test.html" as ' \ |
||||
|
'tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a' in log |
||||
|
assert 'Finished compiling templates' in log |
||||
|
assert 'Could not compile "a/syntaxerror.html": ' \ |
||||
|
'Encountered unknown tag \'endif\'' in log |
||||
|
|
||||
|
def _test_common(self): |
||||
|
tmpl1 = self.reg_env.get_template('a/test.html') |
||||
|
tmpl2 = self.mod_env.get_template('a/test.html') |
||||
|
assert tmpl1.render() == tmpl2.render() |
||||
|
|
||||
|
tmpl1 = self.reg_env.get_template('b/justdict.html') |
||||
|
tmpl2 = self.mod_env.get_template('b/justdict.html') |
||||
|
assert tmpl1.render() == tmpl2.render() |
||||
|
|
||||
|
def test_deflated_zip_compile(self): |
||||
|
self.compile_down(zip='deflated') |
||||
|
self._test_common() |
||||
|
|
||||
|
def test_stored_zip_compile(self): |
||||
|
self.compile_down(zip='stored') |
||||
|
self._test_common() |
||||
|
|
||||
|
def test_filesystem_compile(self): |
||||
|
self.compile_down(zip=None) |
||||
|
self._test_common() |
||||
|
|
||||
|
def test_weak_references(self): |
||||
|
self.compile_down() |
||||
|
tmpl = self.mod_env.get_template('a/test.html') |
||||
|
key = loaders.ModuleLoader.get_template_key('a/test.html') |
||||
|
name = self.mod_env.loader.module.__name__ |
||||
|
|
||||
|
assert hasattr(self.mod_env.loader.module, key) |
||||
|
assert name in sys.modules |
||||
|
|
||||
|
# unset all, ensure the module is gone from sys.modules |
||||
|
self.mod_env = tmpl = None |
||||
|
|
||||
|
try: |
||||
|
import gc |
||||
|
gc.collect() |
||||
|
except: |
||||
|
pass |
||||
|
|
||||
|
assert name not in sys.modules |
||||
|
|
||||
|
def test_byte_compilation(self): |
||||
|
log = self.compile_down(py_compile=True) |
||||
|
assert 'Byte-compiled "a/test.html"' in log |
||||
|
tmpl1 = self.mod_env.get_template('a/test.html') |
||||
|
mod = self.mod_env.loader.module. \ |
||||
|
tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490 |
||||
|
assert mod.__file__.endswith('.pyc') |
||||
|
|
||||
|
def test_choice_loader(self): |
||||
|
log = self.compile_down(py_compile=True) |
||||
|
assert 'Byte-compiled "a/test.html"' in log |
||||
|
|
||||
|
self.mod_env.loader = loaders.ChoiceLoader([ |
||||
|
self.mod_env.loader, |
||||
|
loaders.DictLoader({'DICT_SOURCE': 'DICT_TEMPLATE'}) |
||||
|
]) |
||||
|
|
||||
|
tmpl1 = self.mod_env.get_template('a/test.html') |
||||
|
self.assert_equal(tmpl1.render(), 'BAR') |
||||
|
tmpl2 = self.mod_env.get_template('DICT_SOURCE') |
||||
|
self.assert_equal(tmpl2.render(), 'DICT_TEMPLATE') |
||||
|
|
||||
|
def test_prefix_loader(self): |
||||
|
log = self.compile_down(py_compile=True) |
||||
|
assert 'Byte-compiled "a/test.html"' in log |
||||
|
|
||||
|
self.mod_env.loader = loaders.PrefixLoader({ |
||||
|
'MOD': self.mod_env.loader, |
||||
|
'DICT': loaders.DictLoader({'test.html': 'DICT_TEMPLATE'}) |
||||
|
}) |
||||
|
|
||||
|
tmpl1 = self.mod_env.get_template('MOD/a/test.html') |
||||
|
self.assert_equal(tmpl1.render(), 'BAR') |
||||
|
tmpl2 = self.mod_env.get_template('DICT/test.html') |
||||
|
self.assert_equal(tmpl2.render(), 'DICT_TEMPLATE') |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(unittest.makeSuite(LoaderTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(ModuleLoaderTestCase)) |
||||
|
return suite |
@ -0,0 +1,255 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
""" |
||||
|
jinja2.testsuite.regression |
||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||||
|
|
||||
|
Tests corner cases and bugs. |
||||
|
|
||||
|
:copyright: (c) 2010 by the Jinja Team. |
||||
|
:license: BSD, see LICENSE for more details. |
||||
|
""" |
||||
|
import unittest |
||||
|
|
||||
|
from jinja2.testsuite import JinjaTestCase |
||||
|
|
||||
|
from jinja2 import Template, Environment, DictLoader, TemplateSyntaxError, \ |
||||
|
TemplateNotFound, PrefixLoader |
||||
|
|
||||
|
env = Environment() |
||||
|
|
||||
|
|
||||
|
class CornerTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_assigned_scoping(self): |
||||
|
t = env.from_string(''' |
||||
|
{%- for item in (1, 2, 3, 4) -%} |
||||
|
[{{ item }}] |
||||
|
{%- endfor %} |
||||
|
{{- item -}} |
||||
|
''') |
||||
|
assert t.render(item=42) == '[1][2][3][4]42' |
||||
|
|
||||
|
t = env.from_string(''' |
||||
|
{%- for item in (1, 2, 3, 4) -%} |
||||
|
[{{ item }}] |
||||
|
{%- endfor %} |
||||
|
{%- set item = 42 %} |
||||
|
{{- item -}} |
||||
|
''') |
||||
|
assert t.render() == '[1][2][3][4]42' |
||||
|
|
||||
|
t = env.from_string(''' |
||||
|
{%- set item = 42 %} |
||||
|
{%- for item in (1, 2, 3, 4) -%} |
||||
|
[{{ item }}] |
||||
|
{%- endfor %} |
||||
|
{{- item -}} |
||||
|
''') |
||||
|
assert t.render() == '[1][2][3][4]42' |
||||
|
|
||||
|
def test_closure_scoping(self): |
||||
|
t = env.from_string(''' |
||||
|
{%- set wrapper = "<FOO>" %} |
||||
|
{%- for item in (1, 2, 3, 4) %} |
||||
|
{%- macro wrapper() %}[{{ item }}]{% endmacro %} |
||||
|
{{- wrapper() }} |
||||
|
{%- endfor %} |
||||
|
{{- wrapper -}} |
||||
|
''') |
||||
|
assert t.render() == '[1][2][3][4]<FOO>' |
||||
|
|
||||
|
t = env.from_string(''' |
||||
|
{%- for item in (1, 2, 3, 4) %} |
||||
|
{%- macro wrapper() %}[{{ item }}]{% endmacro %} |
||||
|
{{- wrapper() }} |
||||
|
{%- endfor %} |
||||
|
{%- set wrapper = "<FOO>" %} |
||||
|
{{- wrapper -}} |
||||
|
''') |
||||
|
assert t.render() == '[1][2][3][4]<FOO>' |
||||
|
|
||||
|
t = env.from_string(''' |
||||
|
{%- for item in (1, 2, 3, 4) %} |
||||
|
{%- macro wrapper() %}[{{ item }}]{% endmacro %} |
||||
|
{{- wrapper() }} |
||||
|
{%- endfor %} |
||||
|
{{- wrapper -}} |
||||
|
''') |
||||
|
assert t.render(wrapper=23) == '[1][2][3][4]23' |
||||
|
|
||||
|
|
||||
|
class BugTestCase(JinjaTestCase): |
||||
|
|
||||
|
def test_keyword_folding(self): |
||||
|
env = Environment() |
||||
|
env.filters['testing'] = lambda value, some: value + some |
||||
|
assert env.from_string("{{ 'test'|testing(some='stuff') }}") \ |
||||
|
.render() == 'teststuff' |
||||
|
|
||||
|
def test_extends_output_bugs(self): |
||||
|
env = Environment(loader=DictLoader({ |
||||
|
'parent.html': '(({% block title %}{% endblock %}))' |
||||
|
})) |
||||
|
|
||||
|
t = env.from_string('{% if expr %}{% extends "parent.html" %}{% endif %}' |
||||
|
'[[{% block title %}title{% endblock %}]]' |
||||
|
'{% for item in [1, 2, 3] %}({{ item }}){% endfor %}') |
||||
|
assert t.render(expr=False) == '[[title]](1)(2)(3)' |
||||
|
assert t.render(expr=True) == '((title))' |
||||
|
|
||||
|
def test_urlize_filter_escaping(self): |
||||
|
tmpl = env.from_string('{{ "http://www.example.org/<foo"|urlize }}') |
||||
|
assert tmpl.render() == '<a href="http://www.example.org/<foo">http://www.example.org/<foo</a>' |
||||
|
|
||||
|
def test_loop_call_loop(self): |
||||
|
tmpl = env.from_string(''' |
||||
|
|
||||
|
{% macro test() %} |
||||
|
{{ caller() }} |
||||
|
{% endmacro %} |
||||
|
|
||||
|
{% for num1 in range(5) %} |
||||
|
{% call test() %} |
||||
|
{% for num2 in range(10) %} |
||||
|
{{ loop.index }} |
||||
|
{% endfor %} |
||||
|
{% endcall %} |
||||
|
{% endfor %} |
||||
|
|
||||
|
''') |
||||
|
|
||||
|
assert tmpl.render().split() == map(unicode, range(1, 11)) * 5 |
||||
|
|
||||
|
def test_weird_inline_comment(self): |
||||
|
env = Environment(line_statement_prefix='%') |
||||
|
self.assert_raises(TemplateSyntaxError, env.from_string, |
||||
|
'% for item in seq {# missing #}\n...% endfor') |
||||
|
|
||||
|
def test_old_macro_loop_scoping_bug(self): |
||||
|
tmpl = env.from_string('{% for i in (1, 2) %}{{ i }}{% endfor %}' |
||||
|
'{% macro i() %}3{% endmacro %}{{ i() }}') |
||||
|
assert tmpl.render() == '123' |
||||
|
|
||||
|
def test_partial_conditional_assignments(self): |
||||
|
tmpl = env.from_string('{% if b %}{% set a = 42 %}{% endif %}{{ a }}') |
||||
|
assert tmpl.render(a=23) == '23' |
||||
|
assert tmpl.render(b=True) == '42' |
||||
|
|
||||
|
def test_stacked_locals_scoping_bug(self): |
||||
|
env = Environment(line_statement_prefix='#') |
||||
|
t = env.from_string('''\ |
||||
|
# for j in [1, 2]: |
||||
|
# set x = 1 |
||||
|
# for i in [1, 2]: |
||||
|
# print x |
||||
|
# if i % 2 == 0: |
||||
|
# set x = x + 1 |
||||
|
# endif |
||||
|
# endfor |
||||
|
# endfor |
||||
|
# if a |
||||
|
# print 'A' |
||||
|
# elif b |
||||
|
# print 'B' |
||||
|
# elif c == d |
||||
|
# print 'C' |
||||
|
# else |
||||
|
# print 'D' |
||||
|
# endif |
||||
|
''') |
||||
|
assert t.render(a=0, b=False, c=42, d=42.0) == '1111C' |
||||
|
|
||||
|
def test_stacked_locals_scoping_bug_twoframe(self): |
||||
|
t = Template(''' |
||||
|
{% set x = 1 %} |
||||
|
{% for item in foo %} |
||||
|
{% if item == 1 %} |
||||
|
{% set x = 2 %} |
||||
|
{% endif %} |
||||
|
{% endfor %} |
||||
|
{{ x }} |
||||
|
''') |
||||
|
rv = t.render(foo=[1]).strip() |
||||
|
assert rv == u'1' |
||||
|
|
||||
|
def test_call_with_args(self): |
||||
|
t = Template("""{% macro dump_users(users) -%} |
||||
|
<ul> |
||||
|
{%- for user in users -%} |
||||
|
<li><p>{{ user.username|e }}</p>{{ caller(user) }}</li> |
||||
|
{%- endfor -%} |
||||
|
</ul> |
||||
|
{%- endmacro -%} |
||||
|
|
||||
|
{% call(user) dump_users(list_of_user) -%} |
||||
|
<dl> |
||||
|
<dl>Realname</dl> |
||||
|
<dd>{{ user.realname|e }}</dd> |
||||
|
<dl>Description</dl> |
||||
|
<dd>{{ user.description }}</dd> |
||||
|
</dl> |
||||
|
{% endcall %}""") |
||||
|
|
||||
|
assert [x.strip() for x in t.render(list_of_user=[{ |
||||
|
'username':'apo', |
||||
|
'realname':'something else', |
||||
|
'description':'test' |
||||
|
}]).splitlines()] == [ |
||||
|
u'<ul><li><p>apo</p><dl>', |
||||
|
u'<dl>Realname</dl>', |
||||
|
u'<dd>something else</dd>', |
||||
|
u'<dl>Description</dl>', |
||||
|
u'<dd>test</dd>', |
||||
|
u'</dl>', |
||||
|
u'</li></ul>' |
||||
|
] |
||||
|
|
||||
|
def test_empty_if_condition_fails(self): |
||||
|
self.assert_raises(TemplateSyntaxError, Template, '{% if %}....{% endif %}') |
||||
|
self.assert_raises(TemplateSyntaxError, Template, '{% if foo %}...{% elif %}...{% endif %}') |
||||
|
self.assert_raises(TemplateSyntaxError, Template, '{% for x in %}..{% endfor %}') |
||||
|
|
||||
|
def test_recursive_loop_bug(self): |
||||
|
tpl1 = Template(""" |
||||
|
{% for p in foo recursive%} |
||||
|
{{p.bar}} |
||||
|
{% for f in p.fields recursive%} |
||||
|
{{f.baz}} |
||||
|
{{p.bar}} |
||||
|
{% if f.rec %} |
||||
|
{{ loop(f.sub) }} |
||||
|
{% endif %} |
||||
|
{% endfor %} |
||||
|
{% endfor %} |
||||
|
""") |
||||
|
|
||||
|
tpl2 = Template(""" |
||||
|
{% for p in foo%} |
||||
|
{{p.bar}} |
||||
|
{% for f in p.fields recursive%} |
||||
|
{{f.baz}} |
||||
|
{{p.bar}} |
||||
|
{% if f.rec %} |
||||
|
{{ loop(f.sub) }} |
||||
|
{% endif %} |
||||
|
{% endfor %} |
||||
|
{% endfor %} |
||||
|
""") |
||||
|
|
||||
|
def test_correct_prefix_loader_name(self): |
||||
|
env = Environment(loader=PrefixLoader({ |
||||
|
'foo': DictLoader({}) |
||||
|
})) |
||||
|
try: |
||||
|
env.get_template('foo/bar.html') |
||||
|
except TemplateNotFound, e: |
||||
|
assert e.name == 'foo/bar.html' |
||||
|
else: |
||||
|
assert False, 'expected error here' |
||||
|
|
||||
|
|
||||
|
def suite(): |
||||
|
suite = unittest.TestSuite() |
||||
|
suite.addTest(unittest.makeSuite(CornerTestCase)) |
||||
|
suite.addTest(unittest.makeSuite(BugTestCase)) |
||||
|
return suite |
@ -0,0 +1,3 @@ |
|||||
|
Before |
||||
|
{{ fail() }} |
||||
|
After |
@ -0,0 +1 @@ |
|||||
|
FOO |
@ -0,0 +1,4 @@ |
|||||
|
Foo |
||||
|
{% for item in broken %} |
||||
|
... |
||||
|
{% endif %} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue