From 284b2c3326ac954713f4b9d5008cbfd83299912d Mon Sep 17 00:00:00 2001 From: Jacob Coffee Date: Tue, 17 Sep 2024 02:01:10 -0500 Subject: [PATCH 01/17] feat: restructure app --- .github/workflows/ci.yml | 4 +- .github/workflows/static.yml | 4 +- .gitignore | 2 +- .readthedocs.yaml | 2 +- Dockerfile | 8 +- Dockerfile.cabotage | 10 +- Makefile | 14 +- Procfile | 4 +- {banners => app}/__init__.py | 0 .../migrations => app/banners}/__init__.py | 0 {banners => app/banners}/admin.py | 2 +- {banners => app/banners}/apps.py | 2 +- .../banners}/migrations/0001_initial.py | 0 .../banners/migrations}/__init__.py | 0 {banners => app/banners}/models.py | 0 .../banners/templates}/banner.html | 0 .../banners/templatetags}/__init__.py | 0 .../banners}/templatetags/banners.py | 2 +- {bin => app/bin}/pre_compile | 0 {bin => app/bin}/start-nginx | 0 {blogs/management => app/blogs}/__init__.py | 0 {blogs => app/blogs}/admin.py | 2 +- {blogs => app/blogs}/apps.py | 2 +- {blogs => app/blogs}/factories.py | 2 +- .../blogs/management}/__init__.py | 0 .../blogs/management/commands}/__init__.py | 0 .../management/commands/update_blogs.py | 4 +- .../blogs}/migrations/0001_initial.py | 0 ...02_remove_translations_and_contributors.py | 0 ...0003_alter_relatedblog_creator_and_more.py | 0 .../blogs/migrations}/__init__.py | 0 {blogs => app/blogs}/models.py | 2 +- {blogs => app/blogs}/parser.py | 4 +- .../blogs => app/blogs/templates}/index.html | 0 .../blogs/templates}/supernav.html | 0 .../blogs/templatetags}/__init__.py | 0 {blogs => app/blogs}/templatetags/blogs.py | 2 +- {boxes => app/blogs/tests}/__init__.py | 0 .../blogs}/tests/psf_feed_example.xml | 1724 ++--- {blogs => app/blogs}/tests/test_models.py | 2 +- {blogs => app/blogs}/tests/test_parser.py | 4 +- .../blogs}/tests/test_templatetags.py | 6 +- {blogs => app/blogs}/tests/test_views.py | 4 +- {blogs => app/blogs}/tests/utils.py | 0 {blogs => app/blogs}/urls.py | 2 +- {blogs => app/blogs}/views.py | 4 +- {boxes/migrations => app/boxes}/__init__.py | 0 {boxes => app/boxes}/admin.py | 4 +- {boxes => app/boxes}/apps.py | 2 +- {boxes => app/boxes}/factories.py | 4 +- .../boxes}/migrations/0001_initial.py | 0 .../migrations/0002_auto_20150416_1853.py | 0 .../migrations/0003_auto_20171101_2138.py | 0 ..._box_creator_alter_box_last_modified_by.py | 0 {cms => app/boxes/migrations}/__init__.py | 0 {boxes => app/boxes}/models.py | 2 +- {boxes => app/boxes}/templatetags/boxes.py | 2 +- {boxes => app/boxes}/tests.py | 2 +- {boxes => app/boxes}/urls.py | 2 +- {boxes => app/boxes}/views.py | 2 +- {cms/management => app/cms}/__init__.py | 0 {cms => app/cms}/admin.py | 0 {cms => app/cms}/apps.py | 2 +- {cms => app/cms}/forms.py | 0 .../cms/management}/__init__.py | 0 .../cms/management/commands}/__init__.py | 0 .../commands/create_initial_data.py | 0 {cms => app/cms}/models.py | 0 .../cms/templates}/iso_time_tag.html | 0 .../cms/templatetags}/__init__.py | 0 {cms => app/cms}/templatetags/cms.py | 0 {cms => app/cms}/tests.py | 4 +- {cms => app/cms}/views.py | 0 .../codesamples}/__init__.py | 0 app/codesamples/admin.py | 7 + {codesamples => app/codesamples}/apps.py | 2 +- {codesamples => app/codesamples}/factories.py | 4 +- {codesamples => app/codesamples}/managers.py | 0 .../codesamples}/migrations/0001_initial.py | 0 .../migrations/0002_auto_20150416_1853.py | 0 .../migrations/0003_auto_20170821_2000.py | 0 .../0004_alter_codesample_creator_and_more.py | 0 .../codesamples/migrations}/__init__.py | 0 {codesamples => app/codesamples}/models.py | 4 +- {codesamples => app/codesamples}/tests.py | 2 +- .../migrations => app/community}/__init__.py | 0 {community => app/community}/admin.py | 4 +- {community => app/community}/apps.py | 2 +- {community => app/community}/managers.py | 0 .../community}/migrations/0001_initial.py | 0 .../0001_squashed_0004_auto_20170831_0541.py | 0 .../migrations/0002_auto_20150416_1853.py | 0 .../migrations/0003_auto_20170831_0358.py | 0 .../migrations/0004_auto_20170831_0541.py | 0 ...or_alter_link_last_modified_by_and_more.py | 0 .../community/migrations}/__init__.py | 0 {community => app/community}/models.py | 4 +- .../community/templates}/microbit.html | 0 .../community/templates}/post_detail.html | 0 .../community/templates}/post_list.html | 0 .../community/templates}/types/default.html | 0 .../community/templates}/types/link.html | 0 .../community/templates}/types/photo.html | 0 .../community/templates}/types/text.html | 0 .../community/templates}/types/video.html | 0 .../community/templatetags}/__init__.py | 0 .../community}/templatetags/community.py | 0 .../community/tests}/__init__.py | 0 .../community}/tests/test_managers.py | 2 +- .../community}/tests/test_models.py | 2 +- .../community}/tests/test_views.py | 4 +- {community => app/community}/urls.py | 2 +- {community => app/community}/views.py | 2 +- .../migrations => app/companies}/__init__.py | 0 {companies => app/companies}/admin.py | 4 +- {companies => app/companies}/apps.py | 2 +- {companies => app/companies}/factories.py | 2 +- .../companies}/migrations/0001_initial.py | 0 .../migrations/0002_auto_20150416_1853.py | 0 .../migrations/0003_auto_20170814_0301.py | 0 .../migrations/0004_auto_20170821_2000.py | 0 .../migrations/0005_auto_20180705_0352.py | 0 .../companies/migrations}/__init__.py | 0 {companies => app/companies}/models.py | 2 +- .../companies/templatetags}/__init__.py | 0 .../companies}/templatetags/companies.py | 0 {companies => app/companies}/tests.py | 4 +- {config => app/config}/mime.types | 0 {config => app/config}/nginx.conf | 0 .../custom_storages}/__init__.py | 0 .../custom_storages}/storages.py | 0 .../migrations => app/downloads}/__init__.py | 0 {downloads => app/downloads}/admin.py | 4 +- {downloads => app/downloads}/api.py | 10 +- {downloads => app/downloads}/apps.py | 2 +- {downloads => app/downloads}/factories.py | 4 +- {downloads => app/downloads}/managers.py | 0 .../downloads}/migrations/0001_initial.py | 0 .../migrations/0002_auto_20150416_1853.py | 0 .../migrations/0003_auto_20150824_1612.py | 0 .../migrations/0004_auto_20170821_2000.py | 0 .../0005_move_release_page_content.py | 0 .../migrations/0006_auto_20180705_0352.py | 0 .../migrations/0007_auto_20220809_1655.py | 0 .../migrations/0008_auto_20220907_2102.py | 0 .../0009_releasefile_sigstore_bundle_file.py | 0 .../0010_releasefile_sbom_spdx2_file.py | 0 ...ator_alter_os_last_modified_by_and_more.py | 0 .../downloads/migrations}/__init__.py | 0 {downloads => app/downloads}/models.py | 10 +- .../downloads}/search_indexes.py | 2 +- {downloads => app/downloads}/serializers.py | 2 +- .../downloads/templates}/base.html | 0 .../templates}/download-sources-box.html | 0 .../downloads/templates}/full_os_list.html | 0 .../templates}/homepage-downloads-box.html | 0 .../downloads/templates}/index.html | 0 .../downloads/templates}/os_list.html | 0 .../downloads/templates}/release_detail.html | 0 .../downloads/templates}/supernav.html | 0 .../downloads/templatetags}/__init__.py | 0 .../downloads}/templatetags/download_tags.py | 0 {events => app/downloads/tests}/__init__.py | 0 {downloads => app/downloads}/tests/base.py | 4 +- .../downloads}/tests/test_models.py | 4 +- .../downloads}/tests/test_views.py | 10 +- {downloads => app/downloads}/urls.py | 2 +- {downloads => app/downloads}/views.py | 10 +- {events/management => app/events}/__init__.py | 0 {events => app/events}/admin.py | 4 +- {events => app/events}/apps.py | 2 +- {events => app/events}/factories.py | 2 +- {events => app/events}/forms.py | 0 {events => app/events}/importer.py | 4 +- .../events/management}/__init__.py | 0 .../events/management/commands}/__init__.py | 0 .../commands/import_ics_calendars.py | 0 .../events}/migrations/0001_initial.py | 7 +- .../migrations/0002_auto_20150321_1247.py | 0 .../migrations/0003_auto_20150416_1853.py | 0 .../migrations/0004_auto_20170814_0519.py | 5 +- .../migrations/0005_auto_20170821_2000.py | 0 ...006_change_end_date_for_occurring_rules.py | 0 .../migrations/0007_auto_20180705_0352.py | 0 ...r_alter_alarm_last_modified_by_and_more.py | 0 .../events/migrations}/__init__.py | 0 {events => app/events}/models.py | 6 +- {events => app/events}/search_indexes.py | 2 +- .../events => app/events/templates}/base.html | 0 .../events/templates}/calendar_list.html | 0 .../events/templates}/email/new_event.txt | 0 .../events/templates}/event_detail.html | 0 .../events/templates}/event_form.html | 0 .../events/templates}/event_form_thanks.html | 0 .../events/templates}/event_list.html | 0 .../events/templates}/event_list_past.html | 0 .../events/templates}/eventcategory_list.html | 0 .../events/templates}/eventlocation_list.html | 0 .../events/templates}/includes/time_tag.html | 0 .../events/templatetags}/__init__.py | 0 {events => app/events}/templatetags/events.py | 2 +- {fastly => app/events/tests}/__init__.py | 0 {events => app/events}/tests/events.ics | 2308 +++---- {events => app/events}/tests/test_forms.py | 2 +- {events => app/events}/tests/test_importer.py | 0 {events => app/events}/tests/test_models.py | 4 +- {events => app/events}/tests/test_utils.py | 2 +- {events => app/events}/tests/test_views.py | 6 +- {events => app/events}/urls.py | 2 +- {events => app/events}/utils.py | 0 {events => app/events}/views.py | 12 +- {jobs => app/fastly}/__init__.py | 0 {fastly => app/fastly}/models.py | 0 {fastly => app/fastly}/utils.py | 0 {jobs/management => app/jobs}/__init__.py | 0 {jobs => app/jobs}/admin.py | 4 +- {jobs => app/jobs}/apps.py | 4 +- {jobs => app/jobs}/factories.py | 4 +- {jobs => app/jobs}/feeds.py | 2 +- {jobs => app/jobs}/forms.py | 4 +- {jobs => app/jobs}/listeners.py | 4 +- .../jobs/management}/__init__.py | 0 .../jobs/management/commands}/__init__.py | 0 .../jobs}/management/commands/expire_jobs.py | 2 +- .../commands/jobs_monthly_report.py | 3 +- {jobs => app/jobs}/managers.py | 0 {jobs => app/jobs}/migrations/0001_initial.py | 0 .../migrations/0002_auto_20150211_1634.py | 0 .../migrations/0003_auto_20150211_1738.py | 0 .../migrations/0004_auto_20150216_1544.py | 0 .../migrations/0005_job_other_job_type.py | 0 .../jobs}/migrations/0006_region_nullable.py | 0 .../migrations/0007_auto_20150227_2223.py | 0 .../migrations/0008_auto_20150316_1205.py | 0 .../migrations/0009_auto_20150317_1815.py | 0 .../migrations/0010_auto_20150416_1853.py | 0 .../jobs}/migrations/0011_jobreviewcomment.py | 0 .../migrations/0012_auto_20170809_1849.py | 0 .../migrations/0013_auto_20170810_1625.py | 0 .../migrations/0013_auto_20170810_1627.py | 0 {jobs => app/jobs}/migrations/0014_merge.py | 0 .../migrations/0015_auto_20170814_0301.py | 0 .../migrations/0016_auto_20170821_2000.py | 0 .../migrations/0017_auto_20180705_0348.py | 0 .../migrations/0018_auto_20180705_0352.py | 0 .../jobs}/migrations/0019_job_submitted_by.py | 0 .../migrations/0020_auto_20191101_1601.py | 0 ...tor_alter_job_last_modified_by_and_more.py | 0 ...pe_options_alter_job_job_types_and_more.py | 0 .../tests => app/jobs/migrations}/__init__.py | 0 {jobs => app/jobs}/models.py | 11 +- {jobs => app/jobs}/search_indexes.py | 2 +- {jobs => app/jobs}/signals.py | 0 .../jobs => app/jobs/templates}/base.html | 0 .../templates}/email/comment_was_posted.txt | 0 .../email/comment_was_posted_admin.txt | 0 .../templates}/email/job_was_approved.txt | 0 .../email/job_was_approved_subject.txt | 0 .../templates}/email/job_was_rejected.txt | 0 .../email/job_was_rejected_subject.txt | 0 .../templates}/email/job_was_submitted.txt | 0 .../email/job_was_submitted_subject.txt | 0 .../templates}/email/monthly_jobs_report.txt | 0 .../email/monthly_jobs_report_subject.txt | 0 .../templates}/featured_companies-widget.html | 0 .../jobs/templates}/header_content.html | 0 .../jobs/templates}/job_categories.html | 0 .../jobs/templates}/job_category_list.html | 0 .../jobs/templates}/job_detail.html | 0 .../jobs => app/jobs/templates}/job_form.html | 0 .../jobs => app/jobs/templates}/job_list.html | 0 .../jobs/templates}/job_location_list.html | 0 .../jobs/templates}/job_locations.html | 0 .../jobs/templates}/job_review.html | 0 .../jobs/templates}/job_telecommute_list.html | 0 .../jobs/templates}/job_thanks.html | 0 .../jobs/templates}/job_type_list.html | 0 .../jobs/templates}/job_types.html | 0 .../jobs/templates}/submit_a_job-widget.html | 0 {mailing => app/jobs/tests}/__init__.py | 0 {jobs => app/jobs}/tests/test_models.py | 5 +- {jobs => app/jobs}/tests/test_views.py | 6 +- {jobs => app/jobs}/urls.py | 4 +- {jobs => app/jobs}/views.py | 19 +- .../migrations => app/mailing}/__init__.py | 0 {mailing => app/mailing}/admin.py | 2 +- {mailing => app/mailing}/apps.py | 2 +- {mailing => app/mailing}/forms.py | 2 +- .../mailing/migrations}/__init__.py | 0 {mailing => app/mailing}/models.py | 0 .../admin/base_email_template_form.html | 0 {mailing => app/mailing}/tests/__init__.py | 0 {mailing => app/mailing}/tests/forms.py | 4 +- {mailing => app/mailing}/tests/models.py | 2 +- {mailing => app/mailing}/tests/test_forms.py | 2 +- manage.py => app/manage.py | 2 +- .../migrations => app/membership}/__init__.py | 0 {membership => app/membership}/apps.py | 2 +- .../membership/migrations}/__init__.py | 0 {minutes => app/membership/tests}/__init__.py | 0 .../membership}/tests/test_views.py | 0 {membership => app/membership}/urls.py | 2 +- {membership => app/membership}/views.py | 4 +- .../management => app/minutes}/__init__.py | 0 {minutes => app/minutes}/admin.py | 4 +- {minutes => app/minutes}/apps.py | 2 +- {minutes => app/minutes}/feeds.py | 2 +- .../minutes/management}/__init__.py | 0 .../minutes/management/commands}/__init__.py | 0 .../management/commands/move_meeting_notes.py | 5 +- {minutes => app/minutes}/managers.py | 0 .../minutes}/migrations/0001_initial.py | 0 .../migrations/0002_auto_20150416_1853.py | 0 ..._creator_alter_minutes_last_modified_by.py | 0 .../minutes/migrations}/__init__.py | 0 {minutes => app/minutes}/models.py | 4 +- .../minutes/templates}/minutes_detail.html | 0 .../minutes/templates}/minutes_list.html | 0 .../minutes/tests}/__init__.py | 0 {minutes => app/minutes}/tests/test_models.py | 2 +- {minutes => app/minutes}/tests/test_views.py | 2 +- {minutes => app/minutes}/urls.py | 4 +- {minutes => app/minutes}/views.py | 6 +- .../nominations}/__init__.py | 0 {nominations => app/nominations}/admin.py | 2 +- {nominations => app/nominations}/apps.py | 2 +- {nominations => app/nominations}/forms.py | 2 +- .../nominations}/migrations/0001_initial.py | 0 .../migrations/0002_auto_20190514_1435.py | 0 .../nominations/migrations}/__init__.py | 0 {nominations => app/nominations}/models.py | 5 +- .../templates}/election_detail.html | 0 .../nominations/templates}/election_list.html | 0 .../templates}/nomination_accept_form.html | 0 .../templates}/nomination_detail.html | 0 .../templates}/nomination_form.html | 0 .../templates}/nominee_detail.html | 0 .../nominations/templates}/nominee_list.html | 0 .../nominations/templatetags}/__init__.py | 0 .../nominations}/templatetags/nominations.py | 0 {nominations => app/nominations}/urls.py | 2 +- {nominations => app/nominations}/views.py | 6 +- {pages/management => app/pages}/__init__.py | 0 {pages => app/pages}/admin.py | 4 +- {pages => app/pages}/api.py | 8 +- {pages => app/pages}/apps.py | 2 +- {pages => app/pages}/factories.py | 4 +- .../pages/management}/__init__.py | 0 .../pages/management/commands}/__init__.py | 0 .../commands/fix_success_story_images.py | 2 +- .../commands/import_pages_from_svn.py | 4 +- {pages => app/pages}/managers.py | 0 {pages => app/pages}/middleware.py | 4 +- .../pages}/migrations/0001_initial.py | 4 +- .../migrations/0002_auto_20150416_1853.py | 0 .../migrations/0003_auto_20230214_2113.py | 0 ...age_creator_alter_page_last_modified_by.py | 0 .../pages/migrations}/__init__.py | 0 {pages => app/pages}/models.py | 6 +- {pages => app/pages}/parser.py | 0 {pages => app/pages}/search_indexes.py | 2 +- {pages => app/pages}/serializers.py | 2 +- .../pages/templates}/default.html | 0 .../pages/templates}/pep-page.html | 0 .../pages => app/pages/templates}/raw.html | 0 .../settings => app/pages/tests}/__init__.py | 0 {pages => app/pages}/tests/base.py | 2 +- .../about/content.ht | 0 .../about/success/dlink/content.rst | 0 .../community/content.ht | 0 .../fake_svn_content_checkout/content.ht | 0 {pages => app/pages}/tests/test_api.py | 6 +- {pages => app/pages}/tests/test_models.py | 4 +- {pages => app/pages}/tests/test_parser.py | 4 +- {pages => app/pages}/tests/test_views.py | 2 +- {pages => app/pages}/urls.py | 2 +- {pages => app/pages}/views.py | 6 +- {pydotorg => app/pydotorg}/__init__.py | 0 {pydotorg => app/pydotorg}/celery.py | 4 +- {pydotorg => app/pydotorg}/compilers.py | 0 .../pydotorg}/context_processors.py | 0 {pydotorg => app/pydotorg}/drf.py | 0 {pydotorg => app/pydotorg}/middleware.py | 0 {pydotorg => app/pydotorg}/mixins.py | 0 {pydotorg => app/pydotorg}/resources.py | 0 .../pydotorg/settings}/__init__.py | 0 {pydotorg => app/pydotorg}/settings/base.py | 56 +- .../pydotorg}/settings/cabotage.py | 6 +- {pydotorg => app/pydotorg}/settings/local.py | 2 +- .../pydotorg}/settings/pipeline.py | 4 - {pydotorg => app/pydotorg}/settings/static.py | 8 +- {sponsors => app/pydotorg/tests}/__init__.py | 0 .../pydotorg}/tests/test_classes.py | 0 .../tests/test_context_processors.py | 2 +- .../pydotorg}/tests/test_middleware.py | 0 .../pydotorg}/tests/test_resources.py | 2 +- .../pydotorg}/tests/test_views.py | 2 +- {pydotorg => app/pydotorg}/urls.py | 7 +- {pydotorg => app/pydotorg}/urls_api.py | 10 +- {pydotorg => app/pydotorg}/views.py | 4 +- {pydotorg => app/pydotorg}/wsgi.py | 2 +- .../management => app/sponsors}/__init__.py | 0 {sponsors => app/sponsors}/admin.py | 10 +- {sponsors => app/sponsors}/api.py | 4 +- {sponsors => app/sponsors}/apps.py | 2 +- {sponsors => app/sponsors}/contracts.py | 0 {sponsors => app/sponsors}/cookies.py | 0 {sponsors => app/sponsors}/exceptions.py | 0 {sponsors => app/sponsors}/forms.py | 2 +- .../sponsors/management}/__init__.py | 0 .../sponsors/management/commands}/__init__.py | 0 .../check_sponsorship_assets_due_date.py | 4 +- .../management/commands/create_contracts.py | 2 +- .../create_pycon_vouchers_for_sponsors.py | 6 +- .../commands/fullfill_pycon_2022.py | 5 +- .../sponsors}/migrations/0001_initial.py | 0 .../migrations/0002_auto_20150416_1853.py | 0 .../migrations/0003_auto_20170821_2000.py | 0 .../migrations/0004_auto_20201014_1622.py | 0 .../migrations/0005_auto_20201015_0908.py | 0 .../migrations/0006_auto_20201016_1517.py | 0 .../migrations/0007_auto_20201021_1410.py | 0 .../migrations/0008_auto_20201028_1814.py | 0 .../migrations/0009_auto_20201103_1259.py | 0 .../migrations/0010_auto_20201103_1313.py | 0 .../migrations/0011_auto_20201111_1724.py | 0 .../0012_sponsorship_for_modified_package.py | 0 ...3_sponsorbenefit_benefit_internal_value.py | 0 .../migrations/0014_auto_20201116_1437.py | 0 .../migrations/0015_auto_20201117_1739.py | 0 .../migrations/0016_auto_20201119_1448.py | 0 .../0017_sponsorbenefit_added_by_user.py | 0 .../migrations/0018_auto_20201201_1659.py | 0 .../migrations/0019_sponsor_twitter_handle.py | 0 .../migrations/0019_statementofwork.py | 0 .../migrations/0020_auto_20201210_1802.py | 0 .../0020_sponsorshipbenefit_unavailable.py | 0 .../migrations/0021_auto_20201211_2120.py | 0 .../0022_sponsorcontact_administrative.py | 0 .../migrations/0023_merge_20210406_1522.py | 0 .../migrations/0024_auto_20210414_1449.py | 0 .../migrations/0025_auto_20210416_1939.py | 0 .../migrations/0026_auto_20210416_1940.py | 0 .../0027_sponsorbenefit_program_name.py | 0 .../migrations/0028_auto_20210707_1426.py | 0 .../migrations/0029_auto_20210715_2015.py | 0 .../migrations/0030_auto_20210715_2023.py | 0 .../migrations/0031_auto_20210810_1232.py | 0 .../0032_sponsorcontact_accounting.py | 0 ...redquantity_tieredquantityconfiguration.py | 0 .../migrations/0034_contract_document_docx.py | 0 .../migrations/0035_auto_20210826_1929.py | 0 .../migrations/0036_auto_20210826_1930.py | 0 .../migrations/0037_sponsorship_package.py | 0 .../migrations/0038_auto_20210827_1223.py | 0 .../migrations/0039_auto_20210827_1248.py | 0 .../migrations/0040_auto_20210827_1313.py | 0 .../migrations/0041_auto_20210827_1313.py | 0 .../migrations/0042_auto_20210827_1318.py | 0 .../migrations/0043_auto_20210827_1343.py | 0 .../migrations/0044_auto_20210827_1344.py | 0 .../0045_add_added_by_user_sponsorbenefit.py | 0 .../0046_sponsorshippackage_advertise.py | 0 .../migrations/0047_auto_20210908_1357.py | 0 .../migrations/0048_auto_20210915_1425.py | 0 .../0049_sponsoremailnotificationtemplate.py | 0 ...targetable_emailtargetableconfiguration.py | 0 .../migrations/0051_auto_20211022_1403.py | 0 ...dimgasset_requiredimgassetconfiguration.py | 0 .../migrations/0053_genericasset_imgasset.py | 4 +- .../migrations/0054_auto_20211026_1432.py | 0 .../migrations/0055_auto_20211026_1512.py | 0 .../sponsors}/migrations/0056_textasset.py | 0 .../migrations/0057_auto_20211026_1529.py | 0 .../migrations/0058_auto_20211029_1427.py | 0 .../migrations/0059_auto_20211029_1503.py | 0 .../migrations/0060_auto_20211111_1526.py | 0 .../migrations/0061_auto_20211108_1419.py | 0 .../migrations/0062_auto_20211111_1529.py | 0 .../migrations/0063_auto_20211220_1422.py | 0 .../0064_sponsorshippackage_slug.py | 0 .../migrations/0065_auto_20211223_1309.py | 0 .../migrations/0066_auto_20211223_1318.py | 0 .../0067_sponsorbenefit_a_la_carte.py | 0 .../migrations/0068_auto_20220110_1841.py | 0 .../migrations/0069_auto_20220110_2148.py | 6 +- .../migrations/0070_auto_20220111_2055.py | 10 +- .../migrations/0071_auto_20220113_1843.py | 0 .../migrations/0072_auto_20220125_2005.py | 0 .../migrations/0073_auto_20220128_1906.py | 6 +- .../migrations/0074_auto_20220211_1659.py | 0 .../migrations/0075_auto_20220303_2023.py | 0 .../migrations/0076_auto_20220728_1550.py | 0 .../migrations/0077_sponsorshipcurrentyear.py | 0 .../0078_init_current_year_singleton.py | 0 .../0079_index_to_force_singleton.py | 0 .../migrations/0080_auto_20220728_1644.py | 0 .../0081_sponsorship_application_year.py | 0 .../migrations/0082_auto_20220729_1613.py | 0 .../migrations/0083_auto_20220729_1624.py | 0 .../0084_init_configured_objs_year.py | 0 .../migrations/0085_auto_20220730_0945.py | 0 .../migrations/0086_auto_20220809_1655.py | 0 .../migrations/0087_auto_20220810_1647.py | 0 .../migrations/0088_auto_20220810_1655.py | 0 .../migrations/0089_auto_20220812_1312.py | 0 .../migrations/0090_auto_20220812_1314.py | 0 ...091_sponsorshippackage_allow_a_la_carte.py | 0 .../migrations/0092_auto_20220816_1517.py | 0 .../migrations/0093_auto_20230214_2113.py | 0 .../migrations/0094_sponsorship_locked.py | 2 +- .../migrations/0095_auto_20231214_2025.py | 0 .../migrations/0096_auto_20231214_2108.py | 0 .../migrations/0097_sponsorship_renewal.py | 0 .../migrations/0098_auto_20231219_1910.py | 0 .../migrations/0099_auto_20231224_1854.py | 0 .../migrations/0100_auto_20240107_1054.py | 0 .../0101_sponsor_linked_in_page_url.py | 0 .../migrations/0102_auto_20240509_2037.py | 0 ...nefitfeature_polymorphic_ctype_and_more.py | 0 .../sponsors/migrations}/__init__.py | 0 app/sponsors/models/__init__.py | 17 + {sponsors => app/sponsors}/models/assets.py | 3 +- {sponsors => app/sponsors}/models/benefits.py | 6 +- {sponsors => app/sponsors}/models/contract.py | 6 +- {sponsors => app/sponsors}/models/enums.py | 0 {sponsors => app/sponsors}/models/managers.py | 16 +- .../sponsors}/models/notifications.py | 2 +- {sponsors => app/sponsors}/models/sponsors.py | 6 +- .../sponsors}/models/sponsorship.py | 10 +- {sponsors => app/sponsors}/notifications.py | 2 +- .../sponsors/pandoc_filters}/__init__.py | 0 .../sponsors}/pandoc_filters/pagebreak.py | 0 {sponsors => app/sponsors}/reference.docx | Bin {sponsors => app/sponsors}/serializers.py | 4 +- .../templates}/admin/approve_application.html | 0 .../admin/clone_application_config_form.html | 0 .../admin/contract_change_form.html | 0 .../admin/contracts/sponsorship-agreement.md | 0 .../templates}/admin/execute_contract.html | 0 .../admin/list_uploaded_assets.html | 0 .../templates}/admin/nullify_contract.html | 0 .../templates}/admin/reject_application.html | 0 .../rollback_sponsorship_to_editing.html | 0 .../templates}/admin/send_contract.html | 0 .../admin/send_sponsors_notification.html | 0 ...ors_sponsorshipcurrentyear_changelist.html | 0 .../admin/sponsorship_change_form.html | 0 .../admin/sponsorshipbenefit_change_form.html | 0 .../sponsors/templates}/admin/unlock.html | 0 .../admin/update_related_sponsorships.html | 0 .../templates}/email/psf_contract.txt | 0 .../templates}/email/psf_contract_subject.txt | 0 .../templates}/email/psf_new_application.txt | 0 .../email/psf_new_application_subject.txt | 0 .../email/psf_rejected_sponsorship.txt | 0 .../psf_rejected_sponsorship_subject.txt | 0 .../templates}/email/sponsor_contract.txt | 0 .../email/sponsor_contract_subject.txt | 0 .../email/sponsor_expiring_assets.txt | 0 .../email/sponsor_expiring_assets_subject.txt | 0 .../email/sponsor_new_application.txt | 0 .../email/sponsor_new_application_subject.txt | 0 .../email/sponsor_rejected_sponsorship.txt | 0 .../sponsor_rejected_sponsorship_subject.txt | 0 .../new_sponsorship_application_form.html | 0 .../templates}/partials/full_sponsorship.txt | 0 .../templates}/partials/sponsors-list.html | 0 .../sponsors/templates}/sponsor_list.html | 0 .../sponsorship_application_finished.html | 0 .../templates}/sponsorship_benefits_form.html | 0 .../sponsors/templatetags}/__init__.py | 0 .../sponsors}/templatetags/sponsors.py | 4 +- .../sponsors/tests}/__init__.py | 0 .../sponsors}/tests/baker_recipes.py | 4 +- .../sponsors}/tests/test_admin.py | 4 +- {sponsors => app/sponsors}/tests/test_api.py | 4 +- .../sponsors}/tests/test_contracts.py | 2 +- .../sponsors}/tests/test_forms.py | 8 +- .../tests/test_management_command.py | 6 +- .../sponsors}/tests/test_managers.py | 4 +- .../sponsors}/tests/test_models.py | 8 +- .../sponsors}/tests/test_notifications.py | 4 +- .../sponsors}/tests/test_templatetags.py | 6 +- .../sponsors}/tests/test_use_cases.py | 6 +- .../sponsors}/tests/test_views.py | 6 +- .../sponsors}/tests/test_views_admin.py | 10 +- {sponsors => app/sponsors}/tests/utils.py | 0 {sponsors => app/sponsors}/urls.py | 2 +- {sponsors => app/sponsors}/use_cases.py | 6 +- {sponsors => app/sponsors}/utils.py | 0 {sponsors => app/sponsors}/views.py | 8 +- {sponsors => app/sponsors}/views_admin.py | 10 +- .../apple-touch-icon-114x114-precomposed.png | Bin .../apple-touch-icon-144x144-precomposed.png | Bin .../apple-touch-icon-72x72-precomposed.png | Bin .../static}/apple-touch-icon-precomposed.png | Bin .../static}/community_logos/README.txt | 0 .../community_logos/python-logo-generic.svg | 0 .../community_logos/python-logo-inkscape.svg | 0 .../python-logo-master-v3-TM-flattened.png | Bin .../python-logo-master-v3-TM.png | Bin .../python-logo-master-v3-TM.psd | Bin .../static}/community_logos/python-logo.png | Bin .../python-powered-h-100x130.png | Bin .../python-powered-h-140x182.png | Bin .../python-powered-h-50x65.png | Bin .../python-powered-h-70x91.png | Bin .../community_logos/python-powered-h.svg | 0 .../python-powered-w-100x40.png | Bin .../python-powered-w-140x56.png | Bin .../python-powered-w-200x80.png | Bin .../python-powered-w-70x28.png | Bin .../community_logos/python-powered-w.svg | 0 {static => app/static}/config.rb | 0 {static => app/static}/favicon.ico | Bin {static => app/static}/fonts/FluxBold.eot | Bin {static => app/static}/fonts/FluxBold.ttf | Bin {static => app/static}/fonts/FluxBold.woff | Bin .../static}/fonts/FluxBoldItalic.eot | Bin .../static}/fonts/FluxBoldItalic.ttf | Bin .../static}/fonts/FluxBoldItalic.woff | Bin {static => app/static}/fonts/FluxItalic.eot | Bin {static => app/static}/fonts/FluxItalic.ttf | Bin {static => app/static}/fonts/FluxItalic.woff | Bin {static => app/static}/fonts/FluxRegular.eot | Bin {static => app/static}/fonts/FluxRegular.ttf | Bin {static => app/static}/fonts/FluxRegular.woff | Bin {static => app/static}/fonts/FontAwesome.otf | Bin {static => app/static}/fonts/Pythonicon.eot | Bin {static => app/static}/fonts/Pythonicon.json | 0 {static => app/static}/fonts/Pythonicon.svg | 0 {static => app/static}/fonts/Pythonicon.ttf | Bin {static => app/static}/fonts/Pythonicon.woff | Bin ...SIL OFL Font License - Source Sans Pro.txt | 0 .../fonts/SourceSansPro-Bold-webfont.eot | Bin .../fonts/SourceSansPro-Bold-webfont.svg | 0 .../fonts/SourceSansPro-Bold-webfont.ttf | Bin .../fonts/SourceSansPro-Bold-webfont.woff | Bin .../fonts/SourceSansPro-It-webfont.eot | Bin .../fonts/SourceSansPro-It-webfont.svg | 0 .../fonts/SourceSansPro-It-webfont.ttf | Bin .../fonts/SourceSansPro-It-webfont.woff | Bin .../fonts/SourceSansPro-Regular-webfont.eot | Bin .../fonts/SourceSansPro-Regular-webfont.svg | 0 .../fonts/SourceSansPro-Regular-webfont.ttf | Bin .../fonts/SourceSansPro-Regular-webfont.woff | Bin {static => app/static}/fonts/demo.html | 0 {static => app/static}/fonts/demo/demo.css | 0 {static => app/static}/fonts/demo/demo.js | 0 .../static}/fonts/fontawesome-webfont.eot | Bin .../static}/fonts/fontawesome-webfont.svg | 0 .../static}/fonts/fontawesome-webfont.ttf | Bin .../static}/fonts/fontawesome-webfont.woff | Bin .../static}/fonts/fontawesome-webfont.woff2 | Bin {static => app/static}/fonts/lte-ie7.js | 0 {static => app/static}/fonts/style.css | 0 {static => app/static}/images/CCP.jpg | Bin .../static}/images/ExowebGlossyLogo.png | Bin .../static}/images/Google_Logo_25wht.gif | Bin .../static}/images/Lucasfilm_logo.png | Bin {static => app/static}/images/OSAFLogo.gif | Bin .../images/OnlineDegreeReviews-Logo.png | Bin .../static}/images/PythonPowered.gif | Bin .../static}/images/PythonPoweredAnim.gif | Bin .../static}/images/PythonPoweredAnimSmall.gif | Bin .../static}/images/PythonPoweredSmall.gif | Bin {static => app/static}/images/README.txt | 0 {static => app/static}/images/Red_Hat.png | Bin {static => app/static}/images/activegrid.gif | Bin .../static}/images/activestate_logo.gif | Bin {static => app/static}/images/arraylogo.jpg | Bin {static => app/static}/images/astilogo.gif | Bin .../static}/images/batteries-included.jpg | Bin {static => app/static}/images/beslist.png | Bin {static => app/static}/images/bizrate.gif | Bin {static => app/static}/images/blank.gif | Bin {static => app/static}/images/bullet.gif | Bin .../static}/images/button-on-bg.png | Bin .../static}/images/canonical-logo.png | Bin .../static}/images/cpacket_logo.jpg | Bin {static => app/static}/images/donate.png | Bin {static => app/static}/images/emd_logo.gif | Bin {static => app/static}/images/enthought.jpg | Bin {static => app/static}/images/enthought.png | Bin .../static}/images/favicon16x16.ico | Bin .../static}/images/finding-idle.png | Bin {static => app/static}/images/freewear-1.png | Bin .../static}/images/freewear-logo.png | Bin {static => app/static}/images/globo_logo.gif | Bin {static => app/static}/images/google.gif | Bin {static => app/static}/images/header-bg.png | Bin {static => app/static}/images/header-bg2.png | Bin .../static}/images/hitflip_logo.jpg | Bin {static => app/static}/images/hood_logo.gif | Bin {static => app/static}/images/hw128_28.gif | Bin .../static}/images/infrastructure/dyn.png | Bin .../static}/images/infrastructure/gandi.png | Bin .../static}/images/infrastructure/osl.png | Bin .../images/infrastructure/pagerduty.png | Bin .../static}/images/infrastructure/pingdom.png | Bin .../static}/images/infrastructure/upfront.png | Bin .../static}/images/infrastructure/xs4all.png | Bin {static => app/static}/images/ironport.gif | Bin {static => app/static}/images/knmp-logo.png | Bin .../static}/images/logo_lincoln_loop.png | Bin {static => app/static}/images/microbit.png | Bin {static => app/static}/images/nav-off-bg.png | Bin {static => app/static}/images/nav-on-bg.png | Bin .../static}/images/open_end_ab_logo.png | Bin .../static}/images/openeye-logo.gif | Bin .../static}/images/opensource-110x95.png | Bin .../static}/images/oreilly_logo.gif | Bin .../static}/images/osi-certified-120x100.gif | Bin .../static}/images/pattern_banner.gif | Bin {static => app/static}/images/pep-0001-1.png | Bin {static => app/static}/images/psf-logo.gif | Bin .../static}/images/py_mac-sq-64.png | Bin {static => app/static}/images/pyastra.jpg | Bin .../static}/images/pycon-2010-banner.png | Bin {static => app/static}/images/pygoogle.jpg | Bin {static => app/static}/images/pynasa.jpg | Bin .../static}/images/python-audio-100x40.png | Bin .../static}/images/python-data-100x40.png | Bin {static => app/static}/images/python-logo.gif | Bin .../static}/images/python-video-icon.png | Bin .../static}/images/pythongear-logo.png | Bin {static => app/static}/images/pythonlogo.eps | 0 {static => app/static}/images/pythonlogo.pdf | Bin {static => app/static}/images/pythonlogo.png | Bin {static => app/static}/images/pythonlogo.tiff | Bin {static => app/static}/images/pyxp.jpg | Bin {static => app/static}/images/seo_moves.jpg | Bin {static => app/static}/images/strakt_logo.gif | Bin .../static}/images/success/Carmanah.png | Bin .../static}/images/success/Honeywell.png | Bin .../static}/images/success/StAndrews.png | Bin .../static}/images/success/afnic.fr.png | Bin .../static}/images/success/forecastwatch.png | Bin .../static}/images/success/frequentis.png | Bin .../static}/images/success/journyx.png | Bin .../static}/images/success/mayavi.jpg | Bin .../static}/images/success/mmtk.jpg | Bin .../static}/images/success/nasa.jpg | Bin .../static}/images/success/natsworld.png | Bin .../static}/images/success/standrews.jpg | Bin .../static}/images/success/superleague.png | Bin .../static}/images/success/tribon.jpg | Bin {static => app/static}/images/sun_logo.png | Bin {static => app/static}/images/tabblo.png | Bin .../static}/images/terminal-in-finder.png | Bin {static => app/static}/images/trans.gif | Bin .../static}/images/uniblue-logo.jpg | Bin {static => app/static}/images/wargaming.png | Bin {static => app/static}/images/winglogo.gif | Bin {static => app/static}/images/worldmap.jpg | Bin {static => app/static}/images/zeomega.gif | Bin {static => app/static}/images/zeuux.jpg | Bin .../static}/images/zimbio_corp_logo.gif | Bin {static => app/static}/images/zope_logo.gif | Bin .../static}/img/bg_direction_nav.png | Bin {static => app/static}/img/landing-about.png | Bin .../static}/img/landing-community.png | Bin {static => app/static}/img/landing-docs.png | Bin .../static}/img/landing-downloads.png | Bin {static => app/static}/img/psf-logo.png | Bin {static => app/static}/img/psf-logo@2x.png | Bin {static => app/static}/img/psf-logo_print.png | Bin .../static}/img/python-logo-large.png | Bin {static => app/static}/img/python-logo.png | Bin {static => app/static}/img/python-logo@2x.png | Bin .../static}/img/python-logo_print.png | Bin {static => app/static}/img/sample-gmap.png | Bin .../static}/img/sponsors/tick-placeholder.png | Bin {static => app/static}/img/sponsors/tick.svg | 0 .../static}/img/sponsors/title-1.svg | 0 .../static}/img/sponsors/title-2.svg | 0 .../static}/img/sponsors/title-3.svg | 0 .../static}/img/sponsors/title-4.svg | 0 .../static}/img/sponsors/title-5.svg | 0 .../static}/img/sponsors/title-6.svg | 0 {static => app/static}/img/success-glow2.png | Bin .../static}/js/libs/html-includes.js | 0 .../static}/js/libs/jquery-1.8.2.min.js | 0 .../static}/js/libs/jquery-ui-1.12.1.min.js | 0 .../static}/js/libs/masonry.pkgd.min.js | 0 {static => app/static}/js/libs/modernizr.js | 0 {static => app/static}/js/plugins.js | 0 {static => app/static}/js/plugins/IE7.js | 4818 +++++++------- {static => app/static}/js/plugins/IE8.js | 5380 +++++++-------- {static => app/static}/js/plugins/IE9.js | 5806 ++++++++--------- .../static}/js/plugins/getComputedStyle.js | 0 .../static}/js/plugins/ie7-squish.js | 72 +- .../static}/js/plugins/jquery.cookie.js | 0 {static => app/static}/js/script.js | 0 .../static}/js/sponsors/applicationForm.js | 0 {static => app/static}/metro-icon-144x144.png | Bin .../static}/opengraph-icon-200x200.png | Bin {static => app/static}/sass/_FIX-THESE | 0 {static => app/static}/sass/_base.scss | 0 {static => app/static}/sass/_debug.scss | 0 {static => app/static}/sass/_flexslider.scss | 0 {static => app/static}/sass/_fonts.scss | 0 {static => app/static}/sass/_functions.scss | 0 {static => app/static}/sass/_layout.scss | 0 {static => app/static}/sass/_mixins.scss | 0 {static => app/static}/sass/mq.css | 0 {static => app/static}/sass/mq.scss | 0 {static => app/static}/sass/no-mq.css | 0 {static => app/static}/sass/no-mq.scss | 0 {static => app/static}/sass/style.css | 0 {static => app/static}/sass/style.scss | 0 .../static}/source_files/artboard.psd | Bin {static => app/static}/source_files/glow.psd | Bin .../source_files/psf-top-logo-beta.psd | Bin .../static}/source_files/python logo.svg | 0 .../source_files/python-logo-mods-v2.ai | 0 .../static}/source_files/python-logo-mods.ai | 0 .../source_files/python-top-logo-beta.psd | Bin .../static}/source_files/python-top-logo.psd | Bin .../static}/stylesheets/console.css | 0 .../static}/stylesheets/font-awesome.min.css | 0 .../successstories}/__init__.py | 0 .../successstories}/admin.py | 4 +- .../successstories}/apps.py | 2 +- .../successstories}/factories.py | 2 +- .../successstories}/forms.py | 4 +- .../successstories}/managers.py | 0 .../migrations/0001_initial.py | 0 .../migrations/0002_auto_20150416_1853.py | 0 .../migrations/0003_auto_20170720_1655.py | 0 .../migrations/0004_auto_20170724_0507.py | 0 .../migrations/0005_auto_20170726_0645.py | 0 .../migrations/0006_auto_20170726_0824.py | 2 +- .../migrations/0007_remove_story_weight.py | 0 .../migrations/0008_auto_20170821_2000.py | 0 .../migrations/0009_auto_20180705_0352.py | 0 .../migrations/0010_story_submitted_by.py | 0 .../migrations/0011_auto_20220127_1923.py | 0 ...ry_creator_alter_story_last_modified_by.py | 0 .../successstories/migrations}/__init__.py | 0 .../successstories}/models.py | 11 +- .../successstories/templates}/base.html | 0 .../templates}/story_detail.html | 0 .../successstories/templates}/story_form.html | 0 .../successstories/templates}/story_list.html | 0 .../templates}/storycategory_detail.html | 0 .../successstories/templates}/supernav.html | 0 .../successstories/templatetags}/__init__.py | 0 .../templatetags/successstories.py | 2 +- .../successstories/tests}/__init__.py | 0 .../successstories}/tests/test_forms.py | 4 +- .../successstories}/tests/test_models.py | 4 +- .../tests/test_templatetags.py | 2 +- .../successstories}/tests/test_utils.py | 2 +- .../successstories}/tests/test_views.py | 6 +- .../successstories}/urls.py | 2 +- .../successstories}/utils.py | 0 .../successstories}/views.py | 10 +- {templates => app/templates}/403.html | 0 {templates => app/templates}/404.html | 0 {templates => app/templates}/500.html | 0 .../templates}/admin/base_site.html | 0 {templates => app/templates}/base.html | 0 .../templates}/components/blog-posts.html | 0 .../templates}/components/event-posts.html | 0 .../components/navigation-widget.html | 0 .../templates}/components/psf-widget.html | 0 .../templates}/components/success-story.html | 0 {templates => app/templates}/docs/index.html | 0 {templates => app/templates}/humans.txt | 0 .../templates}/includes/authenticated.html | 0 {templates => app/templates}/psf/default.html | 0 .../templates}/psf/full-width.html | 0 {templates => app/templates}/psf/index.html | 0 .../templates}/psf/sponsors-list.html | 0 {templates => app/templates}/pypl/index.html | 0 .../templates}/python/about.html | 0 .../templates}/python/documentation.html | 0 .../templates}/python/events.html | 0 .../templates}/python/index.html | 0 .../templates}/python/inner.html | 0 .../templates}/python/shell.html | 0 .../templates}/registration/logged_out.html | 0 .../templates}/registration/login.html | 0 {templates => app/templates}/robots.txt | 0 .../search/includes/downloads.release.html | 0 .../search/includes/events.calendar.html | 0 .../search/includes/events.event.html | 0 .../templates}/search/includes/jobs.job.html | 0 .../search/includes/jobs.job_category.html | 0 .../search/includes/jobs.job_type.html | 0 .../search/includes/pages.page.html | 0 .../search/indexes/downloads/release_text.txt | 0 .../search/indexes/events/calendar_text.txt | 0 .../search/indexes/events/event_text.txt | 0 .../search/indexes/jobs/job_text.txt | 0 .../search/indexes/jobs/jobcategory_text.txt | 0 .../search/indexes/jobs/jobtype_text.txt | 0 .../search/indexes/pages/page_text.txt | 0 .../templates}/search/search.html | 0 {templates => app/templates}/shop/index.html | 0 .../templates}/sitetree/breadcrumbs.html | 0 .../templates}/sitetree/footer.html | 0 .../templates}/sitetree/footer_children.html | 0 .../templates}/sitetree/menu.html | 0 .../templates}/sitetree/sidebar_menu.html | 0 .../sitetree/sidebar_menu_root.html | 0 .../templates}/sitetree/submenu.html | 0 .../templates}/sitetree/submenu_children.html | 0 .../templates}/sitetree/top.html | 0 {templates => app/templates}/waitforit.html | 0 {users/migrations => app/users}/__init__.py | 0 {users => app/users}/actions.py | 0 {users => app/users}/admin.py | 4 +- {users => app/users}/apps.py | 4 +- {users => app/users}/factories.py | 2 +- {users => app/users}/forms.py | 2 +- {users => app/users}/listeners.py | 2 +- {users => app/users}/managers.py | 0 .../users}/migrations/0001_initial.py | 0 .../migrations/0002_auto_20150416_1853.py | 0 .../migrations/0003_auto_20150503_2026.py | 0 .../migrations/0004_auto_20150503_2100.py | 0 .../migrations/0005_user_public_profile.py | 0 .../migrations/0006_auto_20150503_2124.py | 0 .../migrations/0007_auto_20150604_1555.py | 0 .../migrations/0008_auto_20170814_0301.py | 0 .../migrations/0009_auto_20170821_2000.py | 0 .../migrations/0010_auto_20170828_1906.py | 0 .../migrations/0011_auto_20170902_0930.py | 0 .../users}/migrations/0012_usergroup.py | 0 .../migrations/0013_auto_20180705_0348.py | 0 .../migrations/0014_auto_20210801_2332.py | 0 .../migrations/0015_alter_user_first_name.py | 0 .../users/migrations}/__init__.py | 0 {users => app/users}/models.py | 4 +- .../users/templates/account}/base.html | 0 .../users/templates}/account/login.html | 0 .../users/templates}/account/logout.html | 0 .../templates}/account/password_change.html | 0 .../users/templates}/account/signup.html | 0 .../templates}/account/verification_sent.html | 0 .../users => app/users/templates}/base.html | 0 .../templates}/list_user_sponsorships.html | 0 .../users/templates}/membership.html | 0 .../users/templates}/membership_form.html | 0 .../users/templates}/membership_thanks.html | 0 .../templates}/membership_vote_affirm.html | 0 .../membership_vote_affirm_done.html | 0 .../users/templates}/nominations_view.html | 0 .../users/templates}/sponsor_info_update.html | 0 .../users/templates}/sponsor_select.html | 0 .../templates}/sponsorship_assets_update.html | 0 .../templates}/sponsorship_assets_view.html | 0 .../users/templates}/sponsorship_detail.html | 0 .../users/templates}/user_detail.html | 0 .../users/templates}/user_form.html | 0 .../users/templatetags}/__init__.py | 0 .../users}/templatetags/users_tags.py | 2 +- {work_groups => app/users/tests}/__init__.py | 0 {users => app/users}/tests/test_forms.py | 2 +- {users => app/users}/tests/test_models.py | 4 +- .../users}/tests/test_templatetags.py | 4 +- {users => app/users}/tests/test_views.py | 12 +- {users => app/users}/urls.py | 2 +- {users => app/users}/validators.py | 0 {users => app/users}/views.py | 36 +- .../work_groups}/__init__.py | 0 {work_groups => app/work_groups}/admin.py | 4 +- {work_groups => app/work_groups}/apps.py | 2 +- .../work_groups}/migrations/0001_initial.py | 0 .../migrations/0002_auto_20150604_2203.py | 0 .../migrations/0003_auto_20170821_2000.py | 0 .../migrations/0004_auto_20180705_0352.py | 0 .../0005_alter_workgroup_creator_and_more.py | 0 .../work_groups/migrations}/__init__.py | 0 {work_groups => app/work_groups}/models.py | 2 +- .../work_groups/tests/__init__.py | 0 app/work_groups/tests/test_models.py | 0 codesamples/admin.py | 7 - docker-compose.yml | 4 +- docs/source/install.md | 2 +- .../base-requirements.txt | 0 .../dev-requirements.txt | 0 .../docs-requirements.txt | 0 .../prod-requirements.txt | 0 .../requirements.txt | 0 sponsors/models/__init__.py | 17 - templates/peps/list.html | 106 - 990 files changed, 10561 insertions(+), 10691 deletions(-) rename {banners => app}/__init__.py (100%) rename {banners/migrations => app/banners}/__init__.py (100%) rename {banners => app/banners}/admin.py (80%) rename {banners => app/banners}/apps.py (74%) rename {banners => app/banners}/migrations/0001_initial.py (100%) rename {banners/templatetags => app/banners/migrations}/__init__.py (100%) rename {banners => app/banners}/models.py (100%) rename {templates/banners => app/banners/templates}/banner.html (100%) rename {blogs => app/banners/templatetags}/__init__.py (100%) rename {banners => app/banners}/templatetags/banners.py (94%) rename {bin => app/bin}/pre_compile (100%) rename {bin => app/bin}/start-nginx (100%) rename {blogs/management => app/blogs}/__init__.py (100%) rename {blogs => app/blogs}/admin.py (91%) rename {blogs => app/blogs}/apps.py (75%) rename {blogs => app/blogs}/factories.py (90%) rename {blogs/management/commands => app/blogs/management}/__init__.py (100%) rename {blogs/migrations => app/blogs/management/commands}/__init__.py (100%) rename {blogs => app/blogs}/management/commands/update_blogs.py (85%) rename {blogs => app/blogs}/migrations/0001_initial.py (100%) rename {blogs => app/blogs}/migrations/0002_remove_translations_and_contributors.py (100%) rename {blogs => app/blogs}/migrations/0003_alter_relatedblog_creator_and_more.py (100%) rename {blogs/templatetags => app/blogs/migrations}/__init__.py (100%) rename {blogs => app/blogs}/models.py (98%) rename {blogs => app/blogs}/parser.py (95%) rename {templates/blogs => app/blogs/templates}/index.html (100%) rename {templates/blogs => app/blogs/templates}/supernav.html (100%) rename {blogs/tests => app/blogs/templatetags}/__init__.py (100%) rename {blogs => app/blogs}/templatetags/blogs.py (93%) rename {boxes => app/blogs/tests}/__init__.py (100%) rename {blogs => app/blogs}/tests/psf_feed_example.xml (99%) rename {blogs => app/blogs}/tests/test_models.py (93%) rename {blogs => app/blogs}/tests/test_parser.py (91%) rename {blogs => app/blogs}/tests/test_templatetags.py (92%) rename {blogs => app/blogs}/tests/test_views.py (89%) rename {blogs => app/blogs}/tests/utils.py (100%) rename {blogs => app/blogs}/urls.py (78%) rename {blogs => app/blogs}/views.py (88%) rename {boxes/migrations => app/boxes}/__init__.py (100%) rename {boxes => app/boxes}/admin.py (59%) rename {boxes => app/boxes}/apps.py (75%) rename {boxes => app/boxes}/factories.py (91%) rename {boxes => app/boxes}/migrations/0001_initial.py (100%) rename {boxes => app/boxes}/migrations/0002_auto_20150416_1853.py (100%) rename {boxes => app/boxes}/migrations/0003_auto_20171101_2138.py (100%) rename {boxes => app/boxes}/migrations/0004_alter_box_creator_alter_box_last_modified_by.py (100%) rename {cms => app/boxes/migrations}/__init__.py (100%) rename {boxes => app/boxes}/models.py (94%) rename {boxes => app/boxes}/templatetags/boxes.py (92%) rename {boxes => app/boxes}/tests.py (96%) rename {boxes => app/boxes}/urls.py (74%) rename {boxes => app/boxes}/views.py (85%) rename {cms/management => app/cms}/__init__.py (100%) rename {cms => app/cms}/admin.py (100%) rename {cms => app/cms}/apps.py (76%) rename {cms => app/cms}/forms.py (100%) rename {cms/management/commands => app/cms/management}/__init__.py (100%) rename {cms/templatetags => app/cms/management/commands}/__init__.py (100%) rename {cms => app/cms}/management/commands/create_initial_data.py (100%) rename {cms => app/cms}/models.py (100%) rename {templates/cms => app/cms/templates}/iso_time_tag.html (100%) rename {codesamples => app/cms/templatetags}/__init__.py (100%) rename {cms => app/cms}/templatetags/cms.py (100%) rename {cms => app/cms}/tests.py (97%) rename {cms => app/cms}/views.py (100%) rename {codesamples/migrations => app/codesamples}/__init__.py (100%) create mode 100644 app/codesamples/admin.py rename {codesamples => app/codesamples}/apps.py (72%) rename {codesamples => app/codesamples}/factories.py (98%) rename {codesamples => app/codesamples}/managers.py (100%) rename {codesamples => app/codesamples}/migrations/0001_initial.py (100%) rename {codesamples => app/codesamples}/migrations/0002_auto_20150416_1853.py (100%) rename {codesamples => app/codesamples}/migrations/0003_auto_20170821_2000.py (100%) rename {codesamples => app/codesamples}/migrations/0004_alter_codesample_creator_and_more.py (100%) rename {community => app/codesamples/migrations}/__init__.py (100%) rename {codesamples => app/codesamples}/models.py (87%) rename {codesamples => app/codesamples}/tests.py (93%) rename {community/migrations => app/community}/__init__.py (100%) rename {community => app/community}/admin.py (83%) rename {community => app/community}/apps.py (73%) rename {community => app/community}/managers.py (100%) rename {community => app/community}/migrations/0001_initial.py (100%) rename {community => app/community}/migrations/0001_squashed_0004_auto_20170831_0541.py (100%) rename {community => app/community}/migrations/0002_auto_20150416_1853.py (100%) rename {community => app/community}/migrations/0003_auto_20170831_0358.py (100%) rename {community => app/community}/migrations/0004_auto_20170831_0541.py (100%) rename {community => app/community}/migrations/0005_alter_link_creator_alter_link_last_modified_by_and_more.py (100%) rename {community/templatetags => app/community/migrations}/__init__.py (100%) rename {community => app/community}/models.py (97%) rename {templates/community => app/community/templates}/microbit.html (100%) rename {templates/community => app/community/templates}/post_detail.html (100%) rename {templates/community => app/community/templates}/post_list.html (100%) rename {templates/community => app/community/templates}/types/default.html (100%) rename {templates/community => app/community/templates}/types/link.html (100%) rename {templates/community => app/community/templates}/types/photo.html (100%) rename {templates/community => app/community/templates}/types/text.html (100%) rename {templates/community => app/community/templates}/types/video.html (100%) rename {community/tests => app/community/templatetags}/__init__.py (100%) rename {community => app/community}/templatetags/community.py (100%) rename {companies => app/community/tests}/__init__.py (100%) rename {community => app/community}/tests/test_managers.py (94%) rename {community => app/community}/tests/test_models.py (91%) rename {community => app/community}/tests/test_views.py (85%) rename {community => app/community}/urls.py (86%) rename {community => app/community}/views.py (81%) rename {companies/migrations => app/companies}/__init__.py (100%) rename {companies => app/companies}/admin.py (71%) rename {companies => app/companies}/apps.py (73%) rename {companies => app/companies}/factories.py (91%) rename {companies => app/companies}/migrations/0001_initial.py (100%) rename {companies => app/companies}/migrations/0002_auto_20150416_1853.py (100%) rename {companies => app/companies}/migrations/0003_auto_20170814_0301.py (100%) rename {companies => app/companies}/migrations/0004_auto_20170821_2000.py (100%) rename {companies => app/companies}/migrations/0005_auto_20180705_0352.py (100%) rename {companies/templatetags => app/companies/migrations}/__init__.py (100%) rename {companies => app/companies}/models.py (94%) rename {custom_storages => app/companies/templatetags}/__init__.py (100%) rename {companies => app/companies}/templatetags/companies.py (100%) rename {companies => app/companies}/tests.py (72%) rename {config => app/config}/mime.types (100%) rename {config => app/config}/nginx.conf (100%) rename {downloads => app/custom_storages}/__init__.py (100%) rename {custom_storages => app/custom_storages}/storages.py (100%) rename {downloads/migrations => app/downloads}/__init__.py (100%) rename {downloads => app/downloads}/admin.py (82%) rename {downloads => app/downloads}/api.py (92%) rename {downloads => app/downloads}/apps.py (73%) rename {downloads => app/downloads}/factories.py (97%) rename {downloads => app/downloads}/managers.py (100%) rename {downloads => app/downloads}/migrations/0001_initial.py (100%) rename {downloads => app/downloads}/migrations/0002_auto_20150416_1853.py (100%) rename {downloads => app/downloads}/migrations/0003_auto_20150824_1612.py (100%) rename {downloads => app/downloads}/migrations/0004_auto_20170821_2000.py (100%) rename {downloads => app/downloads}/migrations/0005_move_release_page_content.py (100%) rename {downloads => app/downloads}/migrations/0006_auto_20180705_0352.py (100%) rename {downloads => app/downloads}/migrations/0007_auto_20220809_1655.py (100%) rename {downloads => app/downloads}/migrations/0008_auto_20220907_2102.py (100%) rename {downloads => app/downloads}/migrations/0009_releasefile_sigstore_bundle_file.py (100%) rename {downloads => app/downloads}/migrations/0010_releasefile_sbom_spdx2_file.py (100%) rename {downloads => app/downloads}/migrations/0011_alter_os_creator_alter_os_last_modified_by_and_more.py (100%) rename {downloads/templatetags => app/downloads/migrations}/__init__.py (100%) rename {downloads => app/downloads}/models.py (98%) rename {downloads => app/downloads}/search_indexes.py (97%) rename {downloads => app/downloads}/serializers.py (95%) rename {templates/account => app/downloads/templates}/base.html (100%) rename {templates/downloads => app/downloads/templates}/download-sources-box.html (100%) rename {templates/downloads => app/downloads/templates}/full_os_list.html (100%) rename {templates/downloads => app/downloads/templates}/homepage-downloads-box.html (100%) rename {templates/downloads => app/downloads/templates}/index.html (100%) rename {templates/downloads => app/downloads/templates}/os_list.html (100%) rename {templates/downloads => app/downloads/templates}/release_detail.html (100%) rename {templates/downloads => app/downloads/templates}/supernav.html (100%) rename {downloads/tests => app/downloads/templatetags}/__init__.py (100%) rename {downloads => app/downloads}/templatetags/download_tags.py (100%) rename {events => app/downloads/tests}/__init__.py (100%) rename {downloads => app/downloads}/tests/base.py (97%) rename {downloads => app/downloads}/tests/test_models.py (97%) rename {downloads => app/downloads}/tests/test_views.py (98%) rename {downloads => app/downloads}/urls.py (95%) rename {downloads => app/downloads}/views.py (96%) rename {events/management => app/events}/__init__.py (100%) rename {events => app/events}/admin.py (83%) rename {events => app/events}/apps.py (74%) rename {events => app/events}/factories.py (97%) rename {events => app/events}/forms.py (100%) rename {events => app/events}/importer.py (95%) rename {events/management/commands => app/events/management}/__init__.py (100%) rename {events/migrations => app/events/management/commands}/__init__.py (100%) rename {events => app/events}/management/commands/import_ics_calendars.py (100%) rename {events => app/events}/migrations/0001_initial.py (98%) rename {events => app/events}/migrations/0002_auto_20150321_1247.py (100%) rename {events => app/events}/migrations/0003_auto_20150416_1853.py (100%) rename {events => app/events}/migrations/0004_auto_20170814_0519.py (80%) rename {events => app/events}/migrations/0005_auto_20170821_2000.py (100%) rename {events => app/events}/migrations/0006_change_end_date_for_occurring_rules.py (100%) rename {events => app/events}/migrations/0007_auto_20180705_0352.py (100%) rename {events => app/events}/migrations/0008_alter_alarm_creator_alter_alarm_last_modified_by_and_more.py (100%) rename {events/templatetags => app/events/migrations}/__init__.py (100%) rename {events => app/events}/models.py (98%) rename {events => app/events}/search_indexes.py (97%) rename {templates/events => app/events/templates}/base.html (100%) rename {templates/events => app/events/templates}/calendar_list.html (100%) rename {templates/events => app/events/templates}/email/new_event.txt (100%) rename {templates/events => app/events/templates}/event_detail.html (100%) rename {templates/events => app/events/templates}/event_form.html (100%) rename {templates/events => app/events/templates}/event_form_thanks.html (100%) rename {templates/events => app/events/templates}/event_list.html (100%) rename {templates/events => app/events/templates}/event_list_past.html (100%) rename {templates/events => app/events/templates}/eventcategory_list.html (100%) rename {templates/events => app/events/templates}/eventlocation_list.html (100%) rename {templates/events => app/events/templates}/includes/time_tag.html (100%) rename {events/tests => app/events/templatetags}/__init__.py (100%) rename {events => app/events}/templatetags/events.py (90%) rename {fastly => app/events/tests}/__init__.py (100%) rename {events => app/events}/tests/events.ics (96%) rename {events => app/events}/tests/test_forms.py (97%) rename {events => app/events}/tests/test_importer.py (100%) rename {events => app/events}/tests/test_models.py (98%) rename {events => app/events}/tests/test_utils.py (99%) rename {events => app/events}/tests/test_views.py (98%) rename {events => app/events}/urls.py (97%) rename {events => app/events}/utils.py (100%) rename {events => app/events}/views.py (94%) rename {jobs => app/fastly}/__init__.py (100%) rename {fastly => app/fastly}/models.py (100%) rename {fastly => app/fastly}/utils.py (100%) rename {jobs/management => app/jobs}/__init__.py (100%) rename {jobs => app/jobs}/admin.py (86%) rename {jobs => app/jobs}/apps.py (69%) rename {jobs => app/jobs}/factories.py (97%) rename {jobs => app/jobs}/feeds.py (95%) rename {jobs => app/jobs}/forms.py (94%) rename {jobs => app/jobs}/listeners.py (98%) rename {jobs/management/commands => app/jobs/management}/__init__.py (100%) rename {jobs/migrations => app/jobs/management/commands}/__init__.py (100%) rename {jobs => app/jobs}/management/commands/expire_jobs.py (94%) rename {jobs => app/jobs}/management/commands/jobs_monthly_report.py (98%) rename {jobs => app/jobs}/managers.py (100%) rename {jobs => app/jobs}/migrations/0001_initial.py (100%) rename {jobs => app/jobs}/migrations/0002_auto_20150211_1634.py (100%) rename {jobs => app/jobs}/migrations/0003_auto_20150211_1738.py (100%) rename {jobs => app/jobs}/migrations/0004_auto_20150216_1544.py (100%) rename {jobs => app/jobs}/migrations/0005_job_other_job_type.py (100%) rename {jobs => app/jobs}/migrations/0006_region_nullable.py (100%) rename {jobs => app/jobs}/migrations/0007_auto_20150227_2223.py (100%) rename {jobs => app/jobs}/migrations/0008_auto_20150316_1205.py (100%) rename {jobs => app/jobs}/migrations/0009_auto_20150317_1815.py (100%) rename {jobs => app/jobs}/migrations/0010_auto_20150416_1853.py (100%) rename {jobs => app/jobs}/migrations/0011_jobreviewcomment.py (100%) rename {jobs => app/jobs}/migrations/0012_auto_20170809_1849.py (100%) rename {jobs => app/jobs}/migrations/0013_auto_20170810_1625.py (100%) rename {jobs => app/jobs}/migrations/0013_auto_20170810_1627.py (100%) rename {jobs => app/jobs}/migrations/0014_merge.py (100%) rename {jobs => app/jobs}/migrations/0015_auto_20170814_0301.py (100%) rename {jobs => app/jobs}/migrations/0016_auto_20170821_2000.py (100%) rename {jobs => app/jobs}/migrations/0017_auto_20180705_0348.py (100%) rename {jobs => app/jobs}/migrations/0018_auto_20180705_0352.py (100%) rename {jobs => app/jobs}/migrations/0019_job_submitted_by.py (100%) rename {jobs => app/jobs}/migrations/0020_auto_20191101_1601.py (100%) rename {jobs => app/jobs}/migrations/0021_alter_job_creator_alter_job_last_modified_by_and_more.py (100%) rename {jobs => app/jobs}/migrations/0022_alter_jobtype_options_alter_job_job_types_and_more.py (100%) rename {jobs/tests => app/jobs/migrations}/__init__.py (100%) rename {jobs => app/jobs}/models.py (96%) rename {jobs => app/jobs}/search_indexes.py (97%) rename {jobs => app/jobs}/signals.py (100%) rename {templates/jobs => app/jobs/templates}/base.html (100%) rename {templates/jobs => app/jobs/templates}/email/comment_was_posted.txt (100%) rename {templates/jobs => app/jobs/templates}/email/comment_was_posted_admin.txt (100%) rename {templates/jobs => app/jobs/templates}/email/job_was_approved.txt (100%) rename {templates/jobs => app/jobs/templates}/email/job_was_approved_subject.txt (100%) rename {templates/jobs => app/jobs/templates}/email/job_was_rejected.txt (100%) rename {templates/jobs => app/jobs/templates}/email/job_was_rejected_subject.txt (100%) rename {templates/jobs => app/jobs/templates}/email/job_was_submitted.txt (100%) rename {templates/jobs => app/jobs/templates}/email/job_was_submitted_subject.txt (100%) rename {templates/jobs => app/jobs/templates}/email/monthly_jobs_report.txt (100%) rename {templates/jobs => app/jobs/templates}/email/monthly_jobs_report_subject.txt (100%) rename {templates/jobs => app/jobs/templates}/featured_companies-widget.html (100%) rename {templates/jobs => app/jobs/templates}/header_content.html (100%) rename {templates/jobs => app/jobs/templates}/job_categories.html (100%) rename {templates/jobs => app/jobs/templates}/job_category_list.html (100%) rename {templates/jobs => app/jobs/templates}/job_detail.html (100%) rename {templates/jobs => app/jobs/templates}/job_form.html (100%) rename {templates/jobs => app/jobs/templates}/job_list.html (100%) rename {templates/jobs => app/jobs/templates}/job_location_list.html (100%) rename {templates/jobs => app/jobs/templates}/job_locations.html (100%) rename {templates/jobs => app/jobs/templates}/job_review.html (100%) rename {templates/jobs => app/jobs/templates}/job_telecommute_list.html (100%) rename {templates/jobs => app/jobs/templates}/job_thanks.html (100%) rename {templates/jobs => app/jobs/templates}/job_type_list.html (100%) rename {templates/jobs => app/jobs/templates}/job_types.html (100%) rename {templates/jobs => app/jobs/templates}/submit_a_job-widget.html (100%) rename {mailing => app/jobs/tests}/__init__.py (100%) rename {jobs => app/jobs}/tests/test_models.py (97%) rename {jobs => app/jobs}/tests/test_views.py (99%) rename {jobs => app/jobs}/urls.py (96%) rename {jobs => app/jobs}/views.py (96%) rename {mailing/migrations => app/mailing}/__init__.py (100%) rename {mailing => app/mailing}/admin.py (96%) rename {mailing => app/mailing}/apps.py (73%) rename {mailing => app/mailing}/forms.py (91%) rename {membership => app/mailing/migrations}/__init__.py (100%) rename {mailing => app/mailing}/models.py (100%) rename {templates/mailing => app/mailing/templates}/admin/base_email_template_form.html (100%) rename {mailing => app/mailing}/tests/__init__.py (100%) rename {mailing => app/mailing}/tests/forms.py (71%) rename {mailing => app/mailing}/tests/models.py (86%) rename {mailing => app/mailing}/tests/test_forms.py (93%) rename manage.py => app/manage.py (87%) rename {membership/migrations => app/membership}/__init__.py (100%) rename {membership => app/membership}/apps.py (72%) rename {membership/tests => app/membership/migrations}/__init__.py (100%) rename {minutes => app/membership/tests}/__init__.py (100%) rename {membership => app/membership}/tests/test_views.py (100%) rename {membership => app/membership}/urls.py (76%) rename {membership => app/membership}/views.py (77%) rename {minutes/management => app/minutes}/__init__.py (100%) rename {minutes => app/minutes}/admin.py (81%) rename {minutes => app/minutes}/apps.py (74%) rename {minutes => app/minutes}/feeds.py (94%) rename {minutes/management/commands => app/minutes/management}/__init__.py (100%) rename {minutes/migrations => app/minutes/management/commands}/__init__.py (100%) rename {minutes => app/minutes}/management/commands/move_meeting_notes.py (93%) rename {minutes => app/minutes}/managers.py (100%) rename {minutes => app/minutes}/migrations/0001_initial.py (100%) rename {minutes => app/minutes}/migrations/0002_auto_20150416_1853.py (100%) rename {minutes => app/minutes}/migrations/0003_alter_minutes_creator_alter_minutes_last_modified_by.py (100%) rename {minutes/tests => app/minutes/migrations}/__init__.py (100%) rename {minutes => app/minutes}/models.py (92%) rename {templates/minutes => app/minutes/templates}/minutes_detail.html (100%) rename {templates/minutes => app/minutes/templates}/minutes_list.html (100%) rename {nominations => app/minutes/tests}/__init__.py (100%) rename {minutes => app/minutes}/tests/test_models.py (96%) rename {minutes => app/minutes}/tests/test_views.py (98%) rename {minutes => app/minutes}/urls.py (81%) rename {minutes => app/minutes}/views.py (91%) rename {nominations/migrations => app/nominations}/__init__.py (100%) rename {nominations => app/nominations}/admin.py (93%) rename {nominations => app/nominations}/apps.py (72%) rename {nominations => app/nominations}/forms.py (97%) rename {nominations => app/nominations}/migrations/0001_initial.py (100%) rename {nominations => app/nominations}/migrations/0002_auto_20190514_1435.py (100%) rename {nominations/templatetags => app/nominations/migrations}/__init__.py (100%) rename {nominations => app/nominations}/models.py (99%) rename {templates/nominations => app/nominations/templates}/election_detail.html (100%) rename {templates/nominations => app/nominations/templates}/election_list.html (100%) rename {templates/nominations => app/nominations/templates}/nomination_accept_form.html (100%) rename {templates/nominations => app/nominations/templates}/nomination_detail.html (100%) rename {templates/nominations => app/nominations/templates}/nomination_form.html (100%) rename {templates/nominations => app/nominations/templates}/nominee_detail.html (100%) rename {templates/nominations => app/nominations/templates}/nominee_list.html (100%) rename {pages => app/nominations/templatetags}/__init__.py (100%) rename {nominations => app/nominations}/templatetags/nominations.py (100%) rename {nominations => app/nominations}/urls.py (96%) rename {nominations => app/nominations}/views.py (96%) rename {pages/management => app/pages}/__init__.py (100%) rename {pages => app/pages}/admin.py (93%) rename {pages => app/pages}/api.py (86%) rename {pages => app/pages}/apps.py (75%) rename {pages => app/pages}/factories.py (87%) rename {pages/management/commands => app/pages/management}/__init__.py (100%) rename {pages/migrations => app/pages/management/commands}/__init__.py (100%) rename {pages => app/pages}/management/commands/fix_success_story_images.py (97%) rename {pages => app/pages}/management/commands/import_pages_from_svn.py (97%) rename {pages => app/pages}/managers.py (100%) rename {pages => app/pages}/middleware.py (95%) rename {pages => app/pages}/migrations/0001_initial.py (96%) rename {pages => app/pages}/migrations/0002_auto_20150416_1853.py (100%) rename {pages => app/pages}/migrations/0003_auto_20230214_2113.py (100%) rename {pages => app/pages}/migrations/0004_alter_page_creator_alter_page_last_modified_by.py (100%) rename {pages/tests => app/pages/migrations}/__init__.py (100%) rename {pages => app/pages}/models.py (97%) rename {pages => app/pages}/parser.py (100%) rename {pages => app/pages}/search_indexes.py (96%) rename {pages => app/pages}/serializers.py (91%) rename {templates/pages => app/pages/templates}/default.html (100%) rename {templates/pages => app/pages/templates}/pep-page.html (100%) rename {templates/pages => app/pages/templates}/raw.html (100%) rename {pydotorg/settings => app/pages/tests}/__init__.py (100%) rename {pages => app/pages}/tests/base.py (93%) rename {pages => app/pages}/tests/fake_svn_content_checkout/about/content.ht (100%) rename {pages => app/pages}/tests/fake_svn_content_checkout/about/success/dlink/content.rst (100%) rename {pages => app/pages}/tests/fake_svn_content_checkout/community/content.ht (100%) rename {pages => app/pages}/tests/fake_svn_content_checkout/content.ht (100%) rename {pages => app/pages}/tests/test_api.py (95%) rename {pages => app/pages}/tests/test_models.py (95%) rename {pages => app/pages}/tests/test_parser.py (92%) rename {pages => app/pages}/tests/test_views.py (96%) rename {pages => app/pages}/urls.py (75%) rename {pages => app/pages}/views.py (94%) rename {pydotorg => app/pydotorg}/__init__.py (100%) rename {pydotorg => app/pydotorg}/celery.py (74%) rename {pydotorg => app/pydotorg}/compilers.py (100%) rename {pydotorg => app/pydotorg}/context_processors.py (100%) rename {pydotorg => app/pydotorg}/drf.py (100%) rename {pydotorg => app/pydotorg}/middleware.py (100%) rename {pydotorg => app/pydotorg}/mixins.py (100%) rename {pydotorg => app/pydotorg}/resources.py (100%) rename {pydotorg/tests => app/pydotorg/settings}/__init__.py (100%) rename {pydotorg => app/pydotorg}/settings/base.py (90%) rename {pydotorg => app/pydotorg}/settings/cabotage.py (97%) rename {pydotorg => app/pydotorg}/settings/local.py (98%) rename {pydotorg => app/pydotorg}/settings/pipeline.py (98%) rename {pydotorg => app/pydotorg}/settings/static.py (85%) rename {sponsors => app/pydotorg/tests}/__init__.py (100%) rename {pydotorg => app/pydotorg}/tests/test_classes.py (100%) rename {pydotorg => app/pydotorg}/tests/test_context_processors.py (99%) rename {pydotorg => app/pydotorg}/tests/test_middleware.py (100%) rename {pydotorg => app/pydotorg}/tests/test_resources.py (92%) rename {pydotorg => app/pydotorg}/tests/test_views.py (97%) rename {pydotorg => app/pydotorg}/urls.py (95%) rename {pydotorg => app/pydotorg}/urls_api.py (71%) rename {pydotorg => app/pydotorg}/views.py (94%) rename {pydotorg => app/pydotorg}/wsgi.py (94%) rename {sponsors/management => app/sponsors}/__init__.py (100%) rename {sponsors => app/sponsors}/admin.py (99%) rename {sponsors => app/sponsors}/api.py (93%) rename {sponsors => app/sponsors}/apps.py (73%) rename {sponsors => app/sponsors}/contracts.py (100%) rename {sponsors => app/sponsors}/cookies.py (100%) rename {sponsors => app/sponsors}/exceptions.py (100%) rename {sponsors => app/sponsors}/forms.py (99%) rename {sponsors/management/commands => app/sponsors/management}/__init__.py (100%) rename {sponsors/migrations => app/sponsors/management/commands}/__init__.py (100%) rename {sponsors => app/sponsors}/management/commands/check_sponsorship_assets_due_date.py (94%) rename {sponsors => app/sponsors}/management/commands/create_contracts.py (96%) rename {sponsors => app/sponsors}/management/commands/create_pycon_vouchers_for_sponsors.py (98%) rename {sponsors => app/sponsors}/management/commands/fullfill_pycon_2022.py (97%) rename {sponsors => app/sponsors}/migrations/0001_initial.py (100%) rename {sponsors => app/sponsors}/migrations/0002_auto_20150416_1853.py (100%) rename {sponsors => app/sponsors}/migrations/0003_auto_20170821_2000.py (100%) rename {sponsors => app/sponsors}/migrations/0004_auto_20201014_1622.py (100%) rename {sponsors => app/sponsors}/migrations/0005_auto_20201015_0908.py (100%) rename {sponsors => app/sponsors}/migrations/0006_auto_20201016_1517.py (100%) rename {sponsors => app/sponsors}/migrations/0007_auto_20201021_1410.py (100%) rename {sponsors => app/sponsors}/migrations/0008_auto_20201028_1814.py (100%) rename {sponsors => app/sponsors}/migrations/0009_auto_20201103_1259.py (100%) rename {sponsors => app/sponsors}/migrations/0010_auto_20201103_1313.py (100%) rename {sponsors => app/sponsors}/migrations/0011_auto_20201111_1724.py (100%) rename {sponsors => app/sponsors}/migrations/0012_sponsorship_for_modified_package.py (100%) rename {sponsors => app/sponsors}/migrations/0013_sponsorbenefit_benefit_internal_value.py (100%) rename {sponsors => app/sponsors}/migrations/0014_auto_20201116_1437.py (100%) rename {sponsors => app/sponsors}/migrations/0015_auto_20201117_1739.py (100%) rename {sponsors => app/sponsors}/migrations/0016_auto_20201119_1448.py (100%) rename {sponsors => app/sponsors}/migrations/0017_sponsorbenefit_added_by_user.py (100%) rename {sponsors => app/sponsors}/migrations/0018_auto_20201201_1659.py (100%) rename {sponsors => app/sponsors}/migrations/0019_sponsor_twitter_handle.py (100%) rename {sponsors => app/sponsors}/migrations/0019_statementofwork.py (100%) rename {sponsors => app/sponsors}/migrations/0020_auto_20201210_1802.py (100%) rename {sponsors => app/sponsors}/migrations/0020_sponsorshipbenefit_unavailable.py (100%) rename {sponsors => app/sponsors}/migrations/0021_auto_20201211_2120.py (100%) rename {sponsors => app/sponsors}/migrations/0022_sponsorcontact_administrative.py (100%) rename {sponsors => app/sponsors}/migrations/0023_merge_20210406_1522.py (100%) rename {sponsors => app/sponsors}/migrations/0024_auto_20210414_1449.py (100%) rename {sponsors => app/sponsors}/migrations/0025_auto_20210416_1939.py (100%) rename {sponsors => app/sponsors}/migrations/0026_auto_20210416_1940.py (100%) rename {sponsors => app/sponsors}/migrations/0027_sponsorbenefit_program_name.py (100%) rename {sponsors => app/sponsors}/migrations/0028_auto_20210707_1426.py (100%) rename {sponsors => app/sponsors}/migrations/0029_auto_20210715_2015.py (100%) rename {sponsors => app/sponsors}/migrations/0030_auto_20210715_2023.py (100%) rename {sponsors => app/sponsors}/migrations/0031_auto_20210810_1232.py (100%) rename {sponsors => app/sponsors}/migrations/0032_sponsorcontact_accounting.py (100%) rename {sponsors => app/sponsors}/migrations/0033_tieredquantity_tieredquantityconfiguration.py (100%) rename {sponsors => app/sponsors}/migrations/0034_contract_document_docx.py (100%) rename {sponsors => app/sponsors}/migrations/0035_auto_20210826_1929.py (100%) rename {sponsors => app/sponsors}/migrations/0036_auto_20210826_1930.py (100%) rename {sponsors => app/sponsors}/migrations/0037_sponsorship_package.py (100%) rename {sponsors => app/sponsors}/migrations/0038_auto_20210827_1223.py (100%) rename {sponsors => app/sponsors}/migrations/0039_auto_20210827_1248.py (100%) rename {sponsors => app/sponsors}/migrations/0040_auto_20210827_1313.py (100%) rename {sponsors => app/sponsors}/migrations/0041_auto_20210827_1313.py (100%) rename {sponsors => app/sponsors}/migrations/0042_auto_20210827_1318.py (100%) rename {sponsors => app/sponsors}/migrations/0043_auto_20210827_1343.py (100%) rename {sponsors => app/sponsors}/migrations/0044_auto_20210827_1344.py (100%) rename {sponsors => app/sponsors}/migrations/0045_add_added_by_user_sponsorbenefit.py (100%) rename {sponsors => app/sponsors}/migrations/0046_sponsorshippackage_advertise.py (100%) rename {sponsors => app/sponsors}/migrations/0047_auto_20210908_1357.py (100%) rename {sponsors => app/sponsors}/migrations/0048_auto_20210915_1425.py (100%) rename {sponsors => app/sponsors}/migrations/0049_sponsoremailnotificationtemplate.py (100%) rename {sponsors => app/sponsors}/migrations/0050_emailtargetable_emailtargetableconfiguration.py (100%) rename {sponsors => app/sponsors}/migrations/0051_auto_20211022_1403.py (100%) rename {sponsors => app/sponsors}/migrations/0052_requiredimgasset_requiredimgassetconfiguration.py (100%) rename {sponsors => app/sponsors}/migrations/0053_genericasset_imgasset.py (95%) rename {sponsors => app/sponsors}/migrations/0054_auto_20211026_1432.py (100%) rename {sponsors => app/sponsors}/migrations/0055_auto_20211026_1512.py (100%) rename {sponsors => app/sponsors}/migrations/0056_textasset.py (100%) rename {sponsors => app/sponsors}/migrations/0057_auto_20211026_1529.py (100%) rename {sponsors => app/sponsors}/migrations/0058_auto_20211029_1427.py (100%) rename {sponsors => app/sponsors}/migrations/0059_auto_20211029_1503.py (100%) rename {sponsors => app/sponsors}/migrations/0060_auto_20211111_1526.py (100%) rename {sponsors => app/sponsors}/migrations/0061_auto_20211108_1419.py (100%) rename {sponsors => app/sponsors}/migrations/0062_auto_20211111_1529.py (100%) rename {sponsors => app/sponsors}/migrations/0063_auto_20211220_1422.py (100%) rename {sponsors => app/sponsors}/migrations/0064_sponsorshippackage_slug.py (100%) rename {sponsors => app/sponsors}/migrations/0065_auto_20211223_1309.py (100%) rename {sponsors => app/sponsors}/migrations/0066_auto_20211223_1318.py (100%) rename {sponsors => app/sponsors}/migrations/0067_sponsorbenefit_a_la_carte.py (100%) rename {sponsors => app/sponsors}/migrations/0068_auto_20220110_1841.py (100%) rename {sponsors => app/sponsors}/migrations/0069_auto_20220110_2148.py (92%) rename {sponsors => app/sponsors}/migrations/0070_auto_20220111_2055.py (91%) rename {sponsors => app/sponsors}/migrations/0071_auto_20220113_1843.py (100%) rename {sponsors => app/sponsors}/migrations/0072_auto_20220125_2005.py (100%) rename {sponsors => app/sponsors}/migrations/0073_auto_20220128_1906.py (93%) rename {sponsors => app/sponsors}/migrations/0074_auto_20220211_1659.py (100%) rename {sponsors => app/sponsors}/migrations/0075_auto_20220303_2023.py (100%) rename {sponsors => app/sponsors}/migrations/0076_auto_20220728_1550.py (100%) rename {sponsors => app/sponsors}/migrations/0077_sponsorshipcurrentyear.py (100%) rename {sponsors => app/sponsors}/migrations/0078_init_current_year_singleton.py (100%) rename {sponsors => app/sponsors}/migrations/0079_index_to_force_singleton.py (100%) rename {sponsors => app/sponsors}/migrations/0080_auto_20220728_1644.py (100%) rename {sponsors => app/sponsors}/migrations/0081_sponsorship_application_year.py (100%) rename {sponsors => app/sponsors}/migrations/0082_auto_20220729_1613.py (100%) rename {sponsors => app/sponsors}/migrations/0083_auto_20220729_1624.py (100%) rename {sponsors => app/sponsors}/migrations/0084_init_configured_objs_year.py (100%) rename {sponsors => app/sponsors}/migrations/0085_auto_20220730_0945.py (100%) rename {sponsors => app/sponsors}/migrations/0086_auto_20220809_1655.py (100%) rename {sponsors => app/sponsors}/migrations/0087_auto_20220810_1647.py (100%) rename {sponsors => app/sponsors}/migrations/0088_auto_20220810_1655.py (100%) rename {sponsors => app/sponsors}/migrations/0089_auto_20220812_1312.py (100%) rename {sponsors => app/sponsors}/migrations/0090_auto_20220812_1314.py (100%) rename {sponsors => app/sponsors}/migrations/0091_sponsorshippackage_allow_a_la_carte.py (100%) rename {sponsors => app/sponsors}/migrations/0092_auto_20220816_1517.py (100%) rename {sponsors => app/sponsors}/migrations/0093_auto_20230214_2113.py (100%) rename {sponsors => app/sponsors}/migrations/0094_sponsorship_locked.py (91%) rename {sponsors => app/sponsors}/migrations/0095_auto_20231214_2025.py (100%) rename {sponsors => app/sponsors}/migrations/0096_auto_20231214_2108.py (100%) rename {sponsors => app/sponsors}/migrations/0097_sponsorship_renewal.py (100%) rename {sponsors => app/sponsors}/migrations/0098_auto_20231219_1910.py (100%) rename {sponsors => app/sponsors}/migrations/0099_auto_20231224_1854.py (100%) rename {sponsors => app/sponsors}/migrations/0100_auto_20240107_1054.py (100%) rename {sponsors => app/sponsors}/migrations/0101_sponsor_linked_in_page_url.py (100%) rename {sponsors => app/sponsors}/migrations/0102_auto_20240509_2037.py (100%) rename {sponsors => app/sponsors}/migrations/0103_alter_benefitfeature_polymorphic_ctype_and_more.py (100%) rename {sponsors/pandoc_filters => app/sponsors/migrations}/__init__.py (100%) create mode 100644 app/sponsors/models/__init__.py rename {sponsors => app/sponsors}/models/assets.py (97%) rename {sponsors => app/sponsors}/models/benefits.py (98%) rename {sponsors => app/sponsors}/models/contract.py (98%) rename {sponsors => app/sponsors}/models/enums.py (100%) rename {sponsors => app/sponsors}/models/managers.py (91%) rename {sponsors => app/sponsors}/models/notifications.py (97%) rename {sponsors => app/sponsors}/models/sponsors.py (98%) rename {sponsors => app/sponsors}/models/sponsorship.py (98%) rename {sponsors => app/sponsors}/notifications.py (99%) rename {sponsors/templatetags => app/sponsors/pandoc_filters}/__init__.py (100%) rename {sponsors => app/sponsors}/pandoc_filters/pagebreak.py (100%) rename {sponsors => app/sponsors}/reference.docx (100%) rename {sponsors => app/sponsors}/serializers.py (95%) rename {templates/sponsors => app/sponsors/templates}/admin/approve_application.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/clone_application_config_form.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/contract_change_form.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/contracts/sponsorship-agreement.md (100%) rename {templates/sponsors => app/sponsors/templates}/admin/execute_contract.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/list_uploaded_assets.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/nullify_contract.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/reject_application.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/rollback_sponsorship_to_editing.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/send_contract.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/send_sponsors_notification.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/sponsors_sponsorshipcurrentyear_changelist.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/sponsorship_change_form.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/sponsorshipbenefit_change_form.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/unlock.html (100%) rename {templates/sponsors => app/sponsors/templates}/admin/update_related_sponsorships.html (100%) rename {templates/sponsors => app/sponsors/templates}/email/psf_contract.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/psf_contract_subject.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/psf_new_application.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/psf_new_application_subject.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/psf_rejected_sponsorship.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/psf_rejected_sponsorship_subject.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/sponsor_contract.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/sponsor_contract_subject.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/sponsor_expiring_assets.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/sponsor_expiring_assets_subject.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/sponsor_new_application.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/sponsor_new_application_subject.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/sponsor_rejected_sponsorship.txt (100%) rename {templates/sponsors => app/sponsors/templates}/email/sponsor_rejected_sponsorship_subject.txt (100%) rename {templates/sponsors => app/sponsors/templates}/new_sponsorship_application_form.html (100%) rename {templates/sponsors => app/sponsors/templates}/partials/full_sponsorship.txt (100%) rename {templates/sponsors => app/sponsors/templates}/partials/sponsors-list.html (100%) rename {templates/sponsors => app/sponsors/templates}/sponsor_list.html (100%) rename {templates/sponsors => app/sponsors/templates}/sponsorship_application_finished.html (100%) rename {templates/sponsors => app/sponsors/templates}/sponsorship_benefits_form.html (100%) rename {sponsors/tests => app/sponsors/templatetags}/__init__.py (100%) rename {sponsors => app/sponsors}/templatetags/sponsors.py (94%) rename {successstories => app/sponsors/tests}/__init__.py (100%) rename {sponsors => app/sponsors}/tests/baker_recipes.py (89%) rename {sponsors => app/sponsors}/tests/test_admin.py (95%) rename {sponsors => app/sponsors}/tests/test_api.py (98%) rename {sponsors => app/sponsors}/tests/test_contracts.py (95%) rename {sponsors => app/sponsors}/tests/test_forms.py (99%) rename {sponsors => app/sponsors}/tests/test_management_command.py (89%) rename {sponsors => app/sponsors}/tests/test_managers.py (97%) rename {sponsors => app/sponsors}/tests/test_models.py (99%) rename {sponsors => app/sponsors}/tests/test_notifications.py (99%) rename {sponsors => app/sponsors}/tests/test_templatetags.py (96%) rename {sponsors => app/sponsors}/tests/test_use_cases.py (98%) rename {sponsors => app/sponsors}/tests/test_views.py (99%) rename {sponsors => app/sponsors}/tests/test_views_admin.py (98%) rename {sponsors => app/sponsors}/tests/utils.py (100%) rename {sponsors => app/sponsors}/urls.py (91%) rename {sponsors => app/sponsors}/use_cases.py (96%) rename {sponsors => app/sponsors}/utils.py (100%) rename {sponsors => app/sponsors}/views.py (97%) rename {sponsors => app/sponsors}/views_admin.py (97%) rename {static => app/static}/apple-touch-icon-114x114-precomposed.png (100%) rename {static => app/static}/apple-touch-icon-144x144-precomposed.png (100%) rename {static => app/static}/apple-touch-icon-72x72-precomposed.png (100%) rename {static => app/static}/apple-touch-icon-precomposed.png (100%) rename {static => app/static}/community_logos/README.txt (100%) rename {static => app/static}/community_logos/python-logo-generic.svg (100%) rename {static => app/static}/community_logos/python-logo-inkscape.svg (100%) rename {static => app/static}/community_logos/python-logo-master-v3-TM-flattened.png (100%) rename {static => app/static}/community_logos/python-logo-master-v3-TM.png (100%) rename {static => app/static}/community_logos/python-logo-master-v3-TM.psd (100%) rename {static => app/static}/community_logos/python-logo.png (100%) rename {static => app/static}/community_logos/python-powered-h-100x130.png (100%) rename {static => app/static}/community_logos/python-powered-h-140x182.png (100%) rename {static => app/static}/community_logos/python-powered-h-50x65.png (100%) rename {static => app/static}/community_logos/python-powered-h-70x91.png (100%) rename {static => app/static}/community_logos/python-powered-h.svg (100%) rename {static => app/static}/community_logos/python-powered-w-100x40.png (100%) rename {static => app/static}/community_logos/python-powered-w-140x56.png (100%) rename {static => app/static}/community_logos/python-powered-w-200x80.png (100%) rename {static => app/static}/community_logos/python-powered-w-70x28.png (100%) rename {static => app/static}/community_logos/python-powered-w.svg (100%) rename {static => app/static}/config.rb (100%) rename {static => app/static}/favicon.ico (100%) rename {static => app/static}/fonts/FluxBold.eot (100%) rename {static => app/static}/fonts/FluxBold.ttf (100%) rename {static => app/static}/fonts/FluxBold.woff (100%) rename {static => app/static}/fonts/FluxBoldItalic.eot (100%) rename {static => app/static}/fonts/FluxBoldItalic.ttf (100%) rename {static => app/static}/fonts/FluxBoldItalic.woff (100%) rename {static => app/static}/fonts/FluxItalic.eot (100%) rename {static => app/static}/fonts/FluxItalic.ttf (100%) rename {static => app/static}/fonts/FluxItalic.woff (100%) rename {static => app/static}/fonts/FluxRegular.eot (100%) rename {static => app/static}/fonts/FluxRegular.ttf (100%) rename {static => app/static}/fonts/FluxRegular.woff (100%) rename {static => app/static}/fonts/FontAwesome.otf (100%) rename {static => app/static}/fonts/Pythonicon.eot (100%) rename {static => app/static}/fonts/Pythonicon.json (100%) rename {static => app/static}/fonts/Pythonicon.svg (100%) rename {static => app/static}/fonts/Pythonicon.ttf (100%) rename {static => app/static}/fonts/Pythonicon.woff (100%) rename {static => app/static}/fonts/SIL OFL Font License - Source Sans Pro.txt (100%) rename {static => app/static}/fonts/SourceSansPro-Bold-webfont.eot (100%) rename {static => app/static}/fonts/SourceSansPro-Bold-webfont.svg (100%) rename {static => app/static}/fonts/SourceSansPro-Bold-webfont.ttf (100%) rename {static => app/static}/fonts/SourceSansPro-Bold-webfont.woff (100%) rename {static => app/static}/fonts/SourceSansPro-It-webfont.eot (100%) rename {static => app/static}/fonts/SourceSansPro-It-webfont.svg (100%) rename {static => app/static}/fonts/SourceSansPro-It-webfont.ttf (100%) rename {static => app/static}/fonts/SourceSansPro-It-webfont.woff (100%) rename {static => app/static}/fonts/SourceSansPro-Regular-webfont.eot (100%) rename {static => app/static}/fonts/SourceSansPro-Regular-webfont.svg (100%) rename {static => app/static}/fonts/SourceSansPro-Regular-webfont.ttf (100%) rename {static => app/static}/fonts/SourceSansPro-Regular-webfont.woff (100%) rename {static => app/static}/fonts/demo.html (100%) rename {static => app/static}/fonts/demo/demo.css (100%) rename {static => app/static}/fonts/demo/demo.js (100%) rename {static => app/static}/fonts/fontawesome-webfont.eot (100%) rename {static => app/static}/fonts/fontawesome-webfont.svg (100%) rename {static => app/static}/fonts/fontawesome-webfont.ttf (100%) rename {static => app/static}/fonts/fontawesome-webfont.woff (100%) rename {static => app/static}/fonts/fontawesome-webfont.woff2 (100%) rename {static => app/static}/fonts/lte-ie7.js (100%) rename {static => app/static}/fonts/style.css (100%) rename {static => app/static}/images/CCP.jpg (100%) rename {static => app/static}/images/ExowebGlossyLogo.png (100%) rename {static => app/static}/images/Google_Logo_25wht.gif (100%) rename {static => app/static}/images/Lucasfilm_logo.png (100%) rename {static => app/static}/images/OSAFLogo.gif (100%) rename {static => app/static}/images/OnlineDegreeReviews-Logo.png (100%) rename {static => app/static}/images/PythonPowered.gif (100%) rename {static => app/static}/images/PythonPoweredAnim.gif (100%) rename {static => app/static}/images/PythonPoweredAnimSmall.gif (100%) rename {static => app/static}/images/PythonPoweredSmall.gif (100%) rename {static => app/static}/images/README.txt (100%) rename {static => app/static}/images/Red_Hat.png (100%) rename {static => app/static}/images/activegrid.gif (100%) rename {static => app/static}/images/activestate_logo.gif (100%) rename {static => app/static}/images/arraylogo.jpg (100%) rename {static => app/static}/images/astilogo.gif (100%) rename {static => app/static}/images/batteries-included.jpg (100%) rename {static => app/static}/images/beslist.png (100%) rename {static => app/static}/images/bizrate.gif (100%) rename {static => app/static}/images/blank.gif (100%) rename {static => app/static}/images/bullet.gif (100%) rename {static => app/static}/images/button-on-bg.png (100%) rename {static => app/static}/images/canonical-logo.png (100%) rename {static => app/static}/images/cpacket_logo.jpg (100%) rename {static => app/static}/images/donate.png (100%) rename {static => app/static}/images/emd_logo.gif (100%) rename {static => app/static}/images/enthought.jpg (100%) rename {static => app/static}/images/enthought.png (100%) rename {static => app/static}/images/favicon16x16.ico (100%) rename {static => app/static}/images/finding-idle.png (100%) rename {static => app/static}/images/freewear-1.png (100%) rename {static => app/static}/images/freewear-logo.png (100%) rename {static => app/static}/images/globo_logo.gif (100%) rename {static => app/static}/images/google.gif (100%) rename {static => app/static}/images/header-bg.png (100%) rename {static => app/static}/images/header-bg2.png (100%) rename {static => app/static}/images/hitflip_logo.jpg (100%) rename {static => app/static}/images/hood_logo.gif (100%) rename {static => app/static}/images/hw128_28.gif (100%) rename {static => app/static}/images/infrastructure/dyn.png (100%) rename {static => app/static}/images/infrastructure/gandi.png (100%) rename {static => app/static}/images/infrastructure/osl.png (100%) rename {static => app/static}/images/infrastructure/pagerduty.png (100%) rename {static => app/static}/images/infrastructure/pingdom.png (100%) rename {static => app/static}/images/infrastructure/upfront.png (100%) rename {static => app/static}/images/infrastructure/xs4all.png (100%) rename {static => app/static}/images/ironport.gif (100%) rename {static => app/static}/images/knmp-logo.png (100%) rename {static => app/static}/images/logo_lincoln_loop.png (100%) rename {static => app/static}/images/microbit.png (100%) rename {static => app/static}/images/nav-off-bg.png (100%) rename {static => app/static}/images/nav-on-bg.png (100%) rename {static => app/static}/images/open_end_ab_logo.png (100%) rename {static => app/static}/images/openeye-logo.gif (100%) rename {static => app/static}/images/opensource-110x95.png (100%) rename {static => app/static}/images/oreilly_logo.gif (100%) rename {static => app/static}/images/osi-certified-120x100.gif (100%) rename {static => app/static}/images/pattern_banner.gif (100%) rename {static => app/static}/images/pep-0001-1.png (100%) rename {static => app/static}/images/psf-logo.gif (100%) rename {static => app/static}/images/py_mac-sq-64.png (100%) rename {static => app/static}/images/pyastra.jpg (100%) rename {static => app/static}/images/pycon-2010-banner.png (100%) rename {static => app/static}/images/pygoogle.jpg (100%) rename {static => app/static}/images/pynasa.jpg (100%) rename {static => app/static}/images/python-audio-100x40.png (100%) rename {static => app/static}/images/python-data-100x40.png (100%) rename {static => app/static}/images/python-logo.gif (100%) rename {static => app/static}/images/python-video-icon.png (100%) rename {static => app/static}/images/pythongear-logo.png (100%) rename {static => app/static}/images/pythonlogo.eps (100%) rename {static => app/static}/images/pythonlogo.pdf (100%) rename {static => app/static}/images/pythonlogo.png (100%) rename {static => app/static}/images/pythonlogo.tiff (100%) rename {static => app/static}/images/pyxp.jpg (100%) rename {static => app/static}/images/seo_moves.jpg (100%) rename {static => app/static}/images/strakt_logo.gif (100%) rename {static => app/static}/images/success/Carmanah.png (100%) rename {static => app/static}/images/success/Honeywell.png (100%) rename {static => app/static}/images/success/StAndrews.png (100%) rename {static => app/static}/images/success/afnic.fr.png (100%) rename {static => app/static}/images/success/forecastwatch.png (100%) rename {static => app/static}/images/success/frequentis.png (100%) rename {static => app/static}/images/success/journyx.png (100%) rename {static => app/static}/images/success/mayavi.jpg (100%) rename {static => app/static}/images/success/mmtk.jpg (100%) rename {static => app/static}/images/success/nasa.jpg (100%) rename {static => app/static}/images/success/natsworld.png (100%) rename {static => app/static}/images/success/standrews.jpg (100%) rename {static => app/static}/images/success/superleague.png (100%) rename {static => app/static}/images/success/tribon.jpg (100%) rename {static => app/static}/images/sun_logo.png (100%) rename {static => app/static}/images/tabblo.png (100%) rename {static => app/static}/images/terminal-in-finder.png (100%) rename {static => app/static}/images/trans.gif (100%) rename {static => app/static}/images/uniblue-logo.jpg (100%) rename {static => app/static}/images/wargaming.png (100%) rename {static => app/static}/images/winglogo.gif (100%) rename {static => app/static}/images/worldmap.jpg (100%) rename {static => app/static}/images/zeomega.gif (100%) rename {static => app/static}/images/zeuux.jpg (100%) rename {static => app/static}/images/zimbio_corp_logo.gif (100%) rename {static => app/static}/images/zope_logo.gif (100%) rename {static => app/static}/img/bg_direction_nav.png (100%) rename {static => app/static}/img/landing-about.png (100%) rename {static => app/static}/img/landing-community.png (100%) rename {static => app/static}/img/landing-docs.png (100%) rename {static => app/static}/img/landing-downloads.png (100%) rename {static => app/static}/img/psf-logo.png (100%) rename {static => app/static}/img/psf-logo@2x.png (100%) rename {static => app/static}/img/psf-logo_print.png (100%) rename {static => app/static}/img/python-logo-large.png (100%) rename {static => app/static}/img/python-logo.png (100%) rename {static => app/static}/img/python-logo@2x.png (100%) rename {static => app/static}/img/python-logo_print.png (100%) rename {static => app/static}/img/sample-gmap.png (100%) rename {static => app/static}/img/sponsors/tick-placeholder.png (100%) rename {static => app/static}/img/sponsors/tick.svg (100%) rename {static => app/static}/img/sponsors/title-1.svg (100%) rename {static => app/static}/img/sponsors/title-2.svg (100%) rename {static => app/static}/img/sponsors/title-3.svg (100%) rename {static => app/static}/img/sponsors/title-4.svg (100%) rename {static => app/static}/img/sponsors/title-5.svg (100%) rename {static => app/static}/img/sponsors/title-6.svg (100%) rename {static => app/static}/img/success-glow2.png (100%) rename {static => app/static}/js/libs/html-includes.js (100%) rename {static => app/static}/js/libs/jquery-1.8.2.min.js (100%) rename {static => app/static}/js/libs/jquery-ui-1.12.1.min.js (100%) rename {static => app/static}/js/libs/masonry.pkgd.min.js (100%) rename {static => app/static}/js/libs/modernizr.js (100%) rename {static => app/static}/js/plugins.js (100%) rename {static => app/static}/js/plugins/IE7.js (97%) rename {static => app/static}/js/plugins/IE8.js (97%) rename {static => app/static}/js/plugins/IE9.js (97%) rename {static => app/static}/js/plugins/getComputedStyle.js (100%) rename {static => app/static}/js/plugins/ie7-squish.js (97%) rename {static => app/static}/js/plugins/jquery.cookie.js (100%) rename {static => app/static}/js/script.js (100%) rename {static => app/static}/js/sponsors/applicationForm.js (100%) rename {static => app/static}/metro-icon-144x144.png (100%) rename {static => app/static}/opengraph-icon-200x200.png (100%) rename {static => app/static}/sass/_FIX-THESE (100%) rename {static => app/static}/sass/_base.scss (100%) rename {static => app/static}/sass/_debug.scss (100%) rename {static => app/static}/sass/_flexslider.scss (100%) rename {static => app/static}/sass/_fonts.scss (100%) rename {static => app/static}/sass/_functions.scss (100%) rename {static => app/static}/sass/_layout.scss (100%) rename {static => app/static}/sass/_mixins.scss (100%) rename {static => app/static}/sass/mq.css (100%) rename {static => app/static}/sass/mq.scss (100%) rename {static => app/static}/sass/no-mq.css (100%) rename {static => app/static}/sass/no-mq.scss (100%) rename {static => app/static}/sass/style.css (100%) rename {static => app/static}/sass/style.scss (100%) rename {static => app/static}/source_files/artboard.psd (100%) rename {static => app/static}/source_files/glow.psd (100%) rename {static => app/static}/source_files/psf-top-logo-beta.psd (100%) rename {static => app/static}/source_files/python logo.svg (100%) rename {static => app/static}/source_files/python-logo-mods-v2.ai (100%) rename {static => app/static}/source_files/python-logo-mods.ai (100%) rename {static => app/static}/source_files/python-top-logo-beta.psd (100%) rename {static => app/static}/source_files/python-top-logo.psd (100%) rename {static => app/static}/stylesheets/console.css (100%) rename {static => app/static}/stylesheets/font-awesome.min.css (100%) rename {successstories/migrations => app/successstories}/__init__.py (100%) rename {successstories => app/successstories}/admin.py (87%) rename {successstories => app/successstories}/apps.py (71%) rename {successstories => app/successstories}/factories.py (95%) rename {successstories => app/successstories}/forms.py (90%) rename {successstories => app/successstories}/managers.py (100%) rename {successstories => app/successstories}/migrations/0001_initial.py (100%) rename {successstories => app/successstories}/migrations/0002_auto_20150416_1853.py (100%) rename {successstories => app/successstories}/migrations/0003_auto_20170720_1655.py (100%) rename {successstories => app/successstories}/migrations/0004_auto_20170724_0507.py (100%) rename {successstories => app/successstories}/migrations/0005_auto_20170726_0645.py (100%) rename {successstories => app/successstories}/migrations/0006_auto_20170726_0824.py (98%) rename {successstories => app/successstories}/migrations/0007_remove_story_weight.py (100%) rename {successstories => app/successstories}/migrations/0008_auto_20170821_2000.py (100%) rename {successstories => app/successstories}/migrations/0009_auto_20180705_0352.py (100%) rename {successstories => app/successstories}/migrations/0010_story_submitted_by.py (100%) rename {successstories => app/successstories}/migrations/0011_auto_20220127_1923.py (100%) rename {successstories => app/successstories}/migrations/0012_alter_story_creator_alter_story_last_modified_by.py (100%) rename {successstories/templatetags => app/successstories/migrations}/__init__.py (100%) rename {successstories => app/successstories}/models.py (95%) rename {templates/successstories => app/successstories/templates}/base.html (100%) rename {templates/successstories => app/successstories/templates}/story_detail.html (100%) rename {templates/successstories => app/successstories/templates}/story_form.html (100%) rename {templates/successstories => app/successstories/templates}/story_list.html (100%) rename {templates/successstories => app/successstories/templates}/storycategory_detail.html (100%) rename {templates/successstories => app/successstories/templates}/supernav.html (100%) rename {successstories/tests => app/successstories/templatetags}/__init__.py (100%) rename {successstories => app/successstories}/templatetags/successstories.py (89%) rename {users => app/successstories/tests}/__init__.py (100%) rename {successstories => app/successstories}/tests/test_forms.py (93%) rename {successstories => app/successstories}/tests/test_models.py (89%) rename {successstories => app/successstories}/tests/test_templatetags.py (95%) rename {successstories => app/successstories}/tests/test_utils.py (91%) rename {successstories => app/successstories}/tests/test_views.py (98%) rename {successstories => app/successstories}/urls.py (91%) rename {successstories => app/successstories}/utils.py (100%) rename {successstories => app/successstories}/views.py (87%) rename {templates => app/templates}/403.html (100%) rename {templates => app/templates}/404.html (100%) rename {templates => app/templates}/500.html (100%) rename {templates => app/templates}/admin/base_site.html (100%) rename {templates => app/templates}/base.html (100%) rename {templates => app/templates}/components/blog-posts.html (100%) rename {templates => app/templates}/components/event-posts.html (100%) rename {templates => app/templates}/components/navigation-widget.html (100%) rename {templates => app/templates}/components/psf-widget.html (100%) rename {templates => app/templates}/components/success-story.html (100%) rename {templates => app/templates}/docs/index.html (100%) rename {templates => app/templates}/humans.txt (100%) rename {templates => app/templates}/includes/authenticated.html (100%) rename {templates => app/templates}/psf/default.html (100%) rename {templates => app/templates}/psf/full-width.html (100%) rename {templates => app/templates}/psf/index.html (100%) rename {templates => app/templates}/psf/sponsors-list.html (100%) rename {templates => app/templates}/pypl/index.html (100%) rename {templates => app/templates}/python/about.html (100%) rename {templates => app/templates}/python/documentation.html (100%) rename {templates => app/templates}/python/events.html (100%) rename {templates => app/templates}/python/index.html (100%) rename {templates => app/templates}/python/inner.html (100%) rename {templates => app/templates}/python/shell.html (100%) rename {templates => app/templates}/registration/logged_out.html (100%) rename {templates => app/templates}/registration/login.html (100%) rename {templates => app/templates}/robots.txt (100%) rename {templates => app/templates}/search/includes/downloads.release.html (100%) rename {templates => app/templates}/search/includes/events.calendar.html (100%) rename {templates => app/templates}/search/includes/events.event.html (100%) rename {templates => app/templates}/search/includes/jobs.job.html (100%) rename {templates => app/templates}/search/includes/jobs.job_category.html (100%) rename {templates => app/templates}/search/includes/jobs.job_type.html (100%) rename {templates => app/templates}/search/includes/pages.page.html (100%) rename {templates => app/templates}/search/indexes/downloads/release_text.txt (100%) rename {templates => app/templates}/search/indexes/events/calendar_text.txt (100%) rename {templates => app/templates}/search/indexes/events/event_text.txt (100%) rename {templates => app/templates}/search/indexes/jobs/job_text.txt (100%) rename {templates => app/templates}/search/indexes/jobs/jobcategory_text.txt (100%) rename {templates => app/templates}/search/indexes/jobs/jobtype_text.txt (100%) rename {templates => app/templates}/search/indexes/pages/page_text.txt (100%) rename {templates => app/templates}/search/search.html (100%) rename {templates => app/templates}/shop/index.html (100%) rename {templates => app/templates}/sitetree/breadcrumbs.html (100%) rename {templates => app/templates}/sitetree/footer.html (100%) rename {templates => app/templates}/sitetree/footer_children.html (100%) rename {templates => app/templates}/sitetree/menu.html (100%) rename {templates => app/templates}/sitetree/sidebar_menu.html (100%) rename {templates => app/templates}/sitetree/sidebar_menu_root.html (100%) rename {templates => app/templates}/sitetree/submenu.html (100%) rename {templates => app/templates}/sitetree/submenu_children.html (100%) rename {templates => app/templates}/sitetree/top.html (100%) rename {templates => app/templates}/waitforit.html (100%) rename {users/migrations => app/users}/__init__.py (100%) rename {users => app/users}/actions.py (100%) rename {users => app/users}/admin.py (95%) rename {users => app/users}/apps.py (67%) rename {users => app/users}/factories.py (96%) rename {users => app/users}/forms.py (98%) rename {users => app/users}/listeners.py (89%) rename {users => app/users}/managers.py (100%) rename {users => app/users}/migrations/0001_initial.py (100%) rename {users => app/users}/migrations/0002_auto_20150416_1853.py (100%) rename {users => app/users}/migrations/0003_auto_20150503_2026.py (100%) rename {users => app/users}/migrations/0004_auto_20150503_2100.py (100%) rename {users => app/users}/migrations/0005_user_public_profile.py (100%) rename {users => app/users}/migrations/0006_auto_20150503_2124.py (100%) rename {users => app/users}/migrations/0007_auto_20150604_1555.py (100%) rename {users => app/users}/migrations/0008_auto_20170814_0301.py (100%) rename {users => app/users}/migrations/0009_auto_20170821_2000.py (100%) rename {users => app/users}/migrations/0010_auto_20170828_1906.py (100%) rename {users => app/users}/migrations/0011_auto_20170902_0930.py (100%) rename {users => app/users}/migrations/0012_usergroup.py (100%) rename {users => app/users}/migrations/0013_auto_20180705_0348.py (100%) rename {users => app/users}/migrations/0014_auto_20210801_2332.py (100%) rename {users => app/users}/migrations/0015_alter_user_first_name.py (100%) rename {users/templatetags => app/users/migrations}/__init__.py (100%) rename {users => app/users}/models.py (98%) rename {templates/downloads => app/users/templates/account}/base.html (100%) rename {templates => app/users/templates}/account/login.html (100%) rename {templates => app/users/templates}/account/logout.html (100%) rename {templates => app/users/templates}/account/password_change.html (100%) rename {templates => app/users/templates}/account/signup.html (100%) rename {templates => app/users/templates}/account/verification_sent.html (100%) rename {templates/users => app/users/templates}/base.html (100%) rename {templates/users => app/users/templates}/list_user_sponsorships.html (100%) rename {templates/users => app/users/templates}/membership.html (100%) rename {templates/users => app/users/templates}/membership_form.html (100%) rename {templates/users => app/users/templates}/membership_thanks.html (100%) rename {templates/users => app/users/templates}/membership_vote_affirm.html (100%) rename {templates/users => app/users/templates}/membership_vote_affirm_done.html (100%) rename {templates/users => app/users/templates}/nominations_view.html (100%) rename {templates/users => app/users/templates}/sponsor_info_update.html (100%) rename {templates/users => app/users/templates}/sponsor_select.html (100%) rename {templates/users => app/users/templates}/sponsorship_assets_update.html (100%) rename {templates/users => app/users/templates}/sponsorship_assets_view.html (100%) rename {templates/users => app/users/templates}/sponsorship_detail.html (100%) rename {templates/users => app/users/templates}/user_detail.html (100%) rename {templates/users => app/users/templates}/user_form.html (100%) rename {users/tests => app/users/templatetags}/__init__.py (100%) rename {users => app/users}/templatetags/users_tags.py (95%) rename {work_groups => app/users/tests}/__init__.py (100%) rename {users => app/users}/tests/test_forms.py (98%) rename {users => app/users}/tests/test_models.py (95%) rename {users => app/users}/tests/test_templatetags.py (94%) rename {users => app/users}/tests/test_views.py (98%) rename {users => app/users}/urls.py (98%) rename {users => app/users}/validators.py (100%) rename {users => app/users}/views.py (92%) rename {work_groups/migrations => app/work_groups}/__init__.py (100%) rename {work_groups => app/work_groups}/admin.py (90%) rename {work_groups => app/work_groups}/apps.py (72%) rename {work_groups => app/work_groups}/migrations/0001_initial.py (100%) rename {work_groups => app/work_groups}/migrations/0002_auto_20150604_2203.py (100%) rename {work_groups => app/work_groups}/migrations/0003_auto_20170821_2000.py (100%) rename {work_groups => app/work_groups}/migrations/0004_auto_20180705_0352.py (100%) rename {work_groups => app/work_groups}/migrations/0005_alter_workgroup_creator_and_more.py (100%) rename {work_groups/tests => app/work_groups/migrations}/__init__.py (100%) rename {work_groups => app/work_groups}/models.py (97%) rename work_groups/tests/test_models.py => app/work_groups/tests/__init__.py (100%) create mode 100644 app/work_groups/tests/test_models.py delete mode 100644 codesamples/admin.py rename base-requirements.txt => requirements/base-requirements.txt (100%) rename dev-requirements.txt => requirements/dev-requirements.txt (100%) rename docs-requirements.txt => requirements/docs-requirements.txt (100%) rename prod-requirements.txt => requirements/prod-requirements.txt (100%) rename requirements.txt => requirements/requirements.txt (100%) delete mode 100644 sponsors/models/__init__.py delete mode 100644 templates/peps/list.html diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed08f4b7f..b8ee2fb21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: cache-name: pythondotorg-cache-pip with: path: ~/.cache/pip - key: ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}-${{ hashFiles('requirements.txt', '*-requirements.txt') }} + key: ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}-${{ hashFiles('requirements/requirements.txt', 'requirements/*-requirements.txt') }} restore-keys: | ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}- ${{ runner.os }}-${{ github.job }}- @@ -46,7 +46,7 @@ jobs: - name: Install Python dependencies run: | pip install -U pip setuptools wheel - pip install -r dev-requirements.txt + pip install -r requirements/dev-requirements.txt - name: Check for ungenerated database migrations run: | python manage.py makemigrations --check --dry-run diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 3207b964e..455998786 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -15,7 +15,7 @@ jobs: cache-name: pythondotorg-cache-pip with: path: ~/.cache/pip - key: ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}-${{ hashFiles('requirements.txt', '*-requirements.txt') }} + key: ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}-${{ hashFiles('requirements/requirements.txt', 'requirements/*-requirements.txt') }} restore-keys: | ${{ runner.os }}-${{ github.job }}-${{ env.cache-name }}- ${{ runner.os }}-${{ github.job }}- @@ -23,7 +23,7 @@ jobs: - name: Install Python dependencies run: | pip install -U pip setuptools wheel - pip install -r requirements.txt -r prod-requirements.txt + pip install -r requirements/requirements.txt -r requirements/prod-requirements.txt - name: Run Tests run: | DJANGO_SETTINGS_MODULE=pydotorg.settings.static python manage.py collectstatic --noinput diff --git a/.gitignore b/.gitignore index a9eca9d19..7c7e28b42 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ .sass-cache/ docs/build -media/* +app/media/* static-root/ static/stylesheets/mq.css static/stylesheets/no-mq.css diff --git a/.readthedocs.yaml b/.readthedocs.yaml index ec9dc1ce9..b88e479a9 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -10,6 +10,6 @@ build: python: "3" commands: - - python -m pip install -r docs-requirements.txt + - python -m pip install -r requirements/docs-requirements.txt - make -C docs html JOBS=$(nproc) BUILDDIR=_readthedocs - mv docs/_readthedocs _readthedocs diff --git a/Dockerfile b/Dockerfile index c701cd76c..0cb26c482 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,10 +32,10 @@ RUN case $(uname -m) in \ RUN mkdir /code WORKDIR /code -COPY dev-requirements.txt /code/ -COPY base-requirements.txt /code/ -COPY prod-requirements.txt /code/ -COPY requirements.txt /code/ +COPY requirements/dev-requirements.txt /code/ +COPY requirements/base-requirements.txt /code/ +COPY requirements/prod-requirements.txt /code/ +COPY requirements/requirements.txt /code/ RUN pip --no-cache-dir --disable-pip-version-check install --upgrade pip setuptools wheel diff --git a/Dockerfile.cabotage b/Dockerfile.cabotage index 9bc9d27ad..622c2eaef 100644 --- a/Dockerfile.cabotage +++ b/Dockerfile.cabotage @@ -33,10 +33,10 @@ RUN case $(uname -m) in \ RUN mkdir /code WORKDIR /code -COPY dev-requirements.txt /code/ -COPY base-requirements.txt /code/ -COPY prod-requirements.txt /code/ -COPY requirements.txt /code/ +COPY requirements/dev-requirements.txt /code/ +COPY requirements/base-requirements.txt /code/ +COPY requirements/prod-requirements.txt /code/ +COPY requirements/requirements.txt /code/ RUN pip --no-cache-dir --disable-pip-version-check install --upgrade pip setuptools wheel @@ -46,4 +46,4 @@ RUN --mount=type=cache,target=/root/.cache/pip \ install \ -r requirements.txt -r prod-requirements.txt COPY . /code/ -RUN DJANGO_SETTINGS_MODULE=pydotorg.settings.static python manage.py collectstatic --noinput +RUN DJANGO_SETTINGS_MODULE=pydotorg.settings.static python app/manage.py collectstatic --noinput diff --git a/Makefile b/Makefile index bd4291bbe..b4ded197c 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ default: @echo @exit 1 -.state/docker-build-web: Dockerfile dev-requirements.txt base-requirements.txt +.state/docker-build-web: Dockerfile requirements/dev-requirements.txt requirements/base-requirements.txt # Build web container for this project docker compose build --force-rm web @@ -24,7 +24,7 @@ default: .state/db-initialized: .state/docker-build-web .state/db-migrated # Load all fixtures - docker compose run --rm web ./manage.py loaddata fixtures/*.json + docker compose run --rm web ./app/manage.py loaddata fixtures/*.json # Mark the state so we don't rebuild this needlessly. mkdir -p .state && touch .state/db-initialized @@ -34,25 +34,25 @@ serve: .state/db-initialized migrations: .state/db-initialized # Run Django makemigrations - docker compose run --rm web ./manage.py makemigrations + docker compose run --rm web ./app/manage.py makemigrations migrate: .state/docker-build-web # Run Django migrate - docker compose run --rm web ./manage.py migrate + docker compose run --rm web ./app/manage.py migrate manage: .state/db-initialized # Run Django manage to accept arbitrary arguments - docker compose run --rm web ./manage.py $(filter-out $@,$(MAKECMDGOALS)) + docker compose run --rm web ./app/manage.py $(filter-out $@,$(MAKECMDGOALS)) shell: .state/db-initialized - docker compose run --rm web ./manage.py shell + docker compose run --rm web ./app/manage.py shell clean: docker compose down -v rm -f .state/docker-build-web .state/db-initialized .state/db-migrated test: .state/db-initialized - docker compose run --rm web ./manage.py test + docker compose run --rm web ./app/manage.py test docker_shell: .state/db-initialized docker compose run --rm web /bin/bash diff --git a/Procfile b/Procfile index 16deb5f5b..552d05a89 100644 --- a/Procfile +++ b/Procfile @@ -1,4 +1,4 @@ -release: python manage.py migrate --noinput +release: python app/manage.py migrate --noinput web: bin/start-nginx gunicorn -c gunicorn.conf pydotorg.wsgi -worker: celery -A pydotorg worker -l INFO +worker: celery -A app.pydotorg worker -l INFO worker-beat: celery -A pydotorg beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler diff --git a/banners/__init__.py b/app/__init__.py similarity index 100% rename from banners/__init__.py rename to app/__init__.py diff --git a/banners/migrations/__init__.py b/app/banners/__init__.py similarity index 100% rename from banners/migrations/__init__.py rename to app/banners/__init__.py diff --git a/banners/admin.py b/app/banners/admin.py similarity index 80% rename from banners/admin.py rename to app/banners/admin.py index cfb0e1073..613344e50 100644 --- a/banners/admin.py +++ b/app/banners/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from banners.models import Banner +from app.banners.models import Banner @admin.register(Banner) diff --git a/banners/apps.py b/app/banners/apps.py similarity index 74% rename from banners/apps.py rename to app/banners/apps.py index 9e3aa2c34..336a1f307 100644 --- a/banners/apps.py +++ b/app/banners/apps.py @@ -3,4 +3,4 @@ class BannersAppConfig(AppConfig): - name = 'banners' + name = 'app.banners' diff --git a/banners/migrations/0001_initial.py b/app/banners/migrations/0001_initial.py similarity index 100% rename from banners/migrations/0001_initial.py rename to app/banners/migrations/0001_initial.py diff --git a/banners/templatetags/__init__.py b/app/banners/migrations/__init__.py similarity index 100% rename from banners/templatetags/__init__.py rename to app/banners/migrations/__init__.py diff --git a/banners/models.py b/app/banners/models.py similarity index 100% rename from banners/models.py rename to app/banners/models.py diff --git a/templates/banners/banner.html b/app/banners/templates/banner.html similarity index 100% rename from templates/banners/banner.html rename to app/banners/templates/banner.html diff --git a/blogs/__init__.py b/app/banners/templatetags/__init__.py similarity index 100% rename from blogs/__init__.py rename to app/banners/templatetags/__init__.py diff --git a/banners/templatetags/banners.py b/app/banners/templatetags/banners.py similarity index 94% rename from banners/templatetags/banners.py rename to app/banners/templatetags/banners.py index 24c62b5e8..5a9ddbb33 100644 --- a/banners/templatetags/banners.py +++ b/app/banners/templatetags/banners.py @@ -1,7 +1,7 @@ from django import template from django.template.loader import render_to_string -from banners.models import Banner +from app.banners.models import Banner register = template.Library() diff --git a/bin/pre_compile b/app/bin/pre_compile similarity index 100% rename from bin/pre_compile rename to app/bin/pre_compile diff --git a/bin/start-nginx b/app/bin/start-nginx similarity index 100% rename from bin/start-nginx rename to app/bin/start-nginx diff --git a/blogs/management/__init__.py b/app/blogs/__init__.py similarity index 100% rename from blogs/management/__init__.py rename to app/blogs/__init__.py diff --git a/blogs/admin.py b/app/blogs/admin.py similarity index 91% rename from blogs/admin.py rename to app/blogs/admin.py index e5fea1cfb..c0b61cd95 100644 --- a/blogs/admin.py +++ b/app/blogs/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin from django.core.management import call_command -from .models import BlogEntry, Feed, FeedAggregate +from app.blogs.models import BlogEntry, Feed, FeedAggregate @admin.register(BlogEntry) diff --git a/blogs/apps.py b/app/blogs/apps.py similarity index 75% rename from blogs/apps.py rename to app/blogs/apps.py index 0c88608d1..22210acf6 100644 --- a/blogs/apps.py +++ b/app/blogs/apps.py @@ -3,4 +3,4 @@ class BlogsAppConfig(AppConfig): - name = 'blogs' + name = 'app.blogs' diff --git a/blogs/factories.py b/app/blogs/factories.py similarity index 90% rename from blogs/factories.py rename to app/blogs/factories.py index e66c4b36c..1a8d7dfa7 100644 --- a/blogs/factories.py +++ b/app/blogs/factories.py @@ -1,6 +1,6 @@ from django.conf import settings -from .models import Feed +from app.blogs.models import Feed def initial_data(): diff --git a/blogs/management/commands/__init__.py b/app/blogs/management/__init__.py similarity index 100% rename from blogs/management/commands/__init__.py rename to app/blogs/management/__init__.py diff --git a/blogs/migrations/__init__.py b/app/blogs/management/commands/__init__.py similarity index 100% rename from blogs/migrations/__init__.py rename to app/blogs/management/commands/__init__.py diff --git a/blogs/management/commands/update_blogs.py b/app/blogs/management/commands/update_blogs.py similarity index 85% rename from blogs/management/commands/update_blogs.py rename to app/blogs/management/commands/update_blogs.py index 8914d0a78..166c4342a 100644 --- a/blogs/management/commands/update_blogs.py +++ b/app/blogs/management/commands/update_blogs.py @@ -1,8 +1,8 @@ from django.core.management.base import BaseCommand from django.utils.timezone import now -from ...models import BlogEntry, RelatedBlog, Feed -from ...parser import get_all_entries, update_blog_supernav +from app.blogs..models import BlogEntry, RelatedBlog, Feed +from app.blogs..parser import get_all_entries, update_blog_supernav class Command(BaseCommand): diff --git a/blogs/migrations/0001_initial.py b/app/blogs/migrations/0001_initial.py similarity index 100% rename from blogs/migrations/0001_initial.py rename to app/blogs/migrations/0001_initial.py diff --git a/blogs/migrations/0002_remove_translations_and_contributors.py b/app/blogs/migrations/0002_remove_translations_and_contributors.py similarity index 100% rename from blogs/migrations/0002_remove_translations_and_contributors.py rename to app/blogs/migrations/0002_remove_translations_and_contributors.py diff --git a/blogs/migrations/0003_alter_relatedblog_creator_and_more.py b/app/blogs/migrations/0003_alter_relatedblog_creator_and_more.py similarity index 100% rename from blogs/migrations/0003_alter_relatedblog_creator_and_more.py rename to app/blogs/migrations/0003_alter_relatedblog_creator_and_more.py diff --git a/blogs/templatetags/__init__.py b/app/blogs/migrations/__init__.py similarity index 100% rename from blogs/templatetags/__init__.py rename to app/blogs/migrations/__init__.py diff --git a/blogs/models.py b/app/blogs/models.py similarity index 98% rename from blogs/models.py rename to app/blogs/models.py index 2703fefaf..817f8a8c7 100644 --- a/blogs/models.py +++ b/app/blogs/models.py @@ -5,7 +5,7 @@ from django.db import models -from cms.models import ContentManageable +from app.cms.models import ContentManageable def tag_visible(element): diff --git a/blogs/parser.py b/app/blogs/parser.py similarity index 95% rename from blogs/parser.py rename to app/blogs/parser.py index fd5e4b54d..85513e8a9 100644 --- a/blogs/parser.py +++ b/app/blogs/parser.py @@ -5,8 +5,8 @@ from django.template.loader import render_to_string from django.utils.timezone import make_aware -from boxes.models import Box -from .models import BlogEntry, Feed +from app.boxes.models import Box +from app.blogs.models import BlogEntry, Feed def get_all_entries(feed_url): diff --git a/templates/blogs/index.html b/app/blogs/templates/index.html similarity index 100% rename from templates/blogs/index.html rename to app/blogs/templates/index.html diff --git a/templates/blogs/supernav.html b/app/blogs/templates/supernav.html similarity index 100% rename from templates/blogs/supernav.html rename to app/blogs/templates/supernav.html diff --git a/blogs/tests/__init__.py b/app/blogs/templatetags/__init__.py similarity index 100% rename from blogs/tests/__init__.py rename to app/blogs/templatetags/__init__.py diff --git a/blogs/templatetags/blogs.py b/app/blogs/templatetags/blogs.py similarity index 93% rename from blogs/templatetags/blogs.py rename to app/blogs/templatetags/blogs.py index bc055312e..fde2d35bd 100644 --- a/blogs/templatetags/blogs.py +++ b/app/blogs/templatetags/blogs.py @@ -1,6 +1,6 @@ from django import template -from ..models import BlogEntry +from app.blogs.models import BlogEntry register = template.Library() diff --git a/boxes/__init__.py b/app/blogs/tests/__init__.py similarity index 100% rename from boxes/__init__.py rename to app/blogs/tests/__init__.py diff --git a/blogs/tests/psf_feed_example.xml b/app/blogs/tests/psf_feed_example.xml similarity index 99% rename from blogs/tests/psf_feed_example.xml rename to app/blogs/tests/psf_feed_example.xml index 202f3df2b..94ae984ac 100644 --- a/blogs/tests/psf_feed_example.xml +++ b/app/blogs/tests/psf_feed_example.xml @@ -1,862 +1,862 @@ - -tag:blogger.com,1999:blog-39415539074308991632013-08-27T00:33:50.336-04:00Python InsiderPython core development news and information.Doug Hellmannhttp://www.blogger.com/profile/01892352754222143463noreply@blogger.comBlogger36125PythonInsiderhttp://feedburner.google.comtag:blogger.com,1999:blog-3941553907430899163.post-15569992107993551332013-03-04T10:00:00.000-05:002013-03-04T10:00:06.719-05:002013-03-04T10:00:06.719-05:00Introducing Electronic Contributor Agreements<br /> -We're happy to announce the new way to file a contributor agreement: on the web at&nbsp;<a href="http://www.python.org/psf/contrib/contrib-form/">http://www.python.org/psf/contrib/contrib-form/</a>.<br /> -<br /> -Through the use of&nbsp;<a href="https://www.echosign.adobe.com/en/home.html">Adobe's EchoSign</a>, we got rid of the old hand-written, print out, scan or photograph, then fax or email of your form. It was a hassle for our contributors, and a hassle for our administrators. Faxes fail, mail gets lost, and sometimes pictures or scans turn out poorly. It was time to find a more user-friendly solution, and the Foundation is happy to finally offer this electronic form.<br /> -<br /> -<br /> -The new form is easy to fill out right on the site, guiding you through each of the required fields such as your name, bug tracker ID, address, and initial license. If you're signing the form on behalf of an organization, there's a check box to specify this, and then you are asked near the bottom to state your title in the organization. Lastly, your signature is either generated from your typed name, or you can draw your own or upload a signature file of your own.<br /> -<br /> -Once you submit the form, you'll receive an email from echosign.com to verify the email address you entered. Once you click to confirm your address, the form will be emailed to the PSF and will be recorded.<br /> -<br /> -<br /> -We require all contributors to CPython to have a signed form, and we hope this makes it easier for potential contributors to join up and help make Python better. It's available just in time for&nbsp;<a href="https://us.pycon.org/2013/">PyCon</a>&nbsp;and the&nbsp;<a href="https://us.pycon.org/2013/community/sprints/projects/#core-python">CPython sprint</a>&nbsp;that will be occurring March 18 through 21 in Santa Clara, California. Join us at the sprint, sign your contributor form, and help us fix some bugs or add some features!<div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tGNCqyOiun4:FplHbf8RNFc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tGNCqyOiun4:FplHbf8RNFc:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tGNCqyOiun4:FplHbf8RNFc:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tGNCqyOiun4:FplHbf8RNFc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tGNCqyOiun4:FplHbf8RNFc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tGNCqyOiun4:FplHbf8RNFc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tGNCqyOiun4:FplHbf8RNFc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tGNCqyOiun4:FplHbf8RNFc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/tGNCqyOiun4" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2013/03/introducing-electronic-contributor.htmltag:blogger.com,1999:blog-3941553907430899163.post-27930385091234657372013-02-19T10:00:00.000-05:002013-02-21T01:14:37.819-05:002013-02-21T01:14:37.819-05:00Announcing defusedxml, Fixes for XML Security Issues<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: xx-small;"><i>The following post was created on behalf of CPython contributor Christian Heimes using a subset of details found <a href="https://bitbucket.org/tiran/defusedxml">here</a>.</i></span><br /> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Christian Heimes announces the release of his <a href="https://bitbucket.org/tiran/defusedxml">defusedxml</a>&nbsp;and <a href="https://bitbucket.org/tiran/defusedexpat">defusedexpat</a>&nbsp;packages to address XML-related security issues which were reported to <a href="mailto:security@python.org">security@python.org</a> over the last several months. Throughout the development of the patches, the security team has coordinated with other open source projects in order to make this announcement at 1500 UTC on Tuesday February 19.</span><br /> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Details will follow once releases of CPython have been organized.</span><br /> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: xx-small;"><i style="background-color: #cfe2f3;"><b>Note: this post will be updated with more details as they switch from being private to publicly available, including links to the public bug reports on&nbsp;<a href="http://bugs.python.org/">http://bugs.python.org</a>.</b></i></span><br /> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><span style="background-color: white;"><br /></span></span> -<span style="background-color: white;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">defusedxml on PyPI:&nbsp;</span><a href="https://pypi.python.org/pypi/defusedxml">https://pypi.python.org/pypi/defusedxml</a></span><br /> -<span style="background-color: white;">defusedexpat on PyPI:&nbsp;<a href="https://pypi.python.org/pypi/defusedexpat">https://pypi.python.org/pypi/defusedexpat</a></span><br /> -"XML vulnerabilities" on bug tracker:&nbsp;<a href="http://bugs.python.org/issue17239">http://bugs.python.org/issue17239</a><br /> -<h2 style="background-color: white; color: #333333; line-height: 1.5625; margin: 20px 0px 5px;"> -<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml/#id2" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">Synopsis</span></a></h2> -<div style="background-color: white; color: #333333; line-height: 20px; margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The results of an attack on a vulnerable XML library can be fairly dramatic. With just a few hundred&nbsp;<strong>Bytes</strong>&nbsp;of XML data an attacker can occupy several&nbsp;<strong>Gigabytes</strong>&nbsp;of memory within&nbsp;<strong>seconds</strong>. An attacker can also keep CPUs busy for a long time with a small to medium size request. Under some circumstances it is even possible to access local files on your server, to circumvent a firewall, or to abuse services to rebound attacks to third parties.</span></div> -<div style="background-color: white; color: #333333; line-height: 20px; margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The attacks use and abuse less common features of XML and its parsers. The majority of developers are unacquainted with features such as processing instructions and entity expansions that XML inherited from SGML. At best they know about&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;">&lt;!DOCTYPE&gt;</tt>&nbsp;from experience with HTML but they are not aware that a document type definition (DTD) can generate an HTTP request or load a file from the file system.</span></div> -<div style="background-color: white; color: #333333; line-height: 20px; margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">None of the issues is new. They have been known for a long time. Billion laughs was first reported in 2003. Nevertheless some XML libraries and applications are still vulnerable and even heavy users of XML are surprised by these features. It's hard to say whom to blame for the situation. It's too short sighted to shift all blame on XML parsers and XML libraries for using insecure default settings. After all they properly implement XML specifications. Application developers must not rely that a library is always configured for security and potential harmful data by default.</span></div> -<div style="background-color: white; color: #333333; font-size: 14px; line-height: 20px; margin-top: 10px;"> -</div> -<h2 style="font-size: 16px; line-height: 1.5625; margin: 20px 0px 5px;"> -</h2> -<h2 style="line-height: 1.5625; margin: 20px 0px 5px;"> -<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id3" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">Attack vectors</span></a></h2> -<div class="section" id="billion-laughs-exponential-entity-expansion" style="font-weight: normal; line-height: 20px;"> -<h3 style="line-height: 1.5; margin: 0px 0px 5px;"> -<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id4" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">billion laughs / exponential entity expansion</span></a></h3> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The&nbsp;<a class="reference external" href="http://en.wikipedia.org/wiki/Billion_laughs" style="color: #3c77b4; text-decoration: initial;">Billion Laughs</a>&nbsp;attack -- also known as exponential entity expansion -- uses multiple levels of nested entities. The original example uses 9 levels of 10 expansions in each level to expand the string&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;">lol</tt>&nbsp;to a string of 3 * 10&nbsp;<sup>9</sup>&nbsp;bytes, hence the name "billion laughs". The resulting string occupies 3 GB (2.79 GiB) of memory; intermediate strings require additional memory. Because most parsers don't cache the intermediate step for every expansion it is repeated over and over again. It increases the CPU load even more.</span></div> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An XML document of just a few hundred bytes can disrupt all services on a machine within seconds.</span></div> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Example XML:</span></div> -<pre class="literal-block" style="background-color: whitesmoke; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; line-height: 1.4; margin-bottom: 9px; margin-top: 9px; overflow: auto; padding: 10px; width: 615px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">&lt;!DOCTYPE xmlbomb [ -&lt;!ENTITY a "1234567890" &gt; -&lt;!ENTITY b "&amp;a;&amp;a;&amp;a;&amp;a;&amp;a;&amp;a;&amp;a;&amp;a;"&gt; -&lt;!ENTITY c "&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;"&gt; -&lt;!ENTITY d "&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;"&gt; -]&gt; -&lt;bomb&gt;&amp;d;&lt;/bomb&gt; -</span></pre> -</div> -<div class="section" id="quadratic-blowup-entity-expansion" style="font-weight: normal; line-height: 20px;"> -<h3 style="line-height: 1.5; margin: 0px 0px 5px;"> -<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id5" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">quadratic blowup entity expansion</span></a></h3> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">A quadratic blowup attack is similar to a&nbsp;<a class="reference external" href="http://en.wikipedia.org/wiki/Billion_laughs" style="color: #3c77b4; text-decoration: initial;">Billion Laughs</a>&nbsp;attack; it abuses entity expansion, too. Instead of nested entities it repeats one large entity with a couple of ten thousand chars over and over again. The attack isn't as efficient as the exponential case but it avoids triggering countermeasures of parsers against heavily nested entities. Some parsers limit the depth and breadth of a single entity but not the total amount of expanded text throughout an entire XML document.</span></div> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">A medium-sized XML document with a couple of hundred kilobytes can require a couple of hundred MB to several GB of memory. When the attack is combined with some level of nested expansion an attacker is able to achieve a higher ratio of success.</span></div> -<pre class="literal-block" style="background-color: whitesmoke; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; line-height: 1.4; margin-bottom: 9px; margin-top: 9px; overflow: auto; padding: 10px; width: 615px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">&lt;!DOCTYPE bomb [ -&lt;!ENTITY a "xxxxxxx... a couple of ten thousand chars"&gt; -]&gt; -&lt;bomb&gt;&amp;a;&amp;a;&amp;a;... repeat&lt;/bomb&gt; -</span></pre> -</div> -<div class="section" id="external-entity-expansion-remote" style="font-weight: normal; line-height: 20px;"> -<h3 style="line-height: 1.5; margin: 0px 0px 5px;"> -<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id6" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">external entity expansion (remote)</span></a></h3> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Entity declarations can contain more than just text for replacement. They can also point to external resources by public identifiers or system identifiers. System identifiers are standard URIs. When the URI is a URL (e.g. a&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;"><span class="pre">http://</span></tt>&nbsp;locator) some parsers download the resource from the remote location and embed them into the XML document verbatim.</span></div> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Simple example of a parsed external entity:</span></div> -<pre class="literal-block" style="background-color: whitesmoke; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; line-height: 1.4; margin-bottom: 9px; margin-top: 9px; overflow: auto; padding: 10px; width: 615px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">&lt;!DOCTYPE external [ -&lt;!ENTITY ee SYSTEM "http://www.python.org/some.xml"&gt; -]&gt; -&lt;root&gt;&amp;ee;&lt;/root&gt; -</span></pre> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The case of parsed external entities works only for valid XML content. The XML standard also supports unparsed external entities with a&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;">NData declaration</tt>.</span></div> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">External entity expansion opens the door to plenty of exploits. An attacker can abuse a vulnerable XML library and application to rebound and forward network requests with the IP address of the server. It highly depends on the parser and the application what kind of exploit is possible. For example:</span></div> -<ul class="simple" style="margin: 10px 0px 0px;"> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker can circumvent firewalls and gain access to restricted resources as all the requests are made from an internal and trustworthy IP address, not from the outside.</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker can abuse a service to attack, spy on or DoS your servers but also third party services. The attack is disguised with the IP address of the server and the attacker is able to utilize the high bandwidth of a big machine.</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker can exhaust additional resources on the machine, e.g. with requests to a service that doesn't respond or responds with very large files.</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker may gain knowledge, when, how often and from which IP address a XML document is accessed.</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker could send mail from inside your network if the URL handler supports&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;"><span class="pre">smtp://</span></tt>&nbsp;URIs.</span></li> -</ul> -</div> -<div class="section" id="external-entity-expansion-local-file" style="font-weight: normal; line-height: 20px;"> -<h3 style="line-height: 1.5; margin: 0px 0px 5px;"> -<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id7" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">external entity expansion (local file)</span></a></h3> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">External entities with references to local files are a sub-case of external entity expansion. It's listed as an extra attack because it deserves extra attention. Some XML libraries such as lxml disable network access by default but still allow entity expansion with local file access by default. Local files are either referenced with a&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;"><span class="pre">file://</span></tt>&nbsp;URL or by a file path (either relative or absolute).</span></div> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker may be able to access and download all files that can be read by the application process. This may include critical configuration files, too.</span></div> -<pre class="literal-block" style="background-color: whitesmoke; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; line-height: 1.4; margin-bottom: 9px; margin-top: 9px; overflow: auto; padding: 10px; width: 615px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">&lt;!DOCTYPE external [ -&lt;!ENTITY ee SYSTEM "file:///PATH/TO/simple.xml"&gt; -]&gt; -&lt;root&gt;&amp;ee;&lt;/root&gt;</span></pre> -</div> -<div> -<h2 style="font-size: 16px; line-height: 1.5625; margin: 20px 0px 5px;"> -</h2> -<h2 style="line-height: 1.5625; margin: 20px 0px 5px;"> -<span style="color: #3c77b4; font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: xx-small; text-decoration: initial;"><a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id9" style="color: #3c77b4; text-decoration: initial;">Python XML Libraries</a></span></h2> -<table border="1" class="docutils" style="color: #333333; line-height: 20px;"><caption><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">vulnerabilities and features</span></caption><colgroup><col width="31%"></col><col width="9%"></col><col width="10%"></col><col width="10%"></col><col width="9%"></col><col width="10%"></col><col width="10%"></col><col width="10%"></col></colgroup><thead valign="bottom"> -<tr><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">kind</span></th><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">sax</span></th><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">etree</span></th><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">minidom</span></th><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">pulldom</span></th><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">xmlrpc</span></th></tr> -</thead><tbody valign="top"> -<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">billion laughs</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td></tr> -<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">quadratic blowup</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td></tr> -<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">external entity expansion (remote)</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False (3)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False (4)</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">untested</span></td></tr> -<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">external entity expansion (local file)</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False (3)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False (4)</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">untested</span></td></tr> -<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">DTD retrieval</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">untested</span></td></tr> -<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">gzip bomb</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td></tr> -<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">xpath support (7)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td></tr> -<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">xsl(t) support (7)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td></tr> -<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">xinclude support (7)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><strong>True</strong>&nbsp;(6)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td></tr> -<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">C library</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">expat</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">expat</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">expat</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">expat</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">expat</span></td></tr> -</tbody></table> -<ol class="arabic simple" style="margin: 10px 0px 0px;"> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Lxml is protected against billion laughs attacks and doesn't do network lookups by default.</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">libxml2 and lxml are not directly vulnerable to gzip decompression bombs but they don't protect you against them either.</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">xml.etree doesn't expand entities and raises a ParserError when an entity occurs.</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">minidom doesn't expand entities and simply returns the unexpanded entity verbatim.</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">genshi.input of genshi 0.6 doesn't support entity expansion and raises a ParserError when an entity occurs.</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Library has (limited) XInclude support but requires an additional step to process inclusion.</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">These are features but they may introduce exploitable holes</span></li> -</ol> -</div> -<div> -<br /> -<h2 style="background-color: white; color: #333333; font-size: 16px; line-height: 1.5625; margin: 20px 0px 5px;"> -<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id24" style="color: #3c77b4; font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; font-size: medium; line-height: 1.5625;">How to avoid XML vulnerabilities</a></h2> -<div class="section" id="best-practices" style="background-color: white; color: #333333; line-height: 20px;"> -<h3 style="line-height: 1.5; margin: 0px 0px 5px;"> -<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id25" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">Best practices</span></a></h3> -<ul class="simple" style="margin: 10px 0px 0px;"> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Don't allow DTDs</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Don't expand entities</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Don't resolve externals</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Limit parse depth</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Limit total input size</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Limit parse time</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Favor a SAX or iterparse-like parser for potential large data</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Validate and properly quote arguments to XSL transformations and XPath queries</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Don't use XPath expression from untrusted sources</span></li> -<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Don't apply XSL transformations that come untrusted sources</span></li> -</ul> -<div style="margin-top: 10px;"> -<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">(based on Brad Hill's&nbsp;<a class="reference external" href="https://www.isecpartners.com/media/12976/iSEC-HILL-Attacking-XML-Security-bh07.pdf" style="color: #3c77b4; text-decoration: initial;">Attacking XML Security</a>)</span></div> -<div style="margin-top: 10px;"> -</div> -<h2 style="line-height: 1.5625; margin: 20px 0px 5px;"> -<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id35" style="color: #3c77b4; font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; font-size: medium; line-height: 1.5625;">Related CVEs</a></h2> -<div class="section" id="python"> - -<dl class="docutils" style="margin: 10px 0px;"> -<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">CVE-2013-1664</span></dt> -<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Unrestricted entity expansion induces DoS vulnerabilities in Python XML libraries (XML bomb)</span></dd> -<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">CVE-2013-1665</span></dt> -<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">External entity expansion in Python XML libraries inflicts potential security flaws and DoS vulnerabilities</span></dd></dl> -</div> -<div style="margin-top: 10px;"> -</div> -<h2 style="line-height: 1.5625; margin: 20px 0px 5px;"> -<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id46" style="color: #3c77b4;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">Acknowledgements</span></a></h2> -<dl class="docutils" style="margin: 10px 0px;"> -<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Brett Cannon (Python Core developer)</span></dt> -<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">review and code cleanup</span></dd> -<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Antoine Pitrou (Python Core developer)</span></dt> -<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">code review</span></dd> -<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Aaron Patterson, Ben Murphy and Michael Koziarski (Ruby community)</span></dt> -<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Many thanks to Aaron, Ben and Michael from the Ruby community for their report and assistance.</span></dd> -<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Thierry Carrez (OpenStack)</span></dt> -<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Many thanks to Thierry for his report to the Python Security Response Team on behalf of the OpenStack security team.</span></dd> -<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Carl Meyer (Django)</span></dt> -<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Many thanks to Carl for his report to PSRT on behalf of the Django security team.</span></dd> -<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Daniel Veillard (libxml2)</span></dt> -<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Many thanks to Daniel for his insight and assistance with libxml2.</span></dd> -<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">semantics GmbH (<a class="reference external" href="http://www.semantics.de/" style="color: #3c77b4; text-decoration: initial;">http://www.semantics.de/</a>)</span></dt> -<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Many thanks to my employer semantics for letting me work on the issue during working hours as part of semantics's open source initiative.</span></dd></dl> -</div> -</div> -<div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=mEuAaPL7awE:FNzZUH2cZ0E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=mEuAaPL7awE:FNzZUH2cZ0E:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=mEuAaPL7awE:FNzZUH2cZ0E:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=mEuAaPL7awE:FNzZUH2cZ0E:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=mEuAaPL7awE:FNzZUH2cZ0E:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=mEuAaPL7awE:FNzZUH2cZ0E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=mEuAaPL7awE:FNzZUH2cZ0E:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=mEuAaPL7awE:FNzZUH2cZ0E:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/mEuAaPL7awE" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2013/02/announcing-defusedxml-fixes-for-xml.htmltag:blogger.com,1999:blog-3941553907430899163.post-81464114770300829952012-12-20T12:26:00.001-05:002012-12-20T12:26:18.294-05:002012-12-20T12:26:18.294-05:00PandaBoard, Raspberry Pi coming to Buildbot fleet<b id="internal-source-marker_0.3835159728769213" style="font-weight: normal;"><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Thanks to the </span><a href="http://python.org/psf/"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Python Software Foundation</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">, a </span><a href="http://pandaboard.org/"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">PandaBoard</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"> arrived on Trent Nelson’s desk just in time for the holidays! Santa dropped off the present for python-dev this morning, and there’s a </span><a href="http://www.raspberrypi.org/"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Raspberry Pi</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"> not far behind it.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">On Raymond Hettinger’s recent thread about the memory layout of </span><a href="http://mail.python.org/pipermail/python-dev/2012-December/123028.html"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">dictionaries</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">, Barry Warsaw and Christian Heimes shared concerns about how things might look on ARM devices. Christian mentioned the </span><a href="http://www.snakebite.net/"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Snakebite</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"> environment, run by Trent Nelson, but without any ARM machines in the environment, Trent offered to host the boxes if someone donates them.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Based on the thread’s suggestions and the low cost of the devices, the PSF authorized purchase of a PandaBoard ES, featuring a 1.2 GHz ARM Cortex A9, along with several accessories to get it running. The PSF already had a few Raspberry Pi devices on hand, which come with a 700 MHz ARMv6, so one was dispatched to Trent.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Thanks to the PSF for making the purchase, and thanks to Trent for offering to set up the machines and add them to the environment!</span></b><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=c-6RjbAraEg:nFRQWgfDEF8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=c-6RjbAraEg:nFRQWgfDEF8:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=c-6RjbAraEg:nFRQWgfDEF8:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=c-6RjbAraEg:nFRQWgfDEF8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=c-6RjbAraEg:nFRQWgfDEF8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=c-6RjbAraEg:nFRQWgfDEF8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=c-6RjbAraEg:nFRQWgfDEF8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=c-6RjbAraEg:nFRQWgfDEF8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/c-6RjbAraEg" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/12/pandaboard-raspberry-pi-coming-to.htmltag:blogger.com,1999:blog-3941553907430899163.post-57110134124002473822012-11-19T09:53:00.002-05:002012-11-19T09:53:39.015-05:002012-11-19T09:53:39.015-05:00New Contributor Experience in Python and other FOSS Communities - A Survey<b id="internal-source-marker_0.9831261797808111" style="font-weight: normal;"><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">If you have joined the community of developers contributing to CPython since January 2010, I hope you can find a few spare minutes to participate in a survey being put on by Kevin Carillo. He’s a Ph. D. student at Victoria University of Wellington completing research on new contributors to free and open source projects. Kevin is interested in hearing from everyone from technical to non-technical contributors, whether you had positive or negative experiences.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">The survey is available at </span><a href="https://limesurvey.sim.vuw.ac.nz/index.php?sid=65151&amp;lang=en"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">https://limesurvey.sim.vuw.ac.nz/index.php?sid=65151&amp;lang=en</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Kevin states, “The goal of this research is to understand how a person's experience as a newcomer to a Free/Open Source Software (FOSS) community influences that person's behavior and contributions within that community.” He estimates that the survey will take around 20 minutes to complete.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Throughout the nearly three year period since January 2010, over 40 </span><a href="http://docs.python.org/devguide/developers.html"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">committers</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"> were added and countless others contributed patches, reviews, and bug triage. Since the creation of the </span><a href="http://pythonmentors.com/"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Core-Mentors</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"> group in March 2011, we’ve seen many first timers come through and have their work committed and released.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">We hope that the mentorship group has helped introduce contributors in a positive manner, so we’re looking forward to the results of Kevin’s studies. One of the things Kevin hopes to find is whether or not formal mentorship programs work for introducing contributors. He also looks to find answers to how much community support of newcomers matters, whether formal joining processes involving sponsorship work, and if newcomer specific tasks are the way to go.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">If you have the time, please fill out </span><a href="https://limesurvey.sim.vuw.ac.nz/index.php?sid=65151&amp;lang=en"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">the survey</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">. Python is participating in this survey along with several other groups including Debian, KDE, Gnome, openSUSE, and OpenHatch. Perhaps we can learn a few things and create an even better experience for new contributors!</span></b><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ICfH8qB5Y0s:SXWcsYAImj0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ICfH8qB5Y0s:SXWcsYAImj0:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ICfH8qB5Y0s:SXWcsYAImj0:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ICfH8qB5Y0s:SXWcsYAImj0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ICfH8qB5Y0s:SXWcsYAImj0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ICfH8qB5Y0s:SXWcsYAImj0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ICfH8qB5Y0s:SXWcsYAImj0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ICfH8qB5Y0s:SXWcsYAImj0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/ICfH8qB5Y0s" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/11/new-contributor-experience-in-python.htmltag:blogger.com,1999:blog-3941553907430899163.post-39133167538009318292012-10-30T23:44:00.000-04:002012-10-30T23:45:36.034-04:002012-10-30T23:45:36.034-04:00Python Bug Day this Saturday<div class="entry"> -This Saturday, you have the opportunity of participating to the -Python Bug Day. How would you like to be one of the contributors of -Python? If you have ideas for improving parts of the official -documentation, the standard library, the language itself, or if you have - a patch waiting for a review that you would like to see committed, or -if you just want to come and fix an existing bug, it’s your day!<br /> -<br /> -Join us for an effort at closing some Python bugs and feature -requests. Get quick feedback on your patches and bugfixes, learn how to - submit and examine patches, and have fun chatting with the Python -developers and other contributors. You don’t need to know the CPython -codebase or process to join, just Python programming knowledge.<br /> -<br /> -If you live in <a href="http://montrealpython.org/2012/10/python-bug-day/" target="_blank">Montreal</a>, come at Caravan to meet fellow hackers and -take part in a physical sprint!<br /> -<br /> -<b><a href="http://mpbugday.eventbrite.ca/" target="_blank">Please register</a><a href="http://mpbugday.eventbrite.ca/"></a></b> - to let us know how many people to expect. People from around the world - are should join the #python-dev IRC channel to participate in the -bug day.<br /> -<br /> -<div class="line862"> -This page contains all the information you need to get set up, see the list of bugs or learn about IRC: <a href="http://wiki.python.org/moin/PythonBugDay">http://wiki.python.org/moin/PythonBugDay</a>&nbsp;</div> -<div class="line862"> -<br /></div> -<div class="line862"> -The goal of the bug day is to process bug reports in <a class="http" href="http://bugs.python.org/">the Python bug tracker</a>, trying to <span class="anchor" id="line-50"></span>fix and close issues.&nbsp;</div> -<div class="line862"> -</div> -<div class="line862"> -<span class="anchor" id="line-51"></span><span class="anchor" id="line-52"></span></div> -<div class="line867"> -<span class="anchor" id="line-53"></span><span class="anchor" id="line-54"></span></div> -<div class="line867"> -<span class="anchor" id="line-55"></span></div> -<div class="line867"> -<span class="anchor" id="line-56"></span><span class="anchor" id="line-57"></span></div> -<div class="line867"> -<span class="anchor" id="line-58"></span></div> -<div class="line867"> -<span class="anchor" id="line-59"></span><span class="anchor" id="line-60"></span></div> -<div class="line874"> -<br /></div> -<div class="line874"> -<b>&nbsp;What to do: </b><span class="anchor" id="line-61"></span><span class="anchor" id="line-62"></span></div> -<ul> -<li><div class="line862"> -Grab a copy of the Python codebase from Mercurial, following instructions in the <a class="http" href="http://docs.python.org/devguide">Developer's Guide</a>, and compile it. <span class="anchor" id="line-63"></span></div> -</li> -<li><div class="line862"> -If - you have a problem that isn't in the bug tracker, announce it to the -IRC channel, and if it's more than five minutes' work, create a bug -report for it. See the <a class="http" href="http://docs.python.org/dev/bugs.html">bug reporting instructions</a> to learn <span class="anchor" id="line-64"></span>how to write bug reports. <span class="anchor" id="line-65"></span></div> -</li> -<li>When you choose a bug to work on, announce it to the IRC channel (e.g. "I'm <span class="anchor" id="line-66"></span>working on #123456.") or on the bug report itself. This avoids accidentally duplicating work. <span class="anchor" id="line-67"></span></li> -<li>Consider - providing a patch that fixes the problem, or at least a simple test -case that demonstrates the bug. Please see the patch submission -guidelines in the Developer's Guide before submitting a patch. <span class="anchor" id="line-68"></span></li> -<li>Does - the bug appear to be gone in the Python development version (the -Mercurial branch "default", that will become 3.4), but not the 3.2, 3.3 -or 2.7 maintenance branchs? Report that, too. <span class="anchor" id="line-69"></span></li> -<li>If someone else has supplied a fix, see if this fix works for² you, and add your results to the bug. <span class="anchor" id="line-70"></span></li> -<li>Read the text of proposed patches and assess them for correctness and code quality. <span class="anchor" id="line-71"></span>This is usually the most time-consuming step in the bug fixing process, so reading patches <span class="anchor" id="line-72"></span>is very useful. <span class="anchor" id="line-73"></span></li> -<li>If there's a working fix, feel free to add a note asking for <span class="anchor" id="line-74"></span>the fix to get committed. The bug tracker has a lot of items in it, and it's easy for bugs to be overlooked. <span class="anchor" id="line-75"></span></li> -<li>Feature requests should be classified as type 'feature request' in the bug tracker. </li> -</ul> -If you need any help beforehand, feel free to ask on <a href="http://mail.python.org/mailman/listinfo/core-mentorship">core-mentorship mailing-list </a></div> -<div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=YwdJhjL4F0Y:gqJ51WnKXno:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=YwdJhjL4F0Y:gqJ51WnKXno:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=YwdJhjL4F0Y:gqJ51WnKXno:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=YwdJhjL4F0Y:gqJ51WnKXno:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=YwdJhjL4F0Y:gqJ51WnKXno:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=YwdJhjL4F0Y:gqJ51WnKXno:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=YwdJhjL4F0Y:gqJ51WnKXno:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=YwdJhjL4F0Y:gqJ51WnKXno:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/YwdJhjL4F0Y" height="1" width="1"/>Mathieu Leduc-Hamelhttp://www.blogger.com/profile/07757697862303956313noreply@blogger.comMontreal, QC, Canada45.5086699 -73.553992545.3306269 -73.8698495 45.6867129 -73.23813550000001http://blog.python.org/2012/10/python-bug-day-this-saturday.htmltag:blogger.com,1999:blog-3941553907430899163.post-74817557241470528852012-10-29T13:51:00.000-04:002012-10-29T13:58:42.023-04:002012-10-29T13:58:42.023-04:00Updates to docs.python.org<div class="document" id="updates-to-docs-python-org"> -If you haven't already noticed, several months ago we updated the Sphinx theme for documentation of versions Python 3.2 and beyond on <a href="http://docs.python.org">docs.python.org</a>. It's a more modern look, and it also serves as an indicator that you're looking at documentation for a newer version. Thanks go out to Georg Brandl for his work on Sphinx, Python's documentation, and this new theme!<br /> -<div class="section" id="pep-430"><br/> -<h4>PEP 430</h4><br/> -Over the weekend, <a class="reference external" href="http://www.python.org/dev/peps/pep-0430/">PEP 430</a> was approved, which changes the default documentation displayed at <a class="reference external" href="http://docs.python.org/">http://docs.python.org</a>. See the PEP for full details, but the jist is that we're now promoting the current Python 3 release as the default when you go to the docs home page. However, as the majority use case is still for Python 2 documentation, navigating straight to an unversioned page will present you with the current Python 2 documentation. For example, an unversioned link such as <a class="reference external" href="http://docs.python.org/library/zipfile">http://docs.python.org/library/zipfile</a> will bring up the 2.7.3 documentation.</div> -<div class="section" id="version-dropdown"><br/> -<h4>Version Dropdown</h4><br/> -Supporting that change is a new feature that adds a version dropdown to the top of all documentation pages. Not only does this help when users are brought to a page which they don't expect, but switching between versions is a common operation as more and more projects work to add support for Python 3. <a class="reference external" href="http://bugs.python.org/issue8040">Issue 8040</a> is where you'll find discussion on the change and its patches, with the bulk of the work completed by Yury Selivanov with some help from Georg.<br /><br/> -<div class="separator" style="clear: both; text-align: center;"> -<a href="http://i.imgur.com/GMPHE.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="177" width="529" src="http://i.imgur.com/GMPHE.png" /></a></div> -<br /> -This dropdown is especially handy as you peruse the documentation and come to a page that you want to view in another version. Choosing another version while on any page will load that page's other version, where the latest release of that version is chosen, e.g., 2.7 currently points to 2.7.3. So, as you browse the 2.7.3 built-ins page, choosing 3.3 in the dropdown will bring you to the 3.3.0 built-ins page.<br /> -<br /> -<div class="separator" style="clear: both; text-align: center;"> -<a href="http://i.imgur.com/9Zz7s.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="243" width="541" src="http://i.imgur.com/9Zz7s.png" /></a></div> - - -<br/> -We hope these changes enhance your experience when browsing the Python documentation!</div> -</div> -<div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=0eVUB6TXykc:93UNm5liOJw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=0eVUB6TXykc:93UNm5liOJw:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=0eVUB6TXykc:93UNm5liOJw:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=0eVUB6TXykc:93UNm5liOJw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=0eVUB6TXykc:93UNm5liOJw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=0eVUB6TXykc:93UNm5liOJw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=0eVUB6TXykc:93UNm5liOJw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=0eVUB6TXykc:93UNm5liOJw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/0eVUB6TXykc" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/10/updates-to-docspythonorg.htmltag:blogger.com,1999:blog-3941553907430899163.post-26874471934921781862012-08-14T10:00:00.000-04:002012-08-14T10:00:02.798-04:002012-08-14T10:00:02.798-04:00Python 3.3 Beta 2 Released<div class="document" id="python-3-3-beta-2-released"> - -<p>Release manager Georg Brandl announced on August 12 that <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">the second beta of -CPython 3.3 was released</a>, complete with installers for both Mac and Windows. -This release represents the final feature set, and the goal is to get it in -the hands of users to iron out any last issues.</p> -<p>Following this beta will be two release candidates, coming August 25 and -September 8. The final release is slated to happen on September 22.</p> -<p>The &quot;<a class="reference external" href="http://docs.python.org/dev/whatsnew/3.3.html">What's New in Python 3.3</a>&quot; document is currently being finalized by -curator and long time developer Raymond Hettinger. The document already -contains many of the new changes, but keep an eye out for newer versions.</p> -<p>Here are some of the bigger changes:</p> -<ul class="simple"> -<li><a class="reference external" href="http://python.org/dev/peps/pep-0380">PEP 380</a>, syntax for delegating to a subgenerator (&quot;yield from&quot;)</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-0393">PEP 393</a>, flexible string representation (doing away with the -distinction between &quot;wide&quot; and &quot;narrow&quot; Unicode builds)</li> -<li>A <a class="reference external" href="http://bugs.python.org/issue7652">C implementation of the &quot;decimal&quot; module</a>, with up to 80x speedup -for decimal-heavy applications</li> -<li>The import system (__import__) <a class="reference external" href="http://bugs.python.org/issue2377">now based on importlib</a> by default</li> -<li>The new &quot;<a class="reference external" href="http://docs.python.org/dev/library/lzma">lzma</a>&quot; module with LZMA/XZ support</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-0397">PEP 397</a>, a Python launcher for Windows</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-0405">PEP 405</a>, virtual environment support in core</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-0420">PEP 420</a>, namespace package support</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-3151">PEP 3151</a>, reworking the OS and IO exception hierarchy</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-3155">PEP 3155</a>, qualified name for classes and functions</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-0409">PEP 409</a>, suppressing exception context</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-0414">PEP 414</a>, explicit Unicode literals to help with porting</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-0418">PEP 418</a>, extended platform-independent clocks in the &quot;time&quot; module</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-0412">PEP 412</a>, a new key-sharing dictionary implementation that -significantly saves memory for object-oriented code</li> -<li><a class="reference external" href="http://python.org/dev/peps/pep-0361">PEP 362</a>, the function-signature object</li> -<li>The new &quot;<a class="reference external" href="http://docs.python.org/dev/library/faulthandler">faulthandler</a>&quot; module that helps diagnosing crashes</li> -<li>The new &quot;<a class="reference external" href="http://docs.python.org/dev/library/unittest.mock">unittest.mock</a>&quot; module</li> -<li>The new &quot;<a class="reference external" href="http://docs.python.org/dev/library/ipaddress">ipaddress</a>&quot; module</li> -<li>The &quot;<a class="reference external" href="http://docs.python.org/dev/library/sys#sys.implementation">sys.implementation</a>&quot; attribute</li> -<li>A policy framework for the email package, with a provisional (see -<a class="reference external" href="http://python.org/dev/peps/pep-0411">PEP 411</a>) policy that adds much improved unicode support for email -header parsing</li> -<li>A &quot;<a class="reference external" href="http://docs.python.org/dev/library/collections#collections.ChainMap">collections.ChainMap</a>&quot; class for linking mappings to a single unit</li> -<li>Wrappers for many more POSIX functions in the &quot;os&quot; and &quot;signal&quot; -modules, as well as other useful functions such as &quot;sendfile()&quot;</li> -<li>Hash randomization, introduced in earlier bugfix releases, is now -switched on by default</li> -</ul> -<p>In total, almost 500 API items are new or improved in Python 3.3.</p> -<p>Be sure to check out this release at <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">http://www.python.org/download/releases/3.3.0/</a> -and report any issues to <a class="reference external" href="http://bugs.python.org">http://bugs.python.org</a>.</p> -</div> -<div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=fyJFt5G70x0:bM6oa3IqoU4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=fyJFt5G70x0:bM6oa3IqoU4:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=fyJFt5G70x0:bM6oa3IqoU4:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=fyJFt5G70x0:bM6oa3IqoU4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=fyJFt5G70x0:bM6oa3IqoU4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=fyJFt5G70x0:bM6oa3IqoU4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=fyJFt5G70x0:bM6oa3IqoU4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=fyJFt5G70x0:bM6oa3IqoU4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/fyJFt5G70x0" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/08/python-33-beta-2-released.htmltag:blogger.com,1999:blog-3941553907430899163.post-31899894346973035052012-06-07T10:00:00.000-04:002012-06-07T10:00:03.299-04:002012-06-07T10:00:03.299-04:00Mercurial Mirrors Provided by Atlassian<div class="document" id="mercurial-mirrors-provided-by-atlassian"> -Long-time friends of the Python community, Atlassian (makers of <a class="reference external" href="http://www.bitbucket.org/">Bitbucket</a>) recently made available a mirror of <a class="reference external" href="http://hg.python.org/">http://hg.python.org</a>, synchronized hourly, for your cloning and hacking pleasure.<br /> -<br /> -Using <a class="reference external" href="https://bitbucket.org/python_mirrors">the new mirror</a> should be very intuitive for current users of the Hg repository -- the projects housed in the mirror follow the same naming convention as the repository they're mirroring. So, the CPython source code is mirrored at <a class="reference external" href="https://bitbucket.org/python_mirrors/cpython">https://bitbucket.org/python_mirrors/cpython</a>, corresponding to its canonical home at <a class="reference external" href="http://hg.python.org/cpython">http://hg.python.org/cpython</a>.<br /> -<br /> -Since it's hosted on Bitbucket, the collaborative floodgates are effectively flung open. Not only is it dead easy to clone and submit contributions back to the project, you'll also have the ability to follow the project and receive updates in your dashboard. If RSS is more your style, Bitbucket makes it easy to stay up-to-date with changes via each repository's feed.<br /> -<br /> -If you cloned the cpython repo and want to submit your changes to an issue on <a class="reference external" href="http://bugs.python.org/">http://bugs.python.org</a>, it's as simple as pasting a link to your Bitbucket clone in the "Remote hg repo" box. The <tt class="docutils literal">default</tt> branch is automatically chosen, but appending <tt class="docutils literal">#branchname</tt> to the end of your link will choose that branch.<br /> -<img alt="http://i.imgur.com/6popx.png" src="http://i.imgur.com/6popx.png" /> -<br /> -See how easy it is to get your changes associated with an issue? If you're interested in getting started with CPython development, check out our <a class="reference external" href="http://docs.python.org/devguide">developer guide</a>.<br /> -<hr class="docutils" /> -Atlassian has been a user of Python and supporter of the Python community for some time now. They've sponsored PyCons around the world as well as events at those conferences, from the CodeWars competitions during PyCon AU to the recent PyLadies party at PyCon US!<br /> -<br /> -Thanks, Atlassian!</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TKMQ7tK4z0c:8G3frAu_Ep0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TKMQ7tK4z0c:8G3frAu_Ep0:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TKMQ7tK4z0c:8G3frAu_Ep0:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TKMQ7tK4z0c:8G3frAu_Ep0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TKMQ7tK4z0c:8G3frAu_Ep0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TKMQ7tK4z0c:8G3frAu_Ep0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TKMQ7tK4z0c:8G3frAu_Ep0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TKMQ7tK4z0c:8G3frAu_Ep0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/TKMQ7tK4z0c" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/06/mercurial-mirrors-provided-by-atlassian.htmltag:blogger.com,1999:blog-3941553907430899163.post-45498580821081577872012-06-01T10:30:00.000-04:002012-06-01T10:30:00.743-04:002012-06-01T10:30:00.743-04:00Python 3.3 Alpha 4 Released<div class="document" id="python-3-3-alpha-4-released"> -<p>Yesterday, May 31, brought the <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">fourth alpha release</a> in the Python 3.3 development schedule. It's an exciting release as it introduces a number of long awaited features that we really hope the community will enjoy.</p> -<div class="section" id="new-features"> -<h4>New Features</h4> -<div class="section" id="pep-405-virtual-environments"> -<h5>PEP 405 - Virtual Environments</h5> -<p>Just in time for Alpha 4 comes the addition of <a class="reference external" href="http://www.python.org/dev/peps/pep-0405/">PEP 405</a>'s support for virtual environments by way of the <tt class="docutils literal">venv</tt> module and <tt class="docutils literal">pyenv</tt> script.</p> -<blockquote> -<tt class="docutils literal">python <span class="pre">-m</span> venv /home/yourname/dev/myproject</tt></blockquote> -<p>You may know this functionality through <a class="reference external" href="http://www.virtualenv.org/en/latest/index.html">virtualenv</a>, originally created by Ian Bicking. Thanks to Carl Meyer, Vinay Sajip, and anyone else for working on the PEP and implementation, we now have this widely used functionality available in a Python release!</p> -</div> -<div class="section" id="pep-420-namespace-packages"> -<h5>PEP 420 - Namespace Packages</h5> -<p>After a long road featuring two preceding PEPS (<a class="reference external" href="http://www.python.org/dev/peps/pep-0382/">382</a> and <a class="reference external" href="http://www.python.org/dev/peps/pep-0402/">402</a>), several sprints (including one <a class="reference external" href="http://pythonsprints.com/2011/06/16/pep-382-sprint-maryland/">sponsored by the PSF</a>), and much discussion on python-dev, import-sig, and at PyCon language summits over the last two years, namespace packages are here. At <a class="reference external" href="http://blog.python.org/2012/03/2012-language-summit-report.html">the summit</a>, Eric Smith stepped up to write a new PEP after the group decided to reject PEPs 382 and 402.</p> -<p>The result is <a class="reference external" href="http://www.python.org/dev/peps/pep-0420/">PEP 420</a>. The most obvious feature of a namespace package is the lack of a <tt class="docutils literal">__init__.py</tt> file. However, there's a lot more to it, so check out the PEP!</p> -</div> -<div class="section" id="pep-3144-the-ipaddress-module"> -<h5>PEP 3144 - The ipaddress Module</h5> -<p>After discussion starting during the Python 3.2 development cycle, the - -<tt class="docutils literal">ipaddress</tt> module has a new home in the standard library for 3.3. - -<a class="reference external" href="http://www.python.org/dev/peps/pep-3144/">PEP 3144</a>, authored by Peter Moody and taken up by core contributor Nick Coghlan, introduces a collection of classes for working with addresses, networks, and interfaces for both IPv4 and IPv6.</p> -</div> -<div class="section" id="windows-build-upgraded-to-visual-studio-2010"> -<h5>Windows Build Upgraded to Visual Studio 2010</h5> -<p>As was <a class="reference external" href="http://blog.python.org/2012/05/recent-windows-changes-in-python-33.html">recently covered</a>, the Alpha 4 Windows installers now feature binaries produced by Visual Studio 2010, up from the 2008 version. We needed to upgrade to keep up with what most organizations and many of our contributors were using, along with the fact that <em>not changing</em> would mean we'd be at least two versions behind at our next opportunity to do so. With Python 3.4 not coming out until some time in 2014, we didn't want to end up eight years behind the curve and have to make that big of a version jump.</p> -</div> -</div> -<div class="section" id="bug-fixes"> -<h4>Bug Fixes</h4> -<p>As with all of our releases, many contributors submitted patches to fix over 80 issues since last month's Alpha 3. We have fixes across a number of modules, including batches of fixes to <a class="reference external" href="http://docs.python.org/dev/library/idle.html">IDLE</a>, <a class="reference external" href="http://docs.python.org/dev/library/email.html">email</a>, and <a class="reference external" href="http://docs.python.org/dev/library/urllib.request.html">urllib</a>.</p> -</div> -<div class="section" id="we-need-your-help"> -<h4>We Need Your Help!</h4> -<p>As with all of our releases, backwards compatibility is important to us, so we'd love to hear if any of your projects have issues. Please help us make the best release possible by <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">trying it out</a>!</p> -<p>Python 3.3 is quickly shaping up to be the release everyone's waiting for, so run your tests and report your issues to <a class="reference external" href="http://bugs.python.org">http://bugs.python.org</a>.</p> -<hr class="docutils" /> -<p><a class="reference external" href="http://www.python.org/download/releases/3.3.0/">Download it now</a>!</p> -</div> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rUOAjDbK18A:ezJqXnlP8Gg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rUOAjDbK18A:ezJqXnlP8Gg:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rUOAjDbK18A:ezJqXnlP8Gg:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rUOAjDbK18A:ezJqXnlP8Gg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rUOAjDbK18A:ezJqXnlP8Gg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rUOAjDbK18A:ezJqXnlP8Gg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rUOAjDbK18A:ezJqXnlP8Gg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rUOAjDbK18A:ezJqXnlP8Gg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/rUOAjDbK18A" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/06/python-33-alpha-4-released.htmltag:blogger.com,1999:blog-3941553907430899163.post-21176445189675247772012-05-24T11:00:00.000-04:002012-05-24T12:08:43.331-04:002012-05-24T12:08:43.331-04:00Recent Windows Changes in Python 3.3<div class="document" id="recent-windows-changes-in-python-3-3"> -The Windows build of Python 3.3 has recently seen changes that could use a look from the community throughout our alpha and beta cycle. The first change is the long requested addition of Python to the system <tt class="docutils literal">Path</tt> variable, which was completed in the installer. Secondly, the build was upgraded to Visual Studio 2010.<br /> -<br /> -<div class="section" id="python-on-the-path"> -<h4> - - -Python on the Path</h4> -A long requested feature, especially from beginners to those involved in education and training, has been the ability for the Python installer to place itself in the system <tt class="docutils literal">Path</tt> environment variable. Having the following message appear when you try to run a simple exercise is not a great first experience:<br /> -<blockquote> -<tt class="docutils literal">'python' is not recognized as an internal or external command, operable program or batch file.</tt></blockquote> -Because of that, the first post-install step by many users is to edit the <tt class="docutils literal">Path</tt> environment variable manually to insert the C:Python33 directory. This allows the user to simply type <tt class="docutils literal">python</tt> on the command line and have it open <tt class="docutils literal"><span class="pre">C:\\Python33\\python.exe</span></tt> -- a very desirable feature for a majority of users. In fact, it's such a common post-install step that there are a huge amount of tutorials either about this step by itself or tutorials where their setup introduces this step before moving on.<br /> -<blockquote> -<img alt="http://i.imgur.com/aixuY.png" src="http://i.imgur.com/aixuY.png" /> -</blockquote> -The easiest part of the whole thing was <a class="reference external" href="http://hg.python.org/cpython/rev/4e9f1017355f">the code</a>. <tt class="docutils literal">Path</tt> manipulation in the installer consists of adding a new feature to the Feature table, then the Environment table may be updated based on selection of the Path feature. If the feature was selected, the Environment table is modified in a way that the <tt class="docutils literal">Path</tt> is prepended to and will be correctly cleaned up on uninstallation.<br /> -<br /> -The harder part was deciding how to go about the change. If you're going to provide <tt class="docutils literal">Path</tt> manipulation, the major questions are to do it by default or not, and to prepend or append to the <tt class="docutils literal">Path</tt>.<br /> -<br /> -We decided that it wasn't appropriate to make this a default feature. For one, in the dual-version state many users are running in, we run the risk of users running through the installer and putting their system into a state they aren't prepared for. We don't want to change the meaning of <tt class="docutils literal">python</tt> when executed on the command line without the user asking for it. On one hand it's a very beginner focused feature in that it gets a first-timer successfully up and running with ease. However, it's also an advanced feature in that it takes a good understanding of what it's going to do to the users who have 2.6, 2.7, 3.2, and now 3.3 on their machines. We think the best solution for all is to leave it up to them and include an explanation.<br /> -<br /> -The other part we had to think about was whether to prepend or append to the path. While some believe that appending to the path is the more friendly way to work with the system, it would seem to be of limited utility given that the feature is added this late in the game. Instead we went the route of prepending the installation folder, e.g., C:\Python33, in order to make sure this feature is actually useful to our users.<br /> -<br /> -If you have questions or comments, please feel free to raise them on python-dev or see <a class="reference external" href="http://bugs.python.org/issue3561">Issue 3561</a>.<br /> -<br /></div> -<div class="section" id="transition-to-visual-studio-2010"> -<h4> - - -Transition to Visual Studio 2010</h4> -In time for the last alpha release, we've updated our build tools from Visual Studio 2008 to 2010.<br /> -Many potential contributors as well as general Python users have long moved to work environments that use Visual Studio 2010. During a "bug day" some months ago, we had two or three patches come from interested first-timers who found our VS2008 solution not working in VS2010. Over time we received a few more contributions and bug reports on the topic, as well as some chatter in IRC about being behind the curve.<br /> -<br /> -On top of that, my employer at the time moved to VS2010 as well as the employers of at least one other core maintainer, so we were already operating on ports for our companies.<br /> -<br /> -When it came time to think about what to do for Python 3.3, moving to VS2010 became a <em>must have</em> due to our release schedule. Staying with VS2008 for 3.3 would put us into the middle of 2014 as the next time we could release on a new version. That would leave us at least two versions behind, with VS2010 as well as VS11 being available by then.<br /> -<br /> -Another reason is the relative ease of porting between VS2010 and VS11. Once we got ourselves on to 2010, moving on to 11 would not be that hard. VS11 currently reads our VS2010 files without change if you want to use the IDE features of VS11. However, there'd need to be another port in order to use the VS11 compiler suite, but it seems to require minimal effort. Just following the VS11 wizard produced a functioning executable, although it didn't build cleanly.<br /> -<br /> -<div class="section" id="where-to-get-visual-studio-2010"> -<h5> - - -Where to get Visual Studio 2010?</h5> -As usual, Microsoft provides a zero-cost version of Visual Studio 2010 in the name Visual C++ Express, available at <a class="reference external" href="http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express">http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express</a>. While there are <a class="reference external" href="http://msdn.microsoft.com/en-us/library/hs24szh9(v=vs.100).aspx">some differences</a> between the Express version and the for-purchase versions, the Express version is used successfully by many contributors.<br /> -<br /> -The fine folks at Microsoft's <a class="reference external" href="http://www.microsoft.com/en-us/openness/default.aspx#home">Open Source Technology Center</a> have provided the core contributors with MSDN licenses free of charge, allowing for access to the full versions of Visual Studio among other products. The full versions of Visual Studio support 64-bit compilation which comes in handy for our amd64 releases, which have been available since 2.5.<br /> -<br /></div> -</div> -<div class="section" id="help-us-out-try-the-alphas-and-betas"> -<h4> - - -Help us out -- try the alphas and betas!</h4> -With a change to the installer, a new build system, and the <a class="reference external" href="http://docs.python.org/dev/whatsnew/3.3.html">other great changes</a> we have in store, the more feedback we hear from the community during the development cycle, the better we can make this release. If you have a chance to run your projects on Python 3.3, <a class="reference external" href="http://bugs.python.org/">http://bugs.python.org</a> is always open for your reports. You've even got a month to get feature requests in and completed!<br /> -<br /> -The last alpha release is scheduled for this weekend, and the first beta release is scheduled for June 24. You can download our 3.3.0 releases at <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">http://www.python.org/download/releases/3.3.0/</a>.</div> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/rWPwayEXWfE" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/05/recent-windows-changes-in-python-33.htmltag:blogger.com,1999:blog-3941553907430899163.post-86221028548645707822012-03-14T10:05:00.000-04:002012-03-14T23:36:35.528-04:002012-03-14T23:36:35.528-04:002012 Language Summit Report<div class="document" id="language-summit-report"> -This year's Language Summit took place on Wednesday March 7 in Santa Clara, CA before the start of <a class="reference external" href="https://us.pycon.org/2012/">PyCon 2012</a>. As with previous years, in attendance were members of the various Python VMs, packagers from various Linux distributions, and members of several community projects.<br /><br /> -<div class="section" id="the-namespace-peps"> -<h4> -The Namespace PEPs</h4> -The summit began with a discussion on PEPs <a class="reference external" href="http://www.python.org/dev/peps/pep-0382/">382</a> and <a class="reference external" href="http://www.python.org/dev/peps/pep-0402/">402</a>, with Barry Warsaw leading much of the discussion. After some discussion, the decision was ultimately deferred with what appeared to be a want for parts of both PEPs.<br /> -<br /> -As of Monday at the PyCon sprints, both PEPs have been rejected (see the Rejection Notice at the top of each PEP). Martin von Loewis <a class="reference external" href="http://mail.python.org/pipermail/import-sig/2012-March/000421.html">posted to the import-sig list</a> that a resolution has been found and Eric Smith will draft a new PEP on the ideas agreed upon there. Effectively, PEP 382 has been outright rejected, while portions of PEP 402 will be accepted.</div> -<br /> -<div class="section" id="importlib-status"> -<h4> -<tt class="docutils literal">importlib</tt> Status</h4> -Brett Cannon announced that there is a completed and available branch of CPython using importlib at <a class="reference external" href="http://hg.python.org/sandbox/bcannon/">http://hg.python.org/sandbox/bcannon/</a>. See the <tt class="docutils literal">bootstrap_importlib</tt> named branch.<br /> -<br /> -Discussion began by outlining the only real existing issue, which lies in <tt class="docutils literal">stat</tt>'ing of directories. There's a minor backwards incompatibility issue with time granularity. However, everyone agreed that it's so unlikely to be of issue that it's not a showstopper and the work can move forward. Additionally, there was an optimization made around the <tt class="docutils literal">stat</tt> calls, which was arrived at independently by each of Brett, Antoine Pitrou, and P.J. Eby.<br /> -<br /> -The topic of performance came up and Brett explained that the current pure-Python implementation is around 5% slower. Thomas Wouters exclaimed that 5% slower is actually really good, especially given some recent benchmark work he was doing showing that changing compilers sometimes shows a 5% difference in startup time. There was a shared feeling that 5% slower was not something to hold up integration of the code, which pushed discussion happily along.<br /> -<br /> -Brett went on to explain what the bootstrapping actually looks like, even asserting that the implementation finds what could be the first <em>real</em> use of frozen modules! Guido's first response was, "you mean to tell me that after 20 years we finally found a use for freezing code?"<br /> -<br /> -<tt class="docutils literal">importlib._bootstrap</tt> is a frozen module containing the necessary builtins to operate, along with some re-implementations of a small number of functions. Some of the libraries included in the frozen module are <tt class="docutils literal">warnings</tt>, <tt class="docutils literal">_os</tt> (select code from <tt class="docutils literal">posix</tt>), and <tt class="docutils literal">marshal</tt>.<br /> -<br /> -Another compatibility issue was brought up, but again, was decided to be an issue unworthy of halting the progress on this issue. There's a negative level count which is not supported in <tt class="docutils literal">importlib</tt>, used in implicit relative imports, and it was agreed that it's acceptable to continue not supporting it.<br /> -<br /> -The future will likely result in a strip down of <tt class="docutils literal">import.c</tt>, as well as the exposure of numerous hooks as well as exposure of much of the <tt class="docutils literal">importlib</tt> API.<br /> -<br /> -As for merging with the <tt class="docutils literal">default</tt> branch, it was pretty universally agreed upon that this should happen for 3.3 and it should happen soon in order to get mileage on the implementation throughout the alpha and beta cycles. Since this will be happening shortly, Brett is going to follow-up to python-dev with some cleanup details and look for reviews.</div> -<br /> -<div class="section" id="release-schedule-peps"> -<h4> -Release Schedule PEPs</h4> -Discussion on PEPs <a class="reference external" href="http://www.python.org/dev/peps/pep-0407/">407</a> and <a class="reference external" href="http://www.python.org/dev/peps/pep-0413/">413</a> followed the <tt class="docutils literal">importlib</tt> talk. Like the namespace PEP discussion, several ideas were tossed around but the group didn't arrive at any conclusion on acceptability of the PEPs.<br /> -<br /> -Immediately, the idea of splitting out the standard library to be on its own was resurrected, which could lend itself to both PEPs. Some questions remain, namely in where would the test suite live. Additionally, there may need to be some distinction between the tests which cover standard libraries versus the tests which cover language features.<br /> -<br /> -The topic of versioning came up, with three distinctions needing to be made. We would seem to need a version of the language spec, a version of the implementation, and a version of the standard library.<br /> -<br /> -Many commenters mentioned that these PEPs make things too complicated. Additionally, there was a question about whether there are enough users who care about either of these changes being made. Several of us stated that <em>we</em> could use the quicker releases, but with so many users being stuck on old versions for one reason or another, there was a wonder of who would take the releases.<br /> -<br /> -Thomas Wouters mentioned a good point about the difficulty in lining up the so-called Python "LTS" releases with other Python consumers who do similar LTS-style releases. Ubuntu and their LTS schedule was a prime example, as well as the organizations who plan releases atop something like Ubuntu. Many of the Linux distribution packagers in attendance seemed to agree.<br /> -<br /> -One thing that seemed to have broad agreement was that shortening the standard library turnaround time would be a good thing in terms of new contributors. Few people are interested in writing new features that might not be released for over a year -- it's just not fun. Even with bug fixes, sometimes the duration can be seen as too long, to the point where users may end up just fixing our problems from within their own code if possible.<br /> -<br /> -Guido went on to make a comment about how we hope to avoid the mindset some have of "my package isn't accepted until it's in the standard library". The focus continues to be on projects being hosted on PyPI, being successful out in the wild, then vetted for acceptance in the standard library after maturity of the project and its APIs.<br /> -<br /> -It was suggested that perhaps speeding up bug fix releases could be a good move, but we would need to check with release managers to ensure they're on board and willing to expend the effort to produce more frequent releases. As with the new feature releases, we need to be sure there's an audience to take the new bug fixes.<br /> -<br /> -There was also some discussion about what have previously been called "sumo" releases. Given that some similar releases are already made by third-party vendors, the idea didn't seem to gain much traction.</div> -<br /> -<div class="section" id="funding-from-the-python-software-foundation"> -<h4> -Funding from the Python Software Foundation</h4> -PSF Chairman Steve Holden joined the group after lunch to mention that the foundation has resources available to assist development efforts, especially given the sponsorship success of this year's conference. While the foundation can't and won't dictate what should be coded up, they're open to proposals about the types of work to be funded.<br /> -<br /> -Steve and Jesse Noller were adamant about the support not only being for all Python implementations, but also for third-party projects. What's needed to begin funding for a project is a concrete proposal on what will be accomplished. They stressed that the money is ready and waiting -- proposals are the way to unlock it.<br /> -<br /> -Some ideas for how to use the funding came from Steve but also from around the room. One idea which started off the discussion was the idea of funding one-month sabbaticals. Then comes the issue of who might be available. Some suggested that freelance consultants in the development community might be the ones we should try to engage. Those with full-time employment may find it harder to acquire such a sabbatical, but the possibility is open to anyone.<br /> -Another thought was potential funding of someone to do spurts of full-time effort on the bug tracker, ideally someone already involved in the triage effort. This type of funding would hope to put an end to the times when it takes three days to fix a bug and three years for the patch to be accepted. Some thought this might be a nice idea in the short term, but it could be tough work and burn out the individual(s) involved. If anyone is up for it, they're encouraged to propose the idea to the foundation.<br /> -<br /> -Along similar lines of tracker maintenance, Glyph Lefkowitz of the Twisted project had an idea to fund code reviews over code-writing efforts. Some thought this might be a good way to push forward the <tt class="docutils literal">regex</tt>/<tt class="docutils literal">re</tt> situation, given that the <tt class="docutils literal">regex</tt> is very large and most felt that the only thing holding it back from some form of inclusion is an in-depth review. The <tt class="docutils literal">cdecimal</tt> module was mentioned as another project that could use some review assistance.<br /> -<br /> -The code review funding is also an idea to push forward some third-party project's ports to Python 3, specifically including Twisted, which the group felt was an effort which should receive some of this funding.<br /> -<br /> -Along the way it was remarked that the <a class="reference external" href="http://pythonmentors.com/">core-mentors</a> group has been a success in involving new contributors. Kudos to those involved with that list.</div> -<br /> -<div class="section" id="virtualenv-inclusion"> -<h4> -<tt class="docutils literal">virtualenv</tt> Inclusion</h4> -In about two minutes, discussion on PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0405/">405</a> came and went. Carl Meyer mentioned that a reference implementation is available and is working pretty well. A look from the OSX maintainers would be beneficial, and both Ned Deily and Ronald Oussoren were in attendance. It seemed like one of the only things left in terms of the PEP was to find someone to make a declaration on it, and Thomas Wouters put his name out there if Nick Coghlan wasn't going to do t (update: Nick will be the PEP czar).</div> -<br /> -<div class="section" id="pep-397-inclusion"> -<h4> -PEP 397 Inclusion</h4> -Without much of a Windows representation at the summit, discussion was fairlyquick, but it was pretty much agreed that PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0397/">397</a> was something we should accept. Brian Curtin spoke in favor of the PEP, as well as mentioning ongoing work on the Windows installer to optionally add the executable's directory to the Path.<br /> -<br /> -After discussion outside of the summit, it was additionally agreed upon that the launcher should be installed via the 3.3 Windows installer, while it can also live as a standalone installer for those not taking 3.3. Additionally, there needs to be some work done on the PEP to remove much of the low-level detail that is coupled too tightly with the implementation, e.g., explaining of the location of the <tt class="docutils literal">py.ini</tt> file.</div> -<br /> -<div class="section" id="speed-python-org"> -<h4> -speed.python.org</h4> -After generous hardware donations, the <a class="reference external" href="http://speed.python.org/">http://speed.python.org</a> site has gone live and is currently running PyPy benchmarks. We need to make a decision on what benchmarks can be used as well as what benchmarks <em>should</em> be used when it comes to creating a Python 3 suite. As we get implementations on Python 3 we'll want to scale back 2.7 testing and push forward with 3.x.<br /> -<br /> -The project suffers not from a technological problem but from a personnel problem, which was thought to be another area that funding could be used for. However, even if money is on the table, we still need to find someone with the time, the know-how, and the drive to complete the task. Ideally the starting task would be to get PyPy and CPython implementations running and comparing. After that, there are a number of infrastructure tasks in line.</div> -<br /> -<div class="section" id="pep-411-inclusion"> -<h4> -PEP 411 Inclusion</h4> -PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0411/">411</a> proposes the inclusion of provisional packages into the standard library. The recently discussed <tt class="docutils literal">regex</tt> and <tt class="docutils literal">ipaddr</tt> modules were used as examples of libraries to include under this PEP. As for how this inclusion should be implemented and denoted to users was the major discussion point.<br /> -<br /> -It was first suggested that documentation notes don't work -- we can't rely only on documentation to be the single notification point, especially for this type of code inclusion. Other thoughts were some type of flag on the library to specify its experimental status. Another thought was to emit a warning on import of a provisional library, but it's another thing that we'd likely want to silence by default in order to not affect user code in the hopes that developers are running their test suite with warnings enabled. However, as with other times we've gone down this path, we run the risk of developers just disabling warnings all together if they become annoying.<br /> -<br /> -As has been suggested on python-dev, importing a provisional library from a special package, e.g., <tt class="docutils literal">from __experimental__ import foo</tt>, was pretty strongly discouraged. If the library gains a consistent API, it penalizes users once it moves from provisional status to being officially accepted. Aliasing just exacerbates the problem.<br /> -<br /> -The PEP boils down to being about process, and we need to be sure that libraries being included use the ability to change APIs very carefully. We also need to make people, especially the library author, aware of the need to be responsive to feedback and open to change as the code reaches a wider audience.<br /> -<br /> -Looking back, Jesse Noller suggested <tt class="docutils literal">multiprocessing</tt> would have been a good candidate for something like this PEP is suggesting. Around this time, it was suggested that Michael Foord's <a class="reference external" href="http://www.voidspace.org.uk/python/mock/">mock</a> could gain some provisional inclusion within <tt class="docutils literal">unittest</tt>, perhaps as <tt class="docutils literal">unittest.mock</tt>. Instead, given <tt class="docutils literal">mock</tt>'s stable API and wide use among us, along with the need for a mocking library within our own test suite, it was agreed to just accept it directly into the standard library without any provisional status.<br > -<br /> -While on the topic of ``regex``'s role within the PEP came an idea from Thomas Wouters that ``regex`` be introduced into the standard library, bypassing any provisional status. From there, the previously known ``re`` module could be moved to the ``sre`` name, and there didn't appear to be any dissenting opinion there.<br /> -<br /> -It should also be noted to users of provisional libraries that the library maintainers would need to exercise extreme care and be very conservative in changing of the APIs. The last thing we want to do is introduce a good library but as a moving target to its users.<br /> -</div> -<br /> -<div class="section" id="keyword-arguments-on-all-builtin-functions"> -<h4> -Keyword Arguments on all builtin functions</h4> -As recently came up on the tracker, it was suggested that wider use of keyword arguments in our APIs would likely be a good thing. Gregory P. Smith suggested that we leave single-argument APIs alone, which was agreed upon. However, the overall change got some push back as "change for change's sake".<br /> -<br /> -In order to support this, the <tt class="docutils literal">PyArg_ParseTuple</tt> function would need to do more work, and it's already known to be somewhat slow. Alternatively, <tt class="docutils literal">PyArg_Parse</tt> is much faster, and the tuple version could take a thing or two from it regardless of any wide scale change to builtins.<br /> -<br /> -There does exist some potential break in compatibility when replacing a builtin function with a Python one, where positional-only arguments suddenly get a potentially conflicting name.<br /> -<br /> -It was widely agreed upon that we should avoid any blanket rules and keep changes to places where it makes sense rather than make wholesale changes. We also need to be mindful of documentation and doc strings being kept to match the actual keyword argument names as well as keep them in sync.<br /> -<br /> -OrderedDict was suggested as the container for keyword arguments, but Guido and Gregory were unsure of use-cases for that. Whether or not we use a traditional or ordered dictionary, it was suggested that we could possibly use a decorator to handle some of this. We could even go as far as exposing something like <tt class="docutils literal">PyArg_ParseTuple</tt> as a Python-level function.<br /> -<br /> -PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0362/">362</a>, a proposal for a function signature object, would help here and with decorators in general. It seems that all that's left with that PEP is another look and someone to declare on it.</div> -<br /> -<div class="section" id="porting-to-python-3"> -<h4> -Porting to Python 3</h4> -We moved on to talk about Python 3 porting, starting with the current strategies and how they're working out. Single-codebase porting is working better than expected for most of us, although <tt class="docutils literal">except</tt> handling is a bit messy when supporting versions like 2.4. Having a lot of options, from 3to2 to 2to3, then the single codebase through parallel trees, is a really good thing. However, it's hard for us to choose a strategy for projects, so we don't, which is why most documentation tries to lay numerous strategies out there.<br /> -<br /> -It was suggested that documentation could stand to gain more examples of real-world porting examples, ideally pointing to changesets of these projects. The thought of our porting documentation gaining a cookbook-style approach seemed to get some agreement as a good idea.</div> -<br /> -<div class="section" id="hash-randomization"> -<h4> -Hash Randomization</h4> -Release candidates are available to all branches receiving security fixes, and in the meantime, David Malcolm found and reported a security issue in the upstream <tt class="docutils literal">expat</tt> project. However, since the upstream fix includes many other fixes at the same time, we should pick up only the security fix at this time and leave the bug fixes for the next bug fix release of the relevant branches.</div> -<br /> -<div class="section" id="new-dict-implementation"> -<h4> -New <tt class="docutils literal">dict</tt> Implementation</h4> -Since the implementation makes sense and the tests pass, it was quickly agreed upon that Mark Shannon's PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0412/">412</a> should be accepted. As with other changes agreed upon in this summit, we'd like for the change to be pushed soon in order to get mileage on it throughout the alpha and beta cycles. With this acceptance comes commit access for Mark so that he can maintain the code.<br /> -<br /> -It was also remarked that the only user-visible difference that this implementation brings is a difference in sort ordering, but the recent hash randomization work makes this a moot point.<br /></div> -<br /> -<div class="section" id="new-pickle-protocol"> -<h4> -New <tt class="docutils literal">pickle</tt> Protocol</h4> -PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-3154/">3154</a>, mentioned by Lukasz Langa, specifies a new pickle protocol -- version 4. Lukasz mentioned exception pickling in <tt class="docutils literal">multiprocessing</tt> as being an issue, and Antoine solved it with this PEP. While qualified names provide some help, it was agreed upon that this PEP needs more attention.<br /> -<hr class="docutils" /> -<br /> -If you have any questions or comments, please post to <a class="reference external" href="http://mail.python.org/mailman/listinfo/python-dev">python-dev</a>.<br /> -<br /> -<em>Thanks to Eric Snow and Senthil Kumaran for contributing to this post.</em></div> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ZLaHCD80z5E:ySbBd-izDGM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ZLaHCD80z5E:ySbBd-izDGM:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ZLaHCD80z5E:ySbBd-izDGM:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ZLaHCD80z5E:ySbBd-izDGM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ZLaHCD80z5E:ySbBd-izDGM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ZLaHCD80z5E:ySbBd-izDGM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ZLaHCD80z5E:ySbBd-izDGM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ZLaHCD80z5E:ySbBd-izDGM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/ZLaHCD80z5E" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/03/2012-language-summit-report.htmltag:blogger.com,1999:blog-3941553907430899163.post-59360939132650670282011-08-24T09:53:00.001-04:002011-08-24T09:53:33.817-04:002011-08-24T09:53:33.817-04:00Meet the Team: Brett Cannon<div class="document" id="meet-the-team-brett-cannon"> -<p><em>This post is part of the &quot;Meet the Team&quot; series of posts, which is meant to give a brief introduction to the Python core development team.</em></p> -<table class="docutils field-list" frame="void" rules="none"><col class="field-name"></col><col class="field-body"></col><tbody valign="top"><tr class="field"><th class="field-name">Name:</th><td class="field-body">Brett Cannon</td></tr><tr class="field"><th class="field-name">Location:</th><td class="field-body">San Francisco, CA, USA</td></tr><tr class="field"><th class="field-name">Home Page:</th><td class="field-body"><a class="reference external" href="https://profiles.google.com/bcannon">https://profiles.google.com/bcannon</a></td></tr><tr class="field"><th class="field-name">Blog:</th><td class="field-body"><a class="reference external" href="http://sayspy.blogspot.com">http://sayspy.blogspot.com</a></td></tr></tbody></table> -<p><strong>How long have you been using Python?</strong></p> -<p>Since the fall of 2000</p> -<p><strong>How long have you been a core committer?</strong></p> -<p>Since April 2003 (shortly after PyCon 2003).</p> -<p><strong>How did you get started as a core developer? Do you remember your first commit?</strong></p> -<p>I became a core developer thanks to incessantly bugging people to commit patches for me (a trick that doesn't quite work as well as it used to; perk of getting in before Python's popularity spikein 2003/2004). Starting in August 2002 I revitalized the Python-Dev Summaries (which lasted for about 2.5 years). While writing the Summaries I would fairly regularly pick up on little issues that needed fixing. Since I was already talking on python-dev fairly regularly I simply asked folks to check my patches and commit them for me. One day Guido just asked why I didn't commit myself, I said I didn't have commit rights, and then he more or less said &quot;you do now&quot;.</p> -<p>As for my first commit (changeset 28686), it was fixing some string escapement in time.strptime() (which happens to be my first contribution to Python itself).</p> -<p><strong>Which parts of Python are you working on now?</strong></p> -<p>I typically focus on the import machinery and making the Python language work well across all VMs.</p> -<p><strong>What do you do with Python when you aren't doing core development work?</strong></p> -<p>I managed to use Python a little bit in my PhD thesis by implementing some server-side stuff in Python. Otherwise all of my personal projects use Python as much as possible. And my future job at Google is going to be mostly in Python.</p> -<p><strong>What do you do when you aren't programming?</strong></p> -<p>I'm somewhat of a movie junkie with selective bits of TV tossed in (losing my television in the summer of 2000 to a heat wave was one of the best things that ever accidentally happened to me; marrying my wife has been the best thing I did on purpose =). Otherwise I read a lot; mostly magazines and websites, but with some book always under progress.</p> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TfQ5Aqj0liU:SIyoG2wHDSA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TfQ5Aqj0liU:SIyoG2wHDSA:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TfQ5Aqj0liU:SIyoG2wHDSA:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TfQ5Aqj0liU:SIyoG2wHDSA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TfQ5Aqj0liU:SIyoG2wHDSA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TfQ5Aqj0liU:SIyoG2wHDSA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TfQ5Aqj0liU:SIyoG2wHDSA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TfQ5Aqj0liU:SIyoG2wHDSA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/TfQ5Aqj0liU" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/08/meet-team-brett-cannon.htmltag:blogger.com,1999:blog-3941553907430899163.post-31132325031242113212011-08-08T09:09:00.000-04:002011-08-08T09:21:37.739-04:002011-08-08T09:21:37.739-04:00Meet the Team: Michael Foord<div class="document" id="meet-the-team-michael-foord"> -<p><em>This post is part of the &quot;Meet the Team&quot; series of posts, which is meant to give a brief introduction to the Python core development team.</em></p> -<table class="docutils field-list" frame="void" rules="none"><col class="field-name"></col><col class="field-body"></col><tbody valign="top"><tr class="field"><th class="field-name">Name:</th><td class="field-body">Michael Foord</td></tr><tr class="field"><th class="field-name">Location:</th><td class="field-body">Northampton UK</td></tr><tr class="field"><th class="field-name">Home Page:</th><td class="field-body"><a class="reference external" href="http://www.voidspace.org.uk/">http://www.voidspace.org.uk/</a></td></tr></tbody></table> -<p><strong>How long have you been using Python?</strong></p> -<p>I first started using Python as a hobby in 2002. I started using Python full time for work in 2006. When I started programming with Python it was with a group of guys who wanted to write a program to aggregate information from a Play By Email game. None of us had done any programming for a while and we had just decided on using Smalltalk when someone suggested we try Python. I quickly fell in love with Python.</p> -<p><strong>How long have you been a core committer?</strong></p> -<p>I became a core-committer at PyCon in 2009. It was originally because of my involvement with IronPython.</p> -<p><strong>How did you get started as a core developer? Do you remember your first commit?</strong></p> -<p>During the PyCon 2009 sprints I worked with Gregory Smith, another core developer, to incorporate some improvements to unittest contributed by Google.</p> -<p><strong>Which parts of Python are you working on now?</strong></p> -<p>After the initial work on unittest at the PyCon sprint I took on fixing other issues and making improvements to unittest, which was without a maintainer. I became the maintainer of unittest but also contribute to other parts of the standard library.</p> -<p>I'm involved in supporting Python in various other minor ways, such as looking after Planet Python, being a PSF member, helping out on the python.org webmaster alias and so on.</p> -<p><strong>What do you do with Python when you aren't doing core development work?</strong></p> -<p>For my day job I do web development for Canonical. I work on some of the web services infrastructure around the Canonical websites and also some of the services that integrate with Ubuntu itself. That's good fun and its a great team.</p> -<p>In my spare time I work on projects like <a class="reference external" href="http://pypi.python.org/pypi/unittest2">unittest2</a> (a backport of the improvements of unittest for other platforms), <a class="reference external" href="http://pypi.python.org/pypi/mock">mock</a> (a testing library that provides mock objects and support for monkey patching in tests) and a whole bunch of other smaller stuff.</p> -<p>I'd like to write more, but having devoted the best part of two years to writing IronPython in Action I doubt I'll take on any large writing projects soon.</p> -<p><strong>What do you do when you aren't programming?</strong></p> -<p>I'm very involved in a church in Northampton (UK), which takes a lot of my time and I help with administration for a charity we run. This is one reason why working for Canonical is good - I can work from home and having put my roots down here I won't move anywhere else (I certainly don't stay for the weather). Needless to say there isn't much Python programming happening in Northampton. My first full time programming gig was with an amazing team in London, which was a two hour door to door commute each way. I managed four years of that, and really enjoyed the job, but having escaped the commute I'm not likely to ever go back.</p> -<p>I also enjoy gaming on the XBox. Unfortunately if I find a game I like I can get sucked into it for weeks so I have to be careful. I've avoided world of warcraft and eve online for this reason... I also organise a monthly geek meet in Northampton. There aren't enough Python programmers for a Python user group but we have a good collection of geeks of all sorts. We normally just get together in a pub and chew the fat or show off our latest gadgets.</p> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=szWrurZ-wqo:4pbNUjG7kzo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=szWrurZ-wqo:4pbNUjG7kzo:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=szWrurZ-wqo:4pbNUjG7kzo:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=szWrurZ-wqo:4pbNUjG7kzo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=szWrurZ-wqo:4pbNUjG7kzo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=szWrurZ-wqo:4pbNUjG7kzo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=szWrurZ-wqo:4pbNUjG7kzo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=szWrurZ-wqo:4pbNUjG7kzo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/szWrurZ-wqo" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/08/meet-team-michael-foord.htmltag:blogger.com,1999:blog-3941553907430899163.post-28161494873014049382011-07-11T13:11:00.000-04:002011-07-11T13:11:07.551-04:002011-07-11T13:11:07.551-04:00A Python Launcher For Windows<div class="document" id="a-python-launcher-for-windows"> <p>Mark Hammond (author of <a class="reference external" href="http://sourceforge.net/projects/pywin32/">pywin32</a> and long-time supporter of Python on Windows) has written <a class="reference external" href="http://www.python.org/dev/peps/pep-0397/">PEP 397</a>, which describes a new launcher for Python on Windows. Vinay Sanjip (author of the standard library <a class="reference external" href="http://docs.python.org/py3k/library/logging.html">logging</a> module) has recently created an implementation of the launcher, downloadable from <a class="reference external" href="https://bitbucket.org/vinay.sajip/pylauncher/downloads">https://bitbucket.org/vinay.sajip/pylauncher/downloads</a></p><p>The launcher allows Python scripts (<tt class="docutils literal">.py</tt> and <tt class="docutils literal">.pyw</tt> files) on Windows to specify the version of Python which should be used, allowing simultaneous use of Python 2 and 3.</p><p>Windows users should consider downloading the launcher and testing it, to help the Python developers iron out any remaining issues. The launcher is packaged as a standalone application, and will support currently available versions of Python. The intention is that once the launcher is finalised, it will be included as part of Python 3.3 (although it will remain available as a standalone download for users of earlier versions).</p><p>Two versions of the launcher are available - <tt class="docutils literal">launcher.msi</tt> which installs in the <tt class="docutils literal">Program Files</tt> directory, and <tt class="docutils literal">launchsys.msi</tt> which installs in Windows' <tt class="docutils literal">System32</tt> directory. (There are also 64-bit versions for 64-bit versions of Windows).</p><div class="section" id="some-details-about-the-launcher"><h4>Some Details About the Launcher</h4><p>The full specification of the behaviour of the launcher is given in <a class="reference external" href="http://www.python.org/dev/peps/pep-0397/">PEP 397</a>. To summarise the basic principles:</p><ul class="simple"><li>The launcher supplies two executables - <tt class="docutils literal">py.exe</tt> (the console version) and <tt class="docutils literal">pyw.exe</tt> (the GUI version).</li> -<li>The launcher is registered as the handler for <tt class="docutils literal">.py</tt> (console) and <tt class="docutils literal">.pyw</tt> (GUI) file extensions.</li> -<li>When executing a script, the launcher looks for a Unix-style <tt class="docutils literal">#!</tt> (shebang) line in the script. It recognises executable names <tt class="docutils literal">python</tt> (system default python), <tt class="docutils literal">python2</tt> (default Python 2 release) and <tt class="docutils literal">python3</tt> (default Python 3 release). The precise details can easily be customised on a per-user or per-machine basis.</li> -<li>When used standalone, the <tt class="docutils literal">py.exe</tt> command launches the Python interactive interpreter. Command line switches are supported, so that <tt class="docutils literal">py <span class="pre">-2</span></tt> launches Python 2, <tt class="docutils literal">py <span class="pre">-3</span></tt> launches Python 3, and <tt class="docutils literal">py</tt> launches the default version.</li> -</ul></div><div class="section" id="simple-usage-instructions"><h4>Simple Usage Instructions</h4><p>When it is installed, the launcher associates itself with <tt class="docutils literal">.py</tt> and <tt class="docutils literal">.pyw</tt> scripts. Unless you do anything else, scripts will be run using the default Python on the machine, so you will see no change. One thing you might like to do, if you use the console a lot, is to add <tt class="docutils literal">.py</tt> to your <tt class="docutils literal">PATHEXT</tt> variable so that scripts don't get executed in a separate console.</p><p>To specify that a script must use Python 2, simply add:</p><pre class="literal-block">#!/usr/bin/env python2 -</pre><p>as the first line of the script. (This is a Unix-compatible form. If you don't need Unix compatibility, <tt class="docutils literal">#!python2</tt> will do).</p><p>If on the other hand, you want to specify that a script must use Python 3, add:</p><pre class="literal-block">#!/usr/bin/env python3 -</pre><p>as the first line.</p><p>You can also start the Python interpreter using any of the following commands:</p><pre class="literal-block"># Default version of Python -py -# Python 2 -py -2 -# Python 3 -py -3 -</pre><p>For this to work, the <tt class="docutils literal">py.exe</tt> executable must be on your path. This is automatic with the <tt class="docutils literal">launchsys</tt> version of the installer, but the install directory (<tt class="docutils literal"><span class="pre">C:\Program</span> Files\Python Launcher</tt>) must be added manually to <tt class="docutils literal">PATH</tt> with <tt class="docutils literal">launcher.msi</tt>.</p></div><div class="section" id="further-reading"><h4>Further Reading</h4><p>The following email threads on python-dev cover some of the key discussions:</p><ul class="simple"><li>Mark's initial announcement of the draft PEP: <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-March/109509.html">http://mail.python.org/pipermail/python-dev/2011-March/109509.html</a></li> -<li>The second draft of the PEP: <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-March/109786.html">http://mail.python.org/pipermail/python-dev/2011-March/109786.html</a></li> -<li>Vinay's initial query about a C implementation of the launcher: <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-June/112145.html">http://mail.python.org/pipermail/python-dev/2011-June/112145.html</a></li> -<li>Vinay's announcement of his C implementation: <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-July/112184.html">http://mail.python.org/pipermail/python-dev/2011-July/112184.html</a></li> -<li>Vinay's call for testers: <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-July/112251.html">http://mail.python.org/pipermail/python-dev/2011-July/112251.html</a></li> -</ul></div></div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=1JqABSwTN5U:LfTvU-8RBmk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=1JqABSwTN5U:LfTvU-8RBmk:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=1JqABSwTN5U:LfTvU-8RBmk:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=1JqABSwTN5U:LfTvU-8RBmk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=1JqABSwTN5U:LfTvU-8RBmk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=1JqABSwTN5U:LfTvU-8RBmk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=1JqABSwTN5U:LfTvU-8RBmk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=1JqABSwTN5U:LfTvU-8RBmk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/1JqABSwTN5U" height="1" width="1"/>Paul Moorehttp://www.blogger.com/profile/17557923197983461835noreply@blogger.comhttp://blog.python.org/2011/07/python-launcher-for-windows_11.htmltag:blogger.com,1999:blog-3941553907430899163.post-87542017192875531832011-07-11T10:20:00.000-04:002011-07-11T10:21:31.074-04:002011-07-11T10:21:31.074-04:00CPython 3.2.1 Released<div class="document" id="cpython-3-2-1-released"> -<p>On behalf of the python-dev team, release manager <a class="reference external" href="http://pythonic.pocoo.org/">Georg Brandl</a> has announced the final release of <a class="reference external" href="http://www.python.org/download/releases/3.2.1/">CPython 3.2.1</a>. Windows installers and tarballs are available as of July 10, so please consider upgrading to this release.</p> -<p>The <a class="reference external" href="http://docs.python.org/3.2/whatsnew/3.2.html">What's New</a> document lists all of the new features in 3.2, and the <a class="reference external" href="http://hg.python.org/cpython/file/v3.2.1/Misc/NEWS">Misc/NEWS</a> file in the source lists each bug fixed.</p> -<p>If you find any issues with this release or any other, please report them to <a class="reference external" href="http://bugs.python.org/">http://bugs.python.org/</a>.</p> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tsieHw51jhc:G_3vQohz6Mo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tsieHw51jhc:G_3vQohz6Mo:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tsieHw51jhc:G_3vQohz6Mo:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tsieHw51jhc:G_3vQohz6Mo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tsieHw51jhc:G_3vQohz6Mo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tsieHw51jhc:G_3vQohz6Mo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tsieHw51jhc:G_3vQohz6Mo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tsieHw51jhc:G_3vQohz6Mo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/tsieHw51jhc" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/07/cpython-321-released.htmltag:blogger.com,1999:blog-3941553907430899163.post-5346886995889209832011-07-06T11:31:00.000-04:002011-07-06T11:35:31.744-04:002011-07-06T11:35:31.744-04:003.2.1 Release Candidate 2 Released<div class="document" id="release-candidate-2-released"> -<p>Following up a big month of <a class="reference external" href="http://blog.python.org/2011/06/june-releases-267-272-314.html">releases in June</a>, the second release candidate of the 3.2.1 line <a class="reference external" href="http://www.python.org/download/releases/3.2.1/">is now ready</a>. Since the first release candidate on May 15, over 40 issues have been fixed. We encourage everyone to test their projects with this candidate to get one last look before the final release of 3.2.1.</p> -<div class="section" id="what-s-fixed"><h4>What's fixed?</h4> -<div class="section" id="i-o"><h5>I/O</h5> -<p><a class="reference external" href="http://bugs.python.org/issue1195">#1195</a> spent a few years witout a fix, but a simple addition to clear errors before calling <tt class="docutils literal">fgets</tt> solves the problem of interrupting <tt class="docutils literal">sys.stdin.read()</tt> with CTRL-D inside of <tt class="docutils literal">input()</tt>. The <tt class="docutils literal">io</tt> system saw a cleanup in <a class="reference external" href="http://bugs.python.org/issue12175">#12175</a> with the <tt class="docutils literal">readall</tt> method with <tt class="docutils literal">None</tt> being the return value on a <tt class="docutils literal">read()</tt> which returns <tt class="docutils literal">None</tt>, and a <tt class="docutils literal">ValueError</tt> is now raised when a file can't be opened.</p> -<p>Although this isn't new for RC2, <a class="reference external" href="http://bugs.python.org/issue11272">#11272</a> is an important 3.2.1 fix to <tt class="docutils literal">input()</tt> on Windows - the fixing of a trailing <tt class="docutils literal">\r</tt>. The issue has been reported many times over and affects a many people (distutils upload command anyone?), so hopefully 3.2.1 does the trick for you.</p> -</div> -<div class="section" id="windows"><h5>Windows</h5> -<p>3.2.0 brought a new feature for Windows: <tt class="docutils literal">os.symlink</tt> support. With that feature came <a class="reference external" href="http://bugs.python.org/issue12084">#12084</a>, <tt class="docutils literal">os.stat</tt> was improperly evaluating Windows symlinks, so the inner workings of the various <tt class="docutils literal">stat</tt> functions were corrected.</p> -<p>A user noticed that <tt class="docutils literal">os.path.isdir</tt> was slow, and the fact that it relied on <tt class="docutils literal">os.stat</tt> contributed to that, especially when evaluating symlinks (which are generally twice as slow as regular files). While <tt class="docutils literal">os.path.isdir</tt> isn't anyone's performance bottleneck, it's called numerous times on interpreter startup so changing it in <a class="reference external" href="http://bugs.python.org/issue11583">#11583</a> to use <tt class="docutils literal">GetFileAttributes</tt> gives a tiny speedup to build on.</p> -</div> -<div class="section" id="subprocess"><h5>subprocess</h5> -<p>Creating a <tt class="docutils literal">Popen</tt> object with unexpected arguments was causing an <tt class="docutils literal">AttributeError</tt>, but that was reported in <a class="reference external" href="http://bugs.python.org/issue12085">#12085</a> and was fixed by the reporter. Due to a change in 3.2.0, <tt class="docutils literal">Popen</tt> wasn't correctly handling empty environment variables, specifically the <tt class="docutils literal">env</tt> argument. <a class="reference external" href="http://bugs.python.org/issue12383">#12383</a> was created for the issue and was promptly fixed.</p> -</div> -<div class="section" id="and-more"><h5>...and more!</h5> -<p>For a full list of changes through 3.2.1 RC2, check out <a class="reference external" href="http://hg.python.org/releasing/3.2.1/file/v3.2.1rc2/Misc/NEWS">the change log</a> and <a class="reference external" href="http://www.python.org/download/releases/3.2.1/">download it now</a>!</p> -<p>As always, please report any issues you find to <a class="reference external" href="http://bugs.python.org">http://bugs.python.org</a>. We appreciate your help in making great Python releases.</p> -</div> -</div> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qJVUVTi0FtY:PUk3o78ZLFA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qJVUVTi0FtY:PUk3o78ZLFA:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qJVUVTi0FtY:PUk3o78ZLFA:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qJVUVTi0FtY:PUk3o78ZLFA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qJVUVTi0FtY:PUk3o78ZLFA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qJVUVTi0FtY:PUk3o78ZLFA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qJVUVTi0FtY:PUk3o78ZLFA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qJVUVTi0FtY:PUk3o78ZLFA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/qJVUVTi0FtY" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/07/321-release-candidate-2-released.htmltag:blogger.com,1999:blog-3941553907430899163.post-33308038161260090022011-06-14T09:08:00.001-04:002011-06-14T09:09:54.410-04:002011-06-14T09:09:54.410-04:00June Releases - 2.6.7, 2.7.2, 3.1.4<div class="document" id="june-2011-releases"> -<p>June is a big month for Python releases, with an update coming out of all active branches.</p> -<div class="section" id="id1"> -<h4>2.6.7</h4> -<p>A new source-only release of Python <a class="reference external" href="http://www.python.org/download/releases/2.6.7/">2.6.7</a> is available, providing fixes to three security issues. Now that the 2.6 line is in security-mode, these releases will happen on an as-needed basis until October 2013 in source-only form. If you require binary installers, you should consider an upgrade to 2.7 or 3.2.</p> -<p>2.6.7 is the first release to contain a fix to the previously covered <a class="reference external" href="http://blog.python.org/2011/04/urllib-security-vulnerability-fixed.html">urllib vulnerability</a>. Additionally, an <tt class="docutils literal">smtpd</tt> DoS vulnerability (Issue <a class="reference external" href="http://bugs.python.org/issue9129">#9129</a>) and <tt class="docutils literal">SimpleHTTPServer.list_directory</tt> XSS vulnerability (Issue <a class="reference external" href="http://bugs.python.org/issue11442">#11442</a>) are fixed.</p> -</div> -<div class="section" id="id2"> -<h4>2.7.2</h4> -<p>The last minor version of the 2.x line, 2.7, received over 150 bug fixes since 2.7.1 in November 2010. <a class="reference external" href="http://www.python.org/download/releases/2.7.2/">2.7.2</a> source and binary installers are available as of June 12, which include the security fixes mentioned in 2.6.7.</p> -<p>A number of crashes are fixed: a situation when Python incorrectly used non-Python managed memory while it was being modified by another thread, when deleting <tt class="docutils literal">__abstractmethods__</tt> from a class, accessing a memory-mapped file past its length, and several others.</p> -<p>A fix to <tt class="docutils literal">getpass</tt> corrects a regression in regards to CTRL-C and CTRL-Z handling. <tt class="docutils literal">multiprocessing</tt> received a number of fixes, including treating Windows services like frozen executables and a correction to a race condition when terminating <tt class="docutils literal">multiprocessing.Pool</tt> workers. <tt class="docutils literal">mmap</tt> was fixed to work with file sizes and offsets larger than 4 GB even on 32-bit builds, and a <tt class="docutils literal">TypeError</tt> is now raised rather than segfaulting when trying to write to a non-writeable map.</p> -<p>For a full list of changes, see <a class="reference external" href="http://hg.python.org/cpython/raw-file/eb3c9b74884c/Misc/NEWS">the 2.7.2 news file</a>.</p> -</div> -<div class="section" id="id3"> -<h4>3.1.4</h4> -<p>3.1.4 is the last bug-fix release of the 3.1.x line, sending 3.1 into security-mode as the 3.2 line carries on. 3.1.4 contains over 100 bug fixes since the 3.1.3 release in November 2010. As with 2.7.2, binary installers are available as of June 12, and 3.1.4 is the first 3.x release to contain the security fixes listed in 2.6.7.</p> -<p>3.1.4 corrects some problems with <tt class="docutils literal">__dir__</tt> lookups on objects, dates past 2038 in the Windows implementation of <tt class="docutils literal">os.stat</tt> and <tt class="docutils literal">os.utime</tt>, and a number of 64-bit cleanups. The <tt class="docutils literal">io</tt> library saw a number of changes in returning <tt class="docutils literal">None</tt> when nothing was read and raising appropriate exceptions in other spots. <tt class="docutils literal">ctypes</tt> callback arguments were fixed on 64-bit Windows and a crash was also remedied.</p> -<p>For a full list of changes, see <a class="reference external" href="http://hg.python.org/cpython/raw-file/feae9f9e9f30/Misc/NEWS">the 3.1.4 news file</a>.</p></div> -<div class="section" id="id4"> -<h4>3.2.1</h4> -<p><a class="reference external" href="http://www.python.org/download/releases/3.2.1/">3.2.1</a> is currently in the release candidate phase, with one round already completed and a second release candidate expected soon. We would greatly appreciate 3.2 users trying out the release candidates to ensure we cover any issues you may be seeing. If you have any bugs to report, please file them on <a class="reference external" href="http://bugs.python.org">bugs.python.org</a>.</p> -</div> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=Y0OHiMAU4rA:8amqCEIJod4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=Y0OHiMAU4rA:8amqCEIJod4:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=Y0OHiMAU4rA:8amqCEIJod4:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=Y0OHiMAU4rA:8amqCEIJod4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=Y0OHiMAU4rA:8amqCEIJod4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=Y0OHiMAU4rA:8amqCEIJod4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=Y0OHiMAU4rA:8amqCEIJod4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=Y0OHiMAU4rA:8amqCEIJod4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/Y0OHiMAU4rA" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/06/june-releases-267-272-314.htmltag:blogger.com,1999:blog-3941553907430899163.post-15716525742476766862011-05-26T18:44:00.009-04:002011-05-26T18:59:16.298-04:002011-05-26T18:59:16.298-04:00New faulthandler module in Python 3.3 helps debugging<div class="document" id="new-faulthandler-module-in-python-3-3-helps-debugging"><p>When a user reports that your program crashes or hangs, sometimes you can only help to try and collect more information and outline a scenario to reproduce the situation. Even with a reliable user scenario, as a developer you are often unable to reproduce the situation due to environment differences, e.g., operating system and compiler. If you are lucky, the user will be able to install debug tools, but most of time you will have to wait until another person is able to obtain more information from the same situation.</p><div class="section" id="fatal-errors"><h4>Fatal Errors</h4><p>A new module introduced in Python 3.3 should help this problem: <a class="reference external" href="http://docs.python.org/dev/library/faulthandler.html">faulthandler</a>. <tt class="docutils literal">faulthandler</tt> provides the ability to dump the Python traceback on a fatal error such as a segmentation fault, division by zero, abort, or bus error. You can enable it inside your application using <tt class="docutils literal">faulthandler.enable()</tt>, by providing the <tt class="docutils literal"><span class="pre">-X</span> faulthandler</tt> option to the Python executable, or with the <a class="reference external" href="http://docs.python.org/dev/using/cmdline.html#envvar-PYTHONFAULTHANDLER">PYTHONFAULTHANDLER=1</a> environment variable. Output example:</p><pre class="literal-block">Fatal Python error: Segmentation fault - -Current thread 0x00007f7babc6b700: - File "Lib/test/crashers/gc_inspection.py", line 29 in g - File "Lib/test/crashers/gc_inspection.py", line 32 in &lt;module&gt; -Segmentation fault</pre></div><div class="section" id="timeout"><h4>Timeout</h4><p><tt class="docutils literal">faulthandler</tt> can also dump the traceback after a timeout using <tt class="docutils literal">faulthandler.dump_tracebacks_later(timeout)</tt>. Call it again to restart the timer or call <tt class="docutils literal">faulthandler.cancel_dump_tracebacks_later()</tt> to stop the timer. Output example:</p><pre class="literal-block">Timeout (0:01:00)! -Current thread 0x00007f987d459700: - File "Lib/test/crashers/infinite_loop_re.py", line 20 in &lt;module&gt; -</pre><p>Use the <tt class="docutils literal">repeat=True</tt> option to dump the traceback each <tt class="docutils literal">timeout</tt> seconds, or <tt class="docutils literal">exit=True</tt> to immediatly exit the program in an unsafe fashion, e.g. don't flush files.</p></div><div class="section" id="user-signal"><h4>User Signal</h4><p>If you have access to the host on which the program is running, you can use <tt class="docutils literal">faulthandler.register(signal)</tt> to install a signal handler to dump the traceback when <tt class="docutils literal">signal</tt> is received. On UNIX, for example, you can use the <tt class="docutils literal">SIGUSR1 </tt>signal: <tt class="docutils literal">kill <span class="pre">-USR1</span> &lt;pid&gt;</tt> will dump the current traceback. This feature is not available on Windows. Output example:</p><pre class="literal-block">Current thread 0x00007fdc3da74700: - File "Lib/test/crashers/infinite_loop_re.py", line 19 in &lt;module&gt; -</pre><p>Another possibility is to explicitly call <tt class="docutils literal">faulthandler.dump_traceback()</tt> in your program.</p></div><div class="section" id="security-issues-and-the-output-file"><h4>Security Issues and the Output File</h4><p><tt class="docutils literal">faulthandler</tt> is disabled by default for security reasons, mainly because it stores the file descriptor of <tt class="docutils literal">sys.stderr</tt> and writes the tracebacks into this file descriptor. If <tt class="docutils literal">sys.stderr</tt> is closed and the file descriptor is reused, the file descriptor may be a socket, a pipe, a critical file or something else. By default, <tt class="docutils literal">faulthandler</tt> writes the tracebacks to <tt class="docutils literal">sys.stderr</tt>, but you can specify another file. For more information, see the <a class="reference external" href="http://docs.python.org/dev/library/faulthandler.html#file-descriptor-issue">faulthandler documentation</a>.</p></div><div class="section" id="third-party-module-for-older-python-versions"><h4>Third-party Module for Older Python Versions</h4><p><tt class="docutils literal">faulthandler</tt> is also maintained as a third-party module for Python 2.5 through 3.2 <cite style="font-style: normal;"><a href="http://pypi.python.org/pypi/faulthandler/">on PyPI</a></cite>. The major difference between the Python 3.3 module and the third-party module is the implementation of <tt class="docutils literal">dump_tracebacks_later()</tt>: Python 3.3 uses a thread with a timeout on a lock, whereas the third party uses <tt class="docutils literal">SIGALRM</tt> and <tt class="docutils literal">alarm()</tt>.</p><p>The lock timeout, which is a new feature of Python 3.3, has a microsecond resolution. The <tt class="docutils literal">alarm()</tt> timer used on older versions has a resolution of one second, and the <tt class="docutils literal">SIGALRM</tt> signal may interrupt the current system call which will fail with an <tt class="docutils literal">EINTR</tt> error.</p></div><div class="section" id="early-success"><h4>Early Success</h4><p>The new <tt class="docutils literal">faulthandler</tt> module has already helped with tracking down race conditions in <a href="http://www.python.org/dev/buildbot/">our buildbots</a>. We hope that it will also help you in your programs.</p></div></div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qqYRL00AmXY:vzhC57CLoWc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qqYRL00AmXY:vzhC57CLoWc:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qqYRL00AmXY:vzhC57CLoWc:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qqYRL00AmXY:vzhC57CLoWc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qqYRL00AmXY:vzhC57CLoWc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qqYRL00AmXY:vzhC57CLoWc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qqYRL00AmXY:vzhC57CLoWc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qqYRL00AmXY:vzhC57CLoWc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/qqYRL00AmXY" height="1" width="1"/>haypohttp://www.blogger.com/profile/14658404449913582628noreply@blogger.comhttp://blog.python.org/2011/05/new-faulthandler-module-in-python-33.htmltag:blogger.com,1999:blog-3941553907430899163.post-80130733679677389692011-05-23T10:00:00.005-04:002011-05-23T10:00:11.685-04:002011-05-23T10:00:11.685-04:00The Python Core Mentorship Program<div class="document" id="the-python-core-mentorship-program"> - -<p><a class="reference external" href="http://jessenoller.com/">Jesse Noller</a> recently <a class="reference external" href="http://jessenoller.com/2011/04/05/python-core-mentorship-up-and-running/"> announced</a> the formation of the <em>Python Core Mentorship</em> program. The idea behind the program is to help programmers, including students and developers from other projects, connect with experienced contributors who serve as mentors to ease them into Python Core development.</p> -<div class="section" id="contributors-wanted"> -<h4>Contributors Wanted</h4> -<p>The mentors will help people regardless of experience level by -bringing them up to speed, answering questions, and giving guidance as -needed in a non-confrontational and welcoming way. The contributors -will receive guidance through the entire contribution process, -including discussions on the related mailing lists, the bug tracker, -Mercurial, code reviews, and much more.</p> -</div> -<div class="section" id="early-success"> -<h4>Early Success</h4> -<p>The program already has been successful, and the participants have -actively committed a number of patches. There have also been several -constructive discussions on the mailing list, helping guide people in -the right direction for a variety of issues.</p> -</div> -<div class="section" id="code-of-conduct"> -<h4>Code of Conduct</h4> -<p>The program has a code of conduct explained on the <a class="reference external" href="http://pythonmentors.com/">website</a> that aims to assuage concerns many new contributors have when interacting with experienced developers and mailing lists on contribution in general. Jesse and the other mentors hope that this program can act as a model for other projects long-term, not just benefiting Python-Core. They also want the program to help increase the overall diversity of the contributors to Python.</p> -</div> -<div class="section" id="signing-up"> -<h4>Signing Up</h4> -<p>The program is run via the <a class="reference external" href="http://mail.python.org/mailman/listinfo/core-mentorship">mailing list</a> and has a clear, concise <a class="reference external" href="http://pythonmentors.com/">website</a> devoted to it. If you would like to join to ask questions and begin on the path of core contribution, or even if you are an experienced developer (even experienced in Python-Core) looking to ask questions you're worried about asking on other lists, this is an excellent opportunity to jump in, ask and get your feet wet!</p> -</div> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=SgkfTGCVy1c:olf4Uqq8tXk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=SgkfTGCVy1c:olf4Uqq8tXk:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=SgkfTGCVy1c:olf4Uqq8tXk:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=SgkfTGCVy1c:olf4Uqq8tXk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=SgkfTGCVy1c:olf4Uqq8tXk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=SgkfTGCVy1c:olf4Uqq8tXk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=SgkfTGCVy1c:olf4Uqq8tXk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=SgkfTGCVy1c:olf4Uqq8tXk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/SgkfTGCVy1c" height="1" width="1"/>Mike Driscollhttp://www.blogger.com/profile/06351908417200979114noreply@blogger.comhttp://blog.python.org/2011/05/python-core-mentorship-program.htmltag:blogger.com,1999:blog-3941553907430899163.post-31262668843164743032011-05-19T08:45:00.000-04:002011-05-19T08:45:49.363-04:002011-05-19T08:45:49.363-04:00Portuguese, German, Korean, and Traditional Chinese Translations<div class="document" id="portuguese-german-korean-and-traditional-chinese-translations"> - -<p>The Python Insider <a class="reference external" href="http://blog.python.org/2011/05/python-insider-translation-project.html">translation project</a> is continuing to grow! Today - -we are launching <a class="reference external" href="http://blog-pt.python.org">Portuguese</a>, <a class="reference external" href="http://blog-de.python.org">German</a>, <a class="reference external" href="http://blog-ko.python.org">Korean</a>, and <a class="reference external" href="http://blog-tw.python.org">Traditional - -Chinese</a> versions of the blog. The translators have already started - -publishing the backlog of posts. As with the other translations, these - -parallel editions may lag slightly behind the original posts on - -<a class="reference external" href="http://blog.python.org/">Python Insider</a>.</p> - -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=h1jWkgV8r44:GpriJFbwgcg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=h1jWkgV8r44:GpriJFbwgcg:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=h1jWkgV8r44:GpriJFbwgcg:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=h1jWkgV8r44:GpriJFbwgcg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=h1jWkgV8r44:GpriJFbwgcg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=h1jWkgV8r44:GpriJFbwgcg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=h1jWkgV8r44:GpriJFbwgcg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=h1jWkgV8r44:GpriJFbwgcg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/h1jWkgV8r44" height="1" width="1"/>Michael Markerthttp://www.blogger.com/profile/08761481986934375758noreply@blogger.comhttp://blog.python.org/2011/05/portuguese-german-korean-and.htmltag:blogger.com,1999:blog-3941553907430899163.post-18981709542887702852011-05-09T07:00:00.001-04:002011-05-09T07:00:03.832-04:002011-05-09T07:00:03.832-04:00Romanian and Simplified Chinese Translations<div class="document" id="romanian-and-simplified-chinese-translations"> - -<p>The Python Insider team is very excited to announce two new blogs -today. Translators for <a class="reference external" href="http://blog-ro.python.org">Romanian</a> and <a class="reference external" href="http://blog-cn.python.org">Simplified Chinese</a> have -joined the <a class="reference external" href="http://blog.python.org/2011/05/python-insider-translation-project.html">Translation Project</a>, and have already started publishing -the backlog of posts. As with the other translations, these parallel -editions may lag slightly behind the original posts on <a class="reference external" href="http://blog.python.org/">Python -Insider</a>.</p> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=J4XrijXKrSo:oVHkbmUmvxo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=J4XrijXKrSo:oVHkbmUmvxo:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=J4XrijXKrSo:oVHkbmUmvxo:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=J4XrijXKrSo:oVHkbmUmvxo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=J4XrijXKrSo:oVHkbmUmvxo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=J4XrijXKrSo:oVHkbmUmvxo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=J4XrijXKrSo:oVHkbmUmvxo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=J4XrijXKrSo:oVHkbmUmvxo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/J4XrijXKrSo" height="1" width="1"/>Doug Hellmannhttp://www.blogger.com/profile/01892352754222143463noreply@blogger.comhttp://blog.python.org/2011/05/romanian-and-simplified-chinese.htmltag:blogger.com,1999:blog-3941553907430899163.post-42734756475607251932011-05-07T16:38:00.002-04:002011-05-07T16:38:55.599-04:002011-05-07T16:38:55.599-04:00Jython Migrates to Mercurial<div class="document" id="jython-migrates-to-mercurial"> - -<p>Jython has finally migrated from Subversion to Mercurial. This has been a long -time coming: unfortunately we had a difficult Subversion repo that took some -effort to cleanly convert to a different revision control system.</p> -<p>The new official Jython repo is now hosted @</p> -<p><a class="reference external" href="http://hg.python.org/jython">http://hg.python.org/jython</a></p> -<p>with a <a class="reference external" href="http://bitbucket.org/jython/jython">BitBucket Mirror</a> for easy forking.</p> -<p>There's also a larger read-only repo with ongoing feature branches (converted -to Mercurial Bookmarks) hosted at <a class="reference external" href="http://hg.python.org/jython-fullhistory">http://hg.python.org/jython-fullhistory</a></p> -<p>Mercurial makes it even easier to contribute to Jython, pull up a fork and come -help us build Jython 2.6!</p> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=cr67BEYMOCo:MitZ1cfMsl0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=cr67BEYMOCo:MitZ1cfMsl0:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=cr67BEYMOCo:MitZ1cfMsl0:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=cr67BEYMOCo:MitZ1cfMsl0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=cr67BEYMOCo:MitZ1cfMsl0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=cr67BEYMOCo:MitZ1cfMsl0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=cr67BEYMOCo:MitZ1cfMsl0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=cr67BEYMOCo:MitZ1cfMsl0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/cr67BEYMOCo" height="1" width="1"/>Philip Jenveyhttp://www.blogger.com/profile/17437958274873977298noreply@blogger.comhttp://blog.python.org/2011/05/jython-migrates-to-mercurial.htmltag:blogger.com,1999:blog-3941553907430899163.post-50984214452724273672011-05-04T09:55:00.001-04:002011-05-04T10:07:24.909-04:002011-05-04T10:07:24.909-04:00Python 3.3 to Drop Support for OS/2, Windows 2000, and VMS<div class="document" id="python-3-3-to-drop-support-for-os-2-windows-2000-and-vms"> -<p>Every so often there comes a time to prune the list of supported operating systems to match the usage landscape. On top of that, the pool of contributing developers on a platform also holds significance, as there needs to be someone around to complete development tasks in order to have a quality release. Other factors, such as the age of an operating system and its hinderance on future development work, also weigh on the list.</p> -<p><a class="reference external" href="http://www.haypocalc.com/wiki/Victor_Stinner">Victor Stinner</a> recently proposed <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-April/110872.html">dropping OS/2 and VMS support</a> for CPython, a year after his <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2010-April/099471.html">original question</a> on OS/2 support. Victor's original inquiry came around the time of his seemingly non-stop Unicode efforts, specifically for an issue with <a class="reference external" href="http://docs.python.org/library/os#os.execvpe">os.execvpe()</a> supporting environment variables via the <a class="reference external" href="http://www.python.org/dev/peps/pep-0383/">PEP 383</a> surrogateescape handler. OS/2 and VMS currently have no representation on the development team and receive no testing during the release process.</p> -<p>The process of writing this post <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-May/111159.html">got me thinking</a> about a <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2010-March/098074.html">previous discussion</a> about removing Windows 2000, which seemed to fall to the wayside. Systems setting <tt class="docutils literal">COMSPEC</tt> to <tt class="docutils literal">command.com</tt> were also supposed to be on the chopping block back then. <a class="reference external" href="http://hg.python.org/peps/rev/b9390aa12855">As of now</a>, both have joined OS/2 and VMS. Windows 2000 is up for removal in order to make development work easier, removing the need to account for legacy APIs on an operating system which hit end-of-life in 2010.</p> -<p>In order to begin removing support for those systems, Victor and I started by updating <a class="reference external" href="http://www.python.org/dev/peps/pep-0011/">PEP 11</a>.</p> -<div class="section" id="pep-11"> -<h4>PEP 11</h4> -<p>This PEP outlines the operating systems that are no longer supported and explains the process of adding a system to that list.</p> -<p>Once it is decided that an operating system can start the process of removal, it is formally announced as unsupported. This announcement traditionally goes for the in-development version, so dropping support of OS/2, Windows 2000, and VMS begins with Python 3.3.</p> -<p>The first stage is fairly hands off, more of a raising of the white flag. It's a signal that there's no one around to maintain the code and ensure a quality release. Changes to compilation and installation may be made to alert users on those platforms that the platform is unsupported. A note will go into the &quot;<a class="reference external" href="http://docs.python.org/dev/whatsnew/3.3.html#unsupported-operating-systems">What's New</a>&quot; document listing the newly unsupported platforms.</p> -<p>After a release cycle of being unsupported, the version afterwards becomes fair game for removal of code. In this case, code can be removed in 3.4. There probably won't be a wholesale removal of that code, but developers that come across it in their normal work may remove any <tt class="docutils literal">#ifdef</tt> blocks, <tt class="docutils literal">configure</tt> sections, or out-of-date code.</p> -</div> -<div class="section" id="what-you-can-do"> -<h4>What You Can Do</h4> -<p>If you are a user of OS/2 or VMS, there are a few things you can do to save your platform.</p> -<div class="section" id="become-a-maintainer"> -<h5>Become a Maintainer</h5> -<p>Nothing says support better than an active developer. Andrew MacIntyre has been the OS/2 maintainer for some time now, and he stated during Victor's first OS/2 query that OS/2 is behind on Unicode support, so that's certainly an area that needs focus. VMS appears to have some amount of external support via <a class="reference external" href="http://www.vmspython.org">http://www.vmspython.org</a>, but as discussed in <a class="reference external" href="http://bugs.python.org/issue11918">issue 11918</a>, someone needs to step up to allow the continued VMS support upstream.</p> -<p>If you are interested in taking over for either platform, see the <a class="reference external" href="http://docs.python.org/devguide">developer's guide</a> for the current development proccesses.</p> -</div> -<div class="section" id="contribute-a-build-slave"> -<h5>Contribute a build slave</h5> -<p>With an active developer, a platform stands a better chance of survival. With a build slave, a platform stands an even better chance, not only at survival but also at quality.</p> -<p>Python uses <a class="reference external" href="http://trac.buildbot.net/">Buildbot</a> for continuous integration, and build slaves are <a class="reference external" href="http://www.python.org/dev/buildbot/">currently provided</a> for Linux, Mac, Windows, and Open Indiana (Solaris), for various versions, architectures, and configurations. Being able to donate a machine to the build fleet for OS/2 or VMS would allow those platforms to receive the same attention that more mainstream platforms receive.</p> -<p>If you can donate either time or hardware to help keep OS/2 and VMS alive, contact the <a class="reference external" href="http://mail.python.org/mailman/listinfo/python-dev">python-dev</a> mailing list to coordinate your efforts.</p> -</div> -</div> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=RTWZNjzcHx0:VncS2cQK2Pk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=RTWZNjzcHx0:VncS2cQK2Pk:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=RTWZNjzcHx0:VncS2cQK2Pk:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=RTWZNjzcHx0:VncS2cQK2Pk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=RTWZNjzcHx0:VncS2cQK2Pk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=RTWZNjzcHx0:VncS2cQK2Pk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=RTWZNjzcHx0:VncS2cQK2Pk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=RTWZNjzcHx0:VncS2cQK2Pk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/RTWZNjzcHx0" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/05/python-33-to-drop-support-for-os2.htmltag:blogger.com,1999:blog-3941553907430899163.post-86105312525558548192011-05-02T10:18:00.000-04:002011-05-02T10:18:26.521-04:002011-05-02T10:18:26.521-04:00Python Insider Translation Project<div class="document" id="python-insider-translation-project"> - -<p>We think the content of this blog is useful for the whole Python -community, so reaching as many people as we can is one of our -priorities. To expand our reach, we have assembled a team of -translators to create parallel editions of the blog in other -languages. We are launching two translations today: <a class="reference external" href="http://blog-ja.python.org/">Japanese</a> and -<a class="reference external" href="http://blog-es.python.org/">Spanish</a>.</p> -<p>The translations will lag a little behind the posts on <a class="reference external" href="http://blog.python.org/">Python -Insider</a>, but try to keep more or less up to date.</p> -<div class="section" id="help-wanted"> -<h4>Help Wanted</h4> -<p>The translation team is still very small, so we are looking for more -people to join. We need people able to work on the existing languages, -or to help us expand to other languages. If you can help in either -way, contact Doug Hellmann (doug dot hellmann at gmail).</p> -</div> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qrDBu7N4X_k:wMiUAPxroZQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qrDBu7N4X_k:wMiUAPxroZQ:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qrDBu7N4X_k:wMiUAPxroZQ:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qrDBu7N4X_k:wMiUAPxroZQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qrDBu7N4X_k:wMiUAPxroZQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qrDBu7N4X_k:wMiUAPxroZQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qrDBu7N4X_k:wMiUAPxroZQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qrDBu7N4X_k:wMiUAPxroZQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/qrDBu7N4X_k" height="1" width="1"/>Davidmhhttp://www.blogger.com/profile/14913018830568213369noreply@blogger.comhttp://blog.python.org/2011/05/python-insider-translation-project.htmltag:blogger.com,1999:blog-3941553907430899163.post-61050672932318858162011-04-28T10:05:00.000-04:002011-04-28T10:06:02.380-04:002011-04-28T10:06:02.380-04:00Meet the Team: Brian Curtin<div class="document" id="meet-the-team-brian-curtin"> -<p><em>This post is part of the &quot;Meet the Team&quot; series of posts, which is meant to give a brief introduction to the Python core development team.</em></p> -<table class="docutils field-list" frame="void" rules="none"><col class="field-name"></col><col class="field-body"></col><tbody valign="top"><tr class="field"><th class="field-name">Name:</th><td class="field-body">Brian Curtin</td></tr><tr class="field"><th class="field-name">Location:</th><td class="field-body">Chicago, IL</td></tr><tr class="field"><th class="field-name">Home Page:</th><td class="field-body"><a class="reference external" href="http://blog.briancurtin.com/">http://blog.briancurtin.com/</a></td></tr></tbody></table> -<p><strong>How long have you been using Python?</strong></p> -<p>On a day to day basis going on 6 years. Prior to that I used it occasionally for a class in college and also at a summer internship.</p> -<p><strong>How long have you been a core committer?</strong></p> -<p>Just over a year. March 24 marked my first year with the group.</p> -<p><strong>How did you get started as a core developer? Do you remember your first commit?</strong></p> -<p>I got started after noticing a documentation bug while writing an extension module at work, then I submitted a simple patch and Georg Brandl committed it almost immediately. After having that quick success and a fresh source checkout, I wanted to dive in and learn more about the modules I was using and ended up writing a patch to add context manager support to zipfile.</p> -<p>The first few commits I made were documentation fixes in order to keep it simple early on. My first code commit was to add a few features and expand test coverage in the winreg module.</p> -<p><strong>Which parts of Python are you working on now?</strong></p> -<p>As one of the few Windows users involved in CPython development, I try to keep an eye on whatever issues Windows users are having. Due to that, I've had a chance to work on a bunch of the standard library, including modules I hadn't used. I haven't done much with the interpreter itself, but I'm looking to change that.</p> -<p><strong>What do you do with Python when you aren't doing core development work?</strong></p> -<p>I build a variety of test tools for a trading database which is written in C++. There's an extension module for the data API so we can easily write regression tests, performance tests, and we're always trying to build more.</p> -<p><strong>What do you do when you aren't programming?</strong></p> -<p>I'm a huge baseball fan. I umpire college baseball in the spring, various leagues in the summer, and mix in watching and going to Chicago Cubs games.</p> -</div><div class="feedflare"> -<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=WvEj6rtc9A0:KTaJ5tHvMyM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=WvEj6rtc9A0:KTaJ5tHvMyM:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=WvEj6rtc9A0:KTaJ5tHvMyM:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=WvEj6rtc9A0:KTaJ5tHvMyM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=WvEj6rtc9A0:KTaJ5tHvMyM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=WvEj6rtc9A0:KTaJ5tHvMyM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=WvEj6rtc9A0:KTaJ5tHvMyM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=WvEj6rtc9A0:KTaJ5tHvMyM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> -</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/WvEj6rtc9A0" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/04/meet-team-brian-curtin.html + +tag:blogger.com,1999:blog-39415539074308991632013-08-27T00:33:50.336-04:00Python InsiderPython core development news and information.Doug Hellmannhttp://www.blogger.com/profile/01892352754222143463noreply@blogger.comBlogger36125PythonInsiderhttp://feedburner.google.comtag:blogger.com,1999:blog-3941553907430899163.post-15569992107993551332013-03-04T10:00:00.000-05:002013-03-04T10:00:06.719-05:002013-03-04T10:00:06.719-05:00Introducing Electronic Contributor Agreements<br /> +We're happy to announce the new way to file a contributor agreement: on the web at&nbsp;<a href="http://www.python.org/psf/contrib/contrib-form/">http://www.python.org/psf/contrib/contrib-form/</a>.<br /> +<br /> +Through the use of&nbsp;<a href="https://www.echosign.adobe.com/en/home.html">Adobe's EchoSign</a>, we got rid of the old hand-written, print out, scan or photograph, then fax or email of your form. It was a hassle for our contributors, and a hassle for our administrators. Faxes fail, mail gets lost, and sometimes pictures or scans turn out poorly. It was time to find a more user-friendly solution, and the Foundation is happy to finally offer this electronic form.<br /> +<br /> +<br /> +The new form is easy to fill out right on the site, guiding you through each of the required fields such as your name, bug tracker ID, address, and initial license. If you're signing the form on behalf of an organization, there's a check box to specify this, and then you are asked near the bottom to state your title in the organization. Lastly, your signature is either generated from your typed name, or you can draw your own or upload a signature file of your own.<br /> +<br /> +Once you submit the form, you'll receive an email from echosign.com to verify the email address you entered. Once you click to confirm your address, the form will be emailed to the PSF and will be recorded.<br /> +<br /> +<br /> +We require all contributors to CPython to have a signed form, and we hope this makes it easier for potential contributors to join up and help make Python better. It's available just in time for&nbsp;<a href="https://us.pycon.org/2013/">PyCon</a>&nbsp;and the&nbsp;<a href="https://us.pycon.org/2013/community/sprints/projects/#core-python">CPython sprint</a>&nbsp;that will be occurring March 18 through 21 in Santa Clara, California. Join us at the sprint, sign your contributor form, and help us fix some bugs or add some features!<div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tGNCqyOiun4:FplHbf8RNFc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tGNCqyOiun4:FplHbf8RNFc:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tGNCqyOiun4:FplHbf8RNFc:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tGNCqyOiun4:FplHbf8RNFc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tGNCqyOiun4:FplHbf8RNFc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tGNCqyOiun4:FplHbf8RNFc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tGNCqyOiun4:FplHbf8RNFc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tGNCqyOiun4:FplHbf8RNFc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/tGNCqyOiun4" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2013/03/introducing-electronic-contributor.htmltag:blogger.com,1999:blog-3941553907430899163.post-27930385091234657372013-02-19T10:00:00.000-05:002013-02-21T01:14:37.819-05:002013-02-21T01:14:37.819-05:00Announcing defusedxml, Fixes for XML Security Issues<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: xx-small;"><i>The following post was created on behalf of CPython contributor Christian Heimes using a subset of details found <a href="https://bitbucket.org/tiran/defusedxml">here</a>.</i></span><br /> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Christian Heimes announces the release of his <a href="https://bitbucket.org/tiran/defusedxml">defusedxml</a>&nbsp;and <a href="https://bitbucket.org/tiran/defusedexpat">defusedexpat</a>&nbsp;packages to address XML-related security issues which were reported to <a href="mailto:security@python.org">security@python.org</a> over the last several months. Throughout the development of the patches, the security team has coordinated with other open source projects in order to make this announcement at 1500 UTC on Tuesday February 19.</span><br /> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Details will follow once releases of CPython have been organized.</span><br /> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: xx-small;"><i style="background-color: #cfe2f3;"><b>Note: this post will be updated with more details as they switch from being private to publicly available, including links to the public bug reports on&nbsp;<a href="http://bugs.python.org/">http://bugs.python.org</a>.</b></i></span><br /> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><span style="background-color: white;"><br /></span></span> +<span style="background-color: white;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">defusedxml on PyPI:&nbsp;</span><a href="https://pypi.python.org/pypi/defusedxml">https://pypi.python.org/pypi/defusedxml</a></span><br /> +<span style="background-color: white;">defusedexpat on PyPI:&nbsp;<a href="https://pypi.python.org/pypi/defusedexpat">https://pypi.python.org/pypi/defusedexpat</a></span><br /> +"XML vulnerabilities" on bug tracker:&nbsp;<a href="http://bugs.python.org/issue17239">http://bugs.python.org/issue17239</a><br /> +<h2 style="background-color: white; color: #333333; line-height: 1.5625; margin: 20px 0px 5px;"> +<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml/#id2" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">Synopsis</span></a></h2> +<div style="background-color: white; color: #333333; line-height: 20px; margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The results of an attack on a vulnerable XML library can be fairly dramatic. With just a few hundred&nbsp;<strong>Bytes</strong>&nbsp;of XML data an attacker can occupy several&nbsp;<strong>Gigabytes</strong>&nbsp;of memory within&nbsp;<strong>seconds</strong>. An attacker can also keep CPUs busy for a long time with a small to medium size request. Under some circumstances it is even possible to access local files on your server, to circumvent a firewall, or to abuse services to rebound attacks to third parties.</span></div> +<div style="background-color: white; color: #333333; line-height: 20px; margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The attacks use and abuse less common features of XML and its parsers. The majority of developers are unacquainted with features such as processing instructions and entity expansions that XML inherited from SGML. At best they know about&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;">&lt;!DOCTYPE&gt;</tt>&nbsp;from experience with HTML but they are not aware that a document type definition (DTD) can generate an HTTP request or load a file from the file system.</span></div> +<div style="background-color: white; color: #333333; line-height: 20px; margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">None of the issues is new. They have been known for a long time. Billion laughs was first reported in 2003. Nevertheless some XML libraries and applications are still vulnerable and even heavy users of XML are surprised by these features. It's hard to say whom to blame for the situation. It's too short sighted to shift all blame on XML parsers and XML libraries for using insecure default settings. After all they properly implement XML specifications. Application developers must not rely that a library is always configured for security and potential harmful data by default.</span></div> +<div style="background-color: white; color: #333333; font-size: 14px; line-height: 20px; margin-top: 10px;"> +</div> +<h2 style="font-size: 16px; line-height: 1.5625; margin: 20px 0px 5px;"> +</h2> +<h2 style="line-height: 1.5625; margin: 20px 0px 5px;"> +<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id3" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">Attack vectors</span></a></h2> +<div class="section" id="billion-laughs-exponential-entity-expansion" style="font-weight: normal; line-height: 20px;"> +<h3 style="line-height: 1.5; margin: 0px 0px 5px;"> +<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id4" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">billion laughs / exponential entity expansion</span></a></h3> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The&nbsp;<a class="reference external" href="http://en.wikipedia.org/wiki/Billion_laughs" style="color: #3c77b4; text-decoration: initial;">Billion Laughs</a>&nbsp;attack -- also known as exponential entity expansion -- uses multiple levels of nested entities. The original example uses 9 levels of 10 expansions in each level to expand the string&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;">lol</tt>&nbsp;to a string of 3 * 10&nbsp;<sup>9</sup>&nbsp;bytes, hence the name "billion laughs". The resulting string occupies 3 GB (2.79 GiB) of memory; intermediate strings require additional memory. Because most parsers don't cache the intermediate step for every expansion it is repeated over and over again. It increases the CPU load even more.</span></div> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An XML document of just a few hundred bytes can disrupt all services on a machine within seconds.</span></div> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Example XML:</span></div> +<pre class="literal-block" style="background-color: whitesmoke; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; line-height: 1.4; margin-bottom: 9px; margin-top: 9px; overflow: auto; padding: 10px; width: 615px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">&lt;!DOCTYPE xmlbomb [ +&lt;!ENTITY a "1234567890" &gt; +&lt;!ENTITY b "&amp;a;&amp;a;&amp;a;&amp;a;&amp;a;&amp;a;&amp;a;&amp;a;"&gt; +&lt;!ENTITY c "&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;&amp;b;"&gt; +&lt;!ENTITY d "&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;&amp;c;"&gt; +]&gt; +&lt;bomb&gt;&amp;d;&lt;/bomb&gt; +</span></pre> +</div> +<div class="section" id="quadratic-blowup-entity-expansion" style="font-weight: normal; line-height: 20px;"> +<h3 style="line-height: 1.5; margin: 0px 0px 5px;"> +<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id5" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">quadratic blowup entity expansion</span></a></h3> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">A quadratic blowup attack is similar to a&nbsp;<a class="reference external" href="http://en.wikipedia.org/wiki/Billion_laughs" style="color: #3c77b4; text-decoration: initial;">Billion Laughs</a>&nbsp;attack; it abuses entity expansion, too. Instead of nested entities it repeats one large entity with a couple of ten thousand chars over and over again. The attack isn't as efficient as the exponential case but it avoids triggering countermeasures of parsers against heavily nested entities. Some parsers limit the depth and breadth of a single entity but not the total amount of expanded text throughout an entire XML document.</span></div> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">A medium-sized XML document with a couple of hundred kilobytes can require a couple of hundred MB to several GB of memory. When the attack is combined with some level of nested expansion an attacker is able to achieve a higher ratio of success.</span></div> +<pre class="literal-block" style="background-color: whitesmoke; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; line-height: 1.4; margin-bottom: 9px; margin-top: 9px; overflow: auto; padding: 10px; width: 615px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">&lt;!DOCTYPE bomb [ +&lt;!ENTITY a "xxxxxxx... a couple of ten thousand chars"&gt; +]&gt; +&lt;bomb&gt;&amp;a;&amp;a;&amp;a;... repeat&lt;/bomb&gt; +</span></pre> +</div> +<div class="section" id="external-entity-expansion-remote" style="font-weight: normal; line-height: 20px;"> +<h3 style="line-height: 1.5; margin: 0px 0px 5px;"> +<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id6" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">external entity expansion (remote)</span></a></h3> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Entity declarations can contain more than just text for replacement. They can also point to external resources by public identifiers or system identifiers. System identifiers are standard URIs. When the URI is a URL (e.g. a&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;"><span class="pre">http://</span></tt>&nbsp;locator) some parsers download the resource from the remote location and embed them into the XML document verbatim.</span></div> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Simple example of a parsed external entity:</span></div> +<pre class="literal-block" style="background-color: whitesmoke; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; line-height: 1.4; margin-bottom: 9px; margin-top: 9px; overflow: auto; padding: 10px; width: 615px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">&lt;!DOCTYPE external [ +&lt;!ENTITY ee SYSTEM "http://www.python.org/some.xml"&gt; +]&gt; +&lt;root&gt;&amp;ee;&lt;/root&gt; +</span></pre> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The case of parsed external entities works only for valid XML content. The XML standard also supports unparsed external entities with a&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;">NData declaration</tt>.</span></div> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">External entity expansion opens the door to plenty of exploits. An attacker can abuse a vulnerable XML library and application to rebound and forward network requests with the IP address of the server. It highly depends on the parser and the application what kind of exploit is possible. For example:</span></div> +<ul class="simple" style="margin: 10px 0px 0px;"> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker can circumvent firewalls and gain access to restricted resources as all the requests are made from an internal and trustworthy IP address, not from the outside.</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker can abuse a service to attack, spy on or DoS your servers but also third party services. The attack is disguised with the IP address of the server and the attacker is able to utilize the high bandwidth of a big machine.</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker can exhaust additional resources on the machine, e.g. with requests to a service that doesn't respond or responds with very large files.</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker may gain knowledge, when, how often and from which IP address a XML document is accessed.</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker could send mail from inside your network if the URL handler supports&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;"><span class="pre">smtp://</span></tt>&nbsp;URIs.</span></li> +</ul> +</div> +<div class="section" id="external-entity-expansion-local-file" style="font-weight: normal; line-height: 20px;"> +<h3 style="line-height: 1.5; margin: 0px 0px 5px;"> +<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id7" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">external entity expansion (local file)</span></a></h3> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">External entities with references to local files are a sub-case of external entity expansion. It's listed as an extra attack because it deserves extra attention. Some XML libraries such as lxml disable network access by default but still allow entity expansion with local file access by default. Local files are either referenced with a&nbsp;<tt class="docutils literal" style="background-color: whitesmoke; border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; border-top-left-radius: 2px; border-top-right-radius: 2px; border: 1px solid rgb(204, 204, 204); padding: 1px 3px; vertical-align: middle;"><span class="pre">file://</span></tt>&nbsp;URL or by a file path (either relative or absolute).</span></div> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">An attacker may be able to access and download all files that can be read by the application process. This may include critical configuration files, too.</span></div> +<pre class="literal-block" style="background-color: whitesmoke; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; border-top-left-radius: 5px; border-top-right-radius: 5px; border: 1px solid rgb(204, 204, 204); box-sizing: border-box; line-height: 1.4; margin-bottom: 9px; margin-top: 9px; overflow: auto; padding: 10px; width: 615px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">&lt;!DOCTYPE external [ +&lt;!ENTITY ee SYSTEM "file:///PATH/TO/simple.xml"&gt; +]&gt; +&lt;root&gt;&amp;ee;&lt;/root&gt;</span></pre> +</div> +<div> +<h2 style="font-size: 16px; line-height: 1.5625; margin: 20px 0px 5px;"> +</h2> +<h2 style="line-height: 1.5625; margin: 20px 0px 5px;"> +<span style="color: #3c77b4; font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: xx-small; text-decoration: initial;"><a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id9" style="color: #3c77b4; text-decoration: initial;">Python XML Libraries</a></span></h2> +<table border="1" class="docutils" style="color: #333333; line-height: 20px;"><caption><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">vulnerabilities and features</span></caption><colgroup><col width="31%"></col><col width="9%"></col><col width="10%"></col><col width="10%"></col><col width="9%"></col><col width="10%"></col><col width="10%"></col><col width="10%"></col></colgroup><thead valign="bottom"> +<tr><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">kind</span></th><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">sax</span></th><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">etree</span></th><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">minidom</span></th><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">pulldom</span></th><th class="head"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">xmlrpc</span></th></tr> +</thead><tbody valign="top"> +<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">billion laughs</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td></tr> +<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">quadratic blowup</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td></tr> +<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">external entity expansion (remote)</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False (3)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False (4)</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">untested</span></td></tr> +<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">external entity expansion (local file)</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False (3)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False (4)</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">untested</span></td></tr> +<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">DTD retrieval</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">untested</span></td></tr> +<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">gzip bomb</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><strong><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">True</span></strong></td></tr> +<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">xpath support (7)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td></tr> +<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">xsl(t) support (7)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td></tr> +<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">xinclude support (7)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><strong>True</strong>&nbsp;(6)</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">False</span></td></tr> +<tr><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">C library</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">expat</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">expat</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">expat</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">expat</span></td><td><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">expat</span></td></tr> +</tbody></table> +<ol class="arabic simple" style="margin: 10px 0px 0px;"> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Lxml is protected against billion laughs attacks and doesn't do network lookups by default.</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">libxml2 and lxml are not directly vulnerable to gzip decompression bombs but they don't protect you against them either.</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">xml.etree doesn't expand entities and raises a ParserError when an entity occurs.</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">minidom doesn't expand entities and simply returns the unexpanded entity verbatim.</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">genshi.input of genshi 0.6 doesn't support entity expansion and raises a ParserError when an entity occurs.</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Library has (limited) XInclude support but requires an additional step to process inclusion.</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">These are features but they may introduce exploitable holes</span></li> +</ol> +</div> +<div> +<br /> +<h2 style="background-color: white; color: #333333; font-size: 16px; line-height: 1.5625; margin: 20px 0px 5px;"> +<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id24" style="color: #3c77b4; font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; font-size: medium; line-height: 1.5625;">How to avoid XML vulnerabilities</a></h2> +<div class="section" id="best-practices" style="background-color: white; color: #333333; line-height: 20px;"> +<h3 style="line-height: 1.5; margin: 0px 0px 5px;"> +<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id25" style="color: #3c77b4; text-decoration: initial;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">Best practices</span></a></h3> +<ul class="simple" style="margin: 10px 0px 0px;"> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Don't allow DTDs</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Don't expand entities</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Don't resolve externals</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Limit parse depth</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Limit total input size</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Limit parse time</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Favor a SAX or iterparse-like parser for potential large data</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Validate and properly quote arguments to XSL transformations and XPath queries</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Don't use XPath expression from untrusted sources</span></li> +<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Don't apply XSL transformations that come untrusted sources</span></li> +</ul> +<div style="margin-top: 10px;"> +<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">(based on Brad Hill's&nbsp;<a class="reference external" href="https://www.isecpartners.com/media/12976/iSEC-HILL-Attacking-XML-Security-bh07.pdf" style="color: #3c77b4; text-decoration: initial;">Attacking XML Security</a>)</span></div> +<div style="margin-top: 10px;"> +</div> +<h2 style="line-height: 1.5625; margin: 20px 0px 5px;"> +<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id35" style="color: #3c77b4; font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; font-size: medium; line-height: 1.5625;">Related CVEs</a></h2> +<div class="section" id="python"> + +<dl class="docutils" style="margin: 10px 0px;"> +<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">CVE-2013-1664</span></dt> +<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Unrestricted entity expansion induces DoS vulnerabilities in Python XML libraries (XML bomb)</span></dd> +<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">CVE-2013-1665</span></dt> +<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">External entity expansion in Python XML libraries inflicts potential security flaws and DoS vulnerabilities</span></dd></dl> +</div> +<div style="margin-top: 10px;"> +</div> +<h2 style="line-height: 1.5625; margin: 20px 0px 5px;"> +<a class="toc-backref" href="https://bitbucket.org/PSF/defusedxml#id46" style="color: #3c77b4;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif; font-size: small;">Acknowledgements</span></a></h2> +<dl class="docutils" style="margin: 10px 0px;"> +<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Brett Cannon (Python Core developer)</span></dt> +<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">review and code cleanup</span></dd> +<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Antoine Pitrou (Python Core developer)</span></dt> +<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">code review</span></dd> +<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Aaron Patterson, Ben Murphy and Michael Koziarski (Ruby community)</span></dt> +<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Many thanks to Aaron, Ben and Michael from the Ruby community for their report and assistance.</span></dd> +<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Thierry Carrez (OpenStack)</span></dt> +<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Many thanks to Thierry for his report to the Python Security Response Team on behalf of the OpenStack security team.</span></dd> +<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Carl Meyer (Django)</span></dt> +<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Many thanks to Carl for his report to PSRT on behalf of the Django security team.</span></dd> +<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Daniel Veillard (libxml2)</span></dt> +<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Many thanks to Daniel for his insight and assistance with libxml2.</span></dd> +<dt style="font-weight: bold; margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">semantics GmbH (<a class="reference external" href="http://www.semantics.de/" style="color: #3c77b4; text-decoration: initial;">http://www.semantics.de/</a>)</span></dt> +<dd style="margin-bottom: 10px;"><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Many thanks to my employer semantics for letting me work on the issue during working hours as part of semantics's open source initiative.</span></dd></dl> +</div> +</div> +<div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=mEuAaPL7awE:FNzZUH2cZ0E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=mEuAaPL7awE:FNzZUH2cZ0E:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=mEuAaPL7awE:FNzZUH2cZ0E:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=mEuAaPL7awE:FNzZUH2cZ0E:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=mEuAaPL7awE:FNzZUH2cZ0E:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=mEuAaPL7awE:FNzZUH2cZ0E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=mEuAaPL7awE:FNzZUH2cZ0E:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=mEuAaPL7awE:FNzZUH2cZ0E:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/mEuAaPL7awE" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2013/02/announcing-defusedxml-fixes-for-xml.htmltag:blogger.com,1999:blog-3941553907430899163.post-81464114770300829952012-12-20T12:26:00.001-05:002012-12-20T12:26:18.294-05:002012-12-20T12:26:18.294-05:00PandaBoard, Raspberry Pi coming to Buildbot fleet<b id="internal-source-marker_0.3835159728769213" style="font-weight: normal;"><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Thanks to the </span><a href="http://python.org/psf/"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Python Software Foundation</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">, a </span><a href="http://pandaboard.org/"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">PandaBoard</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"> arrived on Trent Nelson’s desk just in time for the holidays! Santa dropped off the present for python-dev this morning, and there’s a </span><a href="http://www.raspberrypi.org/"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Raspberry Pi</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"> not far behind it.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">On Raymond Hettinger’s recent thread about the memory layout of </span><a href="http://mail.python.org/pipermail/python-dev/2012-December/123028.html"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">dictionaries</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">, Barry Warsaw and Christian Heimes shared concerns about how things might look on ARM devices. Christian mentioned the </span><a href="http://www.snakebite.net/"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Snakebite</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"> environment, run by Trent Nelson, but without any ARM machines in the environment, Trent offered to host the boxes if someone donates them.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Based on the thread’s suggestions and the low cost of the devices, the PSF authorized purchase of a PandaBoard ES, featuring a 1.2 GHz ARM Cortex A9, along with several accessories to get it running. The PSF already had a few Raspberry Pi devices on hand, which come with a 700 MHz ARMv6, so one was dispatched to Trent.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Thanks to the PSF for making the purchase, and thanks to Trent for offering to set up the machines and add them to the environment!</span></b><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=c-6RjbAraEg:nFRQWgfDEF8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=c-6RjbAraEg:nFRQWgfDEF8:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=c-6RjbAraEg:nFRQWgfDEF8:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=c-6RjbAraEg:nFRQWgfDEF8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=c-6RjbAraEg:nFRQWgfDEF8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=c-6RjbAraEg:nFRQWgfDEF8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=c-6RjbAraEg:nFRQWgfDEF8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=c-6RjbAraEg:nFRQWgfDEF8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/c-6RjbAraEg" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/12/pandaboard-raspberry-pi-coming-to.htmltag:blogger.com,1999:blog-3941553907430899163.post-57110134124002473822012-11-19T09:53:00.002-05:002012-11-19T09:53:39.015-05:002012-11-19T09:53:39.015-05:00New Contributor Experience in Python and other FOSS Communities - A Survey<b id="internal-source-marker_0.9831261797808111" style="font-weight: normal;"><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">If you have joined the community of developers contributing to CPython since January 2010, I hope you can find a few spare minutes to participate in a survey being put on by Kevin Carillo. He’s a Ph. D. student at Victoria University of Wellington completing research on new contributors to free and open source projects. Kevin is interested in hearing from everyone from technical to non-technical contributors, whether you had positive or negative experiences.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">The survey is available at </span><a href="https://limesurvey.sim.vuw.ac.nz/index.php?sid=65151&amp;lang=en"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">https://limesurvey.sim.vuw.ac.nz/index.php?sid=65151&amp;lang=en</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Kevin states, “The goal of this research is to understand how a person's experience as a newcomer to a Free/Open Source Software (FOSS) community influences that person's behavior and contributions within that community.” He estimates that the survey will take around 20 minutes to complete.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Throughout the nearly three year period since January 2010, over 40 </span><a href="http://docs.python.org/devguide/developers.html"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">committers</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"> were added and countless others contributed patches, reviews, and bug triage. Since the creation of the </span><a href="http://pythonmentors.com/"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">Core-Mentors</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"> group in March 2011, we’ve seen many first timers come through and have their work committed and released.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">We hope that the mentorship group has helped introduce contributors in a positive manner, so we’re looking forward to the results of Kevin’s studies. One of the things Kevin hopes to find is whether or not formal mentorship programs work for introducing contributors. He also looks to find answers to how much community support of newcomers matters, whether formal joining processes involving sponsorship work, and if newcomer specific tasks are the way to go.</span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"></span><br /><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">If you have the time, please fill out </span><a href="https://limesurvey.sim.vuw.ac.nz/index.php?sid=65151&amp;lang=en"><span style="color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">the survey</span></a><span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;">. Python is participating in this survey along with several other groups including Debian, KDE, Gnome, openSUSE, and OpenHatch. Perhaps we can learn a few things and create an even better experience for new contributors!</span></b><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ICfH8qB5Y0s:SXWcsYAImj0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ICfH8qB5Y0s:SXWcsYAImj0:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ICfH8qB5Y0s:SXWcsYAImj0:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ICfH8qB5Y0s:SXWcsYAImj0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ICfH8qB5Y0s:SXWcsYAImj0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ICfH8qB5Y0s:SXWcsYAImj0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ICfH8qB5Y0s:SXWcsYAImj0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ICfH8qB5Y0s:SXWcsYAImj0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/ICfH8qB5Y0s" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/11/new-contributor-experience-in-python.htmltag:blogger.com,1999:blog-3941553907430899163.post-39133167538009318292012-10-30T23:44:00.000-04:002012-10-30T23:45:36.034-04:002012-10-30T23:45:36.034-04:00Python Bug Day this Saturday<div class="entry"> +This Saturday, you have the opportunity of participating to the +Python Bug Day. How would you like to be one of the contributors of +Python? If you have ideas for improving parts of the official +documentation, the standard library, the language itself, or if you have + a patch waiting for a review that you would like to see committed, or +if you just want to come and fix an existing bug, it’s your day!<br /> +<br /> +Join us for an effort at closing some Python bugs and feature +requests. Get quick feedback on your patches and bugfixes, learn how to + submit and examine patches, and have fun chatting with the Python +developers and other contributors. You don’t need to know the CPython +codebase or process to join, just Python programming knowledge.<br /> +<br /> +If you live in <a href="http://montrealpython.org/2012/10/python-bug-day/" target="_blank">Montreal</a>, come at Caravan to meet fellow hackers and +take part in a physical sprint!<br /> +<br /> +<b><a href="http://mpbugday.eventbrite.ca/" target="_blank">Please register</a><a href="http://mpbugday.eventbrite.ca/"></a></b> + to let us know how many people to expect. People from around the world + are should join the #python-dev IRC channel to participate in the +bug day.<br /> +<br /> +<div class="line862"> +This page contains all the information you need to get set up, see the list of bugs or learn about IRC: <a href="http://wiki.python.org/moin/PythonBugDay">http://wiki.python.org/moin/PythonBugDay</a>&nbsp;</div> +<div class="line862"> +<br /></div> +<div class="line862"> +The goal of the bug day is to process bug reports in <a class="http" href="http://bugs.python.org/">the Python bug tracker</a>, trying to <span class="anchor" id="line-50"></span>fix and close issues.&nbsp;</div> +<div class="line862"> +</div> +<div class="line862"> +<span class="anchor" id="line-51"></span><span class="anchor" id="line-52"></span></div> +<div class="line867"> +<span class="anchor" id="line-53"></span><span class="anchor" id="line-54"></span></div> +<div class="line867"> +<span class="anchor" id="line-55"></span></div> +<div class="line867"> +<span class="anchor" id="line-56"></span><span class="anchor" id="line-57"></span></div> +<div class="line867"> +<span class="anchor" id="line-58"></span></div> +<div class="line867"> +<span class="anchor" id="line-59"></span><span class="anchor" id="line-60"></span></div> +<div class="line874"> +<br /></div> +<div class="line874"> +<b>&nbsp;What to do: </b><span class="anchor" id="line-61"></span><span class="anchor" id="line-62"></span></div> +<ul> +<li><div class="line862"> +Grab a copy of the Python codebase from Mercurial, following instructions in the <a class="http" href="http://docs.python.org/devguide">Developer's Guide</a>, and compile it. <span class="anchor" id="line-63"></span></div> +</li> +<li><div class="line862"> +If + you have a problem that isn't in the bug tracker, announce it to the +IRC channel, and if it's more than five minutes' work, create a bug +report for it. See the <a class="http" href="http://docs.python.org/dev/bugs.html">bug reporting instructions</a> to learn <span class="anchor" id="line-64"></span>how to write bug reports. <span class="anchor" id="line-65"></span></div> +</li> +<li>When you choose a bug to work on, announce it to the IRC channel (e.g. "I'm <span class="anchor" id="line-66"></span>working on #123456.") or on the bug report itself. This avoids accidentally duplicating work. <span class="anchor" id="line-67"></span></li> +<li>Consider + providing a patch that fixes the problem, or at least a simple test +case that demonstrates the bug. Please see the patch submission +guidelines in the Developer's Guide before submitting a patch. <span class="anchor" id="line-68"></span></li> +<li>Does + the bug appear to be gone in the Python development version (the +Mercurial branch "default", that will become 3.4), but not the 3.2, 3.3 +or 2.7 maintenance branchs? Report that, too. <span class="anchor" id="line-69"></span></li> +<li>If someone else has supplied a fix, see if this fix works for² you, and add your results to the bug. <span class="anchor" id="line-70"></span></li> +<li>Read the text of proposed patches and assess them for correctness and code quality. <span class="anchor" id="line-71"></span>This is usually the most time-consuming step in the bug fixing process, so reading patches <span class="anchor" id="line-72"></span>is very useful. <span class="anchor" id="line-73"></span></li> +<li>If there's a working fix, feel free to add a note asking for <span class="anchor" id="line-74"></span>the fix to get committed. The bug tracker has a lot of items in it, and it's easy for bugs to be overlooked. <span class="anchor" id="line-75"></span></li> +<li>Feature requests should be classified as type 'feature request' in the bug tracker. </li> +</ul> +If you need any help beforehand, feel free to ask on <a href="http://mail.python.org/mailman/listinfo/core-mentorship">core-mentorship mailing-list </a></div> +<div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=YwdJhjL4F0Y:gqJ51WnKXno:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=YwdJhjL4F0Y:gqJ51WnKXno:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=YwdJhjL4F0Y:gqJ51WnKXno:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=YwdJhjL4F0Y:gqJ51WnKXno:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=YwdJhjL4F0Y:gqJ51WnKXno:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=YwdJhjL4F0Y:gqJ51WnKXno:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=YwdJhjL4F0Y:gqJ51WnKXno:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=YwdJhjL4F0Y:gqJ51WnKXno:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/YwdJhjL4F0Y" height="1" width="1"/>Mathieu Leduc-Hamelhttp://www.blogger.com/profile/07757697862303956313noreply@blogger.comMontreal, QC, Canada45.5086699 -73.553992545.3306269 -73.8698495 45.6867129 -73.23813550000001http://blog.python.org/2012/10/python-bug-day-this-saturday.htmltag:blogger.com,1999:blog-3941553907430899163.post-74817557241470528852012-10-29T13:51:00.000-04:002012-10-29T13:58:42.023-04:002012-10-29T13:58:42.023-04:00Updates to docs.python.org<div class="document" id="updates-to-docs-python-org"> +If you haven't already noticed, several months ago we updated the Sphinx theme for documentation of versions Python 3.2 and beyond on <a href="http://docs.python.org">docs.python.org</a>. It's a more modern look, and it also serves as an indicator that you're looking at documentation for a newer version. Thanks go out to Georg Brandl for his work on Sphinx, Python's documentation, and this new theme!<br /> +<div class="section" id="pep-430"><br/> +<h4>PEP 430</h4><br/> +Over the weekend, <a class="reference external" href="http://www.python.org/dev/peps/pep-0430/">PEP 430</a> was approved, which changes the default documentation displayed at <a class="reference external" href="http://docs.python.org/">http://docs.python.org</a>. See the PEP for full details, but the jist is that we're now promoting the current Python 3 release as the default when you go to the docs home page. However, as the majority use case is still for Python 2 documentation, navigating straight to an unversioned page will present you with the current Python 2 documentation. For example, an unversioned link such as <a class="reference external" href="http://docs.python.org/library/zipfile">http://docs.python.org/library/zipfile</a> will bring up the 2.7.3 documentation.</div> +<div class="section" id="version-dropdown"><br/> +<h4>Version Dropdown</h4><br/> +Supporting that change is a new feature that adds a version dropdown to the top of all documentation pages. Not only does this help when users are brought to a page which they don't expect, but switching between versions is a common operation as more and more projects work to add support for Python 3. <a class="reference external" href="http://bugs.python.org/issue8040">Issue 8040</a> is where you'll find discussion on the change and its patches, with the bulk of the work completed by Yury Selivanov with some help from Georg.<br /><br/> +<div class="separator" style="clear: both; text-align: center;"> +<a href="http://i.imgur.com/GMPHE.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="177" width="529" src="http://i.imgur.com/GMPHE.png" /></a></div> +<br /> +This dropdown is especially handy as you peruse the documentation and come to a page that you want to view in another version. Choosing another version while on any page will load that page's other version, where the latest release of that version is chosen, e.g., 2.7 currently points to 2.7.3. So, as you browse the 2.7.3 built-ins page, choosing 3.3 in the dropdown will bring you to the 3.3.0 built-ins page.<br /> +<br /> +<div class="separator" style="clear: both; text-align: center;"> +<a href="http://i.imgur.com/9Zz7s.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="243" width="541" src="http://i.imgur.com/9Zz7s.png" /></a></div> + + +<br/> +We hope these changes enhance your experience when browsing the Python documentation!</div> +</div> +<div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=0eVUB6TXykc:93UNm5liOJw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=0eVUB6TXykc:93UNm5liOJw:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=0eVUB6TXykc:93UNm5liOJw:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=0eVUB6TXykc:93UNm5liOJw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=0eVUB6TXykc:93UNm5liOJw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=0eVUB6TXykc:93UNm5liOJw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=0eVUB6TXykc:93UNm5liOJw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=0eVUB6TXykc:93UNm5liOJw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/0eVUB6TXykc" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/10/updates-to-docspythonorg.htmltag:blogger.com,1999:blog-3941553907430899163.post-26874471934921781862012-08-14T10:00:00.000-04:002012-08-14T10:00:02.798-04:002012-08-14T10:00:02.798-04:00Python 3.3 Beta 2 Released<div class="document" id="python-3-3-beta-2-released"> + +<p>Release manager Georg Brandl announced on August 12 that <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">the second beta of +CPython 3.3 was released</a>, complete with installers for both Mac and Windows. +This release represents the final feature set, and the goal is to get it in +the hands of users to iron out any last issues.</p> +<p>Following this beta will be two release candidates, coming August 25 and +September 8. The final release is slated to happen on September 22.</p> +<p>The &quot;<a class="reference external" href="http://docs.python.org/dev/whatsnew/3.3.html">What's New in Python 3.3</a>&quot; document is currently being finalized by +curator and long time developer Raymond Hettinger. The document already +contains many of the new changes, but keep an eye out for newer versions.</p> +<p>Here are some of the bigger changes:</p> +<ul class="simple"> +<li><a class="reference external" href="http://python.org/dev/peps/pep-0380">PEP 380</a>, syntax for delegating to a subgenerator (&quot;yield from&quot;)</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-0393">PEP 393</a>, flexible string representation (doing away with the +distinction between &quot;wide&quot; and &quot;narrow&quot; Unicode builds)</li> +<li>A <a class="reference external" href="http://bugs.python.org/issue7652">C implementation of the &quot;decimal&quot; module</a>, with up to 80x speedup +for decimal-heavy applications</li> +<li>The import system (__import__) <a class="reference external" href="http://bugs.python.org/issue2377">now based on importlib</a> by default</li> +<li>The new &quot;<a class="reference external" href="http://docs.python.org/dev/library/lzma">lzma</a>&quot; module with LZMA/XZ support</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-0397">PEP 397</a>, a Python launcher for Windows</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-0405">PEP 405</a>, virtual environment support in core</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-0420">PEP 420</a>, namespace package support</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-3151">PEP 3151</a>, reworking the OS and IO exception hierarchy</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-3155">PEP 3155</a>, qualified name for classes and functions</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-0409">PEP 409</a>, suppressing exception context</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-0414">PEP 414</a>, explicit Unicode literals to help with porting</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-0418">PEP 418</a>, extended platform-independent clocks in the &quot;time&quot; module</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-0412">PEP 412</a>, a new key-sharing dictionary implementation that +significantly saves memory for object-oriented code</li> +<li><a class="reference external" href="http://python.org/dev/peps/pep-0361">PEP 362</a>, the function-signature object</li> +<li>The new &quot;<a class="reference external" href="http://docs.python.org/dev/library/faulthandler">faulthandler</a>&quot; module that helps diagnosing crashes</li> +<li>The new &quot;<a class="reference external" href="http://docs.python.org/dev/library/unittest.mock">unittest.mock</a>&quot; module</li> +<li>The new &quot;<a class="reference external" href="http://docs.python.org/dev/library/ipaddress">ipaddress</a>&quot; module</li> +<li>The &quot;<a class="reference external" href="http://docs.python.org/dev/library/sys#sys.implementation">sys.implementation</a>&quot; attribute</li> +<li>A policy framework for the email package, with a provisional (see +<a class="reference external" href="http://python.org/dev/peps/pep-0411">PEP 411</a>) policy that adds much improved unicode support for email +header parsing</li> +<li>A &quot;<a class="reference external" href="http://docs.python.org/dev/library/collections#collections.ChainMap">collections.ChainMap</a>&quot; class for linking mappings to a single unit</li> +<li>Wrappers for many more POSIX functions in the &quot;os&quot; and &quot;signal&quot; +modules, as well as other useful functions such as &quot;sendfile()&quot;</li> +<li>Hash randomization, introduced in earlier bugfix releases, is now +switched on by default</li> +</ul> +<p>In total, almost 500 API items are new or improved in Python 3.3.</p> +<p>Be sure to check out this release at <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">http://www.python.org/download/releases/3.3.0/</a> +and report any issues to <a class="reference external" href="http://bugs.python.org">http://bugs.python.org</a>.</p> +</div> +<div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=fyJFt5G70x0:bM6oa3IqoU4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=fyJFt5G70x0:bM6oa3IqoU4:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=fyJFt5G70x0:bM6oa3IqoU4:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=fyJFt5G70x0:bM6oa3IqoU4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=fyJFt5G70x0:bM6oa3IqoU4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=fyJFt5G70x0:bM6oa3IqoU4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=fyJFt5G70x0:bM6oa3IqoU4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=fyJFt5G70x0:bM6oa3IqoU4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/fyJFt5G70x0" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/08/python-33-beta-2-released.htmltag:blogger.com,1999:blog-3941553907430899163.post-31899894346973035052012-06-07T10:00:00.000-04:002012-06-07T10:00:03.299-04:002012-06-07T10:00:03.299-04:00Mercurial Mirrors Provided by Atlassian<div class="document" id="mercurial-mirrors-provided-by-atlassian"> +Long-time friends of the Python community, Atlassian (makers of <a class="reference external" href="http://www.bitbucket.org/">Bitbucket</a>) recently made available a mirror of <a class="reference external" href="http://hg.python.org/">http://hg.python.org</a>, synchronized hourly, for your cloning and hacking pleasure.<br /> +<br /> +Using <a class="reference external" href="https://bitbucket.org/python_mirrors">the new mirror</a> should be very intuitive for current users of the Hg repository -- the projects housed in the mirror follow the same naming convention as the repository they're mirroring. So, the CPython source code is mirrored at <a class="reference external" href="https://bitbucket.org/python_mirrors/cpython">https://bitbucket.org/python_mirrors/cpython</a>, corresponding to its canonical home at <a class="reference external" href="http://hg.python.org/cpython">http://hg.python.org/cpython</a>.<br /> +<br /> +Since it's hosted on Bitbucket, the collaborative floodgates are effectively flung open. Not only is it dead easy to clone and submit contributions back to the project, you'll also have the ability to follow the project and receive updates in your dashboard. If RSS is more your style, Bitbucket makes it easy to stay up-to-date with changes via each repository's feed.<br /> +<br /> +If you cloned the cpython repo and want to submit your changes to an issue on <a class="reference external" href="http://bugs.python.org/">http://bugs.python.org</a>, it's as simple as pasting a link to your Bitbucket clone in the "Remote hg repo" box. The <tt class="docutils literal">default</tt> branch is automatically chosen, but appending <tt class="docutils literal">#branchname</tt> to the end of your link will choose that branch.<br /> +<img alt="http://i.imgur.com/6popx.png" src="http://i.imgur.com/6popx.png" /> +<br /> +See how easy it is to get your changes associated with an issue? If you're interested in getting started with CPython development, check out our <a class="reference external" href="http://docs.python.org/devguide">developer guide</a>.<br /> +<hr class="docutils" /> +Atlassian has been a user of Python and supporter of the Python community for some time now. They've sponsored PyCons around the world as well as events at those conferences, from the CodeWars competitions during PyCon AU to the recent PyLadies party at PyCon US!<br /> +<br /> +Thanks, Atlassian!</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TKMQ7tK4z0c:8G3frAu_Ep0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TKMQ7tK4z0c:8G3frAu_Ep0:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TKMQ7tK4z0c:8G3frAu_Ep0:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TKMQ7tK4z0c:8G3frAu_Ep0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TKMQ7tK4z0c:8G3frAu_Ep0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TKMQ7tK4z0c:8G3frAu_Ep0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TKMQ7tK4z0c:8G3frAu_Ep0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TKMQ7tK4z0c:8G3frAu_Ep0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/TKMQ7tK4z0c" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/06/mercurial-mirrors-provided-by-atlassian.htmltag:blogger.com,1999:blog-3941553907430899163.post-45498580821081577872012-06-01T10:30:00.000-04:002012-06-01T10:30:00.743-04:002012-06-01T10:30:00.743-04:00Python 3.3 Alpha 4 Released<div class="document" id="python-3-3-alpha-4-released"> +<p>Yesterday, May 31, brought the <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">fourth alpha release</a> in the Python 3.3 development schedule. It's an exciting release as it introduces a number of long awaited features that we really hope the community will enjoy.</p> +<div class="section" id="new-features"> +<h4>New Features</h4> +<div class="section" id="pep-405-virtual-environments"> +<h5>PEP 405 - Virtual Environments</h5> +<p>Just in time for Alpha 4 comes the addition of <a class="reference external" href="http://www.python.org/dev/peps/pep-0405/">PEP 405</a>'s support for virtual environments by way of the <tt class="docutils literal">venv</tt> module and <tt class="docutils literal">pyenv</tt> script.</p> +<blockquote> +<tt class="docutils literal">python <span class="pre">-m</span> venv /home/yourname/dev/myproject</tt></blockquote> +<p>You may know this functionality through <a class="reference external" href="http://www.virtualenv.org/en/latest/index.html">virtualenv</a>, originally created by Ian Bicking. Thanks to Carl Meyer, Vinay Sajip, and anyone else for working on the PEP and implementation, we now have this widely used functionality available in a Python release!</p> +</div> +<div class="section" id="pep-420-namespace-packages"> +<h5>PEP 420 - Namespace Packages</h5> +<p>After a long road featuring two preceding PEPS (<a class="reference external" href="http://www.python.org/dev/peps/pep-0382/">382</a> and <a class="reference external" href="http://www.python.org/dev/peps/pep-0402/">402</a>), several sprints (including one <a class="reference external" href="http://pythonsprints.com/2011/06/16/pep-382-sprint-maryland/">sponsored by the PSF</a>), and much discussion on python-dev, import-sig, and at PyCon language summits over the last two years, namespace packages are here. At <a class="reference external" href="http://blog.python.org/2012/03/2012-language-summit-report.html">the summit</a>, Eric Smith stepped up to write a new PEP after the group decided to reject PEPs 382 and 402.</p> +<p>The result is <a class="reference external" href="http://www.python.org/dev/peps/pep-0420/">PEP 420</a>. The most obvious feature of a namespace package is the lack of a <tt class="docutils literal">__init__.py</tt> file. However, there's a lot more to it, so check out the PEP!</p> +</div> +<div class="section" id="pep-3144-the-ipaddress-module"> +<h5>PEP 3144 - The ipaddress Module</h5> +<p>After discussion starting during the Python 3.2 development cycle, the + +<tt class="docutils literal">ipaddress</tt> module has a new home in the standard library for 3.3. + +<a class="reference external" href="http://www.python.org/dev/peps/pep-3144/">PEP 3144</a>, authored by Peter Moody and taken up by core contributor Nick Coghlan, introduces a collection of classes for working with addresses, networks, and interfaces for both IPv4 and IPv6.</p> +</div> +<div class="section" id="windows-build-upgraded-to-visual-studio-2010"> +<h5>Windows Build Upgraded to Visual Studio 2010</h5> +<p>As was <a class="reference external" href="http://blog.python.org/2012/05/recent-windows-changes-in-python-33.html">recently covered</a>, the Alpha 4 Windows installers now feature binaries produced by Visual Studio 2010, up from the 2008 version. We needed to upgrade to keep up with what most organizations and many of our contributors were using, along with the fact that <em>not changing</em> would mean we'd be at least two versions behind at our next opportunity to do so. With Python 3.4 not coming out until some time in 2014, we didn't want to end up eight years behind the curve and have to make that big of a version jump.</p> +</div> +</div> +<div class="section" id="bug-fixes"> +<h4>Bug Fixes</h4> +<p>As with all of our releases, many contributors submitted patches to fix over 80 issues since last month's Alpha 3. We have fixes across a number of modules, including batches of fixes to <a class="reference external" href="http://docs.python.org/dev/library/idle.html">IDLE</a>, <a class="reference external" href="http://docs.python.org/dev/library/email.html">email</a>, and <a class="reference external" href="http://docs.python.org/dev/library/urllib.request.html">urllib</a>.</p> +</div> +<div class="section" id="we-need-your-help"> +<h4>We Need Your Help!</h4> +<p>As with all of our releases, backwards compatibility is important to us, so we'd love to hear if any of your projects have issues. Please help us make the best release possible by <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">trying it out</a>!</p> +<p>Python 3.3 is quickly shaping up to be the release everyone's waiting for, so run your tests and report your issues to <a class="reference external" href="http://bugs.python.org">http://bugs.python.org</a>.</p> +<hr class="docutils" /> +<p><a class="reference external" href="http://www.python.org/download/releases/3.3.0/">Download it now</a>!</p> +</div> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rUOAjDbK18A:ezJqXnlP8Gg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rUOAjDbK18A:ezJqXnlP8Gg:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rUOAjDbK18A:ezJqXnlP8Gg:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rUOAjDbK18A:ezJqXnlP8Gg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rUOAjDbK18A:ezJqXnlP8Gg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rUOAjDbK18A:ezJqXnlP8Gg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rUOAjDbK18A:ezJqXnlP8Gg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rUOAjDbK18A:ezJqXnlP8Gg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/rUOAjDbK18A" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/06/python-33-alpha-4-released.htmltag:blogger.com,1999:blog-3941553907430899163.post-21176445189675247772012-05-24T11:00:00.000-04:002012-05-24T12:08:43.331-04:002012-05-24T12:08:43.331-04:00Recent Windows Changes in Python 3.3<div class="document" id="recent-windows-changes-in-python-3-3"> +The Windows build of Python 3.3 has recently seen changes that could use a look from the community throughout our alpha and beta cycle. The first change is the long requested addition of Python to the system <tt class="docutils literal">Path</tt> variable, which was completed in the installer. Secondly, the build was upgraded to Visual Studio 2010.<br /> +<br /> +<div class="section" id="python-on-the-path"> +<h4> + + +Python on the Path</h4> +A long requested feature, especially from beginners to those involved in education and training, has been the ability for the Python installer to place itself in the system <tt class="docutils literal">Path</tt> environment variable. Having the following message appear when you try to run a simple exercise is not a great first experience:<br /> +<blockquote> +<tt class="docutils literal">'python' is not recognized as an internal or external command, operable program or batch file.</tt></blockquote> +Because of that, the first post-install step by many users is to edit the <tt class="docutils literal">Path</tt> environment variable manually to insert the C:Python33 directory. This allows the user to simply type <tt class="docutils literal">python</tt> on the command line and have it open <tt class="docutils literal"><span class="pre">C:\\Python33\\python.exe</span></tt> -- a very desirable feature for a majority of users. In fact, it's such a common post-install step that there are a huge amount of tutorials either about this step by itself or tutorials where their setup introduces this step before moving on.<br /> +<blockquote> +<img alt="http://i.imgur.com/aixuY.png" src="http://i.imgur.com/aixuY.png" /> +</blockquote> +The easiest part of the whole thing was <a class="reference external" href="http://hg.python.org/cpython/rev/4e9f1017355f">the code</a>. <tt class="docutils literal">Path</tt> manipulation in the installer consists of adding a new feature to the Feature table, then the Environment table may be updated based on selection of the Path feature. If the feature was selected, the Environment table is modified in a way that the <tt class="docutils literal">Path</tt> is prepended to and will be correctly cleaned up on uninstallation.<br /> +<br /> +The harder part was deciding how to go about the change. If you're going to provide <tt class="docutils literal">Path</tt> manipulation, the major questions are to do it by default or not, and to prepend or append to the <tt class="docutils literal">Path</tt>.<br /> +<br /> +We decided that it wasn't appropriate to make this a default feature. For one, in the dual-version state many users are running in, we run the risk of users running through the installer and putting their system into a state they aren't prepared for. We don't want to change the meaning of <tt class="docutils literal">python</tt> when executed on the command line without the user asking for it. On one hand it's a very beginner focused feature in that it gets a first-timer successfully up and running with ease. However, it's also an advanced feature in that it takes a good understanding of what it's going to do to the users who have 2.6, 2.7, 3.2, and now 3.3 on their machines. We think the best solution for all is to leave it up to them and include an explanation.<br /> +<br /> +The other part we had to think about was whether to prepend or append to the path. While some believe that appending to the path is the more friendly way to work with the system, it would seem to be of limited utility given that the feature is added this late in the game. Instead we went the route of prepending the installation folder, e.g., C:\Python33, in order to make sure this feature is actually useful to our users.<br /> +<br /> +If you have questions or comments, please feel free to raise them on python-dev or see <a class="reference external" href="http://bugs.python.org/issue3561">Issue 3561</a>.<br /> +<br /></div> +<div class="section" id="transition-to-visual-studio-2010"> +<h4> + + +Transition to Visual Studio 2010</h4> +In time for the last alpha release, we've updated our build tools from Visual Studio 2008 to 2010.<br /> +Many potential contributors as well as general Python users have long moved to work environments that use Visual Studio 2010. During a "bug day" some months ago, we had two or three patches come from interested first-timers who found our VS2008 solution not working in VS2010. Over time we received a few more contributions and bug reports on the topic, as well as some chatter in IRC about being behind the curve.<br /> +<br /> +On top of that, my employer at the time moved to VS2010 as well as the employers of at least one other core maintainer, so we were already operating on ports for our companies.<br /> +<br /> +When it came time to think about what to do for Python 3.3, moving to VS2010 became a <em>must have</em> due to our release schedule. Staying with VS2008 for 3.3 would put us into the middle of 2014 as the next time we could release on a new version. That would leave us at least two versions behind, with VS2010 as well as VS11 being available by then.<br /> +<br /> +Another reason is the relative ease of porting between VS2010 and VS11. Once we got ourselves on to 2010, moving on to 11 would not be that hard. VS11 currently reads our VS2010 files without change if you want to use the IDE features of VS11. However, there'd need to be another port in order to use the VS11 compiler suite, but it seems to require minimal effort. Just following the VS11 wizard produced a functioning executable, although it didn't build cleanly.<br /> +<br /> +<div class="section" id="where-to-get-visual-studio-2010"> +<h5> + + +Where to get Visual Studio 2010?</h5> +As usual, Microsoft provides a zero-cost version of Visual Studio 2010 in the name Visual C++ Express, available at <a class="reference external" href="http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express">http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express</a>. While there are <a class="reference external" href="http://msdn.microsoft.com/en-us/library/hs24szh9(v=vs.100).aspx">some differences</a> between the Express version and the for-purchase versions, the Express version is used successfully by many contributors.<br /> +<br /> +The fine folks at Microsoft's <a class="reference external" href="http://www.microsoft.com/en-us/openness/default.aspx#home">Open Source Technology Center</a> have provided the core contributors with MSDN licenses free of charge, allowing for access to the full versions of Visual Studio among other products. The full versions of Visual Studio support 64-bit compilation which comes in handy for our amd64 releases, which have been available since 2.5.<br /> +<br /></div> +</div> +<div class="section" id="help-us-out-try-the-alphas-and-betas"> +<h4> + + +Help us out -- try the alphas and betas!</h4> +With a change to the installer, a new build system, and the <a class="reference external" href="http://docs.python.org/dev/whatsnew/3.3.html">other great changes</a> we have in store, the more feedback we hear from the community during the development cycle, the better we can make this release. If you have a chance to run your projects on Python 3.3, <a class="reference external" href="http://bugs.python.org/">http://bugs.python.org</a> is always open for your reports. You've even got a month to get feature requests in and completed!<br /> +<br /> +The last alpha release is scheduled for this weekend, and the first beta release is scheduled for June 24. You can download our 3.3.0 releases at <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">http://www.python.org/download/releases/3.3.0/</a>.</div> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/rWPwayEXWfE" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/05/recent-windows-changes-in-python-33.htmltag:blogger.com,1999:blog-3941553907430899163.post-86221028548645707822012-03-14T10:05:00.000-04:002012-03-14T23:36:35.528-04:002012-03-14T23:36:35.528-04:002012 Language Summit Report<div class="document" id="language-summit-report"> +This year's Language Summit took place on Wednesday March 7 in Santa Clara, CA before the start of <a class="reference external" href="https://us.pycon.org/2012/">PyCon 2012</a>. As with previous years, in attendance were members of the various Python VMs, packagers from various Linux distributions, and members of several community projects.<br /><br /> +<div class="section" id="the-namespace-peps"> +<h4> +The Namespace PEPs</h4> +The summit began with a discussion on PEPs <a class="reference external" href="http://www.python.org/dev/peps/pep-0382/">382</a> and <a class="reference external" href="http://www.python.org/dev/peps/pep-0402/">402</a>, with Barry Warsaw leading much of the discussion. After some discussion, the decision was ultimately deferred with what appeared to be a want for parts of both PEPs.<br /> +<br /> +As of Monday at the PyCon sprints, both PEPs have been rejected (see the Rejection Notice at the top of each PEP). Martin von Loewis <a class="reference external" href="http://mail.python.org/pipermail/import-sig/2012-March/000421.html">posted to the import-sig list</a> that a resolution has been found and Eric Smith will draft a new PEP on the ideas agreed upon there. Effectively, PEP 382 has been outright rejected, while portions of PEP 402 will be accepted.</div> +<br /> +<div class="section" id="importlib-status"> +<h4> +<tt class="docutils literal">importlib</tt> Status</h4> +Brett Cannon announced that there is a completed and available branch of CPython using importlib at <a class="reference external" href="http://hg.python.org/sandbox/bcannon/">http://hg.python.org/sandbox/bcannon/</a>. See the <tt class="docutils literal">bootstrap_importlib</tt> named branch.<br /> +<br /> +Discussion began by outlining the only real existing issue, which lies in <tt class="docutils literal">stat</tt>'ing of directories. There's a minor backwards incompatibility issue with time granularity. However, everyone agreed that it's so unlikely to be of issue that it's not a showstopper and the work can move forward. Additionally, there was an optimization made around the <tt class="docutils literal">stat</tt> calls, which was arrived at independently by each of Brett, Antoine Pitrou, and P.J. Eby.<br /> +<br /> +The topic of performance came up and Brett explained that the current pure-Python implementation is around 5% slower. Thomas Wouters exclaimed that 5% slower is actually really good, especially given some recent benchmark work he was doing showing that changing compilers sometimes shows a 5% difference in startup time. There was a shared feeling that 5% slower was not something to hold up integration of the code, which pushed discussion happily along.<br /> +<br /> +Brett went on to explain what the bootstrapping actually looks like, even asserting that the implementation finds what could be the first <em>real</em> use of frozen modules! Guido's first response was, "you mean to tell me that after 20 years we finally found a use for freezing code?"<br /> +<br /> +<tt class="docutils literal">importlib._bootstrap</tt> is a frozen module containing the necessary builtins to operate, along with some re-implementations of a small number of functions. Some of the libraries included in the frozen module are <tt class="docutils literal">warnings</tt>, <tt class="docutils literal">_os</tt> (select code from <tt class="docutils literal">posix</tt>), and <tt class="docutils literal">marshal</tt>.<br /> +<br /> +Another compatibility issue was brought up, but again, was decided to be an issue unworthy of halting the progress on this issue. There's a negative level count which is not supported in <tt class="docutils literal">importlib</tt>, used in implicit relative imports, and it was agreed that it's acceptable to continue not supporting it.<br /> +<br /> +The future will likely result in a strip down of <tt class="docutils literal">import.c</tt>, as well as the exposure of numerous hooks as well as exposure of much of the <tt class="docutils literal">importlib</tt> API.<br /> +<br /> +As for merging with the <tt class="docutils literal">default</tt> branch, it was pretty universally agreed upon that this should happen for 3.3 and it should happen soon in order to get mileage on the implementation throughout the alpha and beta cycles. Since this will be happening shortly, Brett is going to follow-up to python-dev with some cleanup details and look for reviews.</div> +<br /> +<div class="section" id="release-schedule-peps"> +<h4> +Release Schedule PEPs</h4> +Discussion on PEPs <a class="reference external" href="http://www.python.org/dev/peps/pep-0407/">407</a> and <a class="reference external" href="http://www.python.org/dev/peps/pep-0413/">413</a> followed the <tt class="docutils literal">importlib</tt> talk. Like the namespace PEP discussion, several ideas were tossed around but the group didn't arrive at any conclusion on acceptability of the PEPs.<br /> +<br /> +Immediately, the idea of splitting out the standard library to be on its own was resurrected, which could lend itself to both PEPs. Some questions remain, namely in where would the test suite live. Additionally, there may need to be some distinction between the tests which cover standard libraries versus the tests which cover language features.<br /> +<br /> +The topic of versioning came up, with three distinctions needing to be made. We would seem to need a version of the language spec, a version of the implementation, and a version of the standard library.<br /> +<br /> +Many commenters mentioned that these PEPs make things too complicated. Additionally, there was a question about whether there are enough users who care about either of these changes being made. Several of us stated that <em>we</em> could use the quicker releases, but with so many users being stuck on old versions for one reason or another, there was a wonder of who would take the releases.<br /> +<br /> +Thomas Wouters mentioned a good point about the difficulty in lining up the so-called Python "LTS" releases with other Python consumers who do similar LTS-style releases. Ubuntu and their LTS schedule was a prime example, as well as the organizations who plan releases atop something like Ubuntu. Many of the Linux distribution packagers in attendance seemed to agree.<br /> +<br /> +One thing that seemed to have broad agreement was that shortening the standard library turnaround time would be a good thing in terms of new contributors. Few people are interested in writing new features that might not be released for over a year -- it's just not fun. Even with bug fixes, sometimes the duration can be seen as too long, to the point where users may end up just fixing our problems from within their own code if possible.<br /> +<br /> +Guido went on to make a comment about how we hope to avoid the mindset some have of "my package isn't accepted until it's in the standard library". The focus continues to be on projects being hosted on PyPI, being successful out in the wild, then vetted for acceptance in the standard library after maturity of the project and its APIs.<br /> +<br /> +It was suggested that perhaps speeding up bug fix releases could be a good move, but we would need to check with release managers to ensure they're on board and willing to expend the effort to produce more frequent releases. As with the new feature releases, we need to be sure there's an audience to take the new bug fixes.<br /> +<br /> +There was also some discussion about what have previously been called "sumo" releases. Given that some similar releases are already made by third-party vendors, the idea didn't seem to gain much traction.</div> +<br /> +<div class="section" id="funding-from-the-python-software-foundation"> +<h4> +Funding from the Python Software Foundation</h4> +PSF Chairman Steve Holden joined the group after lunch to mention that the foundation has resources available to assist development efforts, especially given the sponsorship success of this year's conference. While the foundation can't and won't dictate what should be coded up, they're open to proposals about the types of work to be funded.<br /> +<br /> +Steve and Jesse Noller were adamant about the support not only being for all Python implementations, but also for third-party projects. What's needed to begin funding for a project is a concrete proposal on what will be accomplished. They stressed that the money is ready and waiting -- proposals are the way to unlock it.<br /> +<br /> +Some ideas for how to use the funding came from Steve but also from around the room. One idea which started off the discussion was the idea of funding one-month sabbaticals. Then comes the issue of who might be available. Some suggested that freelance consultants in the development community might be the ones we should try to engage. Those with full-time employment may find it harder to acquire such a sabbatical, but the possibility is open to anyone.<br /> +Another thought was potential funding of someone to do spurts of full-time effort on the bug tracker, ideally someone already involved in the triage effort. This type of funding would hope to put an end to the times when it takes three days to fix a bug and three years for the patch to be accepted. Some thought this might be a nice idea in the short term, but it could be tough work and burn out the individual(s) involved. If anyone is up for it, they're encouraged to propose the idea to the foundation.<br /> +<br /> +Along similar lines of tracker maintenance, Glyph Lefkowitz of the Twisted project had an idea to fund code reviews over code-writing efforts. Some thought this might be a good way to push forward the <tt class="docutils literal">regex</tt>/<tt class="docutils literal">re</tt> situation, given that the <tt class="docutils literal">regex</tt> is very large and most felt that the only thing holding it back from some form of inclusion is an in-depth review. The <tt class="docutils literal">cdecimal</tt> module was mentioned as another project that could use some review assistance.<br /> +<br /> +The code review funding is also an idea to push forward some third-party project's ports to Python 3, specifically including Twisted, which the group felt was an effort which should receive some of this funding.<br /> +<br /> +Along the way it was remarked that the <a class="reference external" href="http://pythonmentors.com/">core-mentors</a> group has been a success in involving new contributors. Kudos to those involved with that list.</div> +<br /> +<div class="section" id="virtualenv-inclusion"> +<h4> +<tt class="docutils literal">virtualenv</tt> Inclusion</h4> +In about two minutes, discussion on PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0405/">405</a> came and went. Carl Meyer mentioned that a reference implementation is available and is working pretty well. A look from the OSX maintainers would be beneficial, and both Ned Deily and Ronald Oussoren were in attendance. It seemed like one of the only things left in terms of the PEP was to find someone to make a declaration on it, and Thomas Wouters put his name out there if Nick Coghlan wasn't going to do t (update: Nick will be the PEP czar).</div> +<br /> +<div class="section" id="pep-397-inclusion"> +<h4> +PEP 397 Inclusion</h4> +Without much of a Windows representation at the summit, discussion was fairlyquick, but it was pretty much agreed that PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0397/">397</a> was something we should accept. Brian Curtin spoke in favor of the PEP, as well as mentioning ongoing work on the Windows installer to optionally add the executable's directory to the Path.<br /> +<br /> +After discussion outside of the summit, it was additionally agreed upon that the launcher should be installed via the 3.3 Windows installer, while it can also live as a standalone installer for those not taking 3.3. Additionally, there needs to be some work done on the PEP to remove much of the low-level detail that is coupled too tightly with the implementation, e.g., explaining of the location of the <tt class="docutils literal">py.ini</tt> file.</div> +<br /> +<div class="section" id="speed-python-org"> +<h4> +speed.python.org</h4> +After generous hardware donations, the <a class="reference external" href="http://speed.python.org/">http://speed.python.org</a> site has gone live and is currently running PyPy benchmarks. We need to make a decision on what benchmarks can be used as well as what benchmarks <em>should</em> be used when it comes to creating a Python 3 suite. As we get implementations on Python 3 we'll want to scale back 2.7 testing and push forward with 3.x.<br /> +<br /> +The project suffers not from a technological problem but from a personnel problem, which was thought to be another area that funding could be used for. However, even if money is on the table, we still need to find someone with the time, the know-how, and the drive to complete the task. Ideally the starting task would be to get PyPy and CPython implementations running and comparing. After that, there are a number of infrastructure tasks in line.</div> +<br /> +<div class="section" id="pep-411-inclusion"> +<h4> +PEP 411 Inclusion</h4> +PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0411/">411</a> proposes the inclusion of provisional packages into the standard library. The recently discussed <tt class="docutils literal">regex</tt> and <tt class="docutils literal">ipaddr</tt> modules were used as examples of libraries to include under this PEP. As for how this inclusion should be implemented and denoted to users was the major discussion point.<br /> +<br /> +It was first suggested that documentation notes don't work -- we can't rely only on documentation to be the single notification point, especially for this type of code inclusion. Other thoughts were some type of flag on the library to specify its experimental status. Another thought was to emit a warning on import of a provisional library, but it's another thing that we'd likely want to silence by default in order to not affect user code in the hopes that developers are running their test suite with warnings enabled. However, as with other times we've gone down this path, we run the risk of developers just disabling warnings all together if they become annoying.<br /> +<br /> +As has been suggested on python-dev, importing a provisional library from a special package, e.g., <tt class="docutils literal">from __experimental__ import foo</tt>, was pretty strongly discouraged. If the library gains a consistent API, it penalizes users once it moves from provisional status to being officially accepted. Aliasing just exacerbates the problem.<br /> +<br /> +The PEP boils down to being about process, and we need to be sure that libraries being included use the ability to change APIs very carefully. We also need to make people, especially the library author, aware of the need to be responsive to feedback and open to change as the code reaches a wider audience.<br /> +<br /> +Looking back, Jesse Noller suggested <tt class="docutils literal">multiprocessing</tt> would have been a good candidate for something like this PEP is suggesting. Around this time, it was suggested that Michael Foord's <a class="reference external" href="http://www.voidspace.org.uk/python/mock/">mock</a> could gain some provisional inclusion within <tt class="docutils literal">unittest</tt>, perhaps as <tt class="docutils literal">unittest.mock</tt>. Instead, given <tt class="docutils literal">mock</tt>'s stable API and wide use among us, along with the need for a mocking library within our own test suite, it was agreed to just accept it directly into the standard library without any provisional status.<br > +<br /> +While on the topic of ``regex``'s role within the PEP came an idea from Thomas Wouters that ``regex`` be introduced into the standard library, bypassing any provisional status. From there, the previously known ``re`` module could be moved to the ``sre`` name, and there didn't appear to be any dissenting opinion there.<br /> +<br /> +It should also be noted to users of provisional libraries that the library maintainers would need to exercise extreme care and be very conservative in changing of the APIs. The last thing we want to do is introduce a good library but as a moving target to its users.<br /> +</div> +<br /> +<div class="section" id="keyword-arguments-on-all-builtin-functions"> +<h4> +Keyword Arguments on all builtin functions</h4> +As recently came up on the tracker, it was suggested that wider use of keyword arguments in our APIs would likely be a good thing. Gregory P. Smith suggested that we leave single-argument APIs alone, which was agreed upon. However, the overall change got some push back as "change for change's sake".<br /> +<br /> +In order to support this, the <tt class="docutils literal">PyArg_ParseTuple</tt> function would need to do more work, and it's already known to be somewhat slow. Alternatively, <tt class="docutils literal">PyArg_Parse</tt> is much faster, and the tuple version could take a thing or two from it regardless of any wide scale change to builtins.<br /> +<br /> +There does exist some potential break in compatibility when replacing a builtin function with a Python one, where positional-only arguments suddenly get a potentially conflicting name.<br /> +<br /> +It was widely agreed upon that we should avoid any blanket rules and keep changes to places where it makes sense rather than make wholesale changes. We also need to be mindful of documentation and doc strings being kept to match the actual keyword argument names as well as keep them in sync.<br /> +<br /> +OrderedDict was suggested as the container for keyword arguments, but Guido and Gregory were unsure of use-cases for that. Whether or not we use a traditional or ordered dictionary, it was suggested that we could possibly use a decorator to handle some of this. We could even go as far as exposing something like <tt class="docutils literal">PyArg_ParseTuple</tt> as a Python-level function.<br /> +<br /> +PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0362/">362</a>, a proposal for a function signature object, would help here and with decorators in general. It seems that all that's left with that PEP is another look and someone to declare on it.</div> +<br /> +<div class="section" id="porting-to-python-3"> +<h4> +Porting to Python 3</h4> +We moved on to talk about Python 3 porting, starting with the current strategies and how they're working out. Single-codebase porting is working better than expected for most of us, although <tt class="docutils literal">except</tt> handling is a bit messy when supporting versions like 2.4. Having a lot of options, from 3to2 to 2to3, then the single codebase through parallel trees, is a really good thing. However, it's hard for us to choose a strategy for projects, so we don't, which is why most documentation tries to lay numerous strategies out there.<br /> +<br /> +It was suggested that documentation could stand to gain more examples of real-world porting examples, ideally pointing to changesets of these projects. The thought of our porting documentation gaining a cookbook-style approach seemed to get some agreement as a good idea.</div> +<br /> +<div class="section" id="hash-randomization"> +<h4> +Hash Randomization</h4> +Release candidates are available to all branches receiving security fixes, and in the meantime, David Malcolm found and reported a security issue in the upstream <tt class="docutils literal">expat</tt> project. However, since the upstream fix includes many other fixes at the same time, we should pick up only the security fix at this time and leave the bug fixes for the next bug fix release of the relevant branches.</div> +<br /> +<div class="section" id="new-dict-implementation"> +<h4> +New <tt class="docutils literal">dict</tt> Implementation</h4> +Since the implementation makes sense and the tests pass, it was quickly agreed upon that Mark Shannon's PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-0412/">412</a> should be accepted. As with other changes agreed upon in this summit, we'd like for the change to be pushed soon in order to get mileage on it throughout the alpha and beta cycles. With this acceptance comes commit access for Mark so that he can maintain the code.<br /> +<br /> +It was also remarked that the only user-visible difference that this implementation brings is a difference in sort ordering, but the recent hash randomization work makes this a moot point.<br /></div> +<br /> +<div class="section" id="new-pickle-protocol"> +<h4> +New <tt class="docutils literal">pickle</tt> Protocol</h4> +PEP <a class="reference external" href="http://www.python.org/dev/peps/pep-3154/">3154</a>, mentioned by Lukasz Langa, specifies a new pickle protocol -- version 4. Lukasz mentioned exception pickling in <tt class="docutils literal">multiprocessing</tt> as being an issue, and Antoine solved it with this PEP. While qualified names provide some help, it was agreed upon that this PEP needs more attention.<br /> +<hr class="docutils" /> +<br /> +If you have any questions or comments, please post to <a class="reference external" href="http://mail.python.org/mailman/listinfo/python-dev">python-dev</a>.<br /> +<br /> +<em>Thanks to Eric Snow and Senthil Kumaran for contributing to this post.</em></div> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ZLaHCD80z5E:ySbBd-izDGM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ZLaHCD80z5E:ySbBd-izDGM:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ZLaHCD80z5E:ySbBd-izDGM:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ZLaHCD80z5E:ySbBd-izDGM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ZLaHCD80z5E:ySbBd-izDGM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ZLaHCD80z5E:ySbBd-izDGM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=ZLaHCD80z5E:ySbBd-izDGM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=ZLaHCD80z5E:ySbBd-izDGM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/ZLaHCD80z5E" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2012/03/2012-language-summit-report.htmltag:blogger.com,1999:blog-3941553907430899163.post-59360939132650670282011-08-24T09:53:00.001-04:002011-08-24T09:53:33.817-04:002011-08-24T09:53:33.817-04:00Meet the Team: Brett Cannon<div class="document" id="meet-the-team-brett-cannon"> +<p><em>This post is part of the &quot;Meet the Team&quot; series of posts, which is meant to give a brief introduction to the Python core development team.</em></p> +<table class="docutils field-list" frame="void" rules="none"><col class="field-name"></col><col class="field-body"></col><tbody valign="top"><tr class="field"><th class="field-name">Name:</th><td class="field-body">Brett Cannon</td></tr><tr class="field"><th class="field-name">Location:</th><td class="field-body">San Francisco, CA, USA</td></tr><tr class="field"><th class="field-name">Home Page:</th><td class="field-body"><a class="reference external" href="https://profiles.google.com/bcannon">https://profiles.google.com/bcannon</a></td></tr><tr class="field"><th class="field-name">Blog:</th><td class="field-body"><a class="reference external" href="http://sayspy.blogspot.com">http://sayspy.blogspot.com</a></td></tr></tbody></table> +<p><strong>How long have you been using Python?</strong></p> +<p>Since the fall of 2000</p> +<p><strong>How long have you been a core committer?</strong></p> +<p>Since April 2003 (shortly after PyCon 2003).</p> +<p><strong>How did you get started as a core developer? Do you remember your first commit?</strong></p> +<p>I became a core developer thanks to incessantly bugging people to commit patches for me (a trick that doesn't quite work as well as it used to; perk of getting in before Python's popularity spikein 2003/2004). Starting in August 2002 I revitalized the Python-Dev Summaries (which lasted for about 2.5 years). While writing the Summaries I would fairly regularly pick up on little issues that needed fixing. Since I was already talking on python-dev fairly regularly I simply asked folks to check my patches and commit them for me. One day Guido just asked why I didn't commit myself, I said I didn't have commit rights, and then he more or less said &quot;you do now&quot;.</p> +<p>As for my first commit (changeset 28686), it was fixing some string escapement in time.strptime() (which happens to be my first contribution to Python itself).</p> +<p><strong>Which parts of Python are you working on now?</strong></p> +<p>I typically focus on the import machinery and making the Python language work well across all VMs.</p> +<p><strong>What do you do with Python when you aren't doing core development work?</strong></p> +<p>I managed to use Python a little bit in my PhD thesis by implementing some server-side stuff in Python. Otherwise all of my personal projects use Python as much as possible. And my future job at Google is going to be mostly in Python.</p> +<p><strong>What do you do when you aren't programming?</strong></p> +<p>I'm somewhat of a movie junkie with selective bits of TV tossed in (losing my television in the summer of 2000 to a heat wave was one of the best things that ever accidentally happened to me; marrying my wife has been the best thing I did on purpose =). Otherwise I read a lot; mostly magazines and websites, but with some book always under progress.</p> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TfQ5Aqj0liU:SIyoG2wHDSA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TfQ5Aqj0liU:SIyoG2wHDSA:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TfQ5Aqj0liU:SIyoG2wHDSA:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TfQ5Aqj0liU:SIyoG2wHDSA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TfQ5Aqj0liU:SIyoG2wHDSA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TfQ5Aqj0liU:SIyoG2wHDSA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=TfQ5Aqj0liU:SIyoG2wHDSA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=TfQ5Aqj0liU:SIyoG2wHDSA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/TfQ5Aqj0liU" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/08/meet-team-brett-cannon.htmltag:blogger.com,1999:blog-3941553907430899163.post-31132325031242113212011-08-08T09:09:00.000-04:002011-08-08T09:21:37.739-04:002011-08-08T09:21:37.739-04:00Meet the Team: Michael Foord<div class="document" id="meet-the-team-michael-foord"> +<p><em>This post is part of the &quot;Meet the Team&quot; series of posts, which is meant to give a brief introduction to the Python core development team.</em></p> +<table class="docutils field-list" frame="void" rules="none"><col class="field-name"></col><col class="field-body"></col><tbody valign="top"><tr class="field"><th class="field-name">Name:</th><td class="field-body">Michael Foord</td></tr><tr class="field"><th class="field-name">Location:</th><td class="field-body">Northampton UK</td></tr><tr class="field"><th class="field-name">Home Page:</th><td class="field-body"><a class="reference external" href="http://www.voidspace.org.uk/">http://www.voidspace.org.uk/</a></td></tr></tbody></table> +<p><strong>How long have you been using Python?</strong></p> +<p>I first started using Python as a hobby in 2002. I started using Python full time for work in 2006. When I started programming with Python it was with a group of guys who wanted to write a program to aggregate information from a Play By Email game. None of us had done any programming for a while and we had just decided on using Smalltalk when someone suggested we try Python. I quickly fell in love with Python.</p> +<p><strong>How long have you been a core committer?</strong></p> +<p>I became a core-committer at PyCon in 2009. It was originally because of my involvement with IronPython.</p> +<p><strong>How did you get started as a core developer? Do you remember your first commit?</strong></p> +<p>During the PyCon 2009 sprints I worked with Gregory Smith, another core developer, to incorporate some improvements to unittest contributed by Google.</p> +<p><strong>Which parts of Python are you working on now?</strong></p> +<p>After the initial work on unittest at the PyCon sprint I took on fixing other issues and making improvements to unittest, which was without a maintainer. I became the maintainer of unittest but also contribute to other parts of the standard library.</p> +<p>I'm involved in supporting Python in various other minor ways, such as looking after Planet Python, being a PSF member, helping out on the python.org webmaster alias and so on.</p> +<p><strong>What do you do with Python when you aren't doing core development work?</strong></p> +<p>For my day job I do web development for Canonical. I work on some of the web services infrastructure around the Canonical websites and also some of the services that integrate with Ubuntu itself. That's good fun and its a great team.</p> +<p>In my spare time I work on projects like <a class="reference external" href="http://pypi.python.org/pypi/unittest2">unittest2</a> (a backport of the improvements of unittest for other platforms), <a class="reference external" href="http://pypi.python.org/pypi/mock">mock</a> (a testing library that provides mock objects and support for monkey patching in tests) and a whole bunch of other smaller stuff.</p> +<p>I'd like to write more, but having devoted the best part of two years to writing IronPython in Action I doubt I'll take on any large writing projects soon.</p> +<p><strong>What do you do when you aren't programming?</strong></p> +<p>I'm very involved in a church in Northampton (UK), which takes a lot of my time and I help with administration for a charity we run. This is one reason why working for Canonical is good - I can work from home and having put my roots down here I won't move anywhere else (I certainly don't stay for the weather). Needless to say there isn't much Python programming happening in Northampton. My first full time programming gig was with an amazing team in London, which was a two hour door to door commute each way. I managed four years of that, and really enjoyed the job, but having escaped the commute I'm not likely to ever go back.</p> +<p>I also enjoy gaming on the XBox. Unfortunately if I find a game I like I can get sucked into it for weeks so I have to be careful. I've avoided world of warcraft and eve online for this reason... I also organise a monthly geek meet in Northampton. There aren't enough Python programmers for a Python user group but we have a good collection of geeks of all sorts. We normally just get together in a pub and chew the fat or show off our latest gadgets.</p> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=szWrurZ-wqo:4pbNUjG7kzo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=szWrurZ-wqo:4pbNUjG7kzo:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=szWrurZ-wqo:4pbNUjG7kzo:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=szWrurZ-wqo:4pbNUjG7kzo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=szWrurZ-wqo:4pbNUjG7kzo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=szWrurZ-wqo:4pbNUjG7kzo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=szWrurZ-wqo:4pbNUjG7kzo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=szWrurZ-wqo:4pbNUjG7kzo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/szWrurZ-wqo" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/08/meet-team-michael-foord.htmltag:blogger.com,1999:blog-3941553907430899163.post-28161494873014049382011-07-11T13:11:00.000-04:002011-07-11T13:11:07.551-04:002011-07-11T13:11:07.551-04:00A Python Launcher For Windows<div class="document" id="a-python-launcher-for-windows"> <p>Mark Hammond (author of <a class="reference external" href="http://sourceforge.net/projects/pywin32/">pywin32</a> and long-time supporter of Python on Windows) has written <a class="reference external" href="http://www.python.org/dev/peps/pep-0397/">PEP 397</a>, which describes a new launcher for Python on Windows. Vinay Sanjip (author of the standard library <a class="reference external" href="http://docs.python.org/py3k/library/logging.html">logging</a> module) has recently created an implementation of the launcher, downloadable from <a class="reference external" href="https://bitbucket.org/vinay.sajip/pylauncher/downloads">https://bitbucket.org/vinay.sajip/pylauncher/downloads</a></p><p>The launcher allows Python scripts (<tt class="docutils literal">.py</tt> and <tt class="docutils literal">.pyw</tt> files) on Windows to specify the version of Python which should be used, allowing simultaneous use of Python 2 and 3.</p><p>Windows users should consider downloading the launcher and testing it, to help the Python developers iron out any remaining issues. The launcher is packaged as a standalone application, and will support currently available versions of Python. The intention is that once the launcher is finalised, it will be included as part of Python 3.3 (although it will remain available as a standalone download for users of earlier versions).</p><p>Two versions of the launcher are available - <tt class="docutils literal">launcher.msi</tt> which installs in the <tt class="docutils literal">Program Files</tt> directory, and <tt class="docutils literal">launchsys.msi</tt> which installs in Windows' <tt class="docutils literal">System32</tt> directory. (There are also 64-bit versions for 64-bit versions of Windows).</p><div class="section" id="some-details-about-the-launcher"><h4>Some Details About the Launcher</h4><p>The full specification of the behaviour of the launcher is given in <a class="reference external" href="http://www.python.org/dev/peps/pep-0397/">PEP 397</a>. To summarise the basic principles:</p><ul class="simple"><li>The launcher supplies two executables - <tt class="docutils literal">py.exe</tt> (the console version) and <tt class="docutils literal">pyw.exe</tt> (the GUI version).</li> +<li>The launcher is registered as the handler for <tt class="docutils literal">.py</tt> (console) and <tt class="docutils literal">.pyw</tt> (GUI) file extensions.</li> +<li>When executing a script, the launcher looks for a Unix-style <tt class="docutils literal">#!</tt> (shebang) line in the script. It recognises executable names <tt class="docutils literal">python</tt> (system default python), <tt class="docutils literal">python2</tt> (default Python 2 release) and <tt class="docutils literal">python3</tt> (default Python 3 release). The precise details can easily be customised on a per-user or per-machine basis.</li> +<li>When used standalone, the <tt class="docutils literal">py.exe</tt> command launches the Python interactive interpreter. Command line switches are supported, so that <tt class="docutils literal">py <span class="pre">-2</span></tt> launches Python 2, <tt class="docutils literal">py <span class="pre">-3</span></tt> launches Python 3, and <tt class="docutils literal">py</tt> launches the default version.</li> +</ul></div><div class="section" id="simple-usage-instructions"><h4>Simple Usage Instructions</h4><p>When it is installed, the launcher associates itself with <tt class="docutils literal">.py</tt> and <tt class="docutils literal">.pyw</tt> scripts. Unless you do anything else, scripts will be run using the default Python on the machine, so you will see no change. One thing you might like to do, if you use the console a lot, is to add <tt class="docutils literal">.py</tt> to your <tt class="docutils literal">PATHEXT</tt> variable so that scripts don't get executed in a separate console.</p><p>To specify that a script must use Python 2, simply add:</p><pre class="literal-block">#!/usr/bin/env python2 +</pre><p>as the first line of the script. (This is a Unix-compatible form. If you don't need Unix compatibility, <tt class="docutils literal">#!python2</tt> will do).</p><p>If on the other hand, you want to specify that a script must use Python 3, add:</p><pre class="literal-block">#!/usr/bin/env python3 +</pre><p>as the first line.</p><p>You can also start the Python interpreter using any of the following commands:</p><pre class="literal-block"># Default version of Python +py +# Python 2 +py -2 +# Python 3 +py -3 +</pre><p>For this to work, the <tt class="docutils literal">py.exe</tt> executable must be on your path. This is automatic with the <tt class="docutils literal">launchsys</tt> version of the installer, but the install directory (<tt class="docutils literal"><span class="pre">C:\Program</span> Files\Python Launcher</tt>) must be added manually to <tt class="docutils literal">PATH</tt> with <tt class="docutils literal">launcher.msi</tt>.</p></div><div class="section" id="further-reading"><h4>Further Reading</h4><p>The following email threads on python-dev cover some of the key discussions:</p><ul class="simple"><li>Mark's initial announcement of the draft PEP: <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-March/109509.html">http://mail.python.org/pipermail/python-dev/2011-March/109509.html</a></li> +<li>The second draft of the PEP: <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-March/109786.html">http://mail.python.org/pipermail/python-dev/2011-March/109786.html</a></li> +<li>Vinay's initial query about a C implementation of the launcher: <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-June/112145.html">http://mail.python.org/pipermail/python-dev/2011-June/112145.html</a></li> +<li>Vinay's announcement of his C implementation: <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-July/112184.html">http://mail.python.org/pipermail/python-dev/2011-July/112184.html</a></li> +<li>Vinay's call for testers: <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-July/112251.html">http://mail.python.org/pipermail/python-dev/2011-July/112251.html</a></li> +</ul></div></div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=1JqABSwTN5U:LfTvU-8RBmk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=1JqABSwTN5U:LfTvU-8RBmk:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=1JqABSwTN5U:LfTvU-8RBmk:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=1JqABSwTN5U:LfTvU-8RBmk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=1JqABSwTN5U:LfTvU-8RBmk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=1JqABSwTN5U:LfTvU-8RBmk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=1JqABSwTN5U:LfTvU-8RBmk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=1JqABSwTN5U:LfTvU-8RBmk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/1JqABSwTN5U" height="1" width="1"/>Paul Moorehttp://www.blogger.com/profile/17557923197983461835noreply@blogger.comhttp://blog.python.org/2011/07/python-launcher-for-windows_11.htmltag:blogger.com,1999:blog-3941553907430899163.post-87542017192875531832011-07-11T10:20:00.000-04:002011-07-11T10:21:31.074-04:002011-07-11T10:21:31.074-04:00CPython 3.2.1 Released<div class="document" id="cpython-3-2-1-released"> +<p>On behalf of the python-dev team, release manager <a class="reference external" href="http://pythonic.pocoo.org/">Georg Brandl</a> has announced the final release of <a class="reference external" href="http://www.python.org/download/releases/3.2.1/">CPython 3.2.1</a>. Windows installers and tarballs are available as of July 10, so please consider upgrading to this release.</p> +<p>The <a class="reference external" href="http://docs.python.org/3.2/whatsnew/3.2.html">What's New</a> document lists all of the new features in 3.2, and the <a class="reference external" href="http://hg.python.org/cpython/file/v3.2.1/Misc/NEWS">Misc/NEWS</a> file in the source lists each bug fixed.</p> +<p>If you find any issues with this release or any other, please report them to <a class="reference external" href="http://bugs.python.org/">http://bugs.python.org/</a>.</p> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tsieHw51jhc:G_3vQohz6Mo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tsieHw51jhc:G_3vQohz6Mo:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tsieHw51jhc:G_3vQohz6Mo:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tsieHw51jhc:G_3vQohz6Mo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tsieHw51jhc:G_3vQohz6Mo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tsieHw51jhc:G_3vQohz6Mo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=tsieHw51jhc:G_3vQohz6Mo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=tsieHw51jhc:G_3vQohz6Mo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/tsieHw51jhc" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/07/cpython-321-released.htmltag:blogger.com,1999:blog-3941553907430899163.post-5346886995889209832011-07-06T11:31:00.000-04:002011-07-06T11:35:31.744-04:002011-07-06T11:35:31.744-04:003.2.1 Release Candidate 2 Released<div class="document" id="release-candidate-2-released"> +<p>Following up a big month of <a class="reference external" href="http://blog.python.org/2011/06/june-releases-267-272-314.html">releases in June</a>, the second release candidate of the 3.2.1 line <a class="reference external" href="http://www.python.org/download/releases/3.2.1/">is now ready</a>. Since the first release candidate on May 15, over 40 issues have been fixed. We encourage everyone to test their projects with this candidate to get one last look before the final release of 3.2.1.</p> +<div class="section" id="what-s-fixed"><h4>What's fixed?</h4> +<div class="section" id="i-o"><h5>I/O</h5> +<p><a class="reference external" href="http://bugs.python.org/issue1195">#1195</a> spent a few years witout a fix, but a simple addition to clear errors before calling <tt class="docutils literal">fgets</tt> solves the problem of interrupting <tt class="docutils literal">sys.stdin.read()</tt> with CTRL-D inside of <tt class="docutils literal">input()</tt>. The <tt class="docutils literal">io</tt> system saw a cleanup in <a class="reference external" href="http://bugs.python.org/issue12175">#12175</a> with the <tt class="docutils literal">readall</tt> method with <tt class="docutils literal">None</tt> being the return value on a <tt class="docutils literal">read()</tt> which returns <tt class="docutils literal">None</tt>, and a <tt class="docutils literal">ValueError</tt> is now raised when a file can't be opened.</p> +<p>Although this isn't new for RC2, <a class="reference external" href="http://bugs.python.org/issue11272">#11272</a> is an important 3.2.1 fix to <tt class="docutils literal">input()</tt> on Windows - the fixing of a trailing <tt class="docutils literal">\r</tt>. The issue has been reported many times over and affects a many people (distutils upload command anyone?), so hopefully 3.2.1 does the trick for you.</p> +</div> +<div class="section" id="windows"><h5>Windows</h5> +<p>3.2.0 brought a new feature for Windows: <tt class="docutils literal">os.symlink</tt> support. With that feature came <a class="reference external" href="http://bugs.python.org/issue12084">#12084</a>, <tt class="docutils literal">os.stat</tt> was improperly evaluating Windows symlinks, so the inner workings of the various <tt class="docutils literal">stat</tt> functions were corrected.</p> +<p>A user noticed that <tt class="docutils literal">os.path.isdir</tt> was slow, and the fact that it relied on <tt class="docutils literal">os.stat</tt> contributed to that, especially when evaluating symlinks (which are generally twice as slow as regular files). While <tt class="docutils literal">os.path.isdir</tt> isn't anyone's performance bottleneck, it's called numerous times on interpreter startup so changing it in <a class="reference external" href="http://bugs.python.org/issue11583">#11583</a> to use <tt class="docutils literal">GetFileAttributes</tt> gives a tiny speedup to build on.</p> +</div> +<div class="section" id="subprocess"><h5>subprocess</h5> +<p>Creating a <tt class="docutils literal">Popen</tt> object with unexpected arguments was causing an <tt class="docutils literal">AttributeError</tt>, but that was reported in <a class="reference external" href="http://bugs.python.org/issue12085">#12085</a> and was fixed by the reporter. Due to a change in 3.2.0, <tt class="docutils literal">Popen</tt> wasn't correctly handling empty environment variables, specifically the <tt class="docutils literal">env</tt> argument. <a class="reference external" href="http://bugs.python.org/issue12383">#12383</a> was created for the issue and was promptly fixed.</p> +</div> +<div class="section" id="and-more"><h5>...and more!</h5> +<p>For a full list of changes through 3.2.1 RC2, check out <a class="reference external" href="http://hg.python.org/releasing/3.2.1/file/v3.2.1rc2/Misc/NEWS">the change log</a> and <a class="reference external" href="http://www.python.org/download/releases/3.2.1/">download it now</a>!</p> +<p>As always, please report any issues you find to <a class="reference external" href="http://bugs.python.org">http://bugs.python.org</a>. We appreciate your help in making great Python releases.</p> +</div> +</div> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qJVUVTi0FtY:PUk3o78ZLFA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qJVUVTi0FtY:PUk3o78ZLFA:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qJVUVTi0FtY:PUk3o78ZLFA:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qJVUVTi0FtY:PUk3o78ZLFA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qJVUVTi0FtY:PUk3o78ZLFA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qJVUVTi0FtY:PUk3o78ZLFA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qJVUVTi0FtY:PUk3o78ZLFA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qJVUVTi0FtY:PUk3o78ZLFA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/qJVUVTi0FtY" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/07/321-release-candidate-2-released.htmltag:blogger.com,1999:blog-3941553907430899163.post-33308038161260090022011-06-14T09:08:00.001-04:002011-06-14T09:09:54.410-04:002011-06-14T09:09:54.410-04:00June Releases - 2.6.7, 2.7.2, 3.1.4<div class="document" id="june-2011-releases"> +<p>June is a big month for Python releases, with an update coming out of all active branches.</p> +<div class="section" id="id1"> +<h4>2.6.7</h4> +<p>A new source-only release of Python <a class="reference external" href="http://www.python.org/download/releases/2.6.7/">2.6.7</a> is available, providing fixes to three security issues. Now that the 2.6 line is in security-mode, these releases will happen on an as-needed basis until October 2013 in source-only form. If you require binary installers, you should consider an upgrade to 2.7 or 3.2.</p> +<p>2.6.7 is the first release to contain a fix to the previously covered <a class="reference external" href="http://blog.python.org/2011/04/urllib-security-vulnerability-fixed.html">urllib vulnerability</a>. Additionally, an <tt class="docutils literal">smtpd</tt> DoS vulnerability (Issue <a class="reference external" href="http://bugs.python.org/issue9129">#9129</a>) and <tt class="docutils literal">SimpleHTTPServer.list_directory</tt> XSS vulnerability (Issue <a class="reference external" href="http://bugs.python.org/issue11442">#11442</a>) are fixed.</p> +</div> +<div class="section" id="id2"> +<h4>2.7.2</h4> +<p>The last minor version of the 2.x line, 2.7, received over 150 bug fixes since 2.7.1 in November 2010. <a class="reference external" href="http://www.python.org/download/releases/2.7.2/">2.7.2</a> source and binary installers are available as of June 12, which include the security fixes mentioned in 2.6.7.</p> +<p>A number of crashes are fixed: a situation when Python incorrectly used non-Python managed memory while it was being modified by another thread, when deleting <tt class="docutils literal">__abstractmethods__</tt> from a class, accessing a memory-mapped file past its length, and several others.</p> +<p>A fix to <tt class="docutils literal">getpass</tt> corrects a regression in regards to CTRL-C and CTRL-Z handling. <tt class="docutils literal">multiprocessing</tt> received a number of fixes, including treating Windows services like frozen executables and a correction to a race condition when terminating <tt class="docutils literal">multiprocessing.Pool</tt> workers. <tt class="docutils literal">mmap</tt> was fixed to work with file sizes and offsets larger than 4 GB even on 32-bit builds, and a <tt class="docutils literal">TypeError</tt> is now raised rather than segfaulting when trying to write to a non-writeable map.</p> +<p>For a full list of changes, see <a class="reference external" href="http://hg.python.org/cpython/raw-file/eb3c9b74884c/Misc/NEWS">the 2.7.2 news file</a>.</p> +</div> +<div class="section" id="id3"> +<h4>3.1.4</h4> +<p>3.1.4 is the last bug-fix release of the 3.1.x line, sending 3.1 into security-mode as the 3.2 line carries on. 3.1.4 contains over 100 bug fixes since the 3.1.3 release in November 2010. As with 2.7.2, binary installers are available as of June 12, and 3.1.4 is the first 3.x release to contain the security fixes listed in 2.6.7.</p> +<p>3.1.4 corrects some problems with <tt class="docutils literal">__dir__</tt> lookups on objects, dates past 2038 in the Windows implementation of <tt class="docutils literal">os.stat</tt> and <tt class="docutils literal">os.utime</tt>, and a number of 64-bit cleanups. The <tt class="docutils literal">io</tt> library saw a number of changes in returning <tt class="docutils literal">None</tt> when nothing was read and raising appropriate exceptions in other spots. <tt class="docutils literal">ctypes</tt> callback arguments were fixed on 64-bit Windows and a crash was also remedied.</p> +<p>For a full list of changes, see <a class="reference external" href="http://hg.python.org/cpython/raw-file/feae9f9e9f30/Misc/NEWS">the 3.1.4 news file</a>.</p></div> +<div class="section" id="id4"> +<h4>3.2.1</h4> +<p><a class="reference external" href="http://www.python.org/download/releases/3.2.1/">3.2.1</a> is currently in the release candidate phase, with one round already completed and a second release candidate expected soon. We would greatly appreciate 3.2 users trying out the release candidates to ensure we cover any issues you may be seeing. If you have any bugs to report, please file them on <a class="reference external" href="http://bugs.python.org">bugs.python.org</a>.</p> +</div> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=Y0OHiMAU4rA:8amqCEIJod4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=Y0OHiMAU4rA:8amqCEIJod4:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=Y0OHiMAU4rA:8amqCEIJod4:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=Y0OHiMAU4rA:8amqCEIJod4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=Y0OHiMAU4rA:8amqCEIJod4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=Y0OHiMAU4rA:8amqCEIJod4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=Y0OHiMAU4rA:8amqCEIJod4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=Y0OHiMAU4rA:8amqCEIJod4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/Y0OHiMAU4rA" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/06/june-releases-267-272-314.htmltag:blogger.com,1999:blog-3941553907430899163.post-15716525742476766862011-05-26T18:44:00.009-04:002011-05-26T18:59:16.298-04:002011-05-26T18:59:16.298-04:00New faulthandler module in Python 3.3 helps debugging<div class="document" id="new-faulthandler-module-in-python-3-3-helps-debugging"><p>When a user reports that your program crashes or hangs, sometimes you can only help to try and collect more information and outline a scenario to reproduce the situation. Even with a reliable user scenario, as a developer you are often unable to reproduce the situation due to environment differences, e.g., operating system and compiler. If you are lucky, the user will be able to install debug tools, but most of time you will have to wait until another person is able to obtain more information from the same situation.</p><div class="section" id="fatal-errors"><h4>Fatal Errors</h4><p>A new module introduced in Python 3.3 should help this problem: <a class="reference external" href="http://docs.python.org/dev/library/faulthandler.html">faulthandler</a>. <tt class="docutils literal">faulthandler</tt> provides the ability to dump the Python traceback on a fatal error such as a segmentation fault, division by zero, abort, or bus error. You can enable it inside your application using <tt class="docutils literal">faulthandler.enable()</tt>, by providing the <tt class="docutils literal"><span class="pre">-X</span> faulthandler</tt> option to the Python executable, or with the <a class="reference external" href="http://docs.python.org/dev/using/cmdline.html#envvar-PYTHONFAULTHANDLER">PYTHONFAULTHANDLER=1</a> environment variable. Output example:</p><pre class="literal-block">Fatal Python error: Segmentation fault + +Current thread 0x00007f7babc6b700: + File "Lib/test/crashers/gc_inspection.py", line 29 in g + File "Lib/test/crashers/gc_inspection.py", line 32 in &lt;module&gt; +Segmentation fault</pre></div><div class="section" id="timeout"><h4>Timeout</h4><p><tt class="docutils literal">faulthandler</tt> can also dump the traceback after a timeout using <tt class="docutils literal">faulthandler.dump_tracebacks_later(timeout)</tt>. Call it again to restart the timer or call <tt class="docutils literal">faulthandler.cancel_dump_tracebacks_later()</tt> to stop the timer. Output example:</p><pre class="literal-block">Timeout (0:01:00)! +Current thread 0x00007f987d459700: + File "Lib/test/crashers/infinite_loop_re.py", line 20 in &lt;module&gt; +</pre><p>Use the <tt class="docutils literal">repeat=True</tt> option to dump the traceback each <tt class="docutils literal">timeout</tt> seconds, or <tt class="docutils literal">exit=True</tt> to immediatly exit the program in an unsafe fashion, e.g. don't flush files.</p></div><div class="section" id="user-signal"><h4>User Signal</h4><p>If you have access to the host on which the program is running, you can use <tt class="docutils literal">faulthandler.register(signal)</tt> to install a signal handler to dump the traceback when <tt class="docutils literal">signal</tt> is received. On UNIX, for example, you can use the <tt class="docutils literal">SIGUSR1 </tt>signal: <tt class="docutils literal">kill <span class="pre">-USR1</span> &lt;pid&gt;</tt> will dump the current traceback. This feature is not available on Windows. Output example:</p><pre class="literal-block">Current thread 0x00007fdc3da74700: + File "Lib/test/crashers/infinite_loop_re.py", line 19 in &lt;module&gt; +</pre><p>Another possibility is to explicitly call <tt class="docutils literal">faulthandler.dump_traceback()</tt> in your program.</p></div><div class="section" id="security-issues-and-the-output-file"><h4>Security Issues and the Output File</h4><p><tt class="docutils literal">faulthandler</tt> is disabled by default for security reasons, mainly because it stores the file descriptor of <tt class="docutils literal">sys.stderr</tt> and writes the tracebacks into this file descriptor. If <tt class="docutils literal">sys.stderr</tt> is closed and the file descriptor is reused, the file descriptor may be a socket, a pipe, a critical file or something else. By default, <tt class="docutils literal">faulthandler</tt> writes the tracebacks to <tt class="docutils literal">sys.stderr</tt>, but you can specify another file. For more information, see the <a class="reference external" href="http://docs.python.org/dev/library/faulthandler.html#file-descriptor-issue">faulthandler documentation</a>.</p></div><div class="section" id="third-party-module-for-older-python-versions"><h4>Third-party Module for Older Python Versions</h4><p><tt class="docutils literal">faulthandler</tt> is also maintained as a third-party module for Python 2.5 through 3.2 <cite style="font-style: normal;"><a href="http://pypi.python.org/pypi/faulthandler/">on PyPI</a></cite>. The major difference between the Python 3.3 module and the third-party module is the implementation of <tt class="docutils literal">dump_tracebacks_later()</tt>: Python 3.3 uses a thread with a timeout on a lock, whereas the third party uses <tt class="docutils literal">SIGALRM</tt> and <tt class="docutils literal">alarm()</tt>.</p><p>The lock timeout, which is a new feature of Python 3.3, has a microsecond resolution. The <tt class="docutils literal">alarm()</tt> timer used on older versions has a resolution of one second, and the <tt class="docutils literal">SIGALRM</tt> signal may interrupt the current system call which will fail with an <tt class="docutils literal">EINTR</tt> error.</p></div><div class="section" id="early-success"><h4>Early Success</h4><p>The new <tt class="docutils literal">faulthandler</tt> module has already helped with tracking down race conditions in <a href="http://www.python.org/dev/buildbot/">our buildbots</a>. We hope that it will also help you in your programs.</p></div></div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qqYRL00AmXY:vzhC57CLoWc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qqYRL00AmXY:vzhC57CLoWc:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qqYRL00AmXY:vzhC57CLoWc:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qqYRL00AmXY:vzhC57CLoWc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qqYRL00AmXY:vzhC57CLoWc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qqYRL00AmXY:vzhC57CLoWc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qqYRL00AmXY:vzhC57CLoWc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qqYRL00AmXY:vzhC57CLoWc:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/qqYRL00AmXY" height="1" width="1"/>haypohttp://www.blogger.com/profile/14658404449913582628noreply@blogger.comhttp://blog.python.org/2011/05/new-faulthandler-module-in-python-33.htmltag:blogger.com,1999:blog-3941553907430899163.post-80130733679677389692011-05-23T10:00:00.005-04:002011-05-23T10:00:11.685-04:002011-05-23T10:00:11.685-04:00The Python Core Mentorship Program<div class="document" id="the-python-core-mentorship-program"> + +<p><a class="reference external" href="http://jessenoller.com/">Jesse Noller</a> recently <a class="reference external" href="http://jessenoller.com/2011/04/05/python-core-mentorship-up-and-running/"> announced</a> the formation of the <em>Python Core Mentorship</em> program. The idea behind the program is to help programmers, including students and developers from other projects, connect with experienced contributors who serve as mentors to ease them into Python Core development.</p> +<div class="section" id="contributors-wanted"> +<h4>Contributors Wanted</h4> +<p>The mentors will help people regardless of experience level by +bringing them up to speed, answering questions, and giving guidance as +needed in a non-confrontational and welcoming way. The contributors +will receive guidance through the entire contribution process, +including discussions on the related mailing lists, the bug tracker, +Mercurial, code reviews, and much more.</p> +</div> +<div class="section" id="early-success"> +<h4>Early Success</h4> +<p>The program already has been successful, and the participants have +actively committed a number of patches. There have also been several +constructive discussions on the mailing list, helping guide people in +the right direction for a variety of issues.</p> +</div> +<div class="section" id="code-of-conduct"> +<h4>Code of Conduct</h4> +<p>The program has a code of conduct explained on the <a class="reference external" href="http://pythonmentors.com/">website</a> that aims to assuage concerns many new contributors have when interacting with experienced developers and mailing lists on contribution in general. Jesse and the other mentors hope that this program can act as a model for other projects long-term, not just benefiting Python-Core. They also want the program to help increase the overall diversity of the contributors to Python.</p> +</div> +<div class="section" id="signing-up"> +<h4>Signing Up</h4> +<p>The program is run via the <a class="reference external" href="http://mail.python.org/mailman/listinfo/core-mentorship">mailing list</a> and has a clear, concise <a class="reference external" href="http://pythonmentors.com/">website</a> devoted to it. If you would like to join to ask questions and begin on the path of core contribution, or even if you are an experienced developer (even experienced in Python-Core) looking to ask questions you're worried about asking on other lists, this is an excellent opportunity to jump in, ask and get your feet wet!</p> +</div> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=SgkfTGCVy1c:olf4Uqq8tXk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=SgkfTGCVy1c:olf4Uqq8tXk:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=SgkfTGCVy1c:olf4Uqq8tXk:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=SgkfTGCVy1c:olf4Uqq8tXk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=SgkfTGCVy1c:olf4Uqq8tXk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=SgkfTGCVy1c:olf4Uqq8tXk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=SgkfTGCVy1c:olf4Uqq8tXk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=SgkfTGCVy1c:olf4Uqq8tXk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/SgkfTGCVy1c" height="1" width="1"/>Mike Driscollhttp://www.blogger.com/profile/06351908417200979114noreply@blogger.comhttp://blog.python.org/2011/05/python-core-mentorship-program.htmltag:blogger.com,1999:blog-3941553907430899163.post-31262668843164743032011-05-19T08:45:00.000-04:002011-05-19T08:45:49.363-04:002011-05-19T08:45:49.363-04:00Portuguese, German, Korean, and Traditional Chinese Translations<div class="document" id="portuguese-german-korean-and-traditional-chinese-translations"> + +<p>The Python Insider <a class="reference external" href="http://blog.python.org/2011/05/python-insider-translation-project.html">translation project</a> is continuing to grow! Today + +we are launching <a class="reference external" href="http://blog-pt.python.org">Portuguese</a>, <a class="reference external" href="http://blog-de.python.org">German</a>, <a class="reference external" href="http://blog-ko.python.org">Korean</a>, and <a class="reference external" href="http://blog-tw.python.org">Traditional + +Chinese</a> versions of the blog. The translators have already started + +publishing the backlog of posts. As with the other translations, these + +parallel editions may lag slightly behind the original posts on + +<a class="reference external" href="http://blog.python.org/">Python Insider</a>.</p> + +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=h1jWkgV8r44:GpriJFbwgcg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=h1jWkgV8r44:GpriJFbwgcg:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=h1jWkgV8r44:GpriJFbwgcg:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=h1jWkgV8r44:GpriJFbwgcg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=h1jWkgV8r44:GpriJFbwgcg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=h1jWkgV8r44:GpriJFbwgcg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=h1jWkgV8r44:GpriJFbwgcg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=h1jWkgV8r44:GpriJFbwgcg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/h1jWkgV8r44" height="1" width="1"/>Michael Markerthttp://www.blogger.com/profile/08761481986934375758noreply@blogger.comhttp://blog.python.org/2011/05/portuguese-german-korean-and.htmltag:blogger.com,1999:blog-3941553907430899163.post-18981709542887702852011-05-09T07:00:00.001-04:002011-05-09T07:00:03.832-04:002011-05-09T07:00:03.832-04:00Romanian and Simplified Chinese Translations<div class="document" id="romanian-and-simplified-chinese-translations"> + +<p>The Python Insider team is very excited to announce two new blogs +today. Translators for <a class="reference external" href="http://blog-ro.python.org">Romanian</a> and <a class="reference external" href="http://blog-cn.python.org">Simplified Chinese</a> have +joined the <a class="reference external" href="http://blog.python.org/2011/05/python-insider-translation-project.html">Translation Project</a>, and have already started publishing +the backlog of posts. As with the other translations, these parallel +editions may lag slightly behind the original posts on <a class="reference external" href="http://blog.python.org/">Python +Insider</a>.</p> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=J4XrijXKrSo:oVHkbmUmvxo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=J4XrijXKrSo:oVHkbmUmvxo:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=J4XrijXKrSo:oVHkbmUmvxo:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=J4XrijXKrSo:oVHkbmUmvxo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=J4XrijXKrSo:oVHkbmUmvxo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=J4XrijXKrSo:oVHkbmUmvxo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=J4XrijXKrSo:oVHkbmUmvxo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=J4XrijXKrSo:oVHkbmUmvxo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/J4XrijXKrSo" height="1" width="1"/>Doug Hellmannhttp://www.blogger.com/profile/01892352754222143463noreply@blogger.comhttp://blog.python.org/2011/05/romanian-and-simplified-chinese.htmltag:blogger.com,1999:blog-3941553907430899163.post-42734756475607251932011-05-07T16:38:00.002-04:002011-05-07T16:38:55.599-04:002011-05-07T16:38:55.599-04:00Jython Migrates to Mercurial<div class="document" id="jython-migrates-to-mercurial"> + +<p>Jython has finally migrated from Subversion to Mercurial. This has been a long +time coming: unfortunately we had a difficult Subversion repo that took some +effort to cleanly convert to a different revision control system.</p> +<p>The new official Jython repo is now hosted @</p> +<p><a class="reference external" href="http://hg.python.org/jython">http://hg.python.org/jython</a></p> +<p>with a <a class="reference external" href="http://bitbucket.org/jython/jython">BitBucket Mirror</a> for easy forking.</p> +<p>There's also a larger read-only repo with ongoing feature branches (converted +to Mercurial Bookmarks) hosted at <a class="reference external" href="http://hg.python.org/jython-fullhistory">http://hg.python.org/jython-fullhistory</a></p> +<p>Mercurial makes it even easier to contribute to Jython, pull up a fork and come +help us build Jython 2.6!</p> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=cr67BEYMOCo:MitZ1cfMsl0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=cr67BEYMOCo:MitZ1cfMsl0:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=cr67BEYMOCo:MitZ1cfMsl0:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=cr67BEYMOCo:MitZ1cfMsl0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=cr67BEYMOCo:MitZ1cfMsl0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=cr67BEYMOCo:MitZ1cfMsl0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=cr67BEYMOCo:MitZ1cfMsl0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=cr67BEYMOCo:MitZ1cfMsl0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/cr67BEYMOCo" height="1" width="1"/>Philip Jenveyhttp://www.blogger.com/profile/17437958274873977298noreply@blogger.comhttp://blog.python.org/2011/05/jython-migrates-to-mercurial.htmltag:blogger.com,1999:blog-3941553907430899163.post-50984214452724273672011-05-04T09:55:00.001-04:002011-05-04T10:07:24.909-04:002011-05-04T10:07:24.909-04:00Python 3.3 to Drop Support for OS/2, Windows 2000, and VMS<div class="document" id="python-3-3-to-drop-support-for-os-2-windows-2000-and-vms"> +<p>Every so often there comes a time to prune the list of supported operating systems to match the usage landscape. On top of that, the pool of contributing developers on a platform also holds significance, as there needs to be someone around to complete development tasks in order to have a quality release. Other factors, such as the age of an operating system and its hinderance on future development work, also weigh on the list.</p> +<p><a class="reference external" href="http://www.haypocalc.com/wiki/Victor_Stinner">Victor Stinner</a> recently proposed <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-April/110872.html">dropping OS/2 and VMS support</a> for CPython, a year after his <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2010-April/099471.html">original question</a> on OS/2 support. Victor's original inquiry came around the time of his seemingly non-stop Unicode efforts, specifically for an issue with <a class="reference external" href="http://docs.python.org/library/os#os.execvpe">os.execvpe()</a> supporting environment variables via the <a class="reference external" href="http://www.python.org/dev/peps/pep-0383/">PEP 383</a> surrogateescape handler. OS/2 and VMS currently have no representation on the development team and receive no testing during the release process.</p> +<p>The process of writing this post <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2011-May/111159.html">got me thinking</a> about a <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2010-March/098074.html">previous discussion</a> about removing Windows 2000, which seemed to fall to the wayside. Systems setting <tt class="docutils literal">COMSPEC</tt> to <tt class="docutils literal">command.com</tt> were also supposed to be on the chopping block back then. <a class="reference external" href="http://hg.python.org/peps/rev/b9390aa12855">As of now</a>, both have joined OS/2 and VMS. Windows 2000 is up for removal in order to make development work easier, removing the need to account for legacy APIs on an operating system which hit end-of-life in 2010.</p> +<p>In order to begin removing support for those systems, Victor and I started by updating <a class="reference external" href="http://www.python.org/dev/peps/pep-0011/">PEP 11</a>.</p> +<div class="section" id="pep-11"> +<h4>PEP 11</h4> +<p>This PEP outlines the operating systems that are no longer supported and explains the process of adding a system to that list.</p> +<p>Once it is decided that an operating system can start the process of removal, it is formally announced as unsupported. This announcement traditionally goes for the in-development version, so dropping support of OS/2, Windows 2000, and VMS begins with Python 3.3.</p> +<p>The first stage is fairly hands off, more of a raising of the white flag. It's a signal that there's no one around to maintain the code and ensure a quality release. Changes to compilation and installation may be made to alert users on those platforms that the platform is unsupported. A note will go into the &quot;<a class="reference external" href="http://docs.python.org/dev/whatsnew/3.3.html#unsupported-operating-systems">What's New</a>&quot; document listing the newly unsupported platforms.</p> +<p>After a release cycle of being unsupported, the version afterwards becomes fair game for removal of code. In this case, code can be removed in 3.4. There probably won't be a wholesale removal of that code, but developers that come across it in their normal work may remove any <tt class="docutils literal">#ifdef</tt> blocks, <tt class="docutils literal">configure</tt> sections, or out-of-date code.</p> +</div> +<div class="section" id="what-you-can-do"> +<h4>What You Can Do</h4> +<p>If you are a user of OS/2 or VMS, there are a few things you can do to save your platform.</p> +<div class="section" id="become-a-maintainer"> +<h5>Become a Maintainer</h5> +<p>Nothing says support better than an active developer. Andrew MacIntyre has been the OS/2 maintainer for some time now, and he stated during Victor's first OS/2 query that OS/2 is behind on Unicode support, so that's certainly an area that needs focus. VMS appears to have some amount of external support via <a class="reference external" href="http://www.vmspython.org">http://www.vmspython.org</a>, but as discussed in <a class="reference external" href="http://bugs.python.org/issue11918">issue 11918</a>, someone needs to step up to allow the continued VMS support upstream.</p> +<p>If you are interested in taking over for either platform, see the <a class="reference external" href="http://docs.python.org/devguide">developer's guide</a> for the current development proccesses.</p> +</div> +<div class="section" id="contribute-a-build-slave"> +<h5>Contribute a build slave</h5> +<p>With an active developer, a platform stands a better chance of survival. With a build slave, a platform stands an even better chance, not only at survival but also at quality.</p> +<p>Python uses <a class="reference external" href="http://trac.buildbot.net/">Buildbot</a> for continuous integration, and build slaves are <a class="reference external" href="http://www.python.org/dev/buildbot/">currently provided</a> for Linux, Mac, Windows, and Open Indiana (Solaris), for various versions, architectures, and configurations. Being able to donate a machine to the build fleet for OS/2 or VMS would allow those platforms to receive the same attention that more mainstream platforms receive.</p> +<p>If you can donate either time or hardware to help keep OS/2 and VMS alive, contact the <a class="reference external" href="http://mail.python.org/mailman/listinfo/python-dev">python-dev</a> mailing list to coordinate your efforts.</p> +</div> +</div> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=RTWZNjzcHx0:VncS2cQK2Pk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=RTWZNjzcHx0:VncS2cQK2Pk:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=RTWZNjzcHx0:VncS2cQK2Pk:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=RTWZNjzcHx0:VncS2cQK2Pk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=RTWZNjzcHx0:VncS2cQK2Pk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=RTWZNjzcHx0:VncS2cQK2Pk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=RTWZNjzcHx0:VncS2cQK2Pk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=RTWZNjzcHx0:VncS2cQK2Pk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/RTWZNjzcHx0" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/05/python-33-to-drop-support-for-os2.htmltag:blogger.com,1999:blog-3941553907430899163.post-86105312525558548192011-05-02T10:18:00.000-04:002011-05-02T10:18:26.521-04:002011-05-02T10:18:26.521-04:00Python Insider Translation Project<div class="document" id="python-insider-translation-project"> + +<p>We think the content of this blog is useful for the whole Python +community, so reaching as many people as we can is one of our +priorities. To expand our reach, we have assembled a team of +translators to create parallel editions of the blog in other +languages. We are launching two translations today: <a class="reference external" href="http://blog-ja.python.org/">Japanese</a> and +<a class="reference external" href="http://blog-es.python.org/">Spanish</a>.</p> +<p>The translations will lag a little behind the posts on <a class="reference external" href="http://blog.python.org/">Python +Insider</a>, but try to keep more or less up to date.</p> +<div class="section" id="help-wanted"> +<h4>Help Wanted</h4> +<p>The translation team is still very small, so we are looking for more +people to join. We need people able to work on the existing languages, +or to help us expand to other languages. If you can help in either +way, contact Doug Hellmann (doug dot hellmann at gmail).</p> +</div> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qrDBu7N4X_k:wMiUAPxroZQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qrDBu7N4X_k:wMiUAPxroZQ:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qrDBu7N4X_k:wMiUAPxroZQ:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qrDBu7N4X_k:wMiUAPxroZQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qrDBu7N4X_k:wMiUAPxroZQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qrDBu7N4X_k:wMiUAPxroZQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=qrDBu7N4X_k:wMiUAPxroZQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=qrDBu7N4X_k:wMiUAPxroZQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/qrDBu7N4X_k" height="1" width="1"/>Davidmhhttp://www.blogger.com/profile/14913018830568213369noreply@blogger.comhttp://blog.python.org/2011/05/python-insider-translation-project.htmltag:blogger.com,1999:blog-3941553907430899163.post-61050672932318858162011-04-28T10:05:00.000-04:002011-04-28T10:06:02.380-04:002011-04-28T10:06:02.380-04:00Meet the Team: Brian Curtin<div class="document" id="meet-the-team-brian-curtin"> +<p><em>This post is part of the &quot;Meet the Team&quot; series of posts, which is meant to give a brief introduction to the Python core development team.</em></p> +<table class="docutils field-list" frame="void" rules="none"><col class="field-name"></col><col class="field-body"></col><tbody valign="top"><tr class="field"><th class="field-name">Name:</th><td class="field-body">Brian Curtin</td></tr><tr class="field"><th class="field-name">Location:</th><td class="field-body">Chicago, IL</td></tr><tr class="field"><th class="field-name">Home Page:</th><td class="field-body"><a class="reference external" href="http://blog.briancurtin.com/">http://blog.briancurtin.com/</a></td></tr></tbody></table> +<p><strong>How long have you been using Python?</strong></p> +<p>On a day to day basis going on 6 years. Prior to that I used it occasionally for a class in college and also at a summer internship.</p> +<p><strong>How long have you been a core committer?</strong></p> +<p>Just over a year. March 24 marked my first year with the group.</p> +<p><strong>How did you get started as a core developer? Do you remember your first commit?</strong></p> +<p>I got started after noticing a documentation bug while writing an extension module at work, then I submitted a simple patch and Georg Brandl committed it almost immediately. After having that quick success and a fresh source checkout, I wanted to dive in and learn more about the modules I was using and ended up writing a patch to add context manager support to zipfile.</p> +<p>The first few commits I made were documentation fixes in order to keep it simple early on. My first code commit was to add a few features and expand test coverage in the winreg module.</p> +<p><strong>Which parts of Python are you working on now?</strong></p> +<p>As one of the few Windows users involved in CPython development, I try to keep an eye on whatever issues Windows users are having. Due to that, I've had a chance to work on a bunch of the standard library, including modules I hadn't used. I haven't done much with the interpreter itself, but I'm looking to change that.</p> +<p><strong>What do you do with Python when you aren't doing core development work?</strong></p> +<p>I build a variety of test tools for a trading database which is written in C++. There's an extension module for the data API so we can easily write regression tests, performance tests, and we're always trying to build more.</p> +<p><strong>What do you do when you aren't programming?</strong></p> +<p>I'm a huge baseball fan. I umpire college baseball in the spring, various leagues in the summer, and mix in watching and going to Chicago Cubs games.</p> +</div><div class="feedflare"> +<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=WvEj6rtc9A0:KTaJ5tHvMyM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=WvEj6rtc9A0:KTaJ5tHvMyM:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=WvEj6rtc9A0:KTaJ5tHvMyM:-BTjWOF_DHI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=WvEj6rtc9A0:KTaJ5tHvMyM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=WvEj6rtc9A0:KTaJ5tHvMyM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=WvEj6rtc9A0:KTaJ5tHvMyM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=WvEj6rtc9A0:KTaJ5tHvMyM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=WvEj6rtc9A0:KTaJ5tHvMyM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0"></img></a> +</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/WvEj6rtc9A0" height="1" width="1"/>Brian Curtinnoreply@blogger.comhttp://blog.python.org/2011/04/meet-team-brian-curtin.html diff --git a/blogs/tests/test_models.py b/app/blogs/tests/test_models.py similarity index 93% rename from blogs/tests/test_models.py rename to app/blogs/tests/test_models.py index 3c29299ca..fa18d559e 100644 --- a/blogs/tests/test_models.py +++ b/app/blogs/tests/test_models.py @@ -1,7 +1,7 @@ from django.test import TestCase from django.utils import timezone -from ..models import BlogEntry, Feed +from app.blogs.models import BlogEntry, Feed class BlogModelTest(TestCase): diff --git a/blogs/tests/test_parser.py b/app/blogs/tests/test_parser.py similarity index 91% rename from blogs/tests/test_parser.py rename to app/blogs/tests/test_parser.py index fbfcfca38..64e2ab8d3 100644 --- a/blogs/tests/test_parser.py +++ b/app/blogs/tests/test_parser.py @@ -1,8 +1,8 @@ import datetime import unittest -from ..parser import get_all_entries -from .utils import get_test_rss_path +from app.blogs.parser import get_all_entries +from app.blogs.utils import get_test_rss_path class BlogParserTest(unittest.TestCase): diff --git a/blogs/tests/test_templatetags.py b/app/blogs/tests/test_templatetags.py similarity index 92% rename from blogs/tests/test_templatetags.py rename to app/blogs/tests/test_templatetags.py index c26fbd3ea..81c3c76a1 100644 --- a/blogs/tests/test_templatetags.py +++ b/app/blogs/tests/test_templatetags.py @@ -3,9 +3,9 @@ from django.template import Template, Context from django.utils.timezone import now -from ..templatetags.blogs import get_latest_blog_entries -from ..models import BlogEntry, Feed, FeedAggregate -from .utils import get_test_rss_path +from app.blogs.templatetags.blogs import get_latest_blog_entries +from app.blogs.models import BlogEntry, Feed, FeedAggregate +from app.blogs.utils import get_test_rss_path class BlogTemplateTagTest(TestCase): diff --git a/blogs/tests/test_views.py b/app/blogs/tests/test_views.py similarity index 89% rename from blogs/tests/test_views.py rename to app/blogs/tests/test_views.py index 5c6c5053f..90b1fc62b 100644 --- a/blogs/tests/test_views.py +++ b/app/blogs/tests/test_views.py @@ -2,9 +2,9 @@ from django.urls import reverse from django.test import TestCase -from ..models import BlogEntry, Feed +from app.blogs.models import BlogEntry, Feed -from .utils import get_test_rss_path +from app.blogs.utils import get_test_rss_path class BlogViewTest(TestCase): diff --git a/blogs/tests/utils.py b/app/blogs/tests/utils.py similarity index 100% rename from blogs/tests/utils.py rename to app/blogs/tests/utils.py diff --git a/blogs/urls.py b/app/blogs/urls.py similarity index 78% rename from blogs/urls.py rename to app/blogs/urls.py index d315ed486..5c694eba3 100644 --- a/blogs/urls.py +++ b/app/blogs/urls.py @@ -1,4 +1,4 @@ -from . import views +from app.blogs import views from django.urls import path urlpatterns = [ diff --git a/blogs/views.py b/app/blogs/views.py similarity index 88% rename from blogs/views.py rename to app/blogs/views.py index 2a018c0a5..7155aeab2 100644 --- a/blogs/views.py +++ b/app/blogs/views.py @@ -1,11 +1,11 @@ from django.views.generic import TemplateView -from .models import BlogEntry +from app.blogs.models import BlogEntry class BlogHome(TemplateView): """ Main blog view """ - template_name = 'blogs/index.html' + template_name = 'index.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) diff --git a/boxes/migrations/__init__.py b/app/boxes/__init__.py similarity index 100% rename from boxes/migrations/__init__.py rename to app/boxes/__init__.py diff --git a/boxes/admin.py b/app/boxes/admin.py similarity index 59% rename from boxes/admin.py rename to app/boxes/admin.py index d71e7810a..5ced01bbf 100644 --- a/boxes/admin.py +++ b/app/boxes/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from cms.admin import ContentManageableModelAdmin -from .models import Box +from app.cms.admin import ContentManageableModelAdmin +from app.boxes.models import Box @admin.register(Box) diff --git a/boxes/apps.py b/app/boxes/apps.py similarity index 75% rename from boxes/apps.py rename to app/boxes/apps.py index 6f7e158e2..a3cb53f36 100644 --- a/boxes/apps.py +++ b/app/boxes/apps.py @@ -3,4 +3,4 @@ class BoxesAppConfig(AppConfig): - name = 'boxes' + name = 'app.boxes' diff --git a/boxes/factories.py b/app/boxes/factories.py similarity index 91% rename from boxes/factories.py rename to app/boxes/factories.py index 5d8c7f2ad..c74b5234b 100644 --- a/boxes/factories.py +++ b/app/boxes/factories.py @@ -6,9 +6,9 @@ from django.conf import settings from factory.django import DjangoModelFactory -from .models import Box +from app.boxes.models import Box -from users.factories import UserFactory +from app.users.factories import UserFactory class BoxFactory(DjangoModelFactory): diff --git a/boxes/migrations/0001_initial.py b/app/boxes/migrations/0001_initial.py similarity index 100% rename from boxes/migrations/0001_initial.py rename to app/boxes/migrations/0001_initial.py diff --git a/boxes/migrations/0002_auto_20150416_1853.py b/app/boxes/migrations/0002_auto_20150416_1853.py similarity index 100% rename from boxes/migrations/0002_auto_20150416_1853.py rename to app/boxes/migrations/0002_auto_20150416_1853.py diff --git a/boxes/migrations/0003_auto_20171101_2138.py b/app/boxes/migrations/0003_auto_20171101_2138.py similarity index 100% rename from boxes/migrations/0003_auto_20171101_2138.py rename to app/boxes/migrations/0003_auto_20171101_2138.py diff --git a/boxes/migrations/0004_alter_box_creator_alter_box_last_modified_by.py b/app/boxes/migrations/0004_alter_box_creator_alter_box_last_modified_by.py similarity index 100% rename from boxes/migrations/0004_alter_box_creator_alter_box_last_modified_by.py rename to app/boxes/migrations/0004_alter_box_creator_alter_box_last_modified_by.py diff --git a/cms/__init__.py b/app/boxes/migrations/__init__.py similarity index 100% rename from cms/__init__.py rename to app/boxes/migrations/__init__.py diff --git a/boxes/models.py b/app/boxes/models.py similarity index 94% rename from boxes/models.py rename to app/boxes/models.py index b7b0a3385..55b570ef5 100644 --- a/boxes/models.py +++ b/app/boxes/models.py @@ -11,7 +11,7 @@ from django.conf import settings from django.db import models from markupfield.fields import MarkupField -from cms.models import ContentManageable +from app.cms.models import ContentManageable DEFAULT_MARKUP_TYPE = getattr(settings, 'DEFAULT_MARKUP_TYPE', 'restructuredtext') diff --git a/boxes/templatetags/boxes.py b/app/boxes/templatetags/boxes.py similarity index 92% rename from boxes/templatetags/boxes.py rename to app/boxes/templatetags/boxes.py index 2beba5304..f3c91bc2d 100644 --- a/boxes/templatetags/boxes.py +++ b/app/boxes/templatetags/boxes.py @@ -3,7 +3,7 @@ from django import template from django.utils.html import mark_safe -from ..models import Box +from app.boxes.models import Box log = logging.getLogger(__name__) register = template.Library() diff --git a/boxes/tests.py b/app/boxes/tests.py similarity index 96% rename from boxes/tests.py rename to app/boxes/tests.py index 13a8e998c..ff987928d 100644 --- a/boxes/tests.py +++ b/app/boxes/tests.py @@ -1,7 +1,7 @@ import logging from django import template from django.test import TestCase, override_settings -from .models import Box +from app.boxes.models import Box logging.disable(logging.CRITICAL) diff --git a/boxes/urls.py b/app/boxes/urls.py similarity index 74% rename from boxes/urls.py rename to app/boxes/urls.py index 8ac457c08..cc4c56a82 100644 --- a/boxes/urls.py +++ b/app/boxes/urls.py @@ -1,4 +1,4 @@ -from .views import box +from app.boxes.views import box from django.urls import path urlpatterns = [ diff --git a/boxes/views.py b/app/boxes/views.py similarity index 85% rename from boxes/views.py rename to app/boxes/views.py index 02a50feb6..5f7d5f2eb 100644 --- a/boxes/views.py +++ b/app/boxes/views.py @@ -1,6 +1,6 @@ from django.http import HttpResponse from django.shortcuts import get_object_or_404 -from .models import Box +from app.boxes.models import Box def box(request, label): b = get_object_or_404(Box, label=label) diff --git a/cms/management/__init__.py b/app/cms/__init__.py similarity index 100% rename from cms/management/__init__.py rename to app/cms/__init__.py diff --git a/cms/admin.py b/app/cms/admin.py similarity index 100% rename from cms/admin.py rename to app/cms/admin.py diff --git a/cms/apps.py b/app/cms/apps.py similarity index 76% rename from cms/apps.py rename to app/cms/apps.py index f9df91865..fb1e06af2 100644 --- a/cms/apps.py +++ b/app/cms/apps.py @@ -3,4 +3,4 @@ class CmsAppConfig(AppConfig): - name = 'cms' + name = 'app.cms' diff --git a/cms/forms.py b/app/cms/forms.py similarity index 100% rename from cms/forms.py rename to app/cms/forms.py diff --git a/cms/management/commands/__init__.py b/app/cms/management/__init__.py similarity index 100% rename from cms/management/commands/__init__.py rename to app/cms/management/__init__.py diff --git a/cms/templatetags/__init__.py b/app/cms/management/commands/__init__.py similarity index 100% rename from cms/templatetags/__init__.py rename to app/cms/management/commands/__init__.py diff --git a/cms/management/commands/create_initial_data.py b/app/cms/management/commands/create_initial_data.py similarity index 100% rename from cms/management/commands/create_initial_data.py rename to app/cms/management/commands/create_initial_data.py diff --git a/cms/models.py b/app/cms/models.py similarity index 100% rename from cms/models.py rename to app/cms/models.py diff --git a/templates/cms/iso_time_tag.html b/app/cms/templates/iso_time_tag.html similarity index 100% rename from templates/cms/iso_time_tag.html rename to app/cms/templates/iso_time_tag.html diff --git a/codesamples/__init__.py b/app/cms/templatetags/__init__.py similarity index 100% rename from codesamples/__init__.py rename to app/cms/templatetags/__init__.py diff --git a/cms/templatetags/cms.py b/app/cms/templatetags/cms.py similarity index 100% rename from cms/templatetags/cms.py rename to app/cms/templatetags/cms.py diff --git a/cms/tests.py b/app/cms/tests.py similarity index 97% rename from cms/tests.py rename to app/cms/tests.py index 9c9e8a6d4..3909fa3ed 100644 --- a/cms/tests.py +++ b/app/cms/tests.py @@ -4,8 +4,8 @@ from django.template import Template, Context from django.test import TestCase -from .admin import ContentManageableModelAdmin -from .views import legacy_path +from app.cms.admin import ContentManageableModelAdmin +from app.cms.views import legacy_path import datetime diff --git a/cms/views.py b/app/cms/views.py similarity index 100% rename from cms/views.py rename to app/cms/views.py diff --git a/codesamples/migrations/__init__.py b/app/codesamples/__init__.py similarity index 100% rename from codesamples/migrations/__init__.py rename to app/codesamples/__init__.py diff --git a/app/codesamples/admin.py b/app/codesamples/admin.py new file mode 100644 index 000000000..c4d88f0c4 --- /dev/null +++ b/app/codesamples/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin + +from app.codesamples.models import CodeSample +from app.cms.admin import ContentManageableModelAdmin + + +admin.site.register(CodeSample, ContentManageableModelAdmin) diff --git a/codesamples/apps.py b/app/codesamples/apps.py similarity index 72% rename from codesamples/apps.py rename to app/codesamples/apps.py index 565ae1f8b..2978117da 100644 --- a/codesamples/apps.py +++ b/app/codesamples/apps.py @@ -3,4 +3,4 @@ class CodesamplesAppConfig(AppConfig): - name = 'codesamples' + name = 'app.codesamples' diff --git a/codesamples/factories.py b/app/codesamples/factories.py similarity index 98% rename from codesamples/factories.py rename to app/codesamples/factories.py index 5a52b9738..8e59c2753 100644 --- a/codesamples/factories.py +++ b/app/codesamples/factories.py @@ -3,9 +3,9 @@ import factory from factory.django import DjangoModelFactory -from .models import CodeSample +from app.codesamples.models import CodeSample -from users.factories import UserFactory +from app.users.factories import UserFactory class CodeSampleFactory(DjangoModelFactory): diff --git a/codesamples/managers.py b/app/codesamples/managers.py similarity index 100% rename from codesamples/managers.py rename to app/codesamples/managers.py diff --git a/codesamples/migrations/0001_initial.py b/app/codesamples/migrations/0001_initial.py similarity index 100% rename from codesamples/migrations/0001_initial.py rename to app/codesamples/migrations/0001_initial.py diff --git a/codesamples/migrations/0002_auto_20150416_1853.py b/app/codesamples/migrations/0002_auto_20150416_1853.py similarity index 100% rename from codesamples/migrations/0002_auto_20150416_1853.py rename to app/codesamples/migrations/0002_auto_20150416_1853.py diff --git a/codesamples/migrations/0003_auto_20170821_2000.py b/app/codesamples/migrations/0003_auto_20170821_2000.py similarity index 100% rename from codesamples/migrations/0003_auto_20170821_2000.py rename to app/codesamples/migrations/0003_auto_20170821_2000.py diff --git a/codesamples/migrations/0004_alter_codesample_creator_and_more.py b/app/codesamples/migrations/0004_alter_codesample_creator_and_more.py similarity index 100% rename from codesamples/migrations/0004_alter_codesample_creator_and_more.py rename to app/codesamples/migrations/0004_alter_codesample_creator_and_more.py diff --git a/community/__init__.py b/app/codesamples/migrations/__init__.py similarity index 100% rename from community/__init__.py rename to app/codesamples/migrations/__init__.py diff --git a/codesamples/models.py b/app/codesamples/models.py similarity index 87% rename from codesamples/models.py rename to app/codesamples/models.py index e0158fb69..2c47060c5 100644 --- a/codesamples/models.py +++ b/app/codesamples/models.py @@ -3,9 +3,9 @@ from django.template.defaultfilters import truncatechars, striptags from markupfield.fields import MarkupField -from cms.models import ContentManageable +from app.cms.models import ContentManageable -from .managers import CodeSampleQuerySet +from app.codesamples.managers import CodeSampleQuerySet DEFAULT_MARKUP_TYPE = getattr(settings, 'DEFAULT_MARKUP_TYPE', 'html') diff --git a/codesamples/tests.py b/app/codesamples/tests.py similarity index 93% rename from codesamples/tests.py rename to app/codesamples/tests.py index 7ddf51119..8f632b984 100644 --- a/codesamples/tests.py +++ b/app/codesamples/tests.py @@ -1,6 +1,6 @@ from django.test import TestCase -from .models import CodeSample +from app.codesamples.models import CodeSample class CodeSampleModelTests(TestCase): diff --git a/community/migrations/__init__.py b/app/community/__init__.py similarity index 100% rename from community/migrations/__init__.py rename to app/community/__init__.py diff --git a/community/admin.py b/app/community/admin.py similarity index 83% rename from community/admin.py rename to app/community/admin.py index b9023ac00..f10639f51 100644 --- a/community/admin.py +++ b/app/community/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin -from .models import Link, Photo, Post, Video -from cms.admin import ContentManageableModelAdmin, ContentManageableStackedInline +from app.community.models import Link, Photo, Post, Video +from app.cms.admin import ContentManageableModelAdmin, ContentManageableStackedInline class LinkInline(ContentManageableStackedInline): diff --git a/community/apps.py b/app/community/apps.py similarity index 73% rename from community/apps.py rename to app/community/apps.py index 7dee88ac0..cff35dc99 100644 --- a/community/apps.py +++ b/app/community/apps.py @@ -3,4 +3,4 @@ class CommunityAppConfig(AppConfig): - name = 'community' + name = 'app.community' diff --git a/community/managers.py b/app/community/managers.py similarity index 100% rename from community/managers.py rename to app/community/managers.py diff --git a/community/migrations/0001_initial.py b/app/community/migrations/0001_initial.py similarity index 100% rename from community/migrations/0001_initial.py rename to app/community/migrations/0001_initial.py diff --git a/community/migrations/0001_squashed_0004_auto_20170831_0541.py b/app/community/migrations/0001_squashed_0004_auto_20170831_0541.py similarity index 100% rename from community/migrations/0001_squashed_0004_auto_20170831_0541.py rename to app/community/migrations/0001_squashed_0004_auto_20170831_0541.py diff --git a/community/migrations/0002_auto_20150416_1853.py b/app/community/migrations/0002_auto_20150416_1853.py similarity index 100% rename from community/migrations/0002_auto_20150416_1853.py rename to app/community/migrations/0002_auto_20150416_1853.py diff --git a/community/migrations/0003_auto_20170831_0358.py b/app/community/migrations/0003_auto_20170831_0358.py similarity index 100% rename from community/migrations/0003_auto_20170831_0358.py rename to app/community/migrations/0003_auto_20170831_0358.py diff --git a/community/migrations/0004_auto_20170831_0541.py b/app/community/migrations/0004_auto_20170831_0541.py similarity index 100% rename from community/migrations/0004_auto_20170831_0541.py rename to app/community/migrations/0004_auto_20170831_0541.py diff --git a/community/migrations/0005_alter_link_creator_alter_link_last_modified_by_and_more.py b/app/community/migrations/0005_alter_link_creator_alter_link_last_modified_by_and_more.py similarity index 100% rename from community/migrations/0005_alter_link_creator_alter_link_last_modified_by_and_more.py rename to app/community/migrations/0005_alter_link_creator_alter_link_last_modified_by_and_more.py diff --git a/community/templatetags/__init__.py b/app/community/migrations/__init__.py similarity index 100% rename from community/templatetags/__init__.py rename to app/community/migrations/__init__.py diff --git a/community/models.py b/app/community/models.py similarity index 97% rename from community/models.py rename to app/community/models.py index 75ee94cd8..ae04a3101 100644 --- a/community/models.py +++ b/app/community/models.py @@ -5,9 +5,9 @@ from markupfield.fields import MarkupField -from cms.models import ContentManageable +from app.cms.models import ContentManageable -from .managers import PostQuerySet +from app.community.managers import PostQuerySet DEFAULT_MARKUP_TYPE = 'html' diff --git a/templates/community/microbit.html b/app/community/templates/microbit.html similarity index 100% rename from templates/community/microbit.html rename to app/community/templates/microbit.html diff --git a/templates/community/post_detail.html b/app/community/templates/post_detail.html similarity index 100% rename from templates/community/post_detail.html rename to app/community/templates/post_detail.html diff --git a/templates/community/post_list.html b/app/community/templates/post_list.html similarity index 100% rename from templates/community/post_list.html rename to app/community/templates/post_list.html diff --git a/templates/community/types/default.html b/app/community/templates/types/default.html similarity index 100% rename from templates/community/types/default.html rename to app/community/templates/types/default.html diff --git a/templates/community/types/link.html b/app/community/templates/types/link.html similarity index 100% rename from templates/community/types/link.html rename to app/community/templates/types/link.html diff --git a/templates/community/types/photo.html b/app/community/templates/types/photo.html similarity index 100% rename from templates/community/types/photo.html rename to app/community/templates/types/photo.html diff --git a/templates/community/types/text.html b/app/community/templates/types/text.html similarity index 100% rename from templates/community/types/text.html rename to app/community/templates/types/text.html diff --git a/templates/community/types/video.html b/app/community/templates/types/video.html similarity index 100% rename from templates/community/types/video.html rename to app/community/templates/types/video.html diff --git a/community/tests/__init__.py b/app/community/templatetags/__init__.py similarity index 100% rename from community/tests/__init__.py rename to app/community/templatetags/__init__.py diff --git a/community/templatetags/community.py b/app/community/templatetags/community.py similarity index 100% rename from community/templatetags/community.py rename to app/community/templatetags/community.py diff --git a/companies/__init__.py b/app/community/tests/__init__.py similarity index 100% rename from companies/__init__.py rename to app/community/tests/__init__.py diff --git a/community/tests/test_managers.py b/app/community/tests/test_managers.py similarity index 94% rename from community/tests/test_managers.py rename to app/community/tests/test_managers.py index 8e91e5523..88b577417 100644 --- a/community/tests/test_managers.py +++ b/app/community/tests/test_managers.py @@ -1,6 +1,6 @@ from django.test import TestCase -from ..models import Post +from app.community.models import Post class CommunityManagersTest(TestCase): diff --git a/community/tests/test_models.py b/app/community/tests/test_models.py similarity index 91% rename from community/tests/test_models.py rename to app/community/tests/test_models.py index c3b929c47..c63af490c 100644 --- a/community/tests/test_models.py +++ b/app/community/tests/test_models.py @@ -1,6 +1,6 @@ from django.test import TestCase -from ..models import Post +from app.community.models import Post class ModelTestCase(TestCase): diff --git a/community/tests/test_views.py b/app/community/tests/test_views.py similarity index 85% rename from community/tests/test_views.py rename to app/community/tests/test_views.py index bd6f4d859..19eb27812 100644 --- a/community/tests/test_views.py +++ b/app/community/tests/test_views.py @@ -1,5 +1,5 @@ -from pydotorg.tests.test_classes import TemplateTestCase -from ..models import Post +from app.pydotorg.tests.test_classes import TemplateTestCase +from app.community.models import Post class CommunityTagsTest(TemplateTestCase): diff --git a/community/urls.py b/app/community/urls.py similarity index 86% rename from community/urls.py rename to app/community/urls.py index 531dfe015..666ccdc15 100644 --- a/community/urls.py +++ b/app/community/urls.py @@ -1,4 +1,4 @@ -from . import views +from app.community import views from django.urls import path app_name = 'community' diff --git a/community/views.py b/app/community/views.py similarity index 81% rename from community/views.py rename to app/community/views.py index c9fbe08c5..8f6a07431 100644 --- a/community/views.py +++ b/app/community/views.py @@ -1,6 +1,6 @@ from django.views.generic import ListView, DetailView -from .models import Post +from app.community.models import Post class PostList(ListView): diff --git a/companies/migrations/__init__.py b/app/companies/__init__.py similarity index 100% rename from companies/migrations/__init__.py rename to app/companies/__init__.py diff --git a/companies/admin.py b/app/companies/admin.py similarity index 71% rename from companies/admin.py rename to app/companies/admin.py index f5e2da58f..0fc361883 100644 --- a/companies/admin.py +++ b/app/companies/admin.py @@ -1,8 +1,8 @@ from django.contrib import admin -from cms.admin import NameSlugAdmin +from app.cms.admin import NameSlugAdmin -from .models import Company +from app.companies.models import Company @admin.register(Company) diff --git a/companies/apps.py b/app/companies/apps.py similarity index 73% rename from companies/apps.py rename to app/companies/apps.py index d34262a3c..da7a65fc3 100644 --- a/companies/apps.py +++ b/app/companies/apps.py @@ -3,4 +3,4 @@ class CompaniesAppConfig(AppConfig): - name = 'companies' + name = 'app.companies' diff --git a/companies/factories.py b/app/companies/factories.py similarity index 91% rename from companies/factories.py rename to app/companies/factories.py index 04e7b4ebf..b1ede5e93 100644 --- a/companies/factories.py +++ b/app/companies/factories.py @@ -1,7 +1,7 @@ import factory from factory.django import DjangoModelFactory -from .models import Company +from app.companies.models import Company class CompanyFactory(DjangoModelFactory): diff --git a/companies/migrations/0001_initial.py b/app/companies/migrations/0001_initial.py similarity index 100% rename from companies/migrations/0001_initial.py rename to app/companies/migrations/0001_initial.py diff --git a/companies/migrations/0002_auto_20150416_1853.py b/app/companies/migrations/0002_auto_20150416_1853.py similarity index 100% rename from companies/migrations/0002_auto_20150416_1853.py rename to app/companies/migrations/0002_auto_20150416_1853.py diff --git a/companies/migrations/0003_auto_20170814_0301.py b/app/companies/migrations/0003_auto_20170814_0301.py similarity index 100% rename from companies/migrations/0003_auto_20170814_0301.py rename to app/companies/migrations/0003_auto_20170814_0301.py diff --git a/companies/migrations/0004_auto_20170821_2000.py b/app/companies/migrations/0004_auto_20170821_2000.py similarity index 100% rename from companies/migrations/0004_auto_20170821_2000.py rename to app/companies/migrations/0004_auto_20170821_2000.py diff --git a/companies/migrations/0005_auto_20180705_0352.py b/app/companies/migrations/0005_auto_20180705_0352.py similarity index 100% rename from companies/migrations/0005_auto_20180705_0352.py rename to app/companies/migrations/0005_auto_20180705_0352.py diff --git a/companies/templatetags/__init__.py b/app/companies/migrations/__init__.py similarity index 100% rename from companies/templatetags/__init__.py rename to app/companies/migrations/__init__.py diff --git a/companies/models.py b/app/companies/models.py similarity index 94% rename from companies/models.py rename to app/companies/models.py index 0e97cc779..9d027cb89 100644 --- a/companies/models.py +++ b/app/companies/models.py @@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _ from markupfield.fields import MarkupField -from cms.models import NameSlugModel +from app.cms.models import NameSlugModel DEFAULT_MARKUP_TYPE = getattr(settings, 'DEFAULT_MARKUP_TYPE', 'restructuredtext') diff --git a/custom_storages/__init__.py b/app/companies/templatetags/__init__.py similarity index 100% rename from custom_storages/__init__.py rename to app/companies/templatetags/__init__.py diff --git a/companies/templatetags/companies.py b/app/companies/templatetags/companies.py similarity index 100% rename from companies/templatetags/companies.py rename to app/companies/templatetags/companies.py diff --git a/companies/tests.py b/app/companies/tests.py similarity index 72% rename from companies/tests.py rename to app/companies/tests.py index 083cd9dfe..a4dbb4ca8 100644 --- a/companies/tests.py +++ b/app/companies/tests.py @@ -1,7 +1,7 @@ from django.test import TestCase -from . import admin # coverage FTW -from .templatetags.companies import render_email +from app.companies import admin # coverage FTW +from app.companies.templatetags.companies import render_email class CompaniesTagsTests(TestCase): diff --git a/config/mime.types b/app/config/mime.types similarity index 100% rename from config/mime.types rename to app/config/mime.types diff --git a/config/nginx.conf b/app/config/nginx.conf similarity index 100% rename from config/nginx.conf rename to app/config/nginx.conf diff --git a/downloads/__init__.py b/app/custom_storages/__init__.py similarity index 100% rename from downloads/__init__.py rename to app/custom_storages/__init__.py diff --git a/custom_storages/storages.py b/app/custom_storages/storages.py similarity index 100% rename from custom_storages/storages.py rename to app/custom_storages/storages.py diff --git a/downloads/migrations/__init__.py b/app/downloads/__init__.py similarity index 100% rename from downloads/migrations/__init__.py rename to app/downloads/__init__.py diff --git a/downloads/admin.py b/app/downloads/admin.py similarity index 82% rename from downloads/admin.py rename to app/downloads/admin.py index d32f97b71..9e11e72b1 100644 --- a/downloads/admin.py +++ b/app/downloads/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin -from .models import OS, Release, ReleaseFile -from cms.admin import ContentManageableModelAdmin, ContentManageableStackedInline +from app.downloads.models import OS, Release, ReleaseFile +from app.cms.admin import ContentManageableModelAdmin, ContentManageableStackedInline @admin.register(OS) diff --git a/downloads/api.py b/app/downloads/api.py similarity index 92% rename from downloads/api.py rename to app/downloads/api.py index 73eb9b7bf..072004ea5 100644 --- a/downloads/api.py +++ b/app/downloads/api.py @@ -6,12 +6,12 @@ from tastypie import fields from tastypie.constants import ALL, ALL_WITH_RELATIONS -from pages.api import PageResource -from pydotorg.resources import GenericResource, OnlyPublishedAuthorization -from pydotorg.drf import BaseAPIViewSet, BaseFilterSet, IsStaffOrReadOnly +from app.pages.api import PageResource +from app.pydotorg.resources import GenericResource, OnlyPublishedAuthorization +from app.pydotorg.drf import BaseAPIViewSet, BaseFilterSet, IsStaffOrReadOnly -from .models import OS, Release, ReleaseFile -from .serializers import OSSerializer, ReleaseSerializer, ReleaseFileSerializer +from app.downloads.models import OS, Release, ReleaseFile +from app.downloads.serializers import OSSerializer, ReleaseSerializer, ReleaseFileSerializer class OSResource(GenericResource): diff --git a/downloads/apps.py b/app/downloads/apps.py similarity index 73% rename from downloads/apps.py rename to app/downloads/apps.py index 18c2db44c..bac27973c 100644 --- a/downloads/apps.py +++ b/app/downloads/apps.py @@ -3,4 +3,4 @@ class DownloadsAppConfig(AppConfig): - name = 'downloads' + name = 'app.downloads' diff --git a/downloads/factories.py b/app/downloads/factories.py similarity index 97% rename from downloads/factories.py rename to app/downloads/factories.py index 4ebcbdc22..9014e2d91 100644 --- a/downloads/factories.py +++ b/app/downloads/factories.py @@ -4,9 +4,9 @@ import requests from factory.django import DjangoModelFactory -from users.factories import UserFactory +from app.users.factories import UserFactory -from .models import OS, Release, ReleaseFile +from app.downloads.models import OS, Release, ReleaseFile class OSFactory(DjangoModelFactory): diff --git a/downloads/managers.py b/app/downloads/managers.py similarity index 100% rename from downloads/managers.py rename to app/downloads/managers.py diff --git a/downloads/migrations/0001_initial.py b/app/downloads/migrations/0001_initial.py similarity index 100% rename from downloads/migrations/0001_initial.py rename to app/downloads/migrations/0001_initial.py diff --git a/downloads/migrations/0002_auto_20150416_1853.py b/app/downloads/migrations/0002_auto_20150416_1853.py similarity index 100% rename from downloads/migrations/0002_auto_20150416_1853.py rename to app/downloads/migrations/0002_auto_20150416_1853.py diff --git a/downloads/migrations/0003_auto_20150824_1612.py b/app/downloads/migrations/0003_auto_20150824_1612.py similarity index 100% rename from downloads/migrations/0003_auto_20150824_1612.py rename to app/downloads/migrations/0003_auto_20150824_1612.py diff --git a/downloads/migrations/0004_auto_20170821_2000.py b/app/downloads/migrations/0004_auto_20170821_2000.py similarity index 100% rename from downloads/migrations/0004_auto_20170821_2000.py rename to app/downloads/migrations/0004_auto_20170821_2000.py diff --git a/downloads/migrations/0005_move_release_page_content.py b/app/downloads/migrations/0005_move_release_page_content.py similarity index 100% rename from downloads/migrations/0005_move_release_page_content.py rename to app/downloads/migrations/0005_move_release_page_content.py diff --git a/downloads/migrations/0006_auto_20180705_0352.py b/app/downloads/migrations/0006_auto_20180705_0352.py similarity index 100% rename from downloads/migrations/0006_auto_20180705_0352.py rename to app/downloads/migrations/0006_auto_20180705_0352.py diff --git a/downloads/migrations/0007_auto_20220809_1655.py b/app/downloads/migrations/0007_auto_20220809_1655.py similarity index 100% rename from downloads/migrations/0007_auto_20220809_1655.py rename to app/downloads/migrations/0007_auto_20220809_1655.py diff --git a/downloads/migrations/0008_auto_20220907_2102.py b/app/downloads/migrations/0008_auto_20220907_2102.py similarity index 100% rename from downloads/migrations/0008_auto_20220907_2102.py rename to app/downloads/migrations/0008_auto_20220907_2102.py diff --git a/downloads/migrations/0009_releasefile_sigstore_bundle_file.py b/app/downloads/migrations/0009_releasefile_sigstore_bundle_file.py similarity index 100% rename from downloads/migrations/0009_releasefile_sigstore_bundle_file.py rename to app/downloads/migrations/0009_releasefile_sigstore_bundle_file.py diff --git a/downloads/migrations/0010_releasefile_sbom_spdx2_file.py b/app/downloads/migrations/0010_releasefile_sbom_spdx2_file.py similarity index 100% rename from downloads/migrations/0010_releasefile_sbom_spdx2_file.py rename to app/downloads/migrations/0010_releasefile_sbom_spdx2_file.py diff --git a/downloads/migrations/0011_alter_os_creator_alter_os_last_modified_by_and_more.py b/app/downloads/migrations/0011_alter_os_creator_alter_os_last_modified_by_and_more.py similarity index 100% rename from downloads/migrations/0011_alter_os_creator_alter_os_last_modified_by_and_more.py rename to app/downloads/migrations/0011_alter_os_creator_alter_os_last_modified_by_and_more.py diff --git a/downloads/templatetags/__init__.py b/app/downloads/migrations/__init__.py similarity index 100% rename from downloads/templatetags/__init__.py rename to app/downloads/migrations/__init__.py diff --git a/downloads/models.py b/app/downloads/models.py similarity index 98% rename from downloads/models.py rename to app/downloads/models.py index 4576afb2f..8fe1cb3ff 100644 --- a/downloads/models.py +++ b/app/downloads/models.py @@ -11,12 +11,12 @@ from markupfield.fields import MarkupField -from boxes.models import Box -from cms.models import ContentManageable, NameSlugModel -from fastly.utils import purge_url -from pages.models import Page +from app.boxes.models import Box +from app.cms.models import ContentManageable, NameSlugModel +from app.fastly.utils import purge_url +from app.pages.models import Page -from .managers import ReleaseManager +from app.downloads.managers import ReleaseManager DEFAULT_MARKUP_TYPE = getattr(settings, 'DEFAULT_MARKUP_TYPE', 'restructuredtext') diff --git a/downloads/search_indexes.py b/app/downloads/search_indexes.py similarity index 97% rename from downloads/search_indexes.py rename to app/downloads/search_indexes.py index 7d476fb33..7ba7903d3 100644 --- a/downloads/search_indexes.py +++ b/app/downloads/search_indexes.py @@ -5,7 +5,7 @@ from haystack import indexes -from .models import Release +from app.downloads.models import Release class ReleaseIndex(indexes.SearchIndex, indexes.Indexable): diff --git a/downloads/serializers.py b/app/downloads/serializers.py similarity index 95% rename from downloads/serializers.py rename to app/downloads/serializers.py index 1ff57049f..4f31a5968 100644 --- a/downloads/serializers.py +++ b/app/downloads/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from downloads.models import OS, Release, ReleaseFile +from app.downloads.models import OS, Release, ReleaseFile class OSSerializer(serializers.HyperlinkedModelSerializer): diff --git a/templates/account/base.html b/app/downloads/templates/base.html similarity index 100% rename from templates/account/base.html rename to app/downloads/templates/base.html diff --git a/templates/downloads/download-sources-box.html b/app/downloads/templates/download-sources-box.html similarity index 100% rename from templates/downloads/download-sources-box.html rename to app/downloads/templates/download-sources-box.html diff --git a/templates/downloads/full_os_list.html b/app/downloads/templates/full_os_list.html similarity index 100% rename from templates/downloads/full_os_list.html rename to app/downloads/templates/full_os_list.html diff --git a/templates/downloads/homepage-downloads-box.html b/app/downloads/templates/homepage-downloads-box.html similarity index 100% rename from templates/downloads/homepage-downloads-box.html rename to app/downloads/templates/homepage-downloads-box.html diff --git a/templates/downloads/index.html b/app/downloads/templates/index.html similarity index 100% rename from templates/downloads/index.html rename to app/downloads/templates/index.html diff --git a/templates/downloads/os_list.html b/app/downloads/templates/os_list.html similarity index 100% rename from templates/downloads/os_list.html rename to app/downloads/templates/os_list.html diff --git a/templates/downloads/release_detail.html b/app/downloads/templates/release_detail.html similarity index 100% rename from templates/downloads/release_detail.html rename to app/downloads/templates/release_detail.html diff --git a/templates/downloads/supernav.html b/app/downloads/templates/supernav.html similarity index 100% rename from templates/downloads/supernav.html rename to app/downloads/templates/supernav.html diff --git a/downloads/tests/__init__.py b/app/downloads/templatetags/__init__.py similarity index 100% rename from downloads/tests/__init__.py rename to app/downloads/templatetags/__init__.py diff --git a/downloads/templatetags/download_tags.py b/app/downloads/templatetags/download_tags.py similarity index 100% rename from downloads/templatetags/download_tags.py rename to app/downloads/templatetags/download_tags.py diff --git a/events/__init__.py b/app/downloads/tests/__init__.py similarity index 100% rename from events/__init__.py rename to app/downloads/tests/__init__.py diff --git a/downloads/tests/base.py b/app/downloads/tests/base.py similarity index 97% rename from downloads/tests/base.py rename to app/downloads/tests/base.py index bcb7905c4..ce99460b5 100644 --- a/downloads/tests/base.py +++ b/app/downloads/tests/base.py @@ -3,8 +3,8 @@ from django.test import TestCase from django.utils import timezone -from pages.models import Page -from ..models import OS, Release, ReleaseFile +from app.pages.models import Page +from app.downloads.models import OS, Release, ReleaseFile class DownloadMixin: diff --git a/downloads/tests/test_models.py b/app/downloads/tests/test_models.py similarity index 97% rename from downloads/tests/test_models.py rename to app/downloads/tests/test_models.py index d31afae5c..0c44ef76f 100644 --- a/downloads/tests/test_models.py +++ b/app/downloads/tests/test_models.py @@ -1,5 +1,5 @@ -from ..models import Release -from .base import BaseDownloadTests +from app.downloads.models import Release +from app.downloads.base import BaseDownloadTests class DownloadModelTests(BaseDownloadTests): diff --git a/downloads/tests/test_views.py b/app/downloads/tests/test_views.py similarity index 98% rename from downloads/tests/test_views.py rename to app/downloads/tests/test_views.py index b559a2adc..5895caa12 100644 --- a/downloads/tests/test_views.py +++ b/app/downloads/tests/test_views.py @@ -7,11 +7,11 @@ from rest_framework.test import APITestCase -from .base import BaseDownloadTests, DownloadMixin -from ..models import Release -from pages.factories import PageFactory -from pydotorg.drf import BaseAPITestCase -from users.factories import UserFactory +from app.downloads.base import BaseDownloadTests, DownloadMixin +from app.downloads.models import Release +from app.pages.factories import PageFactory +from app.pydotorg.drf import BaseAPITestCase +from app.users.factories import UserFactory User = get_user_model() diff --git a/downloads/urls.py b/app/downloads/urls.py similarity index 95% rename from downloads/urls.py rename to app/downloads/urls.py index f553caeaa..8323a5736 100644 --- a/downloads/urls.py +++ b/app/downloads/urls.py @@ -1,4 +1,4 @@ -from . import views +from app.downloads import views from django.urls import path, re_path app_name = 'downloads' diff --git a/downloads/views.py b/app/downloads/views.py similarity index 96% rename from downloads/views.py rename to app/downloads/views.py index 6a7f9d95e..6492eaf67 100644 --- a/downloads/views.py +++ b/app/downloads/views.py @@ -10,7 +10,7 @@ from django.contrib.syndication.views import Feed from django.utils.feedgenerator import Rss201rev2Feed -from .models import OS, Release, ReleaseFile +from app.downloads.models import OS, Release, ReleaseFile class DownloadLatestPython2(RedirectView): @@ -57,7 +57,7 @@ def get_context_data(self, **kwargs): class DownloadHome(DownloadBase, TemplateView): - template_name = 'downloads/index.html' + template_name = 'index.html' def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -93,13 +93,13 @@ def get_context_data(self, **kwargs): class DownloadFullOSList(DownloadBase, ListView): - template_name = 'downloads/full_os_list.html' + template_name = 'full_os_list.html' context_object_name = 'os_list' model = OS class DownloadOSList(DownloadBase, DetailView): - template_name = 'downloads/os_list.html' + template_name = 'os_list.html' context_object_name = 'os' model = OS @@ -121,7 +121,7 @@ def get_context_data(self, **kwargs): class DownloadReleaseDetail(DownloadBase, DetailView): - template_name = 'downloads/release_detail.html' + template_name = 'release_detail.html' model = Release context_object_name = 'release' diff --git a/events/management/__init__.py b/app/events/__init__.py similarity index 100% rename from events/management/__init__.py rename to app/events/__init__.py diff --git a/events/admin.py b/app/events/admin.py similarity index 83% rename from events/admin.py rename to app/events/admin.py index ba03c28ed..9875b228d 100644 --- a/events/admin.py +++ b/app/events/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin -from cms.admin import ContentManageableModelAdmin, NameSlugAdmin +from app.cms.admin import ContentManageableModelAdmin, NameSlugAdmin -from .models import Calendar, EventCategory, Event, OccurringRule, RecurringRule, Alarm, EventLocation +from app.events.models import Calendar, EventCategory, Event, OccurringRule, RecurringRule, Alarm, EventLocation class EventInline(admin.StackedInline): diff --git a/events/apps.py b/app/events/apps.py similarity index 74% rename from events/apps.py rename to app/events/apps.py index 23eadd3fe..a191c6d0e 100644 --- a/events/apps.py +++ b/app/events/apps.py @@ -3,4 +3,4 @@ class EventsAppConfig(AppConfig): - name = 'events' + name = 'app.events' diff --git a/events/factories.py b/app/events/factories.py similarity index 97% rename from events/factories.py rename to app/events/factories.py index deef85b38..3c28c3cb1 100644 --- a/events/factories.py +++ b/app/events/factories.py @@ -1,7 +1,7 @@ import factory from factory.django import DjangoModelFactory -from .models import Calendar +from app.events.models import Calendar class CalendarFactory(DjangoModelFactory): diff --git a/events/forms.py b/app/events/forms.py similarity index 100% rename from events/forms.py rename to app/events/forms.py diff --git a/events/importer.py b/app/events/importer.py similarity index 95% rename from events/importer.py rename to app/events/importer.py index fe04d35f5..b3534ed7d 100644 --- a/events/importer.py +++ b/app/events/importer.py @@ -4,8 +4,8 @@ from icalendar import Calendar as ICalendar import requests -from .models import EventLocation, Event, OccurringRule -from .utils import extract_date_or_datetime +from app.events.models import EventLocation, Event, OccurringRule +from app.events.utils import extract_date_or_datetime DATE_RESOLUTION = timedelta(1) TIME_RESOLUTION = timedelta(0, 0, 1) diff --git a/events/management/commands/__init__.py b/app/events/management/__init__.py similarity index 100% rename from events/management/commands/__init__.py rename to app/events/management/__init__.py diff --git a/events/migrations/__init__.py b/app/events/management/commands/__init__.py similarity index 100% rename from events/migrations/__init__.py rename to app/events/management/commands/__init__.py diff --git a/events/management/commands/import_ics_calendars.py b/app/events/management/commands/import_ics_calendars.py similarity index 100% rename from events/management/commands/import_ics_calendars.py rename to app/events/management/commands/import_ics_calendars.py diff --git a/events/migrations/0001_initial.py b/app/events/migrations/0001_initial.py similarity index 98% rename from events/migrations/0001_initial.py rename to app/events/migrations/0001_initial.py index 344633b3a..e21e4821f 100644 --- a/events/migrations/0001_initial.py +++ b/app/events/migrations/0001_initial.py @@ -1,9 +1,10 @@ from django.db import models, migrations -import events.models import markupfield.fields import django.utils.timezone from django.conf import settings +from app.events.models import RuleMixin + class Migration(migrations.Migration): @@ -104,7 +105,7 @@ class Migration(migrations.Migration): ], options={ }, - bases=(events.models.RuleMixin, models.Model), + bases=(RuleMixin, models.Model), ), migrations.CreateModel( name='RecurringRule', @@ -119,7 +120,7 @@ class Migration(migrations.Migration): ], options={ }, - bases=(events.models.RuleMixin, models.Model), + bases=(RuleMixin, models.Model), ), migrations.AddField( model_name='event', diff --git a/events/migrations/0002_auto_20150321_1247.py b/app/events/migrations/0002_auto_20150321_1247.py similarity index 100% rename from events/migrations/0002_auto_20150321_1247.py rename to app/events/migrations/0002_auto_20150321_1247.py diff --git a/events/migrations/0003_auto_20150416_1853.py b/app/events/migrations/0003_auto_20150416_1853.py similarity index 100% rename from events/migrations/0003_auto_20150416_1853.py rename to app/events/migrations/0003_auto_20150416_1853.py diff --git a/events/migrations/0004_auto_20170814_0519.py b/app/events/migrations/0004_auto_20170814_0519.py similarity index 80% rename from events/migrations/0004_auto_20170814_0519.py rename to app/events/migrations/0004_auto_20170814_0519.py index 171852a04..85c6ee79e 100644 --- a/events/migrations/0004_auto_20170814_0519.py +++ b/app/events/migrations/0004_auto_20170814_0519.py @@ -1,5 +1,6 @@ from django.db import migrations, models -import events.models + +from app.events.models import duration_default class Migration(migrations.Migration): @@ -12,7 +13,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='recurringrule', name='duration_internal', - field=models.DurationField(default=events.models.duration_default), + field=models.DurationField(default=duration_default), ), migrations.AlterField( model_name='recurringrule', diff --git a/events/migrations/0005_auto_20170821_2000.py b/app/events/migrations/0005_auto_20170821_2000.py similarity index 100% rename from events/migrations/0005_auto_20170821_2000.py rename to app/events/migrations/0005_auto_20170821_2000.py diff --git a/events/migrations/0006_change_end_date_for_occurring_rules.py b/app/events/migrations/0006_change_end_date_for_occurring_rules.py similarity index 100% rename from events/migrations/0006_change_end_date_for_occurring_rules.py rename to app/events/migrations/0006_change_end_date_for_occurring_rules.py diff --git a/events/migrations/0007_auto_20180705_0352.py b/app/events/migrations/0007_auto_20180705_0352.py similarity index 100% rename from events/migrations/0007_auto_20180705_0352.py rename to app/events/migrations/0007_auto_20180705_0352.py diff --git a/events/migrations/0008_alter_alarm_creator_alter_alarm_last_modified_by_and_more.py b/app/events/migrations/0008_alter_alarm_creator_alter_alarm_last_modified_by_and_more.py similarity index 100% rename from events/migrations/0008_alter_alarm_creator_alter_alarm_last_modified_by_and_more.py rename to app/events/migrations/0008_alter_alarm_creator_alter_alarm_last_modified_by_and_more.py diff --git a/events/templatetags/__init__.py b/app/events/migrations/__init__.py similarity index 100% rename from events/templatetags/__init__.py rename to app/events/migrations/__init__.py diff --git a/events/models.py b/app/events/models.py similarity index 98% rename from events/models.py rename to app/events/models.py index 1f2ab2cb0..38558096a 100644 --- a/events/models.py +++ b/app/events/models.py @@ -11,11 +11,11 @@ from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ -from cms.models import ContentManageable, NameSlugModel +from app.cms.models import ContentManageable, NameSlugModel from markupfield.fields import MarkupField -from .utils import ( +from app.events.utils import ( minutes_resolution, convert_dt_to_aware, timedelta_nice_repr, timedelta_parse, ) @@ -40,7 +40,7 @@ def get_absolute_url(self): def import_events(self): if self.url is None: raise ValueError("calendar must have a url field set") - from .importer import ICSImporter + from app.events.importer import ICSImporter importer = ICSImporter(calendar=self) importer.import_events() diff --git a/events/search_indexes.py b/app/events/search_indexes.py similarity index 97% rename from events/search_indexes.py rename to app/events/search_indexes.py index 9db26a93f..bdef45a1e 100644 --- a/events/search_indexes.py +++ b/app/events/search_indexes.py @@ -2,7 +2,7 @@ from haystack import indexes -from .models import Event, Calendar +from app.events.models import Event, Calendar class CalendarIndex(indexes.SearchIndex, indexes.Indexable): diff --git a/templates/events/base.html b/app/events/templates/base.html similarity index 100% rename from templates/events/base.html rename to app/events/templates/base.html diff --git a/templates/events/calendar_list.html b/app/events/templates/calendar_list.html similarity index 100% rename from templates/events/calendar_list.html rename to app/events/templates/calendar_list.html diff --git a/templates/events/email/new_event.txt b/app/events/templates/email/new_event.txt similarity index 100% rename from templates/events/email/new_event.txt rename to app/events/templates/email/new_event.txt diff --git a/templates/events/event_detail.html b/app/events/templates/event_detail.html similarity index 100% rename from templates/events/event_detail.html rename to app/events/templates/event_detail.html diff --git a/templates/events/event_form.html b/app/events/templates/event_form.html similarity index 100% rename from templates/events/event_form.html rename to app/events/templates/event_form.html diff --git a/templates/events/event_form_thanks.html b/app/events/templates/event_form_thanks.html similarity index 100% rename from templates/events/event_form_thanks.html rename to app/events/templates/event_form_thanks.html diff --git a/templates/events/event_list.html b/app/events/templates/event_list.html similarity index 100% rename from templates/events/event_list.html rename to app/events/templates/event_list.html diff --git a/templates/events/event_list_past.html b/app/events/templates/event_list_past.html similarity index 100% rename from templates/events/event_list_past.html rename to app/events/templates/event_list_past.html diff --git a/templates/events/eventcategory_list.html b/app/events/templates/eventcategory_list.html similarity index 100% rename from templates/events/eventcategory_list.html rename to app/events/templates/eventcategory_list.html diff --git a/templates/events/eventlocation_list.html b/app/events/templates/eventlocation_list.html similarity index 100% rename from templates/events/eventlocation_list.html rename to app/events/templates/eventlocation_list.html diff --git a/templates/events/includes/time_tag.html b/app/events/templates/includes/time_tag.html similarity index 100% rename from templates/events/includes/time_tag.html rename to app/events/templates/includes/time_tag.html diff --git a/events/tests/__init__.py b/app/events/templatetags/__init__.py similarity index 100% rename from events/tests/__init__.py rename to app/events/templatetags/__init__.py diff --git a/events/templatetags/events.py b/app/events/templatetags/events.py similarity index 90% rename from events/templatetags/events.py rename to app/events/templatetags/events.py index fa6bf8063..abfd1549a 100644 --- a/events/templatetags/events.py +++ b/app/events/templatetags/events.py @@ -1,7 +1,7 @@ from django import template from django.utils import timezone -from ..models import Event +from app.events.models import Event register = template.Library() diff --git a/fastly/__init__.py b/app/events/tests/__init__.py similarity index 100% rename from fastly/__init__.py rename to app/events/tests/__init__.py diff --git a/events/tests/events.ics b/app/events/tests/events.ics similarity index 96% rename from events/tests/events.ics rename to app/events/tests/events.ics index f4b15522b..a3668d902 100644 --- a/events/tests/events.ics +++ b/app/events/tests/events.ics @@ -1,1154 +1,1154 @@ -BEGIN:VCALENDAR -PRODID:-//Google Inc//Google Calendar 70.9054//EN -VERSION:2.0 -CALSCALE:GREGORIAN -METHOD:PUBLISH -X-WR-CALNAME:Python Events Calendar -X-WR-TIMEZONE:Etc/GMT -X-WR-CALDESC:Calendar showing Python conference and user group meeting date - s. -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140516 -DTEND;VALUE=DATE:20140519 -DTSTAMP:20140208T185114Z -UID:0dpji3hft657pi6cgradu20rro@google.com -CREATED:20140205T213025Z -DESCRIPTION:PyCon APAC 2014 -LAST-MODIFIED:20140205T213025Z -LOCATION:Academia Sinica\, Taipei\, Taiwan -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon APAC 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140618 -DTEND;VALUE=DATE:20140621 -DTSTAMP:20140208T185114Z -UID:4634mvl5jnlgbtadsfujf1j6kk@google.com -CREATED:20140205T212909Z -DESCRIPTION:PyCon Singapore 2014 -LAST-MODIFIED:20140205T212909Z -LOCATION:Singapore Polytechnic (SP)\, 500 Dover Road\, Singapore 139651 -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Singapore 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140513 -DTEND;VALUE=DATE:20140518 -DTSTAMP:20140208T185114Z -UID:elv2tjohtchcfq3js8b58sp35k@google.com -CREATED:20140205T205101Z -DESCRIPTION:Djangocon Europe 2014 -LAST-MODIFIED:20140205T205101Z -LOCATION:L'Île des Embiez\, Var\, France -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Djangocon Europe 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140726 -DTEND;VALUE=DATE:20140728 -DTSTAMP:20140208T185114Z -UID:m6oiipchdeu2buo2id8ku6g9lg@google.com -CREATED:20140130T103507Z -DESCRIPTION:PyOhio 2014 -LAST-MODIFIED:20140130T103507Z -LOCATION:Columbus\, OH USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyOhio 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140314 -DTEND;VALUE=DATE:20140315 -DTSTAMP:20140208T185114Z -UID:c67i38nf1npuau10ue9nli127k@google.com -CREATED:20140127T123759Z -DESCRIPTION:Conference "for Pytho - n Quants" -LAST-MODIFIED:20140127T123759Z -LOCATION:Executive Conference Center\, 8th Fl\, 1601 Broadway\, NY\, NY\, 1 - 0036\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Conference "for Python Quants" -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140201 -DTEND;VALUE=DATE:20140203 -DTSTAMP:20140208T185114Z -UID:u81fjn1b72ack9ahm1tb30bab0@google.com -CREATED:20140122T140602Z -DESCRIPTION:FOSDEM 2014 with a Python Developer Room on Sunday\ - , Feb 2nd. -LAST-MODIFIED:20140122T140602Z -LOCATION:Université libre de Bruxelles\, Campus du Solbosch\, Avenue Frankl - in D. Roosevelt 50\, 1050 Bruxelles\, Belgium -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:FOSDEM 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140613 -DTEND;VALUE=DATE:20140616 -DTSTAMP:20140208T185114Z -UID:mamkq4rnbbe587ot9doagk2mjc@google.com -CREATED:20140120T172328Z -DESCRIPTION:Full details on the conf - erence website -LAST-MODIFIED:20140120T172328Z -LOCATION:Orvieto\, Terni\, Italy -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:DjangoVillage -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140207 -DTEND;VALUE=DATE:20140210 -DTSTAMP:20140208T185114Z -UID:fji4c5184i3p23enm8e1umkvp8@google.com -CREATED:20140120T103025Z -DESCRIPTION:Django Weekend Cardiff -LAST-MODIFIED:20140120T103025Z -LOCATION:Cardiff University\, Cardiff\, Wales\, UK -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Django Weekend Cardiff -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140221 -DTEND;VALUE=DATE:20140224 -DTSTAMP:20140208T185114Z -UID:6shlu35o5vgqm7kiue9qpt77u4@google.com -CREATED:20140118T202358Z -DESCRIPTION:PyData London 2014 -LAST-MODIFIED:20140118T202738Z -LOCATION:Level39\, One Canada Square\, Canary Wharf\, E14 5AB\, UK -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyData London 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140801 -DTEND;VALUE=DATE:20140806 -DTSTAMP:20140208T185114Z -UID:87ijl7np9urrlnbtlt3f21etug@google.com -ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Python - Events Calendar;X-NUM-GUESTS=0:mailto:j7gov1cmnqr9tvg14k621j7t5c@group.cal - endar.google.com -CREATED:20140115T021111Z -DESCRIPTION:PyCon Australia 2014 -LAST-MODIFIED:20140115T021249Z -LOCATION:Brisbane\, Australia -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Australia 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140706 -DTEND;VALUE=DATE:20140713 -DTSTAMP:20140208T185114Z -UID:u8n3mam03ba47pmtec54sdr1ro@google.com -CREATED:20140115T021240Z -DESCRIPTION:SciPy 2014 -LAST-MODIFIED:20140115T021241Z -LOCATION:Austin\, TX\, United States -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:SciPy 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140329 -DTEND;VALUE=DATE:20140331 -DTSTAMP:20140208T185114Z -UID:cbnul786umrb5o4o84pfi8pqk8@google.com -CREATED:20140114T165443Z -DESCRIPTION:PythonCamp 2 - 014 -LAST-MODIFIED:20140114T165443Z -LOCATION:GFU Cyrus AG\, Am Grauen Stein 27\, 51105 Cologne -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PythonCamp 2014 - Python Bar Camp in Cologne -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140222 -DTEND;VALUE=DATE:20140224 -DTSTAMP:20140208T185114Z -UID:jpjq2oi33tkft2nll0tcohs3i0@google.com -CREATED:20140106T082236Z -DESCRIPTION:PyCon PH 2014 at \nDe La Salle University -LAST-MODIFIED:20140106T082236Z -LOCATION:De La Salle University\, 2401 Taft Avenue\, 1004 Manila\, Philippi - nes -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon PH 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART:20131208T010000Z -DTEND:20131208T100000Z -DTSTAMP:20140208T185114Z -UID:djtvr1jdnjifs9etni3t53ste4@google.com -CREATED:20131201T230024Z -DESCRIPTION:PyCon China 2014 -LAST-MODIFIED:20131201T230127Z -LOCATION:Shanghai\, Zhuhai and Hangzhou\, China -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon China 2014 -TRANSP:OPAQUE -END:VEVENT -BEGIN:VEVENT -DTSTART:20131214T010000Z -DTEND:20131214T100000Z -DTSTAMP:20140208T185114Z -UID:efic4423me14thbb9d4mg96754@google.com -CREATED:20131201T230113Z -DESCRIPTION:PyCon China 2014 -LAST-MODIFIED:20131201T230113Z -LOCATION:Beijing\, China -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon China 2014 -TRANSP:OPAQUE -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140721 -DTEND;VALUE=DATE:20140728 -DTSTAMP:20140208T185114Z -UID:iigilv0r74hhbs8kbfvja7h5fc@google.com -CREATED:20131019T193502Z -DESCRIPTION:EuroPython 2014 -LAST-MODIFIED:20131019T193502Z -LOCATION:Berlin\, Germany -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:EuroPython 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131017 -DTEND;VALUE=DATE:20131021 -DTSTAMP:20140208T185114Z -UID:0jh68f868hfv3l4i1t6s8l33eo@google.com -CREATED:20131012T225812Z -DESCRIPTION:PyCon Poland 2013 -LAST-MODIFIED:20131012T225826Z -LOCATION:„Orle Gniazdo” („Eagle's Nest”) Congress and Recreation Center in - Szczyrk -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Poland 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131026 -DTEND;VALUE=DATE:20131030 -DTSTAMP:20140208T185114Z -UID:vcfe0v28mp3g2p24ne189ol06k@google.com -CREATED:20131004T183105Z -DESCRIPTION:PyCon FR 2013 -LAST-MODIFIED:20131004T183105Z -LOCATION:Strasbourg\, France -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon FR 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131101 -DTEND;VALUE=DATE:20131102 -DTSTAMP:20140208T185114Z -UID:e1p10ro1ek2k1bfsihsk7rp3k8@google.com -CREATED:20131002T120707Z -DESCRIPTION:PyCon Iran 2013 -LAST-MODIFIED:20131002T234550Z -LOCATION:Tehran\, Iran -SEQUENCE:1 -STATUS:CONFIRMED -SUMMARY:PyCon Iran 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131003 -DTEND;VALUE=DATE:20131005 -DTSTAMP:20140208T185114Z -UID:1ccibtmc51p3a4kscbjivo9pag@google.com -CREATED:20130926T082215Z -DESCRIPTION:PyConZA 2013 -LAST-MODIFIED:20130926T082215Z -LOCATION:Cape Town\, South Africa -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyConZA 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131101 -DTEND;VALUE=DATE:20131103 -DTSTAMP:20140208T185114Z -UID:j8orn9jp861v0b26cung8k0bj8@google.com -CREATED:20130926T050621Z -DESCRIPTION:PyCon Uruguay 2013 -LAST-MODIFIED:20130926T050645Z -LOCATION:Montevideo\, Uruguay -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Uruguay 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131108 -DTEND;VALUE=DATE:20131111 -DTSTAMP:20140208T185114Z -UID:o3psu9qiqcas5hcn1lo2d73fao@google.com -CREATED:20130906T210915Z -DESCRIPTION:PyData NYC 2013 -LAST-MODIFIED:20130906T210915Z -LOCATION:1 Chase Manhattan Plaza\, New York City\, NY\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyData NYC 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140222 -DTEND;VALUE=DATE:20140224 -DTSTAMP:20140208T185114Z -UID:2a1ebu3dhr6ppfc656blqin4qk@google.com -CREATED:20130904T122445Z -DESCRIPTION:PyTennessee 2014 -LAST-MODIFIED:20130904T122445Z -LOCATION:Nashville School of Law\, Nashville\, TN\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyTennessee 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130831 -DTEND;VALUE=DATE:20130902 -DTSTAMP:20140208T185114Z -UID:oqtqbi8qja2tllnmijt7ptjsu0@google.com -CREATED:20130820T092236Z -DESCRIPTION:PyCon India 2013 -LAST-MODIFIED:20130820T092236Z -LOCATION:Bangalore\, India -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon India 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130727 -DTEND;VALUE=DATE:20130729 -DTSTAMP:20140208T185114Z -UID:8e858mcc7riq7s5lfspju4hqms@google.com -CREATED:20130719T080530Z -DESCRIPTION:PyData Boston 2013 -LAST-MODIFIED:20130719T080530Z -LOCATION:Microsoft NERD\, Cambridge\, MA\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyData Boston 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20140409 -DTEND;VALUE=DATE:20140418 -DTSTAMP:20140208T185114Z -UID:i2vt342est3ki3o0pfnp1jtgsc@google.com -CREATED:20130511T122254Z -DESCRIPTION:PyCon US 2014 -LAST-MODIFIED:20130716T082226Z -LOCATION:Montreal\, Canada -SEQUENCE:1 -STATUS:CONFIRMED -SUMMARY:PyCon US 2014 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131122 -DTEND;VALUE=DATE:20131125 -DTSTAMP:20140208T185114Z -UID:snb7f46skllv04svdsa1odpge0@google.com -CREATED:20130606T104007Z -DESCRIPTION:PyCon Spain 2013 -LAST-MODIFIED:20130715T115225Z -LOCATION:EU Informática\, Universidad Politécnica de Madrid\, Madrid\, Spai - n -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Spain 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131021 -DTEND;VALUE=DATE:20131023 -DTSTAMP:20140208T185114Z -UID:dcihgnimpqtfqch1co0q65fl9g@google.com -CREATED:20130609T111749Z -DESCRIPTION:PyCon Finland 2013 -LAST-MODIFIED:20130715T115057Z -LOCATION:Otaniemi\, Espoo\, Finland -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Finland 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130920 -DTEND;VALUE=DATE:20130924 -DTSTAMP:20140208T185114Z -UID:ihai7bc5isn0v7k26s7603aiio@google.com -CREATED:20130121T131625Z -DESCRIPTION:PyCon UK 2013 -LAST-MODIFIED:20130715T114945Z -LOCATION:Coventry\, UK -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon UK 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130824 -DTEND;VALUE=DATE:20130826 -DTSTAMP:20140208T185114Z -UID:9uvii4cr43pbaue6ji5uej5398@google.com -CREATED:20130614T205959Z -DESCRIPTION:FrOSCon 2013 - Fre - e and Open Source Software Conference (with Python track) -LAST-MODIFIED:20130614T205959Z -LOCATION:Sankt Augustin\, Germany -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:FrOSCon 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130504 -DTEND;VALUE=DATE:20130506 -DTSTAMP:20140208T185114Z -UID:ob367di2jkh4lopj81vubtpojo@google.com -ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Python - Events Calendar;X-NUM-GUESTS=0:mailto:j7gov1cmnqr9tvg14k621j7t5c@group.cal - endar.google.com -CREATED:20121025T075159Z -DESCRIPTION:PythonCamp 2013 - Ein B - arcamp zum Thema Python -LAST-MODIFIED:20130605T195520Z -LOCATION:Cologne\, Germany -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PythonCamp 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130909 -DTEND;VALUE=DATE:20130914 -DTSTAMP:20140208T185114Z -UID:ni8phh2vocilu08fd7e4uqvo30@google.com -CREATED:20130605T195005Z -DESCRIPTION:Seattle PyCamp - 2013 -LAST-MODIFIED:20130605T195005Z -LOCATION:Seattle\, WA\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY: Seattle PyCamp 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130812 -DTEND;VALUE=DATE:20130817 -DTSTAMP:20140208T185114Z -UID:mdl5qe7obelgri739u1muomq5k@google.com -CREATED:20130605T194913Z -DESCRIPTION:Toronto PyCamp - 2013 -LAST-MODIFIED:20130605T194913Z -LOCATION:Toronto\, ON\, Canada -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Toronto PyCamp 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130805 -DTEND;VALUE=DATE:20130810 -DTSTAMP:20140208T185114Z -UID:pmf3ovjm5fa4j1fpo2ns6p6f38@google.com -CREATED:20130605T194822Z -DESCRIPTION:Python Web Pr - ogramming Workshop -LAST-MODIFIED:20130605T194822Z -LOCATION:Chapel Hill\, NC\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Python Web Programming Workshop -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130722 -DTEND;VALUE=DATE:20130727 -DTSTAMP:20140208T185114Z -UID:31npklj9g1l2b59rdihte7aat4@google.com -CREATED:20130605T194722Z -DESCRIPTION:PyOhio PyCamp - 2013 -LAST-MODIFIED:20130605T194722Z -LOCATION:Columbus\, OH\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyOhio PyCamp 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131011 -DTEND;VALUE=DATE:20131014 -DTSTAMP:20140208T185114Z -UID:sfg4jhcahcbm2u93a8p7gt9r98@google.com -CREATED:20130326T080431Z -DESCRIPTION:RuPy 2013 -LAST-MODIFIED:20130511T124016Z -LOCATION:Budapest\, Hungary -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:RuPy 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130524 -DTEND;VALUE=DATE:20130526 -DTSTAMP:20140208T185114Z -UID:5a0vj73lku9s6sauemeurpgsjc@google.com -CREATED:20130415T100523Z -DESCRIPTION:PythonNordeste 2013 -LAST-MODIFIED:20130511T123912Z -LOCATION:Fortaleza\, Ceará\, Brazil -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PythonNordeste 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130515 -DTEND;VALUE=DATE:20130518 -DTSTAMP:20140208T185114Z -UID:2i2rcneg3b7gkc4q5s58l9ticg@google.com -CREATED:20130121T125304Z -DESCRIPTION:DjangoCon Europe 2013 -LAST-MODIFIED:20130511T123902Z -LOCATION:Warsaw\, Poland -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:DjangoCon Europe 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130613 -DTEND;VALUE=DATE:20130616 -DTSTAMP:20140208T185114Z -UID:jskaup72s08h41uinb8jktuktk@google.com -CREATED:20130205T115419Z -DESCRIPTION:PyCon Singapore 2013 -LAST-MODIFIED:20130511T123850Z -LOCATION:Singapore -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Singapore 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130701 -DTEND;VALUE=DATE:20130708 -DTSTAMP:20140208T185114Z -UID:kkjgb6hrfdc60l8h30j9pj029c@google.com -CREATED:20130121T131729Z -DESCRIPTION:EuroSciPy 2013 -LAST-MODIFIED:20130511T123805Z -LOCATION:Brussels\, Belgium -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:EuroSciPy 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130809 -DTEND;VALUE=DATE:20130814 -DTSTAMP:20140208T185114Z -UID:g9mjr24lb5n7nbb4uf95llvik0@google.com -CREATED:20130306T165642Z -DESCRIPTION:PyCon Canada 2013\n -LAST-MODIFIED:20130511T123752Z -LOCATION:Toronto\, Canada -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Canada 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130906 -DTEND;VALUE=DATE:20130909 -DTSTAMP:20140208T185114Z -UID:gf7gt7n75qsn7d359hc8kum3r4@google.com -CREATED:20130511T120941Z -DESCRIPTION:Kiwi PyCon 2013 -LAST-MODIFIED:20130511T123716Z -LOCATION:Auckland\, New Zealand -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Kiwi PyCon 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130727 -DTEND;VALUE=DATE:20130729 -DTSTAMP:20140208T185114Z -UID:umtv2r1qi4a8iqnn0fv38o9ok8@google.com -ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Python - Events Calendar;X-NUM-GUESTS=0:mailto:j7gov1cmnqr9tvg14k621j7t5c@group.cal - endar.google.com -CREATED:20130114T012524Z -DESCRIPTION:PyOhio 2013 -LAST-MODIFIED:20130405T025124Z -LOCATION:Ohio Union\, Columbus\, OH -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyOhio 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130405 -DTEND;VALUE=DATE:20130406 -DTSTAMP:20140208T185114Z -UID:lqau72c8o889tklo45o91jv5mk@google.com -CREATED:20130325T194752Z -DESCRIPTION:http://www.python-i - n-finance.com/ -LAST-MODIFIED:20130325T194752Z -LOCATION:New York\, NY\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Python in Finance -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130510 -DTEND;VALUE=DATE:20130511 -DTSTAMP:20140208T185114Z -UID:ra1qh5nerakgkotunqbvtbnvjg@google.com -CREATED:20130315T104413Z -DESCRIPTION:http://www.pygrunn.org/ -LAST-MODIFIED:20130315T104413Z -LOCATION:Groningen\, The Netherlands -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyGrunn 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131012 -DTEND;VALUE=DATE:20131014 -DTSTAMP:20140208T185114Z -UID:4lgtcol5pdilgjipr6jv5uc200@google.com -CREATED:20130208T191917Z -DESCRIPTION:http://python.ie/ -LAST-MODIFIED:20130208T191917Z -LOCATION:Dublin -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Ireland -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130313 -DTEND;VALUE=DATE:20130322 -DTSTAMP:20140208T185114Z -UID:cl9rqa2hauj9c1m8ir6c3pgblc@google.com -CREATED:20120912T021247Z -DESCRIPTION:PyCon US 2012 -LAST-MODIFIED:20130207T023434Z -LOCATION:Santa Clara\, CA\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon US 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130525 -DTEND;VALUE=DATE:20130527 -DTSTAMP:20140208T185114Z -UID:ml05rg28jv4g4eq924rq0pfsj8@google.com -CREATED:20130131T233752Z -DESCRIPTION:PyCon Taiwan 2013 -LAST-MODIFIED:20130131T233752Z -LOCATION:Academia Sinica\, Taipei\, Taiwan -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Taiwan 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130202 -DTEND;VALUE=DATE:20130204 -DTSTAMP:20140208T185114Z -UID:jkg8tmojm401caj5k9ro3sds9k@google.com -CREATED:20130131T134247Z -DESCRIPTION:https://fosdem.org/2013/ -LAST-MODIFIED:20130131T134247Z -LOCATION:Brussels\, Belgium -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:FOSDEM 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130930 -DTEND;VALUE=DATE:20131012 -DTSTAMP:20140208T185114Z -UID:neu6hdq13ptk4j2pmr52npag10@google.com -ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Python - Events Calendar;X-NUM-GUESTS=0:mailto:j7gov1cmnqr9tvg14k621j7t5c@group.cal - endar.google.com -CREATED:20130117T231906Z -DESCRIPTION:Plone Conference 2013 -LAST-MODIFIED:20130118T220634Z -LOCATION:Ulysses Guimarães Convention Center\, Brasilia\, Federal District\ - , Brazil -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Plone Conference 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130930 -DTEND;VALUE=DATE:20131012 -DTSTAMP:20140208T185114Z -UID:4iul8bt18both5dsamsojpdmog@google.com -ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Python - Events Calendar;X-NUM-GUESTS=0:mailto:j7gov1cmnqr9tvg14k621j7t5c@group.cal - endar.google.com -CREATED:20130117T231759Z -DESCRIPTION:PythonBrasil 2013 -LAST-MODIFIED:20130118T220625Z -LOCATION:Ulysses Guimarães Convention Center\, Brasilia\, Federal District\ - , Brazil -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PythonBrasil 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130224 -DTEND;VALUE=DATE:20130226 -DTSTAMP:20140208T185114Z -UID:324gfoat0ksia284mr8kmma3n8@google.com -CREATED:20121115T231736Z -DESCRIPTION:PyCon Russia 2013 in Yekateri - nburg -LAST-MODIFIED:20130116T235011Z -LOCATION:Yekaterinburg -SEQUENCE:1 -STATUS:CONFIRMED -SUMMARY:PyCon Russia 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130318 -DTEND;VALUE=DATE:20130321 -DTSTAMP:20140208T185114Z -UID:hp4airqcsi08ijthtjrau01jtg@google.com -CREATED:20121214T002539Z -DESCRIPTION:PyData Silicon Valley 2013 -LAST-MODIFIED:20121214T002540Z -LOCATION:Santa Clara Convention Center\, Santa Clara\, CA\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyData Silicon Valley 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART:20121216T091500Z -DTEND:20121216T161500Z -DTSTAMP:20140208T185114Z -UID:oh5cujs4k3jbi3j06kivrmj854@google.com -CLASS:PUBLIC -CREATED:20121209T102259Z -DESCRIPTION:PyData Workshop-Sprint 2012 at NYC\n\nAre you interested in a o - ne-day hands-on intensive Pandas workshop and sprint for new contributors w - ith a Pandas core-dev leading the sprint?\n\nObjective\n\nThe aim of this w - orkshop and sprint is to encourage and rope in more bug triagers and new co - ntributors to scientific programming in Python\, by teaching attendees abou - t data processing tools in Python\, and have them contribute a patch to Pan - das (or any other PyData stack). \n\nMore Information\n\nhttps://github.com - /svaksha/PyData-Workshop-Sprint/wiki/2012-NYC -LAST-MODIFIED:20121209T103624Z -LOCATION:Pivotal Labs\, 841 Broadway New York\, NY\, New York\, NY\, http:/ - /pivotallabs.com/ -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyData Workshop-Sprint 2012 at NYC -TRANSP:OPAQUE -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130624 -DTEND;VALUE=DATE:20130630 -DTSTAMP:20140208T185114Z -UID:vbnrfhoi0spaojjep7m870p4a8@google.com -CREATED:20121205T160700Z -DESCRIPTION:SciPy 2013 -LAST-MODIFIED:20121205T160700Z -LOCATION:Austin\, TX\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:SciPy 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20130705 -DTEND;VALUE=DATE:20130708 -DTSTAMP:20140208T185114Z -UID:uor3bphhm13koa6fv8qm9f6o9o@google.com -CREATED:20121205T160547Z -DESCRIPTION:PyCon Australia 2013 -LAST-MODIFIED:20121205T160547Z -LOCATION:Hobart\, Australia -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Australia 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART:20121116T153000Z -DTEND:20121116T193000Z -DTSTAMP:20140208T185114Z -UID:b7ioj3qf18n0118mdlhge0f6ec@google.com -CREATED:20121025T040020Z -DESCRIPTION:Python for High Performance and Scientific Computing PyHPC 2012 -LAST-MODIFIED:20121025T040020Z -LOCATION:Salt Lake City\, Utah\, USA -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyHPC 2012 -TRANSP:OPAQUE -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121208 -DTEND;VALUE=DATE:20121210 -DTSTAMP:20140208T185114Z -UID:nf18tfpnlhm6trd8u039god1mk@google.com -CREATED:20121022T154331Z -DESCRIPTION:RuPy 2012 - Brazil Edition -LAST-MODIFIED:20121022T161019Z -LOCATION:São José dos Campos\, São Paulo\, Brazil -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:RuPy 2012 - Brazil Edition -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121116 -DTEND;VALUE=DATE:20121119 -DTSTAMP:20140208T185114Z -UID:3q8q8ojsktdkq0r69s901ulp4o@google.com -CREATED:20121022T154229Z -DESCRIPTION:RuPy 2012 - Brno Edition -LAST-MODIFIED:20121022T160950Z -LOCATION:Brno\, Czech Republic -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:RuPy 2012 - Brno Edition -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121020 -DTEND;VALUE=DATE:20121022 -DTSTAMP:20140208T185114Z -UID:eio3nic7gr16e5t8glcj9mshjc@google.com -CREATED:20121011T224120Z -DESCRIPTION:PyCon China 2012 will be held - on 2012-10-20 in 7 cities. Include Shanghai (Two days conference)\, BeiJin - g (One day conference)\, Zhuhai\, Xian\, Hangzhou\, Hefei\, Wuhan. -LAST-MODIFIED:20121011T224120Z -LOCATION:Shanghai\, Beijing\, Zhuhai\, Xian\, Hangzhou\, Hefei and Wuhan -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon China 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121008 -DTEND;VALUE=DATE:20121013 -DTSTAMP:20140208T185114Z -UID:9m75bs7abfepcq8u3eg82ojl5k@google.com -CREATED:20120910T204121Z -DESCRIPTION:Plone Conference 2012 -LAST-MODIFIED:20120913T085322Z -LOCATION:Arnheim\, The Netherlands -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Plone Conference 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121022 -DTEND;VALUE=DATE:20121024 -DTSTAMP:20140208T185114Z -UID:g20bk4cooh2lau6p9t2irm8rd4@google.com -CREATED:20120910T204508Z -DESCRIPTION:PyCon Finland 2012 -LAST-MODIFIED:20120913T085214Z -LOCATION:Otaniemi\, Finland -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Finland 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20120915 -DTEND;VALUE=DATE:20120917 -DTSTAMP:20140208T185114Z -UID:bkm09cc8gghnkh2mr0b5e43u5s@google.com -CREATED:20120912T133937Z -DESCRIPTION:PyCon Japan 2012 -LAST-MODIFIED:20120912T203007Z -LOCATION:The Advanced Institute of Industrial Technology\, Tokyo\, Japan -SEQUENCE:1 -STATUS:CONFIRMED -SUMMARY:PyCon Japan 2012 -TRANSP:OPAQUE -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20120913 -DTEND;VALUE=DATE:20120917 -DTSTAMP:20140208T185114Z -UID:tikr8pd19jo4nb5qef7urfpd9g@google.com -CREATED:20120910T203711Z -DESCRIPTION:PyCon FR 2012 -LAST-MODIFIED:20120912T202903Z -LOCATION:Paris\, France -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon FR 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20131014 -DTEND;VALUE=DATE:20131020 -DTSTAMP:20140208T185114Z -UID:1vehea30ifl7ulrpgneq6i7vkc@google.com -CREATED:20120912T183727Z -DESCRIPTION:PyCon DE 2013 -LAST-MODIFIED:20120912T183727Z -LOCATION:Cologne\, Germany -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon DE 2013 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121110 -DTEND;VALUE=DATE:20121112 -DTSTAMP:20140208T185114Z -UID:ps0m0ilk540jk6iefa4unnik6s@google.com -CREATED:20120912T092509Z -DESCRIPTION:PyCon Uruguay 2012 -LAST-MODIFIED:20120912T092606Z -LOCATION:Laboratorio Tecnológico del Uruguay\, Montevideo\, Uruguay -SEQUENCE:1 -STATUS:CONFIRMED -SUMMARY:PyCon Uruguay 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121109 -DTEND;VALUE=DATE:20121112 -DTSTAMP:20140208T185114Z -UID:qbmkbm56usob6cibme2iatp718@google.com -CREATED:20120911T190144Z -DESCRIPTION:PyCon Canada 2012 -LAST-MODIFIED:20120911T203141Z -LOCATION:Toronto\, Canada -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Canada 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121027 -DTEND;VALUE=DATE:20121028 -DTSTAMP:20140208T185114Z -UID:jkhcbfip9ca9hrllotge5utcgg@google.com -CREATED:20120911T203126Z -DESCRIPTION:pyArkansas 2012 -LAST-MODIFIED:20120911T203126Z -LOCATION:Conway\, Arkansas -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:pyArkansas 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121029 -DTEND;VALUE=DATE:20121104 -DTSTAMP:20140208T185114Z -UID:j1a58ogo8q5kos9jkgpoc4bits@google.com -CREATED:20120910T204344Z -DESCRIPTION:PyCon DE 2012 -LAST-MODIFIED:20120910T214025Z -LOCATION:Leipzig\, Germany -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon DE 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121004 -DTEND;VALUE=DATE:20121006 -DTSTAMP:20140208T185114Z -UID:5rj0g1jmqg967oa3i10jbobm0k@google.com -CREATED:20120910T212220Z -DESCRIPTION:PyCon ZA 2012 -LAST-MODIFIED:20120910T214001Z -LOCATION:Cape Town\, South Africa -SEQUENCE:1 -STATUS:CONFIRMED -SUMMARY:PyCon ZA 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20120928 -DTEND;VALUE=DATE:20121001 -DTSTAMP:20140208T185114Z -UID:jdh5apv81h3s19v5kk7o555q2s@google.com -CREATED:20120910T213444Z -DESCRIPTION:PyCon India -LAST-MODIFIED:20120910T213952Z -LOCATION:Bangalore\, India -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon India 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121121 -DTEND;VALUE=DATE:20121125 -DTSTAMP:20140208T185114Z -UID:93rvgc214vvb6d1ibit5s2dkrs@google.com -CREATED:20120910T212038Z -DESCRIPTION:Python Brazil 2012 -LAST-MODIFIED:20120910T212038Z -LOCATION:Rio de Janeiro\, Brazil -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:Python Brazil 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121112 -DTEND;VALUE=DATE:20121118 -DTSTAMP:20140208T185114Z -UID:ijrl1ag0k4q0a1k0qpkk5qlq2o@google.com -CREATED:20120910T211905Z -DESCRIPTION:PyCon Argentin - a 2012 -LAST-MODIFIED:20120910T211905Z -LOCATION:Quilmes\, Buenos Aires\, Argentina -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Argentina 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121020 -DTEND;VALUE=DATE:20121022 -DTSTAMP:20140208T185114Z -UID:ret29v2870qqq9a1akfu31em6o@google.com -CREATED:20120910T204435Z -DESCRIPTION:PyCon Ukraine 2012 -LAST-MODIFIED:20120910T210947Z -LOCATION:Kiew\, Ukraine -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon Ukraine 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20121013 -DTEND;VALUE=DATE:20121015 -DTSTAMP:20140208T185114Z -UID:37nkh2c4mq6mp0enulvtqdbk24@google.com -CREATED:20120910T204157Z -DESCRIPTION:PyCon Ireland 2012 -LAST-MODIFIED:20120910T210858Z -LOCATION:Dublin\, Ireland -SEQUENCE:1 -STATUS:CONFIRMED -SUMMARY:PyCon Ireland 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20120928 -DTEND;VALUE=DATE:20121001 -DTSTAMP:20140208T185114Z -UID:a058vod294alfr78f2f9l5naek@google.com -CREATED:20120910T204028Z -DESCRIPTION:PyCon UK 2012 -LAST-MODIFIED:20120910T210818Z -LOCATION:Coventry\, UK -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon UK 2012 -TRANSP:TRANSPARENT -END:VEVENT -BEGIN:VEVENT -DTSTART;VALUE=DATE:20120913 -DTEND;VALUE=DATE:20120917 -DTSTAMP:20140208T185114Z -UID:00rbudjl24p1ov678bp08itri4@google.com -CREATED:20120910T203803Z -DESCRIPTION:PyCon PL 2012 -LAST-MODIFIED:20120910T210739Z -LOCATION:Masłów\, Poland -SEQUENCE:0 -STATUS:CONFIRMED -SUMMARY:PyCon PL 2012 -TRANSP:TRANSPARENT -END:VEVENT -END:VCALENDAR +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-WR-CALNAME:Python Events Calendar +X-WR-TIMEZONE:Etc/GMT +X-WR-CALDESC:Calendar showing Python conference and user group meeting date + s. +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140516 +DTEND;VALUE=DATE:20140519 +DTSTAMP:20140208T185114Z +UID:0dpji3hft657pi6cgradu20rro@google.com +CREATED:20140205T213025Z +DESCRIPTION:PyCon APAC 2014 +LAST-MODIFIED:20140205T213025Z +LOCATION:Academia Sinica\, Taipei\, Taiwan +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon APAC 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140618 +DTEND;VALUE=DATE:20140621 +DTSTAMP:20140208T185114Z +UID:4634mvl5jnlgbtadsfujf1j6kk@google.com +CREATED:20140205T212909Z +DESCRIPTION:PyCon Singapore 2014 +LAST-MODIFIED:20140205T212909Z +LOCATION:Singapore Polytechnic (SP)\, 500 Dover Road\, Singapore 139651 +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Singapore 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140513 +DTEND;VALUE=DATE:20140518 +DTSTAMP:20140208T185114Z +UID:elv2tjohtchcfq3js8b58sp35k@google.com +CREATED:20140205T205101Z +DESCRIPTION:Djangocon Europe 2014 +LAST-MODIFIED:20140205T205101Z +LOCATION:L'Île des Embiez\, Var\, France +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Djangocon Europe 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140726 +DTEND;VALUE=DATE:20140728 +DTSTAMP:20140208T185114Z +UID:m6oiipchdeu2buo2id8ku6g9lg@google.com +CREATED:20140130T103507Z +DESCRIPTION:PyOhio 2014 +LAST-MODIFIED:20140130T103507Z +LOCATION:Columbus\, OH USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyOhio 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140314 +DTEND;VALUE=DATE:20140315 +DTSTAMP:20140208T185114Z +UID:c67i38nf1npuau10ue9nli127k@google.com +CREATED:20140127T123759Z +DESCRIPTION:Conference "for Pytho + n Quants" +LAST-MODIFIED:20140127T123759Z +LOCATION:Executive Conference Center\, 8th Fl\, 1601 Broadway\, NY\, NY\, 1 + 0036\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Conference "for Python Quants" +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140201 +DTEND;VALUE=DATE:20140203 +DTSTAMP:20140208T185114Z +UID:u81fjn1b72ack9ahm1tb30bab0@google.com +CREATED:20140122T140602Z +DESCRIPTION:FOSDEM 2014 with a Python Developer Room on Sunday\ + , Feb 2nd. +LAST-MODIFIED:20140122T140602Z +LOCATION:Université libre de Bruxelles\, Campus du Solbosch\, Avenue Frankl + in D. Roosevelt 50\, 1050 Bruxelles\, Belgium +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:FOSDEM 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140613 +DTEND;VALUE=DATE:20140616 +DTSTAMP:20140208T185114Z +UID:mamkq4rnbbe587ot9doagk2mjc@google.com +CREATED:20140120T172328Z +DESCRIPTION:Full details on the conf + erence website +LAST-MODIFIED:20140120T172328Z +LOCATION:Orvieto\, Terni\, Italy +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:DjangoVillage +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140207 +DTEND;VALUE=DATE:20140210 +DTSTAMP:20140208T185114Z +UID:fji4c5184i3p23enm8e1umkvp8@google.com +CREATED:20140120T103025Z +DESCRIPTION:Django Weekend Cardiff +LAST-MODIFIED:20140120T103025Z +LOCATION:Cardiff University\, Cardiff\, Wales\, UK +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Django Weekend Cardiff +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140221 +DTEND;VALUE=DATE:20140224 +DTSTAMP:20140208T185114Z +UID:6shlu35o5vgqm7kiue9qpt77u4@google.com +CREATED:20140118T202358Z +DESCRIPTION:PyData London 2014 +LAST-MODIFIED:20140118T202738Z +LOCATION:Level39\, One Canada Square\, Canary Wharf\, E14 5AB\, UK +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyData London 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140801 +DTEND;VALUE=DATE:20140806 +DTSTAMP:20140208T185114Z +UID:87ijl7np9urrlnbtlt3f21etug@google.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Python + Events Calendar;X-NUM-GUESTS=0:mailto:j7gov1cmnqr9tvg14k621j7t5c@group.cal + endar.google.com +CREATED:20140115T021111Z +DESCRIPTION:PyCon Australia 2014 +LAST-MODIFIED:20140115T021249Z +LOCATION:Brisbane\, Australia +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Australia 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140706 +DTEND;VALUE=DATE:20140713 +DTSTAMP:20140208T185114Z +UID:u8n3mam03ba47pmtec54sdr1ro@google.com +CREATED:20140115T021240Z +DESCRIPTION:SciPy 2014 +LAST-MODIFIED:20140115T021241Z +LOCATION:Austin\, TX\, United States +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:SciPy 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140329 +DTEND;VALUE=DATE:20140331 +DTSTAMP:20140208T185114Z +UID:cbnul786umrb5o4o84pfi8pqk8@google.com +CREATED:20140114T165443Z +DESCRIPTION:PythonCamp 2 + 014 +LAST-MODIFIED:20140114T165443Z +LOCATION:GFU Cyrus AG\, Am Grauen Stein 27\, 51105 Cologne +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PythonCamp 2014 - Python Bar Camp in Cologne +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140222 +DTEND;VALUE=DATE:20140224 +DTSTAMP:20140208T185114Z +UID:jpjq2oi33tkft2nll0tcohs3i0@google.com +CREATED:20140106T082236Z +DESCRIPTION:PyCon PH 2014 at \nDe La Salle University +LAST-MODIFIED:20140106T082236Z +LOCATION:De La Salle University\, 2401 Taft Avenue\, 1004 Manila\, Philippi + nes +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon PH 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART:20131208T010000Z +DTEND:20131208T100000Z +DTSTAMP:20140208T185114Z +UID:djtvr1jdnjifs9etni3t53ste4@google.com +CREATED:20131201T230024Z +DESCRIPTION:PyCon China 2014 +LAST-MODIFIED:20131201T230127Z +LOCATION:Shanghai\, Zhuhai and Hangzhou\, China +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon China 2014 +TRANSP:OPAQUE +END:VEVENT +BEGIN:VEVENT +DTSTART:20131214T010000Z +DTEND:20131214T100000Z +DTSTAMP:20140208T185114Z +UID:efic4423me14thbb9d4mg96754@google.com +CREATED:20131201T230113Z +DESCRIPTION:PyCon China 2014 +LAST-MODIFIED:20131201T230113Z +LOCATION:Beijing\, China +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon China 2014 +TRANSP:OPAQUE +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140721 +DTEND;VALUE=DATE:20140728 +DTSTAMP:20140208T185114Z +UID:iigilv0r74hhbs8kbfvja7h5fc@google.com +CREATED:20131019T193502Z +DESCRIPTION:EuroPython 2014 +LAST-MODIFIED:20131019T193502Z +LOCATION:Berlin\, Germany +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:EuroPython 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131017 +DTEND;VALUE=DATE:20131021 +DTSTAMP:20140208T185114Z +UID:0jh68f868hfv3l4i1t6s8l33eo@google.com +CREATED:20131012T225812Z +DESCRIPTION:PyCon Poland 2013 +LAST-MODIFIED:20131012T225826Z +LOCATION:„Orle Gniazdo” („Eagle's Nest”) Congress and Recreation Center in + Szczyrk +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Poland 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131026 +DTEND;VALUE=DATE:20131030 +DTSTAMP:20140208T185114Z +UID:vcfe0v28mp3g2p24ne189ol06k@google.com +CREATED:20131004T183105Z +DESCRIPTION:PyCon FR 2013 +LAST-MODIFIED:20131004T183105Z +LOCATION:Strasbourg\, France +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon FR 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131101 +DTEND;VALUE=DATE:20131102 +DTSTAMP:20140208T185114Z +UID:e1p10ro1ek2k1bfsihsk7rp3k8@google.com +CREATED:20131002T120707Z +DESCRIPTION:PyCon Iran 2013 +LAST-MODIFIED:20131002T234550Z +LOCATION:Tehran\, Iran +SEQUENCE:1 +STATUS:CONFIRMED +SUMMARY:PyCon Iran 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131003 +DTEND;VALUE=DATE:20131005 +DTSTAMP:20140208T185114Z +UID:1ccibtmc51p3a4kscbjivo9pag@google.com +CREATED:20130926T082215Z +DESCRIPTION:PyConZA 2013 +LAST-MODIFIED:20130926T082215Z +LOCATION:Cape Town\, South Africa +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyConZA 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131101 +DTEND;VALUE=DATE:20131103 +DTSTAMP:20140208T185114Z +UID:j8orn9jp861v0b26cung8k0bj8@google.com +CREATED:20130926T050621Z +DESCRIPTION:PyCon Uruguay 2013 +LAST-MODIFIED:20130926T050645Z +LOCATION:Montevideo\, Uruguay +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Uruguay 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131108 +DTEND;VALUE=DATE:20131111 +DTSTAMP:20140208T185114Z +UID:o3psu9qiqcas5hcn1lo2d73fao@google.com +CREATED:20130906T210915Z +DESCRIPTION:PyData NYC 2013 +LAST-MODIFIED:20130906T210915Z +LOCATION:1 Chase Manhattan Plaza\, New York City\, NY\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyData NYC 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140222 +DTEND;VALUE=DATE:20140224 +DTSTAMP:20140208T185114Z +UID:2a1ebu3dhr6ppfc656blqin4qk@google.com +CREATED:20130904T122445Z +DESCRIPTION:PyTennessee 2014 +LAST-MODIFIED:20130904T122445Z +LOCATION:Nashville School of Law\, Nashville\, TN\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyTennessee 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130831 +DTEND;VALUE=DATE:20130902 +DTSTAMP:20140208T185114Z +UID:oqtqbi8qja2tllnmijt7ptjsu0@google.com +CREATED:20130820T092236Z +DESCRIPTION:PyCon India 2013 +LAST-MODIFIED:20130820T092236Z +LOCATION:Bangalore\, India +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon India 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130727 +DTEND;VALUE=DATE:20130729 +DTSTAMP:20140208T185114Z +UID:8e858mcc7riq7s5lfspju4hqms@google.com +CREATED:20130719T080530Z +DESCRIPTION:PyData Boston 2013 +LAST-MODIFIED:20130719T080530Z +LOCATION:Microsoft NERD\, Cambridge\, MA\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyData Boston 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20140409 +DTEND;VALUE=DATE:20140418 +DTSTAMP:20140208T185114Z +UID:i2vt342est3ki3o0pfnp1jtgsc@google.com +CREATED:20130511T122254Z +DESCRIPTION:PyCon US 2014 +LAST-MODIFIED:20130716T082226Z +LOCATION:Montreal\, Canada +SEQUENCE:1 +STATUS:CONFIRMED +SUMMARY:PyCon US 2014 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131122 +DTEND;VALUE=DATE:20131125 +DTSTAMP:20140208T185114Z +UID:snb7f46skllv04svdsa1odpge0@google.com +CREATED:20130606T104007Z +DESCRIPTION:PyCon Spain 2013 +LAST-MODIFIED:20130715T115225Z +LOCATION:EU Informática\, Universidad Politécnica de Madrid\, Madrid\, Spai + n +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Spain 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131021 +DTEND;VALUE=DATE:20131023 +DTSTAMP:20140208T185114Z +UID:dcihgnimpqtfqch1co0q65fl9g@google.com +CREATED:20130609T111749Z +DESCRIPTION:PyCon Finland 2013 +LAST-MODIFIED:20130715T115057Z +LOCATION:Otaniemi\, Espoo\, Finland +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Finland 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130920 +DTEND;VALUE=DATE:20130924 +DTSTAMP:20140208T185114Z +UID:ihai7bc5isn0v7k26s7603aiio@google.com +CREATED:20130121T131625Z +DESCRIPTION:PyCon UK 2013 +LAST-MODIFIED:20130715T114945Z +LOCATION:Coventry\, UK +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon UK 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130824 +DTEND;VALUE=DATE:20130826 +DTSTAMP:20140208T185114Z +UID:9uvii4cr43pbaue6ji5uej5398@google.com +CREATED:20130614T205959Z +DESCRIPTION:FrOSCon 2013 - Fre + e and Open Source Software Conference (with Python track) +LAST-MODIFIED:20130614T205959Z +LOCATION:Sankt Augustin\, Germany +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:FrOSCon 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130504 +DTEND;VALUE=DATE:20130506 +DTSTAMP:20140208T185114Z +UID:ob367di2jkh4lopj81vubtpojo@google.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Python + Events Calendar;X-NUM-GUESTS=0:mailto:j7gov1cmnqr9tvg14k621j7t5c@group.cal + endar.google.com +CREATED:20121025T075159Z +DESCRIPTION:PythonCamp 2013 - Ein B + arcamp zum Thema Python +LAST-MODIFIED:20130605T195520Z +LOCATION:Cologne\, Germany +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PythonCamp 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130909 +DTEND;VALUE=DATE:20130914 +DTSTAMP:20140208T185114Z +UID:ni8phh2vocilu08fd7e4uqvo30@google.com +CREATED:20130605T195005Z +DESCRIPTION:Seattle PyCamp + 2013 +LAST-MODIFIED:20130605T195005Z +LOCATION:Seattle\, WA\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY: Seattle PyCamp 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130812 +DTEND;VALUE=DATE:20130817 +DTSTAMP:20140208T185114Z +UID:mdl5qe7obelgri739u1muomq5k@google.com +CREATED:20130605T194913Z +DESCRIPTION:Toronto PyCamp + 2013 +LAST-MODIFIED:20130605T194913Z +LOCATION:Toronto\, ON\, Canada +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Toronto PyCamp 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130805 +DTEND;VALUE=DATE:20130810 +DTSTAMP:20140208T185114Z +UID:pmf3ovjm5fa4j1fpo2ns6p6f38@google.com +CREATED:20130605T194822Z +DESCRIPTION:Python Web Pr + ogramming Workshop +LAST-MODIFIED:20130605T194822Z +LOCATION:Chapel Hill\, NC\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Python Web Programming Workshop +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130722 +DTEND;VALUE=DATE:20130727 +DTSTAMP:20140208T185114Z +UID:31npklj9g1l2b59rdihte7aat4@google.com +CREATED:20130605T194722Z +DESCRIPTION:PyOhio PyCamp + 2013 +LAST-MODIFIED:20130605T194722Z +LOCATION:Columbus\, OH\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyOhio PyCamp 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131011 +DTEND;VALUE=DATE:20131014 +DTSTAMP:20140208T185114Z +UID:sfg4jhcahcbm2u93a8p7gt9r98@google.com +CREATED:20130326T080431Z +DESCRIPTION:RuPy 2013 +LAST-MODIFIED:20130511T124016Z +LOCATION:Budapest\, Hungary +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:RuPy 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130524 +DTEND;VALUE=DATE:20130526 +DTSTAMP:20140208T185114Z +UID:5a0vj73lku9s6sauemeurpgsjc@google.com +CREATED:20130415T100523Z +DESCRIPTION:PythonNordeste 2013 +LAST-MODIFIED:20130511T123912Z +LOCATION:Fortaleza\, Ceará\, Brazil +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PythonNordeste 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130515 +DTEND;VALUE=DATE:20130518 +DTSTAMP:20140208T185114Z +UID:2i2rcneg3b7gkc4q5s58l9ticg@google.com +CREATED:20130121T125304Z +DESCRIPTION:DjangoCon Europe 2013 +LAST-MODIFIED:20130511T123902Z +LOCATION:Warsaw\, Poland +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:DjangoCon Europe 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130613 +DTEND;VALUE=DATE:20130616 +DTSTAMP:20140208T185114Z +UID:jskaup72s08h41uinb8jktuktk@google.com +CREATED:20130205T115419Z +DESCRIPTION:PyCon Singapore 2013 +LAST-MODIFIED:20130511T123850Z +LOCATION:Singapore +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Singapore 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130701 +DTEND;VALUE=DATE:20130708 +DTSTAMP:20140208T185114Z +UID:kkjgb6hrfdc60l8h30j9pj029c@google.com +CREATED:20130121T131729Z +DESCRIPTION:EuroSciPy 2013 +LAST-MODIFIED:20130511T123805Z +LOCATION:Brussels\, Belgium +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:EuroSciPy 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130809 +DTEND;VALUE=DATE:20130814 +DTSTAMP:20140208T185114Z +UID:g9mjr24lb5n7nbb4uf95llvik0@google.com +CREATED:20130306T165642Z +DESCRIPTION:PyCon Canada 2013\n +LAST-MODIFIED:20130511T123752Z +LOCATION:Toronto\, Canada +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Canada 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130906 +DTEND;VALUE=DATE:20130909 +DTSTAMP:20140208T185114Z +UID:gf7gt7n75qsn7d359hc8kum3r4@google.com +CREATED:20130511T120941Z +DESCRIPTION:Kiwi PyCon 2013 +LAST-MODIFIED:20130511T123716Z +LOCATION:Auckland\, New Zealand +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Kiwi PyCon 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130727 +DTEND;VALUE=DATE:20130729 +DTSTAMP:20140208T185114Z +UID:umtv2r1qi4a8iqnn0fv38o9ok8@google.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Python + Events Calendar;X-NUM-GUESTS=0:mailto:j7gov1cmnqr9tvg14k621j7t5c@group.cal + endar.google.com +CREATED:20130114T012524Z +DESCRIPTION:PyOhio 2013 +LAST-MODIFIED:20130405T025124Z +LOCATION:Ohio Union\, Columbus\, OH +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyOhio 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130405 +DTEND;VALUE=DATE:20130406 +DTSTAMP:20140208T185114Z +UID:lqau72c8o889tklo45o91jv5mk@google.com +CREATED:20130325T194752Z +DESCRIPTION:http://www.python-i + n-finance.com/ +LAST-MODIFIED:20130325T194752Z +LOCATION:New York\, NY\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Python in Finance +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130510 +DTEND;VALUE=DATE:20130511 +DTSTAMP:20140208T185114Z +UID:ra1qh5nerakgkotunqbvtbnvjg@google.com +CREATED:20130315T104413Z +DESCRIPTION:http://www.pygrunn.org/ +LAST-MODIFIED:20130315T104413Z +LOCATION:Groningen\, The Netherlands +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyGrunn 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131012 +DTEND;VALUE=DATE:20131014 +DTSTAMP:20140208T185114Z +UID:4lgtcol5pdilgjipr6jv5uc200@google.com +CREATED:20130208T191917Z +DESCRIPTION:http://python.ie/ +LAST-MODIFIED:20130208T191917Z +LOCATION:Dublin +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Ireland +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130313 +DTEND;VALUE=DATE:20130322 +DTSTAMP:20140208T185114Z +UID:cl9rqa2hauj9c1m8ir6c3pgblc@google.com +CREATED:20120912T021247Z +DESCRIPTION:PyCon US 2012 +LAST-MODIFIED:20130207T023434Z +LOCATION:Santa Clara\, CA\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon US 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130525 +DTEND;VALUE=DATE:20130527 +DTSTAMP:20140208T185114Z +UID:ml05rg28jv4g4eq924rq0pfsj8@google.com +CREATED:20130131T233752Z +DESCRIPTION:PyCon Taiwan 2013 +LAST-MODIFIED:20130131T233752Z +LOCATION:Academia Sinica\, Taipei\, Taiwan +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Taiwan 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130202 +DTEND;VALUE=DATE:20130204 +DTSTAMP:20140208T185114Z +UID:jkg8tmojm401caj5k9ro3sds9k@google.com +CREATED:20130131T134247Z +DESCRIPTION:https://fosdem.org/2013/ +LAST-MODIFIED:20130131T134247Z +LOCATION:Brussels\, Belgium +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:FOSDEM 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130930 +DTEND;VALUE=DATE:20131012 +DTSTAMP:20140208T185114Z +UID:neu6hdq13ptk4j2pmr52npag10@google.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Python + Events Calendar;X-NUM-GUESTS=0:mailto:j7gov1cmnqr9tvg14k621j7t5c@group.cal + endar.google.com +CREATED:20130117T231906Z +DESCRIPTION:Plone Conference 2013 +LAST-MODIFIED:20130118T220634Z +LOCATION:Ulysses Guimarães Convention Center\, Brasilia\, Federal District\ + , Brazil +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Plone Conference 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130930 +DTEND;VALUE=DATE:20131012 +DTSTAMP:20140208T185114Z +UID:4iul8bt18both5dsamsojpdmog@google.com +ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Python + Events Calendar;X-NUM-GUESTS=0:mailto:j7gov1cmnqr9tvg14k621j7t5c@group.cal + endar.google.com +CREATED:20130117T231759Z +DESCRIPTION:PythonBrasil 2013 +LAST-MODIFIED:20130118T220625Z +LOCATION:Ulysses Guimarães Convention Center\, Brasilia\, Federal District\ + , Brazil +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PythonBrasil 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130224 +DTEND;VALUE=DATE:20130226 +DTSTAMP:20140208T185114Z +UID:324gfoat0ksia284mr8kmma3n8@google.com +CREATED:20121115T231736Z +DESCRIPTION:PyCon Russia 2013 in Yekateri + nburg +LAST-MODIFIED:20130116T235011Z +LOCATION:Yekaterinburg +SEQUENCE:1 +STATUS:CONFIRMED +SUMMARY:PyCon Russia 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130318 +DTEND;VALUE=DATE:20130321 +DTSTAMP:20140208T185114Z +UID:hp4airqcsi08ijthtjrau01jtg@google.com +CREATED:20121214T002539Z +DESCRIPTION:PyData Silicon Valley 2013 +LAST-MODIFIED:20121214T002540Z +LOCATION:Santa Clara Convention Center\, Santa Clara\, CA\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyData Silicon Valley 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART:20121216T091500Z +DTEND:20121216T161500Z +DTSTAMP:20140208T185114Z +UID:oh5cujs4k3jbi3j06kivrmj854@google.com +CLASS:PUBLIC +CREATED:20121209T102259Z +DESCRIPTION:PyData Workshop-Sprint 2012 at NYC\n\nAre you interested in a o + ne-day hands-on intensive Pandas workshop and sprint for new contributors w + ith a Pandas core-dev leading the sprint?\n\nObjective\n\nThe aim of this w + orkshop and sprint is to encourage and rope in more bug triagers and new co + ntributors to scientific programming in Python\, by teaching attendees abou + t data processing tools in Python\, and have them contribute a patch to Pan + das (or any other PyData stack). \n\nMore Information\n\nhttps://github.com + /svaksha/PyData-Workshop-Sprint/wiki/2012-NYC +LAST-MODIFIED:20121209T103624Z +LOCATION:Pivotal Labs\, 841 Broadway New York\, NY\, New York\, NY\, http:/ + /pivotallabs.com/ +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyData Workshop-Sprint 2012 at NYC +TRANSP:OPAQUE +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130624 +DTEND;VALUE=DATE:20130630 +DTSTAMP:20140208T185114Z +UID:vbnrfhoi0spaojjep7m870p4a8@google.com +CREATED:20121205T160700Z +DESCRIPTION:SciPy 2013 +LAST-MODIFIED:20121205T160700Z +LOCATION:Austin\, TX\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:SciPy 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20130705 +DTEND;VALUE=DATE:20130708 +DTSTAMP:20140208T185114Z +UID:uor3bphhm13koa6fv8qm9f6o9o@google.com +CREATED:20121205T160547Z +DESCRIPTION:PyCon Australia 2013 +LAST-MODIFIED:20121205T160547Z +LOCATION:Hobart\, Australia +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Australia 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART:20121116T153000Z +DTEND:20121116T193000Z +DTSTAMP:20140208T185114Z +UID:b7ioj3qf18n0118mdlhge0f6ec@google.com +CREATED:20121025T040020Z +DESCRIPTION:Python for High Performance and Scientific Computing PyHPC 2012 +LAST-MODIFIED:20121025T040020Z +LOCATION:Salt Lake City\, Utah\, USA +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyHPC 2012 +TRANSP:OPAQUE +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121208 +DTEND;VALUE=DATE:20121210 +DTSTAMP:20140208T185114Z +UID:nf18tfpnlhm6trd8u039god1mk@google.com +CREATED:20121022T154331Z +DESCRIPTION:RuPy 2012 - Brazil Edition +LAST-MODIFIED:20121022T161019Z +LOCATION:São José dos Campos\, São Paulo\, Brazil +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:RuPy 2012 - Brazil Edition +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121116 +DTEND;VALUE=DATE:20121119 +DTSTAMP:20140208T185114Z +UID:3q8q8ojsktdkq0r69s901ulp4o@google.com +CREATED:20121022T154229Z +DESCRIPTION:RuPy 2012 - Brno Edition +LAST-MODIFIED:20121022T160950Z +LOCATION:Brno\, Czech Republic +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:RuPy 2012 - Brno Edition +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121020 +DTEND;VALUE=DATE:20121022 +DTSTAMP:20140208T185114Z +UID:eio3nic7gr16e5t8glcj9mshjc@google.com +CREATED:20121011T224120Z +DESCRIPTION:PyCon China 2012 will be held + on 2012-10-20 in 7 cities. Include Shanghai (Two days conference)\, BeiJin + g (One day conference)\, Zhuhai\, Xian\, Hangzhou\, Hefei\, Wuhan. +LAST-MODIFIED:20121011T224120Z +LOCATION:Shanghai\, Beijing\, Zhuhai\, Xian\, Hangzhou\, Hefei and Wuhan +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon China 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121008 +DTEND;VALUE=DATE:20121013 +DTSTAMP:20140208T185114Z +UID:9m75bs7abfepcq8u3eg82ojl5k@google.com +CREATED:20120910T204121Z +DESCRIPTION:Plone Conference 2012 +LAST-MODIFIED:20120913T085322Z +LOCATION:Arnheim\, The Netherlands +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Plone Conference 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121022 +DTEND;VALUE=DATE:20121024 +DTSTAMP:20140208T185114Z +UID:g20bk4cooh2lau6p9t2irm8rd4@google.com +CREATED:20120910T204508Z +DESCRIPTION:PyCon Finland 2012 +LAST-MODIFIED:20120913T085214Z +LOCATION:Otaniemi\, Finland +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Finland 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20120915 +DTEND;VALUE=DATE:20120917 +DTSTAMP:20140208T185114Z +UID:bkm09cc8gghnkh2mr0b5e43u5s@google.com +CREATED:20120912T133937Z +DESCRIPTION:PyCon Japan 2012 +LAST-MODIFIED:20120912T203007Z +LOCATION:The Advanced Institute of Industrial Technology\, Tokyo\, Japan +SEQUENCE:1 +STATUS:CONFIRMED +SUMMARY:PyCon Japan 2012 +TRANSP:OPAQUE +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20120913 +DTEND;VALUE=DATE:20120917 +DTSTAMP:20140208T185114Z +UID:tikr8pd19jo4nb5qef7urfpd9g@google.com +CREATED:20120910T203711Z +DESCRIPTION:PyCon FR 2012 +LAST-MODIFIED:20120912T202903Z +LOCATION:Paris\, France +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon FR 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20131014 +DTEND;VALUE=DATE:20131020 +DTSTAMP:20140208T185114Z +UID:1vehea30ifl7ulrpgneq6i7vkc@google.com +CREATED:20120912T183727Z +DESCRIPTION:PyCon DE 2013 +LAST-MODIFIED:20120912T183727Z +LOCATION:Cologne\, Germany +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon DE 2013 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121110 +DTEND;VALUE=DATE:20121112 +DTSTAMP:20140208T185114Z +UID:ps0m0ilk540jk6iefa4unnik6s@google.com +CREATED:20120912T092509Z +DESCRIPTION:PyCon Uruguay 2012 +LAST-MODIFIED:20120912T092606Z +LOCATION:Laboratorio Tecnológico del Uruguay\, Montevideo\, Uruguay +SEQUENCE:1 +STATUS:CONFIRMED +SUMMARY:PyCon Uruguay 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121109 +DTEND;VALUE=DATE:20121112 +DTSTAMP:20140208T185114Z +UID:qbmkbm56usob6cibme2iatp718@google.com +CREATED:20120911T190144Z +DESCRIPTION:PyCon Canada 2012 +LAST-MODIFIED:20120911T203141Z +LOCATION:Toronto\, Canada +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Canada 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121027 +DTEND;VALUE=DATE:20121028 +DTSTAMP:20140208T185114Z +UID:jkhcbfip9ca9hrllotge5utcgg@google.com +CREATED:20120911T203126Z +DESCRIPTION:pyArkansas 2012 +LAST-MODIFIED:20120911T203126Z +LOCATION:Conway\, Arkansas +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:pyArkansas 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121029 +DTEND;VALUE=DATE:20121104 +DTSTAMP:20140208T185114Z +UID:j1a58ogo8q5kos9jkgpoc4bits@google.com +CREATED:20120910T204344Z +DESCRIPTION:PyCon DE 2012 +LAST-MODIFIED:20120910T214025Z +LOCATION:Leipzig\, Germany +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon DE 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121004 +DTEND;VALUE=DATE:20121006 +DTSTAMP:20140208T185114Z +UID:5rj0g1jmqg967oa3i10jbobm0k@google.com +CREATED:20120910T212220Z +DESCRIPTION:PyCon ZA 2012 +LAST-MODIFIED:20120910T214001Z +LOCATION:Cape Town\, South Africa +SEQUENCE:1 +STATUS:CONFIRMED +SUMMARY:PyCon ZA 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20120928 +DTEND;VALUE=DATE:20121001 +DTSTAMP:20140208T185114Z +UID:jdh5apv81h3s19v5kk7o555q2s@google.com +CREATED:20120910T213444Z +DESCRIPTION:PyCon India +LAST-MODIFIED:20120910T213952Z +LOCATION:Bangalore\, India +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon India 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121121 +DTEND;VALUE=DATE:20121125 +DTSTAMP:20140208T185114Z +UID:93rvgc214vvb6d1ibit5s2dkrs@google.com +CREATED:20120910T212038Z +DESCRIPTION:Python Brazil 2012 +LAST-MODIFIED:20120910T212038Z +LOCATION:Rio de Janeiro\, Brazil +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Python Brazil 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121112 +DTEND;VALUE=DATE:20121118 +DTSTAMP:20140208T185114Z +UID:ijrl1ag0k4q0a1k0qpkk5qlq2o@google.com +CREATED:20120910T211905Z +DESCRIPTION:PyCon Argentin + a 2012 +LAST-MODIFIED:20120910T211905Z +LOCATION:Quilmes\, Buenos Aires\, Argentina +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Argentina 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121020 +DTEND;VALUE=DATE:20121022 +DTSTAMP:20140208T185114Z +UID:ret29v2870qqq9a1akfu31em6o@google.com +CREATED:20120910T204435Z +DESCRIPTION:PyCon Ukraine 2012 +LAST-MODIFIED:20120910T210947Z +LOCATION:Kiew\, Ukraine +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon Ukraine 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121013 +DTEND;VALUE=DATE:20121015 +DTSTAMP:20140208T185114Z +UID:37nkh2c4mq6mp0enulvtqdbk24@google.com +CREATED:20120910T204157Z +DESCRIPTION:PyCon Ireland 2012 +LAST-MODIFIED:20120910T210858Z +LOCATION:Dublin\, Ireland +SEQUENCE:1 +STATUS:CONFIRMED +SUMMARY:PyCon Ireland 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20120928 +DTEND;VALUE=DATE:20121001 +DTSTAMP:20140208T185114Z +UID:a058vod294alfr78f2f9l5naek@google.com +CREATED:20120910T204028Z +DESCRIPTION:PyCon UK 2012 +LAST-MODIFIED:20120910T210818Z +LOCATION:Coventry\, UK +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon UK 2012 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20120913 +DTEND;VALUE=DATE:20120917 +DTSTAMP:20140208T185114Z +UID:00rbudjl24p1ov678bp08itri4@google.com +CREATED:20120910T203803Z +DESCRIPTION:PyCon PL 2012 +LAST-MODIFIED:20120910T210739Z +LOCATION:Masłów\, Poland +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:PyCon PL 2012 +TRANSP:TRANSPARENT +END:VEVENT +END:VCALENDAR diff --git a/events/tests/test_forms.py b/app/events/tests/test_forms.py similarity index 97% rename from events/tests/test_forms.py rename to app/events/tests/test_forms.py index b032ed12d..ade0364af 100644 --- a/events/tests/test_forms.py +++ b/app/events/tests/test_forms.py @@ -2,7 +2,7 @@ from django.test import SimpleTestCase -from ..forms import EventForm +from app.events.forms import EventForm class EventFormTests(SimpleTestCase): diff --git a/events/tests/test_importer.py b/app/events/tests/test_importer.py similarity index 100% rename from events/tests/test_importer.py rename to app/events/tests/test_importer.py diff --git a/events/tests/test_models.py b/app/events/tests/test_models.py similarity index 98% rename from events/tests/test_models.py rename to app/events/tests/test_models.py index 0f3bafe76..4563573a5 100644 --- a/events/tests/test_models.py +++ b/app/events/tests/test_models.py @@ -6,8 +6,8 @@ from dateutil.rrule import rrule, WEEKLY -from ..models import Calendar, Event, OccurringRule, RecurringRule -from ..utils import seconds_resolution, convert_dt_to_aware +from app.events.models import Calendar, Event, OccurringRule, RecurringRule +from app.events.utils import seconds_resolution, convert_dt_to_aware class EventsModelsTests(TestCase): diff --git a/events/tests/test_utils.py b/app/events/tests/test_utils.py similarity index 99% rename from events/tests/test_utils.py rename to app/events/tests/test_utils.py index 7e49223ec..374a36593 100644 --- a/events/tests/test_utils.py +++ b/app/events/tests/test_utils.py @@ -3,7 +3,7 @@ from django.utils import timezone from django.test import TestCase -from ..utils import ( +from app.events.utils import ( seconds_resolution, minutes_resolution, timedelta_nice_repr, timedelta_parse, ) diff --git a/events/tests/test_views.py b/app/events/tests/test_views.py similarity index 98% rename from events/tests/test_views.py rename to app/events/tests/test_views.py index 1291252a5..d8b0f5617 100644 --- a/events/tests/test_views.py +++ b/app/events/tests/test_views.py @@ -6,9 +6,9 @@ from django.test import TestCase from django.utils import timezone -from ..models import Calendar, Event, EventCategory, EventLocation, RecurringRule -from ..templatetags.events import get_events_upcoming -from users.factories import UserFactory +from app.events.models import Calendar, Event, EventCategory, EventLocation, RecurringRule +from app.events.templatetags.events import get_events_upcoming +from app.users.factories import UserFactory class EventsViewsTests(TestCase): diff --git a/events/urls.py b/app/events/urls.py similarity index 97% rename from events/urls.py rename to app/events/urls.py index 8bb2d0135..b7e55e5ef 100644 --- a/events/urls.py +++ b/app/events/urls.py @@ -1,6 +1,6 @@ from django.views.generic import TemplateView -from . import views +from app.events import views from django.urls import path, re_path app_name = 'events' diff --git a/events/utils.py b/app/events/utils.py similarity index 100% rename from events/utils.py rename to app/events/utils.py diff --git a/events/views.py b/app/events/views.py similarity index 94% rename from events/views.py rename to app/events/views.py index 56df88dcb..74d94a88a 100644 --- a/events/views.py +++ b/app/events/views.py @@ -7,10 +7,10 @@ from django.utils import timezone from django.views.generic import DetailView, ListView, FormView -from pydotorg.mixins import LoginRequiredMixin +from app.pydotorg.mixins import LoginRequiredMixin -from .models import Calendar, Event, EventCategory, EventLocation -from .forms import EventForm +from app.events.models import Calendar, Event, EventCategory, EventLocation +from app.events.forms import EventForm class CalendarList(ListView): @@ -40,7 +40,7 @@ def get_context_data(self, **kwargs): class EventHomepage(ListView): """ Main Event Landing Page """ - template_name = "events/event_list.html" + template_name = "event_list.html" def get_queryset(self) -> Event: """Queryset to return all events, ordered by START date.""" @@ -91,7 +91,7 @@ def get_context_data(self, **kwargs): class PastEventList(EventList): - template_name = 'events/event_list_past.html' + template_name = 'event_list_past.html' def get_queryset(self): return Event.objects.until_datetime(timezone.now()).filter(calendar__slug=self.kwargs['calendar_slug']) @@ -148,7 +148,7 @@ def get_queryset(self): class EventSubmit(LoginRequiredMixin, FormView): - template_name = 'events/event_form.html' + template_name = 'event_form.html' form_class = EventForm success_url = reverse_lazy('events:event_thanks') diff --git a/jobs/__init__.py b/app/fastly/__init__.py similarity index 100% rename from jobs/__init__.py rename to app/fastly/__init__.py diff --git a/fastly/models.py b/app/fastly/models.py similarity index 100% rename from fastly/models.py rename to app/fastly/models.py diff --git a/fastly/utils.py b/app/fastly/utils.py similarity index 100% rename from fastly/utils.py rename to app/fastly/utils.py diff --git a/jobs/management/__init__.py b/app/jobs/__init__.py similarity index 100% rename from jobs/management/__init__.py rename to app/jobs/__init__.py diff --git a/jobs/admin.py b/app/jobs/admin.py similarity index 86% rename from jobs/admin.py rename to app/jobs/admin.py index 7c811e95e..ec1ab076d 100644 --- a/jobs/admin.py +++ b/app/jobs/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin -from .models import JobType, JobCategory, Job, JobReviewComment -from cms.admin import NameSlugAdmin, ContentManageableModelAdmin +from app.jobs.models import JobType, JobCategory, Job, JobReviewComment +from app.cms.admin import NameSlugAdmin, ContentManageableModelAdmin @admin.register(Job) diff --git a/jobs/apps.py b/app/jobs/apps.py similarity index 69% rename from jobs/apps.py rename to app/jobs/apps.py index 92868a79c..6230d9821 100644 --- a/jobs/apps.py +++ b/app/jobs/apps.py @@ -3,8 +3,8 @@ class JobsAppConfig(AppConfig): - name = 'jobs' + name = 'app.jobs' verbose_name = 'Jobs Application' def ready(self): - import jobs.listeners + import app.jobs.listeners diff --git a/jobs/factories.py b/app/jobs/factories.py similarity index 97% rename from jobs/factories.py rename to app/jobs/factories.py index a8c38b423..959bd2a1a 100644 --- a/jobs/factories.py +++ b/app/jobs/factories.py @@ -7,9 +7,9 @@ from faker.providers import BaseProvider -from users.factories import UserFactory +from app.users.factories import UserFactory -from .models import JobType, JobCategory, Job +from app.jobs.models import JobType, JobCategory, Job class JobProvider(BaseProvider): diff --git a/jobs/feeds.py b/app/jobs/feeds.py similarity index 95% rename from jobs/feeds.py rename to app/jobs/feeds.py index b156d1c61..f05ad8a89 100644 --- a/jobs/feeds.py +++ b/app/jobs/feeds.py @@ -1,7 +1,7 @@ from django.contrib.syndication.views import Feed from django.urls import reverse_lazy -from .models import Job +from app.jobs.models import Job class JobFeed(Feed): diff --git a/jobs/forms.py b/app/jobs/forms.py similarity index 94% rename from jobs/forms.py rename to app/jobs/forms.py index 08b35ce00..9d53bf017 100644 --- a/jobs/forms.py +++ b/app/jobs/forms.py @@ -3,8 +3,8 @@ from markupfield.widgets import MarkupTextarea -from .models import Job, JobReviewComment -from cms.forms import ContentManageableModelForm +from app.cms.forms import ContentManageableModelForm +from app.jobs.models import Job, JobReviewComment class JobForm(ContentManageableModelForm): diff --git a/jobs/listeners.py b/app/jobs/listeners.py similarity index 98% rename from jobs/listeners.py rename to app/jobs/listeners.py index 2e88bc793..de7fdac3b 100644 --- a/jobs/listeners.py +++ b/app/jobs/listeners.py @@ -1,13 +1,11 @@ from django.conf import settings from django.core.mail import send_mail -from django.db import models from django.dispatch import receiver from django.contrib.sites.models import Site from django.template import loader from django.utils.translation import gettext_lazy as _ -from .models import Job -from .signals import ( +from app.jobs.signals import ( job_was_submitted, job_was_approved, job_was_rejected, comment_was_posted, ) diff --git a/jobs/management/commands/__init__.py b/app/jobs/management/__init__.py similarity index 100% rename from jobs/management/commands/__init__.py rename to app/jobs/management/__init__.py diff --git a/jobs/migrations/__init__.py b/app/jobs/management/commands/__init__.py similarity index 100% rename from jobs/migrations/__init__.py rename to app/jobs/management/commands/__init__.py diff --git a/jobs/management/commands/expire_jobs.py b/app/jobs/management/commands/expire_jobs.py similarity index 94% rename from jobs/management/commands/expire_jobs.py rename to app/jobs/management/commands/expire_jobs.py index 8c5848b49..435c047e4 100644 --- a/jobs/management/commands/expire_jobs.py +++ b/app/jobs/management/commands/expire_jobs.py @@ -4,7 +4,7 @@ from django.conf import settings from django.utils import timezone -from jobs.models import Job +from app.jobs.models import Job class Command(BaseCommand): diff --git a/jobs/management/commands/jobs_monthly_report.py b/app/jobs/management/commands/jobs_monthly_report.py similarity index 98% rename from jobs/management/commands/jobs_monthly_report.py rename to app/jobs/management/commands/jobs_monthly_report.py index 09f37f9b7..0dab91b90 100644 --- a/jobs/management/commands/jobs_monthly_report.py +++ b/app/jobs/management/commands/jobs_monthly_report.py @@ -6,8 +6,7 @@ from django.conf import settings from django.template import loader - -from jobs.models import Job +from app.jobs.models import Job class Command(BaseCommand): diff --git a/jobs/managers.py b/app/jobs/managers.py similarity index 100% rename from jobs/managers.py rename to app/jobs/managers.py diff --git a/jobs/migrations/0001_initial.py b/app/jobs/migrations/0001_initial.py similarity index 100% rename from jobs/migrations/0001_initial.py rename to app/jobs/migrations/0001_initial.py diff --git a/jobs/migrations/0002_auto_20150211_1634.py b/app/jobs/migrations/0002_auto_20150211_1634.py similarity index 100% rename from jobs/migrations/0002_auto_20150211_1634.py rename to app/jobs/migrations/0002_auto_20150211_1634.py diff --git a/jobs/migrations/0003_auto_20150211_1738.py b/app/jobs/migrations/0003_auto_20150211_1738.py similarity index 100% rename from jobs/migrations/0003_auto_20150211_1738.py rename to app/jobs/migrations/0003_auto_20150211_1738.py diff --git a/jobs/migrations/0004_auto_20150216_1544.py b/app/jobs/migrations/0004_auto_20150216_1544.py similarity index 100% rename from jobs/migrations/0004_auto_20150216_1544.py rename to app/jobs/migrations/0004_auto_20150216_1544.py diff --git a/jobs/migrations/0005_job_other_job_type.py b/app/jobs/migrations/0005_job_other_job_type.py similarity index 100% rename from jobs/migrations/0005_job_other_job_type.py rename to app/jobs/migrations/0005_job_other_job_type.py diff --git a/jobs/migrations/0006_region_nullable.py b/app/jobs/migrations/0006_region_nullable.py similarity index 100% rename from jobs/migrations/0006_region_nullable.py rename to app/jobs/migrations/0006_region_nullable.py diff --git a/jobs/migrations/0007_auto_20150227_2223.py b/app/jobs/migrations/0007_auto_20150227_2223.py similarity index 100% rename from jobs/migrations/0007_auto_20150227_2223.py rename to app/jobs/migrations/0007_auto_20150227_2223.py diff --git a/jobs/migrations/0008_auto_20150316_1205.py b/app/jobs/migrations/0008_auto_20150316_1205.py similarity index 100% rename from jobs/migrations/0008_auto_20150316_1205.py rename to app/jobs/migrations/0008_auto_20150316_1205.py diff --git a/jobs/migrations/0009_auto_20150317_1815.py b/app/jobs/migrations/0009_auto_20150317_1815.py similarity index 100% rename from jobs/migrations/0009_auto_20150317_1815.py rename to app/jobs/migrations/0009_auto_20150317_1815.py diff --git a/jobs/migrations/0010_auto_20150416_1853.py b/app/jobs/migrations/0010_auto_20150416_1853.py similarity index 100% rename from jobs/migrations/0010_auto_20150416_1853.py rename to app/jobs/migrations/0010_auto_20150416_1853.py diff --git a/jobs/migrations/0011_jobreviewcomment.py b/app/jobs/migrations/0011_jobreviewcomment.py similarity index 100% rename from jobs/migrations/0011_jobreviewcomment.py rename to app/jobs/migrations/0011_jobreviewcomment.py diff --git a/jobs/migrations/0012_auto_20170809_1849.py b/app/jobs/migrations/0012_auto_20170809_1849.py similarity index 100% rename from jobs/migrations/0012_auto_20170809_1849.py rename to app/jobs/migrations/0012_auto_20170809_1849.py diff --git a/jobs/migrations/0013_auto_20170810_1625.py b/app/jobs/migrations/0013_auto_20170810_1625.py similarity index 100% rename from jobs/migrations/0013_auto_20170810_1625.py rename to app/jobs/migrations/0013_auto_20170810_1625.py diff --git a/jobs/migrations/0013_auto_20170810_1627.py b/app/jobs/migrations/0013_auto_20170810_1627.py similarity index 100% rename from jobs/migrations/0013_auto_20170810_1627.py rename to app/jobs/migrations/0013_auto_20170810_1627.py diff --git a/jobs/migrations/0014_merge.py b/app/jobs/migrations/0014_merge.py similarity index 100% rename from jobs/migrations/0014_merge.py rename to app/jobs/migrations/0014_merge.py diff --git a/jobs/migrations/0015_auto_20170814_0301.py b/app/jobs/migrations/0015_auto_20170814_0301.py similarity index 100% rename from jobs/migrations/0015_auto_20170814_0301.py rename to app/jobs/migrations/0015_auto_20170814_0301.py diff --git a/jobs/migrations/0016_auto_20170821_2000.py b/app/jobs/migrations/0016_auto_20170821_2000.py similarity index 100% rename from jobs/migrations/0016_auto_20170821_2000.py rename to app/jobs/migrations/0016_auto_20170821_2000.py diff --git a/jobs/migrations/0017_auto_20180705_0348.py b/app/jobs/migrations/0017_auto_20180705_0348.py similarity index 100% rename from jobs/migrations/0017_auto_20180705_0348.py rename to app/jobs/migrations/0017_auto_20180705_0348.py diff --git a/jobs/migrations/0018_auto_20180705_0352.py b/app/jobs/migrations/0018_auto_20180705_0352.py similarity index 100% rename from jobs/migrations/0018_auto_20180705_0352.py rename to app/jobs/migrations/0018_auto_20180705_0352.py diff --git a/jobs/migrations/0019_job_submitted_by.py b/app/jobs/migrations/0019_job_submitted_by.py similarity index 100% rename from jobs/migrations/0019_job_submitted_by.py rename to app/jobs/migrations/0019_job_submitted_by.py diff --git a/jobs/migrations/0020_auto_20191101_1601.py b/app/jobs/migrations/0020_auto_20191101_1601.py similarity index 100% rename from jobs/migrations/0020_auto_20191101_1601.py rename to app/jobs/migrations/0020_auto_20191101_1601.py diff --git a/jobs/migrations/0021_alter_job_creator_alter_job_last_modified_by_and_more.py b/app/jobs/migrations/0021_alter_job_creator_alter_job_last_modified_by_and_more.py similarity index 100% rename from jobs/migrations/0021_alter_job_creator_alter_job_last_modified_by_and_more.py rename to app/jobs/migrations/0021_alter_job_creator_alter_job_last_modified_by_and_more.py diff --git a/jobs/migrations/0022_alter_jobtype_options_alter_job_job_types_and_more.py b/app/jobs/migrations/0022_alter_jobtype_options_alter_job_job_types_and_more.py similarity index 100% rename from jobs/migrations/0022_alter_jobtype_options_alter_job_job_types_and_more.py rename to app/jobs/migrations/0022_alter_jobtype_options_alter_job_job_types_and_more.py diff --git a/jobs/tests/__init__.py b/app/jobs/migrations/__init__.py similarity index 100% rename from jobs/tests/__init__.py rename to app/jobs/migrations/__init__.py diff --git a/jobs/models.py b/app/jobs/models.py similarity index 96% rename from jobs/models.py rename to app/jobs/models.py index 8b232fb93..416753f15 100644 --- a/jobs/models.py +++ b/app/jobs/models.py @@ -10,13 +10,12 @@ from markupfield.fields import MarkupField -from cms.models import ContentManageable, NameSlugModel -from fastly.utils import purge_url +from app.fastly.utils import purge_url +from app.users.models import User +from app.cms.models import NameSlugModel, ContentManageable -from users.models import User - -from .managers import JobQuerySet, JobTypeQuerySet, JobCategoryQuerySet -from .signals import ( +from app.jobs.managers import JobQuerySet, JobTypeQuerySet, JobCategoryQuerySet +from app.jobs.signals import ( job_was_submitted, job_was_approved, job_was_rejected, comment_was_posted ) diff --git a/jobs/search_indexes.py b/app/jobs/search_indexes.py similarity index 97% rename from jobs/search_indexes.py rename to app/jobs/search_indexes.py index 91f56fa58..4817fab27 100644 --- a/jobs/search_indexes.py +++ b/app/jobs/search_indexes.py @@ -3,7 +3,7 @@ from haystack import indexes -from .models import JobType, JobCategory, Job +from app.jobs.models import JobType, JobCategory, Job class JobTypeIndex(indexes.SearchIndex, indexes.Indexable): diff --git a/jobs/signals.py b/app/jobs/signals.py similarity index 100% rename from jobs/signals.py rename to app/jobs/signals.py diff --git a/templates/jobs/base.html b/app/jobs/templates/base.html similarity index 100% rename from templates/jobs/base.html rename to app/jobs/templates/base.html diff --git a/templates/jobs/email/comment_was_posted.txt b/app/jobs/templates/email/comment_was_posted.txt similarity index 100% rename from templates/jobs/email/comment_was_posted.txt rename to app/jobs/templates/email/comment_was_posted.txt diff --git a/templates/jobs/email/comment_was_posted_admin.txt b/app/jobs/templates/email/comment_was_posted_admin.txt similarity index 100% rename from templates/jobs/email/comment_was_posted_admin.txt rename to app/jobs/templates/email/comment_was_posted_admin.txt diff --git a/templates/jobs/email/job_was_approved.txt b/app/jobs/templates/email/job_was_approved.txt similarity index 100% rename from templates/jobs/email/job_was_approved.txt rename to app/jobs/templates/email/job_was_approved.txt diff --git a/templates/jobs/email/job_was_approved_subject.txt b/app/jobs/templates/email/job_was_approved_subject.txt similarity index 100% rename from templates/jobs/email/job_was_approved_subject.txt rename to app/jobs/templates/email/job_was_approved_subject.txt diff --git a/templates/jobs/email/job_was_rejected.txt b/app/jobs/templates/email/job_was_rejected.txt similarity index 100% rename from templates/jobs/email/job_was_rejected.txt rename to app/jobs/templates/email/job_was_rejected.txt diff --git a/templates/jobs/email/job_was_rejected_subject.txt b/app/jobs/templates/email/job_was_rejected_subject.txt similarity index 100% rename from templates/jobs/email/job_was_rejected_subject.txt rename to app/jobs/templates/email/job_was_rejected_subject.txt diff --git a/templates/jobs/email/job_was_submitted.txt b/app/jobs/templates/email/job_was_submitted.txt similarity index 100% rename from templates/jobs/email/job_was_submitted.txt rename to app/jobs/templates/email/job_was_submitted.txt diff --git a/templates/jobs/email/job_was_submitted_subject.txt b/app/jobs/templates/email/job_was_submitted_subject.txt similarity index 100% rename from templates/jobs/email/job_was_submitted_subject.txt rename to app/jobs/templates/email/job_was_submitted_subject.txt diff --git a/templates/jobs/email/monthly_jobs_report.txt b/app/jobs/templates/email/monthly_jobs_report.txt similarity index 100% rename from templates/jobs/email/monthly_jobs_report.txt rename to app/jobs/templates/email/monthly_jobs_report.txt diff --git a/templates/jobs/email/monthly_jobs_report_subject.txt b/app/jobs/templates/email/monthly_jobs_report_subject.txt similarity index 100% rename from templates/jobs/email/monthly_jobs_report_subject.txt rename to app/jobs/templates/email/monthly_jobs_report_subject.txt diff --git a/templates/jobs/featured_companies-widget.html b/app/jobs/templates/featured_companies-widget.html similarity index 100% rename from templates/jobs/featured_companies-widget.html rename to app/jobs/templates/featured_companies-widget.html diff --git a/templates/jobs/header_content.html b/app/jobs/templates/header_content.html similarity index 100% rename from templates/jobs/header_content.html rename to app/jobs/templates/header_content.html diff --git a/templates/jobs/job_categories.html b/app/jobs/templates/job_categories.html similarity index 100% rename from templates/jobs/job_categories.html rename to app/jobs/templates/job_categories.html diff --git a/templates/jobs/job_category_list.html b/app/jobs/templates/job_category_list.html similarity index 100% rename from templates/jobs/job_category_list.html rename to app/jobs/templates/job_category_list.html diff --git a/templates/jobs/job_detail.html b/app/jobs/templates/job_detail.html similarity index 100% rename from templates/jobs/job_detail.html rename to app/jobs/templates/job_detail.html diff --git a/templates/jobs/job_form.html b/app/jobs/templates/job_form.html similarity index 100% rename from templates/jobs/job_form.html rename to app/jobs/templates/job_form.html diff --git a/templates/jobs/job_list.html b/app/jobs/templates/job_list.html similarity index 100% rename from templates/jobs/job_list.html rename to app/jobs/templates/job_list.html diff --git a/templates/jobs/job_location_list.html b/app/jobs/templates/job_location_list.html similarity index 100% rename from templates/jobs/job_location_list.html rename to app/jobs/templates/job_location_list.html diff --git a/templates/jobs/job_locations.html b/app/jobs/templates/job_locations.html similarity index 100% rename from templates/jobs/job_locations.html rename to app/jobs/templates/job_locations.html diff --git a/templates/jobs/job_review.html b/app/jobs/templates/job_review.html similarity index 100% rename from templates/jobs/job_review.html rename to app/jobs/templates/job_review.html diff --git a/templates/jobs/job_telecommute_list.html b/app/jobs/templates/job_telecommute_list.html similarity index 100% rename from templates/jobs/job_telecommute_list.html rename to app/jobs/templates/job_telecommute_list.html diff --git a/templates/jobs/job_thanks.html b/app/jobs/templates/job_thanks.html similarity index 100% rename from templates/jobs/job_thanks.html rename to app/jobs/templates/job_thanks.html diff --git a/templates/jobs/job_type_list.html b/app/jobs/templates/job_type_list.html similarity index 100% rename from templates/jobs/job_type_list.html rename to app/jobs/templates/job_type_list.html diff --git a/templates/jobs/job_types.html b/app/jobs/templates/job_types.html similarity index 100% rename from templates/jobs/job_types.html rename to app/jobs/templates/job_types.html diff --git a/templates/jobs/submit_a_job-widget.html b/app/jobs/templates/submit_a_job-widget.html similarity index 100% rename from templates/jobs/submit_a_job-widget.html rename to app/jobs/templates/submit_a_job-widget.html diff --git a/mailing/__init__.py b/app/jobs/tests/__init__.py similarity index 100% rename from mailing/__init__.py rename to app/jobs/tests/__init__.py diff --git a/jobs/tests/test_models.py b/app/jobs/tests/test_models.py similarity index 97% rename from jobs/tests/test_models.py rename to app/jobs/tests/test_models.py index 5a9c5eb8d..c058b3cdd 100644 --- a/jobs/tests/test_models.py +++ b/app/jobs/tests/test_models.py @@ -1,11 +1,10 @@ import datetime -from django.core import mail from django.test import TestCase from django.utils import timezone -from .. import factories -from ..models import Job, JobType, JobCategory +from app.jobs import factories +from app.jobs.models import Job, JobType, JobCategory class JobsModelsTests(TestCase): diff --git a/jobs/tests/test_views.py b/app/jobs/tests/test_views.py similarity index 99% rename from jobs/tests/test_views.py rename to app/jobs/tests/test_views.py index 763dca666..b6a44635a 100644 --- a/jobs/tests/test_views.py +++ b/app/jobs/tests/test_views.py @@ -3,12 +3,12 @@ from django.urls import reverse from django.test import TestCase -from ..models import Job -from ..factories import ( +from app.jobs.models import Job +from app.jobs.factories import ( ApprovedJobFactory, DraftJobFactory, JobCategoryFactory, JobTypeFactory, ReviewJobFactory, JobsBoardAdminGroupFactory, ) -from users.factories import UserFactory +from app.users.factories import UserFactory class JobsViewTests(TestCase): diff --git a/jobs/urls.py b/app/jobs/urls.py similarity index 96% rename from jobs/urls.py rename to app/jobs/urls.py index 319ec98c3..cac965bd1 100644 --- a/jobs/urls.py +++ b/app/jobs/urls.py @@ -1,7 +1,7 @@ from django.views.generic import TemplateView -from . import views -from . import feeds +from app.jobs import views +from app.jobs import feeds from django.urls import path app_name = 'jobs' diff --git a/jobs/views.py b/app/jobs/views.py similarity index 96% rename from jobs/views.py rename to app/jobs/views.py index 9e781a185..03a2bf87b 100644 --- a/jobs/views.py +++ b/app/jobs/views.py @@ -1,14 +1,13 @@ from django.contrib import messages from django.urls import reverse -from django.db.models import Q from django.http import Http404, HttpResponse, HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect from django.views.generic import ListView, DetailView, CreateView, UpdateView, TemplateView, View -from pydotorg.mixins import GroupRequiredMixin, LoginRequiredMixin +from app.pydotorg.mixins import GroupRequiredMixin, LoginRequiredMixin -from .forms import JobForm, JobReviewCommentForm -from .models import Job, JobType, JobCategory, JobReviewComment +from app.jobs.forms import JobForm, JobReviewCommentForm +from app.jobs.models import Job, JobType, JobCategory, JobReviewComment class JobListMenu: @@ -94,7 +93,7 @@ def get_context_data(self, **kwargs): class JobListType(JobTypeMenu, JobMixin, ListView): paginate_by = 25 - template_name = 'jobs/job_type_list.html' + template_name = 'job_type_list.html' def get_queryset(self): self.current_type = get_object_or_404(JobType, @@ -110,7 +109,7 @@ def get_context_data(self, **kwargs): class JobListCategory(JobCategoryMenu, JobMixin, ListView): paginate_by = 25 - template_name = 'jobs/job_category_list.html' + template_name = 'job_category_list.html' def get_queryset(self): self.current_category = get_object_or_404(JobCategory, @@ -126,7 +125,7 @@ def get_context_data(self, **kwargs): class JobListLocation(JobLocationMenu, JobMixin, ListView): paginate_by = 25 - template_name = 'jobs/job_location_list.html' + template_name = 'job_location_list.html' def get_queryset(self): return Job.objects.visible().select_related().filter( @@ -165,7 +164,7 @@ def get_context_data(self, **kwargs): class JobTelecommute(JobLocationMenu, JobList): """ Specific view for telecommute jobs """ - template_name = 'jobs/job_telecommute_list.html' + template_name = 'job_telecommute_list.html' def get_queryset(self): return super().get_queryset().visible().select_related().filter( @@ -180,7 +179,7 @@ def get_context_data(self, **kwargs): class JobReview(LoginRequiredMixin, JobBoardAdminRequiredMixin, JobMixin, ListView): - template_name = 'jobs/job_review.html' + template_name = 'job_review.html' paginate_by = 20 redirect_url = 'jobs:job_review' @@ -275,7 +274,7 @@ def get_context_data(self, **kwargs): class JobPreview(LoginRequiredMixin, JobDetail, UpdateView): - template_name = 'jobs/job_detail.html' + template_name = 'job_detail.html' form_class = JobForm def get_success_url(self): diff --git a/mailing/migrations/__init__.py b/app/mailing/__init__.py similarity index 100% rename from mailing/migrations/__init__.py rename to app/mailing/__init__.py diff --git a/mailing/admin.py b/app/mailing/admin.py similarity index 96% rename from mailing/admin.py rename to app/mailing/admin.py index 72f78222b..03af51228 100644 --- a/mailing/admin.py +++ b/app/mailing/admin.py @@ -4,7 +4,7 @@ from django.urls import path from django.shortcuts import get_object_or_404 -from mailing.forms import BaseEmailTemplateForm +from app.mailing.forms import BaseEmailTemplateForm class BaseEmailTemplateAdmin(admin.ModelAdmin): diff --git a/mailing/apps.py b/app/mailing/apps.py similarity index 73% rename from mailing/apps.py rename to app/mailing/apps.py index 3021815de..54400f49a 100644 --- a/mailing/apps.py +++ b/app/mailing/apps.py @@ -2,4 +2,4 @@ class MailingConfig(AppConfig): - name = 'mailing' + name = 'app.mailing' diff --git a/mailing/forms.py b/app/mailing/forms.py similarity index 91% rename from mailing/forms.py rename to app/mailing/forms.py index 59f5676e7..347b241e2 100644 --- a/mailing/forms.py +++ b/app/mailing/forms.py @@ -1,7 +1,7 @@ from django import forms from django.template import Template, Context, TemplateSyntaxError -from mailing.models import BaseEmailTemplate +from app.mailing.models import BaseEmailTemplate class BaseEmailTemplateForm(forms.ModelForm): diff --git a/membership/__init__.py b/app/mailing/migrations/__init__.py similarity index 100% rename from membership/__init__.py rename to app/mailing/migrations/__init__.py diff --git a/mailing/models.py b/app/mailing/models.py similarity index 100% rename from mailing/models.py rename to app/mailing/models.py diff --git a/templates/mailing/admin/base_email_template_form.html b/app/mailing/templates/admin/base_email_template_form.html similarity index 100% rename from templates/mailing/admin/base_email_template_form.html rename to app/mailing/templates/admin/base_email_template_form.html diff --git a/mailing/tests/__init__.py b/app/mailing/tests/__init__.py similarity index 100% rename from mailing/tests/__init__.py rename to app/mailing/tests/__init__.py diff --git a/mailing/tests/forms.py b/app/mailing/tests/forms.py similarity index 71% rename from mailing/tests/forms.py rename to app/mailing/tests/forms.py index b433adea6..30d2a15f2 100644 --- a/mailing/tests/forms.py +++ b/app/mailing/tests/forms.py @@ -1,7 +1,7 @@ """Forms to be used in mailing tests.""" -from mailing.forms import BaseEmailTemplateForm -from mailing.tests.models import MockEmailTemplate +from app.mailing.forms import BaseEmailTemplateForm +from app.mailing.tests.models import MockEmailTemplate class TestBaseEmailTemplateForm(BaseEmailTemplateForm): diff --git a/mailing/tests/models.py b/app/mailing/tests/models.py similarity index 86% rename from mailing/tests/models.py rename to app/mailing/tests/models.py index 917e8dfb9..a0bd6a743 100644 --- a/mailing/tests/models.py +++ b/app/mailing/tests/models.py @@ -1,6 +1,6 @@ """Models to be used in mailing tests.""" -from mailing.models import BaseEmailTemplate +from app.mailing.models import BaseEmailTemplate class MockEmailTemplate(BaseEmailTemplate): diff --git a/mailing/tests/test_forms.py b/app/mailing/tests/test_forms.py similarity index 93% rename from mailing/tests/test_forms.py rename to app/mailing/tests/test_forms.py index f7a0c6890..845c10399 100644 --- a/mailing/tests/test_forms.py +++ b/app/mailing/tests/test_forms.py @@ -1,7 +1,7 @@ """Tests for mailing app forms.""" from django.test import TestCase -from mailing.tests.forms import TestBaseEmailTemplateForm +from app.mailing.tests.forms import TestBaseEmailTemplateForm class BaseEmailTemplateFormTests(TestCase): diff --git a/manage.py b/app/manage.py similarity index 87% rename from manage.py rename to app/manage.py index 22c8d4c7b..9802903b0 100755 --- a/manage.py +++ b/app/manage.py @@ -6,7 +6,7 @@ def main(): """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pydotorg.settings.local") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.pydotorg.settings.local") try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/membership/migrations/__init__.py b/app/membership/__init__.py similarity index 100% rename from membership/migrations/__init__.py rename to app/membership/__init__.py diff --git a/membership/apps.py b/app/membership/apps.py similarity index 72% rename from membership/apps.py rename to app/membership/apps.py index 9f3dac7af..8ff0960a7 100644 --- a/membership/apps.py +++ b/app/membership/apps.py @@ -3,4 +3,4 @@ class MembershipAppConfig(AppConfig): - name = 'membership' + name = 'app.membership' diff --git a/membership/tests/__init__.py b/app/membership/migrations/__init__.py similarity index 100% rename from membership/tests/__init__.py rename to app/membership/migrations/__init__.py diff --git a/minutes/__init__.py b/app/membership/tests/__init__.py similarity index 100% rename from minutes/__init__.py rename to app/membership/tests/__init__.py diff --git a/membership/tests/test_views.py b/app/membership/tests/test_views.py similarity index 100% rename from membership/tests/test_views.py rename to app/membership/tests/test_views.py diff --git a/membership/urls.py b/app/membership/urls.py similarity index 76% rename from membership/urls.py rename to app/membership/urls.py index 8d12b46c9..c6b29e6c3 100644 --- a/membership/urls.py +++ b/app/membership/urls.py @@ -1,4 +1,4 @@ -from . import views +from app.membership import views from django.urls import path diff --git a/membership/views.py b/app/membership/views.py similarity index 77% rename from membership/views.py rename to app/membership/views.py index 9ed03581d..ae12aecef 100644 --- a/membership/views.py +++ b/app/membership/views.py @@ -1,6 +1,6 @@ from django.views.generic import TemplateView -from pydotorg.mixins import FlagMixin +from app.pydotorg.mixins import FlagMixin # NOTE: Many aspects of 'membership' such as adjusting a user profile, signup, # etc are handled in the users app @@ -9,4 +9,4 @@ class Membership(FlagMixin, TemplateView): """ Main membership landing page """ flag = 'psf_membership' - template_name = 'users/membership.html' + template_name = 'membership.html' diff --git a/minutes/management/__init__.py b/app/minutes/__init__.py similarity index 100% rename from minutes/management/__init__.py rename to app/minutes/__init__.py diff --git a/minutes/admin.py b/app/minutes/admin.py similarity index 81% rename from minutes/admin.py rename to app/minutes/admin.py index 63f7fdd4d..fe2114263 100644 --- a/minutes/admin.py +++ b/app/minutes/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin -from .models import Minutes -from cms.admin import ContentManageableModelAdmin +from app.cms.admin import ContentManageableModelAdmin +from app.minutes.models import Minutes @admin.register(Minutes) diff --git a/minutes/apps.py b/app/minutes/apps.py similarity index 74% rename from minutes/apps.py rename to app/minutes/apps.py index dfdc40499..9594448ee 100644 --- a/minutes/apps.py +++ b/app/minutes/apps.py @@ -3,4 +3,4 @@ class MinutesAppConfig(AppConfig): - name = 'minutes' + name = 'app.minutes' diff --git a/minutes/feeds.py b/app/minutes/feeds.py similarity index 94% rename from minutes/feeds.py rename to app/minutes/feeds.py index 3d5d6ec72..67a6013ea 100644 --- a/minutes/feeds.py +++ b/app/minutes/feeds.py @@ -3,7 +3,7 @@ from django.contrib.syndication.views import Feed from django.urls import reverse_lazy -from .models import Minutes +from app.minutes.models import Minutes class MinutesFeed(Feed): diff --git a/minutes/management/commands/__init__.py b/app/minutes/management/__init__.py similarity index 100% rename from minutes/management/commands/__init__.py rename to app/minutes/management/__init__.py diff --git a/minutes/migrations/__init__.py b/app/minutes/management/commands/__init__.py similarity index 100% rename from minutes/migrations/__init__.py rename to app/minutes/management/commands/__init__.py diff --git a/minutes/management/commands/move_meeting_notes.py b/app/minutes/management/commands/move_meeting_notes.py similarity index 93% rename from minutes/management/commands/move_meeting_notes.py rename to app/minutes/management/commands/move_meeting_notes.py index 24c04930e..3cef506a2 100644 --- a/minutes/management/commands/move_meeting_notes.py +++ b/app/minutes/management/commands/move_meeting_notes.py @@ -3,8 +3,9 @@ from django.core.management.base import BaseCommand -from pages.models import Page -from ...models import Minutes +from app.minutes.models import Minutes +from app.pages.models import Page + class Command(BaseCommand): diff --git a/minutes/managers.py b/app/minutes/managers.py similarity index 100% rename from minutes/managers.py rename to app/minutes/managers.py diff --git a/minutes/migrations/0001_initial.py b/app/minutes/migrations/0001_initial.py similarity index 100% rename from minutes/migrations/0001_initial.py rename to app/minutes/migrations/0001_initial.py diff --git a/minutes/migrations/0002_auto_20150416_1853.py b/app/minutes/migrations/0002_auto_20150416_1853.py similarity index 100% rename from minutes/migrations/0002_auto_20150416_1853.py rename to app/minutes/migrations/0002_auto_20150416_1853.py diff --git a/minutes/migrations/0003_alter_minutes_creator_alter_minutes_last_modified_by.py b/app/minutes/migrations/0003_alter_minutes_creator_alter_minutes_last_modified_by.py similarity index 100% rename from minutes/migrations/0003_alter_minutes_creator_alter_minutes_last_modified_by.py rename to app/minutes/migrations/0003_alter_minutes_creator_alter_minutes_last_modified_by.py diff --git a/minutes/tests/__init__.py b/app/minutes/migrations/__init__.py similarity index 100% rename from minutes/tests/__init__.py rename to app/minutes/migrations/__init__.py diff --git a/minutes/models.py b/app/minutes/models.py similarity index 92% rename from minutes/models.py rename to app/minutes/models.py index 9101aa5e9..b3fca50c5 100644 --- a/minutes/models.py +++ b/app/minutes/models.py @@ -4,9 +4,9 @@ from markupfield.fields import MarkupField -from cms.models import ContentManageable +from app.cms.models import ContentManageable -from .managers import MinutesQuerySet +from app.minutes.managers import MinutesQuerySet DEFAULT_MARKUP_TYPE = getattr(settings, 'DEFAULT_MARKUP_TYPE', 'restructuredtext') diff --git a/templates/minutes/minutes_detail.html b/app/minutes/templates/minutes_detail.html similarity index 100% rename from templates/minutes/minutes_detail.html rename to app/minutes/templates/minutes_detail.html diff --git a/templates/minutes/minutes_list.html b/app/minutes/templates/minutes_list.html similarity index 100% rename from templates/minutes/minutes_list.html rename to app/minutes/templates/minutes_list.html diff --git a/nominations/__init__.py b/app/minutes/tests/__init__.py similarity index 100% rename from nominations/__init__.py rename to app/minutes/tests/__init__.py diff --git a/minutes/tests/test_models.py b/app/minutes/tests/test_models.py similarity index 96% rename from minutes/tests/test_models.py rename to app/minutes/tests/test_models.py index 4b5603641..7c2067572 100644 --- a/minutes/tests/test_models.py +++ b/app/minutes/tests/test_models.py @@ -2,7 +2,7 @@ from django.test import TestCase -from ..models import Minutes +from app.minutes.models import Minutes class MinutesModelTests(TestCase): diff --git a/minutes/tests/test_views.py b/app/minutes/tests/test_views.py similarity index 98% rename from minutes/tests/test_views.py rename to app/minutes/tests/test_views.py index 5bdee65db..8521696b8 100644 --- a/minutes/tests/test_views.py +++ b/app/minutes/tests/test_views.py @@ -4,7 +4,7 @@ from django.contrib.auth import get_user_model from django.test import TestCase -from ..models import Minutes +from app.minutes.models import Minutes User = get_user_model() diff --git a/minutes/urls.py b/app/minutes/urls.py similarity index 81% rename from minutes/urls.py rename to app/minutes/urls.py index a957df34b..1d5f39c3d 100644 --- a/minutes/urls.py +++ b/app/minutes/urls.py @@ -1,5 +1,5 @@ -from .feeds import MinutesFeed -from . import views +from app.minutes.feeds import MinutesFeed +from app.minutes import views from django.urls import path, re_path diff --git a/minutes/views.py b/app/minutes/views.py similarity index 91% rename from minutes/views.py rename to app/minutes/views.py index 9a88957e4..b297fc15b 100644 --- a/minutes/views.py +++ b/app/minutes/views.py @@ -2,12 +2,12 @@ from django.http import Http404 from django.views.generic import DetailView, ListView -from .models import Minutes +from app.minutes.models import Minutes class MinutesList(ListView): model = Minutes - template_name = 'minutes/minutes_list.html' + template_name = 'minutes_list.html' context_object_name = 'minutes_list' def get_queryset(self): @@ -21,7 +21,7 @@ def get_queryset(self): class MinutesDetail(DetailView): model = Minutes - template_name = 'minutes/minutes_detail.html' + template_name = 'minutes_detail.html' context_object_name = 'minutes' def get_object(self, queryset=None): diff --git a/nominations/migrations/__init__.py b/app/nominations/__init__.py similarity index 100% rename from nominations/migrations/__init__.py rename to app/nominations/__init__.py diff --git a/nominations/admin.py b/app/nominations/admin.py similarity index 93% rename from nominations/admin.py rename to app/nominations/admin.py index 07e516488..bfb053777 100644 --- a/nominations/admin.py +++ b/app/nominations/admin.py @@ -2,7 +2,7 @@ from django.db.models.functions import Lower -from nominations.models import Election, Nominee, Nomination +from app.nominations.models import Election, Nominee, Nomination @admin.register(Election) diff --git a/nominations/apps.py b/app/nominations/apps.py similarity index 72% rename from nominations/apps.py rename to app/nominations/apps.py index 1180cd682..146797d94 100644 --- a/nominations/apps.py +++ b/app/nominations/apps.py @@ -3,4 +3,4 @@ class NominationsAppConfig(AppConfig): - name = 'nominations' + name = 'app.nominations' diff --git a/nominations/forms.py b/app/nominations/forms.py similarity index 97% rename from nominations/forms.py rename to app/nominations/forms.py index 4a221fc2f..2bcdb1ec8 100644 --- a/nominations/forms.py +++ b/app/nominations/forms.py @@ -3,7 +3,7 @@ from markupfield.widgets import MarkupTextarea -from .models import Nomination +from app.nominations.models import Nomination class NominationForm(forms.ModelForm): diff --git a/nominations/migrations/0001_initial.py b/app/nominations/migrations/0001_initial.py similarity index 100% rename from nominations/migrations/0001_initial.py rename to app/nominations/migrations/0001_initial.py diff --git a/nominations/migrations/0002_auto_20190514_1435.py b/app/nominations/migrations/0002_auto_20190514_1435.py similarity index 100% rename from nominations/migrations/0002_auto_20190514_1435.py rename to app/nominations/migrations/0002_auto_20190514_1435.py diff --git a/nominations/templatetags/__init__.py b/app/nominations/migrations/__init__.py similarity index 100% rename from nominations/templatetags/__init__.py rename to app/nominations/migrations/__init__.py diff --git a/nominations/models.py b/app/nominations/models.py similarity index 99% rename from nominations/models.py rename to app/nominations/models.py index f52a286be..7cc5d8a65 100644 --- a/nominations/models.py +++ b/app/nominations/models.py @@ -6,10 +6,11 @@ from django.urls import reverse from django.utils.text import slugify -from fastly.utils import purge_url + from markupfield.fields import MarkupField -from users.models import User +from app.fastly.utils import purge_url +from app.users.models import User class Election(models.Model): diff --git a/templates/nominations/election_detail.html b/app/nominations/templates/election_detail.html similarity index 100% rename from templates/nominations/election_detail.html rename to app/nominations/templates/election_detail.html diff --git a/templates/nominations/election_list.html b/app/nominations/templates/election_list.html similarity index 100% rename from templates/nominations/election_list.html rename to app/nominations/templates/election_list.html diff --git a/templates/nominations/nomination_accept_form.html b/app/nominations/templates/nomination_accept_form.html similarity index 100% rename from templates/nominations/nomination_accept_form.html rename to app/nominations/templates/nomination_accept_form.html diff --git a/templates/nominations/nomination_detail.html b/app/nominations/templates/nomination_detail.html similarity index 100% rename from templates/nominations/nomination_detail.html rename to app/nominations/templates/nomination_detail.html diff --git a/templates/nominations/nomination_form.html b/app/nominations/templates/nomination_form.html similarity index 100% rename from templates/nominations/nomination_form.html rename to app/nominations/templates/nomination_form.html diff --git a/templates/nominations/nominee_detail.html b/app/nominations/templates/nominee_detail.html similarity index 100% rename from templates/nominations/nominee_detail.html rename to app/nominations/templates/nominee_detail.html diff --git a/templates/nominations/nominee_list.html b/app/nominations/templates/nominee_list.html similarity index 100% rename from templates/nominations/nominee_list.html rename to app/nominations/templates/nominee_list.html diff --git a/pages/__init__.py b/app/nominations/templatetags/__init__.py similarity index 100% rename from pages/__init__.py rename to app/nominations/templatetags/__init__.py diff --git a/nominations/templatetags/nominations.py b/app/nominations/templatetags/nominations.py similarity index 100% rename from nominations/templatetags/nominations.py rename to app/nominations/templatetags/nominations.py diff --git a/nominations/urls.py b/app/nominations/urls.py similarity index 96% rename from nominations/urls.py rename to app/nominations/urls.py index 1815ae2e7..73fd53fdc 100644 --- a/nominations/urls.py +++ b/app/nominations/urls.py @@ -1,4 +1,4 @@ -from . import views +from app.nominations import views from django.urls import path app_name = "nominations" diff --git a/nominations/views.py b/app/nominations/views.py similarity index 96% rename from nominations/views.py rename to app/nominations/views.py index 484f7a7c2..99043936f 100644 --- a/nominations/views.py +++ b/app/nominations/views.py @@ -5,10 +5,10 @@ from django.urls import reverse from django.http import Http404 -from pydotorg.mixins import LoginRequiredMixin +from app.pydotorg.mixins import LoginRequiredMixin -from .models import Nomination, Nominee, Election -from .forms import NominationForm, NominationCreateForm, NominationAcceptForm +from app.nominations.models import Nomination, Nominee, Election +from app.nominations.forms import NominationForm, NominationCreateForm, NominationAcceptForm class ElectionsList(ListView): diff --git a/pages/management/__init__.py b/app/pages/__init__.py similarity index 100% rename from pages/management/__init__.py rename to app/pages/__init__.py diff --git a/pages/admin.py b/app/pages/admin.py similarity index 93% rename from pages/admin.py rename to app/pages/admin.py index beb8d3b46..73b5ea877 100644 --- a/pages/admin.py +++ b/app/pages/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin -from cms.admin import ContentManageableModelAdmin -from .models import Page, Image, DocumentFile +from app.cms.admin import ContentManageableModelAdmin +from app.pages.models import Page, Image, DocumentFile class ImageInlineAdmin(admin.StackedInline): diff --git a/pages/api.py b/app/pages/api.py similarity index 86% rename from pages/api.py rename to app/pages/api.py index 073f60e68..0268d9fbc 100644 --- a/pages/api.py +++ b/app/pages/api.py @@ -1,12 +1,12 @@ from rest_framework.authentication import TokenAuthentication -from pydotorg.resources import GenericResource, OnlyPublishedAuthorization -from pydotorg.drf import ( +from app.pydotorg.resources import GenericResource, OnlyPublishedAuthorization +from app.pydotorg.drf import ( BaseReadOnlyAPIViewSet, BaseFilterSet, IsStaffOrReadOnly, ) -from .models import Page -from .serializers import PageSerializer +from app.pages.models import Page +from app.pages.serializers import PageSerializer class PageResource(GenericResource): diff --git a/pages/apps.py b/app/pages/apps.py similarity index 75% rename from pages/apps.py rename to app/pages/apps.py index da243ee7e..88dc79df7 100644 --- a/pages/apps.py +++ b/app/pages/apps.py @@ -3,4 +3,4 @@ class PagesAppConfig(AppConfig): - name = 'pages' + name = 'app.pages' diff --git a/pages/factories.py b/app/pages/factories.py similarity index 87% rename from pages/factories.py rename to app/pages/factories.py index c525f11f4..d07855a54 100644 --- a/pages/factories.py +++ b/app/pages/factories.py @@ -3,9 +3,9 @@ from django.template.defaultfilters import slugify from factory.django import DjangoModelFactory -from users.factories import UserFactory +from app.users.factories import UserFactory -from .models import Page +from app.pages.models import Page class PageFactory(DjangoModelFactory): diff --git a/pages/management/commands/__init__.py b/app/pages/management/__init__.py similarity index 100% rename from pages/management/commands/__init__.py rename to app/pages/management/__init__.py diff --git a/pages/migrations/__init__.py b/app/pages/management/commands/__init__.py similarity index 100% rename from pages/migrations/__init__.py rename to app/pages/management/commands/__init__.py diff --git a/pages/management/commands/fix_success_story_images.py b/app/pages/management/commands/fix_success_story_images.py similarity index 97% rename from pages/management/commands/fix_success_story_images.py rename to app/pages/management/commands/fix_success_story_images.py index 7fc9fe1de..319adf7bb 100644 --- a/pages/management/commands/fix_success_story_images.py +++ b/app/pages/management/commands/fix_success_story_images.py @@ -8,7 +8,7 @@ from django.conf import settings from django.core.files import File -from ...models import Page, Image, page_image_path +from app.pages..models import Page, Image, page_image_path class Command(BaseCommand): diff --git a/pages/management/commands/import_pages_from_svn.py b/app/pages/management/commands/import_pages_from_svn.py similarity index 97% rename from pages/management/commands/import_pages_from_svn.py rename to app/pages/management/commands/import_pages_from_svn.py index f6865c0ed..2bbdf7a5f 100644 --- a/pages/management/commands/import_pages_from_svn.py +++ b/app/pages/management/commands/import_pages_from_svn.py @@ -9,8 +9,8 @@ from bs4 import BeautifulSoup -from ...models import Page, Image -from ...parser import parse_page +from app.pages..models import Page, Image +from app.pages..parser import parse_page def fix_image_path(src): diff --git a/pages/managers.py b/app/pages/managers.py similarity index 100% rename from pages/managers.py rename to app/pages/managers.py diff --git a/pages/middleware.py b/app/pages/middleware.py similarity index 95% rename from pages/middleware.py rename to app/pages/middleware.py index 46b46189a..b601f558b 100644 --- a/pages/middleware.py +++ b/app/pages/middleware.py @@ -1,7 +1,7 @@ from django.conf import settings from django import http -from .models import Page -from .views import PageView +from app.pages.models import Page +from app.pages.views import PageView class PageFallbackMiddleware: diff --git a/pages/migrations/0001_initial.py b/app/pages/migrations/0001_initial.py similarity index 96% rename from pages/migrations/0001_initial.py rename to app/pages/migrations/0001_initial.py index a8eed99ac..df3fa87e0 100644 --- a/pages/migrations/0001_initial.py +++ b/app/pages/migrations/0001_initial.py @@ -1,5 +1,5 @@ from django.db import models, migrations -import pages.models +import app.pages.models import django.core.validators import markupfield.fields import re @@ -28,7 +28,7 @@ class Migration(migrations.Migration): name='Image', fields=[ ('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')), - ('image', models.ImageField(upload_to=pages.models.page_image_path, max_length=400)), + ('image', models.ImageField(upload_to=app.pages.models.page_image_path, max_length=400)), ], options={ }, diff --git a/pages/migrations/0002_auto_20150416_1853.py b/app/pages/migrations/0002_auto_20150416_1853.py similarity index 100% rename from pages/migrations/0002_auto_20150416_1853.py rename to app/pages/migrations/0002_auto_20150416_1853.py diff --git a/pages/migrations/0003_auto_20230214_2113.py b/app/pages/migrations/0003_auto_20230214_2113.py similarity index 100% rename from pages/migrations/0003_auto_20230214_2113.py rename to app/pages/migrations/0003_auto_20230214_2113.py diff --git a/pages/migrations/0004_alter_page_creator_alter_page_last_modified_by.py b/app/pages/migrations/0004_alter_page_creator_alter_page_last_modified_by.py similarity index 100% rename from pages/migrations/0004_alter_page_creator_alter_page_last_modified_by.py rename to app/pages/migrations/0004_alter_page_creator_alter_page_last_modified_by.py diff --git a/pages/tests/__init__.py b/app/pages/migrations/__init__.py similarity index 100% rename from pages/tests/__init__.py rename to app/pages/migrations/__init__.py diff --git a/pages/models.py b/app/pages/models.py similarity index 97% rename from pages/models.py rename to app/pages/models.py index c3973ce68..d2f3d0ade 100644 --- a/pages/models.py +++ b/app/pages/models.py @@ -23,10 +23,10 @@ import cmarkgfm from cmarkgfm.cmark import Options as cmarkgfmOptions -from cms.models import ContentManageable -from fastly.utils import purge_url +from app.cms.models import ContentManageable +from app.fastly.utils import purge_url -from .managers import PageQuerySet +from app.pages.managers import PageQuerySet DEFAULT_MARKUP_TYPE = getattr(settings, 'DEFAULT_MARKUP_TYPE', 'restructuredtext') diff --git a/pages/parser.py b/app/pages/parser.py similarity index 100% rename from pages/parser.py rename to app/pages/parser.py diff --git a/pages/search_indexes.py b/app/pages/search_indexes.py similarity index 96% rename from pages/search_indexes.py rename to app/pages/search_indexes.py index b41e6f369..90fb3fc4a 100644 --- a/pages/search_indexes.py +++ b/app/pages/search_indexes.py @@ -2,7 +2,7 @@ from haystack import indexes -from .models import Page +from app.pages.models import Page class PageIndex(indexes.SearchIndex, indexes.Indexable): diff --git a/pages/serializers.py b/app/pages/serializers.py similarity index 91% rename from pages/serializers.py rename to app/pages/serializers.py index 7838447f4..180e3c31c 100644 --- a/pages/serializers.py +++ b/app/pages/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from .models import Page +from app.pages.models import Page class PageSerializer(serializers.HyperlinkedModelSerializer): diff --git a/templates/pages/default.html b/app/pages/templates/default.html similarity index 100% rename from templates/pages/default.html rename to app/pages/templates/default.html diff --git a/templates/pages/pep-page.html b/app/pages/templates/pep-page.html similarity index 100% rename from templates/pages/pep-page.html rename to app/pages/templates/pep-page.html diff --git a/templates/pages/raw.html b/app/pages/templates/raw.html similarity index 100% rename from templates/pages/raw.html rename to app/pages/templates/raw.html diff --git a/pydotorg/settings/__init__.py b/app/pages/tests/__init__.py similarity index 100% rename from pydotorg/settings/__init__.py rename to app/pages/tests/__init__.py diff --git a/pages/tests/base.py b/app/pages/tests/base.py similarity index 93% rename from pages/tests/base.py rename to app/pages/tests/base.py index b5046816c..d44e34861 100644 --- a/pages/tests/base.py +++ b/app/pages/tests/base.py @@ -1,6 +1,6 @@ from django.contrib.auth import get_user_model from django.test import TestCase -from ..models import Page +from app.pages.models import Page User = get_user_model() diff --git a/pages/tests/fake_svn_content_checkout/about/content.ht b/app/pages/tests/fake_svn_content_checkout/about/content.ht similarity index 100% rename from pages/tests/fake_svn_content_checkout/about/content.ht rename to app/pages/tests/fake_svn_content_checkout/about/content.ht diff --git a/pages/tests/fake_svn_content_checkout/about/success/dlink/content.rst b/app/pages/tests/fake_svn_content_checkout/about/success/dlink/content.rst similarity index 100% rename from pages/tests/fake_svn_content_checkout/about/success/dlink/content.rst rename to app/pages/tests/fake_svn_content_checkout/about/success/dlink/content.rst diff --git a/pages/tests/fake_svn_content_checkout/community/content.ht b/app/pages/tests/fake_svn_content_checkout/community/content.ht similarity index 100% rename from pages/tests/fake_svn_content_checkout/community/content.ht rename to app/pages/tests/fake_svn_content_checkout/community/content.ht diff --git a/pages/tests/fake_svn_content_checkout/content.ht b/app/pages/tests/fake_svn_content_checkout/content.ht similarity index 100% rename from pages/tests/fake_svn_content_checkout/content.ht rename to app/pages/tests/fake_svn_content_checkout/content.ht diff --git a/pages/tests/test_api.py b/app/pages/tests/test_api.py similarity index 95% rename from pages/tests/test_api.py rename to app/pages/tests/test_api.py index 1c4cc6184..f15421728 100644 --- a/pages/tests/test_api.py +++ b/app/pages/tests/test_api.py @@ -1,9 +1,9 @@ from rest_framework.test import APITestCase -from pydotorg.drf import BaseAPITestCase +from app.pydotorg.drf import BaseAPITestCase -from pages.factories import PageFactory -from users.factories import UserFactory +from app.pages.factories import PageFactory +from app.users.factories import UserFactory class PageApiViewsTest(BaseAPITestCase, APITestCase): diff --git a/pages/tests/test_models.py b/app/pages/tests/test_models.py similarity index 95% rename from pages/tests/test_models.py rename to app/pages/tests/test_models.py index eac62f102..145bd1a6a 100644 --- a/pages/tests/test_models.py +++ b/app/pages/tests/test_models.py @@ -3,8 +3,8 @@ import ddt -from .base import BasePageTests -from ..models import Page, PAGE_PATH_RE +from app.pages.base import BasePageTests +from app.pages.models import Page, PAGE_PATH_RE class PageModelTests(BasePageTests): diff --git a/pages/tests/test_parser.py b/app/pages/tests/test_parser.py similarity index 92% rename from pages/tests/test_parser.py rename to app/pages/tests/test_parser.py index 96b7709bb..cb4627693 100644 --- a/pages/tests/test_parser.py +++ b/app/pages/tests/test_parser.py @@ -4,8 +4,8 @@ from django.core.management import call_command from django.test import TestCase -from ..models import Page -from ..parser import determine_page_content_type +from app.pages.models import Page +from app.pages.parser import determine_page_content_type class PagesParserTests(TestCase): diff --git a/pages/tests/test_views.py b/app/pages/tests/test_views.py similarity index 96% rename from pages/tests/test_views.py rename to app/pages/tests/test_views.py index d4e17f8ce..e1cb047ef 100644 --- a/pages/tests/test_views.py +++ b/app/pages/tests/test_views.py @@ -1,4 +1,4 @@ -from .base import BasePageTests +from app.pages.base import BasePageTests from django.contrib.sites.models import Site from django.contrib.redirects.models import Redirect diff --git a/pages/urls.py b/app/pages/urls.py similarity index 75% rename from pages/urls.py rename to app/pages/urls.py index df60e2732..5d012970f 100644 --- a/pages/urls.py +++ b/app/pages/urls.py @@ -1,4 +1,4 @@ -from .views import PageView +from app.pages.views import PageView from django.urls import path urlpatterns = [ diff --git a/pages/views.py b/app/pages/views.py similarity index 94% rename from pages/views.py rename to app/pages/views.py index f7fabe374..aaa858373 100644 --- a/pages/views.py +++ b/app/pages/views.py @@ -4,12 +4,12 @@ from django.urls import reverse from django.views.generic import DetailView -from downloads.models import Release -from .models import Page +from app.downloads.models import Release +from app.pages.models import Page class PageView(DetailView): - template_name = 'pages/default.html' + template_name = 'default.html' template_name_field = 'template_name' context_object_name = 'page' diff --git a/pydotorg/__init__.py b/app/pydotorg/__init__.py similarity index 100% rename from pydotorg/__init__.py rename to app/pydotorg/__init__.py diff --git a/pydotorg/celery.py b/app/pydotorg/celery.py similarity index 74% rename from pydotorg/celery.py rename to app/pydotorg/celery.py index 51062cf9b..8808a69cb 100644 --- a/pydotorg/celery.py +++ b/app/pydotorg/celery.py @@ -3,9 +3,9 @@ from celery import Celery from django.core import management -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pydotorg.settings.local") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.pydotorg.settings.local") -app = Celery("pydotorg") +app = Celery("app.pydotorg") app.config_from_object("django.conf:settings", namespace="CELERY") @app.task(bind=True) diff --git a/pydotorg/compilers.py b/app/pydotorg/compilers.py similarity index 100% rename from pydotorg/compilers.py rename to app/pydotorg/compilers.py diff --git a/pydotorg/context_processors.py b/app/pydotorg/context_processors.py similarity index 100% rename from pydotorg/context_processors.py rename to app/pydotorg/context_processors.py diff --git a/pydotorg/drf.py b/app/pydotorg/drf.py similarity index 100% rename from pydotorg/drf.py rename to app/pydotorg/drf.py diff --git a/pydotorg/middleware.py b/app/pydotorg/middleware.py similarity index 100% rename from pydotorg/middleware.py rename to app/pydotorg/middleware.py diff --git a/pydotorg/mixins.py b/app/pydotorg/mixins.py similarity index 100% rename from pydotorg/mixins.py rename to app/pydotorg/mixins.py diff --git a/pydotorg/resources.py b/app/pydotorg/resources.py similarity index 100% rename from pydotorg/resources.py rename to app/pydotorg/resources.py diff --git a/pydotorg/tests/__init__.py b/app/pydotorg/settings/__init__.py similarity index 100% rename from pydotorg/tests/__init__.py rename to app/pydotorg/settings/__init__.py diff --git a/pydotorg/settings/base.py b/app/pydotorg/settings/base.py similarity index 90% rename from pydotorg/settings/base.py rename to app/pydotorg/settings/base.py index 2c392b355..94d57a0a0 100644 --- a/pydotorg/settings/base.py +++ b/app/pydotorg/settings/base.py @@ -141,11 +141,11 @@ 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', - 'pydotorg.context_processors.site_info', - 'pydotorg.context_processors.url_name', - 'pydotorg.context_processors.get_host_with_scheme', - 'pydotorg.context_processors.blog_url', - 'pydotorg.context_processors.user_nav_bar_links', + 'app.pydotorg.context_processors.site_info', + 'app.pydotorg.context_processors.url_name', + 'app.pydotorg.context_processors.get_host_with_scheme', + 'app.pydotorg.context_processors.blog_url', + 'app.pydotorg.context_processors.user_nav_bar_links', ], }, }, @@ -155,7 +155,7 @@ ### URLs, WSGI, middleware, etc. -ROOT_URLCONF = 'pydotorg.urls' +ROOT_URLCONF = 'app.pydotorg.urls' # Note that we don't need to activate 'XFrameOptionsMiddleware' and # 'SecurityMiddleware' because we set appropriate headers in python/psf-salt. @@ -163,8 +163,8 @@ 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', - 'pydotorg.middleware.AdminNoCaching', - 'pydotorg.middleware.GlobalSurrogateKey', + 'app.pydotorg.middleware.AdminNoCaching', + 'app.pydotorg.middleware.GlobalSurrogateKey', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'waffle.middleware.WaffleMiddleware', @@ -176,7 +176,7 @@ AUTH_USER_MODEL = 'users.User' -WSGI_APPLICATION = 'pydotorg.wsgi.application' +WSGI_APPLICATION = 'app.pydotorg.wsgi.application' ### Apps @@ -208,24 +208,24 @@ 'django_countries', 'sorl.thumbnail', - 'banners', - 'blogs', - 'boxes', - 'cms', - 'codesamples', - 'community', - 'companies', - 'downloads', - 'events', - 'jobs', - 'mailing', - 'minutes', - 'nominations', - 'pages', - 'sponsors', - 'successstories', - 'users', - 'work_groups', + 'app.banners', + 'app.blogs', + 'app.boxes', + 'app.cms', + 'app.codesamples', + 'app.community', + 'app.companies', + 'app.downloads', + 'app.events', + 'app.jobs', + 'app.mailing', + 'app.minutes', + 'app.nominations', + 'app.pages', + 'app.sponsors', + 'app.successstories', + 'app.users', + 'app.work_groups', 'allauth', 'allauth.account', @@ -309,7 +309,7 @@ ### Pipeline -from .pipeline import PIPELINE +from app.pydotorg.settings.pipeline import PIPELINE ### contrib.messages diff --git a/pydotorg/settings/cabotage.py b/app/pydotorg/settings/cabotage.py similarity index 97% rename from pydotorg/settings/cabotage.py rename to app/pydotorg/settings/cabotage.py index 4661fbf66..4ab1b2329 100644 --- a/pydotorg/settings/cabotage.py +++ b/app/pydotorg/settings/cabotage.py @@ -1,10 +1,6 @@ -import os - -import dj_database_url -import raven from decouple import Csv -from .base import * +from app.pydotorg.settings.base import * DEBUG = TEMPLATE_DEBUG = False diff --git a/pydotorg/settings/local.py b/app/pydotorg/settings/local.py similarity index 98% rename from pydotorg/settings/local.py rename to app/pydotorg/settings/local.py index 6525d9837..31c1ac19b 100644 --- a/pydotorg/settings/local.py +++ b/app/pydotorg/settings/local.py @@ -1,4 +1,4 @@ -from .base import * +from app.pydotorg.settings.base import * import os DEBUG = True diff --git a/pydotorg/settings/pipeline.py b/app/pydotorg/settings/pipeline.py similarity index 98% rename from pydotorg/settings/pipeline.py rename to app/pydotorg/settings/pipeline.py index 187613447..e7df0b15a 100644 --- a/pydotorg/settings/pipeline.py +++ b/app/pydotorg/settings/pipeline.py @@ -1,7 +1,3 @@ -import os - -from .base import BASE - PIPELINE_CSS = { 'style': { 'source_filenames': ( diff --git a/pydotorg/settings/static.py b/app/pydotorg/settings/static.py similarity index 85% rename from pydotorg/settings/static.py rename to app/pydotorg/settings/static.py index 5dcbf6f92..d3e4718b5 100644 --- a/pydotorg/settings/static.py +++ b/app/pydotorg/settings/static.py @@ -1,10 +1,4 @@ -import os - -import dj_database_url -import raven -from decouple import Csv - -from .base import * +from app.pydotorg.settings.base import * DEBUG = TEMPLATE_DEBUG = False diff --git a/sponsors/__init__.py b/app/pydotorg/tests/__init__.py similarity index 100% rename from sponsors/__init__.py rename to app/pydotorg/tests/__init__.py diff --git a/pydotorg/tests/test_classes.py b/app/pydotorg/tests/test_classes.py similarity index 100% rename from pydotorg/tests/test_classes.py rename to app/pydotorg/tests/test_classes.py diff --git a/pydotorg/tests/test_context_processors.py b/app/pydotorg/tests/test_context_processors.py similarity index 99% rename from pydotorg/tests/test_context_processors.py rename to app/pydotorg/tests/test_context_processors.py index b1c8f3ed4..8a6eccf57 100644 --- a/pydotorg/tests/test_context_processors.py +++ b/app/pydotorg/tests/test_context_processors.py @@ -2,7 +2,7 @@ from django.urls import reverse from django.conf import settings -from pydotorg import context_processors +from app.pydotorg import context_processors from django.test import TestCase, RequestFactory from django.contrib.auth.models import AnonymousUser diff --git a/pydotorg/tests/test_middleware.py b/app/pydotorg/tests/test_middleware.py similarity index 100% rename from pydotorg/tests/test_middleware.py rename to app/pydotorg/tests/test_middleware.py diff --git a/pydotorg/tests/test_resources.py b/app/pydotorg/tests/test_resources.py similarity index 92% rename from pydotorg/tests/test_resources.py rename to app/pydotorg/tests/test_resources.py index 58c3af256..55a4e29b2 100644 --- a/pydotorg/tests/test_resources.py +++ b/app/pydotorg/tests/test_resources.py @@ -2,7 +2,7 @@ from django.contrib.auth import get_user_model from django.http import HttpRequest -from pydotorg.resources import ApiKeyOrGuestAuthentication +from app.pydotorg.resources import ApiKeyOrGuestAuthentication User = get_user_model() diff --git a/pydotorg/tests/test_views.py b/app/pydotorg/tests/test_views.py similarity index 97% rename from pydotorg/tests/test_views.py rename to app/pydotorg/tests/test_views.py index d6905a41c..0797a50af 100644 --- a/pydotorg/tests/test_views.py +++ b/app/pydotorg/tests/test_views.py @@ -4,7 +4,7 @@ import factory -from downloads.models import Release +from app.downloads.models import Release class ViewsTests(TestCase): diff --git a/pydotorg/urls.py b/app/pydotorg/urls.py similarity index 95% rename from pydotorg/urls.py rename to app/pydotorg/urls.py index f87ab496b..5c2f0ba09 100644 --- a/pydotorg/urls.py +++ b/app/pydotorg/urls.py @@ -1,4 +1,3 @@ -from django.conf.urls import handler404 from django.contrib import admin from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.conf.urls.static import static @@ -7,10 +6,10 @@ from django.views.generic.base import TemplateView from django.conf import settings -from cms.views import custom_404 -from users.views import HoneypotSignupView, CustomPasswordChangeView +from app.cms.views import custom_404 +from app.users.views import HoneypotSignupView, CustomPasswordChangeView -from . import views, urls_api +from app.pydotorg import views, urls_api handler404 = custom_404 diff --git a/pydotorg/urls_api.py b/app/pydotorg/urls_api.py similarity index 71% rename from pydotorg/urls_api.py rename to app/pydotorg/urls_api.py index 4afc7122e..02079e669 100644 --- a/pydotorg/urls_api.py +++ b/app/pydotorg/urls_api.py @@ -3,11 +3,11 @@ from rest_framework import routers from tastypie.api import Api -from downloads.api import OSResource, ReleaseResource, ReleaseFileResource -from downloads.api import OSViewSet, ReleaseViewSet, ReleaseFileViewSet -from pages.api import PageResource -from pages.api import PageViewSet -from sponsors.api import LogoPlacementeAPIList, SponsorshipAssetsAPIList +from app.downloads.api import OSResource, ReleaseResource, ReleaseFileResource +from app.downloads.api import OSViewSet, ReleaseViewSet, ReleaseFileViewSet +from app.pages.api import PageResource +from app.pages.api import PageViewSet +from app.sponsors.api import LogoPlacementeAPIList, SponsorshipAssetsAPIList v1_api = Api(api_name='v1') v1_api.register(PageResource()) diff --git a/pydotorg/views.py b/app/pydotorg/views.py similarity index 94% rename from pydotorg/views.py rename to app/pydotorg/views.py index 9777cf1aa..1cebcec15 100644 --- a/pydotorg/views.py +++ b/app/pydotorg/views.py @@ -2,8 +2,8 @@ from django.http import HttpResponse from django.views.generic.base import RedirectView, TemplateView -from codesamples.models import CodeSample -from downloads.models import Release +from app.codesamples.models import CodeSample +from app.downloads.models import Release def health(request): diff --git a/pydotorg/wsgi.py b/app/pydotorg/wsgi.py similarity index 94% rename from pydotorg/wsgi.py rename to app/pydotorg/wsgi.py index 92031712f..49547fc73 100644 --- a/pydotorg/wsgi.py +++ b/app/pydotorg/wsgi.py @@ -19,7 +19,7 @@ # if running multiple sites in the same mod_wsgi process. To fix this, use # mod_wsgi daemon mode with each site in its own daemon process, or use # os.environ["DJANGO_SETTINGS_MODULE"] = "pydotorg.settings" -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pydotorg.settings.local") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.pydotorg.settings.local") # This application object is used by any WSGI server configured to use this # file. This includes Django's development server, if the WSGI_APPLICATION diff --git a/sponsors/management/__init__.py b/app/sponsors/__init__.py similarity index 100% rename from sponsors/management/__init__.py rename to app/sponsors/__init__.py diff --git a/sponsors/admin.py b/app/sponsors/admin.py similarity index 99% rename from sponsors/admin.py rename to app/sponsors/admin.py index dc7278c08..82073c074 100644 --- a/sponsors/admin.py +++ b/app/sponsors/admin.py @@ -19,12 +19,12 @@ from import_export.admin import ImportExportActionModelAdmin from mailing.admin import BaseEmailTemplateAdmin -from sponsors.models import * -from sponsors.models.benefits import RequiredAssetMixin -from sponsors import views_admin -from sponsors.forms import SponsorshipReviewAdminForm, SponsorBenefitAdminInlineForm, RequiredImgAssetConfigurationForm, \ +from app.sponsors.models import * +from app.sponsors.models.benefits import RequiredAssetMixin +from app.sponsors import views_admin +from app.sponsors.forms import SponsorshipReviewAdminForm, SponsorBenefitAdminInlineForm, RequiredImgAssetConfigurationForm, \ SponsorshipBenefitAdminForm, CloneApplicationConfigForm -from cms.admin import ContentManageableModelAdmin +from app.cms.admin import ContentManageableModelAdmin def get_url_base_name(Model): diff --git a/sponsors/api.py b/app/sponsors/api.py similarity index 93% rename from sponsors/api.py rename to app/sponsors/api.py index 0d180be6d..2b5f083ff 100644 --- a/sponsors/api.py +++ b/app/sponsors/api.py @@ -4,8 +4,8 @@ from rest_framework import permissions from rest_framework.views import APIView from rest_framework.response import Response -from sponsors.models import BenefitFeature, LogoPlacement, Sponsorship, GenericAsset -from sponsors.serializers import LogoPlacementSerializer, FilterLogoPlacementsSerializer, FilterAssetsSerializer, \ +from app.sponsors.models import BenefitFeature, LogoPlacement, Sponsorship, GenericAsset +from app.sponsors.serializers import LogoPlacementSerializer, FilterLogoPlacementsSerializer, FilterAssetsSerializer, \ AssetSerializer diff --git a/sponsors/apps.py b/app/sponsors/apps.py similarity index 73% rename from sponsors/apps.py rename to app/sponsors/apps.py index 0eca9c16e..457066a06 100644 --- a/sponsors/apps.py +++ b/app/sponsors/apps.py @@ -3,4 +3,4 @@ class SponsorsAppConfig(AppConfig): - name = 'sponsors' + name = 'app.sponsors' diff --git a/sponsors/contracts.py b/app/sponsors/contracts.py similarity index 100% rename from sponsors/contracts.py rename to app/sponsors/contracts.py diff --git a/sponsors/cookies.py b/app/sponsors/cookies.py similarity index 100% rename from sponsors/cookies.py rename to app/sponsors/cookies.py diff --git a/sponsors/exceptions.py b/app/sponsors/exceptions.py similarity index 100% rename from sponsors/exceptions.py rename to app/sponsors/exceptions.py diff --git a/sponsors/forms.py b/app/sponsors/forms.py similarity index 99% rename from sponsors/forms.py rename to app/sponsors/forms.py index 4ced017c9..0222370c5 100644 --- a/sponsors/forms.py +++ b/app/sponsors/forms.py @@ -12,7 +12,7 @@ from django.utils.translation import gettext_lazy as _ from django_countries.fields import CountryField -from sponsors.models import ( +from app.sponsors.models import ( SponsorshipBenefit, SponsorshipPackage, SponsorshipProgram, diff --git a/sponsors/management/commands/__init__.py b/app/sponsors/management/__init__.py similarity index 100% rename from sponsors/management/commands/__init__.py rename to app/sponsors/management/__init__.py diff --git a/sponsors/migrations/__init__.py b/app/sponsors/management/commands/__init__.py similarity index 100% rename from sponsors/migrations/__init__.py rename to app/sponsors/management/commands/__init__.py diff --git a/sponsors/management/commands/check_sponsorship_assets_due_date.py b/app/sponsors/management/commands/check_sponsorship_assets_due_date.py similarity index 94% rename from sponsors/management/commands/check_sponsorship_assets_due_date.py rename to app/sponsors/management/commands/check_sponsorship_assets_due_date.py index 0f980fc90..6170b3b74 100644 --- a/sponsors/management/commands/check_sponsorship_assets_due_date.py +++ b/app/sponsors/management/commands/check_sponsorship_assets_due_date.py @@ -4,8 +4,8 @@ from django.db.models import Subquery from django.utils import timezone -from sponsors.models import Sponsorship, Contract, BenefitFeature -from sponsors.notifications import AssetCloseToDueDateNotificationToSponsors +from app.sponsors.models import Sponsorship, Contract, BenefitFeature +from app.sponsors.notifications import AssetCloseToDueDateNotificationToSponsors class Command(BaseCommand): diff --git a/sponsors/management/commands/create_contracts.py b/app/sponsors/management/commands/create_contracts.py similarity index 96% rename from sponsors/management/commands/create_contracts.py rename to app/sponsors/management/commands/create_contracts.py index 16bc986e0..0e0431a37 100644 --- a/sponsors/management/commands/create_contracts.py +++ b/app/sponsors/management/commands/create_contracts.py @@ -1,6 +1,6 @@ from django.core.management import BaseCommand -from sponsors.models import Sponsorship, Contract +from app.sponsors.models import Sponsorship, Contract # The reason to not use a data migration but a django management command # to deal with pre existing approved Sponsorships is due to migrations diff --git a/sponsors/management/commands/create_pycon_vouchers_for_sponsors.py b/app/sponsors/management/commands/create_pycon_vouchers_for_sponsors.py similarity index 98% rename from sponsors/management/commands/create_pycon_vouchers_for_sponsors.py rename to app/sponsors/management/commands/create_pycon_vouchers_for_sponsors.py index 3e3b4973d..c9eac357e 100644 --- a/sponsors/management/commands/create_pycon_vouchers_for_sponsors.py +++ b/app/sponsors/management/commands/create_pycon_vouchers_for_sponsors.py @@ -1,18 +1,16 @@ -import os from hashlib import sha1 from calendar import timegm from datetime import datetime -import sys + from urllib.parse import urlencode import requests from requests.exceptions import RequestException -from django.db.models import Q from django.conf import settings from django.core.management import BaseCommand -from sponsors.models import ( +from app.sponsors.models import ( SponsorBenefit, BenefitFeature, ProvidedTextAsset, diff --git a/sponsors/management/commands/fullfill_pycon_2022.py b/app/sponsors/management/commands/fullfill_pycon_2022.py similarity index 97% rename from sponsors/management/commands/fullfill_pycon_2022.py rename to app/sponsors/management/commands/fullfill_pycon_2022.py index 86ee26a1e..27d4f6f70 100644 --- a/sponsors/management/commands/fullfill_pycon_2022.py +++ b/app/sponsors/management/commands/fullfill_pycon_2022.py @@ -1,18 +1,15 @@ -import os from hashlib import sha1 from calendar import timegm from datetime import datetime -import sys from urllib.parse import urlencode import requests from requests.exceptions import RequestException -from django.db.models import Q from django.conf import settings from django.core.management import BaseCommand -from sponsors.models import ( +from app.sponsors.models import ( SponsorBenefit, BenefitFeature, ProvidedTextAsset, diff --git a/sponsors/migrations/0001_initial.py b/app/sponsors/migrations/0001_initial.py similarity index 100% rename from sponsors/migrations/0001_initial.py rename to app/sponsors/migrations/0001_initial.py diff --git a/sponsors/migrations/0002_auto_20150416_1853.py b/app/sponsors/migrations/0002_auto_20150416_1853.py similarity index 100% rename from sponsors/migrations/0002_auto_20150416_1853.py rename to app/sponsors/migrations/0002_auto_20150416_1853.py diff --git a/sponsors/migrations/0003_auto_20170821_2000.py b/app/sponsors/migrations/0003_auto_20170821_2000.py similarity index 100% rename from sponsors/migrations/0003_auto_20170821_2000.py rename to app/sponsors/migrations/0003_auto_20170821_2000.py diff --git a/sponsors/migrations/0004_auto_20201014_1622.py b/app/sponsors/migrations/0004_auto_20201014_1622.py similarity index 100% rename from sponsors/migrations/0004_auto_20201014_1622.py rename to app/sponsors/migrations/0004_auto_20201014_1622.py diff --git a/sponsors/migrations/0005_auto_20201015_0908.py b/app/sponsors/migrations/0005_auto_20201015_0908.py similarity index 100% rename from sponsors/migrations/0005_auto_20201015_0908.py rename to app/sponsors/migrations/0005_auto_20201015_0908.py diff --git a/sponsors/migrations/0006_auto_20201016_1517.py b/app/sponsors/migrations/0006_auto_20201016_1517.py similarity index 100% rename from sponsors/migrations/0006_auto_20201016_1517.py rename to app/sponsors/migrations/0006_auto_20201016_1517.py diff --git a/sponsors/migrations/0007_auto_20201021_1410.py b/app/sponsors/migrations/0007_auto_20201021_1410.py similarity index 100% rename from sponsors/migrations/0007_auto_20201021_1410.py rename to app/sponsors/migrations/0007_auto_20201021_1410.py diff --git a/sponsors/migrations/0008_auto_20201028_1814.py b/app/sponsors/migrations/0008_auto_20201028_1814.py similarity index 100% rename from sponsors/migrations/0008_auto_20201028_1814.py rename to app/sponsors/migrations/0008_auto_20201028_1814.py diff --git a/sponsors/migrations/0009_auto_20201103_1259.py b/app/sponsors/migrations/0009_auto_20201103_1259.py similarity index 100% rename from sponsors/migrations/0009_auto_20201103_1259.py rename to app/sponsors/migrations/0009_auto_20201103_1259.py diff --git a/sponsors/migrations/0010_auto_20201103_1313.py b/app/sponsors/migrations/0010_auto_20201103_1313.py similarity index 100% rename from sponsors/migrations/0010_auto_20201103_1313.py rename to app/sponsors/migrations/0010_auto_20201103_1313.py diff --git a/sponsors/migrations/0011_auto_20201111_1724.py b/app/sponsors/migrations/0011_auto_20201111_1724.py similarity index 100% rename from sponsors/migrations/0011_auto_20201111_1724.py rename to app/sponsors/migrations/0011_auto_20201111_1724.py diff --git a/sponsors/migrations/0012_sponsorship_for_modified_package.py b/app/sponsors/migrations/0012_sponsorship_for_modified_package.py similarity index 100% rename from sponsors/migrations/0012_sponsorship_for_modified_package.py rename to app/sponsors/migrations/0012_sponsorship_for_modified_package.py diff --git a/sponsors/migrations/0013_sponsorbenefit_benefit_internal_value.py b/app/sponsors/migrations/0013_sponsorbenefit_benefit_internal_value.py similarity index 100% rename from sponsors/migrations/0013_sponsorbenefit_benefit_internal_value.py rename to app/sponsors/migrations/0013_sponsorbenefit_benefit_internal_value.py diff --git a/sponsors/migrations/0014_auto_20201116_1437.py b/app/sponsors/migrations/0014_auto_20201116_1437.py similarity index 100% rename from sponsors/migrations/0014_auto_20201116_1437.py rename to app/sponsors/migrations/0014_auto_20201116_1437.py diff --git a/sponsors/migrations/0015_auto_20201117_1739.py b/app/sponsors/migrations/0015_auto_20201117_1739.py similarity index 100% rename from sponsors/migrations/0015_auto_20201117_1739.py rename to app/sponsors/migrations/0015_auto_20201117_1739.py diff --git a/sponsors/migrations/0016_auto_20201119_1448.py b/app/sponsors/migrations/0016_auto_20201119_1448.py similarity index 100% rename from sponsors/migrations/0016_auto_20201119_1448.py rename to app/sponsors/migrations/0016_auto_20201119_1448.py diff --git a/sponsors/migrations/0017_sponsorbenefit_added_by_user.py b/app/sponsors/migrations/0017_sponsorbenefit_added_by_user.py similarity index 100% rename from sponsors/migrations/0017_sponsorbenefit_added_by_user.py rename to app/sponsors/migrations/0017_sponsorbenefit_added_by_user.py diff --git a/sponsors/migrations/0018_auto_20201201_1659.py b/app/sponsors/migrations/0018_auto_20201201_1659.py similarity index 100% rename from sponsors/migrations/0018_auto_20201201_1659.py rename to app/sponsors/migrations/0018_auto_20201201_1659.py diff --git a/sponsors/migrations/0019_sponsor_twitter_handle.py b/app/sponsors/migrations/0019_sponsor_twitter_handle.py similarity index 100% rename from sponsors/migrations/0019_sponsor_twitter_handle.py rename to app/sponsors/migrations/0019_sponsor_twitter_handle.py diff --git a/sponsors/migrations/0019_statementofwork.py b/app/sponsors/migrations/0019_statementofwork.py similarity index 100% rename from sponsors/migrations/0019_statementofwork.py rename to app/sponsors/migrations/0019_statementofwork.py diff --git a/sponsors/migrations/0020_auto_20201210_1802.py b/app/sponsors/migrations/0020_auto_20201210_1802.py similarity index 100% rename from sponsors/migrations/0020_auto_20201210_1802.py rename to app/sponsors/migrations/0020_auto_20201210_1802.py diff --git a/sponsors/migrations/0020_sponsorshipbenefit_unavailable.py b/app/sponsors/migrations/0020_sponsorshipbenefit_unavailable.py similarity index 100% rename from sponsors/migrations/0020_sponsorshipbenefit_unavailable.py rename to app/sponsors/migrations/0020_sponsorshipbenefit_unavailable.py diff --git a/sponsors/migrations/0021_auto_20201211_2120.py b/app/sponsors/migrations/0021_auto_20201211_2120.py similarity index 100% rename from sponsors/migrations/0021_auto_20201211_2120.py rename to app/sponsors/migrations/0021_auto_20201211_2120.py diff --git a/sponsors/migrations/0022_sponsorcontact_administrative.py b/app/sponsors/migrations/0022_sponsorcontact_administrative.py similarity index 100% rename from sponsors/migrations/0022_sponsorcontact_administrative.py rename to app/sponsors/migrations/0022_sponsorcontact_administrative.py diff --git a/sponsors/migrations/0023_merge_20210406_1522.py b/app/sponsors/migrations/0023_merge_20210406_1522.py similarity index 100% rename from sponsors/migrations/0023_merge_20210406_1522.py rename to app/sponsors/migrations/0023_merge_20210406_1522.py diff --git a/sponsors/migrations/0024_auto_20210414_1449.py b/app/sponsors/migrations/0024_auto_20210414_1449.py similarity index 100% rename from sponsors/migrations/0024_auto_20210414_1449.py rename to app/sponsors/migrations/0024_auto_20210414_1449.py diff --git a/sponsors/migrations/0025_auto_20210416_1939.py b/app/sponsors/migrations/0025_auto_20210416_1939.py similarity index 100% rename from sponsors/migrations/0025_auto_20210416_1939.py rename to app/sponsors/migrations/0025_auto_20210416_1939.py diff --git a/sponsors/migrations/0026_auto_20210416_1940.py b/app/sponsors/migrations/0026_auto_20210416_1940.py similarity index 100% rename from sponsors/migrations/0026_auto_20210416_1940.py rename to app/sponsors/migrations/0026_auto_20210416_1940.py diff --git a/sponsors/migrations/0027_sponsorbenefit_program_name.py b/app/sponsors/migrations/0027_sponsorbenefit_program_name.py similarity index 100% rename from sponsors/migrations/0027_sponsorbenefit_program_name.py rename to app/sponsors/migrations/0027_sponsorbenefit_program_name.py diff --git a/sponsors/migrations/0028_auto_20210707_1426.py b/app/sponsors/migrations/0028_auto_20210707_1426.py similarity index 100% rename from sponsors/migrations/0028_auto_20210707_1426.py rename to app/sponsors/migrations/0028_auto_20210707_1426.py diff --git a/sponsors/migrations/0029_auto_20210715_2015.py b/app/sponsors/migrations/0029_auto_20210715_2015.py similarity index 100% rename from sponsors/migrations/0029_auto_20210715_2015.py rename to app/sponsors/migrations/0029_auto_20210715_2015.py diff --git a/sponsors/migrations/0030_auto_20210715_2023.py b/app/sponsors/migrations/0030_auto_20210715_2023.py similarity index 100% rename from sponsors/migrations/0030_auto_20210715_2023.py rename to app/sponsors/migrations/0030_auto_20210715_2023.py diff --git a/sponsors/migrations/0031_auto_20210810_1232.py b/app/sponsors/migrations/0031_auto_20210810_1232.py similarity index 100% rename from sponsors/migrations/0031_auto_20210810_1232.py rename to app/sponsors/migrations/0031_auto_20210810_1232.py diff --git a/sponsors/migrations/0032_sponsorcontact_accounting.py b/app/sponsors/migrations/0032_sponsorcontact_accounting.py similarity index 100% rename from sponsors/migrations/0032_sponsorcontact_accounting.py rename to app/sponsors/migrations/0032_sponsorcontact_accounting.py diff --git a/sponsors/migrations/0033_tieredquantity_tieredquantityconfiguration.py b/app/sponsors/migrations/0033_tieredquantity_tieredquantityconfiguration.py similarity index 100% rename from sponsors/migrations/0033_tieredquantity_tieredquantityconfiguration.py rename to app/sponsors/migrations/0033_tieredquantity_tieredquantityconfiguration.py diff --git a/sponsors/migrations/0034_contract_document_docx.py b/app/sponsors/migrations/0034_contract_document_docx.py similarity index 100% rename from sponsors/migrations/0034_contract_document_docx.py rename to app/sponsors/migrations/0034_contract_document_docx.py diff --git a/sponsors/migrations/0035_auto_20210826_1929.py b/app/sponsors/migrations/0035_auto_20210826_1929.py similarity index 100% rename from sponsors/migrations/0035_auto_20210826_1929.py rename to app/sponsors/migrations/0035_auto_20210826_1929.py diff --git a/sponsors/migrations/0036_auto_20210826_1930.py b/app/sponsors/migrations/0036_auto_20210826_1930.py similarity index 100% rename from sponsors/migrations/0036_auto_20210826_1930.py rename to app/sponsors/migrations/0036_auto_20210826_1930.py diff --git a/sponsors/migrations/0037_sponsorship_package.py b/app/sponsors/migrations/0037_sponsorship_package.py similarity index 100% rename from sponsors/migrations/0037_sponsorship_package.py rename to app/sponsors/migrations/0037_sponsorship_package.py diff --git a/sponsors/migrations/0038_auto_20210827_1223.py b/app/sponsors/migrations/0038_auto_20210827_1223.py similarity index 100% rename from sponsors/migrations/0038_auto_20210827_1223.py rename to app/sponsors/migrations/0038_auto_20210827_1223.py diff --git a/sponsors/migrations/0039_auto_20210827_1248.py b/app/sponsors/migrations/0039_auto_20210827_1248.py similarity index 100% rename from sponsors/migrations/0039_auto_20210827_1248.py rename to app/sponsors/migrations/0039_auto_20210827_1248.py diff --git a/sponsors/migrations/0040_auto_20210827_1313.py b/app/sponsors/migrations/0040_auto_20210827_1313.py similarity index 100% rename from sponsors/migrations/0040_auto_20210827_1313.py rename to app/sponsors/migrations/0040_auto_20210827_1313.py diff --git a/sponsors/migrations/0041_auto_20210827_1313.py b/app/sponsors/migrations/0041_auto_20210827_1313.py similarity index 100% rename from sponsors/migrations/0041_auto_20210827_1313.py rename to app/sponsors/migrations/0041_auto_20210827_1313.py diff --git a/sponsors/migrations/0042_auto_20210827_1318.py b/app/sponsors/migrations/0042_auto_20210827_1318.py similarity index 100% rename from sponsors/migrations/0042_auto_20210827_1318.py rename to app/sponsors/migrations/0042_auto_20210827_1318.py diff --git a/sponsors/migrations/0043_auto_20210827_1343.py b/app/sponsors/migrations/0043_auto_20210827_1343.py similarity index 100% rename from sponsors/migrations/0043_auto_20210827_1343.py rename to app/sponsors/migrations/0043_auto_20210827_1343.py diff --git a/sponsors/migrations/0044_auto_20210827_1344.py b/app/sponsors/migrations/0044_auto_20210827_1344.py similarity index 100% rename from sponsors/migrations/0044_auto_20210827_1344.py rename to app/sponsors/migrations/0044_auto_20210827_1344.py diff --git a/sponsors/migrations/0045_add_added_by_user_sponsorbenefit.py b/app/sponsors/migrations/0045_add_added_by_user_sponsorbenefit.py similarity index 100% rename from sponsors/migrations/0045_add_added_by_user_sponsorbenefit.py rename to app/sponsors/migrations/0045_add_added_by_user_sponsorbenefit.py diff --git a/sponsors/migrations/0046_sponsorshippackage_advertise.py b/app/sponsors/migrations/0046_sponsorshippackage_advertise.py similarity index 100% rename from sponsors/migrations/0046_sponsorshippackage_advertise.py rename to app/sponsors/migrations/0046_sponsorshippackage_advertise.py diff --git a/sponsors/migrations/0047_auto_20210908_1357.py b/app/sponsors/migrations/0047_auto_20210908_1357.py similarity index 100% rename from sponsors/migrations/0047_auto_20210908_1357.py rename to app/sponsors/migrations/0047_auto_20210908_1357.py diff --git a/sponsors/migrations/0048_auto_20210915_1425.py b/app/sponsors/migrations/0048_auto_20210915_1425.py similarity index 100% rename from sponsors/migrations/0048_auto_20210915_1425.py rename to app/sponsors/migrations/0048_auto_20210915_1425.py diff --git a/sponsors/migrations/0049_sponsoremailnotificationtemplate.py b/app/sponsors/migrations/0049_sponsoremailnotificationtemplate.py similarity index 100% rename from sponsors/migrations/0049_sponsoremailnotificationtemplate.py rename to app/sponsors/migrations/0049_sponsoremailnotificationtemplate.py diff --git a/sponsors/migrations/0050_emailtargetable_emailtargetableconfiguration.py b/app/sponsors/migrations/0050_emailtargetable_emailtargetableconfiguration.py similarity index 100% rename from sponsors/migrations/0050_emailtargetable_emailtargetableconfiguration.py rename to app/sponsors/migrations/0050_emailtargetable_emailtargetableconfiguration.py diff --git a/sponsors/migrations/0051_auto_20211022_1403.py b/app/sponsors/migrations/0051_auto_20211022_1403.py similarity index 100% rename from sponsors/migrations/0051_auto_20211022_1403.py rename to app/sponsors/migrations/0051_auto_20211022_1403.py diff --git a/sponsors/migrations/0052_requiredimgasset_requiredimgassetconfiguration.py b/app/sponsors/migrations/0052_requiredimgasset_requiredimgassetconfiguration.py similarity index 100% rename from sponsors/migrations/0052_requiredimgasset_requiredimgassetconfiguration.py rename to app/sponsors/migrations/0052_requiredimgasset_requiredimgassetconfiguration.py diff --git a/sponsors/migrations/0053_genericasset_imgasset.py b/app/sponsors/migrations/0053_genericasset_imgasset.py similarity index 95% rename from sponsors/migrations/0053_genericasset_imgasset.py rename to app/sponsors/migrations/0053_genericasset_imgasset.py index 616016c0f..1876437b1 100644 --- a/sponsors/migrations/0053_genericasset_imgasset.py +++ b/app/sponsors/migrations/0053_genericasset_imgasset.py @@ -2,7 +2,7 @@ from django.db import migrations, models import django.db.models.deletion -import sponsors.models.assets +import app.sponsors.models.assets class Migration(migrations.Migration): @@ -32,7 +32,7 @@ class Migration(migrations.Migration): name='ImgAsset', fields=[ ('genericasset_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='sponsors.GenericAsset')), - ('image', models.ImageField(null=True, upload_to=sponsors.models.assets.generic_asset_path)), + ('image', models.ImageField(null=True, upload_to=app.sponsors.models.assets.generic_asset_path)), ], options={ 'verbose_name': 'Image Asset', diff --git a/sponsors/migrations/0054_auto_20211026_1432.py b/app/sponsors/migrations/0054_auto_20211026_1432.py similarity index 100% rename from sponsors/migrations/0054_auto_20211026_1432.py rename to app/sponsors/migrations/0054_auto_20211026_1432.py diff --git a/sponsors/migrations/0055_auto_20211026_1512.py b/app/sponsors/migrations/0055_auto_20211026_1512.py similarity index 100% rename from sponsors/migrations/0055_auto_20211026_1512.py rename to app/sponsors/migrations/0055_auto_20211026_1512.py diff --git a/sponsors/migrations/0056_textasset.py b/app/sponsors/migrations/0056_textasset.py similarity index 100% rename from sponsors/migrations/0056_textasset.py rename to app/sponsors/migrations/0056_textasset.py diff --git a/sponsors/migrations/0057_auto_20211026_1529.py b/app/sponsors/migrations/0057_auto_20211026_1529.py similarity index 100% rename from sponsors/migrations/0057_auto_20211026_1529.py rename to app/sponsors/migrations/0057_auto_20211026_1529.py diff --git a/sponsors/migrations/0058_auto_20211029_1427.py b/app/sponsors/migrations/0058_auto_20211029_1427.py similarity index 100% rename from sponsors/migrations/0058_auto_20211029_1427.py rename to app/sponsors/migrations/0058_auto_20211029_1427.py diff --git a/sponsors/migrations/0059_auto_20211029_1503.py b/app/sponsors/migrations/0059_auto_20211029_1503.py similarity index 100% rename from sponsors/migrations/0059_auto_20211029_1503.py rename to app/sponsors/migrations/0059_auto_20211029_1503.py diff --git a/sponsors/migrations/0060_auto_20211111_1526.py b/app/sponsors/migrations/0060_auto_20211111_1526.py similarity index 100% rename from sponsors/migrations/0060_auto_20211111_1526.py rename to app/sponsors/migrations/0060_auto_20211111_1526.py diff --git a/sponsors/migrations/0061_auto_20211108_1419.py b/app/sponsors/migrations/0061_auto_20211108_1419.py similarity index 100% rename from sponsors/migrations/0061_auto_20211108_1419.py rename to app/sponsors/migrations/0061_auto_20211108_1419.py diff --git a/sponsors/migrations/0062_auto_20211111_1529.py b/app/sponsors/migrations/0062_auto_20211111_1529.py similarity index 100% rename from sponsors/migrations/0062_auto_20211111_1529.py rename to app/sponsors/migrations/0062_auto_20211111_1529.py diff --git a/sponsors/migrations/0063_auto_20211220_1422.py b/app/sponsors/migrations/0063_auto_20211220_1422.py similarity index 100% rename from sponsors/migrations/0063_auto_20211220_1422.py rename to app/sponsors/migrations/0063_auto_20211220_1422.py diff --git a/sponsors/migrations/0064_sponsorshippackage_slug.py b/app/sponsors/migrations/0064_sponsorshippackage_slug.py similarity index 100% rename from sponsors/migrations/0064_sponsorshippackage_slug.py rename to app/sponsors/migrations/0064_sponsorshippackage_slug.py diff --git a/sponsors/migrations/0065_auto_20211223_1309.py b/app/sponsors/migrations/0065_auto_20211223_1309.py similarity index 100% rename from sponsors/migrations/0065_auto_20211223_1309.py rename to app/sponsors/migrations/0065_auto_20211223_1309.py diff --git a/sponsors/migrations/0066_auto_20211223_1318.py b/app/sponsors/migrations/0066_auto_20211223_1318.py similarity index 100% rename from sponsors/migrations/0066_auto_20211223_1318.py rename to app/sponsors/migrations/0066_auto_20211223_1318.py diff --git a/sponsors/migrations/0067_sponsorbenefit_a_la_carte.py b/app/sponsors/migrations/0067_sponsorbenefit_a_la_carte.py similarity index 100% rename from sponsors/migrations/0067_sponsorbenefit_a_la_carte.py rename to app/sponsors/migrations/0067_sponsorbenefit_a_la_carte.py diff --git a/sponsors/migrations/0068_auto_20220110_1841.py b/app/sponsors/migrations/0068_auto_20220110_1841.py similarity index 100% rename from sponsors/migrations/0068_auto_20220110_1841.py rename to app/sponsors/migrations/0068_auto_20220110_1841.py diff --git a/sponsors/migrations/0069_auto_20220110_2148.py b/app/sponsors/migrations/0069_auto_20220110_2148.py similarity index 92% rename from sponsors/migrations/0069_auto_20220110_2148.py rename to app/sponsors/migrations/0069_auto_20220110_2148.py index 8492ce06b..d94621509 100644 --- a/sponsors/migrations/0069_auto_20220110_2148.py +++ b/app/sponsors/migrations/0069_auto_20220110_2148.py @@ -2,7 +2,7 @@ from django.db import migrations, models import django.db.models.deletion -import sponsors.models.benefits +import app.sponsors.models.benefits class Migration(migrations.Migration): @@ -27,7 +27,7 @@ class Migration(migrations.Migration): 'abstract': False, 'base_manager_name': 'objects', }, - bases=(sponsors.models.benefits.ProvidedAssetMixin, 'sponsors.benefitfeature', models.Model), + bases=(app.sponsors.models.benefits.ProvidedAssetMixin, 'sponsors.benefitfeature', models.Model), ), migrations.CreateModel( name='ProvidedTextAssetConfiguration', @@ -44,7 +44,7 @@ class Migration(migrations.Migration): 'abstract': False, 'base_manager_name': 'objects', }, - bases=(sponsors.models.benefits.AssetConfigurationMixin, 'sponsors.benefitfeatureconfiguration', models.Model), + bases=(app.sponsors.models.benefits.AssetConfigurationMixin, 'sponsors.benefitfeatureconfiguration', models.Model), ), migrations.AddConstraint( model_name='providedtextassetconfiguration', diff --git a/sponsors/migrations/0070_auto_20220111_2055.py b/app/sponsors/migrations/0070_auto_20220111_2055.py similarity index 91% rename from sponsors/migrations/0070_auto_20220111_2055.py rename to app/sponsors/migrations/0070_auto_20220111_2055.py index 94f8075cb..dc39e4cae 100644 --- a/sponsors/migrations/0070_auto_20220111_2055.py +++ b/app/sponsors/migrations/0070_auto_20220111_2055.py @@ -2,8 +2,8 @@ from django.db import migrations, models import django.db.models.deletion -import sponsors.models.assets -import sponsors.models.benefits +import app.sponsors.models.assets +import app.sponsors.models.benefits class Migration(migrations.Migration): @@ -17,7 +17,7 @@ class Migration(migrations.Migration): name='FileAsset', fields=[ ('genericasset_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='sponsors.GenericAsset')), - ('file', models.FileField(null=True, upload_to=sponsors.models.assets.generic_asset_path)), + ('file', models.FileField(null=True, upload_to=app.sponsors.models.assets.generic_asset_path)), ], options={ 'verbose_name': 'File Asset', @@ -42,7 +42,7 @@ class Migration(migrations.Migration): 'abstract': False, 'base_manager_name': 'objects', }, - bases=(sponsors.models.benefits.ProvidedAssetMixin, 'sponsors.benefitfeature', models.Model), + bases=(app.sponsors.models.benefits.ProvidedAssetMixin, 'sponsors.benefitfeature', models.Model), ), migrations.CreateModel( name='ProvidedFileAssetConfiguration', @@ -61,7 +61,7 @@ class Migration(migrations.Migration): 'abstract': False, 'base_manager_name': 'objects', }, - bases=(sponsors.models.benefits.AssetConfigurationMixin, 'sponsors.benefitfeatureconfiguration', models.Model), + bases=(app.sponsors.models.benefits.AssetConfigurationMixin, 'sponsors.benefitfeatureconfiguration', models.Model), ), migrations.AddField( model_name='providedtextasset', diff --git a/sponsors/migrations/0071_auto_20220113_1843.py b/app/sponsors/migrations/0071_auto_20220113_1843.py similarity index 100% rename from sponsors/migrations/0071_auto_20220113_1843.py rename to app/sponsors/migrations/0071_auto_20220113_1843.py diff --git a/sponsors/migrations/0072_auto_20220125_2005.py b/app/sponsors/migrations/0072_auto_20220125_2005.py similarity index 100% rename from sponsors/migrations/0072_auto_20220125_2005.py rename to app/sponsors/migrations/0072_auto_20220125_2005.py diff --git a/sponsors/migrations/0073_auto_20220128_1906.py b/app/sponsors/migrations/0073_auto_20220128_1906.py similarity index 93% rename from sponsors/migrations/0073_auto_20220128_1906.py rename to app/sponsors/migrations/0073_auto_20220128_1906.py index 39abe43b8..e7a2f0db4 100644 --- a/sponsors/migrations/0073_auto_20220128_1906.py +++ b/app/sponsors/migrations/0073_auto_20220128_1906.py @@ -2,7 +2,7 @@ from django.db import migrations, models import django.db.models.deletion -import sponsors.models.benefits +import app.sponsors.models.benefits class Migration(migrations.Migration): @@ -28,7 +28,7 @@ class Migration(migrations.Migration): 'abstract': False, 'base_manager_name': 'objects', }, - bases=(sponsors.models.benefits.RequiredAssetMixin, 'sponsors.benefitfeature', models.Model), + bases=(app.sponsors.models.benefits.RequiredAssetMixin, 'sponsors.benefitfeature', models.Model), ), migrations.CreateModel( name='RequiredResponseAssetConfiguration', @@ -46,7 +46,7 @@ class Migration(migrations.Migration): 'abstract': False, 'base_manager_name': 'objects', }, - bases=(sponsors.models.benefits.AssetConfigurationMixin, 'sponsors.benefitfeatureconfiguration', models.Model), + bases=(app.sponsors.models.benefits.AssetConfigurationMixin, 'sponsors.benefitfeatureconfiguration', models.Model), ), migrations.CreateModel( name='ResponseAsset', diff --git a/sponsors/migrations/0074_auto_20220211_1659.py b/app/sponsors/migrations/0074_auto_20220211_1659.py similarity index 100% rename from sponsors/migrations/0074_auto_20220211_1659.py rename to app/sponsors/migrations/0074_auto_20220211_1659.py diff --git a/sponsors/migrations/0075_auto_20220303_2023.py b/app/sponsors/migrations/0075_auto_20220303_2023.py similarity index 100% rename from sponsors/migrations/0075_auto_20220303_2023.py rename to app/sponsors/migrations/0075_auto_20220303_2023.py diff --git a/sponsors/migrations/0076_auto_20220728_1550.py b/app/sponsors/migrations/0076_auto_20220728_1550.py similarity index 100% rename from sponsors/migrations/0076_auto_20220728_1550.py rename to app/sponsors/migrations/0076_auto_20220728_1550.py diff --git a/sponsors/migrations/0077_sponsorshipcurrentyear.py b/app/sponsors/migrations/0077_sponsorshipcurrentyear.py similarity index 100% rename from sponsors/migrations/0077_sponsorshipcurrentyear.py rename to app/sponsors/migrations/0077_sponsorshipcurrentyear.py diff --git a/sponsors/migrations/0078_init_current_year_singleton.py b/app/sponsors/migrations/0078_init_current_year_singleton.py similarity index 100% rename from sponsors/migrations/0078_init_current_year_singleton.py rename to app/sponsors/migrations/0078_init_current_year_singleton.py diff --git a/sponsors/migrations/0079_index_to_force_singleton.py b/app/sponsors/migrations/0079_index_to_force_singleton.py similarity index 100% rename from sponsors/migrations/0079_index_to_force_singleton.py rename to app/sponsors/migrations/0079_index_to_force_singleton.py diff --git a/sponsors/migrations/0080_auto_20220728_1644.py b/app/sponsors/migrations/0080_auto_20220728_1644.py similarity index 100% rename from sponsors/migrations/0080_auto_20220728_1644.py rename to app/sponsors/migrations/0080_auto_20220728_1644.py diff --git a/sponsors/migrations/0081_sponsorship_application_year.py b/app/sponsors/migrations/0081_sponsorship_application_year.py similarity index 100% rename from sponsors/migrations/0081_sponsorship_application_year.py rename to app/sponsors/migrations/0081_sponsorship_application_year.py diff --git a/sponsors/migrations/0082_auto_20220729_1613.py b/app/sponsors/migrations/0082_auto_20220729_1613.py similarity index 100% rename from sponsors/migrations/0082_auto_20220729_1613.py rename to app/sponsors/migrations/0082_auto_20220729_1613.py diff --git a/sponsors/migrations/0083_auto_20220729_1624.py b/app/sponsors/migrations/0083_auto_20220729_1624.py similarity index 100% rename from sponsors/migrations/0083_auto_20220729_1624.py rename to app/sponsors/migrations/0083_auto_20220729_1624.py diff --git a/sponsors/migrations/0084_init_configured_objs_year.py b/app/sponsors/migrations/0084_init_configured_objs_year.py similarity index 100% rename from sponsors/migrations/0084_init_configured_objs_year.py rename to app/sponsors/migrations/0084_init_configured_objs_year.py diff --git a/sponsors/migrations/0085_auto_20220730_0945.py b/app/sponsors/migrations/0085_auto_20220730_0945.py similarity index 100% rename from sponsors/migrations/0085_auto_20220730_0945.py rename to app/sponsors/migrations/0085_auto_20220730_0945.py diff --git a/sponsors/migrations/0086_auto_20220809_1655.py b/app/sponsors/migrations/0086_auto_20220809_1655.py similarity index 100% rename from sponsors/migrations/0086_auto_20220809_1655.py rename to app/sponsors/migrations/0086_auto_20220809_1655.py diff --git a/sponsors/migrations/0087_auto_20220810_1647.py b/app/sponsors/migrations/0087_auto_20220810_1647.py similarity index 100% rename from sponsors/migrations/0087_auto_20220810_1647.py rename to app/sponsors/migrations/0087_auto_20220810_1647.py diff --git a/sponsors/migrations/0088_auto_20220810_1655.py b/app/sponsors/migrations/0088_auto_20220810_1655.py similarity index 100% rename from sponsors/migrations/0088_auto_20220810_1655.py rename to app/sponsors/migrations/0088_auto_20220810_1655.py diff --git a/sponsors/migrations/0089_auto_20220812_1312.py b/app/sponsors/migrations/0089_auto_20220812_1312.py similarity index 100% rename from sponsors/migrations/0089_auto_20220812_1312.py rename to app/sponsors/migrations/0089_auto_20220812_1312.py diff --git a/sponsors/migrations/0090_auto_20220812_1314.py b/app/sponsors/migrations/0090_auto_20220812_1314.py similarity index 100% rename from sponsors/migrations/0090_auto_20220812_1314.py rename to app/sponsors/migrations/0090_auto_20220812_1314.py diff --git a/sponsors/migrations/0091_sponsorshippackage_allow_a_la_carte.py b/app/sponsors/migrations/0091_sponsorshippackage_allow_a_la_carte.py similarity index 100% rename from sponsors/migrations/0091_sponsorshippackage_allow_a_la_carte.py rename to app/sponsors/migrations/0091_sponsorshippackage_allow_a_la_carte.py diff --git a/sponsors/migrations/0092_auto_20220816_1517.py b/app/sponsors/migrations/0092_auto_20220816_1517.py similarity index 100% rename from sponsors/migrations/0092_auto_20220816_1517.py rename to app/sponsors/migrations/0092_auto_20220816_1517.py diff --git a/sponsors/migrations/0093_auto_20230214_2113.py b/app/sponsors/migrations/0093_auto_20230214_2113.py similarity index 100% rename from sponsors/migrations/0093_auto_20230214_2113.py rename to app/sponsors/migrations/0093_auto_20230214_2113.py diff --git a/sponsors/migrations/0094_sponsorship_locked.py b/app/sponsors/migrations/0094_sponsorship_locked.py similarity index 91% rename from sponsors/migrations/0094_sponsorship_locked.py rename to app/sponsors/migrations/0094_sponsorship_locked.py index c1c6a8152..f4563e8de 100644 --- a/sponsors/migrations/0094_sponsorship_locked.py +++ b/app/sponsors/migrations/0094_sponsorship_locked.py @@ -2,7 +2,7 @@ from django.db import migrations, models -from sponsors.models.sponsorship import Sponsorship as _Sponsorship +from app.sponsors.models.sponsorship import Sponsorship as _Sponsorship def forwards_func(apps, schema_editor): Sponsorship = apps.get_model('sponsors', 'Sponsorship') diff --git a/sponsors/migrations/0095_auto_20231214_2025.py b/app/sponsors/migrations/0095_auto_20231214_2025.py similarity index 100% rename from sponsors/migrations/0095_auto_20231214_2025.py rename to app/sponsors/migrations/0095_auto_20231214_2025.py diff --git a/sponsors/migrations/0096_auto_20231214_2108.py b/app/sponsors/migrations/0096_auto_20231214_2108.py similarity index 100% rename from sponsors/migrations/0096_auto_20231214_2108.py rename to app/sponsors/migrations/0096_auto_20231214_2108.py diff --git a/sponsors/migrations/0097_sponsorship_renewal.py b/app/sponsors/migrations/0097_sponsorship_renewal.py similarity index 100% rename from sponsors/migrations/0097_sponsorship_renewal.py rename to app/sponsors/migrations/0097_sponsorship_renewal.py diff --git a/sponsors/migrations/0098_auto_20231219_1910.py b/app/sponsors/migrations/0098_auto_20231219_1910.py similarity index 100% rename from sponsors/migrations/0098_auto_20231219_1910.py rename to app/sponsors/migrations/0098_auto_20231219_1910.py diff --git a/sponsors/migrations/0099_auto_20231224_1854.py b/app/sponsors/migrations/0099_auto_20231224_1854.py similarity index 100% rename from sponsors/migrations/0099_auto_20231224_1854.py rename to app/sponsors/migrations/0099_auto_20231224_1854.py diff --git a/sponsors/migrations/0100_auto_20240107_1054.py b/app/sponsors/migrations/0100_auto_20240107_1054.py similarity index 100% rename from sponsors/migrations/0100_auto_20240107_1054.py rename to app/sponsors/migrations/0100_auto_20240107_1054.py diff --git a/sponsors/migrations/0101_sponsor_linked_in_page_url.py b/app/sponsors/migrations/0101_sponsor_linked_in_page_url.py similarity index 100% rename from sponsors/migrations/0101_sponsor_linked_in_page_url.py rename to app/sponsors/migrations/0101_sponsor_linked_in_page_url.py diff --git a/sponsors/migrations/0102_auto_20240509_2037.py b/app/sponsors/migrations/0102_auto_20240509_2037.py similarity index 100% rename from sponsors/migrations/0102_auto_20240509_2037.py rename to app/sponsors/migrations/0102_auto_20240509_2037.py diff --git a/sponsors/migrations/0103_alter_benefitfeature_polymorphic_ctype_and_more.py b/app/sponsors/migrations/0103_alter_benefitfeature_polymorphic_ctype_and_more.py similarity index 100% rename from sponsors/migrations/0103_alter_benefitfeature_polymorphic_ctype_and_more.py rename to app/sponsors/migrations/0103_alter_benefitfeature_polymorphic_ctype_and_more.py diff --git a/sponsors/pandoc_filters/__init__.py b/app/sponsors/migrations/__init__.py similarity index 100% rename from sponsors/pandoc_filters/__init__.py rename to app/sponsors/migrations/__init__.py diff --git a/app/sponsors/models/__init__.py b/app/sponsors/models/__init__.py new file mode 100644 index 000000000..45f50e5ee --- /dev/null +++ b/app/sponsors/models/__init__.py @@ -0,0 +1,17 @@ +""" +Python.org sponsors app is heavily db-oriented. This results in +a huge models.py. To reduce file length the models are being +structured as a python package. +""" + +from app.sponsors.models.assets import GenericAsset, ImgAsset, TextAsset, FileAsset, ResponseAsset +from app.sponsors.models.notifications import SponsorEmailNotificationTemplate, SPONSOR_TEMPLATE_HELP_TEXT +from app.sponsors.models.sponsors import Sponsor, SponsorContact, SponsorBenefit +from app.sponsors.models.benefits import BaseLogoPlacement, BaseTieredBenefit, BaseEmailTargetable, BenefitFeatureConfiguration, \ + LogoPlacementConfiguration, TieredBenefitConfiguration, EmailTargetableConfiguration, BenefitFeature, \ + LogoPlacement, EmailTargetable, TieredBenefit, RequiredImgAsset, RequiredImgAssetConfiguration, \ + RequiredTextAssetConfiguration, RequiredTextAsset, RequiredResponseAssetConfiguration, RequiredResponseAsset, \ + ProvidedTextAssetConfiguration, ProvidedTextAsset, ProvidedFileAssetConfiguration, ProvidedFileAsset +from app.sponsors.models.sponsorship import Sponsorship, SponsorshipProgram, SponsorshipBenefit, Sponsorship, SponsorshipPackage, \ + SponsorshipCurrentYear +from app.sponsors.models.contract import LegalClause, Contract, signed_contract_random_path diff --git a/sponsors/models/assets.py b/app/sponsors/models/assets.py similarity index 97% rename from sponsors/models/assets.py rename to app/sponsors/models/assets.py index 9b4899b5a..17cda0f6e 100644 --- a/sponsors/models/assets.py +++ b/app/sponsors/models/assets.py @@ -10,10 +10,9 @@ from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.db.models.fields.files import ImageFieldFile, FileField -from polymorphic.managers import PolymorphicManager from polymorphic.models import PolymorphicModel -from sponsors.models.managers import GenericAssetQuerySet +from app.sponsors.models.managers import GenericAssetQuerySet def generic_asset_path(instance, filename): diff --git a/sponsors/models/benefits.py b/app/sponsors/models/benefits.py similarity index 98% rename from sponsors/models/benefits.py rename to app/sponsors/models/benefits.py index 750f5af6c..d0a117403 100644 --- a/sponsors/models/benefits.py +++ b/app/sponsors/models/benefits.py @@ -7,8 +7,8 @@ from django.urls import reverse from polymorphic.models import PolymorphicModel -from sponsors.models.assets import ImgAsset, TextAsset, FileAsset, ResponseAsset, Response -from sponsors.models.enums import ( +from app.sponsors.models.assets import ImgAsset, TextAsset, FileAsset, ResponseAsset, Response +from app.sponsors.models.enums import ( PublisherChoices, LogoPlacementChoices, AssetsRelatedTo, @@ -16,7 +16,7 @@ ######################################## # Benefit features abstract classes -from sponsors.models.managers import BenefitFeatureQuerySet, BenefitFeatureConfigurationQuerySet +from app.sponsors.models.managers import BenefitFeatureQuerySet, BenefitFeatureConfigurationQuerySet ######################################## diff --git a/sponsors/models/contract.py b/app/sponsors/models/contract.py similarity index 98% rename from sponsors/models/contract.py rename to app/sponsors/models/contract.py index 3cbf389e2..b87215cbc 100644 --- a/sponsors/models/contract.py +++ b/app/sponsors/models/contract.py @@ -11,9 +11,9 @@ from markupfield.fields import MarkupField from ordered_model.models import OrderedModel -from sponsors.exceptions import InvalidStatusException -from sponsors.utils import file_from_storage -from sponsors.models.sponsorship import Sponsorship +from app.sponsors.exceptions import InvalidStatusException +from app.sponsors.utils import file_from_storage +from app.sponsors.models.sponsorship import Sponsorship class LegalClause(OrderedModel): diff --git a/sponsors/models/enums.py b/app/sponsors/models/enums.py similarity index 100% rename from sponsors/models/enums.py rename to app/sponsors/models/enums.py diff --git a/sponsors/models/managers.py b/app/sponsors/models/managers.py similarity index 91% rename from sponsors/models/managers.py rename to app/sponsors/models/managers.py index 5cb241fc9..4e4438f74 100644 --- a/sponsors/models/managers.py +++ b/app/sponsors/models/managers.py @@ -1,6 +1,6 @@ from django.db import IntegrityError from django.db.models import Count -from ordered_model.models import OrderedModelManager, OrderedModelQuerySet +from ordered_model.models import OrderedModelQuerySet from django.db.models import Q, Subquery from django.db.models.query import QuerySet from django.utils import timezone @@ -35,7 +35,7 @@ def enabled(self): return self.finalized().active_on_date(today).exclude(overlapped_by__isnull=False) def with_logo_placement(self, logo_place=None, publisher=None): - from sponsors.models import LogoPlacement, SponsorBenefit + from app.sponsors.models import LogoPlacement, SponsorBenefit feature_qs = LogoPlacement.objects.all() if logo_place: feature_qs = feature_qs.filter(logo_place=logo_place) @@ -45,7 +45,7 @@ def with_logo_placement(self, logo_place=None, publisher=None): return self.filter(id__in=Subquery(benefit_qs.values_list('sponsorship_id', flat=True))) def includes_benefit_feature(self, feature_model): - from sponsors.models import SponsorBenefit + from app.sponsors.models import SponsorBenefit feature_qs = feature_model.objects.all() benefit_qs = SponsorBenefit.objects.filter(id__in=Subquery(feature_qs.values_list('sponsor_benefit_id', flat=True))) return self.filter(id__in=Subquery(benefit_qs.values_list('sponsorship_id', flat=True))) @@ -106,7 +106,7 @@ def from_year(self, year): return self.filter(year=year).exclude(unavailable=True) def from_current_year(self): - from sponsors.models import SponsorshipCurrentYear + from app.sponsors.models import SponsorshipCurrentYear current_year = SponsorshipCurrentYear.get_year() return self.from_year(current_year) @@ -119,7 +119,7 @@ def from_year(self, year): return self.filter(year=year) def from_current_year(self): - from sponsors.models import SponsorshipCurrentYear + from app.sponsors.models import SponsorshipCurrentYear current_year = SponsorshipCurrentYear.get_year() return self.from_year(current_year) @@ -136,12 +136,12 @@ def from_sponsorship(self, sponsorship): return self.filter(sponsor_benefit__sponsorship=sponsorship).select_related("sponsor_benefit__sponsorship") def required_assets(self): - from sponsors.models.benefits import RequiredAssetMixin + from app.sponsors.models.benefits import RequiredAssetMixin required_assets_classes = RequiredAssetMixin.__subclasses__() return self.instance_of(*required_assets_classes).select_related("sponsor_benefit__sponsorship") def provided_assets(self): - from sponsors.models.benefits import ProvidedAssetMixin + from app.sponsors.models.benefits import ProvidedAssetMixin provided_assets_classes = ProvidedAssetMixin.__subclasses__() return self.instance_of(*provided_assets_classes).select_related("sponsor_benefit__sponsorship") @@ -158,6 +158,6 @@ def delete(self): class GenericAssetQuerySet(PolymorphicQuerySet): def all_assets(self): - from sponsors.models import GenericAsset + from app.sponsors.models import GenericAsset classes = GenericAsset.all_asset_types() return self.select_related("content_type").instance_of(*classes) diff --git a/sponsors/models/notifications.py b/app/sponsors/models/notifications.py similarity index 97% rename from sponsors/models/notifications.py rename to app/sponsors/models/notifications.py index eb80feb1f..7aee4e9d9 100644 --- a/sponsors/models/notifications.py +++ b/app/sponsors/models/notifications.py @@ -1,6 +1,6 @@ from django.conf import settings -from mailing.models import BaseEmailTemplate +from app.mailing.models import BaseEmailTemplate SPONSOR_TEMPLATE_HELP_TEXT = ( "
" diff --git a/sponsors/models/sponsors.py b/app/sponsors/models/sponsors.py similarity index 98% rename from sponsors/models/sponsors.py rename to app/sponsors/models/sponsors.py index 78d5d6e32..dcd16df60 100644 --- a/sponsors/models/sponsors.py +++ b/app/sponsors/models/sponsors.py @@ -12,9 +12,9 @@ from ordered_model.models import OrderedModel from django.contrib.contenttypes.fields import GenericRelation -from cms.models import ContentManageable -from sponsors.models.assets import GenericAsset -from sponsors.models.managers import SponsorContactQuerySet +from app.cms.models import ContentManageable +from app.sponsors.models.assets import GenericAsset +from app.sponsors.models.managers import SponsorContactQuerySet class Sponsor(ContentManageable): diff --git a/sponsors/models/sponsorship.py b/app/sponsors/models/sponsorship.py similarity index 98% rename from sponsors/models/sponsorship.py rename to app/sponsors/models/sponsorship.py index d230e91c3..2aae8b0af 100644 --- a/sponsors/models/sponsorship.py +++ b/app/sponsors/models/sponsorship.py @@ -19,13 +19,13 @@ from ordered_model.models import OrderedModel -from sponsors.exceptions import SponsorWithExistingApplicationException, InvalidStatusException, \ +from app.sponsors.exceptions import SponsorWithExistingApplicationException, InvalidStatusException, \ SponsorshipInvalidDateRangeException -from sponsors.models.assets import GenericAsset -from sponsors.models.managers import SponsorshipPackageQuerySet, SponsorshipBenefitQuerySet, \ +from app.sponsors.models.assets import GenericAsset +from app.sponsors.models.managers import SponsorshipPackageQuerySet, SponsorshipBenefitQuerySet, \ SponsorshipQuerySet, SponsorshipCurrentYearQuerySet -from sponsors.models.benefits import TieredBenefitConfiguration -from sponsors.models.sponsors import SponsorBenefit +from app.sponsors.models.benefits import TieredBenefitConfiguration +from app.sponsors.models.sponsors import SponsorBenefit YEAR_VALIDATORS = [ MinValueValidator(limit_value=2022, message="The min year value is 2022."), diff --git a/sponsors/notifications.py b/app/sponsors/notifications.py similarity index 99% rename from sponsors/notifications.py rename to app/sponsors/notifications.py index 196cc94b6..a04123083 100644 --- a/sponsors/notifications.py +++ b/app/sponsors/notifications.py @@ -5,7 +5,7 @@ from django.contrib.admin.models import LogEntry, CHANGE, ADDITION from django.contrib.contenttypes.models import ContentType -from sponsors.models import Sponsorship, Contract, BenefitFeature +from app.sponsors.models import Sponsorship, Contract, BenefitFeature class BaseEmailSponsorshipNotification: diff --git a/sponsors/templatetags/__init__.py b/app/sponsors/pandoc_filters/__init__.py similarity index 100% rename from sponsors/templatetags/__init__.py rename to app/sponsors/pandoc_filters/__init__.py diff --git a/sponsors/pandoc_filters/pagebreak.py b/app/sponsors/pandoc_filters/pagebreak.py similarity index 100% rename from sponsors/pandoc_filters/pagebreak.py rename to app/sponsors/pandoc_filters/pagebreak.py diff --git a/sponsors/reference.docx b/app/sponsors/reference.docx similarity index 100% rename from sponsors/reference.docx rename to app/sponsors/reference.docx diff --git a/sponsors/serializers.py b/app/sponsors/serializers.py similarity index 95% rename from sponsors/serializers.py rename to app/sponsors/serializers.py index c0782c12a..8178f80c0 100644 --- a/sponsors/serializers.py +++ b/app/sponsors/serializers.py @@ -1,8 +1,8 @@ from rest_framework import serializers -from sponsors.models import GenericAsset -from sponsors.models.enums import PublisherChoices, LogoPlacementChoices +from app.sponsors.models import GenericAsset +from app.sponsors.models.enums import PublisherChoices, LogoPlacementChoices class LogoPlacementSerializer(serializers.Serializer): publisher = serializers.CharField() diff --git a/templates/sponsors/admin/approve_application.html b/app/sponsors/templates/admin/approve_application.html similarity index 100% rename from templates/sponsors/admin/approve_application.html rename to app/sponsors/templates/admin/approve_application.html diff --git a/templates/sponsors/admin/clone_application_config_form.html b/app/sponsors/templates/admin/clone_application_config_form.html similarity index 100% rename from templates/sponsors/admin/clone_application_config_form.html rename to app/sponsors/templates/admin/clone_application_config_form.html diff --git a/templates/sponsors/admin/contract_change_form.html b/app/sponsors/templates/admin/contract_change_form.html similarity index 100% rename from templates/sponsors/admin/contract_change_form.html rename to app/sponsors/templates/admin/contract_change_form.html diff --git a/templates/sponsors/admin/contracts/sponsorship-agreement.md b/app/sponsors/templates/admin/contracts/sponsorship-agreement.md similarity index 100% rename from templates/sponsors/admin/contracts/sponsorship-agreement.md rename to app/sponsors/templates/admin/contracts/sponsorship-agreement.md diff --git a/templates/sponsors/admin/execute_contract.html b/app/sponsors/templates/admin/execute_contract.html similarity index 100% rename from templates/sponsors/admin/execute_contract.html rename to app/sponsors/templates/admin/execute_contract.html diff --git a/templates/sponsors/admin/list_uploaded_assets.html b/app/sponsors/templates/admin/list_uploaded_assets.html similarity index 100% rename from templates/sponsors/admin/list_uploaded_assets.html rename to app/sponsors/templates/admin/list_uploaded_assets.html diff --git a/templates/sponsors/admin/nullify_contract.html b/app/sponsors/templates/admin/nullify_contract.html similarity index 100% rename from templates/sponsors/admin/nullify_contract.html rename to app/sponsors/templates/admin/nullify_contract.html diff --git a/templates/sponsors/admin/reject_application.html b/app/sponsors/templates/admin/reject_application.html similarity index 100% rename from templates/sponsors/admin/reject_application.html rename to app/sponsors/templates/admin/reject_application.html diff --git a/templates/sponsors/admin/rollback_sponsorship_to_editing.html b/app/sponsors/templates/admin/rollback_sponsorship_to_editing.html similarity index 100% rename from templates/sponsors/admin/rollback_sponsorship_to_editing.html rename to app/sponsors/templates/admin/rollback_sponsorship_to_editing.html diff --git a/templates/sponsors/admin/send_contract.html b/app/sponsors/templates/admin/send_contract.html similarity index 100% rename from templates/sponsors/admin/send_contract.html rename to app/sponsors/templates/admin/send_contract.html diff --git a/templates/sponsors/admin/send_sponsors_notification.html b/app/sponsors/templates/admin/send_sponsors_notification.html similarity index 100% rename from templates/sponsors/admin/send_sponsors_notification.html rename to app/sponsors/templates/admin/send_sponsors_notification.html diff --git a/templates/sponsors/admin/sponsors_sponsorshipcurrentyear_changelist.html b/app/sponsors/templates/admin/sponsors_sponsorshipcurrentyear_changelist.html similarity index 100% rename from templates/sponsors/admin/sponsors_sponsorshipcurrentyear_changelist.html rename to app/sponsors/templates/admin/sponsors_sponsorshipcurrentyear_changelist.html diff --git a/templates/sponsors/admin/sponsorship_change_form.html b/app/sponsors/templates/admin/sponsorship_change_form.html similarity index 100% rename from templates/sponsors/admin/sponsorship_change_form.html rename to app/sponsors/templates/admin/sponsorship_change_form.html diff --git a/templates/sponsors/admin/sponsorshipbenefit_change_form.html b/app/sponsors/templates/admin/sponsorshipbenefit_change_form.html similarity index 100% rename from templates/sponsors/admin/sponsorshipbenefit_change_form.html rename to app/sponsors/templates/admin/sponsorshipbenefit_change_form.html diff --git a/templates/sponsors/admin/unlock.html b/app/sponsors/templates/admin/unlock.html similarity index 100% rename from templates/sponsors/admin/unlock.html rename to app/sponsors/templates/admin/unlock.html diff --git a/templates/sponsors/admin/update_related_sponsorships.html b/app/sponsors/templates/admin/update_related_sponsorships.html similarity index 100% rename from templates/sponsors/admin/update_related_sponsorships.html rename to app/sponsors/templates/admin/update_related_sponsorships.html diff --git a/templates/sponsors/email/psf_contract.txt b/app/sponsors/templates/email/psf_contract.txt similarity index 100% rename from templates/sponsors/email/psf_contract.txt rename to app/sponsors/templates/email/psf_contract.txt diff --git a/templates/sponsors/email/psf_contract_subject.txt b/app/sponsors/templates/email/psf_contract_subject.txt similarity index 100% rename from templates/sponsors/email/psf_contract_subject.txt rename to app/sponsors/templates/email/psf_contract_subject.txt diff --git a/templates/sponsors/email/psf_new_application.txt b/app/sponsors/templates/email/psf_new_application.txt similarity index 100% rename from templates/sponsors/email/psf_new_application.txt rename to app/sponsors/templates/email/psf_new_application.txt diff --git a/templates/sponsors/email/psf_new_application_subject.txt b/app/sponsors/templates/email/psf_new_application_subject.txt similarity index 100% rename from templates/sponsors/email/psf_new_application_subject.txt rename to app/sponsors/templates/email/psf_new_application_subject.txt diff --git a/templates/sponsors/email/psf_rejected_sponsorship.txt b/app/sponsors/templates/email/psf_rejected_sponsorship.txt similarity index 100% rename from templates/sponsors/email/psf_rejected_sponsorship.txt rename to app/sponsors/templates/email/psf_rejected_sponsorship.txt diff --git a/templates/sponsors/email/psf_rejected_sponsorship_subject.txt b/app/sponsors/templates/email/psf_rejected_sponsorship_subject.txt similarity index 100% rename from templates/sponsors/email/psf_rejected_sponsorship_subject.txt rename to app/sponsors/templates/email/psf_rejected_sponsorship_subject.txt diff --git a/templates/sponsors/email/sponsor_contract.txt b/app/sponsors/templates/email/sponsor_contract.txt similarity index 100% rename from templates/sponsors/email/sponsor_contract.txt rename to app/sponsors/templates/email/sponsor_contract.txt diff --git a/templates/sponsors/email/sponsor_contract_subject.txt b/app/sponsors/templates/email/sponsor_contract_subject.txt similarity index 100% rename from templates/sponsors/email/sponsor_contract_subject.txt rename to app/sponsors/templates/email/sponsor_contract_subject.txt diff --git a/templates/sponsors/email/sponsor_expiring_assets.txt b/app/sponsors/templates/email/sponsor_expiring_assets.txt similarity index 100% rename from templates/sponsors/email/sponsor_expiring_assets.txt rename to app/sponsors/templates/email/sponsor_expiring_assets.txt diff --git a/templates/sponsors/email/sponsor_expiring_assets_subject.txt b/app/sponsors/templates/email/sponsor_expiring_assets_subject.txt similarity index 100% rename from templates/sponsors/email/sponsor_expiring_assets_subject.txt rename to app/sponsors/templates/email/sponsor_expiring_assets_subject.txt diff --git a/templates/sponsors/email/sponsor_new_application.txt b/app/sponsors/templates/email/sponsor_new_application.txt similarity index 100% rename from templates/sponsors/email/sponsor_new_application.txt rename to app/sponsors/templates/email/sponsor_new_application.txt diff --git a/templates/sponsors/email/sponsor_new_application_subject.txt b/app/sponsors/templates/email/sponsor_new_application_subject.txt similarity index 100% rename from templates/sponsors/email/sponsor_new_application_subject.txt rename to app/sponsors/templates/email/sponsor_new_application_subject.txt diff --git a/templates/sponsors/email/sponsor_rejected_sponsorship.txt b/app/sponsors/templates/email/sponsor_rejected_sponsorship.txt similarity index 100% rename from templates/sponsors/email/sponsor_rejected_sponsorship.txt rename to app/sponsors/templates/email/sponsor_rejected_sponsorship.txt diff --git a/templates/sponsors/email/sponsor_rejected_sponsorship_subject.txt b/app/sponsors/templates/email/sponsor_rejected_sponsorship_subject.txt similarity index 100% rename from templates/sponsors/email/sponsor_rejected_sponsorship_subject.txt rename to app/sponsors/templates/email/sponsor_rejected_sponsorship_subject.txt diff --git a/templates/sponsors/new_sponsorship_application_form.html b/app/sponsors/templates/new_sponsorship_application_form.html similarity index 100% rename from templates/sponsors/new_sponsorship_application_form.html rename to app/sponsors/templates/new_sponsorship_application_form.html diff --git a/templates/sponsors/partials/full_sponsorship.txt b/app/sponsors/templates/partials/full_sponsorship.txt similarity index 100% rename from templates/sponsors/partials/full_sponsorship.txt rename to app/sponsors/templates/partials/full_sponsorship.txt diff --git a/templates/sponsors/partials/sponsors-list.html b/app/sponsors/templates/partials/sponsors-list.html similarity index 100% rename from templates/sponsors/partials/sponsors-list.html rename to app/sponsors/templates/partials/sponsors-list.html diff --git a/templates/sponsors/sponsor_list.html b/app/sponsors/templates/sponsor_list.html similarity index 100% rename from templates/sponsors/sponsor_list.html rename to app/sponsors/templates/sponsor_list.html diff --git a/templates/sponsors/sponsorship_application_finished.html b/app/sponsors/templates/sponsorship_application_finished.html similarity index 100% rename from templates/sponsors/sponsorship_application_finished.html rename to app/sponsors/templates/sponsorship_application_finished.html diff --git a/templates/sponsors/sponsorship_benefits_form.html b/app/sponsors/templates/sponsorship_benefits_form.html similarity index 100% rename from templates/sponsors/sponsorship_benefits_form.html rename to app/sponsors/templates/sponsorship_benefits_form.html diff --git a/sponsors/tests/__init__.py b/app/sponsors/templatetags/__init__.py similarity index 100% rename from sponsors/tests/__init__.py rename to app/sponsors/templatetags/__init__.py diff --git a/sponsors/templatetags/sponsors.py b/app/sponsors/templatetags/sponsors.py similarity index 94% rename from sponsors/templatetags/sponsors.py rename to app/sponsors/templatetags/sponsors.py index 7e2f1f462..d6ae1f6a7 100644 --- a/sponsors/templatetags/sponsors.py +++ b/app/sponsors/templatetags/sponsors.py @@ -5,8 +5,8 @@ from django.conf import settings from django.core.cache import cache -from ..models import Sponsorship, SponsorshipPackage, TieredBenefitConfiguration -from sponsors.models.enums import PublisherChoices, LogoPlacementChoices +from app.sponsors.models import Sponsorship, SponsorshipPackage, TieredBenefitConfiguration +from app.sponsors.models.enums import PublisherChoices, LogoPlacementChoices register = template.Library() diff --git a/successstories/__init__.py b/app/sponsors/tests/__init__.py similarity index 100% rename from successstories/__init__.py rename to app/sponsors/tests/__init__.py diff --git a/sponsors/tests/baker_recipes.py b/app/sponsors/tests/baker_recipes.py similarity index 89% rename from sponsors/tests/baker_recipes.py rename to app/sponsors/tests/baker_recipes.py index 8d24820d6..869cdba18 100644 --- a/sponsors/tests/baker_recipes.py +++ b/app/sponsors/tests/baker_recipes.py @@ -2,8 +2,8 @@ from model_bakery.recipe import Recipe, foreign_key -from sponsors.models import Contract, LogoPlacement, Sponsorship, SponsorshipPackage -from sponsors.models.enums import LogoPlacementChoices, PublisherChoices +from app.sponsors.models import Contract, LogoPlacement, Sponsorship, SponsorshipPackage +from app.sponsors.models.enums import LogoPlacementChoices, PublisherChoices today = date.today() two_days = timedelta(days=2) diff --git a/sponsors/tests/test_admin.py b/app/sponsors/tests/test_admin.py similarity index 95% rename from sponsors/tests/test_admin.py rename to app/sponsors/tests/test_admin.py index 1e94fa6df..305bd7676 100644 --- a/sponsors/tests/test_admin.py +++ b/app/sponsors/tests/test_admin.py @@ -5,8 +5,8 @@ from django.test import TestCase, RequestFactory -from sponsors.admin import SponsorshipStatusListFilter, SponsorshipAdmin -from sponsors.models import Sponsorship +from app.sponsors.admin import SponsorshipStatusListFilter, SponsorshipAdmin +from app.sponsors.models import Sponsorship class TestCustomSponsorshipStatusListFilter(TestCase): diff --git a/sponsors/tests/test_api.py b/app/sponsors/tests/test_api.py similarity index 98% rename from sponsors/tests/test_api.py rename to app/sponsors/tests/test_api.py index 3575e59e6..902cf99b4 100644 --- a/sponsors/tests/test_api.py +++ b/app/sponsors/tests/test_api.py @@ -9,8 +9,8 @@ from rest_framework.authtoken.models import Token from rest_framework.test import APITestCase -from sponsors.models import Sponsor, Sponsorship, TextAsset, ImgAsset -from sponsors.models.enums import LogoPlacementChoices, PublisherChoices +from app.sponsors.models import Sponsor, Sponsorship, TextAsset, ImgAsset +from app.sponsors.models.enums import LogoPlacementChoices, PublisherChoices class LogoPlacementeAPIListTests(APITestCase): diff --git a/sponsors/tests/test_contracts.py b/app/sponsors/tests/test_contracts.py similarity index 95% rename from sponsors/tests/test_contracts.py rename to app/sponsors/tests/test_contracts.py index c330c13a8..37c448ae3 100644 --- a/sponsors/tests/test_contracts.py +++ b/app/sponsors/tests/test_contracts.py @@ -6,7 +6,7 @@ from django.test import TestCase from django.utils.dateformat import format -from sponsors.contracts import render_contract_to_docx_response +from app.sponsors.contracts import render_contract_to_docx_response class TestRenderContract(TestCase): diff --git a/sponsors/tests/test_forms.py b/app/sponsors/tests/test_forms.py similarity index 99% rename from sponsors/tests/test_forms.py rename to app/sponsors/tests/test_forms.py index 49b0515cd..0d1ccdccf 100644 --- a/sponsors/tests/test_forms.py +++ b/app/sponsors/tests/test_forms.py @@ -6,7 +6,7 @@ from django.conf import settings from django.test import TestCase -from sponsors.forms import ( +from app.sponsors.forms import ( SponsorshipsBenefitsForm, SponsorshipApplicationForm, Sponsor, @@ -18,10 +18,10 @@ SponsorshipsListForm, SendSponsorshipNotificationForm, SponsorRequiredAssetsForm, SponsorshipBenefitAdminForm, CloneApplicationConfigForm, ) -from sponsors.models import SponsorshipBenefit, SponsorContact, RequiredTextAssetConfiguration, \ +from app.sponsors.models import SponsorshipBenefit, SponsorContact, RequiredTextAssetConfiguration, \ RequiredImgAssetConfiguration, ImgAsset, RequiredTextAsset, SponsorshipPackage, SponsorshipCurrentYear -from .utils import get_static_image_file_as_upload -from ..models.enums import AssetsRelatedTo +from app.sponsors.utils import get_static_image_file_as_upload +from app.sponsors.models.enums import AssetsRelatedTo class SponsorshipsBenefitsFormTests(TestCase): diff --git a/sponsors/tests/test_management_command.py b/app/sponsors/tests/test_management_command.py similarity index 89% rename from sponsors/tests/test_management_command.py rename to app/sponsors/tests/test_management_command.py index 100daad2a..7e484928a 100644 --- a/sponsors/tests/test_management_command.py +++ b/app/sponsors/tests/test_management_command.py @@ -4,10 +4,10 @@ from unittest import mock -from sponsors.models import ProvidedTextAssetConfiguration, ProvidedTextAsset -from sponsors.models.enums import AssetsRelatedTo +from app.sponsors.models import ProvidedTextAssetConfiguration, ProvidedTextAsset +from app.sponsors.models.enums import AssetsRelatedTo -from sponsors.management.commands.create_pycon_vouchers_for_sponsors import ( +from app.sponsors.management.commands.create_pycon_vouchers_for_sponsors import ( generate_voucher_codes, BENEFITS, ) diff --git a/sponsors/tests/test_managers.py b/app/sponsors/tests/test_managers.py similarity index 97% rename from sponsors/tests/test_managers.py rename to app/sponsors/tests/test_managers.py index c908cfc41..c8e018266 100644 --- a/sponsors/tests/test_managers.py +++ b/app/sponsors/tests/test_managers.py @@ -4,9 +4,9 @@ from django.conf import settings from django.test import TestCase -from ..models import Sponsorship, SponsorBenefit, LogoPlacement, TieredBenefit, RequiredTextAsset, RequiredImgAsset, \ +from app.sponsors.models import Sponsorship, SponsorBenefit, LogoPlacement, TieredBenefit, RequiredTextAsset, RequiredImgAsset, \ BenefitFeature, SponsorshipPackage, SponsorshipBenefit, SponsorshipCurrentYear -from sponsors.models.enums import LogoPlacementChoices, PublisherChoices +from app.sponsors.models.enums import LogoPlacementChoices, PublisherChoices class SponsorshipQuerySetTests(TestCase): diff --git a/sponsors/tests/test_models.py b/app/sponsors/tests/test_models.py similarity index 99% rename from sponsors/tests/test_models.py rename to app/sponsors/tests/test_models.py index 3566f0b08..3c0271978 100644 --- a/sponsors/tests/test_models.py +++ b/app/sponsors/tests/test_models.py @@ -11,7 +11,7 @@ from django.test import TestCase from django.utils import timezone -from ..models import ( +from app.sponsors.models import ( Contract, LegalClause, LogoPlacement, @@ -26,13 +26,13 @@ TieredBenefitConfiguration, RequiredImgAssetConfiguration, RequiredImgAsset, ImgAsset, RequiredTextAssetConfiguration, RequiredTextAsset, TextAsset, SponsorshipCurrentYear ) -from ..exceptions import ( +from app.sponsors.exceptions import ( SponsorWithExistingApplicationException, SponsorshipInvalidDateRangeException, InvalidStatusException, ) -from sponsors.models.enums import PublisherChoices, LogoPlacementChoices, AssetsRelatedTo -from ..models.benefits import RequiredAssetMixin, BaseRequiredImgAsset, BenefitFeature, BaseRequiredTextAsset, \ +from app.sponsors.models.enums import PublisherChoices, LogoPlacementChoices, AssetsRelatedTo +from app.sponsors.models.benefits import RequiredAssetMixin, BaseRequiredImgAsset, BenefitFeature, BaseRequiredTextAsset, \ EmailTargetableConfiguration diff --git a/sponsors/tests/test_notifications.py b/app/sponsors/tests/test_notifications.py similarity index 99% rename from sponsors/tests/test_notifications.py rename to app/sponsors/tests/test_notifications.py index 30151ede0..a19061c76 100644 --- a/sponsors/tests/test_notifications.py +++ b/app/sponsors/tests/test_notifications.py @@ -11,8 +11,8 @@ from django.contrib.admin.models import LogEntry, CHANGE, ADDITION from django.contrib.contenttypes.models import ContentType -from sponsors import notifications -from sponsors.models import Sponsorship, Contract, RequiredTextAssetConfiguration, SponsorBenefit +from app.sponsors import notifications +from app.sponsors.models import Sponsorship, Contract, RequiredTextAssetConfiguration, SponsorBenefit class AppliedSponsorshipNotificationToPSFTests(TestCase): diff --git a/sponsors/tests/test_templatetags.py b/app/sponsors/tests/test_templatetags.py similarity index 96% rename from sponsors/tests/test_templatetags.py rename to app/sponsors/tests/test_templatetags.py index f891a6479..34cbc243f 100644 --- a/sponsors/tests/test_templatetags.py +++ b/app/sponsors/tests/test_templatetags.py @@ -2,15 +2,15 @@ from django.test import TestCase from unittest.mock import patch, Mock -from companies.models import Company +from app.companies.models import Company -from ..models import ( +from app.sponsors.models import ( Sponsor, SponsorBenefit, SponsorshipBenefit, TieredBenefitConfiguration, ) -from ..templatetags.sponsors import ( +from app.sponsors.templatetags.sponsors import ( benefit_name_for_display, benefit_quantity_for_package, full_sponsorship, diff --git a/sponsors/tests/test_use_cases.py b/app/sponsors/tests/test_use_cases.py similarity index 98% rename from sponsors/tests/test_use_cases.py rename to app/sponsors/tests/test_use_cases.py index 3e5e5ad04..81cfca9dd 100644 --- a/sponsors/tests/test_use_cases.py +++ b/app/sponsors/tests/test_use_cases.py @@ -10,9 +10,9 @@ from django.core.mail import EmailMessage from django.core.files.uploadedfile import SimpleUploadedFile -from sponsors import use_cases -from sponsors.notifications import * -from sponsors.models import Sponsorship, Contract, SponsorEmailNotificationTemplate, Sponsor, SponsorshipBenefit, \ +from app.sponsors import use_cases +from app.sponsors.notifications import * +from app.sponsors.models import Sponsorship, Contract, SponsorEmailNotificationTemplate, Sponsor, SponsorshipBenefit, \ SponsorshipPackage diff --git a/sponsors/tests/test_views.py b/app/sponsors/tests/test_views.py similarity index 99% rename from sponsors/tests/test_views.py rename to app/sponsors/tests/test_views.py index 130eb443d..47054beeb 100644 --- a/sponsors/tests/test_views.py +++ b/app/sponsors/tests/test_views.py @@ -10,15 +10,15 @@ from django.test import TestCase from django.urls import reverse, reverse_lazy -from .utils import get_static_image_file_as_upload, assertMessage -from ..models import ( +from app.sponsors.utils import get_static_image_file_as_upload, assertMessage +from app.sponsors.models import ( Sponsor, SponsorshipBenefit, SponsorContact, Sponsorship, SponsorshipCurrentYear, SponsorshipPackage ) -from sponsors.forms import ( +from app.sponsors.forms import ( SponsorshipsBenefitsForm, SponsorshipApplicationForm, ) diff --git a/sponsors/tests/test_views_admin.py b/app/sponsors/tests/test_views_admin.py similarity index 98% rename from sponsors/tests/test_views_admin.py rename to app/sponsors/tests/test_views_admin.py index 1b260187a..7918c4b27 100644 --- a/sponsors/tests/test_views_admin.py +++ b/app/sponsors/tests/test_views_admin.py @@ -18,13 +18,13 @@ from django.test import TestCase, RequestFactory from django.urls import reverse -from .utils import assertMessage, get_static_image_file_as_upload -from ..models import Sponsorship, Contract, SponsorshipBenefit, SponsorBenefit, SponsorEmailNotificationTemplate, \ +from app.sponsors.utils import assertMessage, get_static_image_file_as_upload +from app.sponsors.models import Sponsorship, Contract, SponsorshipBenefit, SponsorBenefit, SponsorEmailNotificationTemplate, \ GenericAsset, ImgAsset, TextAsset, SponsorshipCurrentYear, SponsorshipPackage -from ..forms import SponsorshipReviewAdminForm, SponsorshipsListForm, SignedSponsorshipReviewAdminForm, \ +from app.sponsors.forms import SponsorshipReviewAdminForm, SponsorshipsListForm, SignedSponsorshipReviewAdminForm, \ SendSponsorshipNotificationForm, CloneApplicationConfigForm -from sponsors.views_admin import send_sponsorship_notifications_action, export_assets_as_zipfile -from sponsors.use_cases import SendSponsorshipNotificationUseCase +from app.sponsors.views_admin import send_sponsorship_notifications_action, export_assets_as_zipfile +from app.sponsors.use_cases import SendSponsorshipNotificationUseCase class RollbackSponsorshipToEditingAdminViewTests(TestCase): diff --git a/sponsors/tests/utils.py b/app/sponsors/tests/utils.py similarity index 100% rename from sponsors/tests/utils.py rename to app/sponsors/tests/utils.py diff --git a/sponsors/urls.py b/app/sponsors/urls.py similarity index 91% rename from sponsors/urls.py rename to app/sponsors/urls.py index d658dffe6..530a78190 100644 --- a/sponsors/urls.py +++ b/app/sponsors/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from . import views +from app.sponsors import views urlpatterns = [ diff --git a/sponsors/use_cases.py b/app/sponsors/use_cases.py similarity index 96% rename from sponsors/use_cases.py rename to app/sponsors/use_cases.py index 91271ff64..b584ec400 100644 --- a/sponsors/use_cases.py +++ b/app/sponsors/use_cases.py @@ -1,9 +1,9 @@ from django.db import transaction -from sponsors import notifications -from sponsors.models import Sponsorship, Contract, SponsorContact, SponsorEmailNotificationTemplate, SponsorshipBenefit, \ +from app.sponsors import notifications +from app.sponsors.models import Sponsorship, Contract, SponsorContact, SponsorEmailNotificationTemplate, SponsorshipBenefit, \ SponsorshipPackage -from sponsors.contracts import render_contract_to_pdf_file, render_contract_to_docx_file +from app.sponsors.contracts import render_contract_to_pdf_file, render_contract_to_docx_file class BaseUseCaseWithNotifications: diff --git a/sponsors/utils.py b/app/sponsors/utils.py similarity index 100% rename from sponsors/utils.py rename to app/sponsors/utils.py diff --git a/sponsors/views.py b/app/sponsors/views.py similarity index 97% rename from sponsors/views.py rename to app/sponsors/views.py index dccd8446d..6b6ae5a9b 100644 --- a/sponsors/views.py +++ b/app/sponsors/views.py @@ -9,15 +9,15 @@ from django.utils.decorators import method_decorator from django.views.generic import FormView, DetailView, RedirectView -from .models import ( +from app.sponsors.models import ( SponsorshipBenefit, SponsorshipPackage, SponsorshipProgram, SponsorshipCurrentYear, ) -from sponsors import cookies -from sponsors import use_cases -from sponsors.forms import SponsorshipsBenefitsForm, SponsorshipApplicationForm +from app.sponsors import cookies +from app.sponsors import use_cases +from app.sponsors.forms import SponsorshipsBenefitsForm, SponsorshipApplicationForm class SelectSponsorshipApplicationBenefitsView(FormView): diff --git a/sponsors/views_admin.py b/app/sponsors/views_admin.py similarity index 97% rename from sponsors/views_admin.py rename to app/sponsors/views_admin.py index fd8631d3f..7514cd5c9 100644 --- a/sponsors/views_admin.py +++ b/app/sponsors/views_admin.py @@ -10,12 +10,12 @@ from django.db.models import Q from django.db import transaction -from sponsors import use_cases -from sponsors.forms import SponsorshipReviewAdminForm, SponsorshipsListForm, SignedSponsorshipReviewAdminForm, \ +from app.sponsors import use_cases +from app.sponsors.forms import SponsorshipReviewAdminForm, SponsorshipsListForm, SignedSponsorshipReviewAdminForm, \ SendSponsorshipNotificationForm, CloneApplicationConfigForm -from sponsors.exceptions import InvalidStatusException -from sponsors.contracts import render_contract_to_pdf_response, render_contract_to_docx_response -from sponsors.models import Sponsorship, SponsorBenefit, EmailTargetable, SponsorContact, BenefitFeature, \ +from app.sponsors.exceptions import InvalidStatusException +from app.sponsors.contracts import render_contract_to_pdf_response, render_contract_to_docx_response +from app.sponsors.models import Sponsorship, SponsorBenefit, EmailTargetable, SponsorContact, BenefitFeature, \ SponsorshipCurrentYear, SponsorshipBenefit, SponsorshipPackage diff --git a/static/apple-touch-icon-114x114-precomposed.png b/app/static/apple-touch-icon-114x114-precomposed.png similarity index 100% rename from static/apple-touch-icon-114x114-precomposed.png rename to app/static/apple-touch-icon-114x114-precomposed.png diff --git a/static/apple-touch-icon-144x144-precomposed.png b/app/static/apple-touch-icon-144x144-precomposed.png similarity index 100% rename from static/apple-touch-icon-144x144-precomposed.png rename to app/static/apple-touch-icon-144x144-precomposed.png diff --git a/static/apple-touch-icon-72x72-precomposed.png b/app/static/apple-touch-icon-72x72-precomposed.png similarity index 100% rename from static/apple-touch-icon-72x72-precomposed.png rename to app/static/apple-touch-icon-72x72-precomposed.png diff --git a/static/apple-touch-icon-precomposed.png b/app/static/apple-touch-icon-precomposed.png similarity index 100% rename from static/apple-touch-icon-precomposed.png rename to app/static/apple-touch-icon-precomposed.png diff --git a/static/community_logos/README.txt b/app/static/community_logos/README.txt similarity index 100% rename from static/community_logos/README.txt rename to app/static/community_logos/README.txt diff --git a/static/community_logos/python-logo-generic.svg b/app/static/community_logos/python-logo-generic.svg similarity index 100% rename from static/community_logos/python-logo-generic.svg rename to app/static/community_logos/python-logo-generic.svg diff --git a/static/community_logos/python-logo-inkscape.svg b/app/static/community_logos/python-logo-inkscape.svg similarity index 100% rename from static/community_logos/python-logo-inkscape.svg rename to app/static/community_logos/python-logo-inkscape.svg diff --git a/static/community_logos/python-logo-master-v3-TM-flattened.png b/app/static/community_logos/python-logo-master-v3-TM-flattened.png similarity index 100% rename from static/community_logos/python-logo-master-v3-TM-flattened.png rename to app/static/community_logos/python-logo-master-v3-TM-flattened.png diff --git a/static/community_logos/python-logo-master-v3-TM.png b/app/static/community_logos/python-logo-master-v3-TM.png similarity index 100% rename from static/community_logos/python-logo-master-v3-TM.png rename to app/static/community_logos/python-logo-master-v3-TM.png diff --git a/static/community_logos/python-logo-master-v3-TM.psd b/app/static/community_logos/python-logo-master-v3-TM.psd similarity index 100% rename from static/community_logos/python-logo-master-v3-TM.psd rename to app/static/community_logos/python-logo-master-v3-TM.psd diff --git a/static/community_logos/python-logo.png b/app/static/community_logos/python-logo.png similarity index 100% rename from static/community_logos/python-logo.png rename to app/static/community_logos/python-logo.png diff --git a/static/community_logos/python-powered-h-100x130.png b/app/static/community_logos/python-powered-h-100x130.png similarity index 100% rename from static/community_logos/python-powered-h-100x130.png rename to app/static/community_logos/python-powered-h-100x130.png diff --git a/static/community_logos/python-powered-h-140x182.png b/app/static/community_logos/python-powered-h-140x182.png similarity index 100% rename from static/community_logos/python-powered-h-140x182.png rename to app/static/community_logos/python-powered-h-140x182.png diff --git a/static/community_logos/python-powered-h-50x65.png b/app/static/community_logos/python-powered-h-50x65.png similarity index 100% rename from static/community_logos/python-powered-h-50x65.png rename to app/static/community_logos/python-powered-h-50x65.png diff --git a/static/community_logos/python-powered-h-70x91.png b/app/static/community_logos/python-powered-h-70x91.png similarity index 100% rename from static/community_logos/python-powered-h-70x91.png rename to app/static/community_logos/python-powered-h-70x91.png diff --git a/static/community_logos/python-powered-h.svg b/app/static/community_logos/python-powered-h.svg similarity index 100% rename from static/community_logos/python-powered-h.svg rename to app/static/community_logos/python-powered-h.svg diff --git a/static/community_logos/python-powered-w-100x40.png b/app/static/community_logos/python-powered-w-100x40.png similarity index 100% rename from static/community_logos/python-powered-w-100x40.png rename to app/static/community_logos/python-powered-w-100x40.png diff --git a/static/community_logos/python-powered-w-140x56.png b/app/static/community_logos/python-powered-w-140x56.png similarity index 100% rename from static/community_logos/python-powered-w-140x56.png rename to app/static/community_logos/python-powered-w-140x56.png diff --git a/static/community_logos/python-powered-w-200x80.png b/app/static/community_logos/python-powered-w-200x80.png similarity index 100% rename from static/community_logos/python-powered-w-200x80.png rename to app/static/community_logos/python-powered-w-200x80.png diff --git a/static/community_logos/python-powered-w-70x28.png b/app/static/community_logos/python-powered-w-70x28.png similarity index 100% rename from static/community_logos/python-powered-w-70x28.png rename to app/static/community_logos/python-powered-w-70x28.png diff --git a/static/community_logos/python-powered-w.svg b/app/static/community_logos/python-powered-w.svg similarity index 100% rename from static/community_logos/python-powered-w.svg rename to app/static/community_logos/python-powered-w.svg diff --git a/static/config.rb b/app/static/config.rb similarity index 100% rename from static/config.rb rename to app/static/config.rb diff --git a/static/favicon.ico b/app/static/favicon.ico similarity index 100% rename from static/favicon.ico rename to app/static/favicon.ico diff --git a/static/fonts/FluxBold.eot b/app/static/fonts/FluxBold.eot similarity index 100% rename from static/fonts/FluxBold.eot rename to app/static/fonts/FluxBold.eot diff --git a/static/fonts/FluxBold.ttf b/app/static/fonts/FluxBold.ttf similarity index 100% rename from static/fonts/FluxBold.ttf rename to app/static/fonts/FluxBold.ttf diff --git a/static/fonts/FluxBold.woff b/app/static/fonts/FluxBold.woff similarity index 100% rename from static/fonts/FluxBold.woff rename to app/static/fonts/FluxBold.woff diff --git a/static/fonts/FluxBoldItalic.eot b/app/static/fonts/FluxBoldItalic.eot similarity index 100% rename from static/fonts/FluxBoldItalic.eot rename to app/static/fonts/FluxBoldItalic.eot diff --git a/static/fonts/FluxBoldItalic.ttf b/app/static/fonts/FluxBoldItalic.ttf similarity index 100% rename from static/fonts/FluxBoldItalic.ttf rename to app/static/fonts/FluxBoldItalic.ttf diff --git a/static/fonts/FluxBoldItalic.woff b/app/static/fonts/FluxBoldItalic.woff similarity index 100% rename from static/fonts/FluxBoldItalic.woff rename to app/static/fonts/FluxBoldItalic.woff diff --git a/static/fonts/FluxItalic.eot b/app/static/fonts/FluxItalic.eot similarity index 100% rename from static/fonts/FluxItalic.eot rename to app/static/fonts/FluxItalic.eot diff --git a/static/fonts/FluxItalic.ttf b/app/static/fonts/FluxItalic.ttf similarity index 100% rename from static/fonts/FluxItalic.ttf rename to app/static/fonts/FluxItalic.ttf diff --git a/static/fonts/FluxItalic.woff b/app/static/fonts/FluxItalic.woff similarity index 100% rename from static/fonts/FluxItalic.woff rename to app/static/fonts/FluxItalic.woff diff --git a/static/fonts/FluxRegular.eot b/app/static/fonts/FluxRegular.eot similarity index 100% rename from static/fonts/FluxRegular.eot rename to app/static/fonts/FluxRegular.eot diff --git a/static/fonts/FluxRegular.ttf b/app/static/fonts/FluxRegular.ttf similarity index 100% rename from static/fonts/FluxRegular.ttf rename to app/static/fonts/FluxRegular.ttf diff --git a/static/fonts/FluxRegular.woff b/app/static/fonts/FluxRegular.woff similarity index 100% rename from static/fonts/FluxRegular.woff rename to app/static/fonts/FluxRegular.woff diff --git a/static/fonts/FontAwesome.otf b/app/static/fonts/FontAwesome.otf similarity index 100% rename from static/fonts/FontAwesome.otf rename to app/static/fonts/FontAwesome.otf diff --git a/static/fonts/Pythonicon.eot b/app/static/fonts/Pythonicon.eot similarity index 100% rename from static/fonts/Pythonicon.eot rename to app/static/fonts/Pythonicon.eot diff --git a/static/fonts/Pythonicon.json b/app/static/fonts/Pythonicon.json similarity index 100% rename from static/fonts/Pythonicon.json rename to app/static/fonts/Pythonicon.json diff --git a/static/fonts/Pythonicon.svg b/app/static/fonts/Pythonicon.svg similarity index 100% rename from static/fonts/Pythonicon.svg rename to app/static/fonts/Pythonicon.svg diff --git a/static/fonts/Pythonicon.ttf b/app/static/fonts/Pythonicon.ttf similarity index 100% rename from static/fonts/Pythonicon.ttf rename to app/static/fonts/Pythonicon.ttf diff --git a/static/fonts/Pythonicon.woff b/app/static/fonts/Pythonicon.woff similarity index 100% rename from static/fonts/Pythonicon.woff rename to app/static/fonts/Pythonicon.woff diff --git a/static/fonts/SIL OFL Font License - Source Sans Pro.txt b/app/static/fonts/SIL OFL Font License - Source Sans Pro.txt similarity index 100% rename from static/fonts/SIL OFL Font License - Source Sans Pro.txt rename to app/static/fonts/SIL OFL Font License - Source Sans Pro.txt diff --git a/static/fonts/SourceSansPro-Bold-webfont.eot b/app/static/fonts/SourceSansPro-Bold-webfont.eot similarity index 100% rename from static/fonts/SourceSansPro-Bold-webfont.eot rename to app/static/fonts/SourceSansPro-Bold-webfont.eot diff --git a/static/fonts/SourceSansPro-Bold-webfont.svg b/app/static/fonts/SourceSansPro-Bold-webfont.svg similarity index 100% rename from static/fonts/SourceSansPro-Bold-webfont.svg rename to app/static/fonts/SourceSansPro-Bold-webfont.svg diff --git a/static/fonts/SourceSansPro-Bold-webfont.ttf b/app/static/fonts/SourceSansPro-Bold-webfont.ttf similarity index 100% rename from static/fonts/SourceSansPro-Bold-webfont.ttf rename to app/static/fonts/SourceSansPro-Bold-webfont.ttf diff --git a/static/fonts/SourceSansPro-Bold-webfont.woff b/app/static/fonts/SourceSansPro-Bold-webfont.woff similarity index 100% rename from static/fonts/SourceSansPro-Bold-webfont.woff rename to app/static/fonts/SourceSansPro-Bold-webfont.woff diff --git a/static/fonts/SourceSansPro-It-webfont.eot b/app/static/fonts/SourceSansPro-It-webfont.eot similarity index 100% rename from static/fonts/SourceSansPro-It-webfont.eot rename to app/static/fonts/SourceSansPro-It-webfont.eot diff --git a/static/fonts/SourceSansPro-It-webfont.svg b/app/static/fonts/SourceSansPro-It-webfont.svg similarity index 100% rename from static/fonts/SourceSansPro-It-webfont.svg rename to app/static/fonts/SourceSansPro-It-webfont.svg diff --git a/static/fonts/SourceSansPro-It-webfont.ttf b/app/static/fonts/SourceSansPro-It-webfont.ttf similarity index 100% rename from static/fonts/SourceSansPro-It-webfont.ttf rename to app/static/fonts/SourceSansPro-It-webfont.ttf diff --git a/static/fonts/SourceSansPro-It-webfont.woff b/app/static/fonts/SourceSansPro-It-webfont.woff similarity index 100% rename from static/fonts/SourceSansPro-It-webfont.woff rename to app/static/fonts/SourceSansPro-It-webfont.woff diff --git a/static/fonts/SourceSansPro-Regular-webfont.eot b/app/static/fonts/SourceSansPro-Regular-webfont.eot similarity index 100% rename from static/fonts/SourceSansPro-Regular-webfont.eot rename to app/static/fonts/SourceSansPro-Regular-webfont.eot diff --git a/static/fonts/SourceSansPro-Regular-webfont.svg b/app/static/fonts/SourceSansPro-Regular-webfont.svg similarity index 100% rename from static/fonts/SourceSansPro-Regular-webfont.svg rename to app/static/fonts/SourceSansPro-Regular-webfont.svg diff --git a/static/fonts/SourceSansPro-Regular-webfont.ttf b/app/static/fonts/SourceSansPro-Regular-webfont.ttf similarity index 100% rename from static/fonts/SourceSansPro-Regular-webfont.ttf rename to app/static/fonts/SourceSansPro-Regular-webfont.ttf diff --git a/static/fonts/SourceSansPro-Regular-webfont.woff b/app/static/fonts/SourceSansPro-Regular-webfont.woff similarity index 100% rename from static/fonts/SourceSansPro-Regular-webfont.woff rename to app/static/fonts/SourceSansPro-Regular-webfont.woff diff --git a/static/fonts/demo.html b/app/static/fonts/demo.html similarity index 100% rename from static/fonts/demo.html rename to app/static/fonts/demo.html diff --git a/static/fonts/demo/demo.css b/app/static/fonts/demo/demo.css similarity index 100% rename from static/fonts/demo/demo.css rename to app/static/fonts/demo/demo.css diff --git a/static/fonts/demo/demo.js b/app/static/fonts/demo/demo.js similarity index 100% rename from static/fonts/demo/demo.js rename to app/static/fonts/demo/demo.js diff --git a/static/fonts/fontawesome-webfont.eot b/app/static/fonts/fontawesome-webfont.eot similarity index 100% rename from static/fonts/fontawesome-webfont.eot rename to app/static/fonts/fontawesome-webfont.eot diff --git a/static/fonts/fontawesome-webfont.svg b/app/static/fonts/fontawesome-webfont.svg similarity index 100% rename from static/fonts/fontawesome-webfont.svg rename to app/static/fonts/fontawesome-webfont.svg diff --git a/static/fonts/fontawesome-webfont.ttf b/app/static/fonts/fontawesome-webfont.ttf similarity index 100% rename from static/fonts/fontawesome-webfont.ttf rename to app/static/fonts/fontawesome-webfont.ttf diff --git a/static/fonts/fontawesome-webfont.woff b/app/static/fonts/fontawesome-webfont.woff similarity index 100% rename from static/fonts/fontawesome-webfont.woff rename to app/static/fonts/fontawesome-webfont.woff diff --git a/static/fonts/fontawesome-webfont.woff2 b/app/static/fonts/fontawesome-webfont.woff2 similarity index 100% rename from static/fonts/fontawesome-webfont.woff2 rename to app/static/fonts/fontawesome-webfont.woff2 diff --git a/static/fonts/lte-ie7.js b/app/static/fonts/lte-ie7.js similarity index 100% rename from static/fonts/lte-ie7.js rename to app/static/fonts/lte-ie7.js diff --git a/static/fonts/style.css b/app/static/fonts/style.css similarity index 100% rename from static/fonts/style.css rename to app/static/fonts/style.css diff --git a/static/images/CCP.jpg b/app/static/images/CCP.jpg similarity index 100% rename from static/images/CCP.jpg rename to app/static/images/CCP.jpg diff --git a/static/images/ExowebGlossyLogo.png b/app/static/images/ExowebGlossyLogo.png similarity index 100% rename from static/images/ExowebGlossyLogo.png rename to app/static/images/ExowebGlossyLogo.png diff --git a/static/images/Google_Logo_25wht.gif b/app/static/images/Google_Logo_25wht.gif similarity index 100% rename from static/images/Google_Logo_25wht.gif rename to app/static/images/Google_Logo_25wht.gif diff --git a/static/images/Lucasfilm_logo.png b/app/static/images/Lucasfilm_logo.png similarity index 100% rename from static/images/Lucasfilm_logo.png rename to app/static/images/Lucasfilm_logo.png diff --git a/static/images/OSAFLogo.gif b/app/static/images/OSAFLogo.gif similarity index 100% rename from static/images/OSAFLogo.gif rename to app/static/images/OSAFLogo.gif diff --git a/static/images/OnlineDegreeReviews-Logo.png b/app/static/images/OnlineDegreeReviews-Logo.png similarity index 100% rename from static/images/OnlineDegreeReviews-Logo.png rename to app/static/images/OnlineDegreeReviews-Logo.png diff --git a/static/images/PythonPowered.gif b/app/static/images/PythonPowered.gif similarity index 100% rename from static/images/PythonPowered.gif rename to app/static/images/PythonPowered.gif diff --git a/static/images/PythonPoweredAnim.gif b/app/static/images/PythonPoweredAnim.gif similarity index 100% rename from static/images/PythonPoweredAnim.gif rename to app/static/images/PythonPoweredAnim.gif diff --git a/static/images/PythonPoweredAnimSmall.gif b/app/static/images/PythonPoweredAnimSmall.gif similarity index 100% rename from static/images/PythonPoweredAnimSmall.gif rename to app/static/images/PythonPoweredAnimSmall.gif diff --git a/static/images/PythonPoweredSmall.gif b/app/static/images/PythonPoweredSmall.gif similarity index 100% rename from static/images/PythonPoweredSmall.gif rename to app/static/images/PythonPoweredSmall.gif diff --git a/static/images/README.txt b/app/static/images/README.txt similarity index 100% rename from static/images/README.txt rename to app/static/images/README.txt diff --git a/static/images/Red_Hat.png b/app/static/images/Red_Hat.png similarity index 100% rename from static/images/Red_Hat.png rename to app/static/images/Red_Hat.png diff --git a/static/images/activegrid.gif b/app/static/images/activegrid.gif similarity index 100% rename from static/images/activegrid.gif rename to app/static/images/activegrid.gif diff --git a/static/images/activestate_logo.gif b/app/static/images/activestate_logo.gif similarity index 100% rename from static/images/activestate_logo.gif rename to app/static/images/activestate_logo.gif diff --git a/static/images/arraylogo.jpg b/app/static/images/arraylogo.jpg similarity index 100% rename from static/images/arraylogo.jpg rename to app/static/images/arraylogo.jpg diff --git a/static/images/astilogo.gif b/app/static/images/astilogo.gif similarity index 100% rename from static/images/astilogo.gif rename to app/static/images/astilogo.gif diff --git a/static/images/batteries-included.jpg b/app/static/images/batteries-included.jpg similarity index 100% rename from static/images/batteries-included.jpg rename to app/static/images/batteries-included.jpg diff --git a/static/images/beslist.png b/app/static/images/beslist.png similarity index 100% rename from static/images/beslist.png rename to app/static/images/beslist.png diff --git a/static/images/bizrate.gif b/app/static/images/bizrate.gif similarity index 100% rename from static/images/bizrate.gif rename to app/static/images/bizrate.gif diff --git a/static/images/blank.gif b/app/static/images/blank.gif similarity index 100% rename from static/images/blank.gif rename to app/static/images/blank.gif diff --git a/static/images/bullet.gif b/app/static/images/bullet.gif similarity index 100% rename from static/images/bullet.gif rename to app/static/images/bullet.gif diff --git a/static/images/button-on-bg.png b/app/static/images/button-on-bg.png similarity index 100% rename from static/images/button-on-bg.png rename to app/static/images/button-on-bg.png diff --git a/static/images/canonical-logo.png b/app/static/images/canonical-logo.png similarity index 100% rename from static/images/canonical-logo.png rename to app/static/images/canonical-logo.png diff --git a/static/images/cpacket_logo.jpg b/app/static/images/cpacket_logo.jpg similarity index 100% rename from static/images/cpacket_logo.jpg rename to app/static/images/cpacket_logo.jpg diff --git a/static/images/donate.png b/app/static/images/donate.png similarity index 100% rename from static/images/donate.png rename to app/static/images/donate.png diff --git a/static/images/emd_logo.gif b/app/static/images/emd_logo.gif similarity index 100% rename from static/images/emd_logo.gif rename to app/static/images/emd_logo.gif diff --git a/static/images/enthought.jpg b/app/static/images/enthought.jpg similarity index 100% rename from static/images/enthought.jpg rename to app/static/images/enthought.jpg diff --git a/static/images/enthought.png b/app/static/images/enthought.png similarity index 100% rename from static/images/enthought.png rename to app/static/images/enthought.png diff --git a/static/images/favicon16x16.ico b/app/static/images/favicon16x16.ico similarity index 100% rename from static/images/favicon16x16.ico rename to app/static/images/favicon16x16.ico diff --git a/static/images/finding-idle.png b/app/static/images/finding-idle.png similarity index 100% rename from static/images/finding-idle.png rename to app/static/images/finding-idle.png diff --git a/static/images/freewear-1.png b/app/static/images/freewear-1.png similarity index 100% rename from static/images/freewear-1.png rename to app/static/images/freewear-1.png diff --git a/static/images/freewear-logo.png b/app/static/images/freewear-logo.png similarity index 100% rename from static/images/freewear-logo.png rename to app/static/images/freewear-logo.png diff --git a/static/images/globo_logo.gif b/app/static/images/globo_logo.gif similarity index 100% rename from static/images/globo_logo.gif rename to app/static/images/globo_logo.gif diff --git a/static/images/google.gif b/app/static/images/google.gif similarity index 100% rename from static/images/google.gif rename to app/static/images/google.gif diff --git a/static/images/header-bg.png b/app/static/images/header-bg.png similarity index 100% rename from static/images/header-bg.png rename to app/static/images/header-bg.png diff --git a/static/images/header-bg2.png b/app/static/images/header-bg2.png similarity index 100% rename from static/images/header-bg2.png rename to app/static/images/header-bg2.png diff --git a/static/images/hitflip_logo.jpg b/app/static/images/hitflip_logo.jpg similarity index 100% rename from static/images/hitflip_logo.jpg rename to app/static/images/hitflip_logo.jpg diff --git a/static/images/hood_logo.gif b/app/static/images/hood_logo.gif similarity index 100% rename from static/images/hood_logo.gif rename to app/static/images/hood_logo.gif diff --git a/static/images/hw128_28.gif b/app/static/images/hw128_28.gif similarity index 100% rename from static/images/hw128_28.gif rename to app/static/images/hw128_28.gif diff --git a/static/images/infrastructure/dyn.png b/app/static/images/infrastructure/dyn.png similarity index 100% rename from static/images/infrastructure/dyn.png rename to app/static/images/infrastructure/dyn.png diff --git a/static/images/infrastructure/gandi.png b/app/static/images/infrastructure/gandi.png similarity index 100% rename from static/images/infrastructure/gandi.png rename to app/static/images/infrastructure/gandi.png diff --git a/static/images/infrastructure/osl.png b/app/static/images/infrastructure/osl.png similarity index 100% rename from static/images/infrastructure/osl.png rename to app/static/images/infrastructure/osl.png diff --git a/static/images/infrastructure/pagerduty.png b/app/static/images/infrastructure/pagerduty.png similarity index 100% rename from static/images/infrastructure/pagerduty.png rename to app/static/images/infrastructure/pagerduty.png diff --git a/static/images/infrastructure/pingdom.png b/app/static/images/infrastructure/pingdom.png similarity index 100% rename from static/images/infrastructure/pingdom.png rename to app/static/images/infrastructure/pingdom.png diff --git a/static/images/infrastructure/upfront.png b/app/static/images/infrastructure/upfront.png similarity index 100% rename from static/images/infrastructure/upfront.png rename to app/static/images/infrastructure/upfront.png diff --git a/static/images/infrastructure/xs4all.png b/app/static/images/infrastructure/xs4all.png similarity index 100% rename from static/images/infrastructure/xs4all.png rename to app/static/images/infrastructure/xs4all.png diff --git a/static/images/ironport.gif b/app/static/images/ironport.gif similarity index 100% rename from static/images/ironport.gif rename to app/static/images/ironport.gif diff --git a/static/images/knmp-logo.png b/app/static/images/knmp-logo.png similarity index 100% rename from static/images/knmp-logo.png rename to app/static/images/knmp-logo.png diff --git a/static/images/logo_lincoln_loop.png b/app/static/images/logo_lincoln_loop.png similarity index 100% rename from static/images/logo_lincoln_loop.png rename to app/static/images/logo_lincoln_loop.png diff --git a/static/images/microbit.png b/app/static/images/microbit.png similarity index 100% rename from static/images/microbit.png rename to app/static/images/microbit.png diff --git a/static/images/nav-off-bg.png b/app/static/images/nav-off-bg.png similarity index 100% rename from static/images/nav-off-bg.png rename to app/static/images/nav-off-bg.png diff --git a/static/images/nav-on-bg.png b/app/static/images/nav-on-bg.png similarity index 100% rename from static/images/nav-on-bg.png rename to app/static/images/nav-on-bg.png diff --git a/static/images/open_end_ab_logo.png b/app/static/images/open_end_ab_logo.png similarity index 100% rename from static/images/open_end_ab_logo.png rename to app/static/images/open_end_ab_logo.png diff --git a/static/images/openeye-logo.gif b/app/static/images/openeye-logo.gif similarity index 100% rename from static/images/openeye-logo.gif rename to app/static/images/openeye-logo.gif diff --git a/static/images/opensource-110x95.png b/app/static/images/opensource-110x95.png similarity index 100% rename from static/images/opensource-110x95.png rename to app/static/images/opensource-110x95.png diff --git a/static/images/oreilly_logo.gif b/app/static/images/oreilly_logo.gif similarity index 100% rename from static/images/oreilly_logo.gif rename to app/static/images/oreilly_logo.gif diff --git a/static/images/osi-certified-120x100.gif b/app/static/images/osi-certified-120x100.gif similarity index 100% rename from static/images/osi-certified-120x100.gif rename to app/static/images/osi-certified-120x100.gif diff --git a/static/images/pattern_banner.gif b/app/static/images/pattern_banner.gif similarity index 100% rename from static/images/pattern_banner.gif rename to app/static/images/pattern_banner.gif diff --git a/static/images/pep-0001-1.png b/app/static/images/pep-0001-1.png similarity index 100% rename from static/images/pep-0001-1.png rename to app/static/images/pep-0001-1.png diff --git a/static/images/psf-logo.gif b/app/static/images/psf-logo.gif similarity index 100% rename from static/images/psf-logo.gif rename to app/static/images/psf-logo.gif diff --git a/static/images/py_mac-sq-64.png b/app/static/images/py_mac-sq-64.png similarity index 100% rename from static/images/py_mac-sq-64.png rename to app/static/images/py_mac-sq-64.png diff --git a/static/images/pyastra.jpg b/app/static/images/pyastra.jpg similarity index 100% rename from static/images/pyastra.jpg rename to app/static/images/pyastra.jpg diff --git a/static/images/pycon-2010-banner.png b/app/static/images/pycon-2010-banner.png similarity index 100% rename from static/images/pycon-2010-banner.png rename to app/static/images/pycon-2010-banner.png diff --git a/static/images/pygoogle.jpg b/app/static/images/pygoogle.jpg similarity index 100% rename from static/images/pygoogle.jpg rename to app/static/images/pygoogle.jpg diff --git a/static/images/pynasa.jpg b/app/static/images/pynasa.jpg similarity index 100% rename from static/images/pynasa.jpg rename to app/static/images/pynasa.jpg diff --git a/static/images/python-audio-100x40.png b/app/static/images/python-audio-100x40.png similarity index 100% rename from static/images/python-audio-100x40.png rename to app/static/images/python-audio-100x40.png diff --git a/static/images/python-data-100x40.png b/app/static/images/python-data-100x40.png similarity index 100% rename from static/images/python-data-100x40.png rename to app/static/images/python-data-100x40.png diff --git a/static/images/python-logo.gif b/app/static/images/python-logo.gif similarity index 100% rename from static/images/python-logo.gif rename to app/static/images/python-logo.gif diff --git a/static/images/python-video-icon.png b/app/static/images/python-video-icon.png similarity index 100% rename from static/images/python-video-icon.png rename to app/static/images/python-video-icon.png diff --git a/static/images/pythongear-logo.png b/app/static/images/pythongear-logo.png similarity index 100% rename from static/images/pythongear-logo.png rename to app/static/images/pythongear-logo.png diff --git a/static/images/pythonlogo.eps b/app/static/images/pythonlogo.eps similarity index 100% rename from static/images/pythonlogo.eps rename to app/static/images/pythonlogo.eps diff --git a/static/images/pythonlogo.pdf b/app/static/images/pythonlogo.pdf similarity index 100% rename from static/images/pythonlogo.pdf rename to app/static/images/pythonlogo.pdf diff --git a/static/images/pythonlogo.png b/app/static/images/pythonlogo.png similarity index 100% rename from static/images/pythonlogo.png rename to app/static/images/pythonlogo.png diff --git a/static/images/pythonlogo.tiff b/app/static/images/pythonlogo.tiff similarity index 100% rename from static/images/pythonlogo.tiff rename to app/static/images/pythonlogo.tiff diff --git a/static/images/pyxp.jpg b/app/static/images/pyxp.jpg similarity index 100% rename from static/images/pyxp.jpg rename to app/static/images/pyxp.jpg diff --git a/static/images/seo_moves.jpg b/app/static/images/seo_moves.jpg similarity index 100% rename from static/images/seo_moves.jpg rename to app/static/images/seo_moves.jpg diff --git a/static/images/strakt_logo.gif b/app/static/images/strakt_logo.gif similarity index 100% rename from static/images/strakt_logo.gif rename to app/static/images/strakt_logo.gif diff --git a/static/images/success/Carmanah.png b/app/static/images/success/Carmanah.png similarity index 100% rename from static/images/success/Carmanah.png rename to app/static/images/success/Carmanah.png diff --git a/static/images/success/Honeywell.png b/app/static/images/success/Honeywell.png similarity index 100% rename from static/images/success/Honeywell.png rename to app/static/images/success/Honeywell.png diff --git a/static/images/success/StAndrews.png b/app/static/images/success/StAndrews.png similarity index 100% rename from static/images/success/StAndrews.png rename to app/static/images/success/StAndrews.png diff --git a/static/images/success/afnic.fr.png b/app/static/images/success/afnic.fr.png similarity index 100% rename from static/images/success/afnic.fr.png rename to app/static/images/success/afnic.fr.png diff --git a/static/images/success/forecastwatch.png b/app/static/images/success/forecastwatch.png similarity index 100% rename from static/images/success/forecastwatch.png rename to app/static/images/success/forecastwatch.png diff --git a/static/images/success/frequentis.png b/app/static/images/success/frequentis.png similarity index 100% rename from static/images/success/frequentis.png rename to app/static/images/success/frequentis.png diff --git a/static/images/success/journyx.png b/app/static/images/success/journyx.png similarity index 100% rename from static/images/success/journyx.png rename to app/static/images/success/journyx.png diff --git a/static/images/success/mayavi.jpg b/app/static/images/success/mayavi.jpg similarity index 100% rename from static/images/success/mayavi.jpg rename to app/static/images/success/mayavi.jpg diff --git a/static/images/success/mmtk.jpg b/app/static/images/success/mmtk.jpg similarity index 100% rename from static/images/success/mmtk.jpg rename to app/static/images/success/mmtk.jpg diff --git a/static/images/success/nasa.jpg b/app/static/images/success/nasa.jpg similarity index 100% rename from static/images/success/nasa.jpg rename to app/static/images/success/nasa.jpg diff --git a/static/images/success/natsworld.png b/app/static/images/success/natsworld.png similarity index 100% rename from static/images/success/natsworld.png rename to app/static/images/success/natsworld.png diff --git a/static/images/success/standrews.jpg b/app/static/images/success/standrews.jpg similarity index 100% rename from static/images/success/standrews.jpg rename to app/static/images/success/standrews.jpg diff --git a/static/images/success/superleague.png b/app/static/images/success/superleague.png similarity index 100% rename from static/images/success/superleague.png rename to app/static/images/success/superleague.png diff --git a/static/images/success/tribon.jpg b/app/static/images/success/tribon.jpg similarity index 100% rename from static/images/success/tribon.jpg rename to app/static/images/success/tribon.jpg diff --git a/static/images/sun_logo.png b/app/static/images/sun_logo.png similarity index 100% rename from static/images/sun_logo.png rename to app/static/images/sun_logo.png diff --git a/static/images/tabblo.png b/app/static/images/tabblo.png similarity index 100% rename from static/images/tabblo.png rename to app/static/images/tabblo.png diff --git a/static/images/terminal-in-finder.png b/app/static/images/terminal-in-finder.png similarity index 100% rename from static/images/terminal-in-finder.png rename to app/static/images/terminal-in-finder.png diff --git a/static/images/trans.gif b/app/static/images/trans.gif similarity index 100% rename from static/images/trans.gif rename to app/static/images/trans.gif diff --git a/static/images/uniblue-logo.jpg b/app/static/images/uniblue-logo.jpg similarity index 100% rename from static/images/uniblue-logo.jpg rename to app/static/images/uniblue-logo.jpg diff --git a/static/images/wargaming.png b/app/static/images/wargaming.png similarity index 100% rename from static/images/wargaming.png rename to app/static/images/wargaming.png diff --git a/static/images/winglogo.gif b/app/static/images/winglogo.gif similarity index 100% rename from static/images/winglogo.gif rename to app/static/images/winglogo.gif diff --git a/static/images/worldmap.jpg b/app/static/images/worldmap.jpg similarity index 100% rename from static/images/worldmap.jpg rename to app/static/images/worldmap.jpg diff --git a/static/images/zeomega.gif b/app/static/images/zeomega.gif similarity index 100% rename from static/images/zeomega.gif rename to app/static/images/zeomega.gif diff --git a/static/images/zeuux.jpg b/app/static/images/zeuux.jpg similarity index 100% rename from static/images/zeuux.jpg rename to app/static/images/zeuux.jpg diff --git a/static/images/zimbio_corp_logo.gif b/app/static/images/zimbio_corp_logo.gif similarity index 100% rename from static/images/zimbio_corp_logo.gif rename to app/static/images/zimbio_corp_logo.gif diff --git a/static/images/zope_logo.gif b/app/static/images/zope_logo.gif similarity index 100% rename from static/images/zope_logo.gif rename to app/static/images/zope_logo.gif diff --git a/static/img/bg_direction_nav.png b/app/static/img/bg_direction_nav.png similarity index 100% rename from static/img/bg_direction_nav.png rename to app/static/img/bg_direction_nav.png diff --git a/static/img/landing-about.png b/app/static/img/landing-about.png similarity index 100% rename from static/img/landing-about.png rename to app/static/img/landing-about.png diff --git a/static/img/landing-community.png b/app/static/img/landing-community.png similarity index 100% rename from static/img/landing-community.png rename to app/static/img/landing-community.png diff --git a/static/img/landing-docs.png b/app/static/img/landing-docs.png similarity index 100% rename from static/img/landing-docs.png rename to app/static/img/landing-docs.png diff --git a/static/img/landing-downloads.png b/app/static/img/landing-downloads.png similarity index 100% rename from static/img/landing-downloads.png rename to app/static/img/landing-downloads.png diff --git a/static/img/psf-logo.png b/app/static/img/psf-logo.png similarity index 100% rename from static/img/psf-logo.png rename to app/static/img/psf-logo.png diff --git a/static/img/psf-logo@2x.png b/app/static/img/psf-logo@2x.png similarity index 100% rename from static/img/psf-logo@2x.png rename to app/static/img/psf-logo@2x.png diff --git a/static/img/psf-logo_print.png b/app/static/img/psf-logo_print.png similarity index 100% rename from static/img/psf-logo_print.png rename to app/static/img/psf-logo_print.png diff --git a/static/img/python-logo-large.png b/app/static/img/python-logo-large.png similarity index 100% rename from static/img/python-logo-large.png rename to app/static/img/python-logo-large.png diff --git a/static/img/python-logo.png b/app/static/img/python-logo.png similarity index 100% rename from static/img/python-logo.png rename to app/static/img/python-logo.png diff --git a/static/img/python-logo@2x.png b/app/static/img/python-logo@2x.png similarity index 100% rename from static/img/python-logo@2x.png rename to app/static/img/python-logo@2x.png diff --git a/static/img/python-logo_print.png b/app/static/img/python-logo_print.png similarity index 100% rename from static/img/python-logo_print.png rename to app/static/img/python-logo_print.png diff --git a/static/img/sample-gmap.png b/app/static/img/sample-gmap.png similarity index 100% rename from static/img/sample-gmap.png rename to app/static/img/sample-gmap.png diff --git a/static/img/sponsors/tick-placeholder.png b/app/static/img/sponsors/tick-placeholder.png similarity index 100% rename from static/img/sponsors/tick-placeholder.png rename to app/static/img/sponsors/tick-placeholder.png diff --git a/static/img/sponsors/tick.svg b/app/static/img/sponsors/tick.svg similarity index 100% rename from static/img/sponsors/tick.svg rename to app/static/img/sponsors/tick.svg diff --git a/static/img/sponsors/title-1.svg b/app/static/img/sponsors/title-1.svg similarity index 100% rename from static/img/sponsors/title-1.svg rename to app/static/img/sponsors/title-1.svg diff --git a/static/img/sponsors/title-2.svg b/app/static/img/sponsors/title-2.svg similarity index 100% rename from static/img/sponsors/title-2.svg rename to app/static/img/sponsors/title-2.svg diff --git a/static/img/sponsors/title-3.svg b/app/static/img/sponsors/title-3.svg similarity index 100% rename from static/img/sponsors/title-3.svg rename to app/static/img/sponsors/title-3.svg diff --git a/static/img/sponsors/title-4.svg b/app/static/img/sponsors/title-4.svg similarity index 100% rename from static/img/sponsors/title-4.svg rename to app/static/img/sponsors/title-4.svg diff --git a/static/img/sponsors/title-5.svg b/app/static/img/sponsors/title-5.svg similarity index 100% rename from static/img/sponsors/title-5.svg rename to app/static/img/sponsors/title-5.svg diff --git a/static/img/sponsors/title-6.svg b/app/static/img/sponsors/title-6.svg similarity index 100% rename from static/img/sponsors/title-6.svg rename to app/static/img/sponsors/title-6.svg diff --git a/static/img/success-glow2.png b/app/static/img/success-glow2.png similarity index 100% rename from static/img/success-glow2.png rename to app/static/img/success-glow2.png diff --git a/static/js/libs/html-includes.js b/app/static/js/libs/html-includes.js similarity index 100% rename from static/js/libs/html-includes.js rename to app/static/js/libs/html-includes.js diff --git a/static/js/libs/jquery-1.8.2.min.js b/app/static/js/libs/jquery-1.8.2.min.js similarity index 100% rename from static/js/libs/jquery-1.8.2.min.js rename to app/static/js/libs/jquery-1.8.2.min.js diff --git a/static/js/libs/jquery-ui-1.12.1.min.js b/app/static/js/libs/jquery-ui-1.12.1.min.js similarity index 100% rename from static/js/libs/jquery-ui-1.12.1.min.js rename to app/static/js/libs/jquery-ui-1.12.1.min.js diff --git a/static/js/libs/masonry.pkgd.min.js b/app/static/js/libs/masonry.pkgd.min.js similarity index 100% rename from static/js/libs/masonry.pkgd.min.js rename to app/static/js/libs/masonry.pkgd.min.js diff --git a/static/js/libs/modernizr.js b/app/static/js/libs/modernizr.js similarity index 100% rename from static/js/libs/modernizr.js rename to app/static/js/libs/modernizr.js diff --git a/static/js/plugins.js b/app/static/js/plugins.js similarity index 100% rename from static/js/plugins.js rename to app/static/js/plugins.js diff --git a/static/js/plugins/IE7.js b/app/static/js/plugins/IE7.js similarity index 97% rename from static/js/plugins/IE7.js rename to app/static/js/plugins/IE7.js index 2884c7d6b..7206899f3 100644 --- a/static/js/plugins/IE7.js +++ b/app/static/js/plugins/IE7.js @@ -1,2409 +1,2409 @@ -/* - IE7/IE8/IE9.js - copyright 2004-2010, Dean Edwards - http://code.google.com/p/ie7-js/ - http://www.opensource.org/licenses/mit-license.php -*/ - -/* W3C compliance for Microsoft Internet Explorer */ - -/* credits/thanks: - Shaggy, Martijn Wargers, Jimmy Cerra, Mark D Anderson, - Lars Dieckow, Erik Arvidsson, Gellert Gyuris, James Denny, - Unknown W Brackets, Benjamin Westfarer, Rob Eberhardt, - Bill Edney, Kevin Newman, James Crompton, Matthew Mastracci, - Doug Wright, Richard York, Kenneth Kolano, MegaZone, - Thomas Verelst, Mark 'Tarquin' Wilton-Jones, Rainer Åhlfors, - David Zulaica, Ken Kolano, Kevin Newman, Sjoerd Visscher, - Ingo Chao -*/ - -// timestamp: Fri, 30 Apr 2010 20:59:18 - -(function(window, document) { - -var IE7 = window.IE7 = { - version: "2.1(beta4)", - toString: K("[IE7]") -}; -IE7.compat = 7; -var appVersion = IE7.appVersion = navigator.appVersion.match(/MSIE (\d\.\d)/)[1] - 0; - -if (/ie7_off/.test(top.location.search) || appVersion < 5.5 || appVersion >= IE7.compat) return; - -var MSIE5 = appVersion < 6; - -var Undefined = K(); -var documentElement = document.documentElement, body, viewport; -var ANON = "!"; -var HEADER = ":link{ie7-link:link}:visited{ie7-link:visited}"; - -// ----------------------------------------------------------------------- -// external -// ----------------------------------------------------------------------- - -var RELATIVE = /^[\w\.]+[^:]*$/; -function makePath(href, path) { - if (RELATIVE.test(href)) href = (path || "") + href; - return href; -}; - -function getPath(href, path) { - href = makePath(href, path); - return href.slice(0, href.lastIndexOf("/") + 1); -}; - -// Get the path to this script -var script = document.scripts[document.scripts.length - 1]; -var path = getPath(script.src); - -// Use microsoft's http request object to load external files -try { - var httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); -} catch (ex) { - // ActiveX disabled -} - -var fileCache = {}; -function loadFile(href, path) { - try { - href = makePath(href, path); - if (!fileCache[href]) { - httpRequest.open("GET", href, false); - httpRequest.send(); - if (httpRequest.status == 0 || httpRequest.status == 200) { - fileCache[href] = httpRequest.responseText; - } - } - } catch (ex) { - // ignore errors - } - return fileCache[href] || ""; -}; - -// ----------------------------------------------------------------------- -// OO support -// ----------------------------------------------------------------------- - - -// This is a cut-down version of base2 (http://code.google.com/p/base2/) - -var _slice = Array.prototype.slice; - -// private -var _FORMAT = /%([1-9])/g; -var _LTRIM = /^\s\s*/; -var _RTRIM = /\s\s*$/; -var _RESCAPE = /([\/()[\]{}|*+-.,^$?\\])/g; // safe regular expressions -var _BASE = /\bbase\b/; -var _HIDDEN = ["constructor", "toString"]; // only override these when prototyping - -var prototyping; - -function Base(){}; -Base.extend = function(_instance, _static) { - // Build the prototype. - prototyping = true; - var _prototype = new this; - extend(_prototype, _instance); - prototyping = false; - - // Create the wrapper for the constructor function. - var _constructor = _prototype.constructor; - function klass() { - // Don't call the constructor function when prototyping. - if (!prototyping) _constructor.apply(this, arguments); - }; - _prototype.constructor = klass; - - // Build the static interface. - klass.extend = arguments.callee; - extend(klass, _static); - klass.prototype = _prototype; - return klass; -}; -Base.prototype.extend = function(source) { - return extend(this, source); -}; - - -// A collection of regular expressions and their associated replacement values. -// A Base class for creating parsers. - -var HASH = "#"; -var ITEMS = "#"; -var KEYS = "."; -var COMPILED = "/"; - -var REGGRP_BACK_REF = /\\(\d+)/g, - REGGRP_ESCAPE_COUNT = /\[(\\.|[^\]\\])+\]|\\.|\(\?/g, - REGGRP_PAREN = /\(/g, - REGGRP_LOOKUP = /\$(\d+)/, - REGGRP_LOOKUP_SIMPLE = /^\$\d+$/, - REGGRP_LOOKUPS = /(\[(\\.|[^\]\\])+\]|\\.|\(\?)|\(/g, - REGGRP_DICT_ENTRY = /^<#\w+>$/, - REGGRP_DICT_ENTRIES = /<#(\w+)>/g; - -var RegGrp = Base.extend({ - constructor: function(values) { - this[KEYS] = []; - this[ITEMS] = {}; - this.merge(values); - }, - - //dictionary: null, - //ignoreCase: false, - - add: function(expression, replacement) { - delete this[COMPILED]; - if (expression instanceof RegExp) { - expression = expression.source; - } - if (!this[HASH + expression]) this[KEYS].push(String(expression)); - return this[ITEMS][HASH + expression] = new RegGrp.Item(expression, replacement, this); - }, - - compile: function(recompile) { - if (recompile || !this[COMPILED]) { - this[COMPILED] = new RegExp(this, this.ignoreCase ? "gi" : "g"); - } - return this[COMPILED]; - }, - - merge: function(values) { - for (var i in values) this.add(i, values[i]); - }, - - exec: function(string) { - var group = this, - patterns = group[KEYS], - items = group[ITEMS], item; - var result = this.compile(true).exec(string); - if (result) { - // Loop through the RegGrp items. - var i = 0, offset = 1; - while ((item = items[HASH + patterns[i++]])) { - var next = offset + item.length + 1; - if (result[offset]) { // do we have a result? - if (item.replacement === 0) { - return group.exec(string); - } else { - var args = result.slice(offset, next), j = args.length; - while (--j) args[j] = args[j] || ""; // some platforms return null/undefined for non-matching sub-expressions - args[0] = {match: args[0], item: item}; - return args; - } - } - offset = next; - } - } - return null; - }, - - parse: function(string) { - string += ""; // type safe - var group = this, - patterns = group[KEYS], - items = group[ITEMS]; - return string.replace(this.compile(), function(match) { - var args = [], item, offset = 1, i = arguments.length; - while (--i) args[i] = arguments[i] || ""; // some platforms return null/undefined for non-matching sub-expressions - // Loop through the RegGrp items. - while ((item = items[HASH + patterns[i++]])) { - var next = offset + item.length + 1; - if (args[offset]) { // do we have a result? - var replacement = item.replacement; - switch (typeof replacement) { - case "function": - return replacement.apply(group, args.slice(offset, next)); - case "number": - return args[offset + replacement]; - default: - return replacement; - } - } - offset = next; - } - return match; - }); - }, - - toString: function() { - var strings = [], - keys = this[KEYS], - items = this[ITEMS], item; - for (var i = 0; item = items[HASH + keys[i]]; i++) { - strings[i] = item.source; - } - return "(" + strings.join(")|(") + ")"; - } -}, { - IGNORE: null, // a null replacement value means that there is no replacement. - - Item: Base.extend({ - constructor: function(source, replacement, owner) { - var length = source.indexOf("(") === -1 ? 0 : RegGrp.count(source); - - var dictionary = owner.dictionary; - if (dictionary && source.indexOf("<#") !== -1) { - if (REGGRP_DICT_ENTRY.test(source)) { - var entry = dictionary[ITEMS][HASH + source.slice(2, -1)]; - source = entry.replacement; - length = entry._length; - } else { - source = dictionary.parse(source); - } - } - - if (typeof replacement == "number") replacement = String(replacement); - else if (replacement == null) replacement = 0; - - // Does the expression use sub-expression lookups? - if (typeof replacement == "string" && REGGRP_LOOKUP.test(replacement)) { - if (REGGRP_LOOKUP_SIMPLE.test(replacement)) { // A simple lookup? (e.g. "$2"). - // Store the index (used for fast retrieval of matched strings). - var index = replacement.slice(1) - 0; - if (index && index <= length) replacement = index; - } else { - // A complicated lookup (e.g. "Hello $2 $1."). - var lookup = replacement, regexp; - replacement = function(match) { - if (!regexp) { - regexp = new RegExp(source, "g" + (this.ignoreCase ? "i": "")); - } - return match.replace(regexp, lookup); - }; - } - } - - this.length = length; - this.source = String(source); - this.replacement = replacement; - } - }), - - count: function(expression) { - return (String(expression).replace(REGGRP_ESCAPE_COUNT, "").match(REGGRP_PAREN) || "").length; - } -}); - -var Dictionary = RegGrp.extend({ - parse: function(phrase) { - // Prevent sub-expressions in dictionary entries from capturing. - var entries = this[ITEMS]; - return phrase.replace(REGGRP_DICT_ENTRIES, function(match, entry) { - entry = entries[HASH + entry]; - return entry ? entry._nonCapturing : match; - }); - }, - - add: function(expression, replacement) { - // Get the underlying replacement value. - if (replacement instanceof RegExp) { - replacement = replacement.source; - } - // Translate the replacement. - // The result is the original replacement recursively parsed by this dictionary. - var nonCapturing = replacement.replace(REGGRP_LOOKUPS, _nonCapture); - if (replacement.indexOf("(") !== -1) { - var realLength = RegGrp.count(replacement); - } - if (replacement.indexOf("<#") !== -1) { - replacement = this.parse(replacement); - nonCapturing = this.parse(nonCapturing); - } - var item = this.base(expression, replacement); - item._nonCapturing = nonCapturing; - item._length = realLength || item.length; // underlying number of sub-groups - return item; - }, - - toString: function() { - return "(<#" + this[PATTERNS].join(">)|(<#") + ">)"; - } -}); - -function _nonCapture(match, escaped) { - return escaped || "(?:"; // non-capturing -}; - -// ========================================================================= -// lang/extend.js -// ========================================================================= - -function extend(object, source) { // or extend(object, key, value) - if (object && source) { - var proto = (typeof source == "function" ? Function : Object).prototype; - // Add constructor, toString etc - var i = _HIDDEN.length, key; - if (prototyping) while (key = _HIDDEN[--i]) { - var value = source[key]; - if (value != proto[key]) { - if (_BASE.test(value)) { - _override(object, key, value) - } else { - object[key] = value; - } - } - } - // Copy each of the source object's properties to the target object. - for (key in source) if (typeof proto[key] == "undefined") { - var value = source[key]; - // Check for method overriding. - if (object[key] && typeof value == "function" && _BASE.test(value)) { - _override(object, key, value); - } else { - object[key] = value; - } - } - } - return object; -}; - -function _override(object, name, method) { - // Override an existing method. - var ancestor = object[name]; - object[name] = function() { - var previous = this.base; - this.base = ancestor; - var returnValue = method.apply(this, arguments); - this.base = previous; - return returnValue; - }; -}; - -function combine(keys, values) { - // Combine two arrays to make a hash. - if (!values) values = keys; - var hash = {}; - for (var i in keys) hash[i] = values[i]; - return hash; -}; - -function format(string) { - // Replace %n with arguments[n]. - // e.g. format("%1 %2%3 %2a %1%3", "she", "se", "lls"); - // ==> "she sells sea shells" - // Only %1 - %9 supported. - var args = arguments; - var _FORMAT = new RegExp("%([1-" + arguments.length + "])", "g"); - return String(string).replace(_FORMAT, function(match, index) { - return index < args.length ? args[index] : match; - }); -}; - -function match(string, expression) { - // Same as String.match() except that this function will return an empty - // array if there is no match. - return String(string).match(expression) || []; -}; - -function rescape(string) { - // Make a string safe for creating a RegExp. - return String(string).replace(_RESCAPE, "\\$1"); -}; - -// http://blog.stevenlevithan.com/archives/faster-trim-javascript -function trim(string) { - return String(string).replace(_LTRIM, "").replace(_RTRIM, ""); -}; - -function K(k) { - return function() { - return k; - }; -}; - -// ----------------------------------------------------------------------- -// parsing -// ----------------------------------------------------------------------- - -var Parser = RegGrp.extend({ignoreCase: true}); - -var SINGLE_QUOTES = /'/g, - ESCAPED = /'(\d+)'/g, - ESCAPE = /\\/g, - UNESCAPE = /\\([nrtf'"])/g; - -var strings = []; - -var encoder = new Parser({ - // comments - "": "", - "\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\/": "", - // get rid - "@(namespace|import)[^;\\n]+[;\\n]": "", - // strings - "'(\\\\.|[^'\\\\])*'": encodeString, - '"(\\\\.|[^"\\\\])*"': encodeString, - // white space - "\\s+": " " -}); - -function encode(selector) { - return encoder.parse(selector).replace(UNESCAPE, "$1"); -}; - -function decode(query) { - // put string values back - return query.replace(ESCAPED, decodeString); -}; - -function encodeString(string) { - var index = strings.length; - strings[index] = string.slice(1, -1) - .replace(UNESCAPE, "$1") - .replace(SINGLE_QUOTES, "\\'"); - return "'" + index + "'"; -}; - -function decodeString(match, index) { - var string = strings[index]; - if (string == null) return match; - return "'" + strings[index] + "'"; -}; - -function getString(value) { - return value.indexOf("'") === 0 ? strings[value.slice(1, - 1)] : value; -}; - -// clone a "width" function to create a "height" function -var rotater = new RegGrp({ - Width: "Height", - width: "height", - Left: "Top", - left: "top", - Right: "Bottom", - right: "bottom", - onX: "onY" -}); - -function rotate(fn) { - return rotater.parse(fn); -}; - -// ----------------------------------------------------------------------- -// event handling -// ----------------------------------------------------------------------- - -var eventHandlers = []; - -function addResize(handler) { - addRecalc(handler); - addEventHandler(window, "onresize", handler); -}; - -// add an event handler (function) to an element -function addEventHandler(element, type, handler) { - element.attachEvent(type, handler); - // store the handler so it can be detached later - eventHandlers.push(arguments); -}; - -// remove an event handler assigned to an element by IE7 -function removeEventHandler(element, type, handler) { - try { - element.detachEvent(type, handler); - } catch (ex) { - // write a letter of complaint to microsoft.. - } -}; - -// remove event handlers (they eat memory) -addEventHandler(window, "onunload", function() { - var handler; - while (handler = eventHandlers.pop()) { - removeEventHandler(handler[0], handler[1], handler[2]); - } -}); - -function register(handler, element, condition) { // -@DRE - //var set = handler[element.uniqueID]; - if (!handler.elements) handler.elements = {}; - if (condition) handler.elements[element.uniqueID] = element; - else delete handler.elements[element.uniqueID]; - //return !set && condition; - return condition; -}; - -addEventHandler(window, "onbeforeprint", function() { - if (!IE7.CSS.print) new StyleSheet("print"); - IE7.CSS.print.recalc(); -}); - -// ----------------------------------------------------------------------- -// pixel conversion -// ----------------------------------------------------------------------- - -// this is handy because it means that web developers can mix and match -// measurement units in their style sheets. it is not uncommon to -// express something like padding in "em" units whilst border thickness -// is most often expressed in pixels. - -var PIXEL = /^\d+(px)?$/i; -var PERCENT = /^\d+%$/; -var getPixelValue = function(element, value) { - if (PIXEL.test(value)) return parseInt(value); - var style = element.style.left; - var runtimeStyle = element.runtimeStyle.left; - element.runtimeStyle.left = element.currentStyle.left; - element.style.left = value || 0; - value = element.style.pixelLeft; - element.style.left = style; - element.runtimeStyle.left = runtimeStyle; - return value; -}; - -// ----------------------------------------------------------------------- -// generic -// ----------------------------------------------------------------------- - -var $IE7 = "ie7-"; - -var Fix = Base.extend({ - constructor: function() { - this.fixes = []; - this.recalcs = []; - }, - init: Undefined -}); - -// a store for functions that will be called when refreshing IE7 -var recalcs = []; -function addRecalc(recalc) { - recalcs.push(recalc); -}; - -IE7.recalc = function() { - IE7.HTML.recalc(); - // re-apply style sheet rules (re-calculate ie7 classes) - IE7.CSS.recalc(); - // apply global fixes to the document - for (var i = 0; i < recalcs.length; i++) recalcs[i](); -}; - -function isFixed(element) { - return element.currentStyle["ie7-position"] == "fixed"; -}; - -// original style -function getDefinedStyle(element, propertyName) { - return element.currentStyle[$IE7 + propertyName] || element.currentStyle[propertyName]; -}; - -function setOverrideStyle(element, propertyName, value) { - if (element.currentStyle[$IE7 + propertyName] == null) { - element.runtimeStyle[$IE7 + propertyName] = element.currentStyle[propertyName]; - } - element.runtimeStyle[propertyName] = value; -}; - -// Create a temporary element which is used to inherit styles -// from the target element. -function createTempElement(tagName) { - var element = document.createElement(tagName || "object"); - element.style.cssText = "position:absolute;padding:0;display:block;border:none;clip:rect(0 0 0 0);left:-9999"; - element.ie7_anon = true; - return element; -}; - - -// ========================================================================= -// ie7-css.js -// ========================================================================= - -var NEXT_SIBLING = "(e.nextSibling&&IE7._getElementSibling(e,'next'))", - PREVIOUS_SIBLING = NEXT_SIBLING.replace(/next/g, "previous"), - IS_ELEMENT = "e.nodeName>'@'", - IF_ELEMENT = "if(" + IS_ELEMENT + "){"; - -var ID_ATTRIBUTE = "(e.nodeName==='FORM'?IE7._getAttribute(e,'id'):e.id)"; - -var HYPERLINK = /a(#[\w-]+)?(\.[\w-]+)?:(hover|active)/i; -var FIRST_LINE_LETTER = /(.*)(:first-(line|letter))/; -var SPACE = /\s/; -var RULE = /((?:\\.|[^{\\])+)\{((?:\\.|[^}\\])+)\}/g; -var SELECTOR = /(?:\\.|[^,\\])+/g; - -var styleSheets = document.styleSheets; - -var inheritedProperties = []; - -IE7.CSS = new (Fix.extend({ // single instance - parser: new Parser, - screen: "", - print: "", - styles: [], - rules: [], - pseudoClasses: appVersion < 7 ? "first\\-child" : "", - dynamicPseudoClasses: { - toString: function() { - var strings = []; - for (var pseudoClass in this) strings.push(pseudoClass); - return strings.join("|"); - } - }, - - init: function() { - var NONE = "^\x01$"; - var CLASS = "\\[class=?[^\\]]*\\]"; - var pseudoClasses = []; - if (this.pseudoClasses) pseudoClasses.push(this.pseudoClasses); - var dynamicPseudoClasses = this.dynamicPseudoClasses.toString(); - if (dynamicPseudoClasses) pseudoClasses.push(dynamicPseudoClasses); - pseudoClasses = pseudoClasses.join("|"); - var unknown = appVersion < 7 ? ["[>+~\\[(]|([:.])[\\w-]+\\1"] : [CLASS]; - if (pseudoClasses) unknown.push(":(" + pseudoClasses + ")"); - this.UNKNOWN = new RegExp(unknown.join("|") || NONE, "i"); - var complex = appVersion < 7 ? ["\\[[^\\]]+\\]|[^\\s(\\[]+\\s*[+~]"] : [CLASS]; - var complexRule = complex.concat(); - if (pseudoClasses) complexRule.push(":(" + pseudoClasses + ")"); - Rule.COMPLEX = new RegExp(complexRule.join("|") || NONE, "ig"); - if (this.pseudoClasses) complex.push(":(" + this.pseudoClasses + ")"); - DynamicRule.COMPLEX = new RegExp(complex.join("|") || NONE, "i"); - dynamicPseudoClasses = "not\\(:" + dynamicPseudoClasses.split("|").join("\\)|not\\(:") + "\\)|" + dynamicPseudoClasses; - DynamicRule.MATCH = new RegExp(dynamicPseudoClasses ? "(.*?):(" + dynamicPseudoClasses + ")(.*)" : NONE, "i"); - - this.createStyleSheet(); - this.refresh(); - }, - - addEventHandler: function() { - addEventHandler.apply(null, arguments); - }, - - addFix: function(expression, replacement) { - this.parser.add(expression, replacement); - }, - - addRecalc: function(propertyName, test, handler, replacement) { - // recalcs occur whenever the document is refreshed using document.recalc() - propertyName = propertyName.source || propertyName; - test = new RegExp("([{;\\s])" + propertyName + "\\s*:\\s*" + test + "[^;}]*"); - var id = this.recalcs.length; - if (typeof replacement == "string") replacement = propertyName + ":" + replacement; - this.addFix(test, function(match) { - if (typeof replacement == "function") replacement = replacement(match); - return (replacement ? replacement : match) + ";ie7-" + match.slice(1) + ";ie7_recalc" + id + ":1"; - }); - this.recalcs.push(arguments); - return id; - }, - - apply: function() { - this.getInlineCSS(); - new StyleSheet("screen"); - this.trash(); - }, - - createStyleSheet: function() { - // create the IE7 style sheet - document.getElementsByTagName("head")[0].appendChild(document.createElement("style")); - this.styleSheet = styleSheets[styleSheets.length - 1]; - // flag it so we can ignore it during parsing - this.styleSheet.ie7 = true; - this.styleSheet.owningElement.ie7 = true; - this.styleSheet.cssText = HEADER; - }, - - getInlineCSS: function() {// load inline styles - var styleSheets = document.getElementsByTagName("style"), styleSheet; - for (var i = styleSheets.length - 1; styleSheet = styleSheets[i]; i--) { - if (!styleSheet.disabled && !styleSheet.ie7) { - styleSheet._cssText = styleSheet.innerHTML; - } - } - }, - - getText: function(styleSheet, path) { - // Internet Explorer will trash unknown selectors (it converts them to "UNKNOWN"). - // So we must reload external style sheets (internal style sheets can have their text - // extracted through the innerHTML property). - - // load the style sheet text from an external file - try { - var cssText = styleSheet.cssText; - } catch (e) { - cssText = ""; - } - if (httpRequest) cssText = loadFile(styleSheet.href, path) || cssText; - return cssText; - }, - - recalc: function() { - this.screen.recalc(); - // we're going to read through all style rules. - // certain rules have had ie7 properties added to them. - // e.g. p{top:0; ie7_recalc2:1; left:0} - // this flags a property in the rule as needing a fix. - // the selector text is then used to query the document. - // we can then loop through the results of the query - // and fix the elements. - // we ignore the IE7 rules - so count them in the header - var RECALCS = /ie7_recalc\d+/g; - var start = HEADER.match(/[{,]/g).length; - // only calculate screen fixes. print fixes don't show up anyway - var rules = this.styleSheet.rules, rule; - var calcs, calc, elements, element, i, j, k, id; - // loop through all rules - for (i = start; rule = rules[i]; i++) { - var cssText = rule.style.cssText; - // search for the "ie7_recalc" flag (there may be more than one) - if (calcs = cssText.match(RECALCS)) { - // use the selector text to query the document - elements = cssQuery(rule.selectorText); - // if there are matching elements then loop - // through the recalc functions and apply them - // to each element - if (elements.length) for (j = 0; j < calcs.length; j++) { - // get the matching flag (e.g. ie7_recalc3) - id = calcs[j]; - // extract the numeric id from the end of the flag - // and use it to index the collection of recalc - // functions - calc = IE7.CSS.recalcs[id.slice(10)][2]; - for (k = 0; (element = elements[k]); k++) { - // apply the fix - if (element.currentStyle[id]) calc(element, cssText); - } - } - } - } - }, - - refresh: function() { - this.styleSheet.cssText = HEADER + this.screen + this.print; - }, - - trash: function() { - // trash the old style sheets - for (var i = 0; i < styleSheets.length; i++) { - if (!styleSheets[i].ie7) { - try { - var cssText = styleSheets[i].cssText; - } catch (e) { - cssText = ""; - } - if (cssText) styleSheets[i].cssText = ""; - } - } - } -})); - -// ----------------------------------------------------------------------- -// IE7 StyleSheet class -// ----------------------------------------------------------------------- - -var StyleSheet = Base.extend({ - constructor: function(media) { - this.media = media; - this.load(); - IE7.CSS[media] = this; - IE7.CSS.refresh(); - }, - - createRule: function(selector, cssText) { - var match; - if (PseudoElement && (match = selector.match(PseudoElement.MATCH))) { - return new PseudoElement(match[1], match[2], cssText); - } else if (match = selector.match(DynamicRule.MATCH)) { - if (!HYPERLINK.test(match[0]) || DynamicRule.COMPLEX.test(match[0])) { - return new DynamicRule(selector, match[1], match[2], match[3], cssText); - } - } else { - return new Rule(selector, cssText); - } - return selector + " {" + cssText + "}"; - }, - - getText: function() { - // store for style sheet text - // parse media decalarations - var MEDIA = /@media\s+([^{]+?)\s*\{([^@]+\})\s*\}/gi; - var IMPORTS = /@import[^;\n]+/gi; - var TRIM_IMPORTS = /@import\s+url\s*\(\s*["']?|["']?\s*\)\s*/gi; - var URL = /(url\s*\(\s*['"]?)([\w\.]+[^:\)]*['"]?\))/gi; - - var self = this; - - // Store loaded cssText URLs - var fileCache = {}; - - function getCSSText(styleSheet, path, media, level) { - var cssText = ""; - if (!level) { - media = toSimpleMedia(styleSheet.media); - level = 0; - } - if (media === "none") { - styleSheet.disabled = true; - return ""; - } - if (media === "all" || media === self.media) { - // IE only allows importing style sheets three levels deep. - // it will crash if you try to access a level below this - try { - var canAcess = !!styleSheet.cssText; - } catch (exe) {} - if (level < 3 && canAcess) { - var hrefs = styleSheet.cssText.match(IMPORTS); - // loop through imported style sheets - for (var i = 0, imported; i < styleSheet.imports.length; i++) { - var imported = styleSheet.imports[i]; - var href = styleSheet._href || styleSheet.href; - imported._href = hrefs[i].replace(TRIM_IMPORTS, ""); - // call this function recursively to get all imported style sheets - cssText += getCSSText(imported, getPath(href, path), media, level + 1); - } - } - // retrieve inline style or load an external style sheet - cssText += encode(styleSheet.href ? loadStyleSheet(styleSheet, path) : styleSheet.owningElement._cssText); - cssText = parseMedia(cssText, self.media); - } - return cssText; - }; - - // Load all style sheets in the document - for (var i = 0; i < styleSheets.length; i++) { - var styleSheet = styleSheets[i]; - if (!styleSheet.disabled && !styleSheet.ie7) this.cssText += getCSSText(styleSheet); - } - - // helper functions - function parseMedia(cssText, media) { - filterMedia.value = media; - return cssText.replace(MEDIA, filterMedia); - }; - - function filterMedia(match, media, cssText) { - media = toSimpleMedia(media); - switch (media) { - case "screen": - case "print": - if (media !== filterMedia.value) return ""; - case "all": - return cssText; - } - return ""; - }; - - function toSimpleMedia(media) { - if (!media) return "all"; - var split = media.toLowerCase().split(/\s*,\s*/); - media = "none"; - for (var i = 0; i < split.length; i++) { - if (split[i] === "all") return "all"; - if (split[i] === "screen") { - if (media === "print") return "all"; - media = "screen"; - } else if (split[i] === "print") { - if (media === "screen") return "all"; - media = "print"; - } - } - return media; - }; - - // Load an external style sheet - function loadStyleSheet(styleSheet, path) { - var href = styleSheet._href || styleSheet.href; - var url = makePath(href, path); - // If the style sheet has already loaded then don't reload it - if (fileCache[url]) return ""; - // Load from source - fileCache[url] = styleSheet.disabled ? "" : - fixUrls(IE7.CSS.getText(styleSheet, path), getPath(href, path)); - return fileCache[url]; - }; - - // Fix CSS paths. - // We're lumping all css text into one big style sheet so relative - // paths have to be fixed. This is necessary anyway because of other - // Internet Explorer bugs. - function fixUrls(cssText, pathname) { - // hack & slash - return cssText.replace(URL, "$1" + pathname.slice(0, pathname.lastIndexOf("/") + 1) + "$2"); - }; - }, - - load: function() { - this.cssText = ""; - this.getText(); - this.parse(); - if (inheritedProperties.length) { - this.cssText = parseInherited(this.cssText); - } - this.cssText = decode(this.cssText); - fileCache = {}; - }, - - parse: function() { - var cssText = IE7.CSS.parser.parse(this.cssText); - - var declarations = ""; - this.cssText = cssText.replace(/@charset[^;]+;|@font\-face[^\}]+\}/g, function(match) { - declarations += match + "\n"; - return ""; - }); - this.declarations = decode(declarations); - - // Parse the style sheet - var offset = IE7.CSS.rules.length; - var rules = [], rule; - while ((rule = RULE.exec(this.cssText))) { - var cssText = rule[2]; - if (cssText) { - var fixDescendants = appVersion < 7 && cssText.indexOf("AlphaImageLoader") !== -1; - var selectors = rule[1].match(SELECTOR), selector; - for (var i = 0; selector = selectors[i]; i++) { - selector = trim(selector); - var isUnknown = IE7.CSS.UNKNOWN.test(selector); - selectors[i] = isUnknown ? this.createRule(selector, cssText) : selector + "{" + cssText + "}"; - if (fixDescendants) selectors[i] += this.createRule(selector + ">*", "position:relative"); - } - rules.push(selectors.join("\n")); - } - } - this.cssText = rules.join("\n"); - this.rules = IE7.CSS.rules.slice(offset); - }, - - recalc: function() { - var rule, i; - for (i = 0; (rule = this.rules[i]); i++) rule.recalc(); - }, - - toString: function() { - return this.declarations + "@media " + this.media + "{" + this.cssText + "}"; - } -}); - -var PseudoElement; - -// ----------------------------------------------------------------------- -// IE7 style rules -// ----------------------------------------------------------------------- - -var Rule = IE7.Rule = Base.extend({ - constructor: function(selector, cssText) { - this.id = IE7.CSS.rules.length; - this.className = Rule.PREFIX + this.id; - var pseudoElement = selector.match(FIRST_LINE_LETTER); - this.selector = (pseudoElement ? pseudoElement[1] : selector) || "*"; - this.selectorText = this.parse(this.selector) + (pseudoElement ? pseudoElement[2] : ""); - this.cssText = cssText; - this.MATCH = new RegExp("\\s" + this.className + "(\\s|$)", "g"); - IE7.CSS.rules.push(this); - this.init(); - }, - - init: Undefined, - - add: function(element) { - // allocate this class - element.className += " " + this.className; - }, - - recalc: function() { - // execute the underlying css query for this class - var match = cssQuery(this.selector); - // add the class name for all matching elements - for (var i = 0; i < match.length; i++) this.add(match[i]); - }, - - parse: function(selector) { - // attempt to preserve specificity for "loose" parsing by - // removing unknown tokens from a css selector but keep as - // much as we can.. - var simple = selector.replace(Rule.CHILD, " ").replace(Rule.COMPLEX, ""); - if (appVersion < 7) simple = simple.replace(Rule.MULTI, ""); - var tags = match(simple, Rule.TAGS).length - match(selector, Rule.TAGS).length; - var classes = match(simple, Rule.CLASSES).length - match(selector, Rule.CLASSES).length + 1; - while (classes > 0 && Rule.CLASS.test(simple)) { - simple = simple.replace(Rule.CLASS, ""); - classes--; - } - while (tags > 0 && Rule.TAG.test(simple)) { - simple = simple.replace(Rule.TAG, "$1*"); - tags--; - } - simple += "." + this.className; - classes = Math.min(classes, 2); - tags = Math.min(tags, 2); - var score = -10 * classes - tags; - if (score > 0) { - simple = simple + "," + Rule.MAP[score] + " " + simple; - } - return simple; - }, - - remove: function(element) { - // deallocate this class - element.className = element.className.replace(this.MATCH, "$1"); - }, - - toString: function() { - return format("%1 {%2}", this.selectorText, this.cssText); - } -}, { - CHILD: />/g, - CLASS: /\.[\w-]+/, - CLASSES: /[.:\[]/g, - MULTI: /(\.[\w-]+)+/g, - PREFIX: "ie7_class", - TAG: /^\w+|([\s>+~])\w+/, - TAGS: /^\w|[\s>+~]\w/g, - MAP: { - "1": "html", - "2": "html body", - "10": ".ie7_html", - "11": "html.ie7_html", - "12": "html.ie7_html body", - "20": ".ie7_html .ie7_body", - "21": "html.ie7_html .ie7_body", - "22": "html.ie7_html body.ie7_body" - } -}); - -// ----------------------------------------------------------------------- -// IE7 dynamic style -// ----------------------------------------------------------------------- - -// object properties: -// attach: the element that an event handler will be attached to -// target: the element that will have the IE7 class applied - -var DynamicRule = Rule.extend({ - // properties - constructor: function(selector, attach, dynamicPseudoClass, target, cssText) { - this.negated = dynamicPseudoClass.indexOf("not") === 0; - if (this.negated) dynamicPseudoClass = dynamicPseudoClass.slice(5, -1); - // initialise object properties - this.attach = attach || "*"; - this.dynamicPseudoClass = IE7.CSS.dynamicPseudoClasses[dynamicPseudoClass]; - this.target = target; - this.base(selector, cssText); - }, - - recalc: function() { - // execute the underlying css query for this class - var attaches = cssQuery(this.attach), attach; - // process results - for (var i = 0; attach = attaches[i]; i++) { - // retrieve the event handler's target element(s) - var target = this.target ? cssQuery(this.target, attach) : [attach]; - // attach event handlers for dynamic pseudo-classes - if (target.length) this.dynamicPseudoClass.apply(attach, target, this); - } - } -}); - -// ----------------------------------------------------------------------- -// IE7 dynamic pseudo-classes -// ----------------------------------------------------------------------- - -var DynamicPseudoClass = Base.extend({ - constructor: function(name, apply) { - this.name = name; - this.apply = apply; - this.instances = {}; - IE7.CSS.dynamicPseudoClasses[name] = this; - }, - - register: function(instance, negated) { - // an "instance" is actually an Arguments object - var _class = instance[2]; - if (!negated && _class.negated) { - this.unregister(instance, true); - } else { - instance.id = _class.id + instance[0].uniqueID; - if (!this.instances[instance.id]) { - var target = instance[1], j; - for (j = 0; j < target.length; j++) _class.add(target[j]); - this.instances[instance.id] = instance; - } - } - }, - - unregister: function(instance, negated) { - var _class = instance[2]; - if (!negated && _class.negated) { - this.register(instance, true); - } else { - if (this.instances[instance.id]) { - var target = instance[1], j; - for (j = 0; j < target.length; j++) _class.remove(target[j]); - delete this.instances[instance.id]; - } - } - } -}); - -// ----------------------------------------------------------------------- -// dynamic pseudo-classes -// ----------------------------------------------------------------------- - -var Hover = new DynamicPseudoClass("hover", function(element) { - var instance = arguments; - IE7.CSS.addEventHandler(element, "onmouseenter", function() { - Hover.register(instance); - }); - IE7.CSS.addEventHandler(element, "onmouseleave", function() { - Hover.unregister(instance); - }); -}); - -// globally trap the mouseup event (thanks Martijn!) -addEventHandler(document, "onmouseup", function() { - var instances = Hover.instances; - for (var i in instances) - if (!instances[i][0].contains(event.srcElement)) - Hover.unregister(instances[i]); -}); - -var ATTR = { - "=": "%1==='%2'", // "[@%1='%2']" - "~=": "(' '+%1+' ').indexOf(' %2 ')!==-1", // "[contains(concat(' ',@%1,' '),' %2 ')]", - "|=": "%1==='%2'||%1.indexOf('%2-')===0", // "[@%1='%2' or starts-with(@%1,'%2-')]", - "^=": "%1.indexOf('%2')===0", // "[starts-with(@%1,'%2')]", - "$=": "%1.slice(-'%2'.length)==='%2'", // "[ends-with(@%1,'%2')]", - "*=": "%1.indexOf('%2')!==-1" // "[contains(@%1,'%2')]" -}; -ATTR[""] = "%1!=null"; // "[@%1]" - -var FILTER = { - "<#attr>": function(match, name, operator, value) { - var attr = "IE7._getAttribute(e,'" + name + "')"; - value = getString(value); - if (operator.length > 1) { - if (!value || operator === "~=" && SPACE.test(value)) { - return "false&&"; - } - attr = "(" + attr + "||'')"; - } - return "(" + format(ATTR[operator], attr, value) + ")&&"; - }, - - "<#id>": ID_ATTRIBUTE + "==='$1'&&", - - "<#class>": "e.className&&(' '+e.className+' ').indexOf(' $1 ')!==-1&&", - - // PSEDUO - ":first-child": "!" + PREVIOUS_SIBLING + "&&", - ":link": "e.currentStyle['ie7-link']=='link'&&", - ":visited": "e.currentStyle['ie7-link']=='visited'&&" -}; - -// ========================================================================= -// ie7-html.js -// ========================================================================= - -// default font-sizes -//HEADER += "h1{font-size:2em}h2{font-size:1.5em;}h3{font-size:1.17em;}h4{font-size:1em}h5{font-size:.83em}h6{font-size:.67em}"; - -IE7.HTML = new (Fix.extend({ // single instance - fixed: {}, - - init: Undefined, - - addFix: function() { - // fixes are a one-off, they are applied when the document is loaded - this.fixes.push(arguments); - }, - - apply: function() { - for (var i = 0; i < this.fixes.length; i++) { - var match = cssQuery(this.fixes[i][0]); - var fix = this.fixes[i][1]; - for (var j = 0; j < match.length; j++) fix(match[j]); - } - }, - - addRecalc: function() { - // recalcs occur whenever the document is refreshed using document.recalc() - this.recalcs.push(arguments); - }, - - recalc: function() { - // loop through the fixes - for (var i = 0; i < this.recalcs.length; i++) { - var match = cssQuery(this.recalcs[i][0]); - var recalc = this.recalcs[i][1], element; - var key = Math.pow(2, i); - for (var j = 0; (element = match[j]); j++) { - var uniqueID = element.uniqueID; - if ((this.fixed[uniqueID] & key) === 0) { - element = recalc(element) || element; - this.fixed[uniqueID] |= key; - } - } - } - } -})); - -if (appVersion < 7) { - // provide support for the tag. - document.createElement("abbr"); - - // bind to the first child control - IE7.HTML.addRecalc("label", function(label) { - if (!label.htmlFor) { - var firstChildControl = cssQuery("input,textarea", label, true); - if (firstChildControl) { - addEventHandler(label, "onclick", function() { - firstChildControl.click(); - }); - } - } - }); -} - -// ========================================================================= -// ie7-layout.js -// ========================================================================= - -var NUMERIC = "[.\\d]"; - -(function() { - var layout = IE7.Layout = {}; - - // big, ugly box-model hack + min/max stuff - - // #tantek > #erik > #dean { voice-family: hacker; } - - // ----------------------------------------------------------------------- - // "layout" - // ----------------------------------------------------------------------- - - HEADER += "*{boxSizing:content-box}"; - - // give an element "layout" - layout.boxSizing = function(element) { - if (!element.currentStyle.hasLayout) { - //# element.runtimeStyle.fixedHeight = - element.style.height = "0cm"; - if (element.currentStyle.verticalAlign === "auto") - element.runtimeStyle.verticalAlign = "top"; - // when an element acquires "layout", margins no longer collapse correctly - collapseMargins(element); - } - }; - - // ----------------------------------------------------------------------- - // Margin Collapse - // ----------------------------------------------------------------------- - - function collapseMargins(element) { - if (element != viewport && element.currentStyle.position !== "absolute") { - collapseMargin(element, "marginTop"); - collapseMargin(element, "marginBottom"); - } - }; - - function collapseMargin(element, type) { - if (!element.runtimeStyle[type]) { - var parentElement = element.parentElement; - var isTopMargin = type === "marginTop"; - if (parentElement && parentElement.currentStyle.hasLayout && !IE7._getElementSibling(element, isTopMargin ? "previous" : "next")) return; - var child = element[isTopMargin ? "firstChild" : "lastChild"]; - if (child && child.nodeName < "@") child = IE7._getElementSibling(child, isTopMargin ? "next" : "previous"); - if (child && child.currentStyle.styleFloat === "none" && child.currentStyle.hasLayout) { - collapseMargin(child, type); - margin = _getMargin(element, element.currentStyle[type]); - childMargin = _getMargin(child, child.currentStyle[type]); - if (margin < 0 || childMargin < 0) { - element.runtimeStyle[type] = margin + childMargin; - } else { - element.runtimeStyle[type] = Math.max(childMargin, margin); - } - child.runtimeStyle[type] = "0px"; - } - } - }; - - function _getMargin(element, value) { - return value === "auto" ? 0 : getPixelValue(element, value); - }; - - // ----------------------------------------------------------------------- - // box-model - // ----------------------------------------------------------------------- - - // constants - var UNIT = /^[.\d][\w]*$/, AUTO = /^(auto|0cm)$/; - - var apply = {}; - layout.borderBox = function(element){ - apply.Width(element); - apply.Height(element); - }; - - var _fixWidth = function(HEIGHT) { - apply.Width = function(element) { - if (!PERCENT.test(element.currentStyle.width)) _fixWidth(element); - if (HEIGHT) collapseMargins(element); - }; - - function _fixWidth(element, value) { - if (!element.runtimeStyle.fixedWidth) { - if (!value) value = element.currentStyle.width; - element.runtimeStyle.fixedWidth = UNIT.test(value) ? Math.max(0, getFixedWidth(element, value)) + "px" : value; - setOverrideStyle(element, "width", element.runtimeStyle.fixedWidth); - } - }; - - function layoutWidth(element) { - if (!isFixed(element)) { - var layoutParent = element.offsetParent; - while (layoutParent && !layoutParent.currentStyle.hasLayout) layoutParent = layoutParent.offsetParent; - } - return (layoutParent || viewport).clientWidth; - }; - - function getPixelWidth(element, value) { - if (PERCENT.test(value)) return parseInt(parseFloat(value) / 100 * layoutWidth(element)); - return getPixelValue(element, value); - }; - - var getFixedWidth = function(element, value) { - var borderBox = element.currentStyle["ie7-box-sizing"] === "border-box"; - var adjustment = 0; - if (MSIE5 && !borderBox) - adjustment += getBorderWidth(element) + getWidth(element, "padding"); - else if (!MSIE5 && borderBox) - adjustment -= getBorderWidth(element) + getWidth(element, "padding"); - return getPixelWidth(element, value) + adjustment; - }; - - // easy way to get border thickness for elements with "layout" - function getBorderWidth(element) { - return element.offsetWidth - element.clientWidth; - }; - - // have to do some pixel conversion to get padding/margin thickness :-( - function getWidth(element, type) { - return getPixelWidth(element, element.currentStyle[type + "Left"]) + getPixelWidth(element, element.currentStyle[type + "Right"]); - }; - - // ----------------------------------------------------------------------- - // min/max - // ----------------------------------------------------------------------- - - HEADER += "*{minWidth:none;maxWidth:none;min-width:none;max-width:none}"; - - // handle min-width property - layout.minWidth = function(element) { - // IE6 supports min-height so we frig it here - //#if (element.currentStyle.minHeight === "auto") element.runtimeStyle.minHeight = 0; - if (element.currentStyle["min-width"] != null) { - element.style.minWidth = element.currentStyle["min-width"]; - } - if (register(arguments.callee, element, element.currentStyle.minWidth !== "none")) { - layout.boxSizing(element); - _fixWidth(element); - resizeWidth(element); - } - }; - - // clone the minWidth function to make a maxWidth function - eval("IE7.Layout.maxWidth=" + String(layout.minWidth).replace(/min/g, "max")); - - // apply min/max restrictions - function resizeWidth(element) { - // check boundaries - if (element == document.body) { - var width = element.clientWidth; - } else { - var rect = element.getBoundingClientRect(); - width = rect.right - rect.left; - } - if (element.currentStyle.minWidth !== "none" && width < getFixedWidth(element, element.currentStyle.minWidth)) { - element.runtimeStyle.width = element.currentStyle.minWidth; - } else if (element.currentStyle.maxWidth !== "none" && width >= getFixedWidth(element, element.currentStyle.maxWidth)) { - element.runtimeStyle.width = element.currentStyle.maxWidth; - } else { - element.runtimeStyle.width = element.runtimeStyle.fixedWidth; - } - }; - - // ----------------------------------------------------------------------- - // right/bottom - // ----------------------------------------------------------------------- - - function fixRight(element) { - if (register(fixRight, element, /^(fixed|absolute)$/.test(element.currentStyle.position) && - getDefinedStyle(element, "left") !== "auto" && - getDefinedStyle(element, "right") !== "auto" && - AUTO.test(getDefinedStyle(element, "width")))) { - resizeRight(element); - layout.boxSizing(element); - } - }; - layout.fixRight = fixRight; - - function resizeRight(element) { - var left = getPixelWidth(element, element.runtimeStyle._left || element.currentStyle.left); - var width = layoutWidth(element) - getPixelWidth(element, element.currentStyle.right) - left - getWidth(element, "margin"); - if (parseInt(element.runtimeStyle.width) === width) return; - element.runtimeStyle.width = ""; - if (isFixed(element) || HEIGHT || element.offsetWidth < width) { - if (!MSIE5) width -= getBorderWidth(element) + getWidth(element, "padding"); - if (width < 0) width = 0; - element.runtimeStyle.fixedWidth = width; - setOverrideStyle(element, "width", width); - } - }; - - // ----------------------------------------------------------------------- - // window.onresize - // ----------------------------------------------------------------------- - - // handle window resize - var clientWidth = 0; - addResize(function() { - if (!viewport) return; - var i, wider = (clientWidth < viewport.clientWidth); - clientWidth = viewport.clientWidth; - // resize elements with "min-width" set - var elements = layout.minWidth.elements; - for (i in elements) { - var element = elements[i]; - var fixedWidth = (parseInt(element.runtimeStyle.width) === getFixedWidth(element, element.currentStyle.minWidth)); - if (wider && fixedWidth) element.runtimeStyle.width = ""; - if (wider == fixedWidth) resizeWidth(element); - } - // resize elements with "max-width" set - var elements = layout.maxWidth.elements; - for (i in elements) { - var element = elements[i]; - var fixedWidth = (parseInt(element.runtimeStyle.width) === getFixedWidth(element, element.currentStyle.maxWidth)); - if (!wider && fixedWidth) element.runtimeStyle.width = ""; - if (wider !== fixedWidth) resizeWidth(element); - } - // resize elements with "right" set - for (i in fixRight.elements) resizeRight(fixRight.elements[i]); - }); - - // ----------------------------------------------------------------------- - // fix CSS - // ----------------------------------------------------------------------- - if (MSIE5) { - IE7.CSS.addRecalc("width", NUMERIC, apply.Width); - } - if (appVersion < 7) { - IE7.CSS.addRecalc("max-width", NUMERIC, layout.maxWidth); - IE7.CSS.addRecalc("right", NUMERIC, fixRight); - } else if (appVersion == 7) { - if (HEIGHT) IE7.CSS.addRecalc("height", "[\\d.]+%", function(element) { - element.runtimeStyle.pixelHeight = parseInt(layoutWidth(element) * element.currentStyle["ie7-height"].slice(0, -1) / 100); - }); - } - }; - - eval("var _fixHeight=" + rotate(_fixWidth)); - - // apply box-model + min/max fixes - _fixWidth(); - _fixHeight(true); - - if (appVersion < 7) { - IE7.CSS.addRecalc("min-width", NUMERIC, layout.minWidth); - IE7.CSS.addFix(/\bmin-height\s*/, "height"); - } -})(); - -// ========================================================================= -// ie7-graphics.js -// ========================================================================= - -// a small transparent image used as a placeholder -var BLANK_GIF = makePath("blank.gif", path); - -var ALPHA_IMAGE_LOADER = "DXImageTransform.Microsoft.AlphaImageLoader"; -var PNG_FILTER = "progid:" + ALPHA_IMAGE_LOADER + "(src='%1',sizingMethod='%2')"; - -// regular expression version of the above -var PNG; - -var filtered = []; - -function fixImage(element) { - if (PNG.test(element.src)) { - // we have to preserve width and height - var image = new Image(element.width, element.height); - image.onload = function() { - element.width = image.width; - element.height = image.height; - image = null; - }; - image.src = element.src; - // store the original url (we'll put it back when it's printed) - element.pngSrc = element.src; - // add the AlphaImageLoader thingy - addFilter(element); - } -}; - -if (appVersion < 7) { - // ** IE7 VARIABLE - // e.g. apply the hack to all files ending in ".png" - // IE7_PNG_SUFFIX = ".png"; - // You can also set it to a RegExp - // IE7_PNG_SUFFIX = /\d+\.png$/; - - // replace background(-image): url(..) .. with background(-image): .. ;filter: ..; - IE7.CSS.addFix(/background(-image)?\s*:\s*([^};]*)?url\(([^\)]+)\)([^;}]*)?/, function(match, $1, $2, url, $4) { - url = getString(url); - return PNG.test(url) ? "filter:" + format(PNG_FILTER, url, $4.indexOf("no-repeat") === -1 ? "scale" : "crop") + - ";zoom:1;background" + ($1||"") + ":" + ($2||"") + "none" + ($4||"") : match; - }); - - // list-style-image - IE7.CSS.addRecalc(/list\-style(\-image)?/, "[^};]*url", function(element) { - var url = element.currentStyle.listStyleImage.slice(5, -2); - if (PNG.test(url)) { - if (element.nodeName === "LI") { - fixListStyleImage(element, url) - } else if (element.nodeName === "UL") { - for (var i = 0, li; li = element.childNodes[i]; i++) { - if (li.nodeName === "LI") fixListStyleImage(li, url); - } - } - } - }); - - function fixListStyleImage(element, src) { - var style = element.runtimeStyle; - var originalHeight = element.offsetHeight; - var image = new Image; - image.onload = function() { - var paddingLeft = element.currentStyle.paddingLeft; - paddingLeft = paddingLeft === "0px" ? 0 : getPixelValue(element, paddingLeft); - style.paddingLeft = (paddingLeft + this.width) + "px"; - style.marginLeft = -this.width + "px"; - style.listStyleType = "none"; - style.listStyleImage = "none"; - style.paddingTop = Math.max(originalHeight - element.offsetHeight, 0) + "px"; - addFilter(element, "crop", src); - element.style.zoom = "100%"; - }; - image.src = src; - }; - - // ----------------------------------------------------------------------- - // fix PNG transparency (HTML images) - // ----------------------------------------------------------------------- - - IE7.HTML.addRecalc("img,input", function(element) { - if (element.nodeName === "INPUT" && element.type !== "image") return; - fixImage(element); - addEventHandler(element, "onpropertychange", function() { - if (!printing && event.propertyName === "src" && - element.src.indexOf(BLANK_GIF) === -1) fixImage(element); - }); - }); - - // assume that background images should not be printed - // (if they are not transparent then they'll just obscure content) - // but we'll put foreground images back... - var printing = false; - addEventHandler(window, "onbeforeprint", function() { - printing = true; - for (var i = 0; i < filtered.length; i++) removeFilter(filtered[i]); - }); - addEventHandler(window, "onafterprint", function() { - for (var i = 0; i < filtered.length; i++) addFilter(filtered[i]); - printing = false; - }); -} - -// apply a filter -function addFilter(element, sizingMethod, src) { - var filter = element.filters[ALPHA_IMAGE_LOADER]; - if (filter) { - filter.src = src || element.src; - filter.enabled = true; - } else { - element.runtimeStyle.filter = format(PNG_FILTER, src || element.src, sizingMethod || "scale"); - filtered.push(element); - } - // remove the real image - element.src = BLANK_GIF; -}; - -function removeFilter(element) { - element.src = element.pngSrc; - element.filters[ALPHA_IMAGE_LOADER].enabled = false; -}; - -// ========================================================================= -// ie7-fixed.js -// ========================================================================= - -(function() { - if (appVersion >= 7) return; - - // some things to consider for this hack. - // the document body requires a fixed background. even if - // it is just a blank image. - // you have to use setExpression instead of onscroll, this - // together with a fixed body background helps avoid the - // annoying screen flicker of other solutions. - - IE7.CSS.addRecalc("position", "fixed", _positionFixed, "absolute"); - IE7.CSS.addRecalc("background(-attachment)?", "[^};]*fixed", _backgroundFixed); - - // scrolling is relative to the documentElement (HTML tag) when in - // standards mode, otherwise it's relative to the document body - var $viewport = MSIE5 ? "body" : "documentElement"; - - function _fixBackground() { - // this is required by both position:fixed and background-attachment:fixed. - // it is necessary for the document to also have a fixed background image. - // we can fake this with a blank image if necessary - if (body.currentStyle.backgroundAttachment !== "fixed") { - if (body.currentStyle.backgroundImage === "none") { - body.runtimeStyle.backgroundRepeat = "no-repeat"; - body.runtimeStyle.backgroundImage = "url(" + BLANK_GIF + ")"; // dummy - } - body.runtimeStyle.backgroundAttachment = "fixed"; - } - _fixBackground = Undefined; - }; - - var _tmp = createTempElement("img"); - - function _isFixed(element) { - return element ? isFixed(element) || _isFixed(element.parentElement) : false; - }; - - function _setExpression(element, propertyName, expression) { - setTimeout("document.all." + element.uniqueID + ".runtimeStyle.setExpression('" + propertyName + "','" + expression + "')", 0); - }; - - // ----------------------------------------------------------------------- - // backgroundAttachment: fixed - // ----------------------------------------------------------------------- - - function _backgroundFixed(element) { - if (register(_backgroundFixed, element, element.currentStyle.backgroundAttachment === "fixed" && !element.contains(body))) { - _fixBackground(); - util.bgLeft(element); - util.bgTop(element); - _backgroundPosition(element); - } - }; - - function _backgroundPosition(element) { - _tmp.src = element.currentStyle.backgroundImage.slice(5, -2); - var parentElement = element.canHaveChildren ? element : element.parentElement; - parentElement.appendChild(_tmp); - util.setOffsetLeft(element); - util.setOffsetTop(element); - parentElement.removeChild(_tmp); - }; - - // ----------------------------------------------------------------------- - // position: fixed - // ----------------------------------------------------------------------- - - function _positionFixed(element) { - if (register(_positionFixed, element, isFixed(element))) { - setOverrideStyle(element, "position", "absolute"); - setOverrideStyle(element, "left", element.currentStyle.left); - setOverrideStyle(element, "top", element.currentStyle.top); - _fixBackground(); - IE7.Layout.fixRight(element); - //IE7.Layout.fixBottom(element); - _foregroundPosition(element); - } - }; - - function _foregroundPosition(element, recalc) { - document.body.getBoundingClientRect(); // force a reflow - util.positionTop(element, recalc); - util.positionLeft(element, recalc, true); - if (!element.runtimeStyle.autoLeft && element.currentStyle.marginLeft === "auto" && - element.currentStyle.right !== "auto") { - var left = viewport.clientWidth - util.getPixelWidth(element, element.currentStyle.right) - - util.getPixelWidth(element, element.runtimeStyle._left) - element.clientWidth; - if (element.currentStyle.marginRight === "auto") left = parseInt(left / 2); - if (_isFixed(element.offsetParent)) element.runtimeStyle.pixelLeft += left; - else element.runtimeStyle.shiftLeft = left; - } - if (!element.runtimeStyle.fixedWidth) util.clipWidth(element); - if (!element.runtimeStyle.fixedHeight) util.clipHeight(element); - }; - - // ----------------------------------------------------------------------- - // capture window resize - // ----------------------------------------------------------------------- - - function _resize() { - // if the window has been resized then some positions need to be - // recalculated (especially those aligned to "right" or "top" - var elements = _backgroundFixed.elements; - for (var i in elements) _backgroundPosition(elements[i]); - elements = _positionFixed.elements; - for (i in elements) { - _foregroundPosition(elements[i], true); - _foregroundPosition(elements[i], true); - } - _timer = 0; - }; - - // use a timer (sometimes this is a good way to prevent resize loops) - var _timer; - addResize(function() { - if (!_timer) _timer = setTimeout(_resize, 100); - }); - - // ----------------------------------------------------------------------- - // rotated - // ----------------------------------------------------------------------- - - var util = {}; - - var _horizontal = function(util) { - util.bgLeft = function(element) { - element.style.backgroundPositionX = element.currentStyle.backgroundPositionX; - if (!_isFixed(element)) { - _setExpression(element, "backgroundPositionX", "(parseInt(runtimeStyle.offsetLeft)+document." + $viewport + ".scrollLeft)||0"); - } - }; - - util.setOffsetLeft = function(element) { - var propertyName = _isFixed(element) ? "backgroundPositionX" : "offsetLeft"; - element.runtimeStyle[propertyName] = - util.getOffsetLeft(element, element.style.backgroundPositionX) - - element.getBoundingClientRect().left - element.clientLeft + 2; - }; - - util.getOffsetLeft = function(element, position) { - switch (position) { - case "left": - case "top": - return 0; - case "right": - case "bottom": - return viewport.clientWidth - _tmp.offsetWidth; - case "center": - return (viewport.clientWidth - _tmp.offsetWidth) / 2; - default: - if (PERCENT.test(position)) { - return parseInt((viewport.clientWidth - _tmp.offsetWidth) * parseFloat(position) / 100); - } - _tmp.style.left = position; - return _tmp.offsetLeft; - } - }; - - util.clipWidth = function(element) { - var fixWidth = element.runtimeStyle.fixWidth; - element.runtimeStyle.borderRightWidth = ""; - element.runtimeStyle.width = fixWidth ? util.getPixelWidth(element, fixWidth) + "px" : ""; - if (element.currentStyle.width !== "auto") { - var rect = element.getBoundingClientRect(); - var width = element.offsetWidth - viewport.clientWidth + rect.left - 2; - if (width >= 0) { - element.runtimeStyle.borderRightWidth = "0px"; - width = Math.max(getPixelValue(element, element.currentStyle.width) - width, 0); - setOverrideStyle(element, "width", width); - return width; - } - } - }; - - util.positionLeft = function(element, recalc) { - // if the element's width is in % units then it must be recalculated - // with respect to the viewport - if (!recalc && PERCENT.test(element.currentStyle.width)) { - element.runtimeStyle.fixWidth = element.currentStyle.width; - } - if (element.runtimeStyle.fixWidth) { - element.runtimeStyle.width = util.getPixelWidth(element, element.runtimeStyle.fixWidth); - } - //if (recalc) { - // // if the element is fixed on the right then no need to recalculate - // if (!element.runtimeStyle.autoLeft) return; - //} else { - element.runtimeStyle.shiftLeft = 0; - element.runtimeStyle._left = element.currentStyle.left; - // is the element fixed on the right? - element.runtimeStyle.autoLeft = element.currentStyle.right !== "auto" && element.currentStyle.left === "auto"; - //} - // reset the element's "left" value and get it's natural position - element.runtimeStyle.left = ""; - element.runtimeStyle.screenLeft = util.getScreenLeft(element); - element.runtimeStyle.pixelLeft = element.runtimeStyle.screenLeft; - // if the element is contained by another fixed element then there is no need to - // continually recalculate it's left position - if (!recalc && !_isFixed(element.offsetParent)) { - // onsrcoll produces jerky movement, so we use an expression - _setExpression(element, "pixelLeft", "runtimeStyle.screenLeft+runtimeStyle.shiftLeft+document." + $viewport + ".scrollLeft"); - } - }; - - // I've forgotten how this works... - util.getScreenLeft = function(element) { // thanks to kevin newman (captainn) - var screenLeft = element.offsetLeft, nested = 1; - if (element.runtimeStyle.autoLeft) { - screenLeft = viewport.clientWidth - element.offsetWidth - util.getPixelWidth(element, element.currentStyle.right); - } - // accommodate margins - if (element.currentStyle.marginLeft !== "auto") { - screenLeft -= util.getPixelWidth(element, element.currentStyle.marginLeft); - } - while (element = element.offsetParent) { - if (element.currentStyle.position !== "static") nested = -1; - screenLeft += element.offsetLeft * nested; - } - return screenLeft; - }; - - util.getPixelWidth = function(element, value) { - return PERCENT.test(value) ? parseInt(parseFloat(value) / 100 * viewport.clientWidth) : getPixelValue(element, value); - }; - }; - eval("var _vertical=" + rotate(_horizontal)); - _horizontal(util); - _vertical(util); -})(); - -// ========================================================================= -// ie7-oveflow.js -// ========================================================================= - -/* --------------------------------------------------------------------- - - This module alters the structure of the document. - It may adversely affect other CSS rules. Be warned. - ---------------------------------------------------------------------- */ - -if (appVersion < 7) { - var WRAPPER_STYLE = { - backgroundColor: "transparent", - backgroundImage: "none", - backgroundPositionX: null, - backgroundPositionY: null, - backgroundRepeat: null, - borderTopWidth: 0, - borderRightWidth: 0, - borderBottomWidth: 0, - borderLeftStyle: "none", - borderTopStyle: "none", - borderRightStyle: "none", - borderBottomStyle: "none", - borderLeftWidth: 0, - borderLeftColor: "#000", - borderTopColor: "#000", - borderRightColor: "#000", - borderBottomColor: "#000", - height: null, - marginTop: 0, - marginBottom: 0, - marginRight: 0, - marginLeft: 0, - width: "100%" - }; - - IE7.CSS.addRecalc("overflow", "visible", function(element) { - if (element.currentStyle.position === "absolute") return; - - // don't do this again - if (element.parentNode.ie7_wrapped) return; - - // if max-height is applied, makes sure it gets applied first - if (IE7.Layout && element.currentStyle["max-height"] !== "auto") { - IE7.Layout.maxHeight(element); - } - - if (element.currentStyle.marginLeft === "auto") element.style.marginLeft = 0; - if (element.currentStyle.marginRight === "auto") element.style.marginRight = 0; - - var wrapper = document.createElement(ANON); - wrapper.ie7_wrapped = element; - for (var propertyName in WRAPPER_STYLE) { - wrapper.style[propertyName] = element.currentStyle[propertyName]; - if (WRAPPER_STYLE[propertyName] != null) { - element.runtimeStyle[propertyName] = WRAPPER_STYLE[propertyName]; - } - } - wrapper.style.display = "block"; - wrapper.style.position = "relative"; - element.runtimeStyle.position = "absolute"; - element.parentNode.insertBefore(wrapper, element); - wrapper.appendChild(element); - }); -} - -// ========================================================================= -// ie7-quirks.js -// ========================================================================= - -function ie7Quirks() { - var FONT_SIZES = "xx-small,x-small,small,medium,large,x-large,xx-large".split(","); - for (var i = 0; i < FONT_SIZES.length; i++) { - FONT_SIZES[FONT_SIZES[i]] = FONT_SIZES[i - 1] || "0.67em"; - } - - IE7.CSS.addFix(/(font(-size)?\s*:\s*)([\w.-]+)/, function(match, label, size, value) { - return label + (FONT_SIZES[value] || value); - }); - - var NEGATIVE = /^\-/, LENGTH = /(em|ex)$/i; - var EM = /em$/i, EX = /ex$/i; - - getPixelValue = function(element, value) { - if (PIXEL.test(value)) return parseInt(value)||0; - var scale = NEGATIVE.test(value)? -1 : 1; - if (LENGTH.test(value)) scale *= getFontScale(element); - temp.style.width = scale < 0 ? value.slice(1) : value; - body.appendChild(temp); - // retrieve pixel width - value = scale * temp.offsetWidth; - // remove the temporary element - temp.removeNode(); - return parseInt(value); - }; - - var temp = createTempElement(); - function getFontScale(element) { - var scale = 1; - temp.style.fontFamily = element.currentStyle.fontFamily; - temp.style.lineHeight = element.currentStyle.lineHeight; - //temp.style.fontSize = ""; - while (element != body) { - var fontSize = element.currentStyle["ie7-font-size"]; - if (fontSize) { - if (EM.test(fontSize)) scale *= parseFloat(fontSize); - else if (PERCENT.test(fontSize)) scale *= (parseFloat(fontSize) / 100); - else if (EX.test(fontSize)) scale *= (parseFloat(fontSize) / 2); - else { - temp.style.fontSize = fontSize; - return 1; - } - } - element = element.parentElement; - } - return scale; - }; - - // cursor:pointer (IE5.x) - IE7.CSS.addFix(/cursor\s*:\s*pointer/, "cursor:hand"); - // display:list-item (IE5.x) - IE7.CSS.addFix(/display\s*:\s*list-item/, "display:block"); - - // ----------------------------------------------------------------------- - // margin:auto - // ----------------------------------------------------------------------- - - function fixMargin(element) { - var parent = element.parentElement; - var margin = parent.offsetWidth - element.offsetWidth - getPaddingWidth(parent); - var autoRight = (element.currentStyle["ie7-margin"] && element.currentStyle.marginRight === "auto") || - element.currentStyle["ie7-margin-right"] === "auto"; - switch (parent.currentStyle.textAlign) { - case "right": - margin = autoRight ? parseInt(margin / 2) : 0; - element.runtimeStyle.marginRight = margin + "px"; - break; - case "center": - if (autoRight) margin = 0; - default: - if (autoRight) margin /= 2; - element.runtimeStyle.marginLeft = parseInt(margin) + "px"; - } - }; - - function getPaddingWidth(element) { - return getPixelValue(element, element.currentStyle.paddingLeft) + - getPixelValue(element, element.currentStyle.paddingRight); - }; - - IE7.CSS.addRecalc("margin(-left|-right)?", "[^};]*auto", function(element) { - if (register(fixMargin, element, - element.parentElement && - element.currentStyle.display === "block" && - element.currentStyle.marginLeft === "auto" && - element.currentStyle.position !== "absolute")) { - fixMargin(element); - } - }); - - addResize(function() { - for (var i in fixMargin.elements) { - var element = fixMargin.elements[i]; - element.runtimeStyle.marginLeft = - element.runtimeStyle.marginRight = ""; - fixMargin(element); - } - }); -}; - - -var MATCHER; - -var cssQuery = (function() { - var CONTEXT = /^[>+~]/; - - var useContext = false; - - // This is not a selector engine in the strictest sense. So it's best to silently error. - function cssQuery(selector, context, single) { - selector = trim(selector); - if (!context) context = document; - var ref = context; - useContext = CONTEXT.test(selector); - if (useContext) { - context = context.parentNode; - selector = "*" + selector; - } - try { - return selectQuery.create(selector, useContext)(context, single ? null : [], ref); - } catch (ex) { - return single ? null : []; - } - }; - - var VALID_SELECTOR = /^(\\.|[' >+~#.\[\]:*(),\w-\^|$=]|[^\x00-\xa0])+$/; - - var _EVALUATED = /^(href|src)$/; - var _ATTRIBUTES = { - "class": "className", - "for": "htmlFor" - }; - - var IE7_CLASS_NAMES = /\sie7_\w+/g; - - var USE_IFLAG = /^(action|cite|codebase|data|dynsrc|href|longdesc|lowsrc|src|usemap|url)$/i; - - IE7._getAttribute = function(element, name) { - if (element.getAttributeNode) { - var attribute = element.getAttributeNode(name); - } - name = _ATTRIBUTES[name.toLowerCase()] || name; - if (!attribute) attribute = element.attributes[name]; - var specified = attribute && attribute.specified; - - if (element[name] && typeof element[name] == "boolean") return name.toLowerCase(); - if ((specified && USE_IFLAG.test(name)) || (!attribute && MSIE5) || name === "value" || name === "type") { - return element.getAttribute(name, 2); - } - if (name === "style") return element.style.cssText.toLowerCase() || null; - - return specified ? String(attribute.nodeValue) : null; - }; - - var names = "colSpan,rowSpan,vAlign,dateTime,accessKey,tabIndex,encType,maxLength,readOnly,longDesc"; - // Convert the list of strings to a hash, mapping the lowercase name to the camelCase name. - extend(_ATTRIBUTES, combine(names.toLowerCase().split(","), names.split(","))); - - IE7._getElementSibling = function(node, direction) { - direction += "Sibling"; - do { - node = node[direction]; - if (node && node.nodeName > "@") break; - } while (node); - return node; - }; - - var IMPLIED_ASTERISK = /(^|[, >+~])([#.:\[])/g, - BLOCKS = /\)\{/g, - COMMA = /,/, - QUOTED = /^['"]/, - HEX_ESCAPE = /\\([\da-f]{2,2})/gi, - LAST_CHILD = /last/i; - - IE7._byId = function(document, id) { - var result = document.all[id] || null; - // Returns a single element or a collection. - if (!result || (result.nodeType && IE7._getAttribute(result, "id") === id)) return result; - // document.all has returned a collection of elements with name/id - for (var i = 0; i < result.length; i++) { - if (IE7._getAttribute(result[i], "id") === id) return result[i]; - } - return null; - }; - - // ========================================================================= - // dom/selectors-api/CSSSelectorParser.js - // ========================================================================= - - // http://www.w3.org/TR/css3-selectors/#w3cselgrammar (kinda) - var CSSSelectorParser = RegGrp.extend({ - dictionary: new Dictionary({ - ident: /\-?(\\.|[_a-z]|[^\x00-\xa0])(\\.|[\w-]|[^\x00-\xa0])*/, - combinator: /[\s>+~]/, - operator: /[\^~|$*]?=/, - nth_arg: /[+-]?\d+|[+-]?\d*n(?:\s*[+-]\s*\d+)?|even|odd/, - tag: /\*|<#ident>/, - id: /#(<#ident>)/, - 'class': /\.(<#ident>)/, - pseudo: /\:([\w-]+)(?:\(([^)]+)\))?/, - attr: /\[(<#ident>)(?:(<#operator>)((?:\\.|[^\[\]#.:])+))?\]/, - negation: /:not\((<#tag>|<#id>|<#class>|<#attr>|<#pseudo>)\)/, - sequence: /(\\.|[~*]=|\+\d|\+?\d*n\s*\+\s*\d|[^\s>+~,\*])+/, - filter: /[#.:\[]<#sequence>/, - selector: /[^>+~](\\.|[^,])*?/, - grammar: /^(<#selector>)((,<#selector>)*)$/ - }), - - ignoreCase: true - }); - - var normalizer = new CSSSelectorParser({ - "\\\\.|[~*]\\s+=|\\+\\s+\\d": RegGrp.IGNORE, - "\\[\\s+": "[", - "\\(\\s+": "(", - "\\s+\\)": ")", - "\\s+\\]": "]", - "\\s*([,>+~]|<#operator>)\\s*": "$1", - "\\s+$": "", - "\\s+": " " - }); - - function normalize(selector) { - selector = normalizer.parse(selector.replace(HEX_ESCAPE, "\\x$1")) - .replace(UNESCAPE, "$1") - .replace(IMPLIED_ASTERISK, "$1*$2"); - if (!VALID_SELECTOR.test(selector)) throwSelectorError(); - return selector; - }; - - function unescape(query) { - // put string values back - return query.replace(ESCAPED, unescapeString); - }; - - function unescapeString(match, index) { - return strings[index]; - }; - - var BRACES = /\{/g, BRACES_ESCAPED = /\\{/g; - - function closeBlock(group) { - return Array((group.replace(BRACES_ESCAPED, "").match(BRACES) || "").length + 1).join("}"); - }; - - FILTER = new CSSSelectorParser(FILTER); - - var TARGET = /:target/i, ROOT = /:root/i; - - function getConstants(selector) { - var constants = ""; - if (ROOT.test(selector)) constants += ",R=d.documentElement"; - if (TARGET.test(selector)) constants += ",H=d.location;H=H&&H.hash.replace('#','')"; - if (constants || selector.indexOf("#") !== -1) { - constants = ",t=c.nodeType,d=t===9?c:c.ownerDocument||(c.document||c).parentWindow.document" + constants; - } - return "var ii" + constants + ";"; - }; - - var COMBINATOR = { - " ": ";while(e!=s&&(e=e.parentNode)&&e.nodeType===1){", - ">": ".parentElement;if(e){", - "+": ";while((e=e.previousSibling)&&!(" + IS_ELEMENT + "))continue;if(e){", - "~": ";while((e=e.previousSibling)){" + IF_ELEMENT - }; - - var TOKEN = /\be\b/g; - - MATCHER = new CSSSelectorParser({ - "(?:(<#selector>)(<#combinator>))?(<#tag>)(<#filter>)?$": function(match, before, combinator, tag, filters) { - var group = ""; - if (tag !== "*") { - var TAG = tag.toUpperCase(); - group += "if(e.nodeName==='" + TAG + (TAG === tag ? "" : "'||e.nodeName==='" + tag) + "'){"; - } - if (filters) { - group += "if(" + FILTER.parse(filters).slice(0, -2) + "){"; - } - group = group.replace(TOKEN, "e" + this.index); - if (combinator) { - group += "var e=e" + (this.index++) + COMBINATOR[combinator]; - group = group.replace(TOKEN, "e" + this.index); - } - if (before) { - group += this.parse(before); - } - return group; - } - }); - - var BY_ID = "e0=IE7._byId(d,'%1');if(e0){", - BY_TAG_NAME = "var n=c.getElementsByTagName('%1');", - STORE = "if(r==null)return e0;r[k++]=e0;"; - - var TAG_NAME = 1; - - var SELECTOR = new CSSSelectorParser({ - "^((?:<#selector>)?(?:<#combinator>))(<#tag>)(<#filter>)?$": true - }); - - var cache = {}; - - var selectById = new CSSSelectorParser({ - "^(<#tag>)#(<#ident>)(<#filter>)?( [^,]*)?$": function(match, tagName, id, filters, after) { - var block = format(BY_ID, id), endBlock = "}"; - if (filters) { - block += MATCHER.parse(tagName + filters); - endBlock = closeBlock(block); - } - if (after) { - block += "s=c=e0;" + selectQuery.parse("*" + after); - } else { - block += STORE; - } - return block + endBlock; - }, - - "^([^#,]+)#(<#ident>)(<#filter>)?$": function(match, before, id, filters) { - var block = format(BY_ID, id); - if (before === "*") { - block += STORE; - } else { - block += MATCHER.parse(before + filters) + STORE + "break"; - } - return block + closeBlock(block); - }, - - "^.*$": "" - }); - - var selectQuery = new CSSSelectorParser({ - "<#grammar>": function(match, selector, remainingSelectors) { - if (!this.groups) this.groups = []; - - var group = SELECTOR.exec(" " + selector); - - if (!group) throwSelectorError(); - - this.groups.push(group.slice(1)); - - if (remainingSelectors) { - return this.parse(remainingSelectors.replace(COMMA, "")); - } - - var groups = this.groups, - tagName = groups[0][TAG_NAME]; // first tag name - - for (var i = 1; group = groups[i]; i++) { // search tag names - if (tagName !== group[TAG_NAME]) { - tagName = "*"; // mixed tag names, so use "*" - break; - } - } - - var matcher = "", store = STORE + "continue filtering;"; - - for (var i = 0; group = groups[i]; i++) { - MATCHER.index = 0; - if (tagName !== "*") group[TAG_NAME] = "*"; // we are already filtering by tagName - group = group.join(""); - if (group === " *") { // select all - matcher = store; - break; - } else { - group = MATCHER.parse(group); - if (useContext) group += "if(e" + MATCHER.index + "==s){"; - matcher += group + store + closeBlock(group); - } - } - - // reduce to a single loop - var isWild = tagName === "*"; - return (isWild ? "var n=c.all;" : format(BY_TAG_NAME, tagName)) + - "filtering:while((e0=n[i++]))" + - (isWild ? IF_ELEMENT.replace(TOKEN, "e0") : "{") + - matcher + - "}"; - }, - - "^.*$": throwSelectorError - }); - - var REDUNDANT_NODETYPE_CHECKS = /\&\&(e\d+)\.nodeType===1(\)\{\s*if\(\1\.nodeName=)/g; - - selectQuery.create = function(selector) { - if (!cache[selector]) { - selector = normalize(selector); - this.groups = null; - MATCHER.index = 0; - var block = this.parse(selector); - this.groups = null; - MATCHER.index = 0; - if (selector.indexOf("#") !== -1) { - var byId = selectById.parse(selector); - if (byId) { - block = - "if(t===1||t===11|!c.getElementById){" + - block + - "}else{" + - byId + - "}"; - } - } - // remove redundant nodeType==1 checks - block = block.replace(REDUNDANT_NODETYPE_CHECKS, "$2"); - block = getConstants(selector) + decode(block); - cache[selector] = new Function("return function(c,r,s){var i=0,k=0,e0;" + block + "return r}")(); - } - return cache[selector]; - }; - - return cssQuery; -})(); - -function throwSelectorError() { - throw new SyntaxError("Invalid selector."); -}; - -// ----------------------------------------------------------------------- -// initialisation -// ----------------------------------------------------------------------- - -IE7.loaded = true; - -(function() { - try { - // http://javascript.nwbox.com/IEContentLoaded/ - if (!document.body) throw "continue"; - documentElement.doScroll("left"); - } catch (ex) { - setTimeout(arguments.callee, 1); - return; - } - // execute the inner text of the IE7 script - try { - eval(script.innerHTML); - } catch (ex) { - // ignore errors - } - if (typeof IE7_PNG_SUFFIX == "object") { - PNG = IE7_PNG_SUFFIX; - } else { - PNG = new RegExp(rescape(window.IE7_PNG_SUFFIX || "-trans.png") + "(\\?.*)?$", "i"); - } - - // frequently used references - body = document.body; - viewport = MSIE5 ? body : documentElement; - - // classes - body.className += " ie7_body"; - documentElement.className += " ie7_html"; - - if (MSIE5) ie7Quirks(); - - IE7.CSS.init(); - IE7.HTML.init(); - - IE7.HTML.apply(); - IE7.CSS.apply(); - - IE7.recalc(); -})(); - -})(this, document); - +/* + IE7/IE8/IE9.js - copyright 2004-2010, Dean Edwards + http://code.google.com/p/ie7-js/ + http://www.opensource.org/licenses/mit-license.php +*/ + +/* W3C compliance for Microsoft Internet Explorer */ + +/* credits/thanks: + Shaggy, Martijn Wargers, Jimmy Cerra, Mark D Anderson, + Lars Dieckow, Erik Arvidsson, Gellert Gyuris, James Denny, + Unknown W Brackets, Benjamin Westfarer, Rob Eberhardt, + Bill Edney, Kevin Newman, James Crompton, Matthew Mastracci, + Doug Wright, Richard York, Kenneth Kolano, MegaZone, + Thomas Verelst, Mark 'Tarquin' Wilton-Jones, Rainer Åhlfors, + David Zulaica, Ken Kolano, Kevin Newman, Sjoerd Visscher, + Ingo Chao +*/ + +// timestamp: Fri, 30 Apr 2010 20:59:18 + +(function(window, document) { + +var IE7 = window.IE7 = { + version: "2.1(beta4)", + toString: K("[IE7]") +}; +IE7.compat = 7; +var appVersion = IE7.appVersion = navigator.appVersion.match(/MSIE (\d\.\d)/)[1] - 0; + +if (/ie7_off/.test(top.location.search) || appVersion < 5.5 || appVersion >= IE7.compat) return; + +var MSIE5 = appVersion < 6; + +var Undefined = K(); +var documentElement = document.documentElement, body, viewport; +var ANON = "!"; +var HEADER = ":link{ie7-link:link}:visited{ie7-link:visited}"; + +// ----------------------------------------------------------------------- +// external +// ----------------------------------------------------------------------- + +var RELATIVE = /^[\w\.]+[^:]*$/; +function makePath(href, path) { + if (RELATIVE.test(href)) href = (path || "") + href; + return href; +}; + +function getPath(href, path) { + href = makePath(href, path); + return href.slice(0, href.lastIndexOf("/") + 1); +}; + +// Get the path to this script +var script = document.scripts[document.scripts.length - 1]; +var path = getPath(script.src); + +// Use microsoft's http request object to load external files +try { + var httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); +} catch (ex) { + // ActiveX disabled +} + +var fileCache = {}; +function loadFile(href, path) { + try { + href = makePath(href, path); + if (!fileCache[href]) { + httpRequest.open("GET", href, false); + httpRequest.send(); + if (httpRequest.status == 0 || httpRequest.status == 200) { + fileCache[href] = httpRequest.responseText; + } + } + } catch (ex) { + // ignore errors + } + return fileCache[href] || ""; +}; + +// ----------------------------------------------------------------------- +// OO support +// ----------------------------------------------------------------------- + + +// This is a cut-down version of base2 (http://code.google.com/p/base2/) + +var _slice = Array.prototype.slice; + +// private +var _FORMAT = /%([1-9])/g; +var _LTRIM = /^\s\s*/; +var _RTRIM = /\s\s*$/; +var _RESCAPE = /([\/()[\]{}|*+-.,^$?\\])/g; // safe regular expressions +var _BASE = /\bbase\b/; +var _HIDDEN = ["constructor", "toString"]; // only override these when prototyping + +var prototyping; + +function Base(){}; +Base.extend = function(_instance, _static) { + // Build the prototype. + prototyping = true; + var _prototype = new this; + extend(_prototype, _instance); + prototyping = false; + + // Create the wrapper for the constructor function. + var _constructor = _prototype.constructor; + function klass() { + // Don't call the constructor function when prototyping. + if (!prototyping) _constructor.apply(this, arguments); + }; + _prototype.constructor = klass; + + // Build the static interface. + klass.extend = arguments.callee; + extend(klass, _static); + klass.prototype = _prototype; + return klass; +}; +Base.prototype.extend = function(source) { + return extend(this, source); +}; + + +// A collection of regular expressions and their associated replacement values. +// A Base class for creating parsers. + +var HASH = "#"; +var ITEMS = "#"; +var KEYS = "."; +var COMPILED = "/"; + +var REGGRP_BACK_REF = /\\(\d+)/g, + REGGRP_ESCAPE_COUNT = /\[(\\.|[^\]\\])+\]|\\.|\(\?/g, + REGGRP_PAREN = /\(/g, + REGGRP_LOOKUP = /\$(\d+)/, + REGGRP_LOOKUP_SIMPLE = /^\$\d+$/, + REGGRP_LOOKUPS = /(\[(\\.|[^\]\\])+\]|\\.|\(\?)|\(/g, + REGGRP_DICT_ENTRY = /^<#\w+>$/, + REGGRP_DICT_ENTRIES = /<#(\w+)>/g; + +var RegGrp = Base.extend({ + constructor: function(values) { + this[KEYS] = []; + this[ITEMS] = {}; + this.merge(values); + }, + + //dictionary: null, + //ignoreCase: false, + + add: function(expression, replacement) { + delete this[COMPILED]; + if (expression instanceof RegExp) { + expression = expression.source; + } + if (!this[HASH + expression]) this[KEYS].push(String(expression)); + return this[ITEMS][HASH + expression] = new RegGrp.Item(expression, replacement, this); + }, + + compile: function(recompile) { + if (recompile || !this[COMPILED]) { + this[COMPILED] = new RegExp(this, this.ignoreCase ? "gi" : "g"); + } + return this[COMPILED]; + }, + + merge: function(values) { + for (var i in values) this.add(i, values[i]); + }, + + exec: function(string) { + var group = this, + patterns = group[KEYS], + items = group[ITEMS], item; + var result = this.compile(true).exec(string); + if (result) { + // Loop through the RegGrp items. + var i = 0, offset = 1; + while ((item = items[HASH + patterns[i++]])) { + var next = offset + item.length + 1; + if (result[offset]) { // do we have a result? + if (item.replacement === 0) { + return group.exec(string); + } else { + var args = result.slice(offset, next), j = args.length; + while (--j) args[j] = args[j] || ""; // some platforms return null/undefined for non-matching sub-expressions + args[0] = {match: args[0], item: item}; + return args; + } + } + offset = next; + } + } + return null; + }, + + parse: function(string) { + string += ""; // type safe + var group = this, + patterns = group[KEYS], + items = group[ITEMS]; + return string.replace(this.compile(), function(match) { + var args = [], item, offset = 1, i = arguments.length; + while (--i) args[i] = arguments[i] || ""; // some platforms return null/undefined for non-matching sub-expressions + // Loop through the RegGrp items. + while ((item = items[HASH + patterns[i++]])) { + var next = offset + item.length + 1; + if (args[offset]) { // do we have a result? + var replacement = item.replacement; + switch (typeof replacement) { + case "function": + return replacement.apply(group, args.slice(offset, next)); + case "number": + return args[offset + replacement]; + default: + return replacement; + } + } + offset = next; + } + return match; + }); + }, + + toString: function() { + var strings = [], + keys = this[KEYS], + items = this[ITEMS], item; + for (var i = 0; item = items[HASH + keys[i]]; i++) { + strings[i] = item.source; + } + return "(" + strings.join(")|(") + ")"; + } +}, { + IGNORE: null, // a null replacement value means that there is no replacement. + + Item: Base.extend({ + constructor: function(source, replacement, owner) { + var length = source.indexOf("(") === -1 ? 0 : RegGrp.count(source); + + var dictionary = owner.dictionary; + if (dictionary && source.indexOf("<#") !== -1) { + if (REGGRP_DICT_ENTRY.test(source)) { + var entry = dictionary[ITEMS][HASH + source.slice(2, -1)]; + source = entry.replacement; + length = entry._length; + } else { + source = dictionary.parse(source); + } + } + + if (typeof replacement == "number") replacement = String(replacement); + else if (replacement == null) replacement = 0; + + // Does the expression use sub-expression lookups? + if (typeof replacement == "string" && REGGRP_LOOKUP.test(replacement)) { + if (REGGRP_LOOKUP_SIMPLE.test(replacement)) { // A simple lookup? (e.g. "$2"). + // Store the index (used for fast retrieval of matched strings). + var index = replacement.slice(1) - 0; + if (index && index <= length) replacement = index; + } else { + // A complicated lookup (e.g. "Hello $2 $1."). + var lookup = replacement, regexp; + replacement = function(match) { + if (!regexp) { + regexp = new RegExp(source, "g" + (this.ignoreCase ? "i": "")); + } + return match.replace(regexp, lookup); + }; + } + } + + this.length = length; + this.source = String(source); + this.replacement = replacement; + } + }), + + count: function(expression) { + return (String(expression).replace(REGGRP_ESCAPE_COUNT, "").match(REGGRP_PAREN) || "").length; + } +}); + +var Dictionary = RegGrp.extend({ + parse: function(phrase) { + // Prevent sub-expressions in dictionary entries from capturing. + var entries = this[ITEMS]; + return phrase.replace(REGGRP_DICT_ENTRIES, function(match, entry) { + entry = entries[HASH + entry]; + return entry ? entry._nonCapturing : match; + }); + }, + + add: function(expression, replacement) { + // Get the underlying replacement value. + if (replacement instanceof RegExp) { + replacement = replacement.source; + } + // Translate the replacement. + // The result is the original replacement recursively parsed by this dictionary. + var nonCapturing = replacement.replace(REGGRP_LOOKUPS, _nonCapture); + if (replacement.indexOf("(") !== -1) { + var realLength = RegGrp.count(replacement); + } + if (replacement.indexOf("<#") !== -1) { + replacement = this.parse(replacement); + nonCapturing = this.parse(nonCapturing); + } + var item = this.base(expression, replacement); + item._nonCapturing = nonCapturing; + item._length = realLength || item.length; // underlying number of sub-groups + return item; + }, + + toString: function() { + return "(<#" + this[PATTERNS].join(">)|(<#") + ">)"; + } +}); + +function _nonCapture(match, escaped) { + return escaped || "(?:"; // non-capturing +}; + +// ========================================================================= +// lang/extend.js +// ========================================================================= + +function extend(object, source) { // or extend(object, key, value) + if (object && source) { + var proto = (typeof source == "function" ? Function : Object).prototype; + // Add constructor, toString etc + var i = _HIDDEN.length, key; + if (prototyping) while (key = _HIDDEN[--i]) { + var value = source[key]; + if (value != proto[key]) { + if (_BASE.test(value)) { + _override(object, key, value) + } else { + object[key] = value; + } + } + } + // Copy each of the source object's properties to the target object. + for (key in source) if (typeof proto[key] == "undefined") { + var value = source[key]; + // Check for method overriding. + if (object[key] && typeof value == "function" && _BASE.test(value)) { + _override(object, key, value); + } else { + object[key] = value; + } + } + } + return object; +}; + +function _override(object, name, method) { + // Override an existing method. + var ancestor = object[name]; + object[name] = function() { + var previous = this.base; + this.base = ancestor; + var returnValue = method.apply(this, arguments); + this.base = previous; + return returnValue; + }; +}; + +function combine(keys, values) { + // Combine two arrays to make a hash. + if (!values) values = keys; + var hash = {}; + for (var i in keys) hash[i] = values[i]; + return hash; +}; + +function format(string) { + // Replace %n with arguments[n]. + // e.g. format("%1 %2%3 %2a %1%3", "she", "se", "lls"); + // ==> "she sells sea shells" + // Only %1 - %9 supported. + var args = arguments; + var _FORMAT = new RegExp("%([1-" + arguments.length + "])", "g"); + return String(string).replace(_FORMAT, function(match, index) { + return index < args.length ? args[index] : match; + }); +}; + +function match(string, expression) { + // Same as String.match() except that this function will return an empty + // array if there is no match. + return String(string).match(expression) || []; +}; + +function rescape(string) { + // Make a string safe for creating a RegExp. + return String(string).replace(_RESCAPE, "\\$1"); +}; + +// http://blog.stevenlevithan.com/archives/faster-trim-javascript +function trim(string) { + return String(string).replace(_LTRIM, "").replace(_RTRIM, ""); +}; + +function K(k) { + return function() { + return k; + }; +}; + +// ----------------------------------------------------------------------- +// parsing +// ----------------------------------------------------------------------- + +var Parser = RegGrp.extend({ignoreCase: true}); + +var SINGLE_QUOTES = /'/g, + ESCAPED = /'(\d+)'/g, + ESCAPE = /\\/g, + UNESCAPE = /\\([nrtf'"])/g; + +var strings = []; + +var encoder = new Parser({ + // comments + "": "", + "\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\/": "", + // get rid + "@(namespace|import)[^;\\n]+[;\\n]": "", + // strings + "'(\\\\.|[^'\\\\])*'": encodeString, + '"(\\\\.|[^"\\\\])*"': encodeString, + // white space + "\\s+": " " +}); + +function encode(selector) { + return encoder.parse(selector).replace(UNESCAPE, "$1"); +}; + +function decode(query) { + // put string values back + return query.replace(ESCAPED, decodeString); +}; + +function encodeString(string) { + var index = strings.length; + strings[index] = string.slice(1, -1) + .replace(UNESCAPE, "$1") + .replace(SINGLE_QUOTES, "\\'"); + return "'" + index + "'"; +}; + +function decodeString(match, index) { + var string = strings[index]; + if (string == null) return match; + return "'" + strings[index] + "'"; +}; + +function getString(value) { + return value.indexOf("'") === 0 ? strings[value.slice(1, - 1)] : value; +}; + +// clone a "width" function to create a "height" function +var rotater = new RegGrp({ + Width: "Height", + width: "height", + Left: "Top", + left: "top", + Right: "Bottom", + right: "bottom", + onX: "onY" +}); + +function rotate(fn) { + return rotater.parse(fn); +}; + +// ----------------------------------------------------------------------- +// event handling +// ----------------------------------------------------------------------- + +var eventHandlers = []; + +function addResize(handler) { + addRecalc(handler); + addEventHandler(window, "onresize", handler); +}; + +// add an event handler (function) to an element +function addEventHandler(element, type, handler) { + element.attachEvent(type, handler); + // store the handler so it can be detached later + eventHandlers.push(arguments); +}; + +// remove an event handler assigned to an element by IE7 +function removeEventHandler(element, type, handler) { + try { + element.detachEvent(type, handler); + } catch (ex) { + // write a letter of complaint to microsoft.. + } +}; + +// remove event handlers (they eat memory) +addEventHandler(window, "onunload", function() { + var handler; + while (handler = eventHandlers.pop()) { + removeEventHandler(handler[0], handler[1], handler[2]); + } +}); + +function register(handler, element, condition) { // -@DRE + //var set = handler[element.uniqueID]; + if (!handler.elements) handler.elements = {}; + if (condition) handler.elements[element.uniqueID] = element; + else delete handler.elements[element.uniqueID]; + //return !set && condition; + return condition; +}; + +addEventHandler(window, "onbeforeprint", function() { + if (!IE7.CSS.print) new StyleSheet("print"); + IE7.CSS.print.recalc(); +}); + +// ----------------------------------------------------------------------- +// pixel conversion +// ----------------------------------------------------------------------- + +// this is handy because it means that web developers can mix and match +// measurement units in their style sheets. it is not uncommon to +// express something like padding in "em" units whilst border thickness +// is most often expressed in pixels. + +var PIXEL = /^\d+(px)?$/i; +var PERCENT = /^\d+%$/; +var getPixelValue = function(element, value) { + if (PIXEL.test(value)) return parseInt(value); + var style = element.style.left; + var runtimeStyle = element.runtimeStyle.left; + element.runtimeStyle.left = element.currentStyle.left; + element.style.left = value || 0; + value = element.style.pixelLeft; + element.style.left = style; + element.runtimeStyle.left = runtimeStyle; + return value; +}; + +// ----------------------------------------------------------------------- +// generic +// ----------------------------------------------------------------------- + +var $IE7 = "ie7-"; + +var Fix = Base.extend({ + constructor: function() { + this.fixes = []; + this.recalcs = []; + }, + init: Undefined +}); + +// a store for functions that will be called when refreshing IE7 +var recalcs = []; +function addRecalc(recalc) { + recalcs.push(recalc); +}; + +IE7.recalc = function() { + IE7.HTML.recalc(); + // re-apply style sheet rules (re-calculate ie7 classes) + IE7.CSS.recalc(); + // apply global fixes to the document + for (var i = 0; i < recalcs.length; i++) recalcs[i](); +}; + +function isFixed(element) { + return element.currentStyle["ie7-position"] == "fixed"; +}; + +// original style +function getDefinedStyle(element, propertyName) { + return element.currentStyle[$IE7 + propertyName] || element.currentStyle[propertyName]; +}; + +function setOverrideStyle(element, propertyName, value) { + if (element.currentStyle[$IE7 + propertyName] == null) { + element.runtimeStyle[$IE7 + propertyName] = element.currentStyle[propertyName]; + } + element.runtimeStyle[propertyName] = value; +}; + +// Create a temporary element which is used to inherit styles +// from the target element. +function createTempElement(tagName) { + var element = document.createElement(tagName || "object"); + element.style.cssText = "position:absolute;padding:0;display:block;border:none;clip:rect(0 0 0 0);left:-9999"; + element.ie7_anon = true; + return element; +}; + + +// ========================================================================= +// ie7-css.js +// ========================================================================= + +var NEXT_SIBLING = "(e.nextSibling&&IE7._getElementSibling(e,'next'))", + PREVIOUS_SIBLING = NEXT_SIBLING.replace(/next/g, "previous"), + IS_ELEMENT = "e.nodeName>'@'", + IF_ELEMENT = "if(" + IS_ELEMENT + "){"; + +var ID_ATTRIBUTE = "(e.nodeName==='FORM'?IE7._getAttribute(e,'id'):e.id)"; + +var HYPERLINK = /a(#[\w-]+)?(\.[\w-]+)?:(hover|active)/i; +var FIRST_LINE_LETTER = /(.*)(:first-(line|letter))/; +var SPACE = /\s/; +var RULE = /((?:\\.|[^{\\])+)\{((?:\\.|[^}\\])+)\}/g; +var SELECTOR = /(?:\\.|[^,\\])+/g; + +var styleSheets = document.styleSheets; + +var inheritedProperties = []; + +IE7.CSS = new (Fix.extend({ // single instance + parser: new Parser, + screen: "", + print: "", + styles: [], + rules: [], + pseudoClasses: appVersion < 7 ? "first\\-child" : "", + dynamicPseudoClasses: { + toString: function() { + var strings = []; + for (var pseudoClass in this) strings.push(pseudoClass); + return strings.join("|"); + } + }, + + init: function() { + var NONE = "^\x01$"; + var CLASS = "\\[class=?[^\\]]*\\]"; + var pseudoClasses = []; + if (this.pseudoClasses) pseudoClasses.push(this.pseudoClasses); + var dynamicPseudoClasses = this.dynamicPseudoClasses.toString(); + if (dynamicPseudoClasses) pseudoClasses.push(dynamicPseudoClasses); + pseudoClasses = pseudoClasses.join("|"); + var unknown = appVersion < 7 ? ["[>+~\\[(]|([:.])[\\w-]+\\1"] : [CLASS]; + if (pseudoClasses) unknown.push(":(" + pseudoClasses + ")"); + this.UNKNOWN = new RegExp(unknown.join("|") || NONE, "i"); + var complex = appVersion < 7 ? ["\\[[^\\]]+\\]|[^\\s(\\[]+\\s*[+~]"] : [CLASS]; + var complexRule = complex.concat(); + if (pseudoClasses) complexRule.push(":(" + pseudoClasses + ")"); + Rule.COMPLEX = new RegExp(complexRule.join("|") || NONE, "ig"); + if (this.pseudoClasses) complex.push(":(" + this.pseudoClasses + ")"); + DynamicRule.COMPLEX = new RegExp(complex.join("|") || NONE, "i"); + dynamicPseudoClasses = "not\\(:" + dynamicPseudoClasses.split("|").join("\\)|not\\(:") + "\\)|" + dynamicPseudoClasses; + DynamicRule.MATCH = new RegExp(dynamicPseudoClasses ? "(.*?):(" + dynamicPseudoClasses + ")(.*)" : NONE, "i"); + + this.createStyleSheet(); + this.refresh(); + }, + + addEventHandler: function() { + addEventHandler.apply(null, arguments); + }, + + addFix: function(expression, replacement) { + this.parser.add(expression, replacement); + }, + + addRecalc: function(propertyName, test, handler, replacement) { + // recalcs occur whenever the document is refreshed using document.recalc() + propertyName = propertyName.source || propertyName; + test = new RegExp("([{;\\s])" + propertyName + "\\s*:\\s*" + test + "[^;}]*"); + var id = this.recalcs.length; + if (typeof replacement == "string") replacement = propertyName + ":" + replacement; + this.addFix(test, function(match) { + if (typeof replacement == "function") replacement = replacement(match); + return (replacement ? replacement : match) + ";ie7-" + match.slice(1) + ";ie7_recalc" + id + ":1"; + }); + this.recalcs.push(arguments); + return id; + }, + + apply: function() { + this.getInlineCSS(); + new StyleSheet("screen"); + this.trash(); + }, + + createStyleSheet: function() { + // create the IE7 style sheet + document.getElementsByTagName("head")[0].appendChild(document.createElement("style")); + this.styleSheet = styleSheets[styleSheets.length - 1]; + // flag it so we can ignore it during parsing + this.styleSheet.ie7 = true; + this.styleSheet.owningElement.ie7 = true; + this.styleSheet.cssText = HEADER; + }, + + getInlineCSS: function() {// load inline styles + var styleSheets = document.getElementsByTagName("style"), styleSheet; + for (var i = styleSheets.length - 1; styleSheet = styleSheets[i]; i--) { + if (!styleSheet.disabled && !styleSheet.ie7) { + styleSheet._cssText = styleSheet.innerHTML; + } + } + }, + + getText: function(styleSheet, path) { + // Internet Explorer will trash unknown selectors (it converts them to "UNKNOWN"). + // So we must reload external style sheets (internal style sheets can have their text + // extracted through the innerHTML property). + + // load the style sheet text from an external file + try { + var cssText = styleSheet.cssText; + } catch (e) { + cssText = ""; + } + if (httpRequest) cssText = loadFile(styleSheet.href, path) || cssText; + return cssText; + }, + + recalc: function() { + this.screen.recalc(); + // we're going to read through all style rules. + // certain rules have had ie7 properties added to them. + // e.g. p{top:0; ie7_recalc2:1; left:0} + // this flags a property in the rule as needing a fix. + // the selector text is then used to query the document. + // we can then loop through the results of the query + // and fix the elements. + // we ignore the IE7 rules - so count them in the header + var RECALCS = /ie7_recalc\d+/g; + var start = HEADER.match(/[{,]/g).length; + // only calculate screen fixes. print fixes don't show up anyway + var rules = this.styleSheet.rules, rule; + var calcs, calc, elements, element, i, j, k, id; + // loop through all rules + for (i = start; rule = rules[i]; i++) { + var cssText = rule.style.cssText; + // search for the "ie7_recalc" flag (there may be more than one) + if (calcs = cssText.match(RECALCS)) { + // use the selector text to query the document + elements = cssQuery(rule.selectorText); + // if there are matching elements then loop + // through the recalc functions and apply them + // to each element + if (elements.length) for (j = 0; j < calcs.length; j++) { + // get the matching flag (e.g. ie7_recalc3) + id = calcs[j]; + // extract the numeric id from the end of the flag + // and use it to index the collection of recalc + // functions + calc = IE7.CSS.recalcs[id.slice(10)][2]; + for (k = 0; (element = elements[k]); k++) { + // apply the fix + if (element.currentStyle[id]) calc(element, cssText); + } + } + } + } + }, + + refresh: function() { + this.styleSheet.cssText = HEADER + this.screen + this.print; + }, + + trash: function() { + // trash the old style sheets + for (var i = 0; i < styleSheets.length; i++) { + if (!styleSheets[i].ie7) { + try { + var cssText = styleSheets[i].cssText; + } catch (e) { + cssText = ""; + } + if (cssText) styleSheets[i].cssText = ""; + } + } + } +})); + +// ----------------------------------------------------------------------- +// IE7 StyleSheet class +// ----------------------------------------------------------------------- + +var StyleSheet = Base.extend({ + constructor: function(media) { + this.media = media; + this.load(); + IE7.CSS[media] = this; + IE7.CSS.refresh(); + }, + + createRule: function(selector, cssText) { + var match; + if (PseudoElement && (match = selector.match(PseudoElement.MATCH))) { + return new PseudoElement(match[1], match[2], cssText); + } else if (match = selector.match(DynamicRule.MATCH)) { + if (!HYPERLINK.test(match[0]) || DynamicRule.COMPLEX.test(match[0])) { + return new DynamicRule(selector, match[1], match[2], match[3], cssText); + } + } else { + return new Rule(selector, cssText); + } + return selector + " {" + cssText + "}"; + }, + + getText: function() { + // store for style sheet text + // parse media decalarations + var MEDIA = /@media\s+([^{]+?)\s*\{([^@]+\})\s*\}/gi; + var IMPORTS = /@import[^;\n]+/gi; + var TRIM_IMPORTS = /@import\s+url\s*\(\s*["']?|["']?\s*\)\s*/gi; + var URL = /(url\s*\(\s*['"]?)([\w\.]+[^:\)]*['"]?\))/gi; + + var self = this; + + // Store loaded cssText URLs + var fileCache = {}; + + function getCSSText(styleSheet, path, media, level) { + var cssText = ""; + if (!level) { + media = toSimpleMedia(styleSheet.media); + level = 0; + } + if (media === "none") { + styleSheet.disabled = true; + return ""; + } + if (media === "all" || media === self.media) { + // IE only allows importing style sheets three levels deep. + // it will crash if you try to access a level below this + try { + var canAcess = !!styleSheet.cssText; + } catch (exe) {} + if (level < 3 && canAcess) { + var hrefs = styleSheet.cssText.match(IMPORTS); + // loop through imported style sheets + for (var i = 0, imported; i < styleSheet.imports.length; i++) { + var imported = styleSheet.imports[i]; + var href = styleSheet._href || styleSheet.href; + imported._href = hrefs[i].replace(TRIM_IMPORTS, ""); + // call this function recursively to get all imported style sheets + cssText += getCSSText(imported, getPath(href, path), media, level + 1); + } + } + // retrieve inline style or load an external style sheet + cssText += encode(styleSheet.href ? loadStyleSheet(styleSheet, path) : styleSheet.owningElement._cssText); + cssText = parseMedia(cssText, self.media); + } + return cssText; + }; + + // Load all style sheets in the document + for (var i = 0; i < styleSheets.length; i++) { + var styleSheet = styleSheets[i]; + if (!styleSheet.disabled && !styleSheet.ie7) this.cssText += getCSSText(styleSheet); + } + + // helper functions + function parseMedia(cssText, media) { + filterMedia.value = media; + return cssText.replace(MEDIA, filterMedia); + }; + + function filterMedia(match, media, cssText) { + media = toSimpleMedia(media); + switch (media) { + case "screen": + case "print": + if (media !== filterMedia.value) return ""; + case "all": + return cssText; + } + return ""; + }; + + function toSimpleMedia(media) { + if (!media) return "all"; + var split = media.toLowerCase().split(/\s*,\s*/); + media = "none"; + for (var i = 0; i < split.length; i++) { + if (split[i] === "all") return "all"; + if (split[i] === "screen") { + if (media === "print") return "all"; + media = "screen"; + } else if (split[i] === "print") { + if (media === "screen") return "all"; + media = "print"; + } + } + return media; + }; + + // Load an external style sheet + function loadStyleSheet(styleSheet, path) { + var href = styleSheet._href || styleSheet.href; + var url = makePath(href, path); + // If the style sheet has already loaded then don't reload it + if (fileCache[url]) return ""; + // Load from source + fileCache[url] = styleSheet.disabled ? "" : + fixUrls(IE7.CSS.getText(styleSheet, path), getPath(href, path)); + return fileCache[url]; + }; + + // Fix CSS paths. + // We're lumping all css text into one big style sheet so relative + // paths have to be fixed. This is necessary anyway because of other + // Internet Explorer bugs. + function fixUrls(cssText, pathname) { + // hack & slash + return cssText.replace(URL, "$1" + pathname.slice(0, pathname.lastIndexOf("/") + 1) + "$2"); + }; + }, + + load: function() { + this.cssText = ""; + this.getText(); + this.parse(); + if (inheritedProperties.length) { + this.cssText = parseInherited(this.cssText); + } + this.cssText = decode(this.cssText); + fileCache = {}; + }, + + parse: function() { + var cssText = IE7.CSS.parser.parse(this.cssText); + + var declarations = ""; + this.cssText = cssText.replace(/@charset[^;]+;|@font\-face[^\}]+\}/g, function(match) { + declarations += match + "\n"; + return ""; + }); + this.declarations = decode(declarations); + + // Parse the style sheet + var offset = IE7.CSS.rules.length; + var rules = [], rule; + while ((rule = RULE.exec(this.cssText))) { + var cssText = rule[2]; + if (cssText) { + var fixDescendants = appVersion < 7 && cssText.indexOf("AlphaImageLoader") !== -1; + var selectors = rule[1].match(SELECTOR), selector; + for (var i = 0; selector = selectors[i]; i++) { + selector = trim(selector); + var isUnknown = IE7.CSS.UNKNOWN.test(selector); + selectors[i] = isUnknown ? this.createRule(selector, cssText) : selector + "{" + cssText + "}"; + if (fixDescendants) selectors[i] += this.createRule(selector + ">*", "position:relative"); + } + rules.push(selectors.join("\n")); + } + } + this.cssText = rules.join("\n"); + this.rules = IE7.CSS.rules.slice(offset); + }, + + recalc: function() { + var rule, i; + for (i = 0; (rule = this.rules[i]); i++) rule.recalc(); + }, + + toString: function() { + return this.declarations + "@media " + this.media + "{" + this.cssText + "}"; + } +}); + +var PseudoElement; + +// ----------------------------------------------------------------------- +// IE7 style rules +// ----------------------------------------------------------------------- + +var Rule = IE7.Rule = Base.extend({ + constructor: function(selector, cssText) { + this.id = IE7.CSS.rules.length; + this.className = Rule.PREFIX + this.id; + var pseudoElement = selector.match(FIRST_LINE_LETTER); + this.selector = (pseudoElement ? pseudoElement[1] : selector) || "*"; + this.selectorText = this.parse(this.selector) + (pseudoElement ? pseudoElement[2] : ""); + this.cssText = cssText; + this.MATCH = new RegExp("\\s" + this.className + "(\\s|$)", "g"); + IE7.CSS.rules.push(this); + this.init(); + }, + + init: Undefined, + + add: function(element) { + // allocate this class + element.className += " " + this.className; + }, + + recalc: function() { + // execute the underlying css query for this class + var match = cssQuery(this.selector); + // add the class name for all matching elements + for (var i = 0; i < match.length; i++) this.add(match[i]); + }, + + parse: function(selector) { + // attempt to preserve specificity for "loose" parsing by + // removing unknown tokens from a css selector but keep as + // much as we can.. + var simple = selector.replace(Rule.CHILD, " ").replace(Rule.COMPLEX, ""); + if (appVersion < 7) simple = simple.replace(Rule.MULTI, ""); + var tags = match(simple, Rule.TAGS).length - match(selector, Rule.TAGS).length; + var classes = match(simple, Rule.CLASSES).length - match(selector, Rule.CLASSES).length + 1; + while (classes > 0 && Rule.CLASS.test(simple)) { + simple = simple.replace(Rule.CLASS, ""); + classes--; + } + while (tags > 0 && Rule.TAG.test(simple)) { + simple = simple.replace(Rule.TAG, "$1*"); + tags--; + } + simple += "." + this.className; + classes = Math.min(classes, 2); + tags = Math.min(tags, 2); + var score = -10 * classes - tags; + if (score > 0) { + simple = simple + "," + Rule.MAP[score] + " " + simple; + } + return simple; + }, + + remove: function(element) { + // deallocate this class + element.className = element.className.replace(this.MATCH, "$1"); + }, + + toString: function() { + return format("%1 {%2}", this.selectorText, this.cssText); + } +}, { + CHILD: />/g, + CLASS: /\.[\w-]+/, + CLASSES: /[.:\[]/g, + MULTI: /(\.[\w-]+)+/g, + PREFIX: "ie7_class", + TAG: /^\w+|([\s>+~])\w+/, + TAGS: /^\w|[\s>+~]\w/g, + MAP: { + "1": "html", + "2": "html body", + "10": ".ie7_html", + "11": "html.ie7_html", + "12": "html.ie7_html body", + "20": ".ie7_html .ie7_body", + "21": "html.ie7_html .ie7_body", + "22": "html.ie7_html body.ie7_body" + } +}); + +// ----------------------------------------------------------------------- +// IE7 dynamic style +// ----------------------------------------------------------------------- + +// object properties: +// attach: the element that an event handler will be attached to +// target: the element that will have the IE7 class applied + +var DynamicRule = Rule.extend({ + // properties + constructor: function(selector, attach, dynamicPseudoClass, target, cssText) { + this.negated = dynamicPseudoClass.indexOf("not") === 0; + if (this.negated) dynamicPseudoClass = dynamicPseudoClass.slice(5, -1); + // initialise object properties + this.attach = attach || "*"; + this.dynamicPseudoClass = IE7.CSS.dynamicPseudoClasses[dynamicPseudoClass]; + this.target = target; + this.base(selector, cssText); + }, + + recalc: function() { + // execute the underlying css query for this class + var attaches = cssQuery(this.attach), attach; + // process results + for (var i = 0; attach = attaches[i]; i++) { + // retrieve the event handler's target element(s) + var target = this.target ? cssQuery(this.target, attach) : [attach]; + // attach event handlers for dynamic pseudo-classes + if (target.length) this.dynamicPseudoClass.apply(attach, target, this); + } + } +}); + +// ----------------------------------------------------------------------- +// IE7 dynamic pseudo-classes +// ----------------------------------------------------------------------- + +var DynamicPseudoClass = Base.extend({ + constructor: function(name, apply) { + this.name = name; + this.apply = apply; + this.instances = {}; + IE7.CSS.dynamicPseudoClasses[name] = this; + }, + + register: function(instance, negated) { + // an "instance" is actually an Arguments object + var _class = instance[2]; + if (!negated && _class.negated) { + this.unregister(instance, true); + } else { + instance.id = _class.id + instance[0].uniqueID; + if (!this.instances[instance.id]) { + var target = instance[1], j; + for (j = 0; j < target.length; j++) _class.add(target[j]); + this.instances[instance.id] = instance; + } + } + }, + + unregister: function(instance, negated) { + var _class = instance[2]; + if (!negated && _class.negated) { + this.register(instance, true); + } else { + if (this.instances[instance.id]) { + var target = instance[1], j; + for (j = 0; j < target.length; j++) _class.remove(target[j]); + delete this.instances[instance.id]; + } + } + } +}); + +// ----------------------------------------------------------------------- +// dynamic pseudo-classes +// ----------------------------------------------------------------------- + +var Hover = new DynamicPseudoClass("hover", function(element) { + var instance = arguments; + IE7.CSS.addEventHandler(element, "onmouseenter", function() { + Hover.register(instance); + }); + IE7.CSS.addEventHandler(element, "onmouseleave", function() { + Hover.unregister(instance); + }); +}); + +// globally trap the mouseup event (thanks Martijn!) +addEventHandler(document, "onmouseup", function() { + var instances = Hover.instances; + for (var i in instances) + if (!instances[i][0].contains(event.srcElement)) + Hover.unregister(instances[i]); +}); + +var ATTR = { + "=": "%1==='%2'", // "[@%1='%2']" + "~=": "(' '+%1+' ').indexOf(' %2 ')!==-1", // "[contains(concat(' ',@%1,' '),' %2 ')]", + "|=": "%1==='%2'||%1.indexOf('%2-')===0", // "[@%1='%2' or starts-with(@%1,'%2-')]", + "^=": "%1.indexOf('%2')===0", // "[starts-with(@%1,'%2')]", + "$=": "%1.slice(-'%2'.length)==='%2'", // "[ends-with(@%1,'%2')]", + "*=": "%1.indexOf('%2')!==-1" // "[contains(@%1,'%2')]" +}; +ATTR[""] = "%1!=null"; // "[@%1]" + +var FILTER = { + "<#attr>": function(match, name, operator, value) { + var attr = "IE7._getAttribute(e,'" + name + "')"; + value = getString(value); + if (operator.length > 1) { + if (!value || operator === "~=" && SPACE.test(value)) { + return "false&&"; + } + attr = "(" + attr + "||'')"; + } + return "(" + format(ATTR[operator], attr, value) + ")&&"; + }, + + "<#id>": ID_ATTRIBUTE + "==='$1'&&", + + "<#class>": "e.className&&(' '+e.className+' ').indexOf(' $1 ')!==-1&&", + + // PSEDUO + ":first-child": "!" + PREVIOUS_SIBLING + "&&", + ":link": "e.currentStyle['ie7-link']=='link'&&", + ":visited": "e.currentStyle['ie7-link']=='visited'&&" +}; + +// ========================================================================= +// ie7-html.js +// ========================================================================= + +// default font-sizes +//HEADER += "h1{font-size:2em}h2{font-size:1.5em;}h3{font-size:1.17em;}h4{font-size:1em}h5{font-size:.83em}h6{font-size:.67em}"; + +IE7.HTML = new (Fix.extend({ // single instance + fixed: {}, + + init: Undefined, + + addFix: function() { + // fixes are a one-off, they are applied when the document is loaded + this.fixes.push(arguments); + }, + + apply: function() { + for (var i = 0; i < this.fixes.length; i++) { + var match = cssQuery(this.fixes[i][0]); + var fix = this.fixes[i][1]; + for (var j = 0; j < match.length; j++) fix(match[j]); + } + }, + + addRecalc: function() { + // recalcs occur whenever the document is refreshed using document.recalc() + this.recalcs.push(arguments); + }, + + recalc: function() { + // loop through the fixes + for (var i = 0; i < this.recalcs.length; i++) { + var match = cssQuery(this.recalcs[i][0]); + var recalc = this.recalcs[i][1], element; + var key = Math.pow(2, i); + for (var j = 0; (element = match[j]); j++) { + var uniqueID = element.uniqueID; + if ((this.fixed[uniqueID] & key) === 0) { + element = recalc(element) || element; + this.fixed[uniqueID] |= key; + } + } + } + } +})); + +if (appVersion < 7) { + // provide support for the tag. + document.createElement("abbr"); + + // bind to the first child control + IE7.HTML.addRecalc("label", function(label) { + if (!label.htmlFor) { + var firstChildControl = cssQuery("input,textarea", label, true); + if (firstChildControl) { + addEventHandler(label, "onclick", function() { + firstChildControl.click(); + }); + } + } + }); +} + +// ========================================================================= +// ie7-layout.js +// ========================================================================= + +var NUMERIC = "[.\\d]"; + +(function() { + var layout = IE7.Layout = {}; + + // big, ugly box-model hack + min/max stuff + + // #tantek > #erik > #dean { voice-family: hacker; } + + // ----------------------------------------------------------------------- + // "layout" + // ----------------------------------------------------------------------- + + HEADER += "*{boxSizing:content-box}"; + + // give an element "layout" + layout.boxSizing = function(element) { + if (!element.currentStyle.hasLayout) { + //# element.runtimeStyle.fixedHeight = + element.style.height = "0cm"; + if (element.currentStyle.verticalAlign === "auto") + element.runtimeStyle.verticalAlign = "top"; + // when an element acquires "layout", margins no longer collapse correctly + collapseMargins(element); + } + }; + + // ----------------------------------------------------------------------- + // Margin Collapse + // ----------------------------------------------------------------------- + + function collapseMargins(element) { + if (element != viewport && element.currentStyle.position !== "absolute") { + collapseMargin(element, "marginTop"); + collapseMargin(element, "marginBottom"); + } + }; + + function collapseMargin(element, type) { + if (!element.runtimeStyle[type]) { + var parentElement = element.parentElement; + var isTopMargin = type === "marginTop"; + if (parentElement && parentElement.currentStyle.hasLayout && !IE7._getElementSibling(element, isTopMargin ? "previous" : "next")) return; + var child = element[isTopMargin ? "firstChild" : "lastChild"]; + if (child && child.nodeName < "@") child = IE7._getElementSibling(child, isTopMargin ? "next" : "previous"); + if (child && child.currentStyle.styleFloat === "none" && child.currentStyle.hasLayout) { + collapseMargin(child, type); + margin = _getMargin(element, element.currentStyle[type]); + childMargin = _getMargin(child, child.currentStyle[type]); + if (margin < 0 || childMargin < 0) { + element.runtimeStyle[type] = margin + childMargin; + } else { + element.runtimeStyle[type] = Math.max(childMargin, margin); + } + child.runtimeStyle[type] = "0px"; + } + } + }; + + function _getMargin(element, value) { + return value === "auto" ? 0 : getPixelValue(element, value); + }; + + // ----------------------------------------------------------------------- + // box-model + // ----------------------------------------------------------------------- + + // constants + var UNIT = /^[.\d][\w]*$/, AUTO = /^(auto|0cm)$/; + + var apply = {}; + layout.borderBox = function(element){ + apply.Width(element); + apply.Height(element); + }; + + var _fixWidth = function(HEIGHT) { + apply.Width = function(element) { + if (!PERCENT.test(element.currentStyle.width)) _fixWidth(element); + if (HEIGHT) collapseMargins(element); + }; + + function _fixWidth(element, value) { + if (!element.runtimeStyle.fixedWidth) { + if (!value) value = element.currentStyle.width; + element.runtimeStyle.fixedWidth = UNIT.test(value) ? Math.max(0, getFixedWidth(element, value)) + "px" : value; + setOverrideStyle(element, "width", element.runtimeStyle.fixedWidth); + } + }; + + function layoutWidth(element) { + if (!isFixed(element)) { + var layoutParent = element.offsetParent; + while (layoutParent && !layoutParent.currentStyle.hasLayout) layoutParent = layoutParent.offsetParent; + } + return (layoutParent || viewport).clientWidth; + }; + + function getPixelWidth(element, value) { + if (PERCENT.test(value)) return parseInt(parseFloat(value) / 100 * layoutWidth(element)); + return getPixelValue(element, value); + }; + + var getFixedWidth = function(element, value) { + var borderBox = element.currentStyle["ie7-box-sizing"] === "border-box"; + var adjustment = 0; + if (MSIE5 && !borderBox) + adjustment += getBorderWidth(element) + getWidth(element, "padding"); + else if (!MSIE5 && borderBox) + adjustment -= getBorderWidth(element) + getWidth(element, "padding"); + return getPixelWidth(element, value) + adjustment; + }; + + // easy way to get border thickness for elements with "layout" + function getBorderWidth(element) { + return element.offsetWidth - element.clientWidth; + }; + + // have to do some pixel conversion to get padding/margin thickness :-( + function getWidth(element, type) { + return getPixelWidth(element, element.currentStyle[type + "Left"]) + getPixelWidth(element, element.currentStyle[type + "Right"]); + }; + + // ----------------------------------------------------------------------- + // min/max + // ----------------------------------------------------------------------- + + HEADER += "*{minWidth:none;maxWidth:none;min-width:none;max-width:none}"; + + // handle min-width property + layout.minWidth = function(element) { + // IE6 supports min-height so we frig it here + //#if (element.currentStyle.minHeight === "auto") element.runtimeStyle.minHeight = 0; + if (element.currentStyle["min-width"] != null) { + element.style.minWidth = element.currentStyle["min-width"]; + } + if (register(arguments.callee, element, element.currentStyle.minWidth !== "none")) { + layout.boxSizing(element); + _fixWidth(element); + resizeWidth(element); + } + }; + + // clone the minWidth function to make a maxWidth function + eval("IE7.Layout.maxWidth=" + String(layout.minWidth).replace(/min/g, "max")); + + // apply min/max restrictions + function resizeWidth(element) { + // check boundaries + if (element == document.body) { + var width = element.clientWidth; + } else { + var rect = element.getBoundingClientRect(); + width = rect.right - rect.left; + } + if (element.currentStyle.minWidth !== "none" && width < getFixedWidth(element, element.currentStyle.minWidth)) { + element.runtimeStyle.width = element.currentStyle.minWidth; + } else if (element.currentStyle.maxWidth !== "none" && width >= getFixedWidth(element, element.currentStyle.maxWidth)) { + element.runtimeStyle.width = element.currentStyle.maxWidth; + } else { + element.runtimeStyle.width = element.runtimeStyle.fixedWidth; + } + }; + + // ----------------------------------------------------------------------- + // right/bottom + // ----------------------------------------------------------------------- + + function fixRight(element) { + if (register(fixRight, element, /^(fixed|absolute)$/.test(element.currentStyle.position) && + getDefinedStyle(element, "left") !== "auto" && + getDefinedStyle(element, "right") !== "auto" && + AUTO.test(getDefinedStyle(element, "width")))) { + resizeRight(element); + layout.boxSizing(element); + } + }; + layout.fixRight = fixRight; + + function resizeRight(element) { + var left = getPixelWidth(element, element.runtimeStyle._left || element.currentStyle.left); + var width = layoutWidth(element) - getPixelWidth(element, element.currentStyle.right) - left - getWidth(element, "margin"); + if (parseInt(element.runtimeStyle.width) === width) return; + element.runtimeStyle.width = ""; + if (isFixed(element) || HEIGHT || element.offsetWidth < width) { + if (!MSIE5) width -= getBorderWidth(element) + getWidth(element, "padding"); + if (width < 0) width = 0; + element.runtimeStyle.fixedWidth = width; + setOverrideStyle(element, "width", width); + } + }; + + // ----------------------------------------------------------------------- + // window.onresize + // ----------------------------------------------------------------------- + + // handle window resize + var clientWidth = 0; + addResize(function() { + if (!viewport) return; + var i, wider = (clientWidth < viewport.clientWidth); + clientWidth = viewport.clientWidth; + // resize elements with "min-width" set + var elements = layout.minWidth.elements; + for (i in elements) { + var element = elements[i]; + var fixedWidth = (parseInt(element.runtimeStyle.width) === getFixedWidth(element, element.currentStyle.minWidth)); + if (wider && fixedWidth) element.runtimeStyle.width = ""; + if (wider == fixedWidth) resizeWidth(element); + } + // resize elements with "max-width" set + var elements = layout.maxWidth.elements; + for (i in elements) { + var element = elements[i]; + var fixedWidth = (parseInt(element.runtimeStyle.width) === getFixedWidth(element, element.currentStyle.maxWidth)); + if (!wider && fixedWidth) element.runtimeStyle.width = ""; + if (wider !== fixedWidth) resizeWidth(element); + } + // resize elements with "right" set + for (i in fixRight.elements) resizeRight(fixRight.elements[i]); + }); + + // ----------------------------------------------------------------------- + // fix CSS + // ----------------------------------------------------------------------- + if (MSIE5) { + IE7.CSS.addRecalc("width", NUMERIC, apply.Width); + } + if (appVersion < 7) { + IE7.CSS.addRecalc("max-width", NUMERIC, layout.maxWidth); + IE7.CSS.addRecalc("right", NUMERIC, fixRight); + } else if (appVersion == 7) { + if (HEIGHT) IE7.CSS.addRecalc("height", "[\\d.]+%", function(element) { + element.runtimeStyle.pixelHeight = parseInt(layoutWidth(element) * element.currentStyle["ie7-height"].slice(0, -1) / 100); + }); + } + }; + + eval("var _fixHeight=" + rotate(_fixWidth)); + + // apply box-model + min/max fixes + _fixWidth(); + _fixHeight(true); + + if (appVersion < 7) { + IE7.CSS.addRecalc("min-width", NUMERIC, layout.minWidth); + IE7.CSS.addFix(/\bmin-height\s*/, "height"); + } +})(); + +// ========================================================================= +// ie7-graphics.js +// ========================================================================= + +// a small transparent image used as a placeholder +var BLANK_GIF = makePath("blank.gif", path); + +var ALPHA_IMAGE_LOADER = "DXImageTransform.Microsoft.AlphaImageLoader"; +var PNG_FILTER = "progid:" + ALPHA_IMAGE_LOADER + "(src='%1',sizingMethod='%2')"; + +// regular expression version of the above +var PNG; + +var filtered = []; + +function fixImage(element) { + if (PNG.test(element.src)) { + // we have to preserve width and height + var image = new Image(element.width, element.height); + image.onload = function() { + element.width = image.width; + element.height = image.height; + image = null; + }; + image.src = element.src; + // store the original url (we'll put it back when it's printed) + element.pngSrc = element.src; + // add the AlphaImageLoader thingy + addFilter(element); + } +}; + +if (appVersion < 7) { + // ** IE7 VARIABLE + // e.g. apply the hack to all files ending in ".png" + // IE7_PNG_SUFFIX = ".png"; + // You can also set it to a RegExp + // IE7_PNG_SUFFIX = /\d+\.png$/; + + // replace background(-image): url(..) .. with background(-image): .. ;filter: ..; + IE7.CSS.addFix(/background(-image)?\s*:\s*([^};]*)?url\(([^\)]+)\)([^;}]*)?/, function(match, $1, $2, url, $4) { + url = getString(url); + return PNG.test(url) ? "filter:" + format(PNG_FILTER, url, $4.indexOf("no-repeat") === -1 ? "scale" : "crop") + + ";zoom:1;background" + ($1||"") + ":" + ($2||"") + "none" + ($4||"") : match; + }); + + // list-style-image + IE7.CSS.addRecalc(/list\-style(\-image)?/, "[^};]*url", function(element) { + var url = element.currentStyle.listStyleImage.slice(5, -2); + if (PNG.test(url)) { + if (element.nodeName === "LI") { + fixListStyleImage(element, url) + } else if (element.nodeName === "UL") { + for (var i = 0, li; li = element.childNodes[i]; i++) { + if (li.nodeName === "LI") fixListStyleImage(li, url); + } + } + } + }); + + function fixListStyleImage(element, src) { + var style = element.runtimeStyle; + var originalHeight = element.offsetHeight; + var image = new Image; + image.onload = function() { + var paddingLeft = element.currentStyle.paddingLeft; + paddingLeft = paddingLeft === "0px" ? 0 : getPixelValue(element, paddingLeft); + style.paddingLeft = (paddingLeft + this.width) + "px"; + style.marginLeft = -this.width + "px"; + style.listStyleType = "none"; + style.listStyleImage = "none"; + style.paddingTop = Math.max(originalHeight - element.offsetHeight, 0) + "px"; + addFilter(element, "crop", src); + element.style.zoom = "100%"; + }; + image.src = src; + }; + + // ----------------------------------------------------------------------- + // fix PNG transparency (HTML images) + // ----------------------------------------------------------------------- + + IE7.HTML.addRecalc("img,input", function(element) { + if (element.nodeName === "INPUT" && element.type !== "image") return; + fixImage(element); + addEventHandler(element, "onpropertychange", function() { + if (!printing && event.propertyName === "src" && + element.src.indexOf(BLANK_GIF) === -1) fixImage(element); + }); + }); + + // assume that background images should not be printed + // (if they are not transparent then they'll just obscure content) + // but we'll put foreground images back... + var printing = false; + addEventHandler(window, "onbeforeprint", function() { + printing = true; + for (var i = 0; i < filtered.length; i++) removeFilter(filtered[i]); + }); + addEventHandler(window, "onafterprint", function() { + for (var i = 0; i < filtered.length; i++) addFilter(filtered[i]); + printing = false; + }); +} + +// apply a filter +function addFilter(element, sizingMethod, src) { + var filter = element.filters[ALPHA_IMAGE_LOADER]; + if (filter) { + filter.src = src || element.src; + filter.enabled = true; + } else { + element.runtimeStyle.filter = format(PNG_FILTER, src || element.src, sizingMethod || "scale"); + filtered.push(element); + } + // remove the real image + element.src = BLANK_GIF; +}; + +function removeFilter(element) { + element.src = element.pngSrc; + element.filters[ALPHA_IMAGE_LOADER].enabled = false; +}; + +// ========================================================================= +// ie7-fixed.js +// ========================================================================= + +(function() { + if (appVersion >= 7) return; + + // some things to consider for this hack. + // the document body requires a fixed background. even if + // it is just a blank image. + // you have to use setExpression instead of onscroll, this + // together with a fixed body background helps avoid the + // annoying screen flicker of other solutions. + + IE7.CSS.addRecalc("position", "fixed", _positionFixed, "absolute"); + IE7.CSS.addRecalc("background(-attachment)?", "[^};]*fixed", _backgroundFixed); + + // scrolling is relative to the documentElement (HTML tag) when in + // standards mode, otherwise it's relative to the document body + var $viewport = MSIE5 ? "body" : "documentElement"; + + function _fixBackground() { + // this is required by both position:fixed and background-attachment:fixed. + // it is necessary for the document to also have a fixed background image. + // we can fake this with a blank image if necessary + if (body.currentStyle.backgroundAttachment !== "fixed") { + if (body.currentStyle.backgroundImage === "none") { + body.runtimeStyle.backgroundRepeat = "no-repeat"; + body.runtimeStyle.backgroundImage = "url(" + BLANK_GIF + ")"; // dummy + } + body.runtimeStyle.backgroundAttachment = "fixed"; + } + _fixBackground = Undefined; + }; + + var _tmp = createTempElement("img"); + + function _isFixed(element) { + return element ? isFixed(element) || _isFixed(element.parentElement) : false; + }; + + function _setExpression(element, propertyName, expression) { + setTimeout("document.all." + element.uniqueID + ".runtimeStyle.setExpression('" + propertyName + "','" + expression + "')", 0); + }; + + // ----------------------------------------------------------------------- + // backgroundAttachment: fixed + // ----------------------------------------------------------------------- + + function _backgroundFixed(element) { + if (register(_backgroundFixed, element, element.currentStyle.backgroundAttachment === "fixed" && !element.contains(body))) { + _fixBackground(); + util.bgLeft(element); + util.bgTop(element); + _backgroundPosition(element); + } + }; + + function _backgroundPosition(element) { + _tmp.src = element.currentStyle.backgroundImage.slice(5, -2); + var parentElement = element.canHaveChildren ? element : element.parentElement; + parentElement.appendChild(_tmp); + util.setOffsetLeft(element); + util.setOffsetTop(element); + parentElement.removeChild(_tmp); + }; + + // ----------------------------------------------------------------------- + // position: fixed + // ----------------------------------------------------------------------- + + function _positionFixed(element) { + if (register(_positionFixed, element, isFixed(element))) { + setOverrideStyle(element, "position", "absolute"); + setOverrideStyle(element, "left", element.currentStyle.left); + setOverrideStyle(element, "top", element.currentStyle.top); + _fixBackground(); + IE7.Layout.fixRight(element); + //IE7.Layout.fixBottom(element); + _foregroundPosition(element); + } + }; + + function _foregroundPosition(element, recalc) { + document.body.getBoundingClientRect(); // force a reflow + util.positionTop(element, recalc); + util.positionLeft(element, recalc, true); + if (!element.runtimeStyle.autoLeft && element.currentStyle.marginLeft === "auto" && + element.currentStyle.right !== "auto") { + var left = viewport.clientWidth - util.getPixelWidth(element, element.currentStyle.right) - + util.getPixelWidth(element, element.runtimeStyle._left) - element.clientWidth; + if (element.currentStyle.marginRight === "auto") left = parseInt(left / 2); + if (_isFixed(element.offsetParent)) element.runtimeStyle.pixelLeft += left; + else element.runtimeStyle.shiftLeft = left; + } + if (!element.runtimeStyle.fixedWidth) util.clipWidth(element); + if (!element.runtimeStyle.fixedHeight) util.clipHeight(element); + }; + + // ----------------------------------------------------------------------- + // capture window resize + // ----------------------------------------------------------------------- + + function _resize() { + // if the window has been resized then some positions need to be + // recalculated (especially those aligned to "right" or "top" + var elements = _backgroundFixed.elements; + for (var i in elements) _backgroundPosition(elements[i]); + elements = _positionFixed.elements; + for (i in elements) { + _foregroundPosition(elements[i], true); + _foregroundPosition(elements[i], true); + } + _timer = 0; + }; + + // use a timer (sometimes this is a good way to prevent resize loops) + var _timer; + addResize(function() { + if (!_timer) _timer = setTimeout(_resize, 100); + }); + + // ----------------------------------------------------------------------- + // rotated + // ----------------------------------------------------------------------- + + var util = {}; + + var _horizontal = function(util) { + util.bgLeft = function(element) { + element.style.backgroundPositionX = element.currentStyle.backgroundPositionX; + if (!_isFixed(element)) { + _setExpression(element, "backgroundPositionX", "(parseInt(runtimeStyle.offsetLeft)+document." + $viewport + ".scrollLeft)||0"); + } + }; + + util.setOffsetLeft = function(element) { + var propertyName = _isFixed(element) ? "backgroundPositionX" : "offsetLeft"; + element.runtimeStyle[propertyName] = + util.getOffsetLeft(element, element.style.backgroundPositionX) - + element.getBoundingClientRect().left - element.clientLeft + 2; + }; + + util.getOffsetLeft = function(element, position) { + switch (position) { + case "left": + case "top": + return 0; + case "right": + case "bottom": + return viewport.clientWidth - _tmp.offsetWidth; + case "center": + return (viewport.clientWidth - _tmp.offsetWidth) / 2; + default: + if (PERCENT.test(position)) { + return parseInt((viewport.clientWidth - _tmp.offsetWidth) * parseFloat(position) / 100); + } + _tmp.style.left = position; + return _tmp.offsetLeft; + } + }; + + util.clipWidth = function(element) { + var fixWidth = element.runtimeStyle.fixWidth; + element.runtimeStyle.borderRightWidth = ""; + element.runtimeStyle.width = fixWidth ? util.getPixelWidth(element, fixWidth) + "px" : ""; + if (element.currentStyle.width !== "auto") { + var rect = element.getBoundingClientRect(); + var width = element.offsetWidth - viewport.clientWidth + rect.left - 2; + if (width >= 0) { + element.runtimeStyle.borderRightWidth = "0px"; + width = Math.max(getPixelValue(element, element.currentStyle.width) - width, 0); + setOverrideStyle(element, "width", width); + return width; + } + } + }; + + util.positionLeft = function(element, recalc) { + // if the element's width is in % units then it must be recalculated + // with respect to the viewport + if (!recalc && PERCENT.test(element.currentStyle.width)) { + element.runtimeStyle.fixWidth = element.currentStyle.width; + } + if (element.runtimeStyle.fixWidth) { + element.runtimeStyle.width = util.getPixelWidth(element, element.runtimeStyle.fixWidth); + } + //if (recalc) { + // // if the element is fixed on the right then no need to recalculate + // if (!element.runtimeStyle.autoLeft) return; + //} else { + element.runtimeStyle.shiftLeft = 0; + element.runtimeStyle._left = element.currentStyle.left; + // is the element fixed on the right? + element.runtimeStyle.autoLeft = element.currentStyle.right !== "auto" && element.currentStyle.left === "auto"; + //} + // reset the element's "left" value and get it's natural position + element.runtimeStyle.left = ""; + element.runtimeStyle.screenLeft = util.getScreenLeft(element); + element.runtimeStyle.pixelLeft = element.runtimeStyle.screenLeft; + // if the element is contained by another fixed element then there is no need to + // continually recalculate it's left position + if (!recalc && !_isFixed(element.offsetParent)) { + // onsrcoll produces jerky movement, so we use an expression + _setExpression(element, "pixelLeft", "runtimeStyle.screenLeft+runtimeStyle.shiftLeft+document." + $viewport + ".scrollLeft"); + } + }; + + // I've forgotten how this works... + util.getScreenLeft = function(element) { // thanks to kevin newman (captainn) + var screenLeft = element.offsetLeft, nested = 1; + if (element.runtimeStyle.autoLeft) { + screenLeft = viewport.clientWidth - element.offsetWidth - util.getPixelWidth(element, element.currentStyle.right); + } + // accommodate margins + if (element.currentStyle.marginLeft !== "auto") { + screenLeft -= util.getPixelWidth(element, element.currentStyle.marginLeft); + } + while (element = element.offsetParent) { + if (element.currentStyle.position !== "static") nested = -1; + screenLeft += element.offsetLeft * nested; + } + return screenLeft; + }; + + util.getPixelWidth = function(element, value) { + return PERCENT.test(value) ? parseInt(parseFloat(value) / 100 * viewport.clientWidth) : getPixelValue(element, value); + }; + }; + eval("var _vertical=" + rotate(_horizontal)); + _horizontal(util); + _vertical(util); +})(); + +// ========================================================================= +// ie7-oveflow.js +// ========================================================================= + +/* --------------------------------------------------------------------- + + This module alters the structure of the document. + It may adversely affect other CSS rules. Be warned. + +--------------------------------------------------------------------- */ + +if (appVersion < 7) { + var WRAPPER_STYLE = { + backgroundColor: "transparent", + backgroundImage: "none", + backgroundPositionX: null, + backgroundPositionY: null, + backgroundRepeat: null, + borderTopWidth: 0, + borderRightWidth: 0, + borderBottomWidth: 0, + borderLeftStyle: "none", + borderTopStyle: "none", + borderRightStyle: "none", + borderBottomStyle: "none", + borderLeftWidth: 0, + borderLeftColor: "#000", + borderTopColor: "#000", + borderRightColor: "#000", + borderBottomColor: "#000", + height: null, + marginTop: 0, + marginBottom: 0, + marginRight: 0, + marginLeft: 0, + width: "100%" + }; + + IE7.CSS.addRecalc("overflow", "visible", function(element) { + if (element.currentStyle.position === "absolute") return; + + // don't do this again + if (element.parentNode.ie7_wrapped) return; + + // if max-height is applied, makes sure it gets applied first + if (IE7.Layout && element.currentStyle["max-height"] !== "auto") { + IE7.Layout.maxHeight(element); + } + + if (element.currentStyle.marginLeft === "auto") element.style.marginLeft = 0; + if (element.currentStyle.marginRight === "auto") element.style.marginRight = 0; + + var wrapper = document.createElement(ANON); + wrapper.ie7_wrapped = element; + for (var propertyName in WRAPPER_STYLE) { + wrapper.style[propertyName] = element.currentStyle[propertyName]; + if (WRAPPER_STYLE[propertyName] != null) { + element.runtimeStyle[propertyName] = WRAPPER_STYLE[propertyName]; + } + } + wrapper.style.display = "block"; + wrapper.style.position = "relative"; + element.runtimeStyle.position = "absolute"; + element.parentNode.insertBefore(wrapper, element); + wrapper.appendChild(element); + }); +} + +// ========================================================================= +// ie7-quirks.js +// ========================================================================= + +function ie7Quirks() { + var FONT_SIZES = "xx-small,x-small,small,medium,large,x-large,xx-large".split(","); + for (var i = 0; i < FONT_SIZES.length; i++) { + FONT_SIZES[FONT_SIZES[i]] = FONT_SIZES[i - 1] || "0.67em"; + } + + IE7.CSS.addFix(/(font(-size)?\s*:\s*)([\w.-]+)/, function(match, label, size, value) { + return label + (FONT_SIZES[value] || value); + }); + + var NEGATIVE = /^\-/, LENGTH = /(em|ex)$/i; + var EM = /em$/i, EX = /ex$/i; + + getPixelValue = function(element, value) { + if (PIXEL.test(value)) return parseInt(value)||0; + var scale = NEGATIVE.test(value)? -1 : 1; + if (LENGTH.test(value)) scale *= getFontScale(element); + temp.style.width = scale < 0 ? value.slice(1) : value; + body.appendChild(temp); + // retrieve pixel width + value = scale * temp.offsetWidth; + // remove the temporary element + temp.removeNode(); + return parseInt(value); + }; + + var temp = createTempElement(); + function getFontScale(element) { + var scale = 1; + temp.style.fontFamily = element.currentStyle.fontFamily; + temp.style.lineHeight = element.currentStyle.lineHeight; + //temp.style.fontSize = ""; + while (element != body) { + var fontSize = element.currentStyle["ie7-font-size"]; + if (fontSize) { + if (EM.test(fontSize)) scale *= parseFloat(fontSize); + else if (PERCENT.test(fontSize)) scale *= (parseFloat(fontSize) / 100); + else if (EX.test(fontSize)) scale *= (parseFloat(fontSize) / 2); + else { + temp.style.fontSize = fontSize; + return 1; + } + } + element = element.parentElement; + } + return scale; + }; + + // cursor:pointer (IE5.x) + IE7.CSS.addFix(/cursor\s*:\s*pointer/, "cursor:hand"); + // display:list-item (IE5.x) + IE7.CSS.addFix(/display\s*:\s*list-item/, "display:block"); + + // ----------------------------------------------------------------------- + // margin:auto + // ----------------------------------------------------------------------- + + function fixMargin(element) { + var parent = element.parentElement; + var margin = parent.offsetWidth - element.offsetWidth - getPaddingWidth(parent); + var autoRight = (element.currentStyle["ie7-margin"] && element.currentStyle.marginRight === "auto") || + element.currentStyle["ie7-margin-right"] === "auto"; + switch (parent.currentStyle.textAlign) { + case "right": + margin = autoRight ? parseInt(margin / 2) : 0; + element.runtimeStyle.marginRight = margin + "px"; + break; + case "center": + if (autoRight) margin = 0; + default: + if (autoRight) margin /= 2; + element.runtimeStyle.marginLeft = parseInt(margin) + "px"; + } + }; + + function getPaddingWidth(element) { + return getPixelValue(element, element.currentStyle.paddingLeft) + + getPixelValue(element, element.currentStyle.paddingRight); + }; + + IE7.CSS.addRecalc("margin(-left|-right)?", "[^};]*auto", function(element) { + if (register(fixMargin, element, + element.parentElement && + element.currentStyle.display === "block" && + element.currentStyle.marginLeft === "auto" && + element.currentStyle.position !== "absolute")) { + fixMargin(element); + } + }); + + addResize(function() { + for (var i in fixMargin.elements) { + var element = fixMargin.elements[i]; + element.runtimeStyle.marginLeft = + element.runtimeStyle.marginRight = ""; + fixMargin(element); + } + }); +}; + + +var MATCHER; + +var cssQuery = (function() { + var CONTEXT = /^[>+~]/; + + var useContext = false; + + // This is not a selector engine in the strictest sense. So it's best to silently error. + function cssQuery(selector, context, single) { + selector = trim(selector); + if (!context) context = document; + var ref = context; + useContext = CONTEXT.test(selector); + if (useContext) { + context = context.parentNode; + selector = "*" + selector; + } + try { + return selectQuery.create(selector, useContext)(context, single ? null : [], ref); + } catch (ex) { + return single ? null : []; + } + }; + + var VALID_SELECTOR = /^(\\.|[' >+~#.\[\]:*(),\w-\^|$=]|[^\x00-\xa0])+$/; + + var _EVALUATED = /^(href|src)$/; + var _ATTRIBUTES = { + "class": "className", + "for": "htmlFor" + }; + + var IE7_CLASS_NAMES = /\sie7_\w+/g; + + var USE_IFLAG = /^(action|cite|codebase|data|dynsrc|href|longdesc|lowsrc|src|usemap|url)$/i; + + IE7._getAttribute = function(element, name) { + if (element.getAttributeNode) { + var attribute = element.getAttributeNode(name); + } + name = _ATTRIBUTES[name.toLowerCase()] || name; + if (!attribute) attribute = element.attributes[name]; + var specified = attribute && attribute.specified; + + if (element[name] && typeof element[name] == "boolean") return name.toLowerCase(); + if ((specified && USE_IFLAG.test(name)) || (!attribute && MSIE5) || name === "value" || name === "type") { + return element.getAttribute(name, 2); + } + if (name === "style") return element.style.cssText.toLowerCase() || null; + + return specified ? String(attribute.nodeValue) : null; + }; + + var names = "colSpan,rowSpan,vAlign,dateTime,accessKey,tabIndex,encType,maxLength,readOnly,longDesc"; + // Convert the list of strings to a hash, mapping the lowercase name to the camelCase name. + extend(_ATTRIBUTES, combine(names.toLowerCase().split(","), names.split(","))); + + IE7._getElementSibling = function(node, direction) { + direction += "Sibling"; + do { + node = node[direction]; + if (node && node.nodeName > "@") break; + } while (node); + return node; + }; + + var IMPLIED_ASTERISK = /(^|[, >+~])([#.:\[])/g, + BLOCKS = /\)\{/g, + COMMA = /,/, + QUOTED = /^['"]/, + HEX_ESCAPE = /\\([\da-f]{2,2})/gi, + LAST_CHILD = /last/i; + + IE7._byId = function(document, id) { + var result = document.all[id] || null; + // Returns a single element or a collection. + if (!result || (result.nodeType && IE7._getAttribute(result, "id") === id)) return result; + // document.all has returned a collection of elements with name/id + for (var i = 0; i < result.length; i++) { + if (IE7._getAttribute(result[i], "id") === id) return result[i]; + } + return null; + }; + + // ========================================================================= + // dom/selectors-api/CSSSelectorParser.js + // ========================================================================= + + // http://www.w3.org/TR/css3-selectors/#w3cselgrammar (kinda) + var CSSSelectorParser = RegGrp.extend({ + dictionary: new Dictionary({ + ident: /\-?(\\.|[_a-z]|[^\x00-\xa0])(\\.|[\w-]|[^\x00-\xa0])*/, + combinator: /[\s>+~]/, + operator: /[\^~|$*]?=/, + nth_arg: /[+-]?\d+|[+-]?\d*n(?:\s*[+-]\s*\d+)?|even|odd/, + tag: /\*|<#ident>/, + id: /#(<#ident>)/, + 'class': /\.(<#ident>)/, + pseudo: /\:([\w-]+)(?:\(([^)]+)\))?/, + attr: /\[(<#ident>)(?:(<#operator>)((?:\\.|[^\[\]#.:])+))?\]/, + negation: /:not\((<#tag>|<#id>|<#class>|<#attr>|<#pseudo>)\)/, + sequence: /(\\.|[~*]=|\+\d|\+?\d*n\s*\+\s*\d|[^\s>+~,\*])+/, + filter: /[#.:\[]<#sequence>/, + selector: /[^>+~](\\.|[^,])*?/, + grammar: /^(<#selector>)((,<#selector>)*)$/ + }), + + ignoreCase: true + }); + + var normalizer = new CSSSelectorParser({ + "\\\\.|[~*]\\s+=|\\+\\s+\\d": RegGrp.IGNORE, + "\\[\\s+": "[", + "\\(\\s+": "(", + "\\s+\\)": ")", + "\\s+\\]": "]", + "\\s*([,>+~]|<#operator>)\\s*": "$1", + "\\s+$": "", + "\\s+": " " + }); + + function normalize(selector) { + selector = normalizer.parse(selector.replace(HEX_ESCAPE, "\\x$1")) + .replace(UNESCAPE, "$1") + .replace(IMPLIED_ASTERISK, "$1*$2"); + if (!VALID_SELECTOR.test(selector)) throwSelectorError(); + return selector; + }; + + function unescape(query) { + // put string values back + return query.replace(ESCAPED, unescapeString); + }; + + function unescapeString(match, index) { + return strings[index]; + }; + + var BRACES = /\{/g, BRACES_ESCAPED = /\\{/g; + + function closeBlock(group) { + return Array((group.replace(BRACES_ESCAPED, "").match(BRACES) || "").length + 1).join("}"); + }; + + FILTER = new CSSSelectorParser(FILTER); + + var TARGET = /:target/i, ROOT = /:root/i; + + function getConstants(selector) { + var constants = ""; + if (ROOT.test(selector)) constants += ",R=d.documentElement"; + if (TARGET.test(selector)) constants += ",H=d.location;H=H&&H.hash.replace('#','')"; + if (constants || selector.indexOf("#") !== -1) { + constants = ",t=c.nodeType,d=t===9?c:c.ownerDocument||(c.document||c).parentWindow.document" + constants; + } + return "var ii" + constants + ";"; + }; + + var COMBINATOR = { + " ": ";while(e!=s&&(e=e.parentNode)&&e.nodeType===1){", + ">": ".parentElement;if(e){", + "+": ";while((e=e.previousSibling)&&!(" + IS_ELEMENT + "))continue;if(e){", + "~": ";while((e=e.previousSibling)){" + IF_ELEMENT + }; + + var TOKEN = /\be\b/g; + + MATCHER = new CSSSelectorParser({ + "(?:(<#selector>)(<#combinator>))?(<#tag>)(<#filter>)?$": function(match, before, combinator, tag, filters) { + var group = ""; + if (tag !== "*") { + var TAG = tag.toUpperCase(); + group += "if(e.nodeName==='" + TAG + (TAG === tag ? "" : "'||e.nodeName==='" + tag) + "'){"; + } + if (filters) { + group += "if(" + FILTER.parse(filters).slice(0, -2) + "){"; + } + group = group.replace(TOKEN, "e" + this.index); + if (combinator) { + group += "var e=e" + (this.index++) + COMBINATOR[combinator]; + group = group.replace(TOKEN, "e" + this.index); + } + if (before) { + group += this.parse(before); + } + return group; + } + }); + + var BY_ID = "e0=IE7._byId(d,'%1');if(e0){", + BY_TAG_NAME = "var n=c.getElementsByTagName('%1');", + STORE = "if(r==null)return e0;r[k++]=e0;"; + + var TAG_NAME = 1; + + var SELECTOR = new CSSSelectorParser({ + "^((?:<#selector>)?(?:<#combinator>))(<#tag>)(<#filter>)?$": true + }); + + var cache = {}; + + var selectById = new CSSSelectorParser({ + "^(<#tag>)#(<#ident>)(<#filter>)?( [^,]*)?$": function(match, tagName, id, filters, after) { + var block = format(BY_ID, id), endBlock = "}"; + if (filters) { + block += MATCHER.parse(tagName + filters); + endBlock = closeBlock(block); + } + if (after) { + block += "s=c=e0;" + selectQuery.parse("*" + after); + } else { + block += STORE; + } + return block + endBlock; + }, + + "^([^#,]+)#(<#ident>)(<#filter>)?$": function(match, before, id, filters) { + var block = format(BY_ID, id); + if (before === "*") { + block += STORE; + } else { + block += MATCHER.parse(before + filters) + STORE + "break"; + } + return block + closeBlock(block); + }, + + "^.*$": "" + }); + + var selectQuery = new CSSSelectorParser({ + "<#grammar>": function(match, selector, remainingSelectors) { + if (!this.groups) this.groups = []; + + var group = SELECTOR.exec(" " + selector); + + if (!group) throwSelectorError(); + + this.groups.push(group.slice(1)); + + if (remainingSelectors) { + return this.parse(remainingSelectors.replace(COMMA, "")); + } + + var groups = this.groups, + tagName = groups[0][TAG_NAME]; // first tag name + + for (var i = 1; group = groups[i]; i++) { // search tag names + if (tagName !== group[TAG_NAME]) { + tagName = "*"; // mixed tag names, so use "*" + break; + } + } + + var matcher = "", store = STORE + "continue filtering;"; + + for (var i = 0; group = groups[i]; i++) { + MATCHER.index = 0; + if (tagName !== "*") group[TAG_NAME] = "*"; // we are already filtering by tagName + group = group.join(""); + if (group === " *") { // select all + matcher = store; + break; + } else { + group = MATCHER.parse(group); + if (useContext) group += "if(e" + MATCHER.index + "==s){"; + matcher += group + store + closeBlock(group); + } + } + + // reduce to a single loop + var isWild = tagName === "*"; + return (isWild ? "var n=c.all;" : format(BY_TAG_NAME, tagName)) + + "filtering:while((e0=n[i++]))" + + (isWild ? IF_ELEMENT.replace(TOKEN, "e0") : "{") + + matcher + + "}"; + }, + + "^.*$": throwSelectorError + }); + + var REDUNDANT_NODETYPE_CHECKS = /\&\&(e\d+)\.nodeType===1(\)\{\s*if\(\1\.nodeName=)/g; + + selectQuery.create = function(selector) { + if (!cache[selector]) { + selector = normalize(selector); + this.groups = null; + MATCHER.index = 0; + var block = this.parse(selector); + this.groups = null; + MATCHER.index = 0; + if (selector.indexOf("#") !== -1) { + var byId = selectById.parse(selector); + if (byId) { + block = + "if(t===1||t===11|!c.getElementById){" + + block + + "}else{" + + byId + + "}"; + } + } + // remove redundant nodeType==1 checks + block = block.replace(REDUNDANT_NODETYPE_CHECKS, "$2"); + block = getConstants(selector) + decode(block); + cache[selector] = new Function("return function(c,r,s){var i=0,k=0,e0;" + block + "return r}")(); + } + return cache[selector]; + }; + + return cssQuery; +})(); + +function throwSelectorError() { + throw new SyntaxError("Invalid selector."); +}; + +// ----------------------------------------------------------------------- +// initialisation +// ----------------------------------------------------------------------- + +IE7.loaded = true; + +(function() { + try { + // http://javascript.nwbox.com/IEContentLoaded/ + if (!document.body) throw "continue"; + documentElement.doScroll("left"); + } catch (ex) { + setTimeout(arguments.callee, 1); + return; + } + // execute the inner text of the IE7 script + try { + eval(script.innerHTML); + } catch (ex) { + // ignore errors + } + if (typeof IE7_PNG_SUFFIX == "object") { + PNG = IE7_PNG_SUFFIX; + } else { + PNG = new RegExp(rescape(window.IE7_PNG_SUFFIX || "-trans.png") + "(\\?.*)?$", "i"); + } + + // frequently used references + body = document.body; + viewport = MSIE5 ? body : documentElement; + + // classes + body.className += " ie7_body"; + documentElement.className += " ie7_html"; + + if (MSIE5) ie7Quirks(); + + IE7.CSS.init(); + IE7.HTML.init(); + + IE7.HTML.apply(); + IE7.CSS.apply(); + + IE7.recalc(); +})(); + +})(this, document); + diff --git a/static/js/plugins/IE8.js b/app/static/js/plugins/IE8.js similarity index 97% rename from static/js/plugins/IE8.js rename to app/static/js/plugins/IE8.js index 79dac8468..9d1b3f6c8 100755 --- a/static/js/plugins/IE8.js +++ b/app/static/js/plugins/IE8.js @@ -1,2690 +1,2690 @@ -/* - Upgrade MSIE5.5-7 to be compatible with MSIE8. - - IE7/IE8/IE9.js - copyright 2004-2010, Dean Edwards - http://code.google.com/p/ie7-js/ - http://www.opensource.org/licenses/mit-license.php -*/ - -/* W3C compliance for Microsoft Internet Explorer */ - -/* credits/thanks: - Shaggy, Martijn Wargers, Jimmy Cerra, Mark D Anderson, - Lars Dieckow, Erik Arvidsson, Gellert Gyuris, James Denny, - Unknown W Brackets, Benjamin Westfarer, Rob Eberhardt, - Bill Edney, Kevin Newman, James Crompton, Matthew Mastracci, - Doug Wright, Richard York, Kenneth Kolano, MegaZone, - Thomas Verelst, Mark 'Tarquin' Wilton-Jones, Rainer Ahlfors, - David Zulaica, Ken Kolano, Kevin Newman, Sjoerd Visscher, - Ingo Chao -*/ - -// timestamp: Fri, 30 Apr 2010 20:59:18 - -(function(window, document) { - -var IE7 = window.IE7 = { - version: "2.1(beta4)", - toString: K("[IE7]") -}; -IE7.compat = 8; -var appVersion = IE7.appVersion = navigator.appVersion.match(/MSIE (\d\.\d)/)[1] - 0; - -if (/ie7_off/.test(top.location.search) || appVersion < 5.5 || appVersion >= IE7.compat) return; - -var MSIE5 = appVersion < 6; - -var Undefined = K(); -var documentElement = document.documentElement, body, viewport; -var ANON = "!"; -var HEADER = ":link{ie7-link:link}:visited{ie7-link:visited}"; - -// ----------------------------------------------------------------------- -// external -// ----------------------------------------------------------------------- - -var RELATIVE = /^[\w\.]+[^:]*$/; -function makePath(href, path) { - if (RELATIVE.test(href)) href = (path || "") + href; - return href; -}; - -function getPath(href, path) { - href = makePath(href, path); - return href.slice(0, href.lastIndexOf("/") + 1); -}; - -// Get the path to this script -var script = document.scripts[document.scripts.length - 1]; -var path = getPath(script.src); - -// Use microsoft's http request object to load external files -try { - var httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); -} catch (ex) { - // ActiveX disabled -} - -var fileCache = {}; -function loadFile(href, path) { - try { - href = makePath(href, path); - if (!fileCache[href]) { - httpRequest.open("GET", href, false); - httpRequest.send(); - if (httpRequest.status == 0 || httpRequest.status == 200) { - fileCache[href] = httpRequest.responseText; - } - } - } catch (ex) { - // ignore errors - } - return fileCache[href] || ""; -}; - -// ----------------------------------------------------------------------- -// OO support -// ----------------------------------------------------------------------- - - -// This is a cut-down version of base2 (http://code.google.com/p/base2/) - -var _slice = Array.prototype.slice; - -// private -var _FORMAT = /%([1-9])/g; -var _LTRIM = /^\s\s*/; -var _RTRIM = /\s\s*$/; -var _RESCAPE = /([\/()[\]{}|*+-.,^$?\\])/g; // safe regular expressions -var _BASE = /\bbase\b/; -var _HIDDEN = ["constructor", "toString"]; // only override these when prototyping - -var prototyping; - -function Base(){}; -Base.extend = function(_instance, _static) { - // Build the prototype. - prototyping = true; - var _prototype = new this; - extend(_prototype, _instance); - prototyping = false; - - // Create the wrapper for the constructor function. - var _constructor = _prototype.constructor; - function klass() { - // Don't call the constructor function when prototyping. - if (!prototyping) _constructor.apply(this, arguments); - }; - _prototype.constructor = klass; - - // Build the static interface. - klass.extend = arguments.callee; - extend(klass, _static); - klass.prototype = _prototype; - return klass; -}; -Base.prototype.extend = function(source) { - return extend(this, source); -}; - - -// A collection of regular expressions and their associated replacement values. -// A Base class for creating parsers. - -var HASH = "#"; -var ITEMS = "#"; -var KEYS = "."; -var COMPILED = "/"; - -var REGGRP_BACK_REF = /\\(\d+)/g, - REGGRP_ESCAPE_COUNT = /\[(\\.|[^\]\\])+\]|\\.|\(\?/g, - REGGRP_PAREN = /\(/g, - REGGRP_LOOKUP = /\$(\d+)/, - REGGRP_LOOKUP_SIMPLE = /^\$\d+$/, - REGGRP_LOOKUPS = /(\[(\\.|[^\]\\])+\]|\\.|\(\?)|\(/g, - REGGRP_DICT_ENTRY = /^<#\w+>$/, - REGGRP_DICT_ENTRIES = /<#(\w+)>/g; - -var RegGrp = Base.extend({ - constructor: function(values) { - this[KEYS] = []; - this[ITEMS] = {}; - this.merge(values); - }, - - //dictionary: null, - //ignoreCase: false, - - add: function(expression, replacement) { - delete this[COMPILED]; - if (expression instanceof RegExp) { - expression = expression.source; - } - if (!this[HASH + expression]) this[KEYS].push(String(expression)); - return this[ITEMS][HASH + expression] = new RegGrp.Item(expression, replacement, this); - }, - - compile: function(recompile) { - if (recompile || !this[COMPILED]) { - this[COMPILED] = new RegExp(this, this.ignoreCase ? "gi" : "g"); - } - return this[COMPILED]; - }, - - merge: function(values) { - for (var i in values) this.add(i, values[i]); - }, - - exec: function(string) { - var group = this, - patterns = group[KEYS], - items = group[ITEMS], item; - var result = this.compile(true).exec(string); - if (result) { - // Loop through the RegGrp items. - var i = 0, offset = 1; - while ((item = items[HASH + patterns[i++]])) { - var next = offset + item.length + 1; - if (result[offset]) { // do we have a result? - if (item.replacement === 0) { - return group.exec(string); - } else { - var args = result.slice(offset, next), j = args.length; - while (--j) args[j] = args[j] || ""; // some platforms return null/undefined for non-matching sub-expressions - args[0] = {match: args[0], item: item}; - return args; - } - } - offset = next; - } - } - return null; - }, - - parse: function(string) { - string += ""; // type safe - var group = this, - patterns = group[KEYS], - items = group[ITEMS]; - return string.replace(this.compile(), function(match) { - var args = [], item, offset = 1, i = arguments.length; - while (--i) args[i] = arguments[i] || ""; // some platforms return null/undefined for non-matching sub-expressions - // Loop through the RegGrp items. - while ((item = items[HASH + patterns[i++]])) { - var next = offset + item.length + 1; - if (args[offset]) { // do we have a result? - var replacement = item.replacement; - switch (typeof replacement) { - case "function": - return replacement.apply(group, args.slice(offset, next)); - case "number": - return args[offset + replacement]; - default: - return replacement; - } - } - offset = next; - } - return match; - }); - }, - - toString: function() { - var strings = [], - keys = this[KEYS], - items = this[ITEMS], item; - for (var i = 0; item = items[HASH + keys[i]]; i++) { - strings[i] = item.source; - } - return "(" + strings.join(")|(") + ")"; - } -}, { - IGNORE: null, // a null replacement value means that there is no replacement. - - Item: Base.extend({ - constructor: function(source, replacement, owner) { - var length = source.indexOf("(") === -1 ? 0 : RegGrp.count(source); - - var dictionary = owner.dictionary; - if (dictionary && source.indexOf("<#") !== -1) { - if (REGGRP_DICT_ENTRY.test(source)) { - var entry = dictionary[ITEMS][HASH + source.slice(2, -1)]; - source = entry.replacement; - length = entry._length; - } else { - source = dictionary.parse(source); - } - } - - if (typeof replacement == "number") replacement = String(replacement); - else if (replacement == null) replacement = 0; - - // Does the expression use sub-expression lookups? - if (typeof replacement == "string" && REGGRP_LOOKUP.test(replacement)) { - if (REGGRP_LOOKUP_SIMPLE.test(replacement)) { // A simple lookup? (e.g. "$2"). - // Store the index (used for fast retrieval of matched strings). - var index = replacement.slice(1) - 0; - if (index && index <= length) replacement = index; - } else { - // A complicated lookup (e.g. "Hello $2 $1."). - var lookup = replacement, regexp; - replacement = function(match) { - if (!regexp) { - regexp = new RegExp(source, "g" + (this.ignoreCase ? "i": "")); - } - return match.replace(regexp, lookup); - }; - } - } - - this.length = length; - this.source = String(source); - this.replacement = replacement; - } - }), - - count: function(expression) { - return (String(expression).replace(REGGRP_ESCAPE_COUNT, "").match(REGGRP_PAREN) || "").length; - } -}); - -var Dictionary = RegGrp.extend({ - parse: function(phrase) { - // Prevent sub-expressions in dictionary entries from capturing. - var entries = this[ITEMS]; - return phrase.replace(REGGRP_DICT_ENTRIES, function(match, entry) { - entry = entries[HASH + entry]; - return entry ? entry._nonCapturing : match; - }); - }, - - add: function(expression, replacement) { - // Get the underlying replacement value. - if (replacement instanceof RegExp) { - replacement = replacement.source; - } - // Translate the replacement. - // The result is the original replacement recursively parsed by this dictionary. - var nonCapturing = replacement.replace(REGGRP_LOOKUPS, _nonCapture); - if (replacement.indexOf("(") !== -1) { - var realLength = RegGrp.count(replacement); - } - if (replacement.indexOf("<#") !== -1) { - replacement = this.parse(replacement); - nonCapturing = this.parse(nonCapturing); - } - var item = this.base(expression, replacement); - item._nonCapturing = nonCapturing; - item._length = realLength || item.length; // underlying number of sub-groups - return item; - }, - - toString: function() { - return "(<#" + this[PATTERNS].join(">)|(<#") + ">)"; - } -}); - -function _nonCapture(match, escaped) { - return escaped || "(?:"; // non-capturing -}; - -// ========================================================================= -// lang/extend.js -// ========================================================================= - -function extend(object, source) { // or extend(object, key, value) - if (object && source) { - var proto = (typeof source == "function" ? Function : Object).prototype; - // Add constructor, toString etc - var i = _HIDDEN.length, key; - if (prototyping) while (key = _HIDDEN[--i]) { - var value = source[key]; - if (value != proto[key]) { - if (_BASE.test(value)) { - _override(object, key, value) - } else { - object[key] = value; - } - } - } - // Copy each of the source object's properties to the target object. - for (key in source) if (typeof proto[key] == "undefined") { - var value = source[key]; - // Check for method overriding. - if (object[key] && typeof value == "function" && _BASE.test(value)) { - _override(object, key, value); - } else { - object[key] = value; - } - } - } - return object; -}; - -function _override(object, name, method) { - // Override an existing method. - var ancestor = object[name]; - object[name] = function() { - var previous = this.base; - this.base = ancestor; - var returnValue = method.apply(this, arguments); - this.base = previous; - return returnValue; - }; -}; - -function combine(keys, values) { - // Combine two arrays to make a hash. - if (!values) values = keys; - var hash = {}; - for (var i in keys) hash[i] = values[i]; - return hash; -}; - -function format(string) { - // Replace %n with arguments[n]. - // e.g. format("%1 %2%3 %2a %1%3", "she", "se", "lls"); - // ==> "she sells sea shells" - // Only %1 - %9 supported. - var args = arguments; - var _FORMAT = new RegExp("%([1-" + arguments.length + "])", "g"); - return String(string).replace(_FORMAT, function(match, index) { - return index < args.length ? args[index] : match; - }); -}; - -function match(string, expression) { - // Same as String.match() except that this function will return an empty - // array if there is no match. - return String(string).match(expression) || []; -}; - -function rescape(string) { - // Make a string safe for creating a RegExp. - return String(string).replace(_RESCAPE, "\\$1"); -}; - -// http://blog.stevenlevithan.com/archives/faster-trim-javascript -function trim(string) { - return String(string).replace(_LTRIM, "").replace(_RTRIM, ""); -}; - -function K(k) { - return function() { - return k; - }; -}; - -// ----------------------------------------------------------------------- -// parsing -// ----------------------------------------------------------------------- - -var Parser = RegGrp.extend({ignoreCase: true}); - -var SINGLE_QUOTES = /'/g, - ESCAPED = /'(\d+)'/g, - ESCAPE = /\\/g, - UNESCAPE = /\\([nrtf'"])/g; - -var strings = []; - -var encoder = new Parser({ - // comments - "": "", - "\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\/": "", - // get rid - "@(namespace|import)[^;\\n]+[;\\n]": "", - // strings - "'(\\\\.|[^'\\\\])*'": encodeString, - '"(\\\\.|[^"\\\\])*"': encodeString, - // white space - "\\s+": " " -}); - -function encode(selector) { - return encoder.parse(selector).replace(UNESCAPE, "$1"); -}; - -function decode(query) { - // put string values back - return query.replace(ESCAPED, decodeString); -}; - -function encodeString(string) { - var index = strings.length; - strings[index] = string.slice(1, -1) - .replace(UNESCAPE, "$1") - .replace(SINGLE_QUOTES, "\\'"); - return "'" + index + "'"; -}; - -function decodeString(match, index) { - var string = strings[index]; - if (string == null) return match; - return "'" + strings[index] + "'"; -}; - -function getString(value) { - return value.indexOf("'") === 0 ? strings[value.slice(1, - 1)] : value; -}; - -// clone a "width" function to create a "height" function -var rotater = new RegGrp({ - Width: "Height", - width: "height", - Left: "Top", - left: "top", - Right: "Bottom", - right: "bottom", - onX: "onY" -}); - -function rotate(fn) { - return rotater.parse(fn); -}; - -// ----------------------------------------------------------------------- -// event handling -// ----------------------------------------------------------------------- - -var eventHandlers = []; - -function addResize(handler) { - addRecalc(handler); - addEventHandler(window, "onresize", handler); -}; - -// add an event handler (function) to an element -function addEventHandler(element, type, handler) { - element.attachEvent(type, handler); - // store the handler so it can be detached later - eventHandlers.push(arguments); -}; - -// remove an event handler assigned to an element by IE7 -function removeEventHandler(element, type, handler) { - try { - element.detachEvent(type, handler); - } catch (ex) { - // write a letter of complaint to microsoft.. - } -}; - -// remove event handlers (they eat memory) -addEventHandler(window, "onunload", function() { - var handler; - while (handler = eventHandlers.pop()) { - removeEventHandler(handler[0], handler[1], handler[2]); - } -}); - -function register(handler, element, condition) { // -@DRE - //var set = handler[element.uniqueID]; - if (!handler.elements) handler.elements = {}; - if (condition) handler.elements[element.uniqueID] = element; - else delete handler.elements[element.uniqueID]; - //return !set && condition; - return condition; -}; - -addEventHandler(window, "onbeforeprint", function() { - if (!IE7.CSS.print) new StyleSheet("print"); - IE7.CSS.print.recalc(); -}); - -// ----------------------------------------------------------------------- -// pixel conversion -// ----------------------------------------------------------------------- - -// this is handy because it means that web developers can mix and match -// measurement units in their style sheets. it is not uncommon to -// express something like padding in "em" units whilst border thickness -// is most often expressed in pixels. - -var PIXEL = /^\d+(px)?$/i; -var PERCENT = /^\d+%$/; -var getPixelValue = function(element, value) { - if (PIXEL.test(value)) return parseInt(value); - var style = element.style.left; - var runtimeStyle = element.runtimeStyle.left; - element.runtimeStyle.left = element.currentStyle.left; - element.style.left = value || 0; - value = element.style.pixelLeft; - element.style.left = style; - element.runtimeStyle.left = runtimeStyle; - return value; -}; - -// ----------------------------------------------------------------------- -// generic -// ----------------------------------------------------------------------- - -var $IE7 = "ie7-"; - -var Fix = Base.extend({ - constructor: function() { - this.fixes = []; - this.recalcs = []; - }, - init: Undefined -}); - -// a store for functions that will be called when refreshing IE7 -var recalcs = []; -function addRecalc(recalc) { - recalcs.push(recalc); -}; - -IE7.recalc = function() { - IE7.HTML.recalc(); - // re-apply style sheet rules (re-calculate ie7 classes) - IE7.CSS.recalc(); - // apply global fixes to the document - for (var i = 0; i < recalcs.length; i++) recalcs[i](); -}; - -function isFixed(element) { - return element.currentStyle["ie7-position"] == "fixed"; -}; - -// original style -function getDefinedStyle(element, propertyName) { - return element.currentStyle[$IE7 + propertyName] || element.currentStyle[propertyName]; -}; - -function setOverrideStyle(element, propertyName, value) { - if (element.currentStyle[$IE7 + propertyName] == null) { - element.runtimeStyle[$IE7 + propertyName] = element.currentStyle[propertyName]; - } - element.runtimeStyle[propertyName] = value; -}; - -// Create a temporary element which is used to inherit styles -// from the target element. -function createTempElement(tagName) { - var element = document.createElement(tagName || "object"); - element.style.cssText = "position:absolute;padding:0;display:block;border:none;clip:rect(0 0 0 0);left:-9999"; - element.ie7_anon = true; - return element; -}; - - -// ========================================================================= -// ie7-css.js -// ========================================================================= - -var NEXT_SIBLING = "(e.nextSibling&&IE7._getElementSibling(e,'next'))", - PREVIOUS_SIBLING = NEXT_SIBLING.replace(/next/g, "previous"), - IS_ELEMENT = "e.nodeName>'@'", - IF_ELEMENT = "if(" + IS_ELEMENT + "){"; - -var ID_ATTRIBUTE = "(e.nodeName==='FORM'?IE7._getAttribute(e,'id'):e.id)"; - -var HYPERLINK = /a(#[\w-]+)?(\.[\w-]+)?:(hover|active)/i; -var FIRST_LINE_LETTER = /(.*)(:first-(line|letter))/; -var SPACE = /\s/; -var RULE = /((?:\\.|[^{\\])+)\{((?:\\.|[^}\\])+)\}/g; -var SELECTOR = /(?:\\.|[^,\\])+/g; - -var styleSheets = document.styleSheets; - -var inheritedProperties = []; - -IE7.CSS = new (Fix.extend({ // single instance - parser: new Parser, - screen: "", - print: "", - styles: [], - rules: [], - pseudoClasses: appVersion < 7 ? "first\\-child" : "", - dynamicPseudoClasses: { - toString: function() { - var strings = []; - for (var pseudoClass in this) strings.push(pseudoClass); - return strings.join("|"); - } - }, - - init: function() { - var NONE = "^\x01$"; - var CLASS = "\\[class=?[^\\]]*\\]"; - var pseudoClasses = []; - if (this.pseudoClasses) pseudoClasses.push(this.pseudoClasses); - var dynamicPseudoClasses = this.dynamicPseudoClasses.toString(); - if (dynamicPseudoClasses) pseudoClasses.push(dynamicPseudoClasses); - pseudoClasses = pseudoClasses.join("|"); - var unknown = appVersion < 7 ? ["[>+~\\[(]|([:.])[\\w-]+\\1"] : [CLASS]; - if (pseudoClasses) unknown.push(":(" + pseudoClasses + ")"); - this.UNKNOWN = new RegExp(unknown.join("|") || NONE, "i"); - var complex = appVersion < 7 ? ["\\[[^\\]]+\\]|[^\\s(\\[]+\\s*[+~]"] : [CLASS]; - var complexRule = complex.concat(); - if (pseudoClasses) complexRule.push(":(" + pseudoClasses + ")"); - Rule.COMPLEX = new RegExp(complexRule.join("|") || NONE, "ig"); - if (this.pseudoClasses) complex.push(":(" + this.pseudoClasses + ")"); - DynamicRule.COMPLEX = new RegExp(complex.join("|") || NONE, "i"); - dynamicPseudoClasses = "not\\(:" + dynamicPseudoClasses.split("|").join("\\)|not\\(:") + "\\)|" + dynamicPseudoClasses; - DynamicRule.MATCH = new RegExp(dynamicPseudoClasses ? "(.*?):(" + dynamicPseudoClasses + ")(.*)" : NONE, "i"); - - this.createStyleSheet(); - this.refresh(); - }, - - addEventHandler: function() { - addEventHandler.apply(null, arguments); - }, - - addFix: function(expression, replacement) { - this.parser.add(expression, replacement); - }, - - addRecalc: function(propertyName, test, handler, replacement) { - // recalcs occur whenever the document is refreshed using document.recalc() - propertyName = propertyName.source || propertyName; - test = new RegExp("([{;\\s])" + propertyName + "\\s*:\\s*" + test + "[^;}]*"); - var id = this.recalcs.length; - if (typeof replacement == "string") replacement = propertyName + ":" + replacement; - this.addFix(test, function(match) { - if (typeof replacement == "function") replacement = replacement(match); - return (replacement ? replacement : match) + ";ie7-" + match.slice(1) + ";ie7_recalc" + id + ":1"; - }); - this.recalcs.push(arguments); - return id; - }, - - apply: function() { - this.getInlineCSS(); - new StyleSheet("screen"); - this.trash(); - }, - - createStyleSheet: function() { - // create the IE7 style sheet - document.getElementsByTagName("head")[0].appendChild(document.createElement("style")); - this.styleSheet = styleSheets[styleSheets.length - 1]; - // flag it so we can ignore it during parsing - this.styleSheet.ie7 = true; - this.styleSheet.owningElement.ie7 = true; - this.styleSheet.cssText = HEADER; - }, - - getInlineCSS: function() {// load inline styles - var styleSheets = document.getElementsByTagName("style"), styleSheet; - for (var i = styleSheets.length - 1; styleSheet = styleSheets[i]; i--) { - if (!styleSheet.disabled && !styleSheet.ie7) { - styleSheet._cssText = styleSheet.innerHTML; - } - } - }, - - getText: function(styleSheet, path) { - // Internet Explorer will trash unknown selectors (it converts them to "UNKNOWN"). - // So we must reload external style sheets (internal style sheets can have their text - // extracted through the innerHTML property). - - // load the style sheet text from an external file - try { - var cssText = styleSheet.cssText; - } catch (e) { - cssText = ""; - } - if (httpRequest) cssText = loadFile(styleSheet.href, path) || cssText; - return cssText; - }, - - recalc: function() { - this.screen.recalc(); - // we're going to read through all style rules. - // certain rules have had ie7 properties added to them. - // e.g. p{top:0; ie7_recalc2:1; left:0} - // this flags a property in the rule as needing a fix. - // the selector text is then used to query the document. - // we can then loop through the results of the query - // and fix the elements. - // we ignore the IE7 rules - so count them in the header - var RECALCS = /ie7_recalc\d+/g; - var start = HEADER.match(/[{,]/g).length; - // only calculate screen fixes. print fixes don't show up anyway - var rules = this.styleSheet.rules, rule; - var calcs, calc, elements, element, i, j, k, id; - // loop through all rules - for (i = start; rule = rules[i]; i++) { - var cssText = rule.style.cssText; - // search for the "ie7_recalc" flag (there may be more than one) - if (calcs = cssText.match(RECALCS)) { - // use the selector text to query the document - elements = cssQuery(rule.selectorText); - // if there are matching elements then loop - // through the recalc functions and apply them - // to each element - if (elements.length) for (j = 0; j < calcs.length; j++) { - // get the matching flag (e.g. ie7_recalc3) - id = calcs[j]; - // extract the numeric id from the end of the flag - // and use it to index the collection of recalc - // functions - calc = IE7.CSS.recalcs[id.slice(10)][2]; - for (k = 0; (element = elements[k]); k++) { - // apply the fix - if (element.currentStyle[id]) calc(element, cssText); - } - } - } - } - }, - - refresh: function() { - this.styleSheet.cssText = HEADER + this.screen + this.print; - }, - - trash: function() { - // trash the old style sheets - for (var i = 0; i < styleSheets.length; i++) { - if (!styleSheets[i].ie7) { - try { - var cssText = styleSheets[i].cssText; - } catch (e) { - cssText = ""; - } - if (cssText) styleSheets[i].cssText = ""; - } - } - } -})); - -// ----------------------------------------------------------------------- -// IE7 StyleSheet class -// ----------------------------------------------------------------------- - -var StyleSheet = Base.extend({ - constructor: function(media) { - this.media = media; - this.load(); - IE7.CSS[media] = this; - IE7.CSS.refresh(); - }, - - createRule: function(selector, cssText) { - var match; - if (PseudoElement && (match = selector.match(PseudoElement.MATCH))) { - return new PseudoElement(match[1], match[2], cssText); - } else if (match = selector.match(DynamicRule.MATCH)) { - if (!HYPERLINK.test(match[0]) || DynamicRule.COMPLEX.test(match[0])) { - return new DynamicRule(selector, match[1], match[2], match[3], cssText); - } - } else { - return new Rule(selector, cssText); - } - return selector + " {" + cssText + "}"; - }, - - getText: function() { - // store for style sheet text - // parse media decalarations - var MEDIA = /@media\s+([^{]+?)\s*\{([^@]+\})\s*\}/gi; - var IMPORTS = /@import[^;\n]+/gi; - var TRIM_IMPORTS = /@import\s+url\s*\(\s*["']?|["']?\s*\)\s*/gi; - var URL = /(url\s*\(\s*['"]?)([\w\.]+[^:\)]*['"]?\))/gi; - - var self = this; - - // Store loaded cssText URLs - var fileCache = {}; - - function getCSSText(styleSheet, path, media, level) { - var cssText = ""; - if (!level) { - media = toSimpleMedia(styleSheet.media); - level = 0; - } - if (media === "none") { - styleSheet.disabled = true; - return ""; - } - if (media === "all" || media === self.media) { - // IE only allows importing style sheets three levels deep. - // it will crash if you try to access a level below this - try { - var canAcess = !!styleSheet.cssText; - } catch (exe) {} - if (level < 3 && canAcess) { - var hrefs = styleSheet.cssText.match(IMPORTS); - // loop through imported style sheets - for (var i = 0, imported; i < styleSheet.imports.length; i++) { - var imported = styleSheet.imports[i]; - var href = styleSheet._href || styleSheet.href; - imported._href = hrefs[i].replace(TRIM_IMPORTS, ""); - // call this function recursively to get all imported style sheets - cssText += getCSSText(imported, getPath(href, path), media, level + 1); - } - } - // retrieve inline style or load an external style sheet - cssText += encode(styleSheet.href ? loadStyleSheet(styleSheet, path) : styleSheet.owningElement._cssText); - cssText = parseMedia(cssText, self.media); - } - return cssText; - }; - - // Load all style sheets in the document - for (var i = 0; i < styleSheets.length; i++) { - var styleSheet = styleSheets[i]; - if (!styleSheet.disabled && !styleSheet.ie7) this.cssText += getCSSText(styleSheet); - } - - // helper functions - function parseMedia(cssText, media) { - filterMedia.value = media; - return cssText.replace(MEDIA, filterMedia); - }; - - function filterMedia(match, media, cssText) { - media = toSimpleMedia(media); - switch (media) { - case "screen": - case "print": - if (media !== filterMedia.value) return ""; - case "all": - return cssText; - } - return ""; - }; - - function toSimpleMedia(media) { - if (!media) return "all"; - var split = media.toLowerCase().split(/\s*,\s*/); - media = "none"; - for (var i = 0; i < split.length; i++) { - if (split[i] === "all") return "all"; - if (split[i] === "screen") { - if (media === "print") return "all"; - media = "screen"; - } else if (split[i] === "print") { - if (media === "screen") return "all"; - media = "print"; - } - } - return media; - }; - - // Load an external style sheet - function loadStyleSheet(styleSheet, path) { - var href = styleSheet._href || styleSheet.href; - var url = makePath(href, path); - // If the style sheet has already loaded then don't reload it - if (fileCache[url]) return ""; - // Load from source - fileCache[url] = styleSheet.disabled ? "" : - fixUrls(IE7.CSS.getText(styleSheet, path), getPath(href, path)); - return fileCache[url]; - }; - - // Fix CSS paths. - // We're lumping all css text into one big style sheet so relative - // paths have to be fixed. This is necessary anyway because of other - // Internet Explorer bugs. - function fixUrls(cssText, pathname) { - // hack & slash - return cssText.replace(URL, "$1" + pathname.slice(0, pathname.lastIndexOf("/") + 1) + "$2"); - }; - }, - - load: function() { - this.cssText = ""; - this.getText(); - this.parse(); - if (inheritedProperties.length) { - this.cssText = parseInherited(this.cssText); - } - this.cssText = decode(this.cssText); - fileCache = {}; - }, - - parse: function() { - var cssText = IE7.CSS.parser.parse(this.cssText); - - var declarations = ""; - this.cssText = cssText.replace(/@charset[^;]+;|@font\-face[^\}]+\}/g, function(match) { - declarations += match + "\n"; - return ""; - }); - this.declarations = decode(declarations); - - // Parse the style sheet - var offset = IE7.CSS.rules.length; - var rules = [], rule; - while ((rule = RULE.exec(this.cssText))) { - var cssText = rule[2]; - if (cssText) { - var fixDescendants = appVersion < 7 && cssText.indexOf("AlphaImageLoader") !== -1; - var selectors = rule[1].match(SELECTOR), selector; - for (var i = 0; selector = selectors[i]; i++) { - selector = trim(selector); - var isUnknown = IE7.CSS.UNKNOWN.test(selector); - selectors[i] = isUnknown ? this.createRule(selector, cssText) : selector + "{" + cssText + "}"; - if (fixDescendants) selectors[i] += this.createRule(selector + ">*", "position:relative"); - } - rules.push(selectors.join("\n")); - } - } - this.cssText = rules.join("\n"); - this.rules = IE7.CSS.rules.slice(offset); - }, - - recalc: function() { - var rule, i; - for (i = 0; (rule = this.rules[i]); i++) rule.recalc(); - }, - - toString: function() { - return this.declarations + "@media " + this.media + "{" + this.cssText + "}"; - } -}); - -var PseudoElement; - -// ----------------------------------------------------------------------- -// IE7 style rules -// ----------------------------------------------------------------------- - -var Rule = IE7.Rule = Base.extend({ - constructor: function(selector, cssText) { - this.id = IE7.CSS.rules.length; - this.className = Rule.PREFIX + this.id; - var pseudoElement = selector.match(FIRST_LINE_LETTER); - this.selector = (pseudoElement ? pseudoElement[1] : selector) || "*"; - this.selectorText = this.parse(this.selector) + (pseudoElement ? pseudoElement[2] : ""); - this.cssText = cssText; - this.MATCH = new RegExp("\\s" + this.className + "(\\s|$)", "g"); - IE7.CSS.rules.push(this); - this.init(); - }, - - init: Undefined, - - add: function(element) { - // allocate this class - element.className += " " + this.className; - }, - - recalc: function() { - // execute the underlying css query for this class - var match = cssQuery(this.selector); - // add the class name for all matching elements - for (var i = 0; i < match.length; i++) this.add(match[i]); - }, - - parse: function(selector) { - // attempt to preserve specificity for "loose" parsing by - // removing unknown tokens from a css selector but keep as - // much as we can.. - var simple = selector.replace(Rule.CHILD, " ").replace(Rule.COMPLEX, ""); - if (appVersion < 7) simple = simple.replace(Rule.MULTI, ""); - var tags = match(simple, Rule.TAGS).length - match(selector, Rule.TAGS).length; - var classes = match(simple, Rule.CLASSES).length - match(selector, Rule.CLASSES).length + 1; - while (classes > 0 && Rule.CLASS.test(simple)) { - simple = simple.replace(Rule.CLASS, ""); - classes--; - } - while (tags > 0 && Rule.TAG.test(simple)) { - simple = simple.replace(Rule.TAG, "$1*"); - tags--; - } - simple += "." + this.className; - classes = Math.min(classes, 2); - tags = Math.min(tags, 2); - var score = -10 * classes - tags; - if (score > 0) { - simple = simple + "," + Rule.MAP[score] + " " + simple; - } - return simple; - }, - - remove: function(element) { - // deallocate this class - element.className = element.className.replace(this.MATCH, "$1"); - }, - - toString: function() { - return format("%1 {%2}", this.selectorText, this.cssText); - } -}, { - CHILD: />/g, - CLASS: /\.[\w-]+/, - CLASSES: /[.:\[]/g, - MULTI: /(\.[\w-]+)+/g, - PREFIX: "ie7_class", - TAG: /^\w+|([\s>+~])\w+/, - TAGS: /^\w|[\s>+~]\w/g, - MAP: { - "1": "html", - "2": "html body", - "10": ".ie7_html", - "11": "html.ie7_html", - "12": "html.ie7_html body", - "20": ".ie7_html .ie7_body", - "21": "html.ie7_html .ie7_body", - "22": "html.ie7_html body.ie7_body" - } -}); - -// ----------------------------------------------------------------------- -// IE7 dynamic style -// ----------------------------------------------------------------------- - -// object properties: -// attach: the element that an event handler will be attached to -// target: the element that will have the IE7 class applied - -var DynamicRule = Rule.extend({ - // properties - constructor: function(selector, attach, dynamicPseudoClass, target, cssText) { - this.negated = dynamicPseudoClass.indexOf("not") === 0; - if (this.negated) dynamicPseudoClass = dynamicPseudoClass.slice(5, -1); - // initialise object properties - this.attach = attach || "*"; - this.dynamicPseudoClass = IE7.CSS.dynamicPseudoClasses[dynamicPseudoClass]; - this.target = target; - this.base(selector, cssText); - }, - - recalc: function() { - // execute the underlying css query for this class - var attaches = cssQuery(this.attach), attach; - // process results - for (var i = 0; attach = attaches[i]; i++) { - // retrieve the event handler's target element(s) - var target = this.target ? cssQuery(this.target, attach) : [attach]; - // attach event handlers for dynamic pseudo-classes - if (target.length) this.dynamicPseudoClass.apply(attach, target, this); - } - } -}); - -// ----------------------------------------------------------------------- -// IE7 dynamic pseudo-classes -// ----------------------------------------------------------------------- - -var DynamicPseudoClass = Base.extend({ - constructor: function(name, apply) { - this.name = name; - this.apply = apply; - this.instances = {}; - IE7.CSS.dynamicPseudoClasses[name] = this; - }, - - register: function(instance, negated) { - // an "instance" is actually an Arguments object - var _class = instance[2]; - if (!negated && _class.negated) { - this.unregister(instance, true); - } else { - instance.id = _class.id + instance[0].uniqueID; - if (!this.instances[instance.id]) { - var target = instance[1], j; - for (j = 0; j < target.length; j++) _class.add(target[j]); - this.instances[instance.id] = instance; - } - } - }, - - unregister: function(instance, negated) { - var _class = instance[2]; - if (!negated && _class.negated) { - this.register(instance, true); - } else { - if (this.instances[instance.id]) { - var target = instance[1], j; - for (j = 0; j < target.length; j++) _class.remove(target[j]); - delete this.instances[instance.id]; - } - } - } -}); - -// ----------------------------------------------------------------------- -// dynamic pseudo-classes -// ----------------------------------------------------------------------- - -var Hover = new DynamicPseudoClass("hover", function(element) { - var instance = arguments; - IE7.CSS.addEventHandler(element, "onmouseenter", function() { - Hover.register(instance); - }); - IE7.CSS.addEventHandler(element, "onmouseleave", function() { - Hover.unregister(instance); - }); -}); - -// globally trap the mouseup event (thanks Martijn!) -addEventHandler(document, "onmouseup", function() { - var instances = Hover.instances; - for (var i in instances) - if (!instances[i][0].contains(event.srcElement)) - Hover.unregister(instances[i]); -}); - -var ATTR = { - "=": "%1==='%2'", // "[@%1='%2']" - "~=": "(' '+%1+' ').indexOf(' %2 ')!==-1", // "[contains(concat(' ',@%1,' '),' %2 ')]", - "|=": "%1==='%2'||%1.indexOf('%2-')===0", // "[@%1='%2' or starts-with(@%1,'%2-')]", - "^=": "%1.indexOf('%2')===0", // "[starts-with(@%1,'%2')]", - "$=": "%1.slice(-'%2'.length)==='%2'", // "[ends-with(@%1,'%2')]", - "*=": "%1.indexOf('%2')!==-1" // "[contains(@%1,'%2')]" -}; -ATTR[""] = "%1!=null"; // "[@%1]" - -var FILTER = { - "<#attr>": function(match, name, operator, value) { - var attr = "IE7._getAttribute(e,'" + name + "')"; - value = getString(value); - if (operator.length > 1) { - if (!value || operator === "~=" && SPACE.test(value)) { - return "false&&"; - } - attr = "(" + attr + "||'')"; - } - return "(" + format(ATTR[operator], attr, value) + ")&&"; - }, - - "<#id>": ID_ATTRIBUTE + "==='$1'&&", - - "<#class>": "e.className&&(' '+e.className+' ').indexOf(' $1 ')!==-1&&", - - // PSEDUO - ":first-child": "!" + PREVIOUS_SIBLING + "&&", - ":link": "e.currentStyle['ie7-link']=='link'&&", - ":visited": "e.currentStyle['ie7-link']=='visited'&&" -}; - -// ========================================================================= -// ie7-html.js -// ========================================================================= - -// default font-sizes -//HEADER += "h1{font-size:2em}h2{font-size:1.5em;}h3{font-size:1.17em;}h4{font-size:1em}h5{font-size:.83em}h6{font-size:.67em}"; - -IE7.HTML = new (Fix.extend({ // single instance - fixed: {}, - - init: Undefined, - - addFix: function() { - // fixes are a one-off, they are applied when the document is loaded - this.fixes.push(arguments); - }, - - apply: function() { - for (var i = 0; i < this.fixes.length; i++) { - var match = cssQuery(this.fixes[i][0]); - var fix = this.fixes[i][1]; - for (var j = 0; j < match.length; j++) fix(match[j]); - } - }, - - addRecalc: function() { - // recalcs occur whenever the document is refreshed using document.recalc() - this.recalcs.push(arguments); - }, - - recalc: function() { - // loop through the fixes - for (var i = 0; i < this.recalcs.length; i++) { - var match = cssQuery(this.recalcs[i][0]); - var recalc = this.recalcs[i][1], element; - var key = Math.pow(2, i); - for (var j = 0; (element = match[j]); j++) { - var uniqueID = element.uniqueID; - if ((this.fixed[uniqueID] & key) === 0) { - element = recalc(element) || element; - this.fixed[uniqueID] |= key; - } - } - } - } -})); - -if (appVersion < 7) { - // provide support for the tag. - document.createElement("abbr"); - - // bind to the first child control - IE7.HTML.addRecalc("label", function(label) { - if (!label.htmlFor) { - var firstChildControl = cssQuery("input,textarea", label, true); - if (firstChildControl) { - addEventHandler(label, "onclick", function() { - firstChildControl.click(); - }); - } - } - }); -} - -// ========================================================================= -// ie7-layout.js -// ========================================================================= - -var NUMERIC = "[.\\d]"; - -(function() { - var layout = IE7.Layout = {}; - - // big, ugly box-model hack + min/max stuff - - // #tantek > #erik > #dean { voice-family: hacker; } - - // ----------------------------------------------------------------------- - // "layout" - // ----------------------------------------------------------------------- - - HEADER += "*{boxSizing:content-box}"; - - // give an element "layout" - layout.boxSizing = function(element) { - if (!element.currentStyle.hasLayout) { - //# element.runtimeStyle.fixedHeight = - element.style.height = "0cm"; - if (element.currentStyle.verticalAlign === "auto") - element.runtimeStyle.verticalAlign = "top"; - // when an element acquires "layout", margins no longer collapse correctly - collapseMargins(element); - } - }; - - // ----------------------------------------------------------------------- - // Margin Collapse - // ----------------------------------------------------------------------- - - function collapseMargins(element) { - if (element != viewport && element.currentStyle.position !== "absolute") { - collapseMargin(element, "marginTop"); - collapseMargin(element, "marginBottom"); - } - }; - - function collapseMargin(element, type) { - if (!element.runtimeStyle[type]) { - var parentElement = element.parentElement; - var isTopMargin = type === "marginTop"; - if (parentElement && parentElement.currentStyle.hasLayout && !IE7._getElementSibling(element, isTopMargin ? "previous" : "next")) return; - var child = element[isTopMargin ? "firstChild" : "lastChild"]; - if (child && child.nodeName < "@") child = IE7._getElementSibling(child, isTopMargin ? "next" : "previous"); - if (child && child.currentStyle.styleFloat === "none" && child.currentStyle.hasLayout) { - collapseMargin(child, type); - margin = _getMargin(element, element.currentStyle[type]); - childMargin = _getMargin(child, child.currentStyle[type]); - if (margin < 0 || childMargin < 0) { - element.runtimeStyle[type] = margin + childMargin; - } else { - element.runtimeStyle[type] = Math.max(childMargin, margin); - } - child.runtimeStyle[type] = "0px"; - } - } - }; - - function _getMargin(element, value) { - return value === "auto" ? 0 : getPixelValue(element, value); - }; - - // ----------------------------------------------------------------------- - // box-model - // ----------------------------------------------------------------------- - - // constants - var UNIT = /^[.\d][\w]*$/, AUTO = /^(auto|0cm)$/; - - var apply = {}; - layout.borderBox = function(element){ - apply.Width(element); - apply.Height(element); - }; - - var _fixWidth = function(HEIGHT) { - apply.Width = function(element) { - if (!PERCENT.test(element.currentStyle.width)) _fixWidth(element); - if (HEIGHT) collapseMargins(element); - }; - - function _fixWidth(element, value) { - if (!element.runtimeStyle.fixedWidth) { - if (!value) value = element.currentStyle.width; - element.runtimeStyle.fixedWidth = UNIT.test(value) ? Math.max(0, getFixedWidth(element, value)) + "px" : value; - setOverrideStyle(element, "width", element.runtimeStyle.fixedWidth); - } - }; - - function layoutWidth(element) { - if (!isFixed(element)) { - var layoutParent = element.offsetParent; - while (layoutParent && !layoutParent.currentStyle.hasLayout) layoutParent = layoutParent.offsetParent; - } - return (layoutParent || viewport).clientWidth; - }; - - function getPixelWidth(element, value) { - if (PERCENT.test(value)) return parseInt(parseFloat(value) / 100 * layoutWidth(element)); - return getPixelValue(element, value); - }; - - var getFixedWidth = function(element, value) { - var borderBox = element.currentStyle["ie7-box-sizing"] === "border-box"; - var adjustment = 0; - if (MSIE5 && !borderBox) - adjustment += getBorderWidth(element) + getWidth(element, "padding"); - else if (!MSIE5 && borderBox) - adjustment -= getBorderWidth(element) + getWidth(element, "padding"); - return getPixelWidth(element, value) + adjustment; - }; - - // easy way to get border thickness for elements with "layout" - function getBorderWidth(element) { - return element.offsetWidth - element.clientWidth; - }; - - // have to do some pixel conversion to get padding/margin thickness :-( - function getWidth(element, type) { - return getPixelWidth(element, element.currentStyle[type + "Left"]) + getPixelWidth(element, element.currentStyle[type + "Right"]); - }; - - // ----------------------------------------------------------------------- - // min/max - // ----------------------------------------------------------------------- - - HEADER += "*{minWidth:none;maxWidth:none;min-width:none;max-width:none}"; - - // handle min-width property - layout.minWidth = function(element) { - // IE6 supports min-height so we frig it here - //#if (element.currentStyle.minHeight === "auto") element.runtimeStyle.minHeight = 0; - if (element.currentStyle["min-width"] != null) { - element.style.minWidth = element.currentStyle["min-width"]; - } - if (register(arguments.callee, element, element.currentStyle.minWidth !== "none")) { - layout.boxSizing(element); - _fixWidth(element); - resizeWidth(element); - } - }; - - // clone the minWidth function to make a maxWidth function - eval("IE7.Layout.maxWidth=" + String(layout.minWidth).replace(/min/g, "max")); - - // apply min/max restrictions - function resizeWidth(element) { - // check boundaries - if (element == document.body) { - var width = element.clientWidth; - } else { - var rect = element.getBoundingClientRect(); - width = rect.right - rect.left; - } - if (element.currentStyle.minWidth !== "none" && width < getFixedWidth(element, element.currentStyle.minWidth)) { - element.runtimeStyle.width = element.currentStyle.minWidth; - } else if (element.currentStyle.maxWidth !== "none" && width >= getFixedWidth(element, element.currentStyle.maxWidth)) { - element.runtimeStyle.width = element.currentStyle.maxWidth; - } else { - element.runtimeStyle.width = element.runtimeStyle.fixedWidth; - } - }; - - // ----------------------------------------------------------------------- - // right/bottom - // ----------------------------------------------------------------------- - - function fixRight(element) { - if (register(fixRight, element, /^(fixed|absolute)$/.test(element.currentStyle.position) && - getDefinedStyle(element, "left") !== "auto" && - getDefinedStyle(element, "right") !== "auto" && - AUTO.test(getDefinedStyle(element, "width")))) { - resizeRight(element); - layout.boxSizing(element); - } - }; - layout.fixRight = fixRight; - - function resizeRight(element) { - var left = getPixelWidth(element, element.runtimeStyle._left || element.currentStyle.left); - var width = layoutWidth(element) - getPixelWidth(element, element.currentStyle.right) - left - getWidth(element, "margin"); - if (parseInt(element.runtimeStyle.width) === width) return; - element.runtimeStyle.width = ""; - if (isFixed(element) || HEIGHT || element.offsetWidth < width) { - if (!MSIE5) width -= getBorderWidth(element) + getWidth(element, "padding"); - if (width < 0) width = 0; - element.runtimeStyle.fixedWidth = width; - setOverrideStyle(element, "width", width); - } - }; - - // ----------------------------------------------------------------------- - // window.onresize - // ----------------------------------------------------------------------- - - // handle window resize - var clientWidth = 0; - addResize(function() { - if (!viewport) return; - var i, wider = (clientWidth < viewport.clientWidth); - clientWidth = viewport.clientWidth; - // resize elements with "min-width" set - var elements = layout.minWidth.elements; - for (i in elements) { - var element = elements[i]; - var fixedWidth = (parseInt(element.runtimeStyle.width) === getFixedWidth(element, element.currentStyle.minWidth)); - if (wider && fixedWidth) element.runtimeStyle.width = ""; - if (wider == fixedWidth) resizeWidth(element); - } - // resize elements with "max-width" set - var elements = layout.maxWidth.elements; - for (i in elements) { - var element = elements[i]; - var fixedWidth = (parseInt(element.runtimeStyle.width) === getFixedWidth(element, element.currentStyle.maxWidth)); - if (!wider && fixedWidth) element.runtimeStyle.width = ""; - if (wider !== fixedWidth) resizeWidth(element); - } - // resize elements with "right" set - for (i in fixRight.elements) resizeRight(fixRight.elements[i]); - }); - - // ----------------------------------------------------------------------- - // fix CSS - // ----------------------------------------------------------------------- - if (MSIE5) { - IE7.CSS.addRecalc("width", NUMERIC, apply.Width); - } - if (appVersion < 7) { - IE7.CSS.addRecalc("max-width", NUMERIC, layout.maxWidth); - IE7.CSS.addRecalc("right", NUMERIC, fixRight); - } else if (appVersion == 7) { - if (HEIGHT) IE7.CSS.addRecalc("height", "[\\d.]+%", function(element) { - element.runtimeStyle.pixelHeight = parseInt(layoutWidth(element) * element.currentStyle["ie7-height"].slice(0, -1) / 100); - }); - } - }; - - eval("var _fixHeight=" + rotate(_fixWidth)); - - // apply box-model + min/max fixes - _fixWidth(); - _fixHeight(true); - - if (appVersion < 7) { - IE7.CSS.addRecalc("min-width", NUMERIC, layout.minWidth); - IE7.CSS.addFix(/\bmin-height\s*/, "height"); - } -})(); - -// ========================================================================= -// ie7-graphics.js -// ========================================================================= - -// a small transparent image used as a placeholder -var BLANK_GIF = makePath("blank.gif", path); - -var ALPHA_IMAGE_LOADER = "DXImageTransform.Microsoft.AlphaImageLoader"; -var PNG_FILTER = "progid:" + ALPHA_IMAGE_LOADER + "(src='%1',sizingMethod='%2')"; - -// regular expression version of the above -var PNG; - -var filtered = []; - -function fixImage(element) { - if (PNG.test(element.src)) { - // we have to preserve width and height - var image = new Image(element.width, element.height); - image.onload = function() { - element.width = image.width; - element.height = image.height; - image = null; - }; - image.src = element.src; - // store the original url (we'll put it back when it's printed) - element.pngSrc = element.src; - // add the AlphaImageLoader thingy - addFilter(element); - } -}; - -if (appVersion < 7) { - // ** IE7 VARIABLE - // e.g. apply the hack to all files ending in ".png" - // IE7_PNG_SUFFIX = ".png"; - // You can also set it to a RegExp - // IE7_PNG_SUFFIX = /\d+\.png$/; - - // replace background(-image): url(..) .. with background(-image): .. ;filter: ..; - IE7.CSS.addFix(/background(-image)?\s*:\s*([^};]*)?url\(([^\)]+)\)([^;}]*)?/, function(match, $1, $2, url, $4) { - url = getString(url); - return PNG.test(url) ? "filter:" + format(PNG_FILTER, url, $4.indexOf("no-repeat") === -1 ? "scale" : "crop") + - ";zoom:1;background" + ($1||"") + ":" + ($2||"") + "none" + ($4||"") : match; - }); - - // list-style-image - IE7.CSS.addRecalc(/list\-style(\-image)?/, "[^};]*url", function(element) { - var url = element.currentStyle.listStyleImage.slice(5, -2); - if (PNG.test(url)) { - if (element.nodeName === "LI") { - fixListStyleImage(element, url) - } else if (element.nodeName === "UL") { - for (var i = 0, li; li = element.childNodes[i]; i++) { - if (li.nodeName === "LI") fixListStyleImage(li, url); - } - } - } - }); - - function fixListStyleImage(element, src) { - var style = element.runtimeStyle; - var originalHeight = element.offsetHeight; - var image = new Image; - image.onload = function() { - var paddingLeft = element.currentStyle.paddingLeft; - paddingLeft = paddingLeft === "0px" ? 0 : getPixelValue(element, paddingLeft); - style.paddingLeft = (paddingLeft + this.width) + "px"; - style.marginLeft = -this.width + "px"; - style.listStyleType = "none"; - style.listStyleImage = "none"; - style.paddingTop = Math.max(originalHeight - element.offsetHeight, 0) + "px"; - addFilter(element, "crop", src); - element.style.zoom = "100%"; - }; - image.src = src; - }; - - // ----------------------------------------------------------------------- - // fix PNG transparency (HTML images) - // ----------------------------------------------------------------------- - - IE7.HTML.addRecalc("img,input", function(element) { - if (element.nodeName === "INPUT" && element.type !== "image") return; - fixImage(element); - addEventHandler(element, "onpropertychange", function() { - if (!printing && event.propertyName === "src" && - element.src.indexOf(BLANK_GIF) === -1) fixImage(element); - }); - }); - - // assume that background images should not be printed - // (if they are not transparent then they'll just obscure content) - // but we'll put foreground images back... - var printing = false; - addEventHandler(window, "onbeforeprint", function() { - printing = true; - for (var i = 0; i < filtered.length; i++) removeFilter(filtered[i]); - }); - addEventHandler(window, "onafterprint", function() { - for (var i = 0; i < filtered.length; i++) addFilter(filtered[i]); - printing = false; - }); -} - -// apply a filter -function addFilter(element, sizingMethod, src) { - var filter = element.filters[ALPHA_IMAGE_LOADER]; - if (filter) { - filter.src = src || element.src; - filter.enabled = true; - } else { - element.runtimeStyle.filter = format(PNG_FILTER, src || element.src, sizingMethod || "scale"); - filtered.push(element); - } - // remove the real image - element.src = BLANK_GIF; -}; - -function removeFilter(element) { - element.src = element.pngSrc; - element.filters[ALPHA_IMAGE_LOADER].enabled = false; -}; - -// ========================================================================= -// ie7-fixed.js -// ========================================================================= - -(function() { - if (appVersion >= 7) return; - - // some things to consider for this hack. - // the document body requires a fixed background. even if - // it is just a blank image. - // you have to use setExpression instead of onscroll, this - // together with a fixed body background helps avoid the - // annoying screen flicker of other solutions. - - IE7.CSS.addRecalc("position", "fixed", _positionFixed, "absolute"); - IE7.CSS.addRecalc("background(-attachment)?", "[^};]*fixed", _backgroundFixed); - - // scrolling is relative to the documentElement (HTML tag) when in - // standards mode, otherwise it's relative to the document body - var $viewport = MSIE5 ? "body" : "documentElement"; - - function _fixBackground() { - // this is required by both position:fixed and background-attachment:fixed. - // it is necessary for the document to also have a fixed background image. - // we can fake this with a blank image if necessary - if (body.currentStyle.backgroundAttachment !== "fixed") { - if (body.currentStyle.backgroundImage === "none") { - body.runtimeStyle.backgroundRepeat = "no-repeat"; - body.runtimeStyle.backgroundImage = "url(" + BLANK_GIF + ")"; // dummy - } - body.runtimeStyle.backgroundAttachment = "fixed"; - } - _fixBackground = Undefined; - }; - - var _tmp = createTempElement("img"); - - function _isFixed(element) { - return element ? isFixed(element) || _isFixed(element.parentElement) : false; - }; - - function _setExpression(element, propertyName, expression) { - setTimeout("document.all." + element.uniqueID + ".runtimeStyle.setExpression('" + propertyName + "','" + expression + "')", 0); - }; - - // ----------------------------------------------------------------------- - // backgroundAttachment: fixed - // ----------------------------------------------------------------------- - - function _backgroundFixed(element) { - if (register(_backgroundFixed, element, element.currentStyle.backgroundAttachment === "fixed" && !element.contains(body))) { - _fixBackground(); - util.bgLeft(element); - util.bgTop(element); - _backgroundPosition(element); - } - }; - - function _backgroundPosition(element) { - _tmp.src = element.currentStyle.backgroundImage.slice(5, -2); - var parentElement = element.canHaveChildren ? element : element.parentElement; - parentElement.appendChild(_tmp); - util.setOffsetLeft(element); - util.setOffsetTop(element); - parentElement.removeChild(_tmp); - }; - - // ----------------------------------------------------------------------- - // position: fixed - // ----------------------------------------------------------------------- - - function _positionFixed(element) { - if (register(_positionFixed, element, isFixed(element))) { - setOverrideStyle(element, "position", "absolute"); - setOverrideStyle(element, "left", element.currentStyle.left); - setOverrideStyle(element, "top", element.currentStyle.top); - _fixBackground(); - IE7.Layout.fixRight(element); - //IE7.Layout.fixBottom(element); - _foregroundPosition(element); - } - }; - - function _foregroundPosition(element, recalc) { - document.body.getBoundingClientRect(); // force a reflow - util.positionTop(element, recalc); - util.positionLeft(element, recalc, true); - if (!element.runtimeStyle.autoLeft && element.currentStyle.marginLeft === "auto" && - element.currentStyle.right !== "auto") { - var left = viewport.clientWidth - util.getPixelWidth(element, element.currentStyle.right) - - util.getPixelWidth(element, element.runtimeStyle._left) - element.clientWidth; - if (element.currentStyle.marginRight === "auto") left = parseInt(left / 2); - if (_isFixed(element.offsetParent)) element.runtimeStyle.pixelLeft += left; - else element.runtimeStyle.shiftLeft = left; - } - if (!element.runtimeStyle.fixedWidth) util.clipWidth(element); - if (!element.runtimeStyle.fixedHeight) util.clipHeight(element); - }; - - // ----------------------------------------------------------------------- - // capture window resize - // ----------------------------------------------------------------------- - - function _resize() { - // if the window has been resized then some positions need to be - // recalculated (especially those aligned to "right" or "top" - var elements = _backgroundFixed.elements; - for (var i in elements) _backgroundPosition(elements[i]); - elements = _positionFixed.elements; - for (i in elements) { - _foregroundPosition(elements[i], true); - _foregroundPosition(elements[i], true); - } - _timer = 0; - }; - - // use a timer (sometimes this is a good way to prevent resize loops) - var _timer; - addResize(function() { - if (!_timer) _timer = setTimeout(_resize, 100); - }); - - // ----------------------------------------------------------------------- - // rotated - // ----------------------------------------------------------------------- - - var util = {}; - - var _horizontal = function(util) { - util.bgLeft = function(element) { - element.style.backgroundPositionX = element.currentStyle.backgroundPositionX; - if (!_isFixed(element)) { - _setExpression(element, "backgroundPositionX", "(parseInt(runtimeStyle.offsetLeft)+document." + $viewport + ".scrollLeft)||0"); - } - }; - - util.setOffsetLeft = function(element) { - var propertyName = _isFixed(element) ? "backgroundPositionX" : "offsetLeft"; - element.runtimeStyle[propertyName] = - util.getOffsetLeft(element, element.style.backgroundPositionX) - - element.getBoundingClientRect().left - element.clientLeft + 2; - }; - - util.getOffsetLeft = function(element, position) { - switch (position) { - case "left": - case "top": - return 0; - case "right": - case "bottom": - return viewport.clientWidth - _tmp.offsetWidth; - case "center": - return (viewport.clientWidth - _tmp.offsetWidth) / 2; - default: - if (PERCENT.test(position)) { - return parseInt((viewport.clientWidth - _tmp.offsetWidth) * parseFloat(position) / 100); - } - _tmp.style.left = position; - return _tmp.offsetLeft; - } - }; - - util.clipWidth = function(element) { - var fixWidth = element.runtimeStyle.fixWidth; - element.runtimeStyle.borderRightWidth = ""; - element.runtimeStyle.width = fixWidth ? util.getPixelWidth(element, fixWidth) + "px" : ""; - if (element.currentStyle.width !== "auto") { - var rect = element.getBoundingClientRect(); - var width = element.offsetWidth - viewport.clientWidth + rect.left - 2; - if (width >= 0) { - element.runtimeStyle.borderRightWidth = "0px"; - width = Math.max(getPixelValue(element, element.currentStyle.width) - width, 0); - setOverrideStyle(element, "width", width); - return width; - } - } - }; - - util.positionLeft = function(element, recalc) { - // if the element's width is in % units then it must be recalculated - // with respect to the viewport - if (!recalc && PERCENT.test(element.currentStyle.width)) { - element.runtimeStyle.fixWidth = element.currentStyle.width; - } - if (element.runtimeStyle.fixWidth) { - element.runtimeStyle.width = util.getPixelWidth(element, element.runtimeStyle.fixWidth); - } - //if (recalc) { - // // if the element is fixed on the right then no need to recalculate - // if (!element.runtimeStyle.autoLeft) return; - //} else { - element.runtimeStyle.shiftLeft = 0; - element.runtimeStyle._left = element.currentStyle.left; - // is the element fixed on the right? - element.runtimeStyle.autoLeft = element.currentStyle.right !== "auto" && element.currentStyle.left === "auto"; - //} - // reset the element's "left" value and get it's natural position - element.runtimeStyle.left = ""; - element.runtimeStyle.screenLeft = util.getScreenLeft(element); - element.runtimeStyle.pixelLeft = element.runtimeStyle.screenLeft; - // if the element is contained by another fixed element then there is no need to - // continually recalculate it's left position - if (!recalc && !_isFixed(element.offsetParent)) { - // onsrcoll produces jerky movement, so we use an expression - _setExpression(element, "pixelLeft", "runtimeStyle.screenLeft+runtimeStyle.shiftLeft+document." + $viewport + ".scrollLeft"); - } - }; - - // I've forgotten how this works... - util.getScreenLeft = function(element) { // thanks to kevin newman (captainn) - var screenLeft = element.offsetLeft, nested = 1; - if (element.runtimeStyle.autoLeft) { - screenLeft = viewport.clientWidth - element.offsetWidth - util.getPixelWidth(element, element.currentStyle.right); - } - // accommodate margins - if (element.currentStyle.marginLeft !== "auto") { - screenLeft -= util.getPixelWidth(element, element.currentStyle.marginLeft); - } - while (element = element.offsetParent) { - if (element.currentStyle.position !== "static") nested = -1; - screenLeft += element.offsetLeft * nested; - } - return screenLeft; - }; - - util.getPixelWidth = function(element, value) { - return PERCENT.test(value) ? parseInt(parseFloat(value) / 100 * viewport.clientWidth) : getPixelValue(element, value); - }; - }; - eval("var _vertical=" + rotate(_horizontal)); - _horizontal(util); - _vertical(util); -})(); - -// ========================================================================= -// ie7-oveflow.js -// ========================================================================= - -/* --------------------------------------------------------------------- - - This module alters the structure of the document. - It may adversely affect other CSS rules. Be warned. - ---------------------------------------------------------------------- */ - -if (appVersion < 7) { - var WRAPPER_STYLE = { - backgroundColor: "transparent", - backgroundImage: "none", - backgroundPositionX: null, - backgroundPositionY: null, - backgroundRepeat: null, - borderTopWidth: 0, - borderRightWidth: 0, - borderBottomWidth: 0, - borderLeftStyle: "none", - borderTopStyle: "none", - borderRightStyle: "none", - borderBottomStyle: "none", - borderLeftWidth: 0, - borderLeftColor: "#000", - borderTopColor: "#000", - borderRightColor: "#000", - borderBottomColor: "#000", - height: null, - marginTop: 0, - marginBottom: 0, - marginRight: 0, - marginLeft: 0, - width: "100%" - }; - - IE7.CSS.addRecalc("overflow", "visible", function(element) { - if (element.currentStyle.position === "absolute") return; - - // don't do this again - if (element.parentNode.ie7_wrapped) return; - - // if max-height is applied, makes sure it gets applied first - if (IE7.Layout && element.currentStyle["max-height"] !== "auto") { - IE7.Layout.maxHeight(element); - } - - if (element.currentStyle.marginLeft === "auto") element.style.marginLeft = 0; - if (element.currentStyle.marginRight === "auto") element.style.marginRight = 0; - - var wrapper = document.createElement(ANON); - wrapper.ie7_wrapped = element; - for (var propertyName in WRAPPER_STYLE) { - wrapper.style[propertyName] = element.currentStyle[propertyName]; - if (WRAPPER_STYLE[propertyName] != null) { - element.runtimeStyle[propertyName] = WRAPPER_STYLE[propertyName]; - } - } - wrapper.style.display = "block"; - wrapper.style.position = "relative"; - element.runtimeStyle.position = "absolute"; - element.parentNode.insertBefore(wrapper, element); - wrapper.appendChild(element); - }); -} - -// ========================================================================= -// ie7-quirks.js -// ========================================================================= - -function ie7Quirks() { - var FONT_SIZES = "xx-small,x-small,small,medium,large,x-large,xx-large".split(","); - for (var i = 0; i < FONT_SIZES.length; i++) { - FONT_SIZES[FONT_SIZES[i]] = FONT_SIZES[i - 1] || "0.67em"; - } - - IE7.CSS.addFix(/(font(-size)?\s*:\s*)([\w.-]+)/, function(match, label, size, value) { - return label + (FONT_SIZES[value] || value); - }); - - var NEGATIVE = /^\-/, LENGTH = /(em|ex)$/i; - var EM = /em$/i, EX = /ex$/i; - - getPixelValue = function(element, value) { - if (PIXEL.test(value)) return parseInt(value)||0; - var scale = NEGATIVE.test(value)? -1 : 1; - if (LENGTH.test(value)) scale *= getFontScale(element); - temp.style.width = scale < 0 ? value.slice(1) : value; - body.appendChild(temp); - // retrieve pixel width - value = scale * temp.offsetWidth; - // remove the temporary element - temp.removeNode(); - return parseInt(value); - }; - - var temp = createTempElement(); - function getFontScale(element) { - var scale = 1; - temp.style.fontFamily = element.currentStyle.fontFamily; - temp.style.lineHeight = element.currentStyle.lineHeight; - //temp.style.fontSize = ""; - while (element != body) { - var fontSize = element.currentStyle["ie7-font-size"]; - if (fontSize) { - if (EM.test(fontSize)) scale *= parseFloat(fontSize); - else if (PERCENT.test(fontSize)) scale *= (parseFloat(fontSize) / 100); - else if (EX.test(fontSize)) scale *= (parseFloat(fontSize) / 2); - else { - temp.style.fontSize = fontSize; - return 1; - } - } - element = element.parentElement; - } - return scale; - }; - - // cursor:pointer (IE5.x) - IE7.CSS.addFix(/cursor\s*:\s*pointer/, "cursor:hand"); - // display:list-item (IE5.x) - IE7.CSS.addFix(/display\s*:\s*list-item/, "display:block"); - - // ----------------------------------------------------------------------- - // margin:auto - // ----------------------------------------------------------------------- - - function fixMargin(element) { - var parent = element.parentElement; - var margin = parent.offsetWidth - element.offsetWidth - getPaddingWidth(parent); - var autoRight = (element.currentStyle["ie7-margin"] && element.currentStyle.marginRight === "auto") || - element.currentStyle["ie7-margin-right"] === "auto"; - switch (parent.currentStyle.textAlign) { - case "right": - margin = autoRight ? parseInt(margin / 2) : 0; - element.runtimeStyle.marginRight = margin + "px"; - break; - case "center": - if (autoRight) margin = 0; - default: - if (autoRight) margin /= 2; - element.runtimeStyle.marginLeft = parseInt(margin) + "px"; - } - }; - - function getPaddingWidth(element) { - return getPixelValue(element, element.currentStyle.paddingLeft) + - getPixelValue(element, element.currentStyle.paddingRight); - }; - - IE7.CSS.addRecalc("margin(-left|-right)?", "[^};]*auto", function(element) { - if (register(fixMargin, element, - element.parentElement && - element.currentStyle.display === "block" && - element.currentStyle.marginLeft === "auto" && - element.currentStyle.position !== "absolute")) { - fixMargin(element); - } - }); - - addResize(function() { - for (var i in fixMargin.elements) { - var element = fixMargin.elements[i]; - element.runtimeStyle.marginLeft = - element.runtimeStyle.marginRight = ""; - fixMargin(element); - } - }); -}; - - -// ========================================================================= -// ie8-css.js -// ========================================================================= - -var BRACKETS = "\\([^)]+\\)"; - -// pseudo-elements can be declared with a double colon -encoder.add(/::(before|after)/, ":$1"); - -if (appVersion < 8) { - - if (IE7.CSS.pseudoClasses) IE7.CSS.pseudoClasses += "|"; - IE7.CSS.pseudoClasses += "before|after|lang" + BRACKETS; - - // ----------------------------------------------------------------------- - // propertyName: inherit; - // ----------------------------------------------------------------------- - - function parseInherited(cssText) { - return cssText.replace(new RegExp("([{;\\s])(" + inheritedProperties.join("|") + ")\\s*:\\s*([^;}]+)", "g"), "$1$2:$3;ie7-$2:$3"); - }; - - var INHERITED = /[\w-]+\s*:\s*inherit/g; - var STRIP_IE7_FLAGS = /ie7\-|\s*:\s*inherit/g; - var DASH_LOWER = /\-([a-z])/g; - function toUpper(match, chr) {return chr.toUpperCase()}; - - IE7.CSS.addRecalc("[\\w-]+", "inherit", function(element, cssText) { - if (element.parentElement) { - var inherited = cssText.match(INHERITED); - for (var i = 0; i < inherited.length; i++) { - var propertyName = inherited[i].replace(STRIP_IE7_FLAGS, ""); - if (element.currentStyle["ie7-" + propertyName] === "inherit") { - propertyName = propertyName.replace(DASH_LOWER, toUpper); - element.runtimeStyle[propertyName] = element.parentElement.currentStyle[propertyName]; - } - } - } - }, function(match) { - inheritedProperties.push(rescape(match.slice(1).split(":")[0])); - return match; - }); - - // ----------------------------------------------------------------------- - // dynamic pseudo-classes - // ----------------------------------------------------------------------- - - var Focus = new DynamicPseudoClass("focus", function(element) { - var instance = arguments; - - IE7.CSS.addEventHandler(element, "onfocus", function() { - Focus.unregister(instance); // in case it starts with focus - Focus.register(instance); - }); - - IE7.CSS.addEventHandler(element, "onblur", function() { - Focus.unregister(instance); - }); - - // check the active element for initial state - if (element == document.activeElement) { - Focus.register(instance) - } - }); - - var Active = new DynamicPseudoClass("active", function(element) { - var instance = arguments; - IE7.CSS.addEventHandler(element, "onmousedown", function() { - Active.register(instance); - }); - }); - - // globally trap the mouseup event (thanks Martijn!) - addEventHandler(document, "onmouseup", function() { - var instances = Active.instances; - for (var i in instances) Active.unregister(instances[i]); - }); - - // ----------------------------------------------------------------------- - // IE7 pseudo elements - // ----------------------------------------------------------------------- - - // constants - var URL = /^url\s*\(\s*([^)]*)\)$/; - var POSITION_MAP = { - before0: "beforeBegin", - before1: "afterBegin", - after0: "afterEnd", - after1: "beforeEnd" - }; - - var PseudoElement = IE7.PseudoElement = Rule.extend({ - constructor: function(selector, position, cssText) { - // initialise object properties - this.position = position; - var content = cssText.match(PseudoElement.CONTENT), match, entity; - if (content) { - content = content[1]; - match = content.split(/\s+/); - for (var i = 0; (entity = match[i]); i++) { - match[i] = /^attr/.test(entity) ? {attr: entity.slice(5, -1)} : - entity.charAt(0) === "'" ? getString(entity) : decode(entity); - } - content = match; - } - this.content = content; - // CSS text needs to be decoded immediately - this.base(selector, decode(cssText)); - }, - - init: function() { - // execute the underlying css query for this class - this.match = cssQuery(this.selector); - for (var i = 0; i < this.match.length; i++) { - var runtimeStyle = this.match[i].runtimeStyle; - if (!runtimeStyle[this.position]) runtimeStyle[this.position] = {cssText:""}; - runtimeStyle[this.position].cssText += ";" + this.cssText; - if (this.content != null) runtimeStyle[this.position].content = this.content; - } - }, - - create: function(target) { - var generated = target.runtimeStyle[this.position]; - if (generated) { - // copy the array of values - var content = [].concat(generated.content || ""); - for (var j = 0; j < content.length; j++) { - if (typeof content[j] == "object") { - content[j] = target.getAttribute(content[j].attr); - } - } - content = content.join(""); - var url = content.match(URL); - var cssText = "overflow:hidden;" + generated.cssText.replace(/'/g, '"'); - var position = POSITION_MAP[this.position + Number(target.canHaveChildren)]; - var id = 'ie7_pseudo' + PseudoElement.count++; - target.insertAdjacentHTML(position, format(PseudoElement.ANON, this.className, id, cssText, url ? "" : content)); - if (url) { - var src = getString(url[1]); - var pseudoElement = document.getElementById(id); - pseudoElement.src = src; - addFilter(pseudoElement, "crop"); - var targetIsFloated = target.currentStyle.styleFloat !== "none"; - if (pseudoElement.currentStyle.display === "inline" || targetIsFloated) { - if (appVersion < 7 && targetIsFloated && target.canHaveChildren) { - target.runtimeStyle.display = "inline"; - target.runtimeStyle.position = "relative"; - pseudoElement.runtimeStyle.position = "absolute"; - } - pseudoElement.style.display = "inline-block"; - if (target.currentStyle.styleFloat !== "none") { - pseudoElement.style.pixelWidth = target.offsetWidth; - } - var image = new Image; - image.onload = function() { - pseudoElement.style.pixelWidth = this.width; - pseudoElement.style.pixelHeight = Math.max(this.height, pseudoElement.offsetHeight); - }; - image.src = src; - } - } - target.runtimeStyle[this.position] = null; - } - }, - - recalc: function() { - if (this.content == null) return; - for (var i = 0; i < this.match.length; i++) { - this.create(this.match[i]); - } - }, - - toString: function() { - return "." + this.className + "{display:inline}"; - } - }, { - CONTENT: /content\s*:\s*([^;]*)(;|$)/, - ANON: "%4", - MATCH: /(.*):(before|after).*/, - - count: 0 - }); - - IE7._getLang = function(element) { - var lang = ""; - while (element && element.nodeType === 1) { - lang = element.lang || element.getAttribute("lang") || ""; - if (lang) break; - element = element.parentNode; - } - return lang; - }; - - FILTER = extend(FILTER, { - ":lang\\(([^)]+)\\)": "((ii=IE7._getLang(e))==='$1'||ii.indexOf('$1-')===0)&&" - }); -} - -// ========================================================================= -// ie8-html.js -// ========================================================================= - -var UNSUCCESSFUL = /^(submit|reset|button)$/; - -// ----------------------------------------------------------------------- -//