Skip to content

Commit

Permalink
feat: added analyze_sponsors.py script
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikBjare committed Jun 8, 2023
1 parent b9c9324 commit fd3f931
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
__pycache__
*.png
output
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
output/sponsors.html: output/sponsors.md
markdown2 $< -x tables > $@

output/sponsors.md: analyze_sponsors.py
python3 analyze_sponsors.py > $@
184 changes: 184 additions & 0 deletions analyze_sponsors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
"""
Analyze sponsor data to generate a sponsors table on the website
"""

from dataclasses import dataclass, field
from datetime import datetime, timedelta, timezone
from typing import Optional

import pandas as pd

Amount = float
Currency = str


@dataclass
class Sponsor:
name: str
github_username: Optional[str] = None
donated: list[tuple[Amount, Currency, datetime]] = field(default_factory=list)
source: str = "unknown"

def __repr__(self):
return f"<Sponsor {self.name} ({self.github_username}) on {self.source} total_donated={self.total_donated}>"

@property
def total_donated(self):
# group donated by currency, aggregate by sum
currencies = set([currency for _, currency, _ in self.donated])
total_donated = {}
for currency in currencies:
total_donated[currency] = sum(
[amount for amount, c, _ in self.donated if c == currency]
)
return total_donated


def load_github_sponsors_csv(filename: str) -> list[Sponsor]:
"""The CSV looks like the following:
Sponsor Handle,Sponsor Profile Name,Sponsor Public Email,Sponsorship Started On,Is Public?,Is Yearly?,Transaction ID,Tier Name,Tier Monthly Amount,Processed Amount,Is Prorated?,Status,Transaction Date,Metadata,Country,Region,VAT
snehal-shekatkar,Snehal Shekatkar,,2023-05-07 21:45:50 +0200,true,false,ch_3N5DWnEQsq43iHhX1Svht2g7,$5 a month,$5.00,$4.52,true,settled,2023-05-07 21:46:01 +0200,"",AUT,undefined,
justyn,Justyn Butler,,2023-02-15 12:14:28 +0100,true,false,ch_3NExsXEQsq43iHhX0Fmfcg6w,$3 a month,$3.00,$3.00,false,settled,2023-06-03 19:04:45 +0200,"",GBR,Kent,
justyn,Justyn Butler,,2023-02-15 12:14:28 +0100,true,false,ch_3N3ikOEQsq43iHhX1eMXefVn,$3 a month,$3.00,$3.00,false,settled,2023-05-03 18:41:56 +0200,"",GBR,Kent,
"""

df = pd.read_csv(
filename, parse_dates=["Sponsorship Started On", "Transaction Date"]
)
df = df[df["Is Public?"] == True] # noqa: E712
df = df[df["Status"] == "settled"]

sponsors = []
handles = df["Sponsor Handle"].unique()
for handle in handles:
sponsor = Sponsor(
name="placeholder",
github_username=handle,
donated=[],
source="github",
)
for _, row in df.iterrows():
if row["Sponsor Handle"] != handle:
continue
sponsor.name = row["Sponsor Profile Name"]
sponsor.donated.append(
(
float(row["Processed Amount"].replace("$", "")),
"USD",
row["Transaction Date"],
)
)

sponsors.append(sponsor)

return sponsors


def load_opencollective_csv(filename: str) -> list[Sponsor]:
"""The CSV looks like this:
"datetime","shortId","shortGroup","description","type","kind","isRefund","isRefunded","shortRefundId","displayAmount","amount","paymentProcessorFee","netAmount","balance","currency","accountSlug","accountName","oppositeAccountSlug","oppositeAccountName","paymentMethodService","paymentMethodType","expenseType","expenseTags","payoutMethodType","merchantId","orderMemo"
"2023-06-06T05:47:17","d3f98b95","f2238225","Contribution from Martin","CREDIT","CONTRIBUTION","","","","$50.00 USD",50,-2.5,47.5,3059.14,"USD","activitywatch","ActivityWatch","guest-cf5e5bf5","Martin","STRIPE","CREDITCARD",,"",,,
"2023-06-06T05:47:17","e3c0d1f9","f2238225","Host Fee to Open Source Collective","DEBIT","HOST_FEE","","","","-$5.00 USD",-5,0,-5,3011.64,"USD","activitywatch","ActivityWatch","opensource","Open Source Collective",,,,"",,,
"2023-06-01T04:03:23","80120e4e","9a189bcd","Yearly contribution from Olli Nevalainen","CREDIT","CONTRIBUTION","","","","$24.00 USD",24,-1.24,22.76,3016.64,"USD","activitywatch","ActivityWatch","olli-nevalainen","Olli Nevalainen","STRIPE","CREDITCARD",,"",,,
"""

df = pd.read_csv(filename, parse_dates=["datetime"])
df = df[df["type"] == "CREDIT"]

sponsors = []
handles = df["oppositeAccountSlug"].unique()
for handle in handles:
sponsor = Sponsor(
name="placeholder",
github_username=handle,
donated=[],
source="opencollective",
)
for _, row in df.iterrows():
if row["oppositeAccountSlug"] != handle:
continue
sponsor.name = row["oppositeAccountName"]
sponsor.donated.append(
(
row["amount"],
row["currency"],
row["datetime"].replace(tzinfo=timezone.utc),
)
)

sponsors.append(sponsor)

# remove 'GitHub Sponsors' from sponsors
sponsors = [sponsor for sponsor in sponsors if sponsor.name != "GitHub Sponsors"]

# subtract $3002 from Kerkko (actually FUUG.fi)
for sponsor in sponsors:
if sponsor.name == "Kerkko Pelttari":
sponsor.donated.append((-3002, "USD", datetime.now(tz=timezone.utc)))

return sponsors


def load_patreon_csv(filename: str) -> list[Sponsor]:
"""The CSV looks like:
Name,Email,Twitter,Discord,Patron Status,Follows You,Lifetime Amount,Pledge Amount,Charge Frequency,Tier,Addressee,Street,City,State,Zip,Country,Phone,Patronage Since Date,Last Charge Date,Last Charge Status,Additional Details,User ID,Last Updated,Currency,Max Posts,Access Expiration,Next Charge Date
Karan singh,[email protected],,kraft#9466,Declined patron,No,0.00,1.00,monthly,Time Tracker,,,,,,,,2023-04-08 17:45:28.731953,2023-05-31 07:46:37,Declined,,76783024,2023-05-31 08:01:37.517184,USD,,,2023-05-01 07:00:00
Dan Thompson,[email protected],,,Declined patron,No,0.00,1.00,monthly,Time Tracker,,,,,,,,2023-02-28 20:00:03.756241,2023-03-15 12:03:01,Declined,,46598895,2023-03-15 12:18:01.633900,USD,,,2023-03-01 08:00:00
"""

df = pd.read_csv(filename, parse_dates=["Patronage Since Date", "Last Charge Date"])

sponsors = []
for _, row in df.iterrows():
sponsor = Sponsor(
name=row["Name"],
github_username=None,
donated=[
(
row["Lifetime Amount"],
row["Currency"],
row["Last Charge Date"].replace(tzinfo=timezone.utc),
)
],
source="patreon",
)
sponsors.append(sponsor)

return sponsors


if __name__ == "__main__":
now = datetime.now(tz=timezone.utc)

sponsors = load_github_sponsors_csv(
"data/sponsors/ActivityWatch-sponsorships-all-time.csv"
)
sponsors += load_opencollective_csv(
"data/sponsors/opencollective-activitywatch-transactions.csv"
)
sponsors += load_patreon_csv("data/sponsors/patreon-members-866337.csv")
sponsors = sorted(sponsors, key=lambda s: s.total_donated["USD"], reverse=True)

# filter out sponsors who have donated less than $10
sponsors = [sponsor for sponsor in sponsors if sponsor.total_donated["USD"] >= 10]

# print as markdown table
print("| Name | Active? | Total Donated |")
print("| ---- |:-------:| -------------:|")
for sponsor in sponsors:
link = (
f"([@{sponsor.github_username}](https://github.com/{sponsor.github_username}))"
if sponsor.github_username
else ""
)
# active if last donation was less than 3 months ago
last_donation: datetime = max(timestamp for _, _, timestamp in sponsor.donated)
is_active = (
last_donation > now - timedelta(days=90) if sponsor.donated else False
)
print(
f"| {sponsor.name} {link} | {'✔️' if is_active else ''} | {sponsor.total_donated['USD']:.2f} USD |"
)
Empty file added output/.empty
Empty file.

0 comments on commit fd3f931

Please sign in to comment.