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

Issue:
Support the use of SunPyBaseCoordinateFrame outside of core library
### Describe the feature

* It would be useful to be able to use `SunPyBaseCoordinateFrame` outside of sunpy but currently doing so is alkward as the `frame_to_wcs` and `wcs_to_frame` mappings are hardcode to the current frames / wcs' and raise an error you you try to do so
* The name clearly implies this is SunPy specific but there a lot of boiler plate code that would have to be copied to provide the same thing.

At the moment to make this work you have to make sure what ever frames are added are added before the sunpy function e.g.

`astropy.wcs.utils.FRAME_WCS_MAPPINGS.insert(1, [my_wcs_to_frame])`

### Proposed solution

Don't raise an error the if the frame is a subclass of `SunPyBaseCoordinateFrame` but not one of the frame implemented in sunpy return `None` 

Specifically L198 raise an error as xcoord and xcoord are undefined
https://github.com/sunpy/sunpy/blob/2281a2198997e8671efd48dcb531b07a98b86ddf/sunpy/coordinates/wcs_utils.py#L173-L198

A simple solution would be to an a final else clause to this if Elias
```python
        elif isinstance(frame, HeliographicStonyhurst):
            xcoord = 'HGLN' + '-' + projection
            ycoord = 'HGLT' + '-' + projection
            wcs.wcs.cunit = ['deg', 'deg']
        else
            return None

```


Discussion:

Resolving patch:
diff --git a/sunpy/coordinates/wcs_utils.py b/sunpy/coordinates/wcs_utils.py
--- a/sunpy/coordinates/wcs_utils.py
+++ b/sunpy/coordinates/wcs_utils.py
@@ -191,6 +191,9 @@ def solar_frame_to_wcs_mapping(frame, projection='TAN'):
             xcoord = 'HGLN' + '-' + projection
             ycoord = 'HGLT' + '-' + projection
             wcs.wcs.cunit = ['deg', 'deg']
+        else:
+            # A subclass not supported by the core library
+            return None
 
     else:
         return None


Test patch:
diff --git a/sunpy/coordinates/tests/test_wcs_utils.py b/sunpy/coordinates/tests/test_wcs_utils.py
--- a/sunpy/coordinates/tests/test_wcs_utils.py
+++ b/sunpy/coordinates/tests/test_wcs_utils.py
@@ -15,6 +15,7 @@
     HeliographicCarrington,
     HeliographicStonyhurst,
     Helioprojective,
+    SunPyBaseCoordinateFrame,
 )
 from sunpy.coordinates.wcs_utils import (
     _set_wcs_aux_obs_coord,
@@ -379,3 +380,11 @@ def test_observer_hgln_crln_priority():
     # Note: don't test whether crlt or hglt is used---according to
     # _set_wcs_aux_obs_coord, those are expected to always be the same and so
     # the same one is always used
+
+
+def test_sunpybaseframe_external():
+    class MyFrame(SunPyBaseCoordinateFrame):
+        pass
+
+    out = solar_frame_to_wcs_mapping(MyFrame())
+    assert out is None
Repository: liberapay/liberapay.com

Issue:
Switch Jinja templates to line statements
Because they're easier to type (especially on an azerty keyboard): `% if ...` instead of `{% if ... %}`. [Documentation](http://jinja.pocoo.org/docs/dev/templates/#line-statements).

Any objections?



Discussion:

Resolving patch:
diff --git a/liberapay/constants.py b/liberapay/constants.py
--- a/liberapay/constants.py
+++ b/liberapay/constants.py
@@ -17,6 +17,11 @@
 EMAIL_VERIFICATION_TIMEOUT = timedelta(hours=24)
 EMAIL_RE = re.compile(r'^[^@]+@[^@]+\.[^@]+$')
 
+JINJA_ENV_COMMON = dict(
+    trim_blocks=True, lstrip_blocks=True,
+    line_statement_prefix='%', line_comment_prefix='#',
+)
+
 MAX_TIP = Decimal('100.00')
 MIN_TIP = Decimal('0.01')
 
diff --git a/liberapay/renderers/jinja2_htmlescaped.py b/liberapay/renderers/jinja2_htmlescaped.py
--- a/liberapay/renderers/jinja2_htmlescaped.py
+++ b/liberapay/renderers/jinja2_htmlescaped.py
@@ -2,6 +2,8 @@
 
 from markupsafe import escape as htmlescape
 
+from liberapay.constants import JINJA_ENV_COMMON
+
 
 class HTMLRenderer(base.Renderer):
     def render_content(self, context):
@@ -22,7 +24,8 @@ class Factory(base.Factory):
     def compile_meta(self, configuration):
         # Override to turn on autoescaping.
         loader = base.FileSystemLoader(configuration.project_root)
-        return base.Environment( loader=loader
-                               , autoescape=True
-                               , extensions=['jinja2.ext.autoescape']
-                                )
+        return base.Environment(
+            loader=loader,
+            autoescape=True, extensions=['jinja2.ext.autoescape'],
+            **JINJA_ENV_COMMON
+        )
diff --git a/liberapay/utils/emails.py b/liberapay/utils/emails.py
--- a/liberapay/utils/emails.py
+++ b/liberapay/utils/emails.py
@@ -4,6 +4,8 @@
 from aspen_jinja2_renderer import SimplateLoader
 from jinja2 import Environment
 
+from liberapay.constants import JINJA_ENV_COMMON
+
 
 ( VERIFICATION_MISSING
 , VERIFICATION_FAILED
@@ -14,10 +16,10 @@
  ) = range(6)
 
 
-jinja_env = Environment(trim_blocks=True, lstrip_blocks=True)
+jinja_env = Environment(**JINJA_ENV_COMMON)
 jinja_env_html = Environment(
-    trim_blocks=True, lstrip_blocks=True,
     autoescape=True, extensions=['jinja2.ext.autoescape'],
+    **JINJA_ENV_COMMON
 )
 
 def compile_email_spt(fpath):


Test patch:
Repository: liberapay/liberapay.com

Issue:
Change the default avatar image
@Zatalyz pointed out in IRC yesterday that we're still using Gratipay's logo, I'm so used to it I hadn't even noticed. :D

Change the default avatar image
@Zatalyz pointed out in IRC yesterday that we're still using Gratipay's logo, I'm so used to it I hadn't even noticed. :D



Discussion:

Resolving patch:
diff --git a/liberapay/constants.py b/liberapay/constants.py
--- a/liberapay/constants.py
+++ b/liberapay/constants.py
@@ -14,6 +14,7 @@
                                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                 "-_")
 
+AVATAR_QUERY = '?s=160&default=retro'
 
 BIRTHDAY = date(2015, 5, 22)
 
diff --git a/liberapay/models/account_elsewhere.py b/liberapay/models/account_elsewhere.py
--- a/liberapay/models/account_elsewhere.py
+++ b/liberapay/models/account_elsewhere.py
@@ -14,6 +14,7 @@
 import xmltodict
 
 import liberapay
+from liberapay.constants import AVATAR_QUERY
 from liberapay.security.crypto import constant_time_compare
 
 
@@ -103,7 +104,7 @@ def upsert(cls, i):
             fragment = ''
             if netloc.endswith('githubusercontent.com') or \
                netloc.endswith('gravatar.com'):
-                query = 's=160'
+                query = AVATAR_QUERY
             i.avatar_url = urlunsplit((scheme, netloc, path, query, fragment))
 
         # Serialize extra_info
diff --git a/liberapay/models/participant.py b/liberapay/models/participant.py
--- a/liberapay/models/participant.py
+++ b/liberapay/models/participant.py
@@ -21,7 +21,8 @@
 import liberapay
 from liberapay.billing import mangoapi
 from liberapay.constants import (
-    ASCII_ALLOWED_IN_USERNAME, EMAIL_RE, EMAIL_VERIFICATION_TIMEOUT, MAX_TIP,
+    ASCII_ALLOWED_IN_USERNAME, AVATAR_QUERY, EMAIL_RE,
+    EMAIL_VERIFICATION_TIMEOUT, MAX_TIP,
     MIN_TIP, PASSWORD_MAX_SIZE, PASSWORD_MIN_SIZE, SESSION, SESSION_REFRESH,
     SESSION_TIMEOUT, USERNAME_MAX_SIZE
 )
@@ -572,6 +573,7 @@ def add_email(self, email, cursor=None):
         else:
             gravatar_id = md5(email.strip().lower()).hexdigest()
             gravatar_url = 'https://secure.gravatar.com/avatar/'+gravatar_id
+            gravatar_url += AVATAR_QUERY
             (cursor or self.db).run("""
                 UPDATE participants
                    SET avatar_url = %s


Test patch:
Repository: liberapay/liberapay.com

Issue:
Fix connecting a GitHub org
I tried connecting the GitHub liberapay org to the [LiberapayOrg](https://liberapay.com/LiberapayOrg/) account but I ended up on the take-over confirmation page asking me to transfer my personal account.



Discussion:

Resolving patch:
diff --git a/liberapay/elsewhere/github.py b/liberapay/elsewhere/github.py
--- a/liberapay/elsewhere/github.py
+++ b/liberapay/elsewhere/github.py
@@ -39,8 +39,7 @@ class GitHub(PlatformOAuth2):
     x_avatar_url = key('avatar_url')
     x_is_team = key('type', clean=lambda t: t.lower() == 'organization')
 
-    def is_team_admin(self, team_name, sess):
-        user_teams = self.api_parser(self.api_get('/user/teams', sess=sess))
-        return any(team.get('organization', {}).get('login') == team_name and
-                   team.get('permission') == 'admin'
-                   for team in user_teams)
+    def is_team_member(self, org_name, sess):
+        org_name = org_name.lower()
+        user_orgs = self.api_parser(self.api_get('/user/orgs', sess=sess))
+        return any(org.get('login') == org_name for org in user_orgs)


Test patch:
diff --git a/tests/py/test_elsewhere.py b/tests/py/test_elsewhere.py
--- a/tests/py/test_elsewhere.py
+++ b/tests/py/test_elsewhere.py
@@ -82,7 +82,7 @@ def test_redirect_csrf(self):
         assert response.code == 405
 
     def test_redirects(self):
-        data = dict(action='connect', then='/', user_id='')
+        data = dict(action='lock', then='/', user_id='')
         for platform in self.platforms:
             platform.get_auth_url = lambda *a, **kw: ('', '', '')
             response = self.client.PxST('/on/%s/redirect' % platform.name, data)
Repository: liberapay/liberapay.com

Issue:
Twitter API chokes on at-sign
https://liberapay.com/on/twitter/@korben/ returns a 500. sentry#35, public link: https://sentry.changaco.oy.lc/share/issue/322e3335/.



Discussion:

Resolving patch:
diff --git a/liberapay/models/account_elsewhere.py b/liberapay/models/account_elsewhere.py
--- a/liberapay/models/account_elsewhere.py
+++ b/liberapay/models/account_elsewhere.py
@@ -242,6 +242,8 @@ def get_account_elsewhere(website, state, api_lookup=True):
         uid = uid[1:]
     else:
         key = 'user_name'
+        if uid[:1] == '@':
+            uid = uid[1:]
     try:
         account = AccountElsewhere._from_thing(key, platform.name, uid)
     except UnknownAccountElsewhere:


Test patch:
diff --git a/tests/py/test_elsewhere.py b/tests/py/test_elsewhere.py
--- a/tests/py/test_elsewhere.py
+++ b/tests/py/test_elsewhere.py
@@ -116,6 +116,19 @@ def test_user_page_shows_pledges(self, get_user_info):
         r = self.client.GET('/on/github/alice/')
         assert str(amount) in r.body, r.body.decode('utf8')
 
+    @mock.patch('liberapay.elsewhere._base.Platform.get_user_info')
+    def test_user_page_doesnt_fail_on_at_sign(self, get_user_info):
+        def f(k, v, *a):
+            if (k, v) == ('user_name', 'alice'):
+                return UserInfo(
+                    platform='twitter', user_id='0', user_name='alice',
+                    is_team=False
+                )
+            raise Exception
+        get_user_info.side_effect = f
+        response = self.client.GET('/on/twitter/@alice/')
+        assert response.code == 200
+
     def test_user_pages_not_found(self):
         user_name = 'adhsjakdjsdkjsajdhksda'
         error = "There doesn't seem to be a user named %s on %s."
Repository: liberapay/liberapay.com

Issue:
Allow teams to connect elsewhere accounts and join communities



Discussion:

Resolving patch:
diff --git a/liberapay/models/participant.py b/liberapay/models/participant.py
--- a/liberapay/models/participant.py
+++ b/liberapay/models/participant.py
@@ -1644,6 +1644,12 @@ def path(self, path):
     def is_person(self):
         return self.kind in ('individual', 'organization')
 
+    def controls(self, other):
+        return isinstance(other, Participant) and (
+            self.id == other.id or
+            other.kind == 'group' and self.member_of(other)
+        )
+
 
 class NeedConfirmation(Exception):
     """Represent the case where we need user confirmation during a merge.


Test patch:
diff --git a/tests/py/test_elsewhere.py b/tests/py/test_elsewhere.py
--- a/tests/py/test_elsewhere.py
+++ b/tests/py/test_elsewhere.py
@@ -201,7 +201,7 @@ def test_take_over(self):
         response = self.client.PxST('/on/take-over.html', data=data, auth_as=self.bob,
                                     cookies=self.connect_cookie)
         assert response.code == 302
-        assert response.headers['Location'] == '/bob/'
+        assert response.headers['Location'] == '/bob/edit'
 
 
 class TestFriendFinder(Harness):
Repository: liberapay/liberapay.com

Issue:
LinuxFr issue
The link to my LinuxFr account is broken because of case.
https://liberapay.com/Moul/

LinuxFr issue
The link to my LinuxFr account is broken because of case.
https://liberapay.com/Moul/



Discussion:

Resolving patch:
diff --git a/liberapay/elsewhere/linuxfr.py b/liberapay/elsewhere/linuxfr.py
--- a/liberapay/elsewhere/linuxfr.py
+++ b/liberapay/elsewhere/linuxfr.py
@@ -9,7 +9,7 @@ class LinuxFr(PlatformOAuth2):
     # Platform attributes
     name = 'linuxfr'
     display_name = 'LinuxFr.org'
-    account_url = 'https://linuxfr.org/users/{user_name}'
+    account_url = 'https://linuxfr.org/users/{user_name_lower}'
 
     # Auth attributes
     # LinuxFr uses https://github.com/doorkeeper-gem/doorkeeper
diff --git a/liberapay/models/account_elsewhere.py b/liberapay/models/account_elsewhere.py
--- a/liberapay/models/account_elsewhere.py
+++ b/liberapay/models/account_elsewhere.py
@@ -200,6 +200,7 @@ def html_url(self):
         return self.platform_data.account_url.format(
             user_id=self.user_id,
             user_name=self.user_name,
+            user_name_lower=self.user_name.lower(),
             platform_data=self.platform_data
         )
 


Test patch:
Repository: liberapay/liberapay.com

Issue:
When you add a new OAuth account, avatar resets
I've been using GitHub as my avatar source. Since then I added OpenStreetMap, and I suddenly found a weird avatar and found it's forcibly reset to libavatar. It's usually expected that the user set an avatar and thinks it won't be reset unless user explicitly tells to do it, so it's more natural to leave it even when adding new OAuth account.



Discussion:
You're right, there's a bug in `update_avatar()` that leads to `avatar_src` being overridden.

+1 from @c-geek in #280.


Resolving patch:
diff --git a/liberapay/models/participant.py b/liberapay/models/participant.py
--- a/liberapay/models/participant.py
+++ b/liberapay/models/participant.py
@@ -1011,6 +1011,7 @@ def update_avatar(self, src=None, cursor=None):
         if self.status == 'stub':
             assert src is None
 
+        src = self.avatar_src if src is None else src
         platform, key = src.split(':', 1) if src else (None, None)
         email = self.avatar_email or self.email or self.get_any_email(cursor)
 


Test patch:
diff --git a/tests/py/test_participant.py b/tests/py/test_participant.py
--- a/tests/py/test_participant.py
+++ b/tests/py/test_participant.py
@@ -426,3 +426,26 @@ def test_rs_returns_openstreetmap_url_for_stub_from_openstreetmap(self):
     def test_suggested_payment_is_zero_for_new_user(self):
         alice = self.make_participant('alice')
         assert alice.suggested_payment == 0
+
+    # avatar
+
+    def test_update_avatar(self):
+        libravatar = 'https://seccdn.libravatar.org/avatar/45da67db8d78a92d35f0f5f194328b94?'
+        twitter_avatar = 'https://fake.twitter.com/path/to/avatar.jpg'
+        alice = self.make_participant('alice', email='alice@example.net')
+        alice.update_avatar()
+        assert alice.avatar_src is None
+        assert alice.avatar_url.startswith(libravatar)
+        # connect a twitter account, avatar shouldn't change
+        elsewhere = self.make_elsewhere('twitter', '1', 'alice', avatar_url=twitter_avatar)
+        alice.take_over(elsewhere)
+        assert alice.avatar_src is None
+        assert alice.avatar_url.startswith(libravatar)
+        # switch to twitter avatar
+        alice.update_avatar('twitter:')
+        assert alice.avatar_src == 'twitter:'
+        assert alice.avatar_url.startswith(twitter_avatar)
+        # check that a new call to update_avatar doesn't override avatar_src
+        alice.update_avatar()
+        assert alice.avatar_src == 'twitter:'
+        assert alice.avatar_url.startswith(twitter_avatar)
Repository: liberapay/liberapay.com

Issue:
Payday's log messages don't show the progress
From https://github.com/liberapay/salon/issues/64#issuecomment-240387083:

> Now that the HTTPS connection to MangoPay is reused we don't have any progress indicator left in payday logs, we should probably print one message for each transfer we do.

Payday's log messages don't show the progress
From https://github.com/liberapay/salon/issues/64#issuecomment-240387083:

> Now that the HTTPS connection to MangoPay is reused we don't have any progress indicator left in payday logs, we should probably print one message for each transfer we do.



Discussion:

Resolving patch:
diff --git a/liberapay/billing/payday.py b/liberapay/billing/payday.py
--- a/liberapay/billing/payday.py
+++ b/liberapay/billing/payday.py
@@ -411,7 +411,10 @@ def check_balances(cursor):
 
     def transfer_for_real(self, transfers):
         db = self.db
-        for t in transfers:
+        print("Starting transfers (n=%i)" % len(transfers))
+        msg = "Executing transfer #%i (amount=%s context=%s team=%s tipper_wallet_id=%s tippee_wallet_id=%s)"
+        for i, t in enumerate(transfers):
+            log(msg % (i, t.amount, t.context, t.team, t.tipper_wallet_id, t.tippee_wallet_id))
             transfer(db, **t.__dict__)
 
     def clean_up(self):


Test patch:
Repository: liberapay/liberapay.com

Issue:
Closing account sometimes fails when distributing balance to a team
Sentry: https://sentry.changaco.oy.lc/share/issue/322e313030/

The problem is that the `distribute_balance_as_final_gift` function doesn't skip empty transfers to team members, and the DB constraint on `transfers.amount` prevents empty transfers.

Previous issue: #425.


Discussion:

Resolving patch:
diff --git a/liberapay/models/participant.py b/liberapay/models/participant.py
--- a/liberapay/models/participant.py
+++ b/liberapay/models/participant.py
@@ -441,6 +441,8 @@ def distribute_balance_as_final_gift(self, cursor):
                         (nominal * ratio).quantize(D_CENT, rounding=ROUND_UP),
                         balance
                     )
+                    if actual == 0:
+                        continue
                     balance -= actual
                     transfers.append([take['member_id'], actual, team_id])
                 assert balance == 0


Test patch:
diff --git a/tests/py/test_close.py b/tests/py/test_close.py
--- a/tests/py/test_close.py
+++ b/tests/py/test_close.py
@@ -149,15 +149,18 @@ def test_dbafg_with_zero_balance_is_a_noop(self):
 
     def test_dbafg_distributes_to_team(self):
         team = self.make_participant('team', kind='group')
-        alice = self.make_participant('alice', balance=D('10.00'))
+        alice = self.make_participant('alice', balance=D('0.01'))
         bob = self.make_participant('bob')
+        carl = self.make_participant('carl')
         alice.set_tip_to(team, D('3.00'))
         team.set_take_for(alice, 1, team)
         team.set_take_for(bob, 1, team)
+        team.set_take_for(carl, D('0.01'), team)
         with self.db.get_cursor() as cursor:
             alice.distribute_balance_as_final_gift(cursor)
         assert alice.balance == 0
-        assert bob.refetch().balance == 10
+        assert bob.refetch().balance == D('0.01')
+        assert carl.refetch().balance == 0
 
 
     # ctg - clear_tips_giving
Repository: liberapay/liberapay.com

Issue:
Closed account & password
After closing your account your still can do a password reset, then with the mail's link you can go to the website, connected as the closed account.
You can do nothing (all account's pages as "The account as been closed") but you are connected.



Discussion:
Indeed, thanks for reporting the issue. :-)

I see two possible ways to fix this: disable password resets for closed accounts, or reopen the account when the user logs in via email.

I think the 2nd option is better, like this we can reopen accounts while keeping the same name :)


Resolving patch:
diff --git a/liberapay/security/authentication.py b/liberapay/security/authentication.py
--- a/liberapay/security/authentication.py
+++ b/liberapay/security/authentication.py
@@ -48,8 +48,6 @@ def sign_in_with_form_data(body, state):
             )
             if not p:
                 state['log-in.error'] = _("Bad username or password.")
-            if p and p.status == 'closed':
-                p.update_status('active')
         elif k == 'username':
             state['log-in.error'] = _("\"{0}\" is not a valid email address.", id)
             return
@@ -156,6 +154,8 @@ def authenticate_user_if_possible(request, response, state, user, _):
     if p:
         if session_p:
             session_p.sign_out(response.headers.cookie)
+        if p.status == 'closed':
+            p.update_status('active')
         p.sign_in(response.headers.cookie, session_suffix)
         state['user'] = p
         if request.body.pop('form.repost', None) != 'true':


Test patch:
diff --git a/tests/py/test_sign_in.py b/tests/py/test_sign_in.py
--- a/tests/py/test_sign_in.py
+++ b/tests/py/test_sign_in.py
@@ -130,6 +130,7 @@ def test_email_login(self):
         email = 'alice@example.net'
         alice = self.make_participant('alice')
         alice.add_email(email)
+        alice.close(None)
 
         data = {'log-in.id': email}
         r = self.client.POST('/', data, raise_immediately=False)
Repository: liberapay/liberapay.com

Issue:
Old notifications show current balance
En reprenant les notifications sur : https://liberapay.com/JulienLecaille/notifications

Ca fait des choses incohérentes (car le solde restant sur le compte est corrigé rétrospectivement sur les messages)

![bugliberapay](https://cloud.githubusercontent.com/assets/19620144/18448953/67bd551a-792d-11e6-9816-c2f6856a7f10.JPG)



Discussion:
Thanks for reporting the problem, I was already aware of it but apparently I didn't create an issue for it.

This is a low-priority bug, easy to fix.

It's time to fix this bug. I'll do it in the next few days if nobody else does it first.

Resolving patch:
diff --git a/liberapay/billing/payday.py b/liberapay/billing/payday.py
--- a/liberapay/billing/payday.py
+++ b/liberapay/billing/payday.py
@@ -587,11 +587,13 @@ def notify_participants(self):
                        for k, v in group_by(successes, 'team').items()}
             personal = by_team.pop(None, 0)
             by_team = {Participant.from_id(k).username: v for k, v in by_team.items()}
-            Participant.from_id(tippee_id).notify(
+            p = Participant.from_id(tippee_id)
+            p.notify(
                 'income',
                 total=sum(t['amount'] for t in successes),
                 personal=personal,
                 by_team=by_team,
+                new_balance=p.balance,
             )
 
         # Identity-required notifications
@@ -636,7 +638,7 @@ def notify_participants(self):
                    )
         """, (previous_ts_end, self.ts_end))
         for p in participants:
-            p.notify('low_balance')
+            p.notify('low_balance', low_balance=p.balance)
 
 
 def main(override_payday_checks=False):


Test patch: