diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2142b3afa..b52a7a3c1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.15.0 hooks: - - id: ruff + - id: ruff-check args: [--fix] - id: ruff-format diff --git a/apps/__init__.py b/apps/__init__.py new file mode 100644 index 000000000..0633fe896 --- /dev/null +++ b/apps/__init__.py @@ -0,0 +1 @@ +"""pythondotorg Django applications package.""" diff --git a/banners/__init__.py b/apps/banners/__init__.py similarity index 100% rename from banners/__init__.py rename to apps/banners/__init__.py diff --git a/banners/admin.py b/apps/banners/admin.py similarity index 87% rename from banners/admin.py rename to apps/banners/admin.py index d4ddd21b1..7c32707a9 100644 --- a/banners/admin.py +++ b/apps/banners/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin -from banners.models import Banner +from apps.banners.models import Banner @admin.register(Banner) diff --git a/banners/apps.py b/apps/banners/apps.py similarity index 78% rename from banners/apps.py rename to apps/banners/apps.py index 561dde014..3be8a222c 100644 --- a/banners/apps.py +++ b/apps/banners/apps.py @@ -6,4 +6,5 @@ class BannersAppConfig(AppConfig): """App configuration for the banners app.""" - name = "banners" + name = "apps.banners" + label = "banners" diff --git a/banners/migrations/0001_initial.py b/apps/banners/migrations/0001_initial.py similarity index 100% rename from banners/migrations/0001_initial.py rename to apps/banners/migrations/0001_initial.py diff --git a/banners/migrations/__init__.py b/apps/banners/migrations/__init__.py similarity index 100% rename from banners/migrations/__init__.py rename to apps/banners/migrations/__init__.py diff --git a/banners/models.py b/apps/banners/models.py similarity index 100% rename from banners/models.py rename to apps/banners/models.py diff --git a/templates/banners/banner.html b/apps/banners/templates/banners/banner.html similarity index 100% rename from templates/banners/banner.html rename to apps/banners/templates/banners/banner.html diff --git a/banners/templatetags/__init__.py b/apps/banners/templatetags/__init__.py similarity index 100% rename from banners/templatetags/__init__.py rename to apps/banners/templatetags/__init__.py diff --git a/banners/templatetags/banners.py b/apps/banners/templatetags/banners.py similarity index 95% rename from banners/templatetags/banners.py rename to apps/banners/templatetags/banners.py index a1c334fcd..9aa21b0a5 100644 --- a/banners/templatetags/banners.py +++ b/apps/banners/templatetags/banners.py @@ -3,7 +3,7 @@ from django import template from django.template.loader import render_to_string -from banners.models import Banner +from apps.banners.models import Banner register = template.Library() diff --git a/blogs/__init__.py b/apps/blogs/__init__.py similarity index 100% rename from blogs/__init__.py rename to apps/blogs/__init__.py diff --git a/blogs/admin.py b/apps/blogs/admin.py similarity index 93% rename from blogs/admin.py rename to apps/blogs/admin.py index d150af939..f9b3d55e5 100644 --- a/blogs/admin.py +++ b/apps/blogs/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin from django.core.management import call_command -from blogs.models import BlogEntry, Feed, FeedAggregate +from apps.blogs.models import BlogEntry, Feed, FeedAggregate @admin.register(BlogEntry) diff --git a/blogs/apps.py b/apps/blogs/apps.py similarity index 79% rename from blogs/apps.py rename to apps/blogs/apps.py index 638d729c3..db58f9583 100644 --- a/blogs/apps.py +++ b/apps/blogs/apps.py @@ -6,4 +6,5 @@ class BlogsAppConfig(AppConfig): """App configuration for the blogs app.""" - name = "blogs" + name = "apps.blogs" + label = "blogs" diff --git a/blogs/factories.py b/apps/blogs/factories.py similarity index 93% rename from blogs/factories.py rename to apps/blogs/factories.py index 7ea4231f3..35ed5635a 100644 --- a/blogs/factories.py +++ b/apps/blogs/factories.py @@ -2,7 +2,7 @@ from django.conf import settings -from blogs.models import Feed +from apps.blogs.models import Feed def initial_data(): diff --git a/blogs/management/__init__.py b/apps/blogs/management/__init__.py similarity index 100% rename from blogs/management/__init__.py rename to apps/blogs/management/__init__.py diff --git a/blogs/management/commands/__init__.py b/apps/blogs/management/commands/__init__.py similarity index 100% rename from blogs/management/commands/__init__.py rename to apps/blogs/management/commands/__init__.py diff --git a/blogs/management/commands/update_blogs.py b/apps/blogs/management/commands/update_blogs.py similarity index 86% rename from blogs/management/commands/update_blogs.py rename to apps/blogs/management/commands/update_blogs.py index 7bc91fb5b..f60d4749d 100644 --- a/blogs/management/commands/update_blogs.py +++ b/apps/blogs/management/commands/update_blogs.py @@ -1,8 +1,8 @@ from django.core.management.base import BaseCommand from django.utils.timezone import now -from blogs.models import BlogEntry, Feed, RelatedBlog -from blogs.parser import get_all_entries, update_blog_supernav +from apps.blogs.models import BlogEntry, Feed, RelatedBlog +from apps.blogs.parser import get_all_entries, update_blog_supernav class Command(BaseCommand): diff --git a/blogs/migrations/0001_initial.py b/apps/blogs/migrations/0001_initial.py similarity index 100% rename from blogs/migrations/0001_initial.py rename to apps/blogs/migrations/0001_initial.py diff --git a/blogs/migrations/0002_remove_translations_and_contributors.py b/apps/blogs/migrations/0002_remove_translations_and_contributors.py similarity index 100% rename from blogs/migrations/0002_remove_translations_and_contributors.py rename to apps/blogs/migrations/0002_remove_translations_and_contributors.py diff --git a/blogs/migrations/0003_alter_relatedblog_creator_and_more.py b/apps/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 apps/blogs/migrations/0003_alter_relatedblog_creator_and_more.py diff --git a/blogs/migrations/__init__.py b/apps/blogs/migrations/__init__.py similarity index 100% rename from blogs/migrations/__init__.py rename to apps/blogs/migrations/__init__.py diff --git a/blogs/models.py b/apps/blogs/models.py similarity index 98% rename from blogs/models.py rename to apps/blogs/models.py index f32b51333..407e1d16c 100644 --- a/blogs/models.py +++ b/apps/blogs/models.py @@ -5,7 +5,7 @@ from bs4.element import Comment from django.db import models -from cms.models import ContentManageable +from apps.cms.models import ContentManageable def tag_visible(element): diff --git a/blogs/parser.py b/apps/blogs/parser.py similarity index 95% rename from blogs/parser.py rename to apps/blogs/parser.py index 1f470c525..8f557dd9a 100644 --- a/blogs/parser.py +++ b/apps/blogs/parser.py @@ -6,8 +6,8 @@ from django.conf import settings from django.template.loader import render_to_string -from blogs.models import BlogEntry, Feed -from boxes.models import Box +from apps.blogs.models import BlogEntry, Feed +from apps.boxes.models import Box def get_all_entries(feed_url): diff --git a/templates/blogs/index.html b/apps/blogs/templates/blogs/index.html similarity index 100% rename from templates/blogs/index.html rename to apps/blogs/templates/blogs/index.html diff --git a/templates/blogs/supernav.html b/apps/blogs/templates/blogs/supernav.html similarity index 100% rename from templates/blogs/supernav.html rename to apps/blogs/templates/blogs/supernav.html diff --git a/blogs/templatetags/__init__.py b/apps/blogs/templatetags/__init__.py similarity index 100% rename from blogs/templatetags/__init__.py rename to apps/blogs/templatetags/__init__.py diff --git a/blogs/templatetags/blogs.py b/apps/blogs/templatetags/blogs.py similarity index 93% rename from blogs/templatetags/blogs.py rename to apps/blogs/templatetags/blogs.py index 6b53706a3..4907b4aaa 100644 --- a/blogs/templatetags/blogs.py +++ b/apps/blogs/templatetags/blogs.py @@ -2,7 +2,7 @@ from django import template -from blogs.models import BlogEntry +from apps.blogs.models import BlogEntry register = template.Library() diff --git a/blogs/tests/__init__.py b/apps/blogs/tests/__init__.py similarity index 100% rename from blogs/tests/__init__.py rename to apps/blogs/tests/__init__.py diff --git a/blogs/tests/psf_feed_example.xml b/apps/blogs/tests/psf_feed_example.xml similarity index 99% rename from blogs/tests/psf_feed_example.xml rename to apps/blogs/tests/psf_feed_example.xml index 202f3df2b..94ae984ac 100644 --- a/blogs/tests/psf_feed_example.xml +++ b/apps/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/apps/blogs/tests/test_models.py similarity index 93% rename from blogs/tests/test_models.py rename to apps/blogs/tests/test_models.py index f7c0e80e1..76a129bb2 100644 --- a/blogs/tests/test_models.py +++ b/apps/blogs/tests/test_models.py @@ -1,7 +1,7 @@ from django.test import TestCase from django.utils import timezone -from blogs.models import BlogEntry, Feed +from apps.blogs.models import BlogEntry, Feed class BlogModelTest(TestCase): diff --git a/blogs/tests/test_parser.py b/apps/blogs/tests/test_parser.py similarity index 89% rename from blogs/tests/test_parser.py rename to apps/blogs/tests/test_parser.py index c5da80a4f..1b1a83ae8 100644 --- a/blogs/tests/test_parser.py +++ b/apps/blogs/tests/test_parser.py @@ -1,8 +1,8 @@ import datetime import unittest -from blogs.parser import get_all_entries -from blogs.tests.utils import get_test_rss_path +from apps.blogs.parser import get_all_entries +from apps.blogs.tests.utils import get_test_rss_path class BlogParserTest(unittest.TestCase): diff --git a/blogs/tests/test_templatetags.py b/apps/blogs/tests/test_templatetags.py similarity index 90% rename from blogs/tests/test_templatetags.py rename to apps/blogs/tests/test_templatetags.py index a17bb8226..e04c9cdb3 100644 --- a/blogs/tests/test_templatetags.py +++ b/apps/blogs/tests/test_templatetags.py @@ -3,9 +3,9 @@ from django.test import TestCase from django.utils.timezone import now -from blogs.models import BlogEntry, Feed, FeedAggregate -from blogs.templatetags.blogs import get_latest_blog_entries -from blogs.tests.utils import get_test_rss_path +from apps.blogs.models import BlogEntry, Feed, FeedAggregate +from apps.blogs.templatetags.blogs import get_latest_blog_entries +from apps.blogs.tests.utils import get_test_rss_path class BlogTemplateTagTest(TestCase): diff --git a/blogs/tests/test_views.py b/apps/blogs/tests/test_views.py similarity index 87% rename from blogs/tests/test_views.py rename to apps/blogs/tests/test_views.py index 113beb653..887763d50 100644 --- a/blogs/tests/test_views.py +++ b/apps/blogs/tests/test_views.py @@ -2,8 +2,8 @@ from django.test import TestCase from django.urls import reverse -from blogs.models import BlogEntry, Feed -from blogs.tests.utils import get_test_rss_path +from apps.blogs.models import BlogEntry, Feed +from apps.blogs.tests.utils import get_test_rss_path class BlogViewTest(TestCase): diff --git a/blogs/tests/utils.py b/apps/blogs/tests/utils.py similarity index 100% rename from blogs/tests/utils.py rename to apps/blogs/tests/utils.py diff --git a/blogs/urls.py b/apps/blogs/urls.py similarity index 83% rename from blogs/urls.py rename to apps/blogs/urls.py index 75ed902f3..394d4ce0b 100644 --- a/blogs/urls.py +++ b/apps/blogs/urls.py @@ -2,7 +2,7 @@ from django.urls import path -from blogs import views +from apps.blogs import views urlpatterns = [ path("", views.BlogHome.as_view(), name="blog"), diff --git a/blogs/views.py b/apps/blogs/views.py similarity index 94% rename from blogs/views.py rename to apps/blogs/views.py index 82e0d0171..1750dfc99 100644 --- a/blogs/views.py +++ b/apps/blogs/views.py @@ -2,7 +2,7 @@ from django.views.generic import TemplateView -from blogs.models import BlogEntry +from apps.blogs.models import BlogEntry class BlogHome(TemplateView): diff --git a/boxes/__init__.py b/apps/boxes/__init__.py similarity index 100% rename from boxes/__init__.py rename to apps/boxes/__init__.py diff --git a/boxes/admin.py b/apps/boxes/admin.py similarity index 72% rename from boxes/admin.py rename to apps/boxes/admin.py index 5005f6407..d9525370c 100644 --- a/boxes/admin.py +++ b/apps/boxes/admin.py @@ -2,8 +2,8 @@ from django.contrib import admin -from boxes.models import Box -from cms.admin import ContentManageableModelAdmin +from apps.boxes.models import Box +from apps.cms.admin import ContentManageableModelAdmin @admin.register(Box) diff --git a/boxes/apps.py b/apps/boxes/apps.py similarity index 79% rename from boxes/apps.py rename to apps/boxes/apps.py index 56106baa5..7a0188a68 100644 --- a/boxes/apps.py +++ b/apps/boxes/apps.py @@ -6,4 +6,5 @@ class BoxesAppConfig(AppConfig): """App configuration for the boxes app.""" - name = "boxes" + name = "apps.boxes" + label = "boxes" diff --git a/boxes/factories.py b/apps/boxes/factories.py similarity index 93% rename from boxes/factories.py rename to apps/boxes/factories.py index da63bc3e1..ef58ce6d4 100644 --- a/boxes/factories.py +++ b/apps/boxes/factories.py @@ -7,8 +7,8 @@ from django.conf import settings from factory.django import DjangoModelFactory -from boxes.models import Box -from users.factories import UserFactory +from apps.boxes.models import Box +from apps.users.factories import UserFactory class BoxFactory(DjangoModelFactory): diff --git a/boxes/migrations/0001_initial.py b/apps/boxes/migrations/0001_initial.py similarity index 100% rename from boxes/migrations/0001_initial.py rename to apps/boxes/migrations/0001_initial.py diff --git a/boxes/migrations/0002_auto_20150416_1853.py b/apps/boxes/migrations/0002_auto_20150416_1853.py similarity index 100% rename from boxes/migrations/0002_auto_20150416_1853.py rename to apps/boxes/migrations/0002_auto_20150416_1853.py diff --git a/boxes/migrations/0003_auto_20171101_2138.py b/apps/boxes/migrations/0003_auto_20171101_2138.py similarity index 100% rename from boxes/migrations/0003_auto_20171101_2138.py rename to apps/boxes/migrations/0003_auto_20171101_2138.py diff --git a/boxes/migrations/0004_alter_box_creator_alter_box_last_modified_by.py b/apps/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 apps/boxes/migrations/0004_alter_box_creator_alter_box_last_modified_by.py diff --git a/boxes/migrations/__init__.py b/apps/boxes/migrations/__init__.py similarity index 100% rename from boxes/migrations/__init__.py rename to apps/boxes/migrations/__init__.py diff --git a/boxes/models.py b/apps/boxes/models.py similarity index 95% rename from boxes/models.py rename to apps/boxes/models.py index 80b62a8ab..b70f52a3a 100644 --- a/boxes/models.py +++ b/apps/boxes/models.py @@ -11,7 +11,7 @@ from django.db import models from markupfield.fields import MarkupField -from cms.models import ContentManageable +from apps.cms.models import ContentManageable DEFAULT_MARKUP_TYPE = getattr(settings, "DEFAULT_MARKUP_TYPE", "restructuredtext") diff --git a/boxes/templatetags/__init__.py b/apps/boxes/templatetags/__init__.py similarity index 100% rename from boxes/templatetags/__init__.py rename to apps/boxes/templatetags/__init__.py diff --git a/boxes/templatetags/boxes.py b/apps/boxes/templatetags/boxes.py similarity index 93% rename from boxes/templatetags/boxes.py rename to apps/boxes/templatetags/boxes.py index 9fa54a491..553aae8a8 100644 --- a/boxes/templatetags/boxes.py +++ b/apps/boxes/templatetags/boxes.py @@ -5,7 +5,7 @@ from django import template from django.utils.html import mark_safe -from boxes.models import Box +from apps.boxes.models import Box log = logging.getLogger(__name__) register = template.Library() diff --git a/boxes/tests.py b/apps/boxes/tests.py similarity index 90% rename from boxes/tests.py rename to apps/boxes/tests.py index 2c310f2e2..c0090f3b6 100644 --- a/boxes/tests.py +++ b/apps/boxes/tests.py @@ -3,7 +3,7 @@ from django import template from django.test import TestCase, override_settings -from boxes.models import Box +from apps.boxes.models import Box logging.disable(logging.CRITICAL) @@ -28,7 +28,7 @@ def test_tag_invalid_label(self): class ViewTests(BaseTestCase): - @override_settings(ROOT_URLCONF="boxes.urls") + @override_settings(ROOT_URLCONF="apps.boxes.urls") def test_box_view(self): r = self.client.get("/test/") self.assertContains(r, self.box.content.rendered) diff --git a/boxes/urls.py b/apps/boxes/urls.py similarity index 80% rename from boxes/urls.py rename to apps/boxes/urls.py index b3c5b9c72..90a7ca0a3 100644 --- a/boxes/urls.py +++ b/apps/boxes/urls.py @@ -2,7 +2,7 @@ from django.urls import path -from boxes.views import box +from apps.boxes.views import box urlpatterns = [ path("/", box, name="box"), diff --git a/boxes/views.py b/apps/boxes/views.py similarity index 89% rename from boxes/views.py rename to apps/boxes/views.py index fd3a0f45a..61694ae57 100644 --- a/boxes/views.py +++ b/apps/boxes/views.py @@ -3,7 +3,7 @@ from django.http import HttpResponse from django.shortcuts import get_object_or_404 -from boxes.models import Box +from apps.boxes.models import Box def box(request, label): diff --git a/cms/__init__.py b/apps/cms/__init__.py similarity index 100% rename from cms/__init__.py rename to apps/cms/__init__.py diff --git a/cms/admin.py b/apps/cms/admin.py similarity index 100% rename from cms/admin.py rename to apps/cms/admin.py diff --git a/cms/apps.py b/apps/cms/apps.py similarity index 80% rename from cms/apps.py rename to apps/cms/apps.py index f50fae8db..a4733cb9f 100644 --- a/cms/apps.py +++ b/apps/cms/apps.py @@ -6,4 +6,5 @@ class CmsAppConfig(AppConfig): """App configuration for the cms app.""" - name = "cms" + name = "apps.cms" + label = "cms" diff --git a/cms/forms.py b/apps/cms/forms.py similarity index 100% rename from cms/forms.py rename to apps/cms/forms.py diff --git a/cms/management/__init__.py b/apps/cms/management/__init__.py similarity index 100% rename from cms/management/__init__.py rename to apps/cms/management/__init__.py diff --git a/cms/management/commands/__init__.py b/apps/cms/management/commands/__init__.py similarity index 100% rename from cms/management/commands/__init__.py rename to apps/cms/management/commands/__init__.py diff --git a/cms/management/commands/create_initial_data.py b/apps/cms/management/commands/create_initial_data.py similarity index 100% rename from cms/management/commands/create_initial_data.py rename to apps/cms/management/commands/create_initial_data.py diff --git a/cms/models.py b/apps/cms/models.py similarity index 100% rename from cms/models.py rename to apps/cms/models.py diff --git a/templates/cms/iso_time_tag.html b/apps/cms/templates/cms/iso_time_tag.html similarity index 100% rename from templates/cms/iso_time_tag.html rename to apps/cms/templates/cms/iso_time_tag.html diff --git a/cms/templatetags/__init__.py b/apps/cms/templatetags/__init__.py similarity index 100% rename from cms/templatetags/__init__.py rename to apps/cms/templatetags/__init__.py diff --git a/cms/templatetags/cms.py b/apps/cms/templatetags/cms.py similarity index 100% rename from cms/templatetags/cms.py rename to apps/cms/templatetags/cms.py diff --git a/cms/tests.py b/apps/cms/tests.py similarity index 97% rename from cms/tests.py rename to apps/cms/tests.py index 5a0681043..dc57f828b 100644 --- a/cms/tests.py +++ b/apps/cms/tests.py @@ -5,8 +5,8 @@ from django.template import Context, Template from django.test import TestCase -from cms.admin import ContentManageableModelAdmin -from cms.views import legacy_path +from apps.cms.admin import ContentManageableModelAdmin +from apps.cms.views import legacy_path class ContentManageableAdminTests(unittest.TestCase): diff --git a/cms/views.py b/apps/cms/views.py similarity index 100% rename from cms/views.py rename to apps/cms/views.py diff --git a/codesamples/__init__.py b/apps/codesamples/__init__.py similarity index 100% rename from codesamples/__init__.py rename to apps/codesamples/__init__.py diff --git a/codesamples/admin.py b/apps/codesamples/admin.py similarity index 59% rename from codesamples/admin.py rename to apps/codesamples/admin.py index 91f3edc90..6318333c3 100644 --- a/codesamples/admin.py +++ b/apps/codesamples/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin -from cms.admin import ContentManageableModelAdmin -from codesamples.models import CodeSample +from apps.cms.admin import ContentManageableModelAdmin +from apps.codesamples.models import CodeSample admin.site.register(CodeSample, ContentManageableModelAdmin) diff --git a/codesamples/apps.py b/apps/codesamples/apps.py similarity index 76% rename from codesamples/apps.py rename to apps/codesamples/apps.py index d7a7f3383..42bbe0cae 100644 --- a/codesamples/apps.py +++ b/apps/codesamples/apps.py @@ -6,4 +6,5 @@ class CodesamplesAppConfig(AppConfig): """App configuration for the codesamples app.""" - name = "codesamples" + name = "apps.codesamples" + label = "codesamples" diff --git a/codesamples/factories.py b/apps/codesamples/factories.py similarity index 98% rename from codesamples/factories.py rename to apps/codesamples/factories.py index 0f0176854..654364d7a 100644 --- a/codesamples/factories.py +++ b/apps/codesamples/factories.py @@ -5,8 +5,8 @@ import factory from factory.django import DjangoModelFactory -from codesamples.models import CodeSample -from users.factories import UserFactory +from apps.codesamples.models import CodeSample +from apps.users.factories import UserFactory class CodeSampleFactory(DjangoModelFactory): diff --git a/codesamples/managers.py b/apps/codesamples/managers.py similarity index 100% rename from codesamples/managers.py rename to apps/codesamples/managers.py diff --git a/codesamples/migrations/0001_initial.py b/apps/codesamples/migrations/0001_initial.py similarity index 100% rename from codesamples/migrations/0001_initial.py rename to apps/codesamples/migrations/0001_initial.py diff --git a/codesamples/migrations/0002_auto_20150416_1853.py b/apps/codesamples/migrations/0002_auto_20150416_1853.py similarity index 100% rename from codesamples/migrations/0002_auto_20150416_1853.py rename to apps/codesamples/migrations/0002_auto_20150416_1853.py diff --git a/codesamples/migrations/0003_auto_20170821_2000.py b/apps/codesamples/migrations/0003_auto_20170821_2000.py similarity index 100% rename from codesamples/migrations/0003_auto_20170821_2000.py rename to apps/codesamples/migrations/0003_auto_20170821_2000.py diff --git a/codesamples/migrations/0004_alter_codesample_creator_and_more.py b/apps/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 apps/codesamples/migrations/0004_alter_codesample_creator_and_more.py diff --git a/codesamples/migrations/__init__.py b/apps/codesamples/migrations/__init__.py similarity index 100% rename from codesamples/migrations/__init__.py rename to apps/codesamples/migrations/__init__.py diff --git a/codesamples/models.py b/apps/codesamples/models.py similarity index 90% rename from codesamples/models.py rename to apps/codesamples/models.py index d69df557d..e00bb31a0 100644 --- a/codesamples/models.py +++ b/apps/codesamples/models.py @@ -5,8 +5,8 @@ from django.template.defaultfilters import striptags, truncatechars from markupfield.fields import MarkupField -from cms.models import ContentManageable -from codesamples.managers import CodeSampleQuerySet +from apps.cms.models import ContentManageable +from apps.codesamples.managers import CodeSampleQuerySet DEFAULT_MARKUP_TYPE = getattr(settings, "DEFAULT_MARKUP_TYPE", "html") diff --git a/codesamples/tests.py b/apps/codesamples/tests.py similarity index 92% rename from codesamples/tests.py rename to apps/codesamples/tests.py index 41a42974e..a151253d1 100644 --- a/codesamples/tests.py +++ b/apps/codesamples/tests.py @@ -1,6 +1,6 @@ from django.test import TestCase -from codesamples.models import CodeSample +from apps.codesamples.models import CodeSample class CodeSampleModelTests(TestCase): diff --git a/community/__init__.py b/apps/community/__init__.py similarity index 100% rename from community/__init__.py rename to apps/community/__init__.py diff --git a/community/admin.py b/apps/community/admin.py similarity index 87% rename from community/admin.py rename to apps/community/admin.py index 17a081203..3fa184a5d 100644 --- a/community/admin.py +++ b/apps/community/admin.py @@ -2,8 +2,8 @@ from django.contrib import admin -from cms.admin import ContentManageableModelAdmin, ContentManageableStackedInline -from community.models import Link, Photo, Post, Video +from apps.cms.admin import ContentManageableModelAdmin, ContentManageableStackedInline +from apps.community.models import Link, Photo, Post, Video class LinkInline(ContentManageableStackedInline): diff --git a/community/apps.py b/apps/community/apps.py similarity index 77% rename from community/apps.py rename to apps/community/apps.py index e868cc4fe..bdffa47e2 100644 --- a/community/apps.py +++ b/apps/community/apps.py @@ -6,4 +6,5 @@ class CommunityAppConfig(AppConfig): """App configuration for the community app.""" - name = "community" + name = "apps.community" + label = "community" diff --git a/community/managers.py b/apps/community/managers.py similarity index 100% rename from community/managers.py rename to apps/community/managers.py diff --git a/community/migrations/0001_initial.py b/apps/community/migrations/0001_initial.py similarity index 100% rename from community/migrations/0001_initial.py rename to apps/community/migrations/0001_initial.py diff --git a/community/migrations/0001_squashed_0004_auto_20170831_0541.py b/apps/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 apps/community/migrations/0001_squashed_0004_auto_20170831_0541.py diff --git a/community/migrations/0002_auto_20150416_1853.py b/apps/community/migrations/0002_auto_20150416_1853.py similarity index 100% rename from community/migrations/0002_auto_20150416_1853.py rename to apps/community/migrations/0002_auto_20150416_1853.py diff --git a/community/migrations/0003_auto_20170831_0358.py b/apps/community/migrations/0003_auto_20170831_0358.py similarity index 100% rename from community/migrations/0003_auto_20170831_0358.py rename to apps/community/migrations/0003_auto_20170831_0358.py diff --git a/community/migrations/0004_auto_20170831_0541.py b/apps/community/migrations/0004_auto_20170831_0541.py similarity index 100% rename from community/migrations/0004_auto_20170831_0541.py rename to apps/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/apps/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 apps/community/migrations/0005_alter_link_creator_alter_link_last_modified_by_and_more.py diff --git a/community/migrations/__init__.py b/apps/community/migrations/__init__.py similarity index 100% rename from community/migrations/__init__.py rename to apps/community/migrations/__init__.py diff --git a/community/models.py b/apps/community/models.py similarity index 97% rename from community/models.py rename to apps/community/models.py index c17ceedc9..952765e58 100644 --- a/community/models.py +++ b/apps/community/models.py @@ -6,8 +6,8 @@ from django.utils.translation import gettext_lazy as _ from markupfield.fields import MarkupField -from cms.models import ContentManageable -from community.managers import PostQuerySet +from apps.cms.models import ContentManageable +from apps.community.managers import PostQuerySet DEFAULT_MARKUP_TYPE = "html" diff --git a/templates/community/microbit.html b/apps/community/templates/community/microbit.html similarity index 100% rename from templates/community/microbit.html rename to apps/community/templates/community/microbit.html diff --git a/templates/community/post_detail.html b/apps/community/templates/community/post_detail.html similarity index 100% rename from templates/community/post_detail.html rename to apps/community/templates/community/post_detail.html diff --git a/templates/community/post_list.html b/apps/community/templates/community/post_list.html similarity index 100% rename from templates/community/post_list.html rename to apps/community/templates/community/post_list.html diff --git a/templates/community/types/default.html b/apps/community/templates/community/types/default.html similarity index 100% rename from templates/community/types/default.html rename to apps/community/templates/community/types/default.html diff --git a/templates/community/types/link.html b/apps/community/templates/community/types/link.html similarity index 100% rename from templates/community/types/link.html rename to apps/community/templates/community/types/link.html diff --git a/templates/community/types/photo.html b/apps/community/templates/community/types/photo.html similarity index 100% rename from templates/community/types/photo.html rename to apps/community/templates/community/types/photo.html diff --git a/templates/community/types/text.html b/apps/community/templates/community/types/text.html similarity index 100% rename from templates/community/types/text.html rename to apps/community/templates/community/types/text.html diff --git a/templates/community/types/video.html b/apps/community/templates/community/types/video.html similarity index 100% rename from templates/community/types/video.html rename to apps/community/templates/community/types/video.html diff --git a/community/templatetags/__init__.py b/apps/community/templatetags/__init__.py similarity index 100% rename from community/templatetags/__init__.py rename to apps/community/templatetags/__init__.py diff --git a/community/templatetags/community.py b/apps/community/templatetags/community.py similarity index 100% rename from community/templatetags/community.py rename to apps/community/templatetags/community.py diff --git a/community/tests/__init__.py b/apps/community/tests/__init__.py similarity index 100% rename from community/tests/__init__.py rename to apps/community/tests/__init__.py diff --git a/community/tests/test_managers.py b/apps/community/tests/test_managers.py similarity index 94% rename from community/tests/test_managers.py rename to apps/community/tests/test_managers.py index be22098f9..e7b872144 100644 --- a/community/tests/test_managers.py +++ b/apps/community/tests/test_managers.py @@ -1,6 +1,6 @@ from django.test import TestCase -from community.models import Post +from apps.community.models import Post class CommunityManagersTest(TestCase): diff --git a/community/tests/test_models.py b/apps/community/tests/test_models.py similarity index 91% rename from community/tests/test_models.py rename to apps/community/tests/test_models.py index 62bc7210e..d1b7c8d97 100644 --- a/community/tests/test_models.py +++ b/apps/community/tests/test_models.py @@ -1,6 +1,6 @@ from django.test import TestCase -from community.models import Post +from apps.community.models import Post class ModelTestCase(TestCase): diff --git a/community/tests/test_views.py b/apps/community/tests/test_views.py similarity index 93% rename from community/tests/test_views.py rename to apps/community/tests/test_views.py index c397b4d05..1d2bfb310 100644 --- a/community/tests/test_views.py +++ b/apps/community/tests/test_views.py @@ -1,4 +1,4 @@ -from community.models import Post +from apps.community.models import Post from pydotorg.tests.test_classes import TemplateTestCase diff --git a/community/urls.py b/apps/community/urls.py similarity index 88% rename from community/urls.py rename to apps/community/urls.py index e8a01b33c..ad2d375e5 100644 --- a/community/urls.py +++ b/apps/community/urls.py @@ -2,7 +2,7 @@ from django.urls import path -from community import views +from apps.community import views app_name = "community" urlpatterns = [ diff --git a/community/views.py b/apps/community/views.py similarity index 89% rename from community/views.py rename to apps/community/views.py index 1908d789a..23f9f15a5 100644 --- a/community/views.py +++ b/apps/community/views.py @@ -2,7 +2,7 @@ from django.views.generic import DetailView, ListView -from community.models import Post +from apps.community.models import Post class PostList(ListView): diff --git a/companies/__init__.py b/apps/companies/__init__.py similarity index 100% rename from companies/__init__.py rename to apps/companies/__init__.py diff --git a/companies/admin.py b/apps/companies/admin.py similarity index 78% rename from companies/admin.py rename to apps/companies/admin.py index 3ab08b1a5..95edf7f90 100644 --- a/companies/admin.py +++ b/apps/companies/admin.py @@ -2,8 +2,8 @@ from django.contrib import admin -from cms.admin import NameSlugAdmin -from companies.models import Company +from apps.cms.admin import NameSlugAdmin +from apps.companies.models import Company @admin.register(Company) diff --git a/companies/apps.py b/apps/companies/apps.py similarity index 77% rename from companies/apps.py rename to apps/companies/apps.py index 6dfd8692d..e5ddd6044 100644 --- a/companies/apps.py +++ b/apps/companies/apps.py @@ -6,4 +6,5 @@ class CompaniesAppConfig(AppConfig): """App configuration for the companies app.""" - name = "companies" + name = "apps.companies" + label = "companies" diff --git a/companies/factories.py b/apps/companies/factories.py similarity index 94% rename from companies/factories.py rename to apps/companies/factories.py index fe11e7050..d3ee7220a 100644 --- a/companies/factories.py +++ b/apps/companies/factories.py @@ -3,7 +3,7 @@ import factory from factory.django import DjangoModelFactory -from companies.models import Company +from apps.companies.models import Company class CompanyFactory(DjangoModelFactory): diff --git a/companies/migrations/0001_initial.py b/apps/companies/migrations/0001_initial.py similarity index 100% rename from companies/migrations/0001_initial.py rename to apps/companies/migrations/0001_initial.py diff --git a/companies/migrations/0002_auto_20150416_1853.py b/apps/companies/migrations/0002_auto_20150416_1853.py similarity index 100% rename from companies/migrations/0002_auto_20150416_1853.py rename to apps/companies/migrations/0002_auto_20150416_1853.py diff --git a/companies/migrations/0003_auto_20170814_0301.py b/apps/companies/migrations/0003_auto_20170814_0301.py similarity index 100% rename from companies/migrations/0003_auto_20170814_0301.py rename to apps/companies/migrations/0003_auto_20170814_0301.py diff --git a/companies/migrations/0004_auto_20170821_2000.py b/apps/companies/migrations/0004_auto_20170821_2000.py similarity index 100% rename from companies/migrations/0004_auto_20170821_2000.py rename to apps/companies/migrations/0004_auto_20170821_2000.py diff --git a/companies/migrations/0005_auto_20180705_0352.py b/apps/companies/migrations/0005_auto_20180705_0352.py similarity index 100% rename from companies/migrations/0005_auto_20180705_0352.py rename to apps/companies/migrations/0005_auto_20180705_0352.py diff --git a/companies/migrations/__init__.py b/apps/companies/migrations/__init__.py similarity index 100% rename from companies/migrations/__init__.py rename to apps/companies/migrations/__init__.py diff --git a/companies/models.py b/apps/companies/models.py similarity index 95% rename from companies/models.py rename to apps/companies/models.py index 257f65b03..2d37394ee 100644 --- a/companies/models.py +++ b/apps/companies/models.py @@ -5,7 +5,7 @@ from django.utils.translation import gettext_lazy as _ from markupfield.fields import MarkupField -from cms.models import NameSlugModel +from apps.cms.models import NameSlugModel DEFAULT_MARKUP_TYPE = getattr(settings, "DEFAULT_MARKUP_TYPE", "restructuredtext") diff --git a/companies/templatetags/__init__.py b/apps/companies/templatetags/__init__.py similarity index 100% rename from companies/templatetags/__init__.py rename to apps/companies/templatetags/__init__.py diff --git a/companies/templatetags/companies.py b/apps/companies/templatetags/companies.py similarity index 100% rename from companies/templatetags/companies.py rename to apps/companies/templatetags/companies.py diff --git a/companies/tests.py b/apps/companies/tests.py similarity index 84% rename from companies/tests.py rename to apps/companies/tests.py index 355072b65..8f94a525d 100644 --- a/companies/tests.py +++ b/apps/companies/tests.py @@ -1,6 +1,6 @@ from django.test import TestCase -from companies.templatetags.companies import render_email +from apps.companies.templatetags.companies import render_email class CompaniesTagsTests(TestCase): diff --git a/downloads/__init__.py b/apps/downloads/__init__.py similarity index 100% rename from downloads/__init__.py rename to apps/downloads/__init__.py diff --git a/downloads/admin.py b/apps/downloads/admin.py similarity index 90% rename from downloads/admin.py rename to apps/downloads/admin.py index cae53c297..397631490 100644 --- a/downloads/admin.py +++ b/apps/downloads/admin.py @@ -2,8 +2,8 @@ from django.contrib import admin -from cms.admin import ContentManageableModelAdmin, ContentManageableStackedInline -from downloads.models import OS, Release, ReleaseFile +from apps.cms.admin import ContentManageableModelAdmin, ContentManageableStackedInline +from apps.downloads.models import OS, Release, ReleaseFile @admin.register(OS) diff --git a/downloads/api.py b/apps/downloads/api.py similarity index 96% rename from downloads/api.py rename to apps/downloads/api.py index a705a2c0e..4d8f3010c 100644 --- a/downloads/api.py +++ b/apps/downloads/api.py @@ -7,9 +7,9 @@ from tastypie import fields from tastypie.constants import ALL, ALL_WITH_RELATIONS -from downloads.models import OS, Release, ReleaseFile -from downloads.serializers import OSSerializer, ReleaseFileSerializer, ReleaseSerializer -from pages.api import PageResource +from apps.downloads.models import OS, Release, ReleaseFile +from apps.downloads.serializers import OSSerializer, ReleaseFileSerializer, ReleaseSerializer +from apps.pages.api import PageResource from pydotorg.drf import BaseAPIViewSet, BaseFilterSet, IsStaffOrReadOnly from pydotorg.resources import GenericResource, OnlyPublishedAuthorization diff --git a/downloads/apps.py b/apps/downloads/apps.py similarity index 77% rename from downloads/apps.py rename to apps/downloads/apps.py index afbe21b6f..9773f9a86 100644 --- a/downloads/apps.py +++ b/apps/downloads/apps.py @@ -6,4 +6,5 @@ class DownloadsAppConfig(AppConfig): """Django app configuration for Python downloads.""" - name = "downloads" + name = "apps.downloads" + label = "downloads" diff --git a/downloads/factories.py b/apps/downloads/factories.py similarity index 97% rename from downloads/factories.py rename to apps/downloads/factories.py index 4d1e83cf2..e485d091a 100644 --- a/downloads/factories.py +++ b/apps/downloads/factories.py @@ -6,8 +6,8 @@ import requests from factory.django import DjangoModelFactory -from downloads.models import OS, Release, ReleaseFile -from users.factories import UserFactory +from apps.downloads.models import OS, Release, ReleaseFile +from apps.users.factories import UserFactory class OSFactory(DjangoModelFactory): diff --git a/downloads/managers.py b/apps/downloads/managers.py similarity index 100% rename from downloads/managers.py rename to apps/downloads/managers.py diff --git a/downloads/migrations/0001_initial.py b/apps/downloads/migrations/0001_initial.py similarity index 100% rename from downloads/migrations/0001_initial.py rename to apps/downloads/migrations/0001_initial.py diff --git a/downloads/migrations/0002_auto_20150416_1853.py b/apps/downloads/migrations/0002_auto_20150416_1853.py similarity index 100% rename from downloads/migrations/0002_auto_20150416_1853.py rename to apps/downloads/migrations/0002_auto_20150416_1853.py diff --git a/downloads/migrations/0003_auto_20150824_1612.py b/apps/downloads/migrations/0003_auto_20150824_1612.py similarity index 100% rename from downloads/migrations/0003_auto_20150824_1612.py rename to apps/downloads/migrations/0003_auto_20150824_1612.py diff --git a/downloads/migrations/0004_auto_20170821_2000.py b/apps/downloads/migrations/0004_auto_20170821_2000.py similarity index 100% rename from downloads/migrations/0004_auto_20170821_2000.py rename to apps/downloads/migrations/0004_auto_20170821_2000.py diff --git a/downloads/migrations/0005_move_release_page_content.py b/apps/downloads/migrations/0005_move_release_page_content.py similarity index 100% rename from downloads/migrations/0005_move_release_page_content.py rename to apps/downloads/migrations/0005_move_release_page_content.py diff --git a/downloads/migrations/0006_auto_20180705_0352.py b/apps/downloads/migrations/0006_auto_20180705_0352.py similarity index 100% rename from downloads/migrations/0006_auto_20180705_0352.py rename to apps/downloads/migrations/0006_auto_20180705_0352.py diff --git a/downloads/migrations/0007_auto_20220809_1655.py b/apps/downloads/migrations/0007_auto_20220809_1655.py similarity index 100% rename from downloads/migrations/0007_auto_20220809_1655.py rename to apps/downloads/migrations/0007_auto_20220809_1655.py diff --git a/downloads/migrations/0008_auto_20220907_2102.py b/apps/downloads/migrations/0008_auto_20220907_2102.py similarity index 100% rename from downloads/migrations/0008_auto_20220907_2102.py rename to apps/downloads/migrations/0008_auto_20220907_2102.py diff --git a/downloads/migrations/0009_releasefile_sigstore_bundle_file.py b/apps/downloads/migrations/0009_releasefile_sigstore_bundle_file.py similarity index 100% rename from downloads/migrations/0009_releasefile_sigstore_bundle_file.py rename to apps/downloads/migrations/0009_releasefile_sigstore_bundle_file.py diff --git a/downloads/migrations/0010_releasefile_sbom_spdx2_file.py b/apps/downloads/migrations/0010_releasefile_sbom_spdx2_file.py similarity index 100% rename from downloads/migrations/0010_releasefile_sbom_spdx2_file.py rename to apps/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/apps/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 apps/downloads/migrations/0011_alter_os_creator_alter_os_last_modified_by_and_more.py diff --git a/downloads/migrations/0012_alter_release_version.py b/apps/downloads/migrations/0012_alter_release_version.py similarity index 100% rename from downloads/migrations/0012_alter_release_version.py rename to apps/downloads/migrations/0012_alter_release_version.py diff --git a/downloads/migrations/0013_alter_release_content_markup_type.py b/apps/downloads/migrations/0013_alter_release_content_markup_type.py similarity index 100% rename from downloads/migrations/0013_alter_release_content_markup_type.py rename to apps/downloads/migrations/0013_alter_release_content_markup_type.py diff --git a/downloads/migrations/0014_releasefile_sha256_sum.py b/apps/downloads/migrations/0014_releasefile_sha256_sum.py similarity index 100% rename from downloads/migrations/0014_releasefile_sha256_sum.py rename to apps/downloads/migrations/0014_releasefile_sha256_sum.py diff --git a/downloads/migrations/__init__.py b/apps/downloads/migrations/__init__.py similarity index 100% rename from downloads/migrations/__init__.py rename to apps/downloads/migrations/__init__.py diff --git a/downloads/models.py b/apps/downloads/models.py similarity index 98% rename from downloads/models.py rename to apps/downloads/models.py index 90f77089b..c73a34f29 100644 --- a/downloads/models.py +++ b/apps/downloads/models.py @@ -12,11 +12,11 @@ from django.utils import timezone from markupfield.fields import MarkupField -from boxes.models import Box -from cms.models import ContentManageable, NameSlugModel -from downloads.managers import ReleaseManager +from apps.boxes.models import Box +from apps.cms.models import ContentManageable, NameSlugModel +from apps.downloads.managers import ReleaseManager +from apps.pages.models import Page from fastly.utils import purge_url -from pages.models import Page DEFAULT_MARKUP_TYPE = getattr(settings, "DEFAULT_MARKUP_TYPE", "markdown") diff --git a/downloads/search_indexes.py b/apps/downloads/search_indexes.py similarity index 98% rename from downloads/search_indexes.py rename to apps/downloads/search_indexes.py index ba61601af..c56dc1e06 100644 --- a/downloads/search_indexes.py +++ b/apps/downloads/search_indexes.py @@ -6,7 +6,7 @@ from django.utils import timezone from haystack import indexes -from downloads.models import Release +from apps.downloads.models import Release class ReleaseIndex(indexes.SearchIndex, indexes.Indexable): diff --git a/downloads/serializers.py b/apps/downloads/serializers.py similarity index 96% rename from downloads/serializers.py rename to apps/downloads/serializers.py index 4a06d2a3c..14e74ef06 100644 --- a/downloads/serializers.py +++ b/apps/downloads/serializers.py @@ -2,7 +2,7 @@ from rest_framework import serializers -from downloads.models import OS, Release, ReleaseFile +from apps.downloads.models import OS, Release, ReleaseFile class OSSerializer(serializers.HyperlinkedModelSerializer): diff --git a/templates/downloads/active-releases.html b/apps/downloads/templates/downloads/active-releases.html similarity index 100% rename from templates/downloads/active-releases.html rename to apps/downloads/templates/downloads/active-releases.html diff --git a/templates/downloads/base.html b/apps/downloads/templates/downloads/base.html similarity index 100% rename from templates/downloads/base.html rename to apps/downloads/templates/downloads/base.html diff --git a/templates/downloads/download-sources-box.html b/apps/downloads/templates/downloads/download-sources-box.html similarity index 100% rename from templates/downloads/download-sources-box.html rename to apps/downloads/templates/downloads/download-sources-box.html diff --git a/templates/downloads/full_os_list.html b/apps/downloads/templates/downloads/full_os_list.html similarity index 100% rename from templates/downloads/full_os_list.html rename to apps/downloads/templates/downloads/full_os_list.html diff --git a/templates/downloads/homepage-downloads-box.html b/apps/downloads/templates/downloads/homepage-downloads-box.html similarity index 100% rename from templates/downloads/homepage-downloads-box.html rename to apps/downloads/templates/downloads/homepage-downloads-box.html diff --git a/templates/downloads/index.html b/apps/downloads/templates/downloads/index.html similarity index 100% rename from templates/downloads/index.html rename to apps/downloads/templates/downloads/index.html diff --git a/templates/downloads/os_list.html b/apps/downloads/templates/downloads/os_list.html similarity index 100% rename from templates/downloads/os_list.html rename to apps/downloads/templates/downloads/os_list.html diff --git a/templates/downloads/release_detail.html b/apps/downloads/templates/downloads/release_detail.html similarity index 100% rename from templates/downloads/release_detail.html rename to apps/downloads/templates/downloads/release_detail.html diff --git a/templates/downloads/release_edit_button.html b/apps/downloads/templates/downloads/release_edit_button.html similarity index 100% rename from templates/downloads/release_edit_button.html rename to apps/downloads/templates/downloads/release_edit_button.html diff --git a/templates/downloads/supernav.html b/apps/downloads/templates/downloads/supernav.html similarity index 100% rename from templates/downloads/supernav.html rename to apps/downloads/templates/downloads/supernav.html diff --git a/downloads/templatetags/__init__.py b/apps/downloads/templatetags/__init__.py similarity index 100% rename from downloads/templatetags/__init__.py rename to apps/downloads/templatetags/__init__.py diff --git a/downloads/templatetags/download_tags.py b/apps/downloads/templatetags/download_tags.py similarity index 99% rename from downloads/templatetags/download_tags.py rename to apps/downloads/templatetags/download_tags.py index 8dbaf1fca..8a0830360 100644 --- a/downloads/templatetags/download_tags.py +++ b/apps/downloads/templatetags/download_tags.py @@ -9,7 +9,7 @@ from django.utils.html import format_html from django.utils.safestring import mark_safe -from downloads.models import Release +from apps.downloads.models import Release register = template.Library() logger = logging.getLogger(__name__) diff --git a/downloads/tests/__init__.py b/apps/downloads/tests/__init__.py similarity index 100% rename from downloads/tests/__init__.py rename to apps/downloads/tests/__init__.py diff --git a/downloads/tests/base.py b/apps/downloads/tests/base.py similarity index 97% rename from downloads/tests/base.py rename to apps/downloads/tests/base.py index eda297100..18005aaa5 100644 --- a/downloads/tests/base.py +++ b/apps/downloads/tests/base.py @@ -2,8 +2,8 @@ from django.test import TestCase -from downloads.models import OS, Release, ReleaseFile -from pages.models import Page +from apps.downloads.models import OS, Release, ReleaseFile +from apps.pages.models import Page class DownloadMixin: diff --git a/downloads/tests/test_models.py b/apps/downloads/tests/test_models.py similarity index 96% rename from downloads/tests/test_models.py rename to apps/downloads/tests/test_models.py index c5af33bd0..3a45e1d39 100644 --- a/downloads/tests/test_models.py +++ b/apps/downloads/tests/test_models.py @@ -1,7 +1,7 @@ import datetime as dt -from downloads.models import Release, ReleaseFile -from downloads.tests.base import BaseDownloadTests +from apps.downloads.models import Release, ReleaseFile +from apps.downloads.tests.base import BaseDownloadTests class DownloadModelTests(BaseDownloadTests): @@ -139,8 +139,8 @@ def test_is_version_at_least_with_invalid_name(self): self.assertFalse(invalid_release.is_version_at_least_3_14) def test_update_supernav(self): - from boxes.models import Box - from downloads.models import update_supernav + from apps.boxes.models import Box + from apps.downloads.models import update_supernav release = Release.objects.create( name="Python install manager 25.0", @@ -197,8 +197,8 @@ def test_update_supernav_skips_os_without_files(self): leaving the supernav showing outdated version information. """ # Arrange - from boxes.models import Box - from downloads.models import OS, update_supernav + from apps.boxes.models import Box + from apps.downloads.models import OS, update_supernav # Create an OS without any release files OS.objects.create(name="Android", slug="android") diff --git a/downloads/tests/test_template_tags.py b/apps/downloads/tests/test_template_tags.py similarity index 86% rename from downloads/tests/test_template_tags.py rename to apps/downloads/tests/test_template_tags.py index 6bf48a989..26c1127d2 100644 --- a/downloads/tests/test_template_tags.py +++ b/apps/downloads/tests/test_template_tags.py @@ -5,8 +5,8 @@ from django.test import TestCase, override_settings from django.urls import reverse -from downloads.templatetags.download_tags import get_eol_info, get_release_cycle_data, render_active_releases -from downloads.tests.base import BaseDownloadTests +from apps.downloads.templatetags.download_tags import get_eol_info, get_release_cycle_data, render_active_releases +from apps.downloads.tests.base import BaseDownloadTests MOCK_RELEASE_CYCLE = { "2.7": {"status": "end-of-life", "end_of_life": "2020-01-01", "pep": 373}, @@ -32,7 +32,7 @@ def setUp(self): super().setUp() cache.clear() - @mock.patch("downloads.templatetags.download_tags.get_release_cycle_data") + @mock.patch("apps.downloads.templatetags.download_tags.get_release_cycle_data") def test_eol_status(self, mock_get_data): """Test get_eol_info returns correct EOL status.""" # Arrange @@ -52,7 +52,7 @@ def test_eol_status(self, mock_get_data): self.assertEqual(result["is_eol"], expected_is_eol) self.assertEqual(result["eol_date"], expected_eol_date) - @mock.patch("downloads.templatetags.download_tags.get_release_cycle_data") + @mock.patch("apps.downloads.templatetags.download_tags.get_release_cycle_data") def test_eol_status_api_failure(self, mock_get_data): """Test that API failure results in not showing EOL warning.""" # Arrange @@ -71,7 +71,7 @@ class GetReleaseCycleDataTests(TestCase): def setUp(self): cache.clear() - @mock.patch("downloads.templatetags.download_tags.requests.get") + @mock.patch("apps.downloads.templatetags.download_tags.requests.get") def test_successful_fetch(self, mock_get): """Test successful API fetch.""" # Arrange @@ -87,7 +87,7 @@ def test_successful_fetch(self, mock_get): self.assertEqual(result, MOCK_RELEASE_CYCLE) mock_get.assert_called_once() - @mock.patch("downloads.templatetags.download_tags.requests.get") + @mock.patch("apps.downloads.templatetags.download_tags.requests.get") def test_caches_result(self, mock_get): """Test that the result is cached.""" # Arrange @@ -104,7 +104,7 @@ def test_caches_result(self, mock_get): self.assertEqual(result1, result2) mock_get.assert_called_once() - @mock.patch("downloads.templatetags.download_tags.requests.get") + @mock.patch("apps.downloads.templatetags.download_tags.requests.get") def test_request_exception_returns_none(self, mock_get): """Test that request exceptions return None.""" # Arrange @@ -116,7 +116,7 @@ def test_request_exception_returns_none(self, mock_get): # Assert self.assertIsNone(result) - @mock.patch("downloads.templatetags.download_tags.requests.get") + @mock.patch("apps.downloads.templatetags.download_tags.requests.get") def test_json_decode_error_returns_none(self, mock_get): """Test that JSON decode errors return None.""" # Arrange @@ -138,7 +138,7 @@ def setUp(self): super().setUp() cache.clear() - @mock.patch("downloads.templatetags.download_tags.get_release_cycle_data") + @mock.patch("apps.downloads.templatetags.download_tags.get_release_cycle_data") def test_eol_banner_visibility(self, mock_get_data): """Test EOL banner is shown or hidden correctly.""" # Arrange @@ -176,7 +176,7 @@ def setUp(self): super().setUp() cache.clear() - @mock.patch("downloads.templatetags.download_tags.get_release_cycle_data") + @mock.patch("apps.downloads.templatetags.download_tags.get_release_cycle_data") def test_versions_sorted_descending(self, mock_get_data): """Test that versions are sorted in descending order.""" mock_get_data.return_value = MOCK_RELEASE_CYCLE @@ -187,7 +187,7 @@ def test_versions_sorted_descending(self, mock_get_data): # 3.15, 3.14, 3.10, 3.9 (first EOL); 3.8 and 2.7 skipped (older EOL) self.assertEqual(versions, ["3.15", "3.14", "3.10", "3.9"]) - @mock.patch("downloads.templatetags.download_tags.get_release_cycle_data") + @mock.patch("apps.downloads.templatetags.download_tags.get_release_cycle_data") def test_feature_status_becomes_prerelease(self, mock_get_data): """Test that 'feature' status is converted to 'pre-release'.""" mock_get_data.return_value = MOCK_RELEASE_CYCLE @@ -198,7 +198,7 @@ def test_feature_status_becomes_prerelease(self, mock_get_data): self.assertEqual(prerelease["version"], "3.15") self.assertEqual(prerelease["status"], "pre-release") - @mock.patch("downloads.templatetags.download_tags.get_release_cycle_data") + @mock.patch("apps.downloads.templatetags.download_tags.get_release_cycle_data") def test_feature_first_release_shows_planned(self, mock_get_data): """Test that feature releases show (planned) in first_release.""" mock_get_data.return_value = MOCK_RELEASE_CYCLE @@ -208,7 +208,7 @@ def test_feature_first_release_shows_planned(self, mock_get_data): prerelease = result["releases"][0] self.assertEqual(prerelease["first_release"], "2026-10-01 (planned)") - @mock.patch("downloads.templatetags.download_tags.get_release_cycle_data") + @mock.patch("apps.downloads.templatetags.download_tags.get_release_cycle_data") def test_only_one_eol_release_included(self, mock_get_data): """Test that only the most recent EOL release is included.""" mock_get_data.return_value = MOCK_RELEASE_CYCLE @@ -221,7 +221,7 @@ def test_only_one_eol_release_included(self, mock_get_data): self.assertNotIn("3.8", versions) self.assertNotIn("2.7", versions) - @mock.patch("downloads.templatetags.download_tags.get_release_cycle_data") + @mock.patch("apps.downloads.templatetags.download_tags.get_release_cycle_data") def test_eol_status_includes_last_release_link(self, mock_get_data): """Test that EOL status includes last release link.""" mock_get_data.return_value = MOCK_RELEASE_CYCLE @@ -234,7 +234,7 @@ def test_eol_status_includes_last_release_link(self, mock_get_data): self.assertIn("last release was", status) self.assertIn("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/apps/events/tests/test_forms.py similarity index 97% rename from events/tests/test_forms.py rename to apps/events/tests/test_forms.py index 52ab05d72..a1d2f14e7 100644 --- a/events/tests/test_forms.py +++ b/apps/events/tests/test_forms.py @@ -2,7 +2,7 @@ from django.test import SimpleTestCase -from events.forms import EventForm +from apps.events.forms import EventForm class EventFormTests(SimpleTestCase): diff --git a/events/tests/test_importer.py b/apps/events/tests/test_importer.py similarity index 98% rename from events/tests/test_importer.py rename to apps/events/tests/test_importer.py index 64fb6e2d2..1bb0f4f22 100644 --- a/events/tests/test_importer.py +++ b/apps/events/tests/test_importer.py @@ -3,8 +3,8 @@ from django.test import TestCase from django.utils.timezone import datetime, make_aware -from events.importer import ICSImporter -from events.models import Calendar, Event +from apps.events.importer import ICSImporter +from apps.events.models import Calendar, Event CUR_DIR = Path(__file__).parent EVENTS_CALENDAR = str(CUR_DIR / "events.ics") diff --git a/events/tests/test_models.py b/apps/events/tests/test_models.py similarity index 97% rename from events/tests/test_models.py rename to apps/events/tests/test_models.py index a67aac249..88f909188 100644 --- a/events/tests/test_models.py +++ b/apps/events/tests/test_models.py @@ -7,8 +7,8 @@ from django.test import TestCase from django.utils import timezone -from events.models import Calendar, Event, OccurringRule, RecurringRule -from events.utils import convert_dt_to_aware, seconds_resolution +from apps.events.models import Calendar, Event, OccurringRule, RecurringRule +from apps.events.utils import convert_dt_to_aware, seconds_resolution class EventsModelsTests(TestCase): @@ -189,7 +189,7 @@ def test_scheduled_to_start_this_year_method(self): with ( patch("django.utils.timezone", new=test_datetime) as mock_timezone, - patch("events.models.timezone", new=test_datetime), + patch("apps.events.models.timezone", new=test_datetime), ): now = seconds_resolution(mock_timezone.now()) @@ -219,7 +219,7 @@ def test_scheduled_to_end_this_year_method(self): with ( patch("django.utils.timezone", new=test_datetime) as mock_timezone, - patch("events.models.timezone", new=test_datetime), + patch("apps.events.models.timezone", new=test_datetime), ): now = seconds_resolution(mock_timezone.now()) occurring_time_dtstart = now + datetime.timedelta(days=1) diff --git a/events/tests/test_utils.py b/apps/events/tests/test_utils.py similarity index 97% rename from events/tests/test_utils.py rename to apps/events/tests/test_utils.py index 7bc530284..bddda25a8 100644 --- a/events/tests/test_utils.py +++ b/apps/events/tests/test_utils.py @@ -3,7 +3,7 @@ from django.test import TestCase from django.utils import timezone -from events.utils import minutes_resolution, seconds_resolution, timedelta_nice_repr, timedelta_parse +from apps.events.utils import minutes_resolution, seconds_resolution, timedelta_nice_repr, timedelta_parse class EventsUtilsTests(TestCase): diff --git a/events/tests/test_views.py b/apps/events/tests/test_views.py similarity index 98% rename from events/tests/test_views.py rename to apps/events/tests/test_views.py index 67d839b26..31562c703 100644 --- a/events/tests/test_views.py +++ b/apps/events/tests/test_views.py @@ -6,9 +6,9 @@ from django.urls import reverse, reverse_lazy from django.utils import timezone -from events.models import Calendar, Event, EventCategory, EventLocation, OccurringRule, RecurringRule -from events.templatetags.events import get_events_upcoming -from users.factories import UserFactory +from apps.events.models import Calendar, Event, EventCategory, EventLocation, OccurringRule, RecurringRule +from apps.events.templatetags.events import get_events_upcoming +from apps.users.factories import UserFactory class EventsViewsTests(TestCase): diff --git a/events/urls.py b/apps/events/urls.py similarity index 97% rename from events/urls.py rename to apps/events/urls.py index 3fd982373..cb30f4831 100644 --- a/events/urls.py +++ b/apps/events/urls.py @@ -3,7 +3,7 @@ from django.urls import path, re_path from django.views.generic import TemplateView -from events import views +from apps.events import views app_name = "events" urlpatterns = [ diff --git a/events/utils.py b/apps/events/utils.py similarity index 100% rename from events/utils.py rename to apps/events/utils.py diff --git a/events/views.py b/apps/events/views.py similarity index 98% rename from events/views.py rename to apps/events/views.py index aab505549..ce70fe54a 100644 --- a/events/views.py +++ b/apps/events/views.py @@ -10,8 +10,8 @@ from django.utils import timezone from django.views.generic import DetailView, FormView, ListView -from events.forms import EventForm -from events.models import Calendar, Event, EventCategory, EventLocation +from apps.events.forms import EventForm +from apps.events.models import Calendar, Event, EventCategory, EventLocation from pydotorg.mixins import LoginRequiredMixin diff --git a/jobs/__init__.py b/apps/jobs/__init__.py similarity index 100% rename from jobs/__init__.py rename to apps/jobs/__init__.py diff --git a/jobs/admin.py b/apps/jobs/admin.py similarity index 88% rename from jobs/admin.py rename to apps/jobs/admin.py index 3b5aa7b3f..a673975d8 100644 --- a/jobs/admin.py +++ b/apps/jobs/admin.py @@ -2,8 +2,8 @@ from django.contrib import admin -from cms.admin import ContentManageableModelAdmin, NameSlugAdmin -from jobs.models import Job, JobCategory, JobReviewComment, JobType +from apps.cms.admin import ContentManageableModelAdmin, NameSlugAdmin +from apps.jobs.models import Job, JobCategory, JobReviewComment, JobType @admin.register(Job) diff --git a/jobs/apps.py b/apps/jobs/apps.py similarity index 75% rename from jobs/apps.py rename to apps/jobs/apps.py index 879f9fe6e..4fc97dd0c 100644 --- a/jobs/apps.py +++ b/apps/jobs/apps.py @@ -6,9 +6,10 @@ class JobsAppConfig(AppConfig): """Django app configuration for the job board.""" - name = "jobs" + name = "apps.jobs" + label = "jobs" verbose_name = "Jobs Application" def ready(self): """Perform app initialization on startup.""" - import jobs.listeners # noqa: F401 + import apps.jobs.listeners # noqa: F401 diff --git a/jobs/factories.py b/apps/jobs/factories.py similarity index 98% rename from jobs/factories.py rename to apps/jobs/factories.py index cc3917669..e7ed9c8f6 100644 --- a/jobs/factories.py +++ b/apps/jobs/factories.py @@ -8,8 +8,8 @@ from factory.django import DjangoModelFactory from faker.providers import BaseProvider -from jobs.models import Job, JobCategory, JobType -from users.factories import UserFactory +from apps.jobs.models import Job, JobCategory, JobType +from apps.users.factories import UserFactory class JobProvider(BaseProvider): diff --git a/jobs/feeds.py b/apps/jobs/feeds.py similarity index 95% rename from jobs/feeds.py rename to apps/jobs/feeds.py index 139f4bdda..330315f91 100644 --- a/jobs/feeds.py +++ b/apps/jobs/feeds.py @@ -3,7 +3,7 @@ from django.contrib.syndication.views import Feed from django.urls import reverse_lazy -from jobs.models import Job +from apps.jobs.models import Job class JobFeed(Feed): diff --git a/jobs/forms.py b/apps/jobs/forms.py similarity index 95% rename from jobs/forms.py rename to apps/jobs/forms.py index 06154699e..ae5a256d5 100644 --- a/jobs/forms.py +++ b/apps/jobs/forms.py @@ -4,8 +4,8 @@ from django.forms.widgets import CheckboxSelectMultiple, HiddenInput from markupfield.widgets import MarkupTextarea -from cms.forms import ContentManageableModelForm -from jobs.models import Job, JobReviewComment +from apps.cms.forms import ContentManageableModelForm +from apps.jobs.models import Job, JobReviewComment class JobForm(ContentManageableModelForm): diff --git a/jobs/listeners.py b/apps/jobs/listeners.py similarity index 97% rename from jobs/listeners.py rename to apps/jobs/listeners.py index 8a9e7653a..d893f37df 100644 --- a/jobs/listeners.py +++ b/apps/jobs/listeners.py @@ -7,7 +7,7 @@ from django.template import loader from django.utils.translation import gettext_lazy as _ -from jobs.signals import comment_was_posted, job_was_approved, job_was_rejected, job_was_submitted +from apps.jobs.signals import comment_was_posted, job_was_approved, job_was_rejected, job_was_submitted # Python job board team email address EMAIL_JOBS_BOARD = "jobs@python.org" diff --git a/jobs/management/__init__.py b/apps/jobs/management/__init__.py similarity index 100% rename from jobs/management/__init__.py rename to apps/jobs/management/__init__.py diff --git a/jobs/management/commands/__init__.py b/apps/jobs/management/commands/__init__.py similarity index 100% rename from jobs/management/commands/__init__.py rename to apps/jobs/management/commands/__init__.py diff --git a/jobs/management/commands/expire_jobs.py b/apps/jobs/management/commands/expire_jobs.py similarity index 93% rename from jobs/management/commands/expire_jobs.py rename to apps/jobs/management/commands/expire_jobs.py index 3e9ea9dd9..3907a3771 100644 --- a/jobs/management/commands/expire_jobs.py +++ b/apps/jobs/management/commands/expire_jobs.py @@ -4,7 +4,7 @@ from django.core.management import BaseCommand from django.utils import timezone -from jobs.models import Job +from apps.jobs.models import Job class Command(BaseCommand): diff --git a/jobs/management/commands/jobs_monthly_report.py b/apps/jobs/management/commands/jobs_monthly_report.py similarity index 98% rename from jobs/management/commands/jobs_monthly_report.py rename to apps/jobs/management/commands/jobs_monthly_report.py index 66e1dabee..66c9111f0 100644 --- a/jobs/management/commands/jobs_monthly_report.py +++ b/apps/jobs/management/commands/jobs_monthly_report.py @@ -7,7 +7,7 @@ from django.template import loader from django.utils import timezone -from jobs.models import Job +from apps.jobs.models import Job REPORT_DAY_OF_MONTH = 27 diff --git a/jobs/managers.py b/apps/jobs/managers.py similarity index 100% rename from jobs/managers.py rename to apps/jobs/managers.py diff --git a/jobs/migrations/0001_initial.py b/apps/jobs/migrations/0001_initial.py similarity index 100% rename from jobs/migrations/0001_initial.py rename to apps/jobs/migrations/0001_initial.py diff --git a/jobs/migrations/0002_auto_20150211_1634.py b/apps/jobs/migrations/0002_auto_20150211_1634.py similarity index 100% rename from jobs/migrations/0002_auto_20150211_1634.py rename to apps/jobs/migrations/0002_auto_20150211_1634.py diff --git a/jobs/migrations/0003_auto_20150211_1738.py b/apps/jobs/migrations/0003_auto_20150211_1738.py similarity index 100% rename from jobs/migrations/0003_auto_20150211_1738.py rename to apps/jobs/migrations/0003_auto_20150211_1738.py diff --git a/jobs/migrations/0004_auto_20150216_1544.py b/apps/jobs/migrations/0004_auto_20150216_1544.py similarity index 100% rename from jobs/migrations/0004_auto_20150216_1544.py rename to apps/jobs/migrations/0004_auto_20150216_1544.py diff --git a/jobs/migrations/0005_job_other_job_type.py b/apps/jobs/migrations/0005_job_other_job_type.py similarity index 100% rename from jobs/migrations/0005_job_other_job_type.py rename to apps/jobs/migrations/0005_job_other_job_type.py diff --git a/jobs/migrations/0006_region_nullable.py b/apps/jobs/migrations/0006_region_nullable.py similarity index 100% rename from jobs/migrations/0006_region_nullable.py rename to apps/jobs/migrations/0006_region_nullable.py diff --git a/jobs/migrations/0007_auto_20150227_2223.py b/apps/jobs/migrations/0007_auto_20150227_2223.py similarity index 100% rename from jobs/migrations/0007_auto_20150227_2223.py rename to apps/jobs/migrations/0007_auto_20150227_2223.py diff --git a/jobs/migrations/0008_auto_20150316_1205.py b/apps/jobs/migrations/0008_auto_20150316_1205.py similarity index 100% rename from jobs/migrations/0008_auto_20150316_1205.py rename to apps/jobs/migrations/0008_auto_20150316_1205.py diff --git a/jobs/migrations/0009_auto_20150317_1815.py b/apps/jobs/migrations/0009_auto_20150317_1815.py similarity index 100% rename from jobs/migrations/0009_auto_20150317_1815.py rename to apps/jobs/migrations/0009_auto_20150317_1815.py diff --git a/jobs/migrations/0010_auto_20150416_1853.py b/apps/jobs/migrations/0010_auto_20150416_1853.py similarity index 100% rename from jobs/migrations/0010_auto_20150416_1853.py rename to apps/jobs/migrations/0010_auto_20150416_1853.py diff --git a/jobs/migrations/0011_jobreviewcomment.py b/apps/jobs/migrations/0011_jobreviewcomment.py similarity index 100% rename from jobs/migrations/0011_jobreviewcomment.py rename to apps/jobs/migrations/0011_jobreviewcomment.py diff --git a/jobs/migrations/0012_auto_20170809_1849.py b/apps/jobs/migrations/0012_auto_20170809_1849.py similarity index 100% rename from jobs/migrations/0012_auto_20170809_1849.py rename to apps/jobs/migrations/0012_auto_20170809_1849.py diff --git a/jobs/migrations/0013_auto_20170810_1625.py b/apps/jobs/migrations/0013_auto_20170810_1625.py similarity index 100% rename from jobs/migrations/0013_auto_20170810_1625.py rename to apps/jobs/migrations/0013_auto_20170810_1625.py diff --git a/jobs/migrations/0013_auto_20170810_1627.py b/apps/jobs/migrations/0013_auto_20170810_1627.py similarity index 100% rename from jobs/migrations/0013_auto_20170810_1627.py rename to apps/jobs/migrations/0013_auto_20170810_1627.py diff --git a/jobs/migrations/0014_merge.py b/apps/jobs/migrations/0014_merge.py similarity index 100% rename from jobs/migrations/0014_merge.py rename to apps/jobs/migrations/0014_merge.py diff --git a/jobs/migrations/0015_auto_20170814_0301.py b/apps/jobs/migrations/0015_auto_20170814_0301.py similarity index 100% rename from jobs/migrations/0015_auto_20170814_0301.py rename to apps/jobs/migrations/0015_auto_20170814_0301.py diff --git a/jobs/migrations/0016_auto_20170821_2000.py b/apps/jobs/migrations/0016_auto_20170821_2000.py similarity index 100% rename from jobs/migrations/0016_auto_20170821_2000.py rename to apps/jobs/migrations/0016_auto_20170821_2000.py diff --git a/jobs/migrations/0017_auto_20180705_0348.py b/apps/jobs/migrations/0017_auto_20180705_0348.py similarity index 100% rename from jobs/migrations/0017_auto_20180705_0348.py rename to apps/jobs/migrations/0017_auto_20180705_0348.py diff --git a/jobs/migrations/0018_auto_20180705_0352.py b/apps/jobs/migrations/0018_auto_20180705_0352.py similarity index 100% rename from jobs/migrations/0018_auto_20180705_0352.py rename to apps/jobs/migrations/0018_auto_20180705_0352.py diff --git a/jobs/migrations/0019_job_submitted_by.py b/apps/jobs/migrations/0019_job_submitted_by.py similarity index 100% rename from jobs/migrations/0019_job_submitted_by.py rename to apps/jobs/migrations/0019_job_submitted_by.py diff --git a/jobs/migrations/0020_auto_20191101_1601.py b/apps/jobs/migrations/0020_auto_20191101_1601.py similarity index 100% rename from jobs/migrations/0020_auto_20191101_1601.py rename to apps/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/apps/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 apps/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/apps/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 apps/jobs/migrations/0022_alter_jobtype_options_alter_job_job_types_and_more.py diff --git a/jobs/migrations/__init__.py b/apps/jobs/migrations/__init__.py similarity index 100% rename from jobs/migrations/__init__.py rename to apps/jobs/migrations/__init__.py diff --git a/jobs/models.py b/apps/jobs/models.py similarity index 96% rename from jobs/models.py rename to apps/jobs/models.py index bb23c4f00..59bfedcbe 100644 --- a/jobs/models.py +++ b/apps/jobs/models.py @@ -11,11 +11,11 @@ from django.utils import timezone from markupfield.fields import MarkupField -from cms.models import ContentManageable, NameSlugModel +from apps.cms.models import ContentManageable, NameSlugModel +from apps.jobs.managers import JobCategoryQuerySet, JobQuerySet, JobTypeQuerySet +from apps.jobs.signals import comment_was_posted, job_was_approved, job_was_rejected, job_was_submitted +from apps.users.models import User from fastly.utils import purge_url -from jobs.managers import JobCategoryQuerySet, JobQuerySet, JobTypeQuerySet -from jobs.signals import comment_was_posted, job_was_approved, job_was_rejected, job_was_submitted -from users.models import User DEFAULT_MARKUP_TYPE = getattr(settings, "DEFAULT_MARKUP_TYPE", "restructuredtext") diff --git a/jobs/search_indexes.py b/apps/jobs/search_indexes.py similarity index 98% rename from jobs/search_indexes.py rename to apps/jobs/search_indexes.py index 520847127..48a712849 100644 --- a/jobs/search_indexes.py +++ b/apps/jobs/search_indexes.py @@ -4,7 +4,7 @@ from django.urls import reverse from haystack import indexes -from jobs.models import Job, JobCategory, JobType +from apps.jobs.models import Job, JobCategory, JobType class JobTypeIndex(indexes.SearchIndex, indexes.Indexable): diff --git a/jobs/signals.py b/apps/jobs/signals.py similarity index 100% rename from jobs/signals.py rename to apps/jobs/signals.py diff --git a/templates/jobs/base.html b/apps/jobs/templates/jobs/base.html similarity index 100% rename from templates/jobs/base.html rename to apps/jobs/templates/jobs/base.html diff --git a/templates/jobs/email/comment_was_posted.txt b/apps/jobs/templates/jobs/email/comment_was_posted.txt similarity index 100% rename from templates/jobs/email/comment_was_posted.txt rename to apps/jobs/templates/jobs/email/comment_was_posted.txt diff --git a/templates/jobs/email/comment_was_posted_admin.txt b/apps/jobs/templates/jobs/email/comment_was_posted_admin.txt similarity index 100% rename from templates/jobs/email/comment_was_posted_admin.txt rename to apps/jobs/templates/jobs/email/comment_was_posted_admin.txt diff --git a/templates/jobs/email/job_was_approved.txt b/apps/jobs/templates/jobs/email/job_was_approved.txt similarity index 100% rename from templates/jobs/email/job_was_approved.txt rename to apps/jobs/templates/jobs/email/job_was_approved.txt diff --git a/templates/jobs/email/job_was_approved_subject.txt b/apps/jobs/templates/jobs/email/job_was_approved_subject.txt similarity index 100% rename from templates/jobs/email/job_was_approved_subject.txt rename to apps/jobs/templates/jobs/email/job_was_approved_subject.txt diff --git a/templates/jobs/email/job_was_rejected.txt b/apps/jobs/templates/jobs/email/job_was_rejected.txt similarity index 100% rename from templates/jobs/email/job_was_rejected.txt rename to apps/jobs/templates/jobs/email/job_was_rejected.txt diff --git a/templates/jobs/email/job_was_rejected_subject.txt b/apps/jobs/templates/jobs/email/job_was_rejected_subject.txt similarity index 100% rename from templates/jobs/email/job_was_rejected_subject.txt rename to apps/jobs/templates/jobs/email/job_was_rejected_subject.txt diff --git a/templates/jobs/email/job_was_submitted.txt b/apps/jobs/templates/jobs/email/job_was_submitted.txt similarity index 100% rename from templates/jobs/email/job_was_submitted.txt rename to apps/jobs/templates/jobs/email/job_was_submitted.txt diff --git a/templates/jobs/email/job_was_submitted_subject.txt b/apps/jobs/templates/jobs/email/job_was_submitted_subject.txt similarity index 100% rename from templates/jobs/email/job_was_submitted_subject.txt rename to apps/jobs/templates/jobs/email/job_was_submitted_subject.txt diff --git a/templates/jobs/email/monthly_jobs_report.txt b/apps/jobs/templates/jobs/email/monthly_jobs_report.txt similarity index 100% rename from templates/jobs/email/monthly_jobs_report.txt rename to apps/jobs/templates/jobs/email/monthly_jobs_report.txt diff --git a/templates/jobs/email/monthly_jobs_report_subject.txt b/apps/jobs/templates/jobs/email/monthly_jobs_report_subject.txt similarity index 100% rename from templates/jobs/email/monthly_jobs_report_subject.txt rename to apps/jobs/templates/jobs/email/monthly_jobs_report_subject.txt diff --git a/templates/jobs/featured_companies-widget.html b/apps/jobs/templates/jobs/featured_companies-widget.html similarity index 100% rename from templates/jobs/featured_companies-widget.html rename to apps/jobs/templates/jobs/featured_companies-widget.html diff --git a/templates/jobs/header_content.html b/apps/jobs/templates/jobs/header_content.html similarity index 100% rename from templates/jobs/header_content.html rename to apps/jobs/templates/jobs/header_content.html diff --git a/templates/jobs/job_categories.html b/apps/jobs/templates/jobs/job_categories.html similarity index 100% rename from templates/jobs/job_categories.html rename to apps/jobs/templates/jobs/job_categories.html diff --git a/templates/jobs/job_category_list.html b/apps/jobs/templates/jobs/job_category_list.html similarity index 100% rename from templates/jobs/job_category_list.html rename to apps/jobs/templates/jobs/job_category_list.html diff --git a/templates/jobs/job_detail.html b/apps/jobs/templates/jobs/job_detail.html similarity index 100% rename from templates/jobs/job_detail.html rename to apps/jobs/templates/jobs/job_detail.html diff --git a/templates/jobs/job_form.html b/apps/jobs/templates/jobs/job_form.html similarity index 100% rename from templates/jobs/job_form.html rename to apps/jobs/templates/jobs/job_form.html diff --git a/templates/jobs/job_list.html b/apps/jobs/templates/jobs/job_list.html similarity index 100% rename from templates/jobs/job_list.html rename to apps/jobs/templates/jobs/job_list.html diff --git a/templates/jobs/job_location_list.html b/apps/jobs/templates/jobs/job_location_list.html similarity index 100% rename from templates/jobs/job_location_list.html rename to apps/jobs/templates/jobs/job_location_list.html diff --git a/templates/jobs/job_locations.html b/apps/jobs/templates/jobs/job_locations.html similarity index 100% rename from templates/jobs/job_locations.html rename to apps/jobs/templates/jobs/job_locations.html diff --git a/templates/jobs/job_review.html b/apps/jobs/templates/jobs/job_review.html similarity index 100% rename from templates/jobs/job_review.html rename to apps/jobs/templates/jobs/job_review.html diff --git a/templates/jobs/job_telecommute_list.html b/apps/jobs/templates/jobs/job_telecommute_list.html similarity index 100% rename from templates/jobs/job_telecommute_list.html rename to apps/jobs/templates/jobs/job_telecommute_list.html diff --git a/templates/jobs/job_thanks.html b/apps/jobs/templates/jobs/job_thanks.html similarity index 100% rename from templates/jobs/job_thanks.html rename to apps/jobs/templates/jobs/job_thanks.html diff --git a/templates/jobs/job_type_list.html b/apps/jobs/templates/jobs/job_type_list.html similarity index 100% rename from templates/jobs/job_type_list.html rename to apps/jobs/templates/jobs/job_type_list.html diff --git a/templates/jobs/job_types.html b/apps/jobs/templates/jobs/job_types.html similarity index 100% rename from templates/jobs/job_types.html rename to apps/jobs/templates/jobs/job_types.html diff --git a/templates/jobs/submit_a_job-widget.html b/apps/jobs/templates/jobs/submit_a_job-widget.html similarity index 100% rename from templates/jobs/submit_a_job-widget.html rename to apps/jobs/templates/jobs/submit_a_job-widget.html diff --git a/jobs/tests/__init__.py b/apps/jobs/tests/__init__.py similarity index 100% rename from jobs/tests/__init__.py rename to apps/jobs/tests/__init__.py diff --git a/jobs/tests/test_models.py b/apps/jobs/tests/test_models.py similarity index 98% rename from jobs/tests/test_models.py rename to apps/jobs/tests/test_models.py index d3e0fa636..783dad0f9 100644 --- a/jobs/tests/test_models.py +++ b/apps/jobs/tests/test_models.py @@ -3,8 +3,8 @@ from django.test import TestCase from django.utils import timezone -from jobs import factories -from jobs.models import Job, JobCategory, JobType +from apps.jobs import factories +from apps.jobs.models import Job, JobCategory, JobType class JobsModelsTests(TestCase): diff --git a/jobs/tests/test_views.py b/apps/jobs/tests/test_views.py similarity index 99% rename from jobs/tests/test_views.py rename to apps/jobs/tests/test_views.py index 89339c2c9..1c02a7512 100644 --- a/jobs/tests/test_views.py +++ b/apps/jobs/tests/test_views.py @@ -3,7 +3,7 @@ from django.test import TestCase from django.urls import reverse -from jobs.factories import ( +from apps.jobs.factories import ( ApprovedJobFactory, DraftJobFactory, JobCategoryFactory, @@ -11,8 +11,8 @@ JobTypeFactory, ReviewJobFactory, ) -from jobs.models import Job -from users.factories import UserFactory +from apps.jobs.models import Job +from apps.users.factories import UserFactory class JobsViewTests(TestCase): diff --git a/jobs/urls.py b/apps/jobs/urls.py similarity index 97% rename from jobs/urls.py rename to apps/jobs/urls.py index 4a91b541b..cd3a69785 100644 --- a/jobs/urls.py +++ b/apps/jobs/urls.py @@ -3,7 +3,7 @@ from django.urls import path from django.views.generic import TemplateView -from jobs import feeds, views +from apps.jobs import feeds, views app_name = "jobs" urlpatterns = [ diff --git a/jobs/views.py b/apps/jobs/views.py similarity index 99% rename from jobs/views.py rename to apps/jobs/views.py index c8eddee99..1f5d8d6c9 100644 --- a/jobs/views.py +++ b/apps/jobs/views.py @@ -6,8 +6,8 @@ from django.urls import reverse from django.views.generic import CreateView, DetailView, ListView, TemplateView, UpdateView, View -from jobs.forms import JobForm, JobReviewCommentForm -from jobs.models import Job, JobCategory, JobReviewComment, JobType +from apps.jobs.forms import JobForm, JobReviewCommentForm +from apps.jobs.models import Job, JobCategory, JobReviewComment, JobType from pydotorg.mixins import GroupRequiredMixin, LoginRequiredMixin diff --git a/mailing/__init__.py b/apps/mailing/__init__.py similarity index 100% rename from mailing/__init__.py rename to apps/mailing/__init__.py diff --git a/mailing/admin.py b/apps/mailing/admin.py similarity index 97% rename from mailing/admin.py rename to apps/mailing/admin.py index a20ced3ac..eead65fb9 100644 --- a/mailing/admin.py +++ b/apps/mailing/admin.py @@ -6,7 +6,7 @@ from django.shortcuts import get_object_or_404 from django.urls import path -from mailing.forms import BaseEmailTemplateForm +from apps.mailing.forms import BaseEmailTemplateForm class BaseEmailTemplateAdmin(admin.ModelAdmin): diff --git a/mailing/apps.py b/apps/mailing/apps.py similarity index 78% rename from mailing/apps.py rename to apps/mailing/apps.py index 534b893c8..8bba9ccb5 100644 --- a/mailing/apps.py +++ b/apps/mailing/apps.py @@ -6,4 +6,5 @@ class MailingConfig(AppConfig): """App configuration for the mailing app.""" - name = "mailing" + name = "apps.mailing" + label = "mailing" diff --git a/mailing/forms.py b/apps/mailing/forms.py similarity index 94% rename from mailing/forms.py rename to apps/mailing/forms.py index 6890d0cfd..f16f8a64e 100644 --- a/mailing/forms.py +++ b/apps/mailing/forms.py @@ -3,7 +3,7 @@ from django import forms from django.template import Context, Template, TemplateSyntaxError -from mailing.models import BaseEmailTemplate +from apps.mailing.models import BaseEmailTemplate class BaseEmailTemplateForm(forms.ModelForm): diff --git a/mailing/migrations/__init__.py b/apps/mailing/migrations/__init__.py similarity index 100% rename from mailing/migrations/__init__.py rename to apps/mailing/migrations/__init__.py diff --git a/mailing/models.py b/apps/mailing/models.py similarity index 100% rename from mailing/models.py rename to apps/mailing/models.py diff --git a/templates/mailing/admin/base_email_template_form.html b/apps/mailing/templates/mailing/admin/base_email_template_form.html similarity index 100% rename from templates/mailing/admin/base_email_template_form.html rename to apps/mailing/templates/mailing/admin/base_email_template_form.html diff --git a/mailing/tests/__init__.py b/apps/mailing/tests/__init__.py similarity index 100% rename from mailing/tests/__init__.py rename to apps/mailing/tests/__init__.py diff --git a/mailing/tests/forms.py b/apps/mailing/tests/forms.py similarity index 70% rename from mailing/tests/forms.py rename to apps/mailing/tests/forms.py index 0c2bbbd7c..14142bf19 100644 --- a/mailing/tests/forms.py +++ b/apps/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 apps.mailing.forms import BaseEmailTemplateForm +from apps.mailing.tests.models import MockEmailTemplate class TestBaseEmailTemplateForm(BaseEmailTemplateForm): diff --git a/mailing/tests/models.py b/apps/mailing/tests/models.py similarity index 86% rename from mailing/tests/models.py rename to apps/mailing/tests/models.py index 04d6de619..420317e0e 100644 --- a/mailing/tests/models.py +++ b/apps/mailing/tests/models.py @@ -1,6 +1,6 @@ """Models to be used in mailing tests.""" -from mailing.models import BaseEmailTemplate +from apps.mailing.models import BaseEmailTemplate class MockEmailTemplate(BaseEmailTemplate): diff --git a/mailing/tests/test_forms.py b/apps/mailing/tests/test_forms.py similarity index 94% rename from mailing/tests/test_forms.py rename to apps/mailing/tests/test_forms.py index e1f458bdd..98736bccc 100644 --- a/mailing/tests/test_forms.py +++ b/apps/mailing/tests/test_forms.py @@ -3,7 +3,7 @@ from django.contrib.contenttypes.models import ContentType from django.test import TestCase -from mailing.tests.forms import TestBaseEmailTemplateForm +from apps.mailing.tests.forms import TestBaseEmailTemplateForm class BaseEmailTemplateFormTests(TestCase): diff --git a/membership/__init__.py b/apps/membership/__init__.py similarity index 100% rename from membership/__init__.py rename to apps/membership/__init__.py diff --git a/membership/apps.py b/apps/membership/apps.py similarity index 77% rename from membership/apps.py rename to apps/membership/apps.py index 2d5769fbc..2a9590e41 100644 --- a/membership/apps.py +++ b/apps/membership/apps.py @@ -6,4 +6,5 @@ class MembershipAppConfig(AppConfig): """App configuration for the membership app.""" - name = "membership" + name = "apps.membership" + label = "membership" diff --git a/membership/migrations/__init__.py b/apps/membership/migrations/__init__.py similarity index 100% rename from membership/migrations/__init__.py rename to apps/membership/migrations/__init__.py diff --git a/membership/tests/__init__.py b/apps/membership/tests/__init__.py similarity index 100% rename from membership/tests/__init__.py rename to apps/membership/tests/__init__.py diff --git a/membership/tests/test_views.py b/apps/membership/tests/test_views.py similarity index 100% rename from membership/tests/test_views.py rename to apps/membership/tests/test_views.py diff --git a/membership/urls.py b/apps/membership/urls.py similarity index 82% rename from membership/urls.py rename to apps/membership/urls.py index d49fab9cf..16451c7ab 100644 --- a/membership/urls.py +++ b/apps/membership/urls.py @@ -2,7 +2,7 @@ from django.urls import path -from membership import views +from apps.membership import views urlpatterns = [ path("", views.Membership.as_view(), name="membership"), diff --git a/membership/views.py b/apps/membership/views.py similarity index 100% rename from membership/views.py rename to apps/membership/views.py diff --git a/minutes/__init__.py b/apps/minutes/__init__.py similarity index 100% rename from minutes/__init__.py rename to apps/minutes/__init__.py diff --git a/minutes/admin.py b/apps/minutes/admin.py similarity index 87% rename from minutes/admin.py rename to apps/minutes/admin.py index 935525ed5..698f0e5d9 100644 --- a/minutes/admin.py +++ b/apps/minutes/admin.py @@ -2,8 +2,8 @@ from django.contrib import admin -from cms.admin import ContentManageableModelAdmin -from minutes.models import Minutes +from apps.cms.admin import ContentManageableModelAdmin +from apps.minutes.models import Minutes @admin.register(Minutes) diff --git a/minutes/apps.py b/apps/minutes/apps.py similarity index 78% rename from minutes/apps.py rename to apps/minutes/apps.py index b218d7249..ef672d8c3 100644 --- a/minutes/apps.py +++ b/apps/minutes/apps.py @@ -6,4 +6,5 @@ class MinutesAppConfig(AppConfig): """App configuration for the minutes app.""" - name = "minutes" + name = "apps.minutes" + label = "minutes" diff --git a/minutes/feeds.py b/apps/minutes/feeds.py similarity index 96% rename from minutes/feeds.py rename to apps/minutes/feeds.py index ba071129d..d1065e533 100644 --- a/minutes/feeds.py +++ b/apps/minutes/feeds.py @@ -5,7 +5,7 @@ from django.contrib.syndication.views import Feed from django.urls import reverse_lazy -from minutes.models import Minutes +from apps.minutes.models import Minutes class MinutesFeed(Feed): diff --git a/minutes/management/__init__.py b/apps/minutes/management/__init__.py similarity index 100% rename from minutes/management/__init__.py rename to apps/minutes/management/__init__.py diff --git a/minutes/management/commands/__init__.py b/apps/minutes/management/commands/__init__.py similarity index 100% rename from minutes/management/commands/__init__.py rename to apps/minutes/management/commands/__init__.py diff --git a/minutes/management/commands/move_meeting_notes.py b/apps/minutes/management/commands/move_meeting_notes.py similarity index 93% rename from minutes/management/commands/move_meeting_notes.py rename to apps/minutes/management/commands/move_meeting_notes.py index d0f7bc7bf..6ed352741 100644 --- a/minutes/management/commands/move_meeting_notes.py +++ b/apps/minutes/management/commands/move_meeting_notes.py @@ -3,8 +3,8 @@ from django.core.management.base import BaseCommand -from minutes.models import Minutes -from pages.models import Page +from apps.minutes.models import Minutes +from apps.pages.models import Page class Command(BaseCommand): diff --git a/minutes/managers.py b/apps/minutes/managers.py similarity index 100% rename from minutes/managers.py rename to apps/minutes/managers.py diff --git a/minutes/migrations/0001_initial.py b/apps/minutes/migrations/0001_initial.py similarity index 100% rename from minutes/migrations/0001_initial.py rename to apps/minutes/migrations/0001_initial.py diff --git a/minutes/migrations/0002_auto_20150416_1853.py b/apps/minutes/migrations/0002_auto_20150416_1853.py similarity index 100% rename from minutes/migrations/0002_auto_20150416_1853.py rename to apps/minutes/migrations/0002_auto_20150416_1853.py diff --git a/minutes/migrations/0003_alter_minutes_creator_alter_minutes_last_modified_by.py b/apps/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 apps/minutes/migrations/0003_alter_minutes_creator_alter_minutes_last_modified_by.py diff --git a/minutes/migrations/__init__.py b/apps/minutes/migrations/__init__.py similarity index 100% rename from minutes/migrations/__init__.py rename to apps/minutes/migrations/__init__.py diff --git a/minutes/models.py b/apps/minutes/models.py similarity index 94% rename from minutes/models.py rename to apps/minutes/models.py index 874eb62c4..3147d0a32 100644 --- a/minutes/models.py +++ b/apps/minutes/models.py @@ -5,8 +5,8 @@ from django.urls import reverse from markupfield.fields import MarkupField -from cms.models import ContentManageable -from minutes.managers import MinutesQuerySet +from apps.cms.models import ContentManageable +from apps.minutes.managers import MinutesQuerySet DEFAULT_MARKUP_TYPE = getattr(settings, "DEFAULT_MARKUP_TYPE", "restructuredtext") diff --git a/templates/minutes/minutes_detail.html b/apps/minutes/templates/minutes/minutes_detail.html similarity index 100% rename from templates/minutes/minutes_detail.html rename to apps/minutes/templates/minutes/minutes_detail.html diff --git a/templates/minutes/minutes_list.html b/apps/minutes/templates/minutes/minutes_list.html similarity index 100% rename from templates/minutes/minutes_list.html rename to apps/minutes/templates/minutes/minutes_list.html diff --git a/minutes/tests/__init__.py b/apps/minutes/tests/__init__.py similarity index 100% rename from minutes/tests/__init__.py rename to apps/minutes/tests/__init__.py diff --git a/minutes/tests/test_models.py b/apps/minutes/tests/test_models.py similarity index 96% rename from minutes/tests/test_models.py rename to apps/minutes/tests/test_models.py index c4f5d7f86..eedbd88c6 100644 --- a/minutes/tests/test_models.py +++ b/apps/minutes/tests/test_models.py @@ -2,7 +2,7 @@ from django.test import TestCase -from minutes.models import Minutes +from apps.minutes.models import Minutes class MinutesModelTests(TestCase): diff --git a/minutes/tests/test_views.py b/apps/minutes/tests/test_views.py similarity index 98% rename from minutes/tests/test_views.py rename to apps/minutes/tests/test_views.py index dfb676a8c..d5989ffb8 100644 --- a/minutes/tests/test_views.py +++ b/apps/minutes/tests/test_views.py @@ -5,7 +5,7 @@ from django.urls import reverse from django.utils import timezone -from minutes.models import Minutes +from apps.minutes.models import Minutes User = get_user_model() diff --git a/minutes/urls.py b/apps/minutes/urls.py similarity index 83% rename from minutes/urls.py rename to apps/minutes/urls.py index 711e0bdcb..c57ad90f8 100644 --- a/minutes/urls.py +++ b/apps/minutes/urls.py @@ -2,8 +2,8 @@ from django.urls import path, re_path -from minutes import views -from minutes.feeds import MinutesFeed +from apps.minutes import views +from apps.minutes.feeds import MinutesFeed urlpatterns = [ path("", views.MinutesList.as_view(), name="minutes_list"), diff --git a/minutes/views.py b/apps/minutes/views.py similarity index 97% rename from minutes/views.py rename to apps/minutes/views.py index 751467528..d56fbcd4c 100644 --- a/minutes/views.py +++ b/apps/minutes/views.py @@ -4,7 +4,7 @@ from django.http import Http404 from django.views.generic import DetailView, ListView -from minutes.models import Minutes +from apps.minutes.models import Minutes class MinutesList(ListView): diff --git a/nominations/__init__.py b/apps/nominations/__init__.py similarity index 100% rename from nominations/__init__.py rename to apps/nominations/__init__.py diff --git a/nominations/admin.py b/apps/nominations/admin.py similarity index 94% rename from nominations/admin.py rename to apps/nominations/admin.py index e17fb760e..4b19aff51 100644 --- a/nominations/admin.py +++ b/apps/nominations/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin from django.db.models.functions import Lower -from nominations.models import Election, Nomination, Nominee +from apps.nominations.models import Election, Nomination, Nominee @admin.register(Election) diff --git a/nominations/apps.py b/apps/nominations/apps.py similarity index 76% rename from nominations/apps.py rename to apps/nominations/apps.py index 1108c4a6c..4290a496d 100644 --- a/nominations/apps.py +++ b/apps/nominations/apps.py @@ -6,4 +6,5 @@ class NominationsAppConfig(AppConfig): """App configuration for PSF board nominations.""" - name = "nominations" + name = "apps.nominations" + label = "nominations" diff --git a/nominations/forms.py b/apps/nominations/forms.py similarity index 98% rename from nominations/forms.py rename to apps/nominations/forms.py index cfb56cd82..f00b46732 100644 --- a/nominations/forms.py +++ b/apps/nominations/forms.py @@ -4,7 +4,7 @@ from django.utils.safestring import mark_safe from markupfield.widgets import MarkupTextarea -from nominations.models import Nomination +from apps.nominations.models import Nomination class NominationForm(forms.ModelForm): diff --git a/nominations/migrations/0001_initial.py b/apps/nominations/migrations/0001_initial.py similarity index 100% rename from nominations/migrations/0001_initial.py rename to apps/nominations/migrations/0001_initial.py diff --git a/nominations/migrations/0002_auto_20190514_1435.py b/apps/nominations/migrations/0002_auto_20190514_1435.py similarity index 100% rename from nominations/migrations/0002_auto_20190514_1435.py rename to apps/nominations/migrations/0002_auto_20190514_1435.py diff --git a/nominations/migrations/__init__.py b/apps/nominations/migrations/__init__.py similarity index 100% rename from nominations/migrations/__init__.py rename to apps/nominations/migrations/__init__.py diff --git a/nominations/models.py b/apps/nominations/models.py similarity index 99% rename from nominations/models.py rename to apps/nominations/models.py index 6dd0ed1a1..c440999a4 100644 --- a/nominations/models.py +++ b/apps/nominations/models.py @@ -10,8 +10,8 @@ from django.utils.text import slugify from markupfield.fields import MarkupField +from apps.users.models import User from fastly.utils import purge_url -from users.models import User class Election(models.Model): diff --git a/templates/nominations/election_detail.html b/apps/nominations/templates/nominations/election_detail.html similarity index 100% rename from templates/nominations/election_detail.html rename to apps/nominations/templates/nominations/election_detail.html diff --git a/templates/nominations/election_list.html b/apps/nominations/templates/nominations/election_list.html similarity index 100% rename from templates/nominations/election_list.html rename to apps/nominations/templates/nominations/election_list.html diff --git a/templates/nominations/nomination_accept_form.html b/apps/nominations/templates/nominations/nomination_accept_form.html similarity index 100% rename from templates/nominations/nomination_accept_form.html rename to apps/nominations/templates/nominations/nomination_accept_form.html diff --git a/templates/nominations/nomination_detail.html b/apps/nominations/templates/nominations/nomination_detail.html similarity index 100% rename from templates/nominations/nomination_detail.html rename to apps/nominations/templates/nominations/nomination_detail.html diff --git a/templates/nominations/nomination_form.html b/apps/nominations/templates/nominations/nomination_form.html similarity index 100% rename from templates/nominations/nomination_form.html rename to apps/nominations/templates/nominations/nomination_form.html diff --git a/templates/nominations/nominee_detail.html b/apps/nominations/templates/nominations/nominee_detail.html similarity index 100% rename from templates/nominations/nominee_detail.html rename to apps/nominations/templates/nominations/nominee_detail.html diff --git a/templates/nominations/nominee_list.html b/apps/nominations/templates/nominations/nominee_list.html similarity index 100% rename from templates/nominations/nominee_list.html rename to apps/nominations/templates/nominations/nominee_list.html diff --git a/nominations/templatetags/__init__.py b/apps/nominations/templatetags/__init__.py similarity index 100% rename from nominations/templatetags/__init__.py rename to apps/nominations/templatetags/__init__.py diff --git a/nominations/templatetags/nominations.py b/apps/nominations/templatetags/nominations.py similarity index 100% rename from nominations/templatetags/nominations.py rename to apps/nominations/templatetags/nominations.py diff --git a/nominations/urls.py b/apps/nominations/urls.py similarity index 96% rename from nominations/urls.py rename to apps/nominations/urls.py index 065271e87..c10c7a646 100644 --- a/nominations/urls.py +++ b/apps/nominations/urls.py @@ -2,7 +2,7 @@ from django.urls import path -from nominations import views +from apps.nominations import views app_name = "nominations" urlpatterns = [ diff --git a/nominations/views.py b/apps/nominations/views.py similarity index 98% rename from nominations/views.py rename to apps/nominations/views.py index a9451ba3c..b5c90b455 100644 --- a/nominations/views.py +++ b/apps/nominations/views.py @@ -6,8 +6,8 @@ from django.urls import reverse from django.views.generic import CreateView, DetailView, ListView, UpdateView -from nominations.forms import NominationAcceptForm, NominationCreateForm, NominationForm -from nominations.models import Election, Nomination, Nominee +from apps.nominations.forms import NominationAcceptForm, NominationCreateForm, NominationForm +from apps.nominations.models import Election, Nomination, Nominee from pydotorg.mixins import LoginRequiredMixin diff --git a/pages/__init__.py b/apps/pages/__init__.py similarity index 100% rename from pages/__init__.py rename to apps/pages/__init__.py diff --git a/pages/admin.py b/apps/pages/admin.py similarity index 94% rename from pages/admin.py rename to apps/pages/admin.py index 0a77e731a..1b0a6b342 100644 --- a/pages/admin.py +++ b/apps/pages/admin.py @@ -2,8 +2,8 @@ from django.contrib import admin -from cms.admin import ContentManageableModelAdmin -from pages.models import DocumentFile, Image, Page +from apps.cms.admin import ContentManageableModelAdmin +from apps.pages.models import DocumentFile, Image, Page class ImageInlineAdmin(admin.StackedInline): diff --git a/pages/api.py b/apps/pages/api.py similarity index 95% rename from pages/api.py rename to apps/pages/api.py index d38c18da0..bfe9907a1 100644 --- a/pages/api.py +++ b/apps/pages/api.py @@ -2,8 +2,8 @@ from rest_framework.authentication import TokenAuthentication -from pages.models import Page -from pages.serializers import PageSerializer +from apps.pages.models import Page +from apps.pages.serializers import PageSerializer from pydotorg.drf import ( BaseFilterSet, BaseReadOnlyAPIViewSet, diff --git a/pages/apps.py b/apps/pages/apps.py similarity index 79% rename from pages/apps.py rename to apps/pages/apps.py index 81b49f5f9..bfff9f246 100644 --- a/pages/apps.py +++ b/apps/pages/apps.py @@ -6,4 +6,5 @@ class PagesAppConfig(AppConfig): """App configuration for the pages app.""" - name = "pages" + name = "apps.pages" + label = "pages" diff --git a/pages/factories.py b/apps/pages/factories.py similarity index 90% rename from pages/factories.py rename to apps/pages/factories.py index b4f293a8e..c068c59c1 100644 --- a/pages/factories.py +++ b/apps/pages/factories.py @@ -4,8 +4,8 @@ from django.template.defaultfilters import slugify from factory.django import DjangoModelFactory -from pages.models import Page -from users.factories import UserFactory +from apps.pages.models import Page +from apps.users.factories import UserFactory class PageFactory(DjangoModelFactory): diff --git a/pages/management/__init__.py b/apps/pages/management/__init__.py similarity index 100% rename from pages/management/__init__.py rename to apps/pages/management/__init__.py diff --git a/pages/management/commands/__init__.py b/apps/pages/management/commands/__init__.py similarity index 100% rename from pages/management/commands/__init__.py rename to apps/pages/management/commands/__init__.py diff --git a/pages/management/commands/fix_success_story_images.py b/apps/pages/management/commands/fix_success_story_images.py similarity index 97% rename from pages/management/commands/fix_success_story_images.py rename to apps/pages/management/commands/fix_success_story_images.py index e45d5c0bc..c355b5dec 100644 --- a/pages/management/commands/fix_success_story_images.py +++ b/apps/pages/management/commands/fix_success_story_images.py @@ -7,7 +7,7 @@ from django.core.files import File from django.core.management.base import BaseCommand -from pages.models import Image, Page, page_image_path +from apps.pages.models import Image, Page, page_image_path HTTP_OK = 200 diff --git a/pages/management/commands/import_pages_from_svn.py b/apps/pages/management/commands/import_pages_from_svn.py similarity index 97% rename from pages/management/commands/import_pages_from_svn.py rename to apps/pages/management/commands/import_pages_from_svn.py index b5ff47144..4417b5bb2 100644 --- a/pages/management/commands/import_pages_from_svn.py +++ b/apps/pages/management/commands/import_pages_from_svn.py @@ -10,8 +10,8 @@ from django.core.exceptions import ImproperlyConfigured from django.core.management.base import BaseCommand -from pages.models import Image, Page -from pages.parser import parse_page +from apps.pages.models import Image, Page +from apps.pages.parser import parse_page def fix_image_path(src): diff --git a/pages/managers.py b/apps/pages/managers.py similarity index 100% rename from pages/managers.py rename to apps/pages/managers.py diff --git a/pages/middleware.py b/apps/pages/middleware.py similarity index 96% rename from pages/middleware.py rename to apps/pages/middleware.py index fe6012805..39553e36f 100644 --- a/pages/middleware.py +++ b/apps/pages/middleware.py @@ -6,8 +6,8 @@ from django import http from django.conf import settings -from pages.models import Page -from pages.views import PageView +from apps.pages.models import Page +from apps.pages.views import PageView class PageFallbackMiddleware: diff --git a/pages/migrations/0001_initial.py b/apps/pages/migrations/0001_initial.py similarity index 97% rename from pages/migrations/0001_initial.py rename to apps/pages/migrations/0001_initial.py index 2ca91aff2..099d570a1 100644 --- a/pages/migrations/0001_initial.py +++ b/apps/pages/migrations/0001_initial.py @@ -6,7 +6,7 @@ from django.conf import settings from django.db import migrations, models -import pages.models +import apps.pages.models class Migration(migrations.Migration): @@ -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=apps.pages.models.page_image_path, max_length=400)), ], options={}, bases=(models.Model,), diff --git a/pages/migrations/0002_auto_20150416_1853.py b/apps/pages/migrations/0002_auto_20150416_1853.py similarity index 100% rename from pages/migrations/0002_auto_20150416_1853.py rename to apps/pages/migrations/0002_auto_20150416_1853.py diff --git a/pages/migrations/0003_auto_20230214_2113.py b/apps/pages/migrations/0003_auto_20230214_2113.py similarity index 100% rename from pages/migrations/0003_auto_20230214_2113.py rename to apps/pages/migrations/0003_auto_20230214_2113.py diff --git a/pages/migrations/0004_alter_page_creator_alter_page_last_modified_by.py b/apps/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 apps/pages/migrations/0004_alter_page_creator_alter_page_last_modified_by.py diff --git a/pages/migrations/__init__.py b/apps/pages/migrations/__init__.py similarity index 100% rename from pages/migrations/__init__.py rename to apps/pages/migrations/__init__.py diff --git a/pages/models.py b/apps/pages/models.py similarity index 98% rename from pages/models.py rename to apps/pages/models.py index 9442387fb..e6bbe129e 100644 --- a/pages/models.py +++ b/apps/pages/models.py @@ -18,9 +18,9 @@ from markupfield.fields import MarkupField from markupfield.markup import DEFAULT_MARKUP_TYPES -from cms.models import ContentManageable +from apps.cms.models import ContentManageable +from apps.pages.managers import PageQuerySet from fastly.utils import purge_url -from pages.managers import PageQuerySet DEFAULT_MARKUP_TYPE = getattr(settings, "DEFAULT_MARKUP_TYPE", "restructuredtext") diff --git a/pages/parser.py b/apps/pages/parser.py similarity index 100% rename from pages/parser.py rename to apps/pages/parser.py diff --git a/pages/search_indexes.py b/apps/pages/search_indexes.py similarity index 97% rename from pages/search_indexes.py rename to apps/pages/search_indexes.py index f296fc4fe..f94497773 100644 --- a/pages/search_indexes.py +++ b/apps/pages/search_indexes.py @@ -3,7 +3,7 @@ from django.template.defaultfilters import striptags, truncatewords_html from haystack import indexes -from pages.models import Page +from apps.pages.models import Page class PageIndex(indexes.SearchIndex, indexes.Indexable): diff --git a/pages/serializers.py b/apps/pages/serializers.py similarity index 93% rename from pages/serializers.py rename to apps/pages/serializers.py index 4c3b563a4..2d842e03f 100644 --- a/pages/serializers.py +++ b/apps/pages/serializers.py @@ -2,7 +2,7 @@ from rest_framework import serializers -from pages.models import Page +from apps.pages.models import Page class PageSerializer(serializers.HyperlinkedModelSerializer): diff --git a/templates/pages/default.html b/apps/pages/templates/pages/default.html similarity index 100% rename from templates/pages/default.html rename to apps/pages/templates/pages/default.html diff --git a/templates/pages/raw.html b/apps/pages/templates/pages/raw.html similarity index 100% rename from templates/pages/raw.html rename to apps/pages/templates/pages/raw.html diff --git a/pages/tests/__init__.py b/apps/pages/tests/__init__.py similarity index 100% rename from pages/tests/__init__.py rename to apps/pages/tests/__init__.py diff --git a/pages/tests/base.py b/apps/pages/tests/base.py similarity index 93% rename from pages/tests/base.py rename to apps/pages/tests/base.py index c595eb88b..e966f3f14 100644 --- a/pages/tests/base.py +++ b/apps/pages/tests/base.py @@ -1,7 +1,7 @@ from django.contrib.auth import get_user_model from django.test import TestCase -from pages.models import Page +from apps.pages.models import Page User = get_user_model() diff --git a/pages/tests/fake_svn_content_checkout/about/content.ht b/apps/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 apps/pages/tests/fake_svn_content_checkout/about/content.ht diff --git a/pages/tests/fake_svn_content_checkout/about/success/dlink/content.rst b/apps/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 apps/pages/tests/fake_svn_content_checkout/about/success/dlink/content.rst diff --git a/pages/tests/fake_svn_content_checkout/community/content.ht b/apps/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 apps/pages/tests/fake_svn_content_checkout/community/content.ht diff --git a/pages/tests/fake_svn_content_checkout/content.ht b/apps/pages/tests/fake_svn_content_checkout/content.ht similarity index 100% rename from pages/tests/fake_svn_content_checkout/content.ht rename to apps/pages/tests/fake_svn_content_checkout/content.ht diff --git a/pages/tests/test_api.py b/apps/pages/tests/test_api.py similarity index 97% rename from pages/tests/test_api.py rename to apps/pages/tests/test_api.py index 2d153fd3a..2cbf4711a 100644 --- a/pages/tests/test_api.py +++ b/apps/pages/tests/test_api.py @@ -1,8 +1,8 @@ from rest_framework.test import APITestCase -from pages.factories import PageFactory +from apps.pages.factories import PageFactory +from apps.users.factories import UserFactory from pydotorg.drf import BaseAPITestCase -from users.factories import UserFactory class PageApiViewsTest(BaseAPITestCase, APITestCase): diff --git a/pages/tests/test_models.py b/apps/pages/tests/test_models.py similarity index 94% rename from pages/tests/test_models.py rename to apps/pages/tests/test_models.py index 683e97570..9c67ea00f 100644 --- a/pages/tests/test_models.py +++ b/apps/pages/tests/test_models.py @@ -3,8 +3,8 @@ import ddt -from pages.models import PAGE_PATH_RE, Page -from pages.tests.base import BasePageTests +from apps.pages.models import PAGE_PATH_RE, Page +from apps.pages.tests.base import BasePageTests class PageModelTests(BasePageTests): diff --git a/pages/tests/test_parser.py b/apps/pages/tests/test_parser.py similarity index 91% rename from pages/tests/test_parser.py rename to apps/pages/tests/test_parser.py index 70d13e683..d0b712fc1 100644 --- a/pages/tests/test_parser.py +++ b/apps/pages/tests/test_parser.py @@ -4,8 +4,8 @@ from django.core.management import call_command from django.test import TestCase -from pages.models import Page -from pages.parser import determine_page_content_type +from apps.pages.models import Page +from apps.pages.parser import determine_page_content_type class PagesParserTests(TestCase): diff --git a/pages/tests/test_views.py b/apps/pages/tests/test_views.py similarity index 96% rename from pages/tests/test_views.py rename to apps/pages/tests/test_views.py index c76ba906e..ef5b0e654 100644 --- a/pages/tests/test_views.py +++ b/apps/pages/tests/test_views.py @@ -1,7 +1,7 @@ from django.contrib.redirects.models import Redirect from django.contrib.sites.models import Site -from pages.tests.base import BasePageTests +from apps.pages.tests.base import BasePageTests class PageViewTests(BasePageTests): diff --git a/pages/urls.py b/apps/pages/urls.py similarity index 80% rename from pages/urls.py rename to apps/pages/urls.py index 904ebd0d4..c6f042888 100644 --- a/pages/urls.py +++ b/apps/pages/urls.py @@ -2,7 +2,7 @@ from django.urls import path -from pages.views import PageView +from apps.pages.views import PageView urlpatterns = [ path("/", PageView.as_view(), name="page_detail"), diff --git a/pages/views.py b/apps/pages/views.py similarity index 96% rename from pages/views.py rename to apps/pages/views.py index 834a74867..8a0bb97f0 100644 --- a/pages/views.py +++ b/apps/pages/views.py @@ -6,8 +6,8 @@ from django.urls import reverse from django.views.generic import DetailView -from downloads.models import Release -from pages.models import Page +from apps.downloads.models import Release +from apps.pages.models import Page class PageView(DetailView): diff --git a/sponsors/__init__.py b/apps/sponsors/__init__.py similarity index 100% rename from sponsors/__init__.py rename to apps/sponsors/__init__.py diff --git a/sponsors/admin.py b/apps/sponsors/admin.py similarity index 99% rename from sponsors/admin.py rename to apps/sponsors/admin.py index 2ac22520a..376839ac8 100644 --- a/sponsors/admin.py +++ b/apps/sponsors/admin.py @@ -24,17 +24,17 @@ StackedPolymorphicInline, ) -from cms.admin import ContentManageableModelAdmin -from mailing.admin import BaseEmailTemplateAdmin -from sponsors import views_admin -from sponsors.forms import ( +from apps.cms.admin import ContentManageableModelAdmin +from apps.mailing.admin import BaseEmailTemplateAdmin +from apps.sponsors import views_admin +from apps.sponsors.forms import ( CloneApplicationConfigForm, RequiredImgAssetConfigurationForm, SponsorBenefitAdminInlineForm, SponsorshipBenefitAdminForm, SponsorshipReviewAdminForm, ) -from sponsors.models import ( +from apps.sponsors.models import ( SPONSOR_TEMPLATE_HELP_TEXT, BenefitFeature, BenefitFeatureConfiguration, diff --git a/sponsors/api.py b/apps/sponsors/api.py similarity index 96% rename from sponsors/api.py rename to apps/sponsors/api.py index 36c7753f1..bb5914188 100644 --- a/sponsors/api.py +++ b/apps/sponsors/api.py @@ -6,8 +6,8 @@ from rest_framework.response import Response from rest_framework.views import APIView -from sponsors.models import BenefitFeature, GenericAsset, LogoPlacement, Sponsorship -from sponsors.serializers import ( +from apps.sponsors.models import BenefitFeature, GenericAsset, LogoPlacement, Sponsorship +from apps.sponsors.serializers import ( AssetSerializer, FilterAssetsSerializer, FilterLogoPlacementsSerializer, diff --git a/sponsors/apps.py b/apps/sponsors/apps.py similarity index 78% rename from sponsors/apps.py rename to apps/sponsors/apps.py index a926d937f..b8321049d 100644 --- a/sponsors/apps.py +++ b/apps/sponsors/apps.py @@ -6,4 +6,5 @@ class SponsorsAppConfig(AppConfig): """App configuration for the sponsors Django application.""" - name = "sponsors" + name = "apps.sponsors" + label = "sponsors" diff --git a/sponsors/contracts.py b/apps/sponsors/contracts.py similarity index 100% rename from sponsors/contracts.py rename to apps/sponsors/contracts.py diff --git a/sponsors/cookies.py b/apps/sponsors/cookies.py similarity index 100% rename from sponsors/cookies.py rename to apps/sponsors/cookies.py diff --git a/sponsors/exceptions.py b/apps/sponsors/exceptions.py similarity index 100% rename from sponsors/exceptions.py rename to apps/sponsors/exceptions.py diff --git a/sponsors/forms.py b/apps/sponsors/forms.py similarity index 99% rename from sponsors/forms.py rename to apps/sponsors/forms.py index c89b5b055..3829596e6 100644 --- a/sponsors/forms.py +++ b/apps/sponsors/forms.py @@ -15,7 +15,7 @@ from django.utils.translation import gettext_lazy as _ from django_countries.fields import CountryField -from sponsors.models import ( +from apps.sponsors.models import ( SPONSOR_TEMPLATE_HELP_TEXT, BenefitFeature, RequiredImgAssetConfiguration, diff --git a/sponsors/management/__init__.py b/apps/sponsors/management/__init__.py similarity index 100% rename from sponsors/management/__init__.py rename to apps/sponsors/management/__init__.py diff --git a/sponsors/management/commands/__init__.py b/apps/sponsors/management/commands/__init__.py similarity index 100% rename from sponsors/management/commands/__init__.py rename to apps/sponsors/management/commands/__init__.py diff --git a/sponsors/management/commands/check_sponsorship_assets_due_date.py b/apps/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 apps/sponsors/management/commands/check_sponsorship_assets_due_date.py index 94560d7ab..b8aab5056 100644 --- a/sponsors/management/commands/check_sponsorship_assets_due_date.py +++ b/apps/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 BenefitFeature, Sponsorship -from sponsors.notifications import AssetCloseToDueDateNotificationToSponsors +from apps.sponsors.models import BenefitFeature, Sponsorship +from apps.sponsors.notifications import AssetCloseToDueDateNotificationToSponsors class Command(BaseCommand): diff --git a/sponsors/management/commands/create_contracts.py b/apps/sponsors/management/commands/create_contracts.py similarity index 95% rename from sponsors/management/commands/create_contracts.py rename to apps/sponsors/management/commands/create_contracts.py index 179d42a21..48294a274 100644 --- a/sponsors/management/commands/create_contracts.py +++ b/apps/sponsors/management/commands/create_contracts.py @@ -1,6 +1,6 @@ from django.core.management import BaseCommand -from sponsors.models import Contract, Sponsorship +from apps.sponsors.models import Contract, Sponsorship # 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/apps/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 apps/sponsors/management/commands/create_pycon_vouchers_for_sponsors.py index 3091eaabd..933670ce9 100644 --- a/sponsors/management/commands/create_pycon_vouchers_for_sponsors.py +++ b/apps/sponsors/management/commands/create_pycon_vouchers_for_sponsors.py @@ -7,7 +7,7 @@ from django.conf import settings from django.core.management import BaseCommand -from sponsors.models import ( +from apps.sponsors.models import ( BenefitFeature, ProvidedTextAsset, SponsorBenefit, diff --git a/sponsors/management/commands/create_test_sponsor_data.py b/apps/sponsors/management/commands/create_test_sponsor_data.py similarity index 98% rename from sponsors/management/commands/create_test_sponsor_data.py rename to apps/sponsors/management/commands/create_test_sponsor_data.py index 8bd9c76aa..18f90214d 100644 --- a/sponsors/management/commands/create_test_sponsor_data.py +++ b/apps/sponsors/management/commands/create_test_sponsor_data.py @@ -9,7 +9,7 @@ from django.core.management.base import BaseCommand, CommandError from django.utils import timezone -from sponsors.models import Contract, Sponsor, SponsorContact, Sponsorship, SponsorshipPackage +from apps.sponsors.models import Contract, Sponsor, SponsorContact, Sponsorship, SponsorshipPackage User = get_user_model() diff --git a/sponsors/management/commands/reset_sponsorship_benefits.py b/apps/sponsors/management/commands/reset_sponsorship_benefits.py similarity index 98% rename from sponsors/management/commands/reset_sponsorship_benefits.py rename to apps/sponsors/management/commands/reset_sponsorship_benefits.py index 807b30a09..9930b526a 100644 --- a/sponsors/management/commands/reset_sponsorship_benefits.py +++ b/apps/sponsors/management/commands/reset_sponsorship_benefits.py @@ -1,7 +1,7 @@ from django.core.management.base import BaseCommand from django.db import transaction -from sponsors.models import Sponsorship, SponsorshipBenefit +from apps.sponsors.models import Sponsorship, SponsorshipBenefit DRY_RUN_PREVIEW_LIMIT = 5 @@ -102,7 +102,7 @@ def handle(self, *args, **options): # noqa: C901, PLR0912, PLR0915 - management with transaction.atomic(): from django.contrib.contenttypes.models import ContentType - from sponsors.models import GenericAsset, SponsorBenefit + from apps.sponsors.models import GenericAsset, SponsorBenefit # Get count of current benefits before deletion current_count = sponsorship.benefits.count() diff --git a/sponsors/migrations/0001_initial.py b/apps/sponsors/migrations/0001_initial.py similarity index 100% rename from sponsors/migrations/0001_initial.py rename to apps/sponsors/migrations/0001_initial.py diff --git a/sponsors/migrations/0002_auto_20150416_1853.py b/apps/sponsors/migrations/0002_auto_20150416_1853.py similarity index 100% rename from sponsors/migrations/0002_auto_20150416_1853.py rename to apps/sponsors/migrations/0002_auto_20150416_1853.py diff --git a/sponsors/migrations/0003_auto_20170821_2000.py b/apps/sponsors/migrations/0003_auto_20170821_2000.py similarity index 100% rename from sponsors/migrations/0003_auto_20170821_2000.py rename to apps/sponsors/migrations/0003_auto_20170821_2000.py diff --git a/sponsors/migrations/0004_auto_20201014_1622.py b/apps/sponsors/migrations/0004_auto_20201014_1622.py similarity index 100% rename from sponsors/migrations/0004_auto_20201014_1622.py rename to apps/sponsors/migrations/0004_auto_20201014_1622.py diff --git a/sponsors/migrations/0005_auto_20201015_0908.py b/apps/sponsors/migrations/0005_auto_20201015_0908.py similarity index 100% rename from sponsors/migrations/0005_auto_20201015_0908.py rename to apps/sponsors/migrations/0005_auto_20201015_0908.py diff --git a/sponsors/migrations/0006_auto_20201016_1517.py b/apps/sponsors/migrations/0006_auto_20201016_1517.py similarity index 100% rename from sponsors/migrations/0006_auto_20201016_1517.py rename to apps/sponsors/migrations/0006_auto_20201016_1517.py diff --git a/sponsors/migrations/0007_auto_20201021_1410.py b/apps/sponsors/migrations/0007_auto_20201021_1410.py similarity index 100% rename from sponsors/migrations/0007_auto_20201021_1410.py rename to apps/sponsors/migrations/0007_auto_20201021_1410.py diff --git a/sponsors/migrations/0008_auto_20201028_1814.py b/apps/sponsors/migrations/0008_auto_20201028_1814.py similarity index 100% rename from sponsors/migrations/0008_auto_20201028_1814.py rename to apps/sponsors/migrations/0008_auto_20201028_1814.py diff --git a/sponsors/migrations/0009_auto_20201103_1259.py b/apps/sponsors/migrations/0009_auto_20201103_1259.py similarity index 100% rename from sponsors/migrations/0009_auto_20201103_1259.py rename to apps/sponsors/migrations/0009_auto_20201103_1259.py diff --git a/sponsors/migrations/0010_auto_20201103_1313.py b/apps/sponsors/migrations/0010_auto_20201103_1313.py similarity index 100% rename from sponsors/migrations/0010_auto_20201103_1313.py rename to apps/sponsors/migrations/0010_auto_20201103_1313.py diff --git a/sponsors/migrations/0011_auto_20201111_1724.py b/apps/sponsors/migrations/0011_auto_20201111_1724.py similarity index 100% rename from sponsors/migrations/0011_auto_20201111_1724.py rename to apps/sponsors/migrations/0011_auto_20201111_1724.py diff --git a/sponsors/migrations/0012_sponsorship_for_modified_package.py b/apps/sponsors/migrations/0012_sponsorship_for_modified_package.py similarity index 100% rename from sponsors/migrations/0012_sponsorship_for_modified_package.py rename to apps/sponsors/migrations/0012_sponsorship_for_modified_package.py diff --git a/sponsors/migrations/0013_sponsorbenefit_benefit_internal_value.py b/apps/sponsors/migrations/0013_sponsorbenefit_benefit_internal_value.py similarity index 100% rename from sponsors/migrations/0013_sponsorbenefit_benefit_internal_value.py rename to apps/sponsors/migrations/0013_sponsorbenefit_benefit_internal_value.py diff --git a/sponsors/migrations/0014_auto_20201116_1437.py b/apps/sponsors/migrations/0014_auto_20201116_1437.py similarity index 100% rename from sponsors/migrations/0014_auto_20201116_1437.py rename to apps/sponsors/migrations/0014_auto_20201116_1437.py diff --git a/sponsors/migrations/0015_auto_20201117_1739.py b/apps/sponsors/migrations/0015_auto_20201117_1739.py similarity index 100% rename from sponsors/migrations/0015_auto_20201117_1739.py rename to apps/sponsors/migrations/0015_auto_20201117_1739.py diff --git a/sponsors/migrations/0016_auto_20201119_1448.py b/apps/sponsors/migrations/0016_auto_20201119_1448.py similarity index 100% rename from sponsors/migrations/0016_auto_20201119_1448.py rename to apps/sponsors/migrations/0016_auto_20201119_1448.py diff --git a/sponsors/migrations/0017_sponsorbenefit_added_by_user.py b/apps/sponsors/migrations/0017_sponsorbenefit_added_by_user.py similarity index 100% rename from sponsors/migrations/0017_sponsorbenefit_added_by_user.py rename to apps/sponsors/migrations/0017_sponsorbenefit_added_by_user.py diff --git a/sponsors/migrations/0018_auto_20201201_1659.py b/apps/sponsors/migrations/0018_auto_20201201_1659.py similarity index 100% rename from sponsors/migrations/0018_auto_20201201_1659.py rename to apps/sponsors/migrations/0018_auto_20201201_1659.py diff --git a/sponsors/migrations/0019_sponsor_twitter_handle.py b/apps/sponsors/migrations/0019_sponsor_twitter_handle.py similarity index 100% rename from sponsors/migrations/0019_sponsor_twitter_handle.py rename to apps/sponsors/migrations/0019_sponsor_twitter_handle.py diff --git a/sponsors/migrations/0019_statementofwork.py b/apps/sponsors/migrations/0019_statementofwork.py similarity index 100% rename from sponsors/migrations/0019_statementofwork.py rename to apps/sponsors/migrations/0019_statementofwork.py diff --git a/sponsors/migrations/0020_auto_20201210_1802.py b/apps/sponsors/migrations/0020_auto_20201210_1802.py similarity index 100% rename from sponsors/migrations/0020_auto_20201210_1802.py rename to apps/sponsors/migrations/0020_auto_20201210_1802.py diff --git a/sponsors/migrations/0020_sponsorshipbenefit_unavailable.py b/apps/sponsors/migrations/0020_sponsorshipbenefit_unavailable.py similarity index 100% rename from sponsors/migrations/0020_sponsorshipbenefit_unavailable.py rename to apps/sponsors/migrations/0020_sponsorshipbenefit_unavailable.py diff --git a/sponsors/migrations/0021_auto_20201211_2120.py b/apps/sponsors/migrations/0021_auto_20201211_2120.py similarity index 100% rename from sponsors/migrations/0021_auto_20201211_2120.py rename to apps/sponsors/migrations/0021_auto_20201211_2120.py diff --git a/sponsors/migrations/0022_sponsorcontact_administrative.py b/apps/sponsors/migrations/0022_sponsorcontact_administrative.py similarity index 100% rename from sponsors/migrations/0022_sponsorcontact_administrative.py rename to apps/sponsors/migrations/0022_sponsorcontact_administrative.py diff --git a/sponsors/migrations/0023_merge_20210406_1522.py b/apps/sponsors/migrations/0023_merge_20210406_1522.py similarity index 100% rename from sponsors/migrations/0023_merge_20210406_1522.py rename to apps/sponsors/migrations/0023_merge_20210406_1522.py diff --git a/sponsors/migrations/0024_auto_20210414_1449.py b/apps/sponsors/migrations/0024_auto_20210414_1449.py similarity index 100% rename from sponsors/migrations/0024_auto_20210414_1449.py rename to apps/sponsors/migrations/0024_auto_20210414_1449.py diff --git a/sponsors/migrations/0025_auto_20210416_1939.py b/apps/sponsors/migrations/0025_auto_20210416_1939.py similarity index 100% rename from sponsors/migrations/0025_auto_20210416_1939.py rename to apps/sponsors/migrations/0025_auto_20210416_1939.py diff --git a/sponsors/migrations/0026_auto_20210416_1940.py b/apps/sponsors/migrations/0026_auto_20210416_1940.py similarity index 100% rename from sponsors/migrations/0026_auto_20210416_1940.py rename to apps/sponsors/migrations/0026_auto_20210416_1940.py diff --git a/sponsors/migrations/0027_sponsorbenefit_program_name.py b/apps/sponsors/migrations/0027_sponsorbenefit_program_name.py similarity index 100% rename from sponsors/migrations/0027_sponsorbenefit_program_name.py rename to apps/sponsors/migrations/0027_sponsorbenefit_program_name.py diff --git a/sponsors/migrations/0028_auto_20210707_1426.py b/apps/sponsors/migrations/0028_auto_20210707_1426.py similarity index 100% rename from sponsors/migrations/0028_auto_20210707_1426.py rename to apps/sponsors/migrations/0028_auto_20210707_1426.py diff --git a/sponsors/migrations/0029_auto_20210715_2015.py b/apps/sponsors/migrations/0029_auto_20210715_2015.py similarity index 100% rename from sponsors/migrations/0029_auto_20210715_2015.py rename to apps/sponsors/migrations/0029_auto_20210715_2015.py diff --git a/sponsors/migrations/0030_auto_20210715_2023.py b/apps/sponsors/migrations/0030_auto_20210715_2023.py similarity index 100% rename from sponsors/migrations/0030_auto_20210715_2023.py rename to apps/sponsors/migrations/0030_auto_20210715_2023.py diff --git a/sponsors/migrations/0031_auto_20210810_1232.py b/apps/sponsors/migrations/0031_auto_20210810_1232.py similarity index 100% rename from sponsors/migrations/0031_auto_20210810_1232.py rename to apps/sponsors/migrations/0031_auto_20210810_1232.py diff --git a/sponsors/migrations/0032_sponsorcontact_accounting.py b/apps/sponsors/migrations/0032_sponsorcontact_accounting.py similarity index 100% rename from sponsors/migrations/0032_sponsorcontact_accounting.py rename to apps/sponsors/migrations/0032_sponsorcontact_accounting.py diff --git a/sponsors/migrations/0033_tieredquantity_tieredquantityconfiguration.py b/apps/sponsors/migrations/0033_tieredquantity_tieredquantityconfiguration.py similarity index 100% rename from sponsors/migrations/0033_tieredquantity_tieredquantityconfiguration.py rename to apps/sponsors/migrations/0033_tieredquantity_tieredquantityconfiguration.py diff --git a/sponsors/migrations/0034_contract_document_docx.py b/apps/sponsors/migrations/0034_contract_document_docx.py similarity index 100% rename from sponsors/migrations/0034_contract_document_docx.py rename to apps/sponsors/migrations/0034_contract_document_docx.py diff --git a/sponsors/migrations/0035_auto_20210826_1929.py b/apps/sponsors/migrations/0035_auto_20210826_1929.py similarity index 85% rename from sponsors/migrations/0035_auto_20210826_1929.py rename to apps/sponsors/migrations/0035_auto_20210826_1929.py index cd951e4e2..672f58d49 100644 --- a/sponsors/migrations/0035_auto_20210826_1929.py +++ b/apps/sponsors/migrations/0035_auto_20210826_1929.py @@ -2,7 +2,7 @@ from django.db import migrations, models -import sponsors.models +import apps.sponsors.models class Migration(migrations.Migration): @@ -25,7 +25,7 @@ class Migration(migrations.Migration): model_name="contract", name="signed_document", field=models.FileField( - blank=True, upload_to=sponsors.models.signed_contract_random_path, verbose_name="Signed PDF" + blank=True, upload_to=apps.sponsors.models.signed_contract_random_path, verbose_name="Signed PDF" ), ), ] diff --git a/sponsors/migrations/0036_auto_20210826_1930.py b/apps/sponsors/migrations/0036_auto_20210826_1930.py similarity index 100% rename from sponsors/migrations/0036_auto_20210826_1930.py rename to apps/sponsors/migrations/0036_auto_20210826_1930.py diff --git a/sponsors/migrations/0037_sponsorship_package.py b/apps/sponsors/migrations/0037_sponsorship_package.py similarity index 100% rename from sponsors/migrations/0037_sponsorship_package.py rename to apps/sponsors/migrations/0037_sponsorship_package.py diff --git a/sponsors/migrations/0038_auto_20210827_1223.py b/apps/sponsors/migrations/0038_auto_20210827_1223.py similarity index 100% rename from sponsors/migrations/0038_auto_20210827_1223.py rename to apps/sponsors/migrations/0038_auto_20210827_1223.py diff --git a/sponsors/migrations/0039_auto_20210827_1248.py b/apps/sponsors/migrations/0039_auto_20210827_1248.py similarity index 100% rename from sponsors/migrations/0039_auto_20210827_1248.py rename to apps/sponsors/migrations/0039_auto_20210827_1248.py diff --git a/sponsors/migrations/0040_auto_20210827_1313.py b/apps/sponsors/migrations/0040_auto_20210827_1313.py similarity index 100% rename from sponsors/migrations/0040_auto_20210827_1313.py rename to apps/sponsors/migrations/0040_auto_20210827_1313.py diff --git a/sponsors/migrations/0041_auto_20210827_1313.py b/apps/sponsors/migrations/0041_auto_20210827_1313.py similarity index 100% rename from sponsors/migrations/0041_auto_20210827_1313.py rename to apps/sponsors/migrations/0041_auto_20210827_1313.py diff --git a/sponsors/migrations/0042_auto_20210827_1318.py b/apps/sponsors/migrations/0042_auto_20210827_1318.py similarity index 100% rename from sponsors/migrations/0042_auto_20210827_1318.py rename to apps/sponsors/migrations/0042_auto_20210827_1318.py diff --git a/sponsors/migrations/0043_auto_20210827_1343.py b/apps/sponsors/migrations/0043_auto_20210827_1343.py similarity index 100% rename from sponsors/migrations/0043_auto_20210827_1343.py rename to apps/sponsors/migrations/0043_auto_20210827_1343.py diff --git a/sponsors/migrations/0044_auto_20210827_1344.py b/apps/sponsors/migrations/0044_auto_20210827_1344.py similarity index 100% rename from sponsors/migrations/0044_auto_20210827_1344.py rename to apps/sponsors/migrations/0044_auto_20210827_1344.py diff --git a/sponsors/migrations/0045_add_added_by_user_sponsorbenefit.py b/apps/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 apps/sponsors/migrations/0045_add_added_by_user_sponsorbenefit.py diff --git a/sponsors/migrations/0046_sponsorshippackage_advertise.py b/apps/sponsors/migrations/0046_sponsorshippackage_advertise.py similarity index 100% rename from sponsors/migrations/0046_sponsorshippackage_advertise.py rename to apps/sponsors/migrations/0046_sponsorshippackage_advertise.py diff --git a/sponsors/migrations/0047_auto_20210908_1357.py b/apps/sponsors/migrations/0047_auto_20210908_1357.py similarity index 100% rename from sponsors/migrations/0047_auto_20210908_1357.py rename to apps/sponsors/migrations/0047_auto_20210908_1357.py diff --git a/sponsors/migrations/0048_auto_20210915_1425.py b/apps/sponsors/migrations/0048_auto_20210915_1425.py similarity index 100% rename from sponsors/migrations/0048_auto_20210915_1425.py rename to apps/sponsors/migrations/0048_auto_20210915_1425.py diff --git a/sponsors/migrations/0049_sponsoremailnotificationtemplate.py b/apps/sponsors/migrations/0049_sponsoremailnotificationtemplate.py similarity index 100% rename from sponsors/migrations/0049_sponsoremailnotificationtemplate.py rename to apps/sponsors/migrations/0049_sponsoremailnotificationtemplate.py diff --git a/sponsors/migrations/0050_emailtargetable_emailtargetableconfiguration.py b/apps/sponsors/migrations/0050_emailtargetable_emailtargetableconfiguration.py similarity index 100% rename from sponsors/migrations/0050_emailtargetable_emailtargetableconfiguration.py rename to apps/sponsors/migrations/0050_emailtargetable_emailtargetableconfiguration.py diff --git a/sponsors/migrations/0051_auto_20211022_1403.py b/apps/sponsors/migrations/0051_auto_20211022_1403.py similarity index 100% rename from sponsors/migrations/0051_auto_20211022_1403.py rename to apps/sponsors/migrations/0051_auto_20211022_1403.py diff --git a/sponsors/migrations/0052_requiredimgasset_requiredimgassetconfiguration.py b/apps/sponsors/migrations/0052_requiredimgasset_requiredimgassetconfiguration.py similarity index 100% rename from sponsors/migrations/0052_requiredimgasset_requiredimgassetconfiguration.py rename to apps/sponsors/migrations/0052_requiredimgasset_requiredimgassetconfiguration.py diff --git a/sponsors/migrations/0053_genericasset_imgasset.py b/apps/sponsors/migrations/0053_genericasset_imgasset.py similarity index 96% rename from sponsors/migrations/0053_genericasset_imgasset.py rename to apps/sponsors/migrations/0053_genericasset_imgasset.py index d0699f618..8bebebdae 100644 --- a/sponsors/migrations/0053_genericasset_imgasset.py +++ b/apps/sponsors/migrations/0053_genericasset_imgasset.py @@ -3,7 +3,7 @@ import django.db.models.deletion from django.db import migrations, models -import sponsors.models.assets +import apps.sponsors.models.assets class Migration(migrations.Migration): @@ -54,7 +54,7 @@ class Migration(migrations.Migration): to="sponsors.GenericAsset", ), ), - ("image", models.ImageField(null=True, upload_to=sponsors.models.assets.generic_asset_path)), + ("image", models.ImageField(null=True, upload_to=apps.sponsors.models.assets.generic_asset_path)), ], options={ "verbose_name": "Image Asset", diff --git a/sponsors/migrations/0054_auto_20211026_1432.py b/apps/sponsors/migrations/0054_auto_20211026_1432.py similarity index 100% rename from sponsors/migrations/0054_auto_20211026_1432.py rename to apps/sponsors/migrations/0054_auto_20211026_1432.py diff --git a/sponsors/migrations/0055_auto_20211026_1512.py b/apps/sponsors/migrations/0055_auto_20211026_1512.py similarity index 100% rename from sponsors/migrations/0055_auto_20211026_1512.py rename to apps/sponsors/migrations/0055_auto_20211026_1512.py diff --git a/sponsors/migrations/0056_textasset.py b/apps/sponsors/migrations/0056_textasset.py similarity index 100% rename from sponsors/migrations/0056_textasset.py rename to apps/sponsors/migrations/0056_textasset.py diff --git a/sponsors/migrations/0057_auto_20211026_1529.py b/apps/sponsors/migrations/0057_auto_20211026_1529.py similarity index 100% rename from sponsors/migrations/0057_auto_20211026_1529.py rename to apps/sponsors/migrations/0057_auto_20211026_1529.py diff --git a/sponsors/migrations/0058_auto_20211029_1427.py b/apps/sponsors/migrations/0058_auto_20211029_1427.py similarity index 100% rename from sponsors/migrations/0058_auto_20211029_1427.py rename to apps/sponsors/migrations/0058_auto_20211029_1427.py diff --git a/sponsors/migrations/0059_auto_20211029_1503.py b/apps/sponsors/migrations/0059_auto_20211029_1503.py similarity index 100% rename from sponsors/migrations/0059_auto_20211029_1503.py rename to apps/sponsors/migrations/0059_auto_20211029_1503.py diff --git a/sponsors/migrations/0060_auto_20211111_1526.py b/apps/sponsors/migrations/0060_auto_20211111_1526.py similarity index 100% rename from sponsors/migrations/0060_auto_20211111_1526.py rename to apps/sponsors/migrations/0060_auto_20211111_1526.py diff --git a/sponsors/migrations/0061_auto_20211108_1419.py b/apps/sponsors/migrations/0061_auto_20211108_1419.py similarity index 100% rename from sponsors/migrations/0061_auto_20211108_1419.py rename to apps/sponsors/migrations/0061_auto_20211108_1419.py diff --git a/sponsors/migrations/0062_auto_20211111_1529.py b/apps/sponsors/migrations/0062_auto_20211111_1529.py similarity index 100% rename from sponsors/migrations/0062_auto_20211111_1529.py rename to apps/sponsors/migrations/0062_auto_20211111_1529.py diff --git a/sponsors/migrations/0063_auto_20211220_1422.py b/apps/sponsors/migrations/0063_auto_20211220_1422.py similarity index 100% rename from sponsors/migrations/0063_auto_20211220_1422.py rename to apps/sponsors/migrations/0063_auto_20211220_1422.py diff --git a/sponsors/migrations/0064_sponsorshippackage_slug.py b/apps/sponsors/migrations/0064_sponsorshippackage_slug.py similarity index 100% rename from sponsors/migrations/0064_sponsorshippackage_slug.py rename to apps/sponsors/migrations/0064_sponsorshippackage_slug.py diff --git a/sponsors/migrations/0065_auto_20211223_1309.py b/apps/sponsors/migrations/0065_auto_20211223_1309.py similarity index 100% rename from sponsors/migrations/0065_auto_20211223_1309.py rename to apps/sponsors/migrations/0065_auto_20211223_1309.py diff --git a/sponsors/migrations/0066_auto_20211223_1318.py b/apps/sponsors/migrations/0066_auto_20211223_1318.py similarity index 100% rename from sponsors/migrations/0066_auto_20211223_1318.py rename to apps/sponsors/migrations/0066_auto_20211223_1318.py diff --git a/sponsors/migrations/0067_sponsorbenefit_a_la_carte.py b/apps/sponsors/migrations/0067_sponsorbenefit_a_la_carte.py similarity index 100% rename from sponsors/migrations/0067_sponsorbenefit_a_la_carte.py rename to apps/sponsors/migrations/0067_sponsorbenefit_a_la_carte.py diff --git a/sponsors/migrations/0068_auto_20220110_1841.py b/apps/sponsors/migrations/0068_auto_20220110_1841.py similarity index 100% rename from sponsors/migrations/0068_auto_20220110_1841.py rename to apps/sponsors/migrations/0068_auto_20220110_1841.py diff --git a/sponsors/migrations/0069_auto_20220110_2148.py b/apps/sponsors/migrations/0069_auto_20220110_2148.py similarity index 95% rename from sponsors/migrations/0069_auto_20220110_2148.py rename to apps/sponsors/migrations/0069_auto_20220110_2148.py index 33d3fa055..5a91fe991 100644 --- a/sponsors/migrations/0069_auto_20220110_2148.py +++ b/apps/sponsors/migrations/0069_auto_20220110_2148.py @@ -3,7 +3,7 @@ import django.db.models.deletion from django.db import migrations, models -import sponsors.models.benefits +import apps.sponsors.models.benefits class Migration(migrations.Migration): @@ -66,7 +66,7 @@ class Migration(migrations.Migration): "abstract": False, "base_manager_name": "objects", }, - bases=(sponsors.models.benefits.ProvidedAssetMixin, "sponsors.benefitfeature", models.Model), + bases=(apps.sponsors.models.benefits.ProvidedAssetMixin, "sponsors.benefitfeature", models.Model), ), migrations.CreateModel( name="ProvidedTextAssetConfiguration", @@ -123,7 +123,7 @@ class Migration(migrations.Migration): "base_manager_name": "objects", }, bases=( - sponsors.models.benefits.AssetConfigurationMixin, + apps.sponsors.models.benefits.AssetConfigurationMixin, "sponsors.benefitfeatureconfiguration", models.Model, ), diff --git a/sponsors/migrations/0070_auto_20220111_2055.py b/apps/sponsors/migrations/0070_auto_20220111_2055.py similarity index 94% rename from sponsors/migrations/0070_auto_20220111_2055.py rename to apps/sponsors/migrations/0070_auto_20220111_2055.py index 0390866d9..c83d85d35 100644 --- a/sponsors/migrations/0070_auto_20220111_2055.py +++ b/apps/sponsors/migrations/0070_auto_20220111_2055.py @@ -3,8 +3,8 @@ import django.db.models.deletion from django.db import migrations, models -import sponsors.models.assets -import sponsors.models.benefits +import apps.sponsors.models.assets +import apps.sponsors.models.benefits class Migration(migrations.Migration): @@ -27,7 +27,7 @@ class Migration(migrations.Migration): to="sponsors.GenericAsset", ), ), - ("file", models.FileField(null=True, upload_to=sponsors.models.assets.generic_asset_path)), + ("file", models.FileField(null=True, upload_to=apps.sponsors.models.assets.generic_asset_path)), ], options={ "verbose_name": "File Asset", @@ -91,7 +91,7 @@ class Migration(migrations.Migration): "abstract": False, "base_manager_name": "objects", }, - bases=(sponsors.models.benefits.ProvidedAssetMixin, "sponsors.benefitfeature", models.Model), + bases=(apps.sponsors.models.benefits.ProvidedAssetMixin, "sponsors.benefitfeature", models.Model), ), migrations.CreateModel( name="ProvidedFileAssetConfiguration", @@ -150,7 +150,7 @@ class Migration(migrations.Migration): "base_manager_name": "objects", }, bases=( - sponsors.models.benefits.AssetConfigurationMixin, + apps.sponsors.models.benefits.AssetConfigurationMixin, "sponsors.benefitfeatureconfiguration", models.Model, ), diff --git a/sponsors/migrations/0071_auto_20220113_1843.py b/apps/sponsors/migrations/0071_auto_20220113_1843.py similarity index 100% rename from sponsors/migrations/0071_auto_20220113_1843.py rename to apps/sponsors/migrations/0071_auto_20220113_1843.py diff --git a/sponsors/migrations/0072_auto_20220125_2005.py b/apps/sponsors/migrations/0072_auto_20220125_2005.py similarity index 100% rename from sponsors/migrations/0072_auto_20220125_2005.py rename to apps/sponsors/migrations/0072_auto_20220125_2005.py diff --git a/sponsors/migrations/0073_auto_20220128_1906.py b/apps/sponsors/migrations/0073_auto_20220128_1906.py similarity index 96% rename from sponsors/migrations/0073_auto_20220128_1906.py rename to apps/sponsors/migrations/0073_auto_20220128_1906.py index 9164d7cd9..77c25eea7 100644 --- a/sponsors/migrations/0073_auto_20220128_1906.py +++ b/apps/sponsors/migrations/0073_auto_20220128_1906.py @@ -3,7 +3,7 @@ import django.db.models.deletion from django.db import migrations, models -import sponsors.models.benefits +import apps.sponsors.models.benefits class Migration(migrations.Migration): @@ -67,7 +67,7 @@ class Migration(migrations.Migration): "abstract": False, "base_manager_name": "objects", }, - bases=(sponsors.models.benefits.RequiredAssetMixin, "sponsors.benefitfeature", models.Model), + bases=(apps.sponsors.models.benefits.RequiredAssetMixin, "sponsors.benefitfeature", models.Model), ), migrations.CreateModel( name="RequiredResponseAssetConfiguration", @@ -125,7 +125,7 @@ class Migration(migrations.Migration): "base_manager_name": "objects", }, bases=( - sponsors.models.benefits.AssetConfigurationMixin, + apps.sponsors.models.benefits.AssetConfigurationMixin, "sponsors.benefitfeatureconfiguration", models.Model, ), diff --git a/sponsors/migrations/0074_auto_20220211_1659.py b/apps/sponsors/migrations/0074_auto_20220211_1659.py similarity index 100% rename from sponsors/migrations/0074_auto_20220211_1659.py rename to apps/sponsors/migrations/0074_auto_20220211_1659.py diff --git a/sponsors/migrations/0075_auto_20220303_2023.py b/apps/sponsors/migrations/0075_auto_20220303_2023.py similarity index 100% rename from sponsors/migrations/0075_auto_20220303_2023.py rename to apps/sponsors/migrations/0075_auto_20220303_2023.py diff --git a/sponsors/migrations/0076_auto_20220728_1550.py b/apps/sponsors/migrations/0076_auto_20220728_1550.py similarity index 100% rename from sponsors/migrations/0076_auto_20220728_1550.py rename to apps/sponsors/migrations/0076_auto_20220728_1550.py diff --git a/sponsors/migrations/0077_sponsorshipcurrentyear.py b/apps/sponsors/migrations/0077_sponsorshipcurrentyear.py similarity index 100% rename from sponsors/migrations/0077_sponsorshipcurrentyear.py rename to apps/sponsors/migrations/0077_sponsorshipcurrentyear.py diff --git a/sponsors/migrations/0078_init_current_year_singleton.py b/apps/sponsors/migrations/0078_init_current_year_singleton.py similarity index 100% rename from sponsors/migrations/0078_init_current_year_singleton.py rename to apps/sponsors/migrations/0078_init_current_year_singleton.py diff --git a/sponsors/migrations/0079_index_to_force_singleton.py b/apps/sponsors/migrations/0079_index_to_force_singleton.py similarity index 100% rename from sponsors/migrations/0079_index_to_force_singleton.py rename to apps/sponsors/migrations/0079_index_to_force_singleton.py diff --git a/sponsors/migrations/0080_auto_20220728_1644.py b/apps/sponsors/migrations/0080_auto_20220728_1644.py similarity index 100% rename from sponsors/migrations/0080_auto_20220728_1644.py rename to apps/sponsors/migrations/0080_auto_20220728_1644.py diff --git a/sponsors/migrations/0081_sponsorship_application_year.py b/apps/sponsors/migrations/0081_sponsorship_application_year.py similarity index 100% rename from sponsors/migrations/0081_sponsorship_application_year.py rename to apps/sponsors/migrations/0081_sponsorship_application_year.py diff --git a/sponsors/migrations/0082_auto_20220729_1613.py b/apps/sponsors/migrations/0082_auto_20220729_1613.py similarity index 100% rename from sponsors/migrations/0082_auto_20220729_1613.py rename to apps/sponsors/migrations/0082_auto_20220729_1613.py diff --git a/sponsors/migrations/0083_auto_20220729_1624.py b/apps/sponsors/migrations/0083_auto_20220729_1624.py similarity index 100% rename from sponsors/migrations/0083_auto_20220729_1624.py rename to apps/sponsors/migrations/0083_auto_20220729_1624.py diff --git a/sponsors/migrations/0084_init_configured_objs_year.py b/apps/sponsors/migrations/0084_init_configured_objs_year.py similarity index 100% rename from sponsors/migrations/0084_init_configured_objs_year.py rename to apps/sponsors/migrations/0084_init_configured_objs_year.py diff --git a/sponsors/migrations/0085_auto_20220730_0945.py b/apps/sponsors/migrations/0085_auto_20220730_0945.py similarity index 100% rename from sponsors/migrations/0085_auto_20220730_0945.py rename to apps/sponsors/migrations/0085_auto_20220730_0945.py diff --git a/sponsors/migrations/0086_auto_20220809_1655.py b/apps/sponsors/migrations/0086_auto_20220809_1655.py similarity index 100% rename from sponsors/migrations/0086_auto_20220809_1655.py rename to apps/sponsors/migrations/0086_auto_20220809_1655.py diff --git a/sponsors/migrations/0087_auto_20220810_1647.py b/apps/sponsors/migrations/0087_auto_20220810_1647.py similarity index 100% rename from sponsors/migrations/0087_auto_20220810_1647.py rename to apps/sponsors/migrations/0087_auto_20220810_1647.py diff --git a/sponsors/migrations/0088_auto_20220810_1655.py b/apps/sponsors/migrations/0088_auto_20220810_1655.py similarity index 100% rename from sponsors/migrations/0088_auto_20220810_1655.py rename to apps/sponsors/migrations/0088_auto_20220810_1655.py diff --git a/sponsors/migrations/0089_auto_20220812_1312.py b/apps/sponsors/migrations/0089_auto_20220812_1312.py similarity index 100% rename from sponsors/migrations/0089_auto_20220812_1312.py rename to apps/sponsors/migrations/0089_auto_20220812_1312.py diff --git a/sponsors/migrations/0090_auto_20220812_1314.py b/apps/sponsors/migrations/0090_auto_20220812_1314.py similarity index 100% rename from sponsors/migrations/0090_auto_20220812_1314.py rename to apps/sponsors/migrations/0090_auto_20220812_1314.py diff --git a/sponsors/migrations/0091_sponsorshippackage_allow_a_la_carte.py b/apps/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 apps/sponsors/migrations/0091_sponsorshippackage_allow_a_la_carte.py diff --git a/sponsors/migrations/0092_auto_20220816_1517.py b/apps/sponsors/migrations/0092_auto_20220816_1517.py similarity index 100% rename from sponsors/migrations/0092_auto_20220816_1517.py rename to apps/sponsors/migrations/0092_auto_20220816_1517.py diff --git a/sponsors/migrations/0093_auto_20230214_2113.py b/apps/sponsors/migrations/0093_auto_20230214_2113.py similarity index 100% rename from sponsors/migrations/0093_auto_20230214_2113.py rename to apps/sponsors/migrations/0093_auto_20230214_2113.py diff --git a/sponsors/migrations/0094_sponsorship_locked.py b/apps/sponsors/migrations/0094_sponsorship_locked.py similarity index 91% rename from sponsors/migrations/0094_sponsorship_locked.py rename to apps/sponsors/migrations/0094_sponsorship_locked.py index dbbdeac28..c935e7505 100644 --- a/sponsors/migrations/0094_sponsorship_locked.py +++ b/apps/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 apps.sponsors.models.sponsorship import Sponsorship as _Sponsorship def forwards_func(apps, schema_editor): diff --git a/sponsors/migrations/0095_auto_20231214_2025.py b/apps/sponsors/migrations/0095_auto_20231214_2025.py similarity index 100% rename from sponsors/migrations/0095_auto_20231214_2025.py rename to apps/sponsors/migrations/0095_auto_20231214_2025.py diff --git a/sponsors/migrations/0096_auto_20231214_2108.py b/apps/sponsors/migrations/0096_auto_20231214_2108.py similarity index 100% rename from sponsors/migrations/0096_auto_20231214_2108.py rename to apps/sponsors/migrations/0096_auto_20231214_2108.py diff --git a/sponsors/migrations/0097_sponsorship_renewal.py b/apps/sponsors/migrations/0097_sponsorship_renewal.py similarity index 100% rename from sponsors/migrations/0097_sponsorship_renewal.py rename to apps/sponsors/migrations/0097_sponsorship_renewal.py diff --git a/sponsors/migrations/0098_auto_20231219_1910.py b/apps/sponsors/migrations/0098_auto_20231219_1910.py similarity index 100% rename from sponsors/migrations/0098_auto_20231219_1910.py rename to apps/sponsors/migrations/0098_auto_20231219_1910.py diff --git a/sponsors/migrations/0099_auto_20231224_1854.py b/apps/sponsors/migrations/0099_auto_20231224_1854.py similarity index 100% rename from sponsors/migrations/0099_auto_20231224_1854.py rename to apps/sponsors/migrations/0099_auto_20231224_1854.py diff --git a/sponsors/migrations/0100_auto_20240107_1054.py b/apps/sponsors/migrations/0100_auto_20240107_1054.py similarity index 100% rename from sponsors/migrations/0100_auto_20240107_1054.py rename to apps/sponsors/migrations/0100_auto_20240107_1054.py diff --git a/sponsors/migrations/0101_sponsor_linked_in_page_url.py b/apps/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 apps/sponsors/migrations/0101_sponsor_linked_in_page_url.py diff --git a/sponsors/migrations/0102_auto_20240509_2037.py b/apps/sponsors/migrations/0102_auto_20240509_2037.py similarity index 100% rename from sponsors/migrations/0102_auto_20240509_2037.py rename to apps/sponsors/migrations/0102_auto_20240509_2037.py diff --git a/sponsors/migrations/0103_alter_benefitfeature_polymorphic_ctype_and_more.py b/apps/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 apps/sponsors/migrations/0103_alter_benefitfeature_polymorphic_ctype_and_more.py diff --git a/sponsors/migrations/__init__.py b/apps/sponsors/migrations/__init__.py similarity index 100% rename from sponsors/migrations/__init__.py rename to apps/sponsors/migrations/__init__.py diff --git a/sponsors/models/__init__.py b/apps/sponsors/models/__init__.py similarity index 81% rename from sponsors/models/__init__.py rename to apps/sponsors/models/__init__.py index d775dd939..0b6ac4298 100644 --- a/sponsors/models/__init__.py +++ b/apps/sponsors/models/__init__.py @@ -4,8 +4,8 @@ the models are being structured as a python package. """ -from sponsors.models.assets import FileAsset, GenericAsset, ImgAsset, ResponseAsset, TextAsset -from sponsors.models.benefits import ( +from apps.sponsors.models.assets import FileAsset, GenericAsset, ImgAsset, ResponseAsset, TextAsset +from apps.sponsors.models.benefits import ( BaseEmailTargetable, BaseLogoPlacement, BaseTieredBenefit, @@ -28,10 +28,10 @@ TieredBenefit, TieredBenefitConfiguration, ) -from sponsors.models.contract import Contract, LegalClause, signed_contract_random_path -from sponsors.models.notifications import SPONSOR_TEMPLATE_HELP_TEXT, SponsorEmailNotificationTemplate -from sponsors.models.sponsors import Sponsor, SponsorBenefit, SponsorContact -from sponsors.models.sponsorship import ( +from apps.sponsors.models.contract import Contract, LegalClause, signed_contract_random_path +from apps.sponsors.models.notifications import SPONSOR_TEMPLATE_HELP_TEXT, SponsorEmailNotificationTemplate +from apps.sponsors.models.sponsors import Sponsor, SponsorBenefit, SponsorContact +from apps.sponsors.models.sponsorship import ( Sponsorship, SponsorshipBenefit, SponsorshipCurrentYear, diff --git a/sponsors/models/assets.py b/apps/sponsors/models/assets.py similarity index 98% rename from sponsors/models/assets.py rename to apps/sponsors/models/assets.py index 255517944..ada82159b 100644 --- a/sponsors/models/assets.py +++ b/apps/sponsors/models/assets.py @@ -14,7 +14,7 @@ from django.db.models.fields.files import FileField, ImageFieldFile from polymorphic.models import PolymorphicModel -from sponsors.models.managers import GenericAssetQuerySet +from apps.sponsors.models.managers import GenericAssetQuerySet def generic_asset_path(instance, filename): diff --git a/sponsors/models/benefits.py b/apps/sponsors/models/benefits.py similarity index 99% rename from sponsors/models/benefits.py rename to apps/sponsors/models/benefits.py index e618b9c87..02d6a1718 100644 --- a/sponsors/models/benefits.py +++ b/apps/sponsors/models/benefits.py @@ -6,8 +6,8 @@ from django.urls import reverse from polymorphic.models import PolymorphicModel -from sponsors.models.assets import FileAsset, ImgAsset, Response, ResponseAsset, TextAsset -from sponsors.models.enums import ( +from apps.sponsors.models.assets import FileAsset, ImgAsset, Response, ResponseAsset, TextAsset +from apps.sponsors.models.enums import ( AssetsRelatedTo, LogoPlacementChoices, PublisherChoices, @@ -15,7 +15,7 @@ ######################################## # Benefit features abstract classes -from sponsors.models.managers import BenefitFeatureQuerySet +from apps.sponsors.models.managers import BenefitFeatureQuerySet ######################################## diff --git a/sponsors/models/contract.py b/apps/sponsors/models/contract.py similarity index 98% rename from sponsors/models/contract.py rename to apps/sponsors/models/contract.py index 107a41703..bc7ccae8f 100644 --- a/sponsors/models/contract.py +++ b/apps/sponsors/models/contract.py @@ -10,9 +10,9 @@ from markupfield.fields import MarkupField from ordered_model.models import OrderedModel -from sponsors.exceptions import InvalidStatusError -from sponsors.models.sponsorship import Sponsorship -from sponsors.utils import file_from_storage +from apps.sponsors.exceptions import InvalidStatusError +from apps.sponsors.models.sponsorship import Sponsorship +from apps.sponsors.utils import file_from_storage class LegalClause(OrderedModel): diff --git a/sponsors/models/enums.py b/apps/sponsors/models/enums.py similarity index 100% rename from sponsors/models/enums.py rename to apps/sponsors/models/enums.py diff --git a/sponsors/models/managers.py b/apps/sponsors/models/managers.py similarity index 94% rename from sponsors/models/managers.py rename to apps/sponsors/models/managers.py index 53cbb47f0..e3c3ef06d 100644 --- a/sponsors/models/managers.py +++ b/apps/sponsors/models/managers.py @@ -44,7 +44,7 @@ def enabled(self): def with_logo_placement(self, logo_place=None, publisher=None): """Return sponsorships that have logo placements matching the given filters.""" - from sponsors.models import LogoPlacement, SponsorBenefit + from apps.sponsors.models import LogoPlacement, SponsorBenefit feature_qs = LogoPlacement.objects.all() if logo_place: @@ -58,7 +58,7 @@ def with_logo_placement(self, logo_place=None, publisher=None): def includes_benefit_feature(self, feature_model): """Return sponsorships that include the given benefit feature type.""" - from sponsors.models import SponsorBenefit + from apps.sponsors.models import SponsorBenefit feature_qs = feature_model.objects.all() benefit_qs = SponsorBenefit.objects.filter( @@ -142,7 +142,7 @@ def from_year(self, year): def from_current_year(self): """Return available benefits for the current sponsorship year.""" - from sponsors.models import SponsorshipCurrentYear + from apps.sponsors.models import SponsorshipCurrentYear current_year = SponsorshipCurrentYear.get_year() return self.from_year(current_year) @@ -161,7 +161,7 @@ def from_year(self, year): def from_current_year(self): """Return packages for the current sponsorship year.""" - from sponsors.models import SponsorshipCurrentYear + from apps.sponsors.models import SponsorshipCurrentYear current_year = SponsorshipCurrentYear.get_year() return self.from_year(current_year) @@ -182,14 +182,14 @@ def from_sponsorship(self, sponsorship): def required_assets(self): """Return benefit features that require asset uploads from sponsors.""" - from sponsors.models.benefits import RequiredAssetMixin + from apps.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): """Return benefit features that provide assets to sponsors.""" - from sponsors.models.benefits import ProvidedAssetMixin + from apps.sponsors.models.benefits import ProvidedAssetMixin provided_assets_classes = ProvidedAssetMixin.__subclasses__() return self.instance_of(*provided_assets_classes).select_related("sponsor_benefit__sponsorship") @@ -210,7 +210,7 @@ class GenericAssetQuerySet(PolymorphicQuerySet): def all_assets(self): """Return all assets resolved to their concrete subclass types.""" - from sponsors.models import GenericAsset + from apps.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/apps/sponsors/models/notifications.py similarity index 97% rename from sponsors/models/notifications.py rename to apps/sponsors/models/notifications.py index c508b1670..ee5eb77ea 100644 --- a/sponsors/models/notifications.py +++ b/apps/sponsors/models/notifications.py @@ -2,7 +2,7 @@ from django.conf import settings -from mailing.models import BaseEmailTemplate +from apps.mailing.models import BaseEmailTemplate SPONSOR_TEMPLATE_HELP_TEXT = ( "
" diff --git a/sponsors/models/sponsors.py b/apps/sponsors/models/sponsors.py similarity index 98% rename from sponsors/models/sponsors.py rename to apps/sponsors/models/sponsors.py index 8bc2e06e5..a8f83ccb5 100644 --- a/sponsors/models/sponsors.py +++ b/apps/sponsors/models/sponsors.py @@ -10,9 +10,9 @@ from django_countries.fields import CountryField from ordered_model.models import OrderedModel -from cms.models import ContentManageable -from sponsors.models.assets import GenericAsset -from sponsors.models.managers import SponsorContactQuerySet +from apps.cms.models import ContentManageable +from apps.sponsors.models.assets import GenericAsset +from apps.sponsors.models.managers import SponsorContactQuerySet class Sponsor(ContentManageable): diff --git a/sponsors/models/sponsorship.py b/apps/sponsors/models/sponsorship.py similarity index 98% rename from sponsors/models/sponsorship.py rename to apps/sponsors/models/sponsorship.py index b980651e1..8d5f7c3f9 100644 --- a/sponsors/models/sponsorship.py +++ b/apps/sponsors/models/sponsorship.py @@ -16,20 +16,20 @@ from num2words import num2words from ordered_model.models import OrderedModel, OrderedModelManager -from sponsors.exceptions import ( +from apps.sponsors.exceptions import ( InvalidStatusError, SponsorshipInvalidDateRangeError, SponsorWithExistingApplicationError, ) -from sponsors.models.assets import GenericAsset -from sponsors.models.benefits import TieredBenefitConfiguration -from sponsors.models.managers import ( +from apps.sponsors.models.assets import GenericAsset +from apps.sponsors.models.benefits import TieredBenefitConfiguration +from apps.sponsors.models.managers import ( SponsorshipBenefitQuerySet, SponsorshipCurrentYearQuerySet, SponsorshipPackageQuerySet, SponsorshipQuerySet, ) -from sponsors.models.sponsors import SponsorBenefit +from apps.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/apps/sponsors/notifications.py similarity index 99% rename from sponsors/notifications.py rename to apps/sponsors/notifications.py index ec19e6563..52921cf0d 100644 --- a/sponsors/notifications.py +++ b/apps/sponsors/notifications.py @@ -7,7 +7,7 @@ from django.core.mail import EmailMessage from django.template.loader import render_to_string -from sponsors.models import BenefitFeature +from apps.sponsors.models import BenefitFeature class BaseEmailSponsorshipNotification: diff --git a/sponsors/pandoc_filters/__init__.py b/apps/sponsors/pandoc_filters/__init__.py similarity index 100% rename from sponsors/pandoc_filters/__init__.py rename to apps/sponsors/pandoc_filters/__init__.py diff --git a/sponsors/pandoc_filters/pagebreak.py b/apps/sponsors/pandoc_filters/pagebreak.py similarity index 100% rename from sponsors/pandoc_filters/pagebreak.py rename to apps/sponsors/pandoc_filters/pagebreak.py diff --git a/sponsors/reference.docx b/apps/sponsors/reference.docx similarity index 100% rename from sponsors/reference.docx rename to apps/sponsors/reference.docx diff --git a/sponsors/serializers.py b/apps/sponsors/serializers.py similarity index 96% rename from sponsors/serializers.py rename to apps/sponsors/serializers.py index 14a4dc0e8..a4664d4aa 100644 --- a/sponsors/serializers.py +++ b/apps/sponsors/serializers.py @@ -2,8 +2,8 @@ from rest_framework import serializers -from sponsors.models import GenericAsset -from sponsors.models.enums import LogoPlacementChoices, PublisherChoices +from apps.sponsors.models import GenericAsset +from apps.sponsors.models.enums import LogoPlacementChoices, PublisherChoices class LogoPlacementSerializer(serializers.Serializer): diff --git a/templates/sponsors/admin/approve_application.html b/apps/sponsors/templates/sponsors/admin/approve_application.html similarity index 100% rename from templates/sponsors/admin/approve_application.html rename to apps/sponsors/templates/sponsors/admin/approve_application.html diff --git a/templates/sponsors/admin/clone_application_config_form.html b/apps/sponsors/templates/sponsors/admin/clone_application_config_form.html similarity index 100% rename from templates/sponsors/admin/clone_application_config_form.html rename to apps/sponsors/templates/sponsors/admin/clone_application_config_form.html diff --git a/templates/sponsors/admin/contract_change_form.html b/apps/sponsors/templates/sponsors/admin/contract_change_form.html similarity index 100% rename from templates/sponsors/admin/contract_change_form.html rename to apps/sponsors/templates/sponsors/admin/contract_change_form.html diff --git a/templates/sponsors/admin/contracts/sponsorship-agreement.md b/apps/sponsors/templates/sponsors/admin/contracts/sponsorship-agreement.md similarity index 100% rename from templates/sponsors/admin/contracts/sponsorship-agreement.md rename to apps/sponsors/templates/sponsors/admin/contracts/sponsorship-agreement.md diff --git a/templates/sponsors/admin/execute_contract.html b/apps/sponsors/templates/sponsors/admin/execute_contract.html similarity index 100% rename from templates/sponsors/admin/execute_contract.html rename to apps/sponsors/templates/sponsors/admin/execute_contract.html diff --git a/templates/sponsors/admin/list_uploaded_assets.html b/apps/sponsors/templates/sponsors/admin/list_uploaded_assets.html similarity index 100% rename from templates/sponsors/admin/list_uploaded_assets.html rename to apps/sponsors/templates/sponsors/admin/list_uploaded_assets.html diff --git a/templates/sponsors/admin/nullify_contract.html b/apps/sponsors/templates/sponsors/admin/nullify_contract.html similarity index 100% rename from templates/sponsors/admin/nullify_contract.html rename to apps/sponsors/templates/sponsors/admin/nullify_contract.html diff --git a/templates/sponsors/admin/reject_application.html b/apps/sponsors/templates/sponsors/admin/reject_application.html similarity index 100% rename from templates/sponsors/admin/reject_application.html rename to apps/sponsors/templates/sponsors/admin/reject_application.html diff --git a/templates/sponsors/admin/rollback_sponsorship_to_editing.html b/apps/sponsors/templates/sponsors/admin/rollback_sponsorship_to_editing.html similarity index 100% rename from templates/sponsors/admin/rollback_sponsorship_to_editing.html rename to apps/sponsors/templates/sponsors/admin/rollback_sponsorship_to_editing.html diff --git a/templates/sponsors/admin/send_contract.html b/apps/sponsors/templates/sponsors/admin/send_contract.html similarity index 100% rename from templates/sponsors/admin/send_contract.html rename to apps/sponsors/templates/sponsors/admin/send_contract.html diff --git a/templates/sponsors/admin/send_sponsors_notification.html b/apps/sponsors/templates/sponsors/admin/send_sponsors_notification.html similarity index 100% rename from templates/sponsors/admin/send_sponsors_notification.html rename to apps/sponsors/templates/sponsors/admin/send_sponsors_notification.html diff --git a/templates/sponsors/admin/sponsors_sponsorshipcurrentyear_changelist.html b/apps/sponsors/templates/sponsors/admin/sponsors_sponsorshipcurrentyear_changelist.html similarity index 100% rename from templates/sponsors/admin/sponsors_sponsorshipcurrentyear_changelist.html rename to apps/sponsors/templates/sponsors/admin/sponsors_sponsorshipcurrentyear_changelist.html diff --git a/templates/sponsors/admin/sponsorship_change_form.html b/apps/sponsors/templates/sponsors/admin/sponsorship_change_form.html similarity index 100% rename from templates/sponsors/admin/sponsorship_change_form.html rename to apps/sponsors/templates/sponsors/admin/sponsorship_change_form.html diff --git a/templates/sponsors/admin/sponsorshipbenefit_change_form.html b/apps/sponsors/templates/sponsors/admin/sponsorshipbenefit_change_form.html similarity index 100% rename from templates/sponsors/admin/sponsorshipbenefit_change_form.html rename to apps/sponsors/templates/sponsors/admin/sponsorshipbenefit_change_form.html diff --git a/templates/sponsors/admin/unlock.html b/apps/sponsors/templates/sponsors/admin/unlock.html similarity index 100% rename from templates/sponsors/admin/unlock.html rename to apps/sponsors/templates/sponsors/admin/unlock.html diff --git a/templates/sponsors/admin/update_related_sponsorships.html b/apps/sponsors/templates/sponsors/admin/update_related_sponsorships.html similarity index 100% rename from templates/sponsors/admin/update_related_sponsorships.html rename to apps/sponsors/templates/sponsors/admin/update_related_sponsorships.html diff --git a/templates/sponsors/email/psf_contract.txt b/apps/sponsors/templates/sponsors/email/psf_contract.txt similarity index 100% rename from templates/sponsors/email/psf_contract.txt rename to apps/sponsors/templates/sponsors/email/psf_contract.txt diff --git a/templates/sponsors/email/psf_contract_subject.txt b/apps/sponsors/templates/sponsors/email/psf_contract_subject.txt similarity index 100% rename from templates/sponsors/email/psf_contract_subject.txt rename to apps/sponsors/templates/sponsors/email/psf_contract_subject.txt diff --git a/templates/sponsors/email/psf_new_application.txt b/apps/sponsors/templates/sponsors/email/psf_new_application.txt similarity index 100% rename from templates/sponsors/email/psf_new_application.txt rename to apps/sponsors/templates/sponsors/email/psf_new_application.txt diff --git a/templates/sponsors/email/psf_new_application_subject.txt b/apps/sponsors/templates/sponsors/email/psf_new_application_subject.txt similarity index 100% rename from templates/sponsors/email/psf_new_application_subject.txt rename to apps/sponsors/templates/sponsors/email/psf_new_application_subject.txt diff --git a/templates/sponsors/email/psf_rejected_sponsorship.txt b/apps/sponsors/templates/sponsors/email/psf_rejected_sponsorship.txt similarity index 100% rename from templates/sponsors/email/psf_rejected_sponsorship.txt rename to apps/sponsors/templates/sponsors/email/psf_rejected_sponsorship.txt diff --git a/templates/sponsors/email/psf_rejected_sponsorship_subject.txt b/apps/sponsors/templates/sponsors/email/psf_rejected_sponsorship_subject.txt similarity index 100% rename from templates/sponsors/email/psf_rejected_sponsorship_subject.txt rename to apps/sponsors/templates/sponsors/email/psf_rejected_sponsorship_subject.txt diff --git a/templates/sponsors/email/sponsor_contract.txt b/apps/sponsors/templates/sponsors/email/sponsor_contract.txt similarity index 100% rename from templates/sponsors/email/sponsor_contract.txt rename to apps/sponsors/templates/sponsors/email/sponsor_contract.txt diff --git a/templates/sponsors/email/sponsor_contract_subject.txt b/apps/sponsors/templates/sponsors/email/sponsor_contract_subject.txt similarity index 100% rename from templates/sponsors/email/sponsor_contract_subject.txt rename to apps/sponsors/templates/sponsors/email/sponsor_contract_subject.txt diff --git a/templates/sponsors/email/sponsor_expiring_assets.txt b/apps/sponsors/templates/sponsors/email/sponsor_expiring_assets.txt similarity index 100% rename from templates/sponsors/email/sponsor_expiring_assets.txt rename to apps/sponsors/templates/sponsors/email/sponsor_expiring_assets.txt diff --git a/templates/sponsors/email/sponsor_expiring_assets_subject.txt b/apps/sponsors/templates/sponsors/email/sponsor_expiring_assets_subject.txt similarity index 100% rename from templates/sponsors/email/sponsor_expiring_assets_subject.txt rename to apps/sponsors/templates/sponsors/email/sponsor_expiring_assets_subject.txt diff --git a/templates/sponsors/email/sponsor_new_application.txt b/apps/sponsors/templates/sponsors/email/sponsor_new_application.txt similarity index 100% rename from templates/sponsors/email/sponsor_new_application.txt rename to apps/sponsors/templates/sponsors/email/sponsor_new_application.txt diff --git a/templates/sponsors/email/sponsor_new_application_subject.txt b/apps/sponsors/templates/sponsors/email/sponsor_new_application_subject.txt similarity index 100% rename from templates/sponsors/email/sponsor_new_application_subject.txt rename to apps/sponsors/templates/sponsors/email/sponsor_new_application_subject.txt diff --git a/templates/sponsors/email/sponsor_rejected_sponsorship.txt b/apps/sponsors/templates/sponsors/email/sponsor_rejected_sponsorship.txt similarity index 100% rename from templates/sponsors/email/sponsor_rejected_sponsorship.txt rename to apps/sponsors/templates/sponsors/email/sponsor_rejected_sponsorship.txt diff --git a/templates/sponsors/email/sponsor_rejected_sponsorship_subject.txt b/apps/sponsors/templates/sponsors/email/sponsor_rejected_sponsorship_subject.txt similarity index 100% rename from templates/sponsors/email/sponsor_rejected_sponsorship_subject.txt rename to apps/sponsors/templates/sponsors/email/sponsor_rejected_sponsorship_subject.txt diff --git a/templates/sponsors/new_sponsorship_application_form.html b/apps/sponsors/templates/sponsors/new_sponsorship_application_form.html similarity index 100% rename from templates/sponsors/new_sponsorship_application_form.html rename to apps/sponsors/templates/sponsors/new_sponsorship_application_form.html diff --git a/templates/sponsors/partials/full_sponsorship.txt b/apps/sponsors/templates/sponsors/partials/full_sponsorship.txt similarity index 100% rename from templates/sponsors/partials/full_sponsorship.txt rename to apps/sponsors/templates/sponsors/partials/full_sponsorship.txt diff --git a/templates/sponsors/partials/sponsors-list.html b/apps/sponsors/templates/sponsors/partials/sponsors-list.html similarity index 100% rename from templates/sponsors/partials/sponsors-list.html rename to apps/sponsors/templates/sponsors/partials/sponsors-list.html diff --git a/templates/sponsors/sponsor_list.html b/apps/sponsors/templates/sponsors/sponsor_list.html similarity index 100% rename from templates/sponsors/sponsor_list.html rename to apps/sponsors/templates/sponsors/sponsor_list.html diff --git a/templates/sponsors/sponsorship_application_finished.html b/apps/sponsors/templates/sponsors/sponsorship_application_finished.html similarity index 100% rename from templates/sponsors/sponsorship_application_finished.html rename to apps/sponsors/templates/sponsors/sponsorship_application_finished.html diff --git a/templates/sponsors/sponsorship_benefits_form.html b/apps/sponsors/templates/sponsors/sponsorship_benefits_form.html similarity index 100% rename from templates/sponsors/sponsorship_benefits_form.html rename to apps/sponsors/templates/sponsors/sponsorship_benefits_form.html diff --git a/sponsors/templatetags/__init__.py b/apps/sponsors/templatetags/__init__.py similarity index 100% rename from sponsors/templatetags/__init__.py rename to apps/sponsors/templatetags/__init__.py diff --git a/sponsors/templatetags/sponsors.py b/apps/sponsors/templatetags/sponsors.py similarity index 94% rename from sponsors/templatetags/sponsors.py rename to apps/sponsors/templatetags/sponsors.py index 22ddc0da6..4f4289632 100644 --- a/sponsors/templatetags/sponsors.py +++ b/apps/sponsors/templatetags/sponsors.py @@ -5,8 +5,8 @@ from django import template -from sponsors.models import Sponsorship, SponsorshipPackage, TieredBenefitConfiguration -from sponsors.models.enums import LogoPlacementChoices, PublisherChoices +from apps.sponsors.models import Sponsorship, SponsorshipPackage, TieredBenefitConfiguration +from apps.sponsors.models.enums import LogoPlacementChoices, PublisherChoices register = template.Library() diff --git a/sponsors/tests/__init__.py b/apps/sponsors/tests/__init__.py similarity index 100% rename from sponsors/tests/__init__.py rename to apps/sponsors/tests/__init__.py diff --git a/sponsors/tests/baker_recipes.py b/apps/sponsors/tests/baker_recipes.py similarity index 89% rename from sponsors/tests/baker_recipes.py rename to apps/sponsors/tests/baker_recipes.py index 917caf03b..9468e6cce 100644 --- a/sponsors/tests/baker_recipes.py +++ b/apps/sponsors/tests/baker_recipes.py @@ -3,8 +3,8 @@ from django.utils import timezone from model_bakery.recipe import Recipe, foreign_key -from sponsors.models import Contract, LogoPlacement, Sponsorship, SponsorshipPackage -from sponsors.models.enums import LogoPlacementChoices, PublisherChoices +from apps.sponsors.models import Contract, LogoPlacement, Sponsorship, SponsorshipPackage +from apps.sponsors.models.enums import LogoPlacementChoices, PublisherChoices today = timezone.now().date() two_days = timedelta(days=2) diff --git a/sponsors/tests/test_admin.py b/apps/sponsors/tests/test_admin.py similarity index 95% rename from sponsors/tests/test_admin.py rename to apps/sponsors/tests/test_admin.py index 1175a7c34..850b6475d 100644 --- a/sponsors/tests/test_admin.py +++ b/apps/sponsors/tests/test_admin.py @@ -4,8 +4,8 @@ from django.test import RequestFactory, TestCase from model_bakery import baker -from sponsors.admin import SponsorshipAdmin, SponsorshipStatusListFilter -from sponsors.models import Sponsorship +from apps.sponsors.admin import SponsorshipAdmin, SponsorshipStatusListFilter +from apps.sponsors.models import Sponsorship class TestCustomSponsorshipStatusListFilter(TestCase): diff --git a/sponsors/tests/test_api.py b/apps/sponsors/tests/test_api.py similarity index 94% rename from sponsors/tests/test_api.py rename to apps/sponsors/tests/test_api.py index b39cde356..39c187910 100644 --- a/sponsors/tests/test_api.py +++ b/apps/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 ImgAsset, Sponsor, Sponsorship, TextAsset -from sponsors.models.enums import LogoPlacementChoices, PublisherChoices +from apps.sponsors.models import ImgAsset, Sponsor, Sponsorship, TextAsset +from apps.sponsors.models.enums import LogoPlacementChoices, PublisherChoices class LogoPlacementeAPIListTests(APITestCase): @@ -25,14 +25,14 @@ def setUp(self): self.sponsors = baker.make(Sponsor, _create_files=True, _quantity=3) sponsorships = baker.make_recipe( - "sponsors.tests.finalized_sponsorship", sponsor=iter(self.sponsors), _quantity=3 + "apps.sponsors.tests.finalized_sponsorship", sponsor=iter(self.sponsors), _quantity=3 ) self.sp1, self.sp2, self.sp3 = sponsorships - baker.make_recipe("sponsors.tests.logo_at_download_feature", sponsor_benefit__sponsorship=self.sp1) - baker.make_recipe("sponsors.tests.logo_at_sponsors_feature", sponsor_benefit__sponsorship=self.sp1) - baker.make_recipe("sponsors.tests.logo_at_sponsors_feature", sponsor_benefit__sponsorship=self.sp2) + baker.make_recipe("apps.sponsors.tests.logo_at_download_feature", sponsor_benefit__sponsorship=self.sp1) + baker.make_recipe("apps.sponsors.tests.logo_at_sponsors_feature", sponsor_benefit__sponsorship=self.sp1) + baker.make_recipe("apps.sponsors.tests.logo_at_sponsors_feature", sponsor_benefit__sponsorship=self.sp2) baker.make_recipe( - "sponsors.tests.logo_at_pypi_feature", + "apps.sponsors.tests.logo_at_pypi_feature", sponsor_benefit__sponsorship=self.sp3, link_to_sponsors_page=True, describe_as_sponsor=True, diff --git a/sponsors/tests/test_contracts.py b/apps/sponsors/tests/test_contracts.py similarity index 88% rename from sponsors/tests/test_contracts.py rename to apps/sponsors/tests/test_contracts.py index b030b5d2a..be2dd58f4 100644 --- a/sponsors/tests/test_contracts.py +++ b/apps/sponsors/tests/test_contracts.py @@ -5,13 +5,13 @@ from django.utils import timezone from model_bakery import baker -from sponsors.contracts import render_contract_to_docx_response +from apps.sponsors.contracts import render_contract_to_docx_response class TestRenderContract(TestCase): def setUp(self): self.contract = baker.make_recipe( - "sponsors.tests.empty_contract", sponsorship__start_date=timezone.now().date() + "apps.sponsors.tests.empty_contract", sponsorship__start_date=timezone.now().date() ) # DOCX unit test diff --git a/sponsors/tests/test_forms.py b/apps/sponsors/tests/test_forms.py similarity index 99% rename from sponsors/tests/test_forms.py rename to apps/sponsors/tests/test_forms.py index ec0f103ac..e1107e254 100644 --- a/sponsors/tests/test_forms.py +++ b/apps/sponsors/tests/test_forms.py @@ -5,7 +5,7 @@ from django.test import TestCase from model_bakery import baker -from sponsors.forms import ( +from apps.sponsors.forms import ( CloneApplicationConfigForm, SendSponsorshipNotificationForm, Sponsor, @@ -20,7 +20,7 @@ SponsorshipsBenefitsForm, SponsorshipsListForm, ) -from sponsors.models import ( +from apps.sponsors.models import ( ImgAsset, RequiredImgAssetConfiguration, RequiredTextAsset, @@ -30,8 +30,8 @@ SponsorshipCurrentYear, SponsorshipPackage, ) -from sponsors.models.enums import AssetsRelatedTo -from sponsors.tests.utils import get_static_image_file_as_upload +from apps.sponsors.models.enums import AssetsRelatedTo +from apps.sponsors.tests.utils import get_static_image_file_as_upload class SponsorshipsBenefitsFormTests(TestCase): @@ -646,7 +646,7 @@ def test_update_existing_benefit_features(self): sponsorship_benefit=self.benefit, ) # existing benefit depends on logo - baker.make_recipe("sponsors.tests.logo_at_download_feature", sponsor_benefit=sponsor_benefit) + baker.make_recipe("apps.sponsors.tests.logo_at_download_feature", sponsor_benefit=sponsor_benefit) # new benefit requires text instead of logo new_benefit = baker.make(SponsorshipBenefit) diff --git a/sponsors/tests/test_management_command.py b/apps/sponsors/tests/test_management_command.py similarity index 96% rename from sponsors/tests/test_management_command.py rename to apps/sponsors/tests/test_management_command.py index 16d176960..6b2d34bb1 100644 --- a/sponsors/tests/test_management_command.py +++ b/apps/sponsors/tests/test_management_command.py @@ -6,11 +6,11 @@ from django.test import TestCase from model_bakery import baker -from sponsors.management.commands.create_pycon_vouchers_for_sponsors import ( +from apps.sponsors.management.commands.create_pycon_vouchers_for_sponsors import ( BENEFITS, generate_voucher_codes, ) -from sponsors.models import ( +from apps.sponsors.models import ( GenericAsset, ProvidedTextAsset, ProvidedTextAssetConfiguration, @@ -22,13 +22,13 @@ SponsorshipProgram, TieredBenefitConfiguration, ) -from sponsors.models.assets import TextAsset -from sponsors.models.enums import AssetsRelatedTo +from apps.sponsors.models.assets import TextAsset +from apps.sponsors.models.enums import AssetsRelatedTo class CreatePyConVouchersForSponsorsTestCase(TestCase): @mock.patch( - "sponsors.management.commands.create_pycon_vouchers_for_sponsors.api_call", + "apps.sponsors.management.commands.create_pycon_vouchers_for_sponsors.api_call", return_value={"code": 200, "data": {"promo_code": "test-promo-code"}}, ) def test_generate_voucher_codes(self, mock_api_call): @@ -289,7 +289,7 @@ def test_reset_sponsorship_benefits_from_2025_to_2026(self): self.assertEqual(tiered_features.count(), 1) # Verify the quantity was updated from 2025 config (5) to 2026 config (10) - from sponsors.models import TieredBenefit + from apps.sponsors.models import TieredBenefit tiered_benefit = TieredBenefit.objects.get(sponsor_benefit=conference_passes_benefit) self.assertEqual(tiered_benefit.quantity, 10) @@ -304,7 +304,7 @@ def test_reset_with_duplicate_benefits(self): ) # Manually create a duplicate benefit - from sponsors.models import SponsorBenefit + from apps.sponsors.models import SponsorBenefit SponsorBenefit.new_copy( self.benefit_2025_a, diff --git a/sponsors/tests/test_managers.py b/apps/sponsors/tests/test_managers.py similarity index 89% rename from sponsors/tests/test_managers.py rename to apps/sponsors/tests/test_managers.py index 0341c3284..b27100333 100644 --- a/sponsors/tests/test_managers.py +++ b/apps/sponsors/tests/test_managers.py @@ -5,7 +5,7 @@ from django.utils import timezone from model_bakery import baker -from sponsors.models import ( +from apps.sponsors.models import ( BenefitFeature, LogoPlacement, RequiredImgAsset, @@ -17,7 +17,7 @@ SponsorshipPackage, TieredBenefit, ) -from sponsors.models.enums import LogoPlacementChoices, PublisherChoices +from apps.sponsors.models.enums import LogoPlacementChoices, PublisherChoices class SponsorshipQuerySetTests(TestCase): @@ -77,14 +77,14 @@ def test_enabled_sponsorships(self): self.assertIn(enabled, qs) def test_filter_sponsorship_with_logo_placement_benefits(self): - sponsorship_with_download_logo = baker.make_recipe("sponsors.tests.finalized_sponsorship") - sponsorship_with_sponsors_logo = baker.make_recipe("sponsors.tests.finalized_sponsorship") - simple_sponsorship = baker.make_recipe("sponsors.tests.finalized_sponsorship") + sponsorship_with_download_logo = baker.make_recipe("apps.sponsors.tests.finalized_sponsorship") + sponsorship_with_sponsors_logo = baker.make_recipe("apps.sponsors.tests.finalized_sponsorship") + simple_sponsorship = baker.make_recipe("apps.sponsors.tests.finalized_sponsorship") download_logo_benefit = baker.make(SponsorBenefit, sponsorship=sponsorship_with_download_logo) - baker.make_recipe("sponsors.tests.logo_at_download_feature", sponsor_benefit=download_logo_benefit) + baker.make_recipe("apps.sponsors.tests.logo_at_download_feature", sponsor_benefit=download_logo_benefit) sponsors_logo_benefit = baker.make(SponsorBenefit, sponsorship=sponsorship_with_sponsors_logo) - baker.make_recipe("sponsors.tests.logo_at_sponsors_feature", sponsor_benefit=sponsors_logo_benefit) + baker.make_recipe("apps.sponsors.tests.logo_at_sponsors_feature", sponsor_benefit=sponsors_logo_benefit) baker.make(SponsorBenefit, sponsorship=simple_sponsorship) with self.assertNumQueries(1): @@ -105,8 +105,8 @@ def test_filter_sponsorship_with_logo_placement_benefits(self): self.assertIn(sponsorship_with_download_logo, qs) def test_filter_sponsorship_by_benefit_feature_type(self): - sponsorship_feature_1 = baker.make_recipe("sponsors.tests.finalized_sponsorship") - sponsorship_feature_2 = baker.make_recipe("sponsors.tests.finalized_sponsorship") + sponsorship_feature_1 = baker.make_recipe("apps.sponsors.tests.finalized_sponsorship") + sponsorship_feature_2 = baker.make_recipe("apps.sponsors.tests.finalized_sponsorship") baker.make(LogoPlacement, sponsor_benefit__sponsorship=sponsorship_feature_1) baker.make(TieredBenefit, sponsor_benefit__sponsorship=sponsorship_feature_2) diff --git a/sponsors/tests/test_models.py b/apps/sponsors/tests/test_models.py similarity index 97% rename from sponsors/tests/test_models.py rename to apps/sponsors/tests/test_models.py index 8642573e3..24d5ecf26 100644 --- a/sponsors/tests/test_models.py +++ b/apps/sponsors/tests/test_models.py @@ -10,12 +10,12 @@ from django.utils import timezone from model_bakery import baker, seq -from sponsors.exceptions import ( +from apps.sponsors.exceptions import ( InvalidStatusError, SponsorshipInvalidDateRangeError, SponsorWithExistingApplicationError, ) -from sponsors.models import ( +from apps.sponsors.models import ( Contract, ImgAsset, LegalClause, @@ -36,14 +36,14 @@ TieredBenefit, TieredBenefitConfiguration, ) -from sponsors.models.benefits import ( +from apps.sponsors.models.benefits import ( BaseRequiredImgAsset, BaseRequiredTextAsset, BenefitFeature, EmailTargetableConfiguration, RequiredAssetMixin, ) -from sponsors.models.enums import AssetsRelatedTo, LogoPlacementChoices, PublisherChoices +from apps.sponsors.models.enums import AssetsRelatedTo, LogoPlacementChoices, PublisherChoices class SponsorshipBenefitModelTests(TestCase): @@ -249,7 +249,7 @@ def test_rollback_approved_sponsorship_with_contract_should_delete_it(self): sponsorship = Sponsorship.new(self.sponsor, self.benefits) sponsorship.status = Sponsorship.APPROVED sponsorship.save() - baker.make_recipe("sponsors.tests.empty_contract", sponsorship=sponsorship) + baker.make_recipe("apps.sponsors.tests.empty_contract", sponsorship=sponsorship) sponsorship.rollback_to_editing() sponsorship.save() @@ -262,7 +262,7 @@ def test_can_not_rollback_sponsorship_to_edit_if_contract_was_sent(self): sponsorship = Sponsorship.new(self.sponsor, self.benefits) sponsorship.status = Sponsorship.APPROVED sponsorship.save() - baker.make_recipe("sponsors.tests.awaiting_signature_contract", sponsorship=sponsorship) + baker.make_recipe("apps.sponsors.tests.awaiting_signature_contract", sponsorship=sponsorship) with self.assertRaises(InvalidStatusError): sponsorship.rollback_to_editing() @@ -479,7 +479,7 @@ def setUp(self): self.sponsorship_benefits = SponsorshipBenefit.objects.all() def test_auto_increment_draft_revision_on_save(self): - contract = baker.make_recipe("sponsors.tests.empty_contract") + contract = baker.make_recipe("apps.sponsors.tests.empty_contract") self.assertEqual(contract.status, Contract.DRAFT) self.assertEqual(contract.revision, 0) @@ -491,7 +491,7 @@ def test_auto_increment_draft_revision_on_save(self): self.assertEqual(contract.revision, num_updates) def test_does_not_auto_increment_draft_revision_on_save_if_other_states(self): - contract = baker.make_recipe("sponsors.tests.empty_contract", revision=10) + contract = baker.make_recipe("apps.sponsors.tests.empty_contract", revision=10) choices = Contract.STATUS_CHOICES other_status = [c[0] for c in choices if c[0] != Contract.DRAFT] @@ -583,14 +583,14 @@ def test_control_contract_next_status(self): } for status, exepcted in states_map.items(): contract = baker.prepare_recipe( - "sponsors.tests.empty_contract", + "apps.sponsors.tests.empty_contract", sponsorship__sponsor__name="foo", status=status, ) self.assertEqual(contract.next_status, exepcted) def test_set_final_document_version(self): - contract = baker.make_recipe("sponsors.tests.empty_contract", sponsorship__sponsor__name="foo") + contract = baker.make_recipe("apps.sponsors.tests.empty_contract", sponsorship__sponsor__name="foo") content = b"pdf binary content" self.assertFalse(contract.document.name) @@ -601,7 +601,7 @@ def test_set_final_document_version(self): self.assertEqual(contract.status, Contract.AWAITING_SIGNATURE) def test_set_final_document_version_saves_docx_document_too(self): - contract = baker.make_recipe("sponsors.tests.empty_contract", sponsorship__sponsor__name="foo") + contract = baker.make_recipe("apps.sponsors.tests.empty_contract", sponsorship__sponsor__name="foo") content = b"pdf binary content" docx_content = b"pdf binary content" @@ -612,13 +612,13 @@ def test_set_final_document_version_saves_docx_document_too(self): self.assertEqual(contract.status, Contract.AWAITING_SIGNATURE) def test_raise_invalid_status_exception_if_not_draft(self): - contract = baker.make_recipe("sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) + contract = baker.make_recipe("apps.sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) with self.assertRaises(InvalidStatusError): contract.set_final_version(b"content") def test_execute_contract(self): - contract = baker.make_recipe("sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) + contract = baker.make_recipe("apps.sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) contract.execute() contract.refresh_from_db() @@ -628,13 +628,13 @@ def test_execute_contract(self): self.assertEqual(contract.sponsorship.finalized_on, timezone.now().date()) def test_raise_invalid_status_when_trying_to_execute_contract_if_not_awaiting_signature(self): - contract = baker.make_recipe("sponsors.tests.empty_contract", status=Contract.OUTDATED) + contract = baker.make_recipe("apps.sponsors.tests.empty_contract", status=Contract.OUTDATED) with self.assertRaises(InvalidStatusError): contract.execute() def test_nullify_contract(self): - contract = baker.make_recipe("sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) + contract = baker.make_recipe("apps.sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) contract.nullify() contract.refresh_from_db() @@ -642,7 +642,7 @@ def test_nullify_contract(self): self.assertEqual(contract.status, Contract.NULLIFIED) def test_raise_invalid_status_when_trying_to_nullify_contract_if_not_awaiting_signature(self): - contract = baker.make_recipe("sponsors.tests.empty_contract", status=Contract.DRAFT) + contract = baker.make_recipe("apps.sponsors.tests.empty_contract", status=Contract.DRAFT) with self.assertRaises(InvalidStatusError): contract.nullify() diff --git a/sponsors/tests/test_notifications.py b/apps/sponsors/tests/test_notifications.py similarity index 96% rename from sponsors/tests/test_notifications.py rename to apps/sponsors/tests/test_notifications.py index 73a447a0e..8cbe1d79a 100644 --- a/sponsors/tests/test_notifications.py +++ b/apps/sponsors/tests/test_notifications.py @@ -10,8 +10,8 @@ from django.utils import timezone from model_bakery import baker -from sponsors import notifications -from sponsors.models import Contract, RequiredTextAssetConfiguration, SponsorBenefit, Sponsorship +from apps.sponsors import notifications +from apps.sponsors.models import Contract, RequiredTextAssetConfiguration, SponsorBenefit, Sponsorship class AppliedSponsorshipNotificationToPSFTests(TestCase): @@ -149,7 +149,7 @@ class ContractNotificationToPSFTests(TestCase): def setUp(self): self.notification = notifications.ContractNotificationToPSF() self.contract = baker.make_recipe( - "sponsors.tests.awaiting_signature_contract", + "apps.sponsors.tests.awaiting_signature_contract", _fill_optional=["document"], _create_files=True, ) @@ -198,7 +198,7 @@ def setUp(self): submited_by=self.user, ) self.contract = baker.make_recipe( - "sponsors.tests.awaiting_signature_contract", + "apps.sponsors.tests.awaiting_signature_contract", sponsorship=sponsorship, _fill_optional=["document", "document_docx"], _create_files=True, @@ -262,7 +262,7 @@ def setUp(self): self.sponsorship = baker.make( Sponsorship, status=Sponsorship.APPROVED, sponsor__name="foo", _fill_optional=True ) - self.contract = baker.make_recipe("sponsors.tests.empty_contract", sponsorship=self.sponsorship) + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract", sponsorship=self.sponsorship) self.kwargs = {"request": self.request, "sponsorship": self.sponsorship, "contract": self.contract} self.logger = notifications.SponsorshipApprovalLogger() @@ -292,7 +292,7 @@ class SentContractLoggerTests(TestCase): def setUp(self): self.request = RequestFactory().get("/") self.request.user = baker.make(settings.AUTH_USER_MODEL) - self.contract = baker.make_recipe("sponsors.tests.empty_contract") + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract") self.kwargs = { "request": self.request, "contract": self.contract, @@ -317,7 +317,7 @@ class ExecutedContractLoggerTests(TestCase): def setUp(self): self.request = RequestFactory().get("/") self.request.user = baker.make(settings.AUTH_USER_MODEL) - self.contract = baker.make_recipe("sponsors.tests.empty_contract") + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract") self.kwargs = { "request": self.request, "contract": self.contract, @@ -342,7 +342,7 @@ class ExecutedExistingContractLoggerTests(TestCase): def setUp(self): self.request = RequestFactory().get("/") self.request.user = baker.make(settings.AUTH_USER_MODEL) - self.contract = baker.make_recipe("sponsors.tests.empty_contract") + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract") self.kwargs = { "request": self.request, "contract": self.contract, @@ -367,7 +367,7 @@ class NullifiedContractLoggerTests(TestCase): def setUp(self): self.request = RequestFactory().get("/") self.request.user = baker.make(settings.AUTH_USER_MODEL) - self.contract = baker.make_recipe("sponsors.tests.empty_contract") + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract") self.kwargs = { "request": self.request, "contract": self.contract, diff --git a/sponsors/tests/test_templatetags.py b/apps/sponsors/tests/test_templatetags.py similarity index 91% rename from sponsors/tests/test_templatetags.py rename to apps/sponsors/tests/test_templatetags.py index 5a8e57302..37513cfaf 100644 --- a/sponsors/tests/test_templatetags.py +++ b/apps/sponsors/tests/test_templatetags.py @@ -3,8 +3,8 @@ from django.test import TestCase from model_bakery import baker -from sponsors.models import SponsorshipBenefit, TieredBenefitConfiguration -from sponsors.templatetags.sponsors import ( +from apps.sponsors.models import SponsorshipBenefit, TieredBenefitConfiguration +from apps.sponsors.templatetags.sponsors import ( benefit_name_for_display, benefit_quantity_for_package, full_sponsorship, @@ -37,8 +37,8 @@ def test_allows_to_overwrite_display_fee_flag(self): class ListSponsorsTemplateTag(TestCase): def test_filter_sponsorship_with_logo_placement_benefits(self): - sponsorship = baker.make_recipe("sponsors.tests.finalized_sponsorship") - baker.make_recipe("sponsors.tests.logo_at_download_feature", sponsor_benefit__sponsorship=sponsorship) + sponsorship = baker.make_recipe("apps.sponsors.tests.finalized_sponsorship") + baker.make_recipe("apps.sponsors.tests.logo_at_download_feature", sponsor_benefit__sponsorship=sponsorship) context = list_sponsors("download") diff --git a/sponsors/tests/test_use_cases.py b/apps/sponsors/tests/test_use_cases.py similarity index 96% rename from sponsors/tests/test_use_cases.py rename to apps/sponsors/tests/test_use_cases.py index d3fed86cf..05449c022 100644 --- a/sponsors/tests/test_use_cases.py +++ b/apps/sponsors/tests/test_use_cases.py @@ -9,8 +9,8 @@ from django.utils import timezone from model_bakery import baker -from sponsors import use_cases -from sponsors.models import ( +from apps.sponsors import use_cases +from apps.sponsors.models import ( Contract, Sponsor, SponsorEmailNotificationTemplate, @@ -18,7 +18,7 @@ SponsorshipBenefit, SponsorshipPackage, ) -from sponsors.notifications import ( +from apps.sponsors.notifications import ( AppliedSponsorshipNotificationToPSF, AppliedSponsorshipNotificationToSponsors, ClonedResourcesLogger, @@ -162,7 +162,7 @@ def setUp(self): self.notifications = [Mock(), Mock()] self.use_case = use_cases.SendContractUseCase(self.notifications) self.user = baker.make(settings.AUTH_USER_MODEL) - self.contract = baker.make_recipe("sponsors.tests.empty_contract") + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract") def test_send_and_update_contract_with_document(self): self.use_case.execute(self.contract) @@ -191,7 +191,7 @@ def setUp(self): self.user = baker.make(settings.AUTH_USER_MODEL) self.file = SimpleUploadedFile("contract.txt", b"Contract content") self.contract = baker.make_recipe( - "sponsors.tests.empty_contract", + "apps.sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE, ) @@ -222,7 +222,7 @@ def setUp(self): self.use_case = use_cases.ExecuteExistingContractUseCase(self.notifications) self.user = baker.make(settings.AUTH_USER_MODEL) self.file = SimpleUploadedFile("contract.txt", b"Contract content") - self.contract = baker.make_recipe("sponsors.tests.empty_contract", status=Contract.DRAFT) + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract", status=Contract.DRAFT) def tearDown(self): try: @@ -232,7 +232,7 @@ def tearDown(self): except ValueError: pass - @patch("sponsors.models.contract.uuid.uuid4", Mock(return_value="1234")) + @patch("apps.sponsors.models.contract.uuid.uuid4", Mock(return_value="1234")) def test_execute_and_update_database_object(self): self.use_case.execute(self.contract, self.file) self.contract.refresh_from_db() @@ -254,7 +254,7 @@ def test_execute_contract_flag_overlapping_sponsorships(self): self.use_case.execute(self.contract, self.file) self.contract.refresh_from_db() recent_contract = baker.make_recipe( - "sponsors.tests.empty_contract", + "apps.sponsors.tests.empty_contract", status=Contract.DRAFT, sponsorship__sponsor=sponsorship.sponsor, sponsorship__start_date=sponsorship.start_date + timedelta(days=5), @@ -273,7 +273,7 @@ def test_execute_contract_do_not_flag_overlap_if_no_date_range_conflict(self): self.use_case.execute(self.contract, self.file) self.contract.refresh_from_db() recent_contract = baker.make_recipe( - "sponsors.tests.empty_contract", + "apps.sponsors.tests.empty_contract", status=Contract.DRAFT, sponsorship__sponsor=sponsorship.sponsor, sponsorship__start_date=sponsorship.end_date + timedelta(days=1), @@ -292,7 +292,7 @@ def test_execute_contract_do_not_flag_overlap_if_from_other_sponsor(self): self.use_case.execute(self.contract, self.file) self.contract.refresh_from_db() recent_contract = baker.make_recipe( - "sponsors.tests.empty_contract", + "apps.sponsors.tests.empty_contract", status=Contract.DRAFT, sponsorship__sponsor=baker.make(Sponsor), sponsorship__start_date=sponsorship.start_date + timedelta(days=5), @@ -312,7 +312,7 @@ def setUp(self): self.notifications = [Mock()] self.use_case = use_cases.NullifyContractUseCase(self.notifications) self.user = baker.make(settings.AUTH_USER_MODEL) - self.contract = baker.make_recipe("sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) def test_nullify_and_update_database_object(self): self.use_case.execute(self.contract) diff --git a/sponsors/tests/test_views.py b/apps/sponsors/tests/test_views.py similarity index 99% rename from sponsors/tests/test_views.py rename to apps/sponsors/tests/test_views.py index 8bba146a2..069c544fb 100644 --- a/sponsors/tests/test_views.py +++ b/apps/sponsors/tests/test_views.py @@ -10,11 +10,11 @@ from django.urls import reverse, reverse_lazy from model_bakery import baker -from sponsors.forms import ( +from apps.sponsors.forms import ( SponsorshipApplicationForm, SponsorshipsBenefitsForm, ) -from sponsors.models import ( +from apps.sponsors.models import ( Sponsor, SponsorContact, Sponsorship, @@ -22,7 +22,7 @@ SponsorshipCurrentYear, SponsorshipPackage, ) -from sponsors.tests.utils import assert_message, get_static_image_file_as_upload +from apps.sponsors.tests.utils import assert_message, get_static_image_file_as_upload class SelectSponsorshipApplicationBenefitsViewTests(TestCase): diff --git a/sponsors/tests/test_views_admin.py b/apps/sponsors/tests/test_views_admin.py similarity index 97% rename from sponsors/tests/test_views_admin.py rename to apps/sponsors/tests/test_views_admin.py index e5c13bb89..680c23698 100644 --- a/sponsors/tests/test_views_admin.py +++ b/apps/sponsors/tests/test_views_admin.py @@ -16,14 +16,14 @@ from django.utils import timezone from model_bakery import baker -from sponsors.forms import ( +from apps.sponsors.forms import ( CloneApplicationConfigForm, SendSponsorshipNotificationForm, SignedSponsorshipReviewAdminForm, SponsorshipReviewAdminForm, SponsorshipsListForm, ) -from sponsors.models import ( +from apps.sponsors.models import ( Contract, GenericAsset, ImgAsset, @@ -35,9 +35,9 @@ SponsorshipPackage, TextAsset, ) -from sponsors.tests.utils import assert_message, get_static_image_file_as_upload -from sponsors.use_cases import SendSponsorshipNotificationUseCase -from sponsors.views_admin import export_assets_as_zipfile, send_sponsorship_notifications_action +from apps.sponsors.tests.utils import assert_message, get_static_image_file_as_upload +from apps.sponsors.use_cases import SendSponsorshipNotificationUseCase +from apps.sponsors.views_admin import export_assets_as_zipfile, send_sponsorship_notifications_action class RollbackSponsorshipToEditingAdminViewTests(TestCase): @@ -415,7 +415,7 @@ class SendContractViewTests(TestCase): def setUp(self): self.user = baker.make(settings.AUTH_USER_MODEL, is_staff=True, is_superuser=True) self.client.force_login(self.user) - self.contract = baker.make_recipe("sponsors.tests.empty_contract") + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract") self.url = reverse("admin:sponsors_contract_send", args=[self.contract.pk]) self.data = { "confirm": "yes", @@ -501,7 +501,7 @@ class ExecuteContractViewTests(TestCase): def setUp(self): self.user = baker.make(settings.AUTH_USER_MODEL, is_staff=True, is_superuser=True) self.client.force_login(self.user) - self.contract = baker.make_recipe("sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) self.url = reverse("admin:sponsors_contract_execute", args=[self.contract.pk]) self.data = { "confirm": "yes", @@ -602,7 +602,7 @@ class NullifyContractViewTests(TestCase): def setUp(self): self.user = baker.make(settings.AUTH_USER_MODEL, is_staff=True, is_superuser=True) self.client.force_login(self.user) - self.contract = baker.make_recipe("sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) + self.contract = baker.make_recipe("apps.sponsors.tests.empty_contract", status=Contract.AWAITING_SIGNATURE) self.url = reverse("admin:sponsors_contract_nullify", args=[self.contract.pk]) self.data = { "confirm": "yes", @@ -789,11 +789,11 @@ def setUp(self): self.user = baker.make(settings.AUTH_USER_MODEL, is_staff=True, is_superuser=True) self.client.force_login(self.user) self.contract = baker.make_recipe( - "sponsors.tests.empty_contract", sponsorship__start_date=timezone.now().date() + "apps.sponsors.tests.empty_contract", sponsorship__start_date=timezone.now().date() ) self.url = reverse("admin:sponsors_contract_preview", args=[self.contract.pk]) - @patch("sponsors.views_admin.render_contract_to_pdf_response") + @patch("apps.sponsors.views_admin.render_contract_to_pdf_response") def test_render_pdf_by_default(self, mocked_render): response = HttpResponse() mocked_render.return_value = response @@ -806,7 +806,7 @@ def test_render_pdf_by_default(self, mocked_render): self.assertEqual(mocked_render.call_args[0][1], self.contract) self.assertIsInstance(mocked_render.call_args[0][0], WSGIRequest) - @patch("sponsors.views_admin.render_contract_to_docx_response") + @patch("apps.sponsors.views_admin.render_contract_to_docx_response") def test_render_docx_if_specified_in_the_querystring(self, mocked_render): response = HttpResponse() mocked_render.return_value = response @@ -923,7 +923,7 @@ def setUp(self): self.queryset = Sponsorship.objects.all() self.user = baker.make("users.User") - @patch("sponsors.views_admin.render") + @patch("apps.sponsors.views_admin.render") def test_render_template_and_context_as_expected(self, mocked_render): mocked_render.return_value = "HTTP Response" request = self.request_factory.post("/", data={}) @@ -942,7 +942,7 @@ def test_render_template_and_context_as_expected(self, mocked_render): self.assertNotIn(self.sponsorship, context["to_ignore"]) self.assertIsInstance(context["form"], SendSponsorshipNotificationForm) - @patch("sponsors.views_admin.render") + @patch("apps.sponsors.views_admin.render") def test_render_form_error_if_invalid(self, mocked_render): mocked_render.return_value = "HTTP Response" request = self.request_factory.post("/", data={"confirm": "yes"}) diff --git a/sponsors/tests/utils.py b/apps/sponsors/tests/utils.py similarity index 100% rename from sponsors/tests/utils.py rename to apps/sponsors/tests/utils.py diff --git a/sponsors/urls.py b/apps/sponsors/urls.py similarity index 92% rename from sponsors/urls.py rename to apps/sponsors/urls.py index 407bdb341..508162eda 100644 --- a/sponsors/urls.py +++ b/apps/sponsors/urls.py @@ -2,7 +2,7 @@ from django.urls import path -from sponsors import views +from apps.sponsors import views urlpatterns = [ path( diff --git a/sponsors/use_cases.py b/apps/sponsors/use_cases.py similarity index 97% rename from sponsors/use_cases.py rename to apps/sponsors/use_cases.py index ebe9d3d90..3e1e48c27 100644 --- a/sponsors/use_cases.py +++ b/apps/sponsors/use_cases.py @@ -2,9 +2,9 @@ from django.db import transaction -from sponsors import notifications -from sponsors.contracts import render_contract_to_docx_file, render_contract_to_pdf_file -from sponsors.models import ( +from apps.sponsors import notifications +from apps.sponsors.contracts import render_contract_to_docx_file, render_contract_to_pdf_file +from apps.sponsors.models import ( Contract, SponsorContact, SponsorEmailNotificationTemplate, diff --git a/sponsors/utils.py b/apps/sponsors/utils.py similarity index 100% rename from sponsors/utils.py rename to apps/sponsors/utils.py diff --git a/sponsors/views.py b/apps/sponsors/views.py similarity index 96% rename from sponsors/views.py rename to apps/sponsors/views.py index 03be9e950..1e128dffb 100644 --- a/sponsors/views.py +++ b/apps/sponsors/views.py @@ -12,9 +12,9 @@ from django.utils.decorators import method_decorator from django.views.generic import FormView -from sponsors import cookies, use_cases -from sponsors.forms import SponsorshipApplicationForm, SponsorshipsBenefitsForm -from sponsors.models import SponsorshipBenefit, SponsorshipCurrentYear, SponsorshipPackage, SponsorshipProgram +from apps.sponsors import cookies, use_cases +from apps.sponsors.forms import SponsorshipApplicationForm, SponsorshipsBenefitsForm +from apps.sponsors.models import SponsorshipBenefit, SponsorshipCurrentYear, SponsorshipPackage, SponsorshipProgram class SelectSponsorshipApplicationBenefitsView(FormView): diff --git a/sponsors/views_admin.py b/apps/sponsors/views_admin.py similarity index 98% rename from sponsors/views_admin.py rename to apps/sponsors/views_admin.py index 97c08e025..4931c8c92 100644 --- a/sponsors/views_admin.py +++ b/apps/sponsors/views_admin.py @@ -10,17 +10,17 @@ from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse -from sponsors import use_cases -from sponsors.contracts import render_contract_to_docx_response, render_contract_to_pdf_response -from sponsors.exceptions import InvalidStatusError -from sponsors.forms import ( +from apps.sponsors import use_cases +from apps.sponsors.contracts import render_contract_to_docx_response, render_contract_to_pdf_response +from apps.sponsors.exceptions import InvalidStatusError +from apps.sponsors.forms import ( CloneApplicationConfigForm, SendSponsorshipNotificationForm, SignedSponsorshipReviewAdminForm, SponsorshipReviewAdminForm, SponsorshipsListForm, ) -from sponsors.models import BenefitFeature, EmailTargetable, SponsorshipCurrentYear +from apps.sponsors.models import BenefitFeature, EmailTargetable, SponsorshipCurrentYear def preview_contract_view(model_admin, request, pk): diff --git a/successstories/__init__.py b/apps/successstories/__init__.py similarity index 100% rename from successstories/__init__.py rename to apps/successstories/__init__.py diff --git a/successstories/admin.py b/apps/successstories/admin.py similarity index 90% rename from successstories/admin.py rename to apps/successstories/admin.py index 7e8f19aaa..df4b721e8 100644 --- a/successstories/admin.py +++ b/apps/successstories/admin.py @@ -3,8 +3,8 @@ from django.contrib import admin from django.utils.html import format_html -from cms.admin import ContentManageableModelAdmin, NameSlugAdmin -from successstories.models import Story, StoryCategory +from apps.cms.admin import ContentManageableModelAdmin, NameSlugAdmin +from apps.successstories.models import Story, StoryCategory @admin.register(StoryCategory) diff --git a/successstories/apps.py b/apps/successstories/apps.py similarity index 76% rename from successstories/apps.py rename to apps/successstories/apps.py index cecd1088f..6909cfdde 100644 --- a/successstories/apps.py +++ b/apps/successstories/apps.py @@ -6,4 +6,5 @@ class SuccessstoriesAppConfig(AppConfig): """App configuration for the success stories app.""" - name = "successstories" + name = "apps.successstories" + label = "successstories" diff --git a/successstories/factories.py b/apps/successstories/factories.py similarity index 96% rename from successstories/factories.py rename to apps/successstories/factories.py index 09db6826c..3204c3779 100644 --- a/successstories/factories.py +++ b/apps/successstories/factories.py @@ -4,7 +4,7 @@ from factory.django import DjangoModelFactory from faker.providers import BaseProvider -from successstories.models import Story, StoryCategory +from apps.successstories.models import Story, StoryCategory class StoryProvider(BaseProvider): diff --git a/successstories/forms.py b/apps/successstories/forms.py similarity index 92% rename from successstories/forms.py rename to apps/successstories/forms.py index 7fa31f106..10c5ddb8a 100644 --- a/successstories/forms.py +++ b/apps/successstories/forms.py @@ -4,8 +4,8 @@ from django.db.models import Q from django.utils.text import slugify -from cms.forms import ContentManageableModelForm -from successstories.models import Story +from apps.cms.forms import ContentManageableModelForm +from apps.successstories.models import Story class StoryForm(ContentManageableModelForm): diff --git a/successstories/managers.py b/apps/successstories/managers.py similarity index 100% rename from successstories/managers.py rename to apps/successstories/managers.py diff --git a/successstories/migrations/0001_initial.py b/apps/successstories/migrations/0001_initial.py similarity index 100% rename from successstories/migrations/0001_initial.py rename to apps/successstories/migrations/0001_initial.py diff --git a/successstories/migrations/0002_auto_20150416_1853.py b/apps/successstories/migrations/0002_auto_20150416_1853.py similarity index 100% rename from successstories/migrations/0002_auto_20150416_1853.py rename to apps/successstories/migrations/0002_auto_20150416_1853.py diff --git a/successstories/migrations/0003_auto_20170720_1655.py b/apps/successstories/migrations/0003_auto_20170720_1655.py similarity index 100% rename from successstories/migrations/0003_auto_20170720_1655.py rename to apps/successstories/migrations/0003_auto_20170720_1655.py diff --git a/successstories/migrations/0004_auto_20170724_0507.py b/apps/successstories/migrations/0004_auto_20170724_0507.py similarity index 100% rename from successstories/migrations/0004_auto_20170724_0507.py rename to apps/successstories/migrations/0004_auto_20170724_0507.py diff --git a/successstories/migrations/0005_auto_20170726_0645.py b/apps/successstories/migrations/0005_auto_20170726_0645.py similarity index 100% rename from successstories/migrations/0005_auto_20170726_0645.py rename to apps/successstories/migrations/0005_auto_20170726_0645.py diff --git a/successstories/migrations/0006_auto_20170726_0824.py b/apps/successstories/migrations/0006_auto_20170726_0824.py similarity index 97% rename from successstories/migrations/0006_auto_20170726_0824.py rename to apps/successstories/migrations/0006_auto_20170726_0824.py index f1638487c..05a67f897 100644 --- a/successstories/migrations/0006_auto_20170726_0824.py +++ b/apps/successstories/migrations/0006_auto_20170726_0824.py @@ -2,7 +2,7 @@ from django.utils.text import slugify from django.utils.timezone import now -from successstories.utils import convert_to_datetime, get_field_list +from apps.successstories.utils import convert_to_datetime, get_field_list MARKER = ".. Migrated from Pages model.\n\n" DEFAULT_URL = "https://www.python.org/" diff --git a/successstories/migrations/0007_remove_story_weight.py b/apps/successstories/migrations/0007_remove_story_weight.py similarity index 100% rename from successstories/migrations/0007_remove_story_weight.py rename to apps/successstories/migrations/0007_remove_story_weight.py diff --git a/successstories/migrations/0008_auto_20170821_2000.py b/apps/successstories/migrations/0008_auto_20170821_2000.py similarity index 100% rename from successstories/migrations/0008_auto_20170821_2000.py rename to apps/successstories/migrations/0008_auto_20170821_2000.py diff --git a/successstories/migrations/0009_auto_20180705_0352.py b/apps/successstories/migrations/0009_auto_20180705_0352.py similarity index 100% rename from successstories/migrations/0009_auto_20180705_0352.py rename to apps/successstories/migrations/0009_auto_20180705_0352.py diff --git a/successstories/migrations/0010_story_submitted_by.py b/apps/successstories/migrations/0010_story_submitted_by.py similarity index 100% rename from successstories/migrations/0010_story_submitted_by.py rename to apps/successstories/migrations/0010_story_submitted_by.py diff --git a/successstories/migrations/0011_auto_20220127_1923.py b/apps/successstories/migrations/0011_auto_20220127_1923.py similarity index 100% rename from successstories/migrations/0011_auto_20220127_1923.py rename to apps/successstories/migrations/0011_auto_20220127_1923.py diff --git a/successstories/migrations/0012_alter_story_creator_alter_story_last_modified_by.py b/apps/successstories/migrations/0012_alter_story_creator_alter_story_last_modified_by.py similarity index 100% rename from successstories/migrations/0012_alter_story_creator_alter_story_last_modified_by.py rename to apps/successstories/migrations/0012_alter_story_creator_alter_story_last_modified_by.py diff --git a/successstories/migrations/__init__.py b/apps/successstories/migrations/__init__.py similarity index 100% rename from successstories/migrations/__init__.py rename to apps/successstories/migrations/__init__.py diff --git a/successstories/models.py b/apps/successstories/models.py similarity index 96% rename from successstories/models.py rename to apps/successstories/models.py index 2a9e40438..0d0b5705d 100644 --- a/successstories/models.py +++ b/apps/successstories/models.py @@ -10,11 +10,11 @@ from django.urls import reverse from markupfield.fields import MarkupField -from boxes.models import Box -from cms.models import ContentManageable, NameSlugModel -from companies.models import Company +from apps.boxes.models import Box +from apps.cms.models import ContentManageable, NameSlugModel +from apps.companies.models import Company +from apps.successstories.managers import StoryManager from fastly.utils import purge_url -from successstories.managers import StoryManager PSF_TO_EMAILS = ["psf-staff@python.org"] DEFAULT_MARKUP_TYPE = getattr(settings, "DEFAULT_MARKUP_TYPE", "restructuredtext") diff --git a/templates/successstories/base.html b/apps/successstories/templates/successstories/base.html similarity index 100% rename from templates/successstories/base.html rename to apps/successstories/templates/successstories/base.html diff --git a/templates/successstories/story_detail.html b/apps/successstories/templates/successstories/story_detail.html similarity index 100% rename from templates/successstories/story_detail.html rename to apps/successstories/templates/successstories/story_detail.html diff --git a/templates/successstories/story_form.html b/apps/successstories/templates/successstories/story_form.html similarity index 100% rename from templates/successstories/story_form.html rename to apps/successstories/templates/successstories/story_form.html diff --git a/templates/successstories/story_list.html b/apps/successstories/templates/successstories/story_list.html similarity index 100% rename from templates/successstories/story_list.html rename to apps/successstories/templates/successstories/story_list.html diff --git a/templates/successstories/storycategory_detail.html b/apps/successstories/templates/successstories/storycategory_detail.html similarity index 100% rename from templates/successstories/storycategory_detail.html rename to apps/successstories/templates/successstories/storycategory_detail.html diff --git a/templates/successstories/supernav.html b/apps/successstories/templates/successstories/supernav.html similarity index 100% rename from templates/successstories/supernav.html rename to apps/successstories/templates/successstories/supernav.html diff --git a/successstories/templatetags/__init__.py b/apps/successstories/templatetags/__init__.py similarity index 100% rename from successstories/templatetags/__init__.py rename to apps/successstories/templatetags/__init__.py diff --git a/successstories/templatetags/successstories.py b/apps/successstories/templatetags/successstories.py similarity index 93% rename from successstories/templatetags/successstories.py rename to apps/successstories/templatetags/successstories.py index 9d241564d..b40709a8c 100644 --- a/successstories/templatetags/successstories.py +++ b/apps/successstories/templatetags/successstories.py @@ -2,7 +2,7 @@ from django import template -from successstories.models import Story, StoryCategory +from apps.successstories.models import Story, StoryCategory register = template.Library() diff --git a/successstories/tests/__init__.py b/apps/successstories/tests/__init__.py similarity index 100% rename from successstories/tests/__init__.py rename to apps/successstories/tests/__init__.py diff --git a/successstories/tests/test_forms.py b/apps/successstories/tests/test_forms.py similarity index 93% rename from successstories/tests/test_forms.py rename to apps/successstories/tests/test_forms.py index 91f8d33e6..88d4cb6d9 100644 --- a/successstories/tests/test_forms.py +++ b/apps/successstories/tests/test_forms.py @@ -1,7 +1,7 @@ from django.test import TestCase -from successstories.factories import StoryCategoryFactory -from successstories.forms import StoryForm +from apps.successstories.factories import StoryCategoryFactory +from apps.successstories.forms import StoryForm class StoryFormTests(TestCase): diff --git a/successstories/tests/test_models.py b/apps/successstories/tests/test_models.py similarity index 89% rename from successstories/tests/test_models.py rename to apps/successstories/tests/test_models.py index adaa45d76..496b49902 100644 --- a/successstories/tests/test_models.py +++ b/apps/successstories/tests/test_models.py @@ -1,7 +1,7 @@ from django.test import TestCase -from successstories.factories import StoryCategoryFactory, StoryFactory -from successstories.models import Story +from apps.successstories.factories import StoryCategoryFactory, StoryFactory +from apps.successstories.models import Story class StoryModelTests(TestCase): diff --git a/successstories/tests/test_templatetags.py b/apps/successstories/tests/test_templatetags.py similarity index 95% rename from successstories/tests/test_templatetags.py rename to apps/successstories/tests/test_templatetags.py index 63c74f921..17d793b04 100644 --- a/successstories/tests/test_templatetags.py +++ b/apps/successstories/tests/test_templatetags.py @@ -1,7 +1,7 @@ from django import template from django.test import TestCase -from successstories.factories import StoryCategoryFactory, StoryFactory +from apps.successstories.factories import StoryCategoryFactory, StoryFactory class StoryTemplateTagTests(TestCase): diff --git a/successstories/tests/test_utils.py b/apps/successstories/tests/test_utils.py similarity index 91% rename from successstories/tests/test_utils.py rename to apps/successstories/tests/test_utils.py index fc05cbee3..05eaf4623 100644 --- a/successstories/tests/test_utils.py +++ b/apps/successstories/tests/test_utils.py @@ -2,7 +2,7 @@ from django.test import SimpleTestCase -from successstories.utils import convert_to_datetime, get_field_list +from apps.successstories.utils import convert_to_datetime, get_field_list class UtilsTestCase(SimpleTestCase): diff --git a/successstories/tests/test_views.py b/apps/successstories/tests/test_views.py similarity index 98% rename from successstories/tests/test_views.py rename to apps/successstories/tests/test_views.py index 1d5741d50..9d86e8e59 100644 --- a/successstories/tests/test_views.py +++ b/apps/successstories/tests/test_views.py @@ -6,9 +6,9 @@ from django.test import TestCase from django.urls import reverse -from successstories.factories import StoryCategoryFactory, StoryFactory -from successstories.models import Story -from users.factories import UserFactory +from apps.successstories.factories import StoryCategoryFactory, StoryFactory +from apps.successstories.models import Story +from apps.users.factories import UserFactory User = get_user_model() diff --git a/successstories/urls.py b/apps/successstories/urls.py similarity index 92% rename from successstories/urls.py rename to apps/successstories/urls.py index fcaed509e..64d49bbd4 100644 --- a/successstories/urls.py +++ b/apps/successstories/urls.py @@ -2,7 +2,7 @@ from django.urls import path -from successstories import views +from apps.successstories import views urlpatterns = [ path("", views.StoryList.as_view(), name="success_story_list"), diff --git a/successstories/utils.py b/apps/successstories/utils.py similarity index 100% rename from successstories/utils.py rename to apps/successstories/utils.py diff --git a/successstories/views.py b/apps/successstories/views.py similarity index 96% rename from successstories/views.py rename to apps/successstories/views.py index ff6624bf0..db68312fc 100644 --- a/successstories/views.py +++ b/apps/successstories/views.py @@ -7,8 +7,8 @@ from django.views.generic import CreateView, DetailView, ListView from honeypot.decorators import check_honeypot -from successstories.forms import StoryForm -from successstories.models import Story, StoryCategory +from apps.successstories.forms import StoryForm +from apps.successstories.models import Story, StoryCategory class ContextMixin: diff --git a/users/__init__.py b/apps/users/__init__.py similarity index 100% rename from users/__init__.py rename to apps/users/__init__.py diff --git a/users/actions.py b/apps/users/actions.py similarity index 100% rename from users/actions.py rename to apps/users/actions.py diff --git a/users/admin.py b/apps/users/admin.py similarity index 96% rename from users/admin.py rename to apps/users/admin.py index 015cb9684..fd0101f4f 100644 --- a/users/admin.py +++ b/apps/users/admin.py @@ -6,8 +6,8 @@ from rest_framework.authtoken.admin import TokenAdmin from tastypie.admin import ApiKeyInline as TastypieApiKeyInline -from users.actions import export_csv -from users.models import Membership, User +from apps.users.actions import export_csv +from apps.users.models import Membership, User TokenAdmin.search_fields = ("user__username",) TokenAdmin.raw_id_fields = ("user",) diff --git a/users/apps.py b/apps/users/apps.py similarity index 75% rename from users/apps.py rename to apps/users/apps.py index 73a799649..bcdad1e33 100644 --- a/users/apps.py +++ b/apps/users/apps.py @@ -6,9 +6,10 @@ class UsersAppConfig(AppConfig): """App configuration for user accounts and profiles.""" - name = "users" + name = "apps.users" + label = "users" verbose_name = "Users" def ready(self): """Perform app initialization when Django starts.""" - import users.listeners # noqa: F401 + import apps.users.listeners # noqa: F401 diff --git a/users/factories.py b/apps/users/factories.py similarity index 92% rename from users/factories.py rename to apps/users/factories.py index e672e0e8e..2bc819e53 100644 --- a/users/factories.py +++ b/apps/users/factories.py @@ -3,7 +3,7 @@ import factory from factory.django import DjangoModelFactory -from users.models import Membership, User +from apps.users.models import Membership, User class UserFactory(DjangoModelFactory): @@ -31,7 +31,7 @@ class Meta: User.EMAIL_NEVER, ] ) - membership = factory.RelatedFactory("users.factories.MembershipFactory", "creator") + membership = factory.RelatedFactory("apps.users.factories.MembershipFactory", "creator") @factory.post_generation def groups(self, create, extracted, **kwargs): diff --git a/users/forms.py b/apps/users/forms.py similarity index 98% rename from users/forms.py rename to apps/users/forms.py index 4618c85ac..c84142c79 100644 --- a/users/forms.py +++ b/apps/users/forms.py @@ -3,7 +3,7 @@ from django import forms from django.forms import ModelForm -from users.models import Membership, User +from apps.users.models import Membership, User class UserProfileForm(ModelForm): diff --git a/users/listeners.py b/apps/users/listeners.py similarity index 92% rename from users/listeners.py rename to apps/users/listeners.py index 91cd5304c..d0fc216d7 100644 --- a/users/listeners.py +++ b/apps/users/listeners.py @@ -4,7 +4,7 @@ from django.dispatch import receiver from rest_framework.authtoken.models import Token -from users.models import User +from apps.users.models import User @receiver(post_save, sender=User) diff --git a/users/managers.py b/apps/users/managers.py similarity index 100% rename from users/managers.py rename to apps/users/managers.py diff --git a/users/migrations/0001_initial.py b/apps/users/migrations/0001_initial.py similarity index 100% rename from users/migrations/0001_initial.py rename to apps/users/migrations/0001_initial.py diff --git a/users/migrations/0002_auto_20150416_1853.py b/apps/users/migrations/0002_auto_20150416_1853.py similarity index 100% rename from users/migrations/0002_auto_20150416_1853.py rename to apps/users/migrations/0002_auto_20150416_1853.py diff --git a/users/migrations/0003_auto_20150503_2026.py b/apps/users/migrations/0003_auto_20150503_2026.py similarity index 100% rename from users/migrations/0003_auto_20150503_2026.py rename to apps/users/migrations/0003_auto_20150503_2026.py diff --git a/users/migrations/0004_auto_20150503_2100.py b/apps/users/migrations/0004_auto_20150503_2100.py similarity index 100% rename from users/migrations/0004_auto_20150503_2100.py rename to apps/users/migrations/0004_auto_20150503_2100.py diff --git a/users/migrations/0005_user_public_profile.py b/apps/users/migrations/0005_user_public_profile.py similarity index 100% rename from users/migrations/0005_user_public_profile.py rename to apps/users/migrations/0005_user_public_profile.py diff --git a/users/migrations/0006_auto_20150503_2124.py b/apps/users/migrations/0006_auto_20150503_2124.py similarity index 100% rename from users/migrations/0006_auto_20150503_2124.py rename to apps/users/migrations/0006_auto_20150503_2124.py diff --git a/users/migrations/0007_auto_20150604_1555.py b/apps/users/migrations/0007_auto_20150604_1555.py similarity index 100% rename from users/migrations/0007_auto_20150604_1555.py rename to apps/users/migrations/0007_auto_20150604_1555.py diff --git a/users/migrations/0008_auto_20170814_0301.py b/apps/users/migrations/0008_auto_20170814_0301.py similarity index 100% rename from users/migrations/0008_auto_20170814_0301.py rename to apps/users/migrations/0008_auto_20170814_0301.py diff --git a/users/migrations/0009_auto_20170821_2000.py b/apps/users/migrations/0009_auto_20170821_2000.py similarity index 100% rename from users/migrations/0009_auto_20170821_2000.py rename to apps/users/migrations/0009_auto_20170821_2000.py diff --git a/users/migrations/0010_auto_20170828_1906.py b/apps/users/migrations/0010_auto_20170828_1906.py similarity index 100% rename from users/migrations/0010_auto_20170828_1906.py rename to apps/users/migrations/0010_auto_20170828_1906.py diff --git a/users/migrations/0011_auto_20170902_0930.py b/apps/users/migrations/0011_auto_20170902_0930.py similarity index 100% rename from users/migrations/0011_auto_20170902_0930.py rename to apps/users/migrations/0011_auto_20170902_0930.py diff --git a/users/migrations/0012_usergroup.py b/apps/users/migrations/0012_usergroup.py similarity index 100% rename from users/migrations/0012_usergroup.py rename to apps/users/migrations/0012_usergroup.py diff --git a/users/migrations/0013_auto_20180705_0348.py b/apps/users/migrations/0013_auto_20180705_0348.py similarity index 100% rename from users/migrations/0013_auto_20180705_0348.py rename to apps/users/migrations/0013_auto_20180705_0348.py diff --git a/users/migrations/0014_auto_20210801_2332.py b/apps/users/migrations/0014_auto_20210801_2332.py similarity index 100% rename from users/migrations/0014_auto_20210801_2332.py rename to apps/users/migrations/0014_auto_20210801_2332.py diff --git a/users/migrations/0015_alter_user_first_name.py b/apps/users/migrations/0015_alter_user_first_name.py similarity index 100% rename from users/migrations/0015_alter_user_first_name.py rename to apps/users/migrations/0015_alter_user_first_name.py diff --git a/users/migrations/__init__.py b/apps/users/migrations/__init__.py similarity index 100% rename from users/migrations/__init__.py rename to apps/users/migrations/__init__.py diff --git a/users/models.py b/apps/users/models.py similarity index 98% rename from users/models.py rename to apps/users/models.py index 1727e87b2..9f79f2bb3 100644 --- a/users/models.py +++ b/apps/users/models.py @@ -11,7 +11,7 @@ from rest_framework.authtoken.models import Token from tastypie.models import create_api_key -from users.managers import UserManager +from apps.users.managers import UserManager DEFAULT_MARKUP_TYPE = getattr(settings, "DEFAULT_MARKUP_TYPE", "markdown") @@ -69,7 +69,7 @@ def has_membership(self): @property def sponsorships(self): """Return sponsorships visible to this user.""" - from sponsors.models import Sponsorship + from apps.sponsors.models import Sponsorship return Sponsorship.objects.visible_to(self) diff --git a/templates/users/_membership_detail.html b/apps/users/templates/users/_membership_detail.html similarity index 100% rename from templates/users/_membership_detail.html rename to apps/users/templates/users/_membership_detail.html diff --git a/templates/users/base.html b/apps/users/templates/users/base.html similarity index 100% rename from templates/users/base.html rename to apps/users/templates/users/base.html diff --git a/templates/users/list_user_sponsorships.html b/apps/users/templates/users/list_user_sponsorships.html similarity index 100% rename from templates/users/list_user_sponsorships.html rename to apps/users/templates/users/list_user_sponsorships.html diff --git a/templates/users/membership.html b/apps/users/templates/users/membership.html similarity index 100% rename from templates/users/membership.html rename to apps/users/templates/users/membership.html diff --git a/templates/users/membership_form.html b/apps/users/templates/users/membership_form.html similarity index 100% rename from templates/users/membership_form.html rename to apps/users/templates/users/membership_form.html diff --git a/templates/users/membership_thanks.html b/apps/users/templates/users/membership_thanks.html similarity index 100% rename from templates/users/membership_thanks.html rename to apps/users/templates/users/membership_thanks.html diff --git a/templates/users/membership_vote_affirm.html b/apps/users/templates/users/membership_vote_affirm.html similarity index 100% rename from templates/users/membership_vote_affirm.html rename to apps/users/templates/users/membership_vote_affirm.html diff --git a/templates/users/membership_vote_affirm_done.html b/apps/users/templates/users/membership_vote_affirm_done.html similarity index 100% rename from templates/users/membership_vote_affirm_done.html rename to apps/users/templates/users/membership_vote_affirm_done.html diff --git a/templates/users/nominations_view.html b/apps/users/templates/users/nominations_view.html similarity index 100% rename from templates/users/nominations_view.html rename to apps/users/templates/users/nominations_view.html diff --git a/templates/users/sponsor_info_update.html b/apps/users/templates/users/sponsor_info_update.html similarity index 100% rename from templates/users/sponsor_info_update.html rename to apps/users/templates/users/sponsor_info_update.html diff --git a/templates/users/sponsor_select.html b/apps/users/templates/users/sponsor_select.html similarity index 100% rename from templates/users/sponsor_select.html rename to apps/users/templates/users/sponsor_select.html diff --git a/templates/users/sponsorship_assets_update.html b/apps/users/templates/users/sponsorship_assets_update.html similarity index 100% rename from templates/users/sponsorship_assets_update.html rename to apps/users/templates/users/sponsorship_assets_update.html diff --git a/templates/users/sponsorship_assets_view.html b/apps/users/templates/users/sponsorship_assets_view.html similarity index 100% rename from templates/users/sponsorship_assets_view.html rename to apps/users/templates/users/sponsorship_assets_view.html diff --git a/templates/users/sponsorship_detail.html b/apps/users/templates/users/sponsorship_detail.html similarity index 100% rename from templates/users/sponsorship_detail.html rename to apps/users/templates/users/sponsorship_detail.html diff --git a/templates/users/user_detail.html b/apps/users/templates/users/user_detail.html similarity index 100% rename from templates/users/user_detail.html rename to apps/users/templates/users/user_detail.html diff --git a/templates/users/user_form.html b/apps/users/templates/users/user_form.html similarity index 100% rename from templates/users/user_form.html rename to apps/users/templates/users/user_form.html diff --git a/users/templatetags/__init__.py b/apps/users/templatetags/__init__.py similarity index 100% rename from users/templatetags/__init__.py rename to apps/users/templatetags/__init__.py diff --git a/users/templatetags/users_tags.py b/apps/users/templatetags/users_tags.py similarity index 95% rename from users/templatetags/users_tags.py rename to apps/users/templatetags/users_tags.py index 8b2af9c89..4eb224c3e 100644 --- a/users/templatetags/users_tags.py +++ b/apps/users/templatetags/users_tags.py @@ -2,7 +2,7 @@ from django import template -from users.models import Membership +from apps.users.models import Membership register = template.Library() diff --git a/users/tests/__init__.py b/apps/users/tests/__init__.py similarity index 100% rename from users/tests/__init__.py rename to apps/users/tests/__init__.py diff --git a/users/tests/test_forms.py b/apps/users/tests/test_forms.py similarity index 98% rename from users/tests/test_forms.py rename to apps/users/tests/test_forms.py index 286f2f823..8c814848b 100644 --- a/users/tests/test_forms.py +++ b/apps/users/tests/test_forms.py @@ -3,7 +3,7 @@ from django.contrib.auth import get_user_model from django.test import TestCase -from users.forms import MembershipForm, UserProfileForm +from apps.users.forms import MembershipForm, UserProfileForm User = get_user_model() diff --git a/users/tests/test_membership_links.py b/apps/users/tests/test_membership_links.py similarity index 96% rename from users/tests/test_membership_links.py rename to apps/users/tests/test_membership_links.py index 3f21c140c..37bdd54d7 100644 --- a/users/tests/test_membership_links.py +++ b/apps/users/tests/test_membership_links.py @@ -3,7 +3,7 @@ from django.template import Context, Template from django.test import RequestFactory, TestCase -from users.models import Membership +from apps.users.models import Membership User = get_user_model() diff --git a/users/tests/test_models.py b/apps/users/tests/test_models.py similarity index 94% rename from users/tests/test_models.py rename to apps/users/tests/test_models.py index a6b37d481..68e5418bb 100644 --- a/users/tests/test_models.py +++ b/apps/users/tests/test_models.py @@ -4,8 +4,8 @@ from django.test import TestCase from django.utils import timezone -from users.factories import MembershipFactory, UserFactory -from users.models import Membership, UserGroup +from apps.users.factories import MembershipFactory, UserFactory +from apps.users.models import Membership, UserGroup User = get_user_model() diff --git a/users/tests/test_templatetags.py b/apps/users/tests/test_templatetags.py similarity index 97% rename from users/tests/test_templatetags.py rename to apps/users/tests/test_templatetags.py index c85926abf..fdd6bc994 100644 --- a/users/tests/test_templatetags.py +++ b/apps/users/tests/test_templatetags.py @@ -1,5 +1,5 @@ +from apps.users.factories import UserFactory from pydotorg.tests.test_classes import TemplateTestCase -from users.factories import UserFactory class UsersTagsTest(TemplateTestCase): diff --git a/users/tests/test_views.py b/apps/users/tests/test_views.py similarity index 98% rename from users/tests/test_views.py rename to apps/users/tests/test_views.py index 383ef9f3d..008802771 100644 --- a/users/tests/test_views.py +++ b/apps/users/tests/test_views.py @@ -5,12 +5,12 @@ from django.urls import reverse from model_bakery import baker -from sponsors.forms import SponsorRequiredAssetsForm, SponsorUpdateForm -from sponsors.models import RequiredTextAssetConfiguration, SponsorBenefit, Sponsorship -from sponsors.models.enums import AssetsRelatedTo -from sponsors.tests.utils import get_static_image_file_as_upload -from users.factories import UserFactory -from users.models import Membership +from apps.sponsors.forms import SponsorRequiredAssetsForm, SponsorUpdateForm +from apps.sponsors.models import RequiredTextAssetConfiguration, SponsorBenefit, Sponsorship +from apps.sponsors.models.enums import AssetsRelatedTo +from apps.sponsors.tests.utils import get_static_image_file_as_upload +from apps.users.factories import UserFactory +from apps.users.models import Membership User = get_user_model() diff --git a/users/urls.py b/apps/users/urls.py similarity index 98% rename from users/urls.py rename to apps/users/urls.py index 3f88d1acf..110090ff4 100644 --- a/users/urls.py +++ b/apps/users/urls.py @@ -2,7 +2,7 @@ from django.urls import path, re_path -from users import views +from apps.users import views app_name = "users" urlpatterns = [ diff --git a/users/validators.py b/apps/users/validators.py similarity index 100% rename from users/validators.py rename to apps/users/validators.py diff --git a/users/views.py b/apps/users/views.py similarity index 98% rename from users/views.py rename to apps/users/views.py index 053fa1451..9a3264d2e 100644 --- a/users/views.py +++ b/apps/users/views.py @@ -18,11 +18,11 @@ from django.views.generic import CreateView, DeleteView, DetailView, ListView, TemplateView, UpdateView from honeypot.decorators import check_honeypot +from apps.sponsors.forms import SponsorRequiredAssetsForm, SponsorUpdateForm +from apps.sponsors.models import BenefitFeature, Sponsor, Sponsorship +from apps.users.forms import MembershipForm, MembershipUpdateForm, UserProfileForm +from apps.users.models import Membership from pydotorg.mixins import LoginRequiredMixin -from sponsors.forms import SponsorRequiredAssetsForm, SponsorUpdateForm -from sponsors.models import BenefitFeature, Sponsor, Sponsorship -from users.forms import MembershipForm, MembershipUpdateForm, UserProfileForm -from users.models import Membership User = get_user_model() diff --git a/work_groups/__init__.py b/apps/work_groups/__init__.py similarity index 100% rename from work_groups/__init__.py rename to apps/work_groups/__init__.py diff --git a/work_groups/admin.py b/apps/work_groups/admin.py similarity index 92% rename from work_groups/admin.py rename to apps/work_groups/admin.py index a0537776d..04ded118c 100644 --- a/work_groups/admin.py +++ b/apps/work_groups/admin.py @@ -2,8 +2,8 @@ from django.contrib import admin -from cms.admin import ContentManageableModelAdmin -from work_groups.models import WorkGroup +from apps.cms.admin import ContentManageableModelAdmin +from apps.work_groups.models import WorkGroup @admin.register(WorkGroup) diff --git a/work_groups/apps.py b/apps/work_groups/apps.py similarity index 76% rename from work_groups/apps.py rename to apps/work_groups/apps.py index c3e013d22..42ab59b9d 100644 --- a/work_groups/apps.py +++ b/apps/work_groups/apps.py @@ -6,4 +6,5 @@ class WorkGroupsAppConfig(AppConfig): """App configuration for the work_groups app.""" - name = "work_groups" + name = "apps.work_groups" + label = "work_groups" diff --git a/work_groups/migrations/0001_initial.py b/apps/work_groups/migrations/0001_initial.py similarity index 100% rename from work_groups/migrations/0001_initial.py rename to apps/work_groups/migrations/0001_initial.py diff --git a/work_groups/migrations/0002_auto_20150604_2203.py b/apps/work_groups/migrations/0002_auto_20150604_2203.py similarity index 100% rename from work_groups/migrations/0002_auto_20150604_2203.py rename to apps/work_groups/migrations/0002_auto_20150604_2203.py diff --git a/work_groups/migrations/0003_auto_20170821_2000.py b/apps/work_groups/migrations/0003_auto_20170821_2000.py similarity index 100% rename from work_groups/migrations/0003_auto_20170821_2000.py rename to apps/work_groups/migrations/0003_auto_20170821_2000.py diff --git a/work_groups/migrations/0004_auto_20180705_0352.py b/apps/work_groups/migrations/0004_auto_20180705_0352.py similarity index 100% rename from work_groups/migrations/0004_auto_20180705_0352.py rename to apps/work_groups/migrations/0004_auto_20180705_0352.py diff --git a/work_groups/migrations/0005_alter_workgroup_creator_and_more.py b/apps/work_groups/migrations/0005_alter_workgroup_creator_and_more.py similarity index 100% rename from work_groups/migrations/0005_alter_workgroup_creator_and_more.py rename to apps/work_groups/migrations/0005_alter_workgroup_creator_and_more.py diff --git a/work_groups/migrations/__init__.py b/apps/work_groups/migrations/__init__.py similarity index 100% rename from work_groups/migrations/__init__.py rename to apps/work_groups/migrations/__init__.py diff --git a/work_groups/models.py b/apps/work_groups/models.py similarity index 97% rename from work_groups/models.py rename to apps/work_groups/models.py index d0c4e5a78..cdba21737 100644 --- a/work_groups/models.py +++ b/apps/work_groups/models.py @@ -4,7 +4,7 @@ from django.db import models from markupfield.fields import MarkupField -from cms.models import ContentManageable, NameSlugModel +from apps.cms.models import ContentManageable, NameSlugModel DEFAULT_MARKUP_TYPE = getattr(settings, "DEFAULT_MARKUP_TYPE", "restructuredtext") diff --git a/work_groups/tests/__init__.py b/apps/work_groups/tests/__init__.py similarity index 100% rename from work_groups/tests/__init__.py rename to apps/work_groups/tests/__init__.py diff --git a/work_groups/tests/test_models.py b/apps/work_groups/tests/test_models.py similarity index 100% rename from work_groups/tests/test_models.py rename to apps/work_groups/tests/test_models.py diff --git a/pydotorg/settings/base.py b/pydotorg/settings/base.py index 9d94fe4d0..4ae7cc97e 100644 --- a/pydotorg/settings/base.py +++ b/pydotorg/settings/base.py @@ -102,7 +102,7 @@ SOCIALACCOUNT_EMAIL_REQUIRED = True SOCIALACCOUNT_EMAIL_VERIFICATION = True SOCIALACCOUNT_QUERY_EMAIL = True -ACCOUNT_USERNAME_VALIDATORS = "users.validators.username_validators" +ACCOUNT_USERNAME_VALIDATORS = "apps.users.validators.username_validators" ### Templates @@ -156,7 +156,7 @@ "django.contrib.messages.middleware.MessageMiddleware", "waffle.middleware.WaffleMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", - "pages.middleware.PageFallbackMiddleware", + "apps.pages.middleware.PageFallbackMiddleware", "django.contrib.redirects.middleware.RedirectFallbackMiddleware", "allauth.account.middleware.AccountMiddleware", ] @@ -192,24 +192,24 @@ "widget_tweaks", "django_countries", "sorl.thumbnail", - "banners", - "blogs", - "boxes", - "cms", - "codesamples", - "community", - "companies", - "downloads", - "events", - "jobs", - "mailing", - "minutes", - "nominations", - "pages", - "sponsors", - "successstories", - "users", - "work_groups", + "apps.banners", + "apps.blogs", + "apps.boxes", + "apps.cms", + "apps.codesamples", + "apps.community", + "apps.companies", + "apps.downloads", + "apps.events", + "apps.jobs", + "apps.mailing", + "apps.minutes", + "apps.nominations", + "apps.pages", + "apps.sponsors", + "apps.successstories", + "apps.users", + "apps.work_groups", "allauth", "allauth.account", # Tastypie needs the `users` app to be already loaded. diff --git a/pydotorg/tests/test_views.py b/pydotorg/tests/test_views.py index b71f832e0..b21c54b57 100644 --- a/pydotorg/tests/test_views.py +++ b/pydotorg/tests/test_views.py @@ -3,7 +3,7 @@ from django.test import TestCase from django.urls import reverse -from downloads.models import Release +from apps.downloads.models import Release class ViewsTests(TestCase): diff --git a/pydotorg/urls.py b/pydotorg/urls.py index 11e323e69..fd0ec3c25 100644 --- a/pydotorg/urls.py +++ b/pydotorg/urls.py @@ -7,10 +7,10 @@ from django.urls import include, path, re_path from django.views.generic.base import TemplateView -from cms.views import custom_404 -from downloads.views import ReleaseEditButton +from apps.cms.views import custom_404 +from apps.downloads.views import ReleaseEditButton +from apps.users.views import CustomPasswordChangeView, HoneypotSignupView from pydotorg import urls_api, views -from users.views import CustomPasswordChangeView, HoneypotSignupView handler404 = custom_404 @@ -28,11 +28,11 @@ path("about/", TemplateView.as_view(template_name="python/about.html"), name="about"), # duplicated downloads to getit to bypass China's firewall. See # https://github.com/python/pythondotorg/issues/427 for more info. - path("getit/", include("downloads.urls", namespace="getit")), - path("downloads/", include("downloads.urls", namespace="download")), + path("getit/", include("apps.downloads.urls", namespace="getit")), + path("downloads/", include("apps.downloads.urls", namespace="download")), path("doc/", views.DocumentationIndexView.as_view(), name="documentation"), path("doc/versions/", views.DocsByVersionView.as_view(), name="docs-versions"), - path("blogs/", include("blogs.urls")), + path("blogs/", include("apps.blogs.urls")), path("inner/", TemplateView.as_view(template_name="python/inner.html"), name="inner"), # other section landing pages path("psf-landing/", TemplateView.as_view(template_name="psf/index.html"), name="psf-landing"), @@ -46,18 +46,18 @@ # and change success URL. path("accounts/password/change/", CustomPasswordChangeView.as_view(), name="account_change_password"), path("accounts/", include("allauth.urls")), - path("box/", include("boxes.urls")), - path("community/", include("community.urls", namespace="community")), + path("box/", include("apps.boxes.urls")), + path("community/", include("apps.community.urls", namespace="community")), path("community/microbit/", TemplateView.as_view(template_name="community/microbit.html"), name="microbit"), - path("events/", include("events.urls", namespace="events")), - path("jobs/", include("jobs.urls", namespace="jobs")), - path("sponsors/", include("sponsors.urls")), - path("success-stories/", include("successstories.urls")), - path("users/", include("users.urls", namespace="users")), - path("psf/records/board/minutes/", include("minutes.urls")), - path("membership/", include("membership.urls")), + path("events/", include("apps.events.urls", namespace="events")), + path("jobs/", include("apps.jobs.urls", namespace="jobs")), + path("sponsors/", include("apps.sponsors.urls")), + path("success-stories/", include("apps.successstories.urls")), + path("users/", include("apps.users.urls", namespace="users")), + path("psf/records/board/minutes/", include("apps.minutes.urls")), + path("membership/", include("apps.membership.urls")), path("search/", include("haystack.urls")), - path("nominations/", include("nominations.urls")), + path("nominations/", include("apps.nominations.urls")), # admin path("admin/doc/", include("django.contrib.admindocs.urls")), path("admin/", admin.site.urls), diff --git a/pydotorg/urls_api.py b/pydotorg/urls_api.py index 727206d83..06ffc11ad 100644 --- a/pydotorg/urls_api.py +++ b/pydotorg/urls_api.py @@ -4,7 +4,7 @@ from rest_framework import routers from tastypie.api import Api -from downloads.api import ( +from apps.downloads.api import ( OSResource, OSViewSet, ReleaseFileResource, @@ -12,8 +12,8 @@ ReleaseResource, ReleaseViewSet, ) -from pages.api import PageResource, PageViewSet -from sponsors.api import LogoPlacementeAPIList, SponsorshipAssetsAPIList +from apps.pages.api import PageResource, PageViewSet +from apps.sponsors.api import LogoPlacementeAPIList, SponsorshipAssetsAPIList v1_api = Api(api_name="v1") v1_api.register(PageResource()) diff --git a/pydotorg/views.py b/pydotorg/views.py index dc3f79cdf..53bcc76e8 100644 --- a/pydotorg/views.py +++ b/pydotorg/views.py @@ -10,8 +10,8 @@ from django.http import HttpResponse, JsonResponse from django.views.generic.base import RedirectView, TemplateView -from codesamples.models import CodeSample -from downloads.models import Release +from apps.codesamples.models import CodeSample +from apps.downloads.models import Release def health(request): diff --git a/ruff.toml b/ruff.toml index 24ebf7d58..088430b3a 100644 --- a/ruff.toml +++ b/ruff.toml @@ -39,23 +39,10 @@ ban-relative-imports = "all" [lint.isort] known-first-party = [ + "apps", + "custom_storages", + "fastly", "pydotorg", - "blogs", - "boxes", - "cms", - "codesamples", - "community", - "companies", - "downloads", - "events", - "jobs", - "mailing", - "minutes", - "nominations", - "pages", - "sponsors", - "successstories", - "users", ] [lint.per-file-ignores]