internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: django-oscar/django-oscar

Issue:
UnicodeCSVWriter raises AttributeError: 'NoneType' object has no attribute 'writerows'
when it used in a second variant in the `with` statement and a filename has passed to the constructor.
I've tried smth like:

<pre>
from oscar.core.compat import UnicodeCSVWriter

data = [[1, 2, 3], [4, 5, 6]]
with UnicodeCSVWriter('test.csv') as writer:
    writer.writerows(data)`
</pre>

and have got AttributeError, while `test.csv` file was created but remains empty.

However, it works perfectly in the first variant: `writer = UnicodeCSVWriter(open_file=fhandler)`

It seems like `return self` should be in the end of the `__enter__` method (here: https://github.com/django-oscar/django-oscar/blob/master/src/oscar/core/compat.py#L154 )



Discussion:

Resolving patch:
diff --git a/src/oscar/core/compat.py b/src/oscar/core/compat.py
--- a/src/oscar/core/compat.py
+++ b/src/oscar/core/compat.py
@@ -151,6 +151,7 @@ def __enter__(self):
                           encoding=self.encoding, newline='')
         else:
             self.f = open(self.filename, 'wb')
+        return self
 
     def __exit__(self, type, value, traceback):
         assert self.filename is not None


Test patch:
diff --git a/tests/unit/core/compat_tests.py b/tests/unit/core/compat_tests.py
--- a/tests/unit/core/compat_tests.py
+++ b/tests/unit/core/compat_tests.py
@@ -1,5 +1,6 @@
 # -*- coding: utf-8 -*-
 import datetime
+from tempfile import NamedTemporaryFile
 from django.utils import six
 from django.utils.six.moves import cStringIO
 
@@ -7,6 +8,19 @@
 
 from oscar.core.compat import UnicodeCSVWriter, existing_user_fields
 
+
+class unicodeobj(object):
+
+    def __init__(self, s):
+        self.s = s
+
+    def __str__(self):
+        return self.s
+
+    def __unicode__(self):
+        return self.s
+
+
 class TestExistingUserFields(TestCase):
 
     def test_order(self):
@@ -19,15 +33,17 @@ class TestUnicodeCSVWriter(TestCase):
     def test_can_write_different_values(self):
         writer = UnicodeCSVWriter(open_file=cStringIO())
         s = u'ünįcodē'
-        class unicodeobj(object):
-            def __str__(self):
-                return s
-            def __unicode__(self):
-                return s
-        rows = [[s, unicodeobj(), 123, datetime.date.today()], ]
+        rows = [[s, unicodeobj(s), 123, datetime.date.today()], ]
         writer.writerows(rows)
         self.assertRaises(TypeError, writer.writerows, [object()])
 
+    def test_context_manager(self):
+        tmp_file = NamedTemporaryFile()
+        with UnicodeCSVWriter(filename=tmp_file.name) as writer:
+            s = u'ünįcodē'
+            rows = [[s, unicodeobj(s), 123, datetime.date.today()], ]
+            writer.writerows(rows)
+
 
 class TestPython3Compatibility(TestCase):
Repository: django-oscar/django-oscar

Issue:
Broken sandbox gateway page
The README states that dashboard users for the sandbox site could be created using [this gateway page](http://latest.oscarcommerce.com/gateway/) - however this link returns a django error page:

```
TemplateDoesNotExist at /de/gateway/
gateway/form.html
```



Discussion:
Indeed, template path for the sandbox site is incorrect. Thanks for the find!


Resolving patch:
diff --git a/sites/sandbox/settings.py b/sites/sandbox/settings.py
--- a/sites/sandbox/settings.py
+++ b/sites/sandbox/settings.py
@@ -123,7 +123,7 @@
     {
         'BACKEND': 'django.template.backends.django.DjangoTemplates',
         'DIRS': [
-            location('_site/templates'),
+            location('templates'),
             oscar.OSCAR_MAIN_TEMPLATE_DIR,
         ],
         'OPTIONS': {


Test patch:
Repository: django-oscar/django-oscar

Issue:
TypeError in the dashboard reports
When date range in dashboard reports does not have both start and end date, report form throws and exception:

```python
TypeError at /ru/dashboard/reports/
unorderable types: NoneType() > datetime.date()
```


Discussion:

Resolving patch:
diff --git a/src/oscar/apps/dashboard/reports/forms.py b/src/oscar/apps/dashboard/reports/forms.py
--- a/src/oscar/apps/dashboard/reports/forms.py
+++ b/src/oscar/apps/dashboard/reports/forms.py
@@ -31,8 +31,9 @@ class ReportForm(forms.Form):
     download = forms.BooleanField(label=_("Download"), required=False)
 
     def clean(self):
-        if ('date_from' in self.cleaned_data and 'date_to' in self.cleaned_data
-                and self.cleaned_data['date_from'] >
+        date_from = self.cleaned_data.get('date_from', None)
+        date_to = self.cleaned_data.get('date_to', None)
+        if (all([date_from, date_to]) and self.cleaned_data['date_from'] >
                 self.cleaned_data['date_to']):
             raise forms.ValidationError(_("Your start date must be before your"
                                           " end date"))


Test patch:
diff --git a/tests/unit/dashboard/reports_form_tests.py b/tests/unit/dashboard/reports_form_tests.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/dashboard/reports_form_tests.py
@@ -0,0 +1,50 @@
+from django.test import TestCase
+
+from oscar.apps.dashboard.reports import forms
+
+
+class TestReportsForm(TestCase):
+
+    def test_date_range_empty(self):
+        form = forms.ReportForm(data={})
+        self.assertFalse(form.is_valid())
+
+    def test_date_range_complete(self):
+        form = forms.ReportForm(data={
+            'date_from': '2016-11-02',
+            'date_to': '2016-11-03',
+            'report_type': 'order_report'
+        })
+        self.assertTrue(form.is_valid())
+
+    def test_date_range_incomplete(self):
+        form = forms.ReportForm(data={
+            'report_type': 'order_report',
+            'date_to': '',
+            'date_from': '2016-11-02'
+        })
+        self.assertTrue(form.is_valid(), form.errors)
+        form = forms.ReportForm(data={
+            'date_from': '',
+            'date_to': '2016-11-03',
+            'report_type': 'order_report'
+        })
+        self.assertTrue(form.is_valid())
+        form = forms.ReportForm(data={
+            'date_from': '2016-11-02',
+            'report_type': 'order_report'
+        })
+        self.assertTrue(form.is_valid())
+        form = forms.ReportForm(data={
+            'date_to': '2016-11-03',
+            'report_type': 'order_report'
+        })
+        self.assertTrue(form.is_valid())
+
+    def test_date_range_incorrect(self):
+        form = forms.ReportForm(data={
+            'date_from': '2016-11-03',
+            'date_to': '2016-11-02',
+            'report_type': 'order_report'
+        })
+        self.assertFalse(form.is_valid())
Repository: django-oscar/django-oscar

Issue:
Can't re-add removed product to the range
After product was removed though the dashboard range edit and then added again, it does not appear in products list.


Discussion:

Resolving patch:
diff --git a/src/oscar/apps/offer/abstract_models.py b/src/oscar/apps/offer/abstract_models.py
--- a/src/oscar/apps/offer/abstract_models.py
+++ b/src/oscar/apps/offer/abstract_models.py
@@ -840,6 +840,12 @@ def add_product(self, product, display_order=None):
             relation.display_order = display_order
             relation.save()
 
+        # Remove product from excluded products if it was removed earlier and
+        # re-added again, thus it returns back to the range product list.
+        if product.id in self._excluded_product_ids():
+            self.excluded_products.remove(product)
+            self.invalidate_cached_ids()
+
     def remove_product(self, product):
         """
         Remove product from range. To save on queries, this function does not


Test patch:
diff --git a/tests/integration/offer/range_tests.py b/tests/integration/offer/range_tests.py
--- a/tests/integration/offer/range_tests.py
+++ b/tests/integration/offer/range_tests.py
@@ -191,6 +191,12 @@ def test_product_remove_from_range(self):
         all_products = self.range.all_products()
         self.assertFalse(product in all_products)
 
+        # Re-adding product should return it to the products range
+        self.range.add_product(product)
+
+        all_products = self.range.all_products()
+        self.assertTrue(product in all_products)
+
     def test_range_is_reordable(self):
         product = create_product()
         self.range.add_product(product)
Repository: django-oscar/django-oscar

Issue:
Offer conditions are unwieldy to modify or extend because the proxy_class attribute is unique
This issue is related to #685. Just as the offer benefits the offer conditions should not require a unique proxy class. This would make writing and applying custom conditions easier as a single condition proxy class could be applied to multiple conditions.

Hacks for overwriting the AbstractCondition class as well as custom migrations don't seem like a good long term solution.


Discussion:
+1

We sort of addressed this in https://gitlab.com/thelabnyc/django-oscar-bluelight, but it certainly would be nice to see something upstream. The whole offers system is kind of unwieldy right now.


Resolving patch:
diff --git a/src/oscar/apps/offer/abstract_models.py b/src/oscar/apps/offer/abstract_models.py
--- a/src/oscar/apps/offer/abstract_models.py
+++ b/src/oscar/apps/offer/abstract_models.py
@@ -642,7 +642,7 @@ class AbstractCondition(models.Model):
         _('Value'), decimal_places=2, max_digits=12, null=True, blank=True)
 
     proxy_class = fields.NullCharField(
-        _("Custom class"), max_length=255, unique=True, default=None)
+        _("Custom class"), max_length=255, default=None)
 
     class Meta:
         abstract = True
diff --git a/src/oscar/apps/offer/migrations/0003_auto_20161120_1707.py b/src/oscar/apps/offer/migrations/0003_auto_20161120_1707.py
new file mode 100644
--- /dev/null
+++ b/src/oscar/apps/offer/migrations/0003_auto_20161120_1707.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.11 on 2016-11-20 17:07
+from __future__ import unicode_literals
+
+from django.db import migrations
+import oscar.models.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('offer', '0002_auto_20151210_1053'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='condition',
+            name='proxy_class',
+            field=oscar.models.fields.NullCharField(default=None, max_length=255, verbose_name='Custom class'),
+        ),
+    ]


Test patch:
Repository: django-oscar/django-oscar

Issue:
build_submission error
Hi,
You've changed ```get_order_totals``` call from (1.3)
```
total = self.get_order_totals( basket, shipping_charge=shipping_charge)
```
to (master branch)
```
total = self.get_order_totals( basket, shipping_charge=shipping_charge, **kwargs)
```
In apps.checkout.session.CheckoutSessionMixin.
So, the problem is when you call build_submission with basket passed in kwargs.
You are given ```django oscar get order_totals() got multiple values for argument 'basket'``` error when call ```get_order_totals``` because basek is passed twice ones as positional arg the second in kwargs.

For my own workaround I've just removed ``**kwargs```. The right way how to solve it is up to you.

Of course it is possible that I'm wrong and I try to use build_submission in strange way.

Regards
Jarek



```python
   def build_submission(self, **kwargs):
        """
        Return a dict of data that contains everything required for an order
        submission.  This includes payment details (if any).
        This can be the right place to perform tax lookups and apply them to
        the basket.
        """
--->        basket = kwargs.get('basket', self.request.basket)
        shipping_address = self.get_shipping_address(basket)
        shipping_method = self.get_shipping_method(
            basket, shipping_address)
        billing_address = self.get_billing_address(shipping_address)
        if not shipping_method:
            total = shipping_charge = None
        else:
            shipping_charge = shipping_method.calculate(basket)
--->            total = self.get_order_totals( basket, shipping_charge=shipping_charge, **kwargs)
```


Discussion:

Resolving patch:
diff --git a/src/oscar/apps/checkout/session.py b/src/oscar/apps/checkout/session.py
--- a/src/oscar/apps/checkout/session.py
+++ b/src/oscar/apps/checkout/session.py
@@ -264,7 +264,9 @@ def build_submission(self, **kwargs):
         This can be the right place to perform tax lookups and apply them to
         the basket.
         """
-        basket = kwargs.get('basket', self.request.basket)
+        # Pop the basket if there is one, because we pass it as a positional
+        # argument to methods below
+        basket = kwargs.pop('basket', self.request.basket)
         shipping_address = self.get_shipping_address(basket)
         shipping_method = self.get_shipping_method(
             basket, shipping_address)


Test patch:
Repository: django-oscar/django-oscar

Issue:
order statistics status link loses date range
1. In /dashboard/orders/statistics/ apply a date filter.
   - the order statuses now count only orders within the given period
2. Click on one of the order statuses

_Actual_: A list with all orders with that status is shown.

_Expected_: A list with orders within the given period and with that status is shown.



Discussion:
This also require changes in the order list filters, since there's only shortcut query filter for order status.


Resolving patch:
diff --git a/src/oscar/apps/dashboard/orders/views.py b/src/oscar/apps/dashboard/orders/views.py
--- a/src/oscar/apps/dashboard/orders/views.py
+++ b/src/oscar/apps/dashboard/orders/views.py
@@ -145,18 +145,6 @@ def get_queryset(self):  # noqa (too complex (19))
         queryset = sort_queryset(self.base_queryset, self.request,
                                  ['number', 'total_incl_tax'])
 
-        # Look for shortcut query filters
-        if 'order_status' in self.request.GET:
-            self.form = self.form_class()
-            status = self.request.GET['order_status']
-            if status.lower() == 'none':
-                status = None
-            return self.base_queryset.filter(status=status)
-
-        if 'order_number' not in self.request.GET:
-            self.form = self.form_class()
-            return queryset
-
         self.form = self.form_class(self.request.GET)
         if not self.form.is_valid():
             return queryset


Test patch:
Repository: django-oscar/django-oscar

Issue:
google analytics uses legacy tracking methods
Should probably switch analytics over to Universal Analytics.

`templates/google_analytics.html` and `templates/partials/google_analytics_transaction.html`

Resources:
- https://support.google.com/analytics/answer/2790010?hl=en
- https://developers.google.com/analytics/devguides/collection/analyticsjs/ecommerce



Discussion:

Resolving patch:
diff --git a/src/oscar/core/context_processors.py b/src/oscar/core/context_processors.py
--- a/src/oscar/core/context_processors.py
+++ b/src/oscar/core/context_processors.py
@@ -20,12 +20,12 @@ def metadata(request):
     """
     Add some generally useful metadata to the template context
     """
-    return {'display_version': getattr(settings, 'DISPLAY_VERSION', False),
-            'version': getattr(settings, 'VERSION', 'N/A'),
-            'shop_name': settings.OSCAR_SHOP_NAME,
+    return {'shop_name': settings.OSCAR_SHOP_NAME,
             'shop_tagline': settings.OSCAR_SHOP_TAGLINE,
             'homepage_url': settings.OSCAR_HOMEPAGE,
-            'use_less': getattr(settings, 'USE_LESS', False),
             'language_neutral_url_path': strip_language_code(request),
-            'google_analytics_id': getattr(settings,
-                                           'GOOGLE_ANALYTICS_ID', None)}
+            # Fallback to old settings name for backwards compatibility
+            'use_less': getattr(settings, 'OSCAR_USE_LESS', None) or
+                        getattr(settings, 'USE_LESS', False),
+            'google_analytics_id': getattr(settings, 'OSCAR_GOOGLE_ANALYTICS_ID', None) or
+                                   getattr(settings, 'GOOGLE_ANALYTICS_ID', None)}


Test patch:
Repository: django-oscar/django-oscar

Issue:
Use the mailgun templates for our notification emails
See http://blog.mailgun.com/transactional-html-email-templates/

We can use these to provide a good base template for our HTML emails.



Discussion:
Oops, closed the wrong issue from https://github.com/tangentlabs/django-oscar/commit/48761ed2ba0b607aab0d255bc39c0a2a3f36f232


Resolving patch:
diff --git a/src/oscar/apps/customer/utils.py b/src/oscar/apps/customer/utils.py
--- a/src/oscar/apps/customer/utils.py
+++ b/src/oscar/apps/customer/utils.py
@@ -10,6 +10,7 @@
 from oscar.core.compat import user_is_authenticated
 from oscar.core.loading import get_model
 
+
 CommunicationEvent = get_model('order', 'CommunicationEvent')
 Email = get_model('customer', 'Email')
 


Test patch:
Repository: django-oscar/django-oscar

Issue:
Decide if reviews should exist without products
There's an [unresolved discussion](https://groups.google.com/forum/#!msg/django-oscar/1gur_QmbgzY/W2_MOW906cMJ) about whether reviews should be deleted when the product is deleted. This issue has been added to track it.

If it is decided that reviews can live on their own, it should be ensured that the dashboard handles that case okay. The related issue #836 has been fixed now.



Discussion:
I wote to delete the attached reviews when deleting a product. 
Maybe notify the user that x reviews will be deleted as well...
What is the purpose of keeping the review if we're not selling the product?

If a merchant dont want to delete products and its reviews, he should add something like "deactivate_product" to the Product model.

I also personally don't see reason why to keep reviews after product removal.

Resolving patch:
diff --git a/src/oscar/apps/catalogue/reviews/abstract_models.py b/src/oscar/apps/catalogue/reviews/abstract_models.py
--- a/src/oscar/apps/catalogue/reviews/abstract_models.py
+++ b/src/oscar/apps/catalogue/reviews/abstract_models.py
@@ -20,10 +20,9 @@ class AbstractProductReview(models.Model):
     Reviews can belong to a user or be anonymous.
     """
 
-    # Note we keep the review even if the product is deleted
     product = models.ForeignKey(
         'catalogue.Product', related_name='reviews', null=True,
-        on_delete=models.SET_NULL)
+        on_delete=models.CASCADE)
 
     # Scores are between 0 and 5
     SCORE_CHOICES = tuple([(x, x) for x in range(0, 6)])
diff --git a/src/oscar/apps/catalogue/reviews/migrations/0004_auto_20170429_0941.py b/src/oscar/apps/catalogue/reviews/migrations/0004_auto_20170429_0941.py
new file mode 100644
--- /dev/null
+++ b/src/oscar/apps/catalogue/reviews/migrations/0004_auto_20170429_0941.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11 on 2017-04-29 08:41
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('reviews', '0003_auto_20160802_1358'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='productreview',
+            name='product',
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='catalogue.Product'),
+        ),
+    ]


Test patch:
Repository: django-oscar/django-oscar

Issue:
ProductImage display_order is broken if images are simultaneously added and deleted from the dashboard
Using django oscar 1.1.1, I get the following error:
```
duplicate key value violates unique constraint "catalogue_productimage_product_id_1ade50c7ba4a8344_uniq"
DETAIL:  Key (product_id, display_order)=(4746, 2) already exists.
```

This happens when I try to upload an image to a product, on which I have previously deleted and uploaded an image at the same time (successfully).



Discussion:
I think the approach in #2287 of dropping the `unique_together` constraint will be the best way to fix this.

Resolving patch:
diff --git a/src/oscar/apps/catalogue/abstract_models.py b/src/oscar/apps/catalogue/abstract_models.py
--- a/src/oscar/apps/catalogue/abstract_models.py
+++ b/src/oscar/apps/catalogue/abstract_models.py
@@ -1166,7 +1166,6 @@ class Meta:
         # Any custom models should ensure that this ordering is unchanged, or
         # your query count will explode. See AbstractProduct.primary_image.
         ordering = ["display_order"]
-        unique_together = ("product", "display_order")
         verbose_name = _('Product image')
         verbose_name_plural = _('Product images')
 
diff --git a/src/oscar/apps/catalogue/migrations/0011_auto_20170422_1355.py b/src/oscar/apps/catalogue/migrations/0011_auto_20170422_1355.py
new file mode 100644
--- /dev/null
+++ b/src/oscar/apps/catalogue/migrations/0011_auto_20170422_1355.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.7 on 2017-04-22 12:55
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('catalogue', '0010_auto_20170420_0439'),
+    ]
+
+    operations = [
+        migrations.AlterUniqueTogether(
+            name='productimage',
+            unique_together=set([]),
+        ),
+    ]


Test patch:
Repository: django-oscar/django-oscar

Issue:
search_index strategy should not be instantiated outside of a class
The Strategy selector is instantiated outside of a class in the search_index.py.  This makes it difficult to use a custom strategy (with different arguments to the method) as we cannot override this functionality in the oscar base class



Discussion:
Hi Nathan, could you expand on that? I'm trying to understand what you're trying to do before I can figure out a good solution.

If you have a custom strategy, can't you make the parameters optional? 

I suppose the real problem is that one can't customise the ProductIndex class. Otherwise one could add a `get_strategy` method that can be overridden.


Resolving patch:
diff --git a/src/oscar/apps/search/search_indexes.py b/src/oscar/apps/search/search_indexes.py
--- a/src/oscar/apps/search/search_indexes.py
+++ b/src/oscar/apps/search/search_indexes.py
@@ -5,7 +5,6 @@
 # Load default strategy (without a user/request)
 is_solr_supported = get_class('search.features', 'is_solr_supported')
 Selector = get_class('partner.strategy', 'Selector')
-strategy = Selector().strategy()
 
 
 class ProductIndex(indexes.SearchIndex, indexes.Indexable):
@@ -31,6 +30,8 @@ class ProductIndex(indexes.SearchIndex, indexes.Indexable):
     date_created = indexes.DateTimeField(model_attr='date_created')
     date_updated = indexes.DateTimeField(model_attr='date_updated')
 
+    _strategy = None
+
     def get_model(self):
         return get_model('catalogue', 'Product')
 
@@ -57,7 +58,13 @@ def prepare_rating(self, obj):
     # most common case is for customers to see the same prices and stock levels
     # and so we implement that case here.
 
+    def get_strategy(self):
+        if not self._strategy:
+            self._strategy = Selector().strategy()
+        return self._strategy
+
     def prepare_price(self, obj):
+        strategy = self.get_strategy()
         result = None
         if obj.is_parent:
             result = strategy.fetch_for_parent(obj)
@@ -70,6 +77,7 @@ def prepare_price(self, obj):
             return result.price.excl_tax
 
     def prepare_num_in_stock(self, obj):
+        strategy = self.get_strategy()
         if obj.is_parent:
             # Don't return a stock level for parent products
             return None


Test patch: