30 Jun 2024 |
| Wild rose changed their display name from war to Wild rose. | 21:43:10 |
10 Jul 2024 |
| Jonathan Chun joined the room. | 18:23:40 |
Jonathan Chun | any way to get in contact with the aiohttp.org maintainer(s)? i picked up aiohttp.com for $5. I'm assuming it was off the maintainer who let it drop but willing to donate it back if they want it. | 20:48:40 |
@webknjaz πΊπ¦ #StandWithUkraine | https://stand-with-ukraine.pp.ua | #russiaIsANaziState | In reply to @jonchun:matrix.org any way to get in contact with the aiohttp.org maintainer(s)? i picked up aiohttp.com for $5. I'm assuming it was off the maintainer who let it drop but willing to donate it back if they want it. I don't think we ever used that domain | 21:18:05 |
@webknjaz πΊπ¦ #StandWithUkraine | https://stand-with-ukraine.pp.ua | #russiaIsANaziState | In reply to @jonchun:matrix.org any way to get in contact with the aiohttp.org maintainer(s)? i picked up aiohttp.com for $5. I'm assuming it was off the maintainer who let it drop but willing to donate it back if they want it. @sam:sambull.org do we want to have such a backup? | 21:19:27 |
11 Jul 2024 |
Sam Bull | I already reserved aiohttp.dev and aiohttp.net as a backup. I can take aiohttp.com, and just set them to redirect, then we can figure out what to do next year. With no way to contact Andrew, it looks like there is no way to take over aiohttp.org other than letting it expire and rebuying like this (the registrar will let me renew on his account, but not gain any access to the settings or transfer). | 13:40:56 |
@webknjaz πΊπ¦ #StandWithUkraine | https://stand-with-ukraine.pp.ua | #russiaIsANaziState | In reply to @sam:sambull.org I already reserved aiohttp.dev and aiohttp.net as a backup. I can take aiohttp.com, and just set them to redirect, then we can figure out what to do next year. With no way to contact Andrew, it looks like there is no way to take over aiohttp.org other than letting it expire and rebuying like this (the registrar will let me renew on his account, but not gain any access to the settings or transfer). Fair | 16:52:52 |
12 Jul 2024 |
Jonathan Chun | Sam Bull: if you have a namecheap account I'm happy to push the .com to you. it's already renewed for the next year so it should cost nothing. | 01:45:42 |
Jonathan Chun | also definitely don't let the domain expire if you can avoid it because chances are some bot/domain squatter will pick it up since it's a domain with a decent amount of traffic/backlinks. | 01:51:49 |
Sam Bull | Yeah, but I can't change the DNS without rebuying it. Maybe we'll need to transition to a new domain over time, and then we can let it expire... | 13:43:15 |
Sam Bull | Namecheap username is Dreamsorcerer (same as my Github user). | 13:43:33 |
Jonathan Chun | Download image.png | 14:09:45 |
Jonathan Chun | In reply to @sam:sambull.org Namecheap username is Dreamsorcerer (same as my Github user). cool - sent. I think you just need to accept it now | 14:10:13 |
Sam Bull | Received, thanks. | 14:13:26 |
Jonathan Chun | have you tried reaching out to cloudflare as well? if the registrar doesn't allow you to do anything but extend the registration perhaps cloudflare may have a more lenient process for open source projects and you can at least change the DNS records | 14:15:28 |
Sam Bull | The root domain appears to just point to Github, which is the one I'm more interested in updating. | 15:14:57 |
Jonathan Chun | In reply to @sam:sambull.org The root domain appears to just point to Github, which is the one I'm more interested in updating. ~ dig aiohttp.org ns +short
dale.ns.cloudflare.com.
beth.ns.cloudflare.com.
| 15:20:36 |
Jonathan Chun | the NS are already pointed at Cloudflare though -- so potentially if they are willing to work with you, you can at least take over the records to update where it points and come up with a transition plan by setting up 301's even without the registrar's help | 15:21:22 |
Sam Bull | Ah yes, I didn't check that. Will send them a message. | 15:37:43 |
@webknjaz πΊπ¦ #StandWithUkraine | https://stand-with-ukraine.pp.ua | #russiaIsANaziState | In reply to @jonchun:matrix.org also definitely don't let the domain expire if you can avoid it because chances are some bot/domain squatter will pick it up since it's a domain with a decent amount of traffic/backlinks. Yep, that's how we lost cherrypy.org a few years ago and had to replace it with a .dev | 21:29:32 |
@webknjaz πΊπ¦ #StandWithUkraine | https://stand-with-ukraine.pp.ua | #russiaIsANaziState | In reply to @sam:sambull.org Ah yes, I didn't check that. Will send them a message. No need, I have access to DNS. | 21:30:14 |
@webknjaz πΊπ¦ #StandWithUkraine | https://stand-with-ukraine.pp.ua | #russiaIsANaziState | In reply to @webknjaz:matrix.org No need, I have access to DNS. For both aio-libs and aiohttp. | 21:30:39 |
21 Jul 2024 |
| Denis Otkidach joined the room. | 10:02:38 |
24 Jul 2024 |
Sam Bull | I've been working on a new library at work for schema generation with Pydantic validation of user input (the existing libraries didn't really do what we wanted). I'm looking for some feedback on the API before I finish it off and create a release. The goal is to be explicit and fully typed.
The example I've worked with is:
<details>
<summary>Example code</summary>
<code>
from datetime import datetime
from typing import Annotated, Literal
from aiohttp import web from aiohttp_apischema import APIResponse, SchemaGenerator from pydantic import Field
from typing_extensions import TypedDict
class Choice(TypedDict): """An answer to a poll."""
choice: str
votes: int
class Poll(TypedDict): """A question to be voted on."""
id: int
question: str
pub_date: str
class NewPoll(TypedDict): """Details to create a new poll."""
question: str
choices: Annotated[tuple[str, ...], Field(min_length=2)]
POLL1: Poll = {"id": 1, "question": "What's new?", "pub_date": datetime(2015, 12, 15, 17, 17, 49).isoformat()} CHOICES1: tuple[Choice, ...] = ({"choice": "Not much", "votes": 0}, {"choice": "The sky", "votes": 5}, {"choice": "Just hacking again", "votes": 2})
SCHEMA = SchemaGenerator()
POLLS = {1: POLL1} CHOICES = {1: list(CHOICES1)}
@SCHEMA.api() async def list_polls(request: web.Request) -> APIResponse[tuple[Poll, ...], Literal[200]]: """List available polls.
Return a list of objects containing details about each poll.
"""
return APIResponse((POLL1,))
@SCHEMA.api() async def add_choice(request: web.Request, message: str) -> APIResponse[int, Literal[201]] | APIResponse[None, Literal[404]]: """Edit a choice.
Return the ID of the new choice.
"""
poll_id = int(request.match_info["id"])
choices = CHOICES.get(poll_id)
if choices:
choices.append({"choice": message, "votes": 0})
return APIResponse[int, Literal[201]](len(choices) - 1, status=201)
return APIResponse[None, Literal[404]](None, status=404)
@SCHEMA.api_view() class PollView(web.View): """Endpoints for individual polls."""
async def get(self) -> APIResponse[Poll, Literal[200]] | APIResponse[None, Literal[404]]:
"""Fetch a poll by ID."""
poll_id = int(self.request.match_info["id"])
poll = POLLS.get(poll_id)
if poll:
return APIResponse(poll)
return APIResponse[None, Literal[404]](None, status=404)
async def put(self, body: NewPoll) -> APIResponse[int, Literal[200]]:
"""Set value for poll.
Return ID for newly created poll.
"""
poll_id = max(POLLS.keys()) + 1
POLLS[poll_id] = {"id": poll_id, "question": body["question"], "pub_date": datetime.now().isoformat()}
CHOICES[poll_id] = [{"choice": c, "votes": 0} for c in body["choices"]]
return APIResponse(poll_id)
def init_app() -> web.Application: app = web.Application() app.router.add_get("/polls", list_polls) app.router.add_view("/poll/{id:\d+}", PollView) app.router.add_put("/poll/{id:\d+}/choice", add_choice)
SCHEMA.setup(app)
return app
if name == "main": web.run_app(init_app()) </code>
</details>
Docstrings are pulled out for the API documentation. APIResponse will likely be expanded to also include headers and parameters.
| 16:44:08 |
Sam Bull | * I've been working on a new library at work for schema generation with Pydantic validation of user input (the existing libraries didn't really do what we wanted). I'm looking for some feedback on the API before I finish it off and create a release. The goal is to be explicit and fully typed.
The example I've worked with is:
from datetime import datetime
from typing import Annotated, Literal
from aiohttp import web
from aiohttp_apischema import APIResponse, SchemaGenerator
from pydantic import Field
from typing_extensions import TypedDict
class Choice(TypedDict):
"""An answer to a poll."""
choice: str
votes: int
class Poll(TypedDict):
"""A question to be voted on."""
id: int
question: str
pub_date: str
class NewPoll(TypedDict):
"""Details to create a new poll."""
question: str
choices: Annotated[tuple[str, ...], Field(min_length=2)]
POLL1: Poll = {"id": 1, "question": "What's new?", "pub_date": datetime(2015, 12, 15, 17, 17, 49).isoformat()}
CHOICES1: tuple[Choice, ...] = ({"choice": "Not much", "votes": 0},
{"choice": "The sky", "votes": 5},
{"choice": "Just hacking again", "votes": 2})
SCHEMA = SchemaGenerator()
POLLS = {1: POLL1}
CHOICES = {1: list(CHOICES1)}
@SCHEMA.api()
async def list_polls(request: web.Request) -> APIResponse[tuple[Poll, ...], Literal[200]]:
"""List available polls.
Return a list of objects containing details about each poll.
"""
return APIResponse((POLL1,))
@SCHEMA.api()
async def add_choice(request: web.Request, message: str) -> APIResponse[int, Literal[201]] | APIResponse[None, Literal[404]]:
"""Edit a choice.
Return the ID of the new choice.
"""
poll_id = int(request.match_info["id"])
choices = CHOICES.get(poll_id)
if choices:
choices.append({"choice": message, "votes": 0})
return APIResponse[int, Literal[201]](len(choices) - 1, status=201)
return APIResponse[None, Literal[404]](None, status=404)
@SCHEMA.api_view()
class PollView(web.View):
"""Endpoints for individual polls."""
async def get(self) -> APIResponse[Poll, Literal[200]] | APIResponse[None, Literal[404]]:
"""Fetch a poll by ID."""
poll_id = int(self.request.match_info["id"])
poll = POLLS.get(poll_id)
if poll:
return APIResponse(poll)
return APIResponse[None, Literal[404]](None, status=404)
async def put(self, body: NewPoll) -> APIResponse[int, Literal[200]]:
"""Set value for poll.
Return ID for newly created poll.
"""
poll_id = max(POLLS.keys()) + 1
POLLS[poll_id] = {"id": poll_id, "question": body["question"], "pub_date": datetime.now().isoformat()}
CHOICES[poll_id] = [{"choice": c, "votes": 0} for c in body["choices"]]
return APIResponse(poll_id)
def init_app() -> web.Application:
app = web.Application()
app.router.add_get("/polls", list_polls)
app.router.add_view("/poll/{id:\d+}", PollView)
app.router.add_put("/poll/{id:\d+}/choice", add_choice)
SCHEMA.setup(app)
return app
if __name__ == "__main__":
web.run_app(init_app())
Docstrings are pulled out for the API documentation. APIResponse will likely be expanded to also include headers and parameters.
| 16:45:02 |
Sam Bull | * I've been working on a new library at work for schema generation with Pydantic validation of user input (the existing libraries didn't really do what we wanted). I'm looking for some feedback on the API before I finish it off and create a release. The goal is to be explicit and fully typed.
The example I've worked with is:
from datetime import datetime
from typing import Annotated, Literal, TypedDict
from aiohttp import web
from aiohttp_apischema import APIResponse, SchemaGenerator
from pydantic import Field
class Choice(TypedDict):
"""An answer to a poll."""
choice: str
votes: int
class Poll(TypedDict):
"""A question to be voted on."""
id: int
question: str
pub_date: str
class NewPoll(TypedDict):
"""Details to create a new poll."""
question: str
choices: Annotated[tuple[str, ...], Field(min_length=2)]
POLL1: Poll = {"id": 1, "question": "What's new?", "pub_date": datetime(2015, 12, 15, 17, 17, 49).isoformat()}
CHOICES1: tuple[Choice, ...] = ({"choice": "Not much", "votes": 0},
{"choice": "The sky", "votes": 5},
{"choice": "Just hacking again", "votes": 2})
SCHEMA = SchemaGenerator()
POLLS = {1: POLL1}
CHOICES = {1: list(CHOICES1)}
@SCHEMA.api()
async def list_polls(request: web.Request) -> APIResponse[tuple[Poll, ...], Literal[200]]:
"""List available polls.
Return a list of objects containing details about each poll.
"""
return APIResponse(tuple(POLLS.values()))
@SCHEMA.api()
async def add_choice(request: web.Request, message: str) -> APIResponse[int, Literal[201]] | APIResponse[None, Literal[404]]:
"""Edit a choice.
Return the ID of the new choice.
"""
poll_id = int(request.match_info["id"])
choices = CHOICES.get(poll_id)
if choices:
choices.append({"choice": message, "votes": 0})
return APIResponse[int, Literal[201]](len(choices) - 1, status=201)
return APIResponse[None, Literal[404]](None, status=404)
@SCHEMA.api_view()
class PollView(web.View):
"""Endpoints for individual polls."""
async def get(self) -> APIResponse[Poll, Literal[200]] | APIResponse[None, Literal[404]]:
"""Fetch a poll by ID."""
poll_id = int(self.request.match_info["id"])
poll = POLLS.get(poll_id)
if poll:
return APIResponse(poll)
return APIResponse[None, Literal[404]](None, status=404)
async def put(self, body: NewPoll) -> APIResponse[int, Literal[200]]:
"""Set value for poll.
Return ID for newly created poll.
"""
poll_id = max(POLLS.keys()) + 1
POLLS[poll_id] = {"id": poll_id, "question": body["question"], "pub_date": datetime.now().isoformat()}
CHOICES[poll_id] = [{"choice": c, "votes": 0} for c in body["choices"]]
return APIResponse(poll_id)
def init_app() -> web.Application:
app = web.Application()
app.router.add_get("/polls", list_polls)
app.router.add_view("/poll/{id:\d+}", PollView)
app.router.add_put("/poll/{id:\d+}/choice", add_choice)
SCHEMA.setup(app)
return app
if __name__ == "__main__":
web.run_app(init_app())
Docstrings are pulled out for the API documentation. APIResponse will likely be expanded to also include headers and parameters.
| 16:45:46 |
Sam Bull | * I've been working on a new library at work for schema generation with Pydantic validation of user input (the existing libraries didn't really do what we wanted). I'm looking for some feedback on the API before I finish it off and create a release. The goal is to be explicit and fully typed.
The example I've worked with is:
from datetime import datetime
from typing import Annotated, Literal, TypedDict
from aiohttp import web
from aiohttp_apischema import APIResponse, SchemaGenerator
from pydantic import Field
class Choice(TypedDict):
"""An answer to a poll."""
choice: str
votes: int
class Poll(TypedDict):
"""A question to be voted on."""
id: int
question: str
pub_date: str
class NewPoll(TypedDict):
"""Details to create a new poll."""
question: str
choices: Annotated[tuple[str, ...], Field(min_length=2)]
POLL1: Poll = {"id": 1, "question": "What's new?", "pub_date": datetime(2015, 12, 15, 17, 17, 49).isoformat()}
CHOICES1: tuple[Choice, ...] = ({"choice": "Not much", "votes": 0},
{"choice": "The sky", "votes": 5},
{"choice": "Just hacking again", "votes": 2})
SCHEMA = SchemaGenerator()
POLLS = {1: POLL1}
CHOICES = {1: list(CHOICES1)}
@SCHEMA.api()
async def list_polls(request: web.Request) -> APIResponse[tuple[Poll, ...], Literal[200]]:
"""List available polls.
Return a list of objects containing details about each poll.
"""
return APIResponse(tuple(POLLS.values()))
@SCHEMA.api()
async def add_choice(request: web.Request, message: str) -> APIResponse[int, Literal[201]] | APIResponse[None, Literal[404]]:
"""Edit a choice.
Return the ID of the new choice.
"""
poll_id = int(request.match_info["id"])
choices = CHOICES.get(poll_id)
if choices:
choices.append({"choice": message, "votes": 0})
return APIResponse[int, Literal[201]](len(choices) - 1, status=201)
# If mypy issue is fixed, then these would become `APIResponse(None, status=404)`.
return APIResponse[None, Literal[404]](None, status=404)
@SCHEMA.api_view()
class PollView(web.View):
"""Endpoints for individual polls."""
async def get(self) -> APIResponse[Poll, Literal[200]] | APIResponse[None, Literal[404]]:
"""Fetch a poll by ID."""
poll_id = int(self.request.match_info["id"])
poll = POLLS.get(poll_id)
if poll:
return APIResponse(poll)
return APIResponse[None, Literal[404]](None, status=404)
async def put(self, body: NewPoll) -> APIResponse[int, Literal[200]]:
"""Set value for poll.
Return ID for newly created poll.
"""
poll_id = max(POLLS.keys()) + 1
POLLS[poll_id] = {"id": poll_id, "question": body["question"], "pub_date": datetime.now().isoformat()}
CHOICES[poll_id] = [{"choice": c, "votes": 0} for c in body["choices"]]
return APIResponse(poll_id)
def init_app() -> web.Application:
app = web.Application()
app.router.add_get("/polls", list_polls)
app.router.add_view("/poll/{id:\d+}", PollView)
app.router.add_put("/poll/{id:\d+}/choice", add_choice)
SCHEMA.setup(app)
return app
if __name__ == "__main__":
web.run_app(init_app())
Docstrings are pulled out for the API documentation. APIResponse will likely be expanded to also include headers and parameters.
| 16:46:32 |
Sam Bull | * I've been working on a new library at work for schema generation with Pydantic validation of user input (the existing libraries didn't really do what we wanted). I'm looking for some feedback on the API before I finish it off and create a release. The goal is to be explicit and fully typed.
The example I've worked with is:
from datetime import datetime
from typing import Annotated, Literal, TypedDict
from aiohttp import web
from aiohttp_apischema import APIResponse, SchemaGenerator
from pydantic import Field
class Choice(TypedDict):
"""An answer to a poll."""
choice: str
votes: int
class Poll(TypedDict):
"""A question to be voted on."""
id: int
question: str
pub_date: str
class NewPoll(TypedDict):
"""Details to create a new poll."""
question: str
choices: Annotated[tuple[str, ...], Field(min_length=2)]
POLL1: Poll = {"id": 1, "question": "What's new?", "pub_date": datetime(2015, 12, 15, 17, 17, 49).isoformat()}
CHOICES1: tuple[Choice, ...] = ({"choice": "Not much", "votes": 0},
{"choice": "The sky", "votes": 5},
{"choice": "Just hacking again", "votes": 2})
SCHEMA = SchemaGenerator()
POLLS = {1: POLL1}
CHOICES = {1: list(CHOICES1)}
@SCHEMA.api()
async def list_polls(request: web.Request) -> APIResponse[tuple[Poll, ...], Literal[200]]:
"""List available polls.
Return a list of objects containing details about each poll.
"""
return APIResponse(tuple(POLLS.values()))
@SCHEMA.api()
async def add_choice(request: web.Request, message: str) -> APIResponse[int, Literal[201]] | APIResponse[None, Literal[404]]:
"""Edit a choice.
Return the ID of the new choice.
"""
poll_id = int(request.match_info["id"])
choices = CHOICES.get(poll_id)
if choices:
choices.append({"choice": message, "votes": 0})
return APIResponse[int, Literal[201]](len(choices) - 1, status=201)
# If mypy issue is fixed, then these would become `APIResponse(None, status=404)`.
# https://github.com/python/mypy/issues/17572
return APIResponse[None, Literal[404]](None, status=404)
@SCHEMA.api_view()
class PollView(web.View):
"""Endpoints for individual polls."""
async def get(self) -> APIResponse[Poll, Literal[200]] | APIResponse[None, Literal[404]]:
"""Fetch a poll by ID."""
poll_id = int(self.request.match_info["id"])
poll = POLLS.get(poll_id)
if poll:
return APIResponse(poll)
return APIResponse[None, Literal[404]](None, status=404)
async def put(self, body: NewPoll) -> APIResponse[int, Literal[200]]:
"""Set value for poll.
Return ID for newly created poll.
"""
poll_id = max(POLLS.keys()) + 1
POLLS[poll_id] = {"id": poll_id, "question": body["question"], "pub_date": datetime.now().isoformat()}
CHOICES[poll_id] = [{"choice": c, "votes": 0} for c in body["choices"]]
return APIResponse(poll_id)
def init_app() -> web.Application:
app = web.Application()
app.router.add_get("/polls", list_polls)
app.router.add_view("/poll/{id:\d+}", PollView)
app.router.add_put("/poll/{id:\d+}/choice", add_choice)
SCHEMA.setup(app)
return app
if __name__ == "__main__":
web.run_app(init_app())
Docstrings are pulled out for the API documentation. APIResponse will likely be expanded to also include headers and parameters.
| 16:49:33 |
Sam Bull | * I've been working on a new library at work for schema generation with Pydantic validation of user input (the existing libraries didn't really do what we wanted). I'm looking for some feedback on the API before I finish it off and create a release. The goal is to be explicit and fully typed.
The example I've worked with is:
from datetime import datetime
from typing import Annotated, Literal, TypedDict
from aiohttp import web
from aiohttp_api import APIResponse, SchemaGenerator
from pydantic import Field
class Choice(TypedDict):
"""An answer to a poll."""
choice: str
votes: int
class Poll(TypedDict):
"""A question to be voted on."""
id: int
question: str
pub_date: str
class NewPoll(TypedDict):
"""Details to create a new poll."""
question: str
choices: Annotated[tuple[str, ...], Field(min_length=2)]
POLL1: Poll = {"id": 1, "question": "What's new?", "pub_date": datetime(2015, 12, 15, 17, 17, 49).isoformat()}
CHOICES1: tuple[Choice, ...] = ({"choice": "Not much", "votes": 0},
{"choice": "The sky", "votes": 5},
{"choice": "Just hacking again", "votes": 2})
SCHEMA = SchemaGenerator()
POLLS = {1: POLL1}
CHOICES = {1: list(CHOICES1)}
@SCHEMA.api()
async def list_polls(request: web.Request) -> APIResponse[tuple[Poll, ...], Literal[200]]:
"""List available polls.
Return a list of objects containing details about each poll.
"""
return APIResponse(tuple(POLLS.values()))
@SCHEMA.api()
async def add_choice(request: web.Request, message: str) -> APIResponse[int, Literal[201]] | APIResponse[None, Literal[404]]:
"""Edit a choice.
Return the ID of the new choice.
"""
poll_id = int(request.match_info["id"])
choices = CHOICES.get(poll_id)
if choices:
choices.append({"choice": message, "votes": 0})
return APIResponse[int, Literal[201]](len(choices) - 1, status=201)
# If mypy issue is fixed, then these would become `APIResponse(None, status=404)`.
# https://github.com/python/mypy/issues/17572
return APIResponse[None, Literal[404]](None, status=404)
@SCHEMA.api_view()
class PollView(web.View):
"""Endpoints for individual polls."""
async def get(self) -> APIResponse[Poll, Literal[200]] | APIResponse[None, Literal[404]]:
"""Fetch a poll by ID."""
poll_id = int(self.request.match_info["id"])
poll = POLLS.get(poll_id)
if poll:
return APIResponse(poll)
return APIResponse[None, Literal[404]](None, status=404)
async def put(self, body: NewPoll) -> APIResponse[int, Literal[200]]:
"""Set value for poll.
Return ID for newly created poll.
"""
poll_id = max(POLLS.keys()) + 1
POLLS[poll_id] = {"id": poll_id, "question": body["question"], "pub_date": datetime.now().isoformat()}
CHOICES[poll_id] = [{"choice": c, "votes": 0} for c in body["choices"]]
return APIResponse(poll_id)
def init_app() -> web.Application:
app = web.Application()
app.router.add_get("/polls", list_polls)
app.router.add_view("/poll/{id:\d+}", PollView)
app.router.add_put("/poll/{id:\d+}/choice", add_choice)
SCHEMA.setup(app)
return app
if __name__ == "__main__":
web.run_app(init_app())
Docstrings are pulled out for the API documentation. APIResponse will likely be expanded to also include headers and parameters.
| 17:00:29 |
26 Jul 2024 |
| Chris218 left the room. | 22:03:59 |