Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mypy + Ruff #269

Merged
merged 13 commits into from
Mar 17, 2024
12 changes: 12 additions & 0 deletions .github/workflows/build-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Lint
run: |
pip install mypy ruff
make lint

- run: |
make preprocess
pipx run build --sdist

- uses: actions/upload-artifact@v3
with:
path: ./dist/*.tar.gz
Expand Down Expand Up @@ -57,6 +64,11 @@ jobs:
brew install make automake libtool
which pipx || brew install pipx && pipx ensurepath

- name: Lint
deedy5 marked this conversation as resolved.
Show resolved Hide resolved
run: |
pip install mypy ruff
make lint

- name: Build and test wheels
uses: pypa/[email protected]

Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ curl-*/
.preprocessed
include/
.DS_Store

.mypy_cache/
.ruff_cache/
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ build: .preprocessed
pip install build
python -m build --wheel

lint:
ruff check .
ruff format . --check --target-version py38
mypy .

format:
ruff format . --target-version py38
deedy5 marked this conversation as resolved.
Show resolved Hide resolved

test:
python -bb -m pytest tests/unittest

Expand Down
22 changes: 13 additions & 9 deletions benchmark/benchmark.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import asyncio
import queue
import threading
import time
import pandas as pd
import requests
from io import BytesIO

import aiohttp
import httpx
import pandas as pd
import pycurl
import requests
import tls_client
import httpx

import curl_cffi
import curl_cffi.requests
import queue
import threading
from io import BytesIO

# import uvloop
# uvloop.install()

results = []


class FakePycurlSession:
def __init__(self):
self.c = pycurl.Curl()
Expand Down Expand Up @@ -68,16 +71,17 @@ def __del__(self):
print("One worker, {}: ".format(size), stats)

df = pd.DataFrame(results)
df.to_csv("single_worker.csv", index=False, float_format='%.4f')
df.to_csv("single_worker.csv", index=False, float_format="%.4f")

results = []


def worker(q, done, SessionClass):
s = SessionClass()
while not done.is_set():
try:
url = q.get_nowait()
except:
except Exception:
continue
s.get(url)
q.task_done()
Expand Down Expand Up @@ -156,4 +160,4 @@ async def test_asyncs_workers():
print("10 Workers, {}: ".format(size), stats)

df = pd.DataFrame(results)
df.to_csv("multiple_workers.csv", index=False, float_format='%.4f')
df.to_csv("multiple_workers.csv", index=False, float_format="%.4f")
4 changes: 2 additions & 2 deletions benchmark/server.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import os

from starlette.applications import Starlette
from starlette.responses import Response, PlainTextResponse
from starlette.responses import PlainTextResponse
from starlette.routing import Route


random_1k = os.urandom(1 * 1024)
random_20k = os.urandom(20 * 1024)
random_200k = os.urandom(200 * 1024)
Expand Down
10 changes: 4 additions & 6 deletions curl_cffi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@
]

import _cffi_backend # noqa: F401 # required by _wrapper
# This line includes _wrapper.so into the wheel
from ._wrapper import ffi, lib # type: ignore

from .const import CurlInfo, CurlMOpt, CurlOpt, CurlECode, CurlHttpVersion, CurlWsFlag
from .curl import Curl, CurlError, CurlMime
# This line includes _wrapper.so into the wheel
from ._wrapper import ffi, lib
from .aio import AsyncCurl

from .__version__ import __title__, __version__, __description__, __curl_version__
deedy5 marked this conversation as resolved.
Show resolved Hide resolved
from .const import CurlECode, CurlHttpVersion, CurlInfo, CurlMOpt, CurlOpt, CurlWsFlag
from .curl import Curl, CurlError, CurlMime
2 changes: 1 addition & 1 deletion curl_cffi/__version__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from importlib import metadata
from .curl import Curl

from .curl import Curl

__title__ = "curl_cffi"
__description__ = metadata.metadata("curl_cffi")["Summary"]
Expand Down
57 changes: 31 additions & 26 deletions curl_cffi/_asyncio_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
running select in a thread and defining these methods on the running event loop.
This factors out the functionality of AddThreadSelectorEventLoop
into a standalone SelectorThread object which can be attached to any running event loop.
Vendored from tornado v6.1.0-64-g289c834b (PR #3029)
Vendored from tornado v6.4.0
Redistributed under license Apache-2.0
"""

import asyncio
import atexit
import errno
Expand All @@ -17,16 +18,17 @@
from typing import (
Any,
Callable,
Union,
Optional,
Dict,
List,
Optional,
Protocol,
Set,
Tuple,
Dict,
) # noqa: F401

from typing import Set # noqa: F401
TypeVar,
Union,
)

from typing import Protocol
_T = TypeVar("_T")


class _HasFileno(Protocol):
Expand All @@ -50,11 +52,12 @@ def _atexit_callback() -> None:
loop._waker_w.send(b"a")
except BlockingIOError:
pass
# If we don't join our (daemon) thread here, we may get a deadlock
# during interpreter shutdown. I don't really understand why. This
# deadlock happens every time in CI (both travis and appveyor) but
# I've never been able to reproduce locally.
loop._thread.join()
if loop._thread is not None:
# If we don't join our (daemon) thread here, we may get a deadlock
# during interpreter shutdown. I don't really understand why. This
# deadlock happens every time in CI (both travis and appveyor) but
# I've never been able to reproduce locally.
loop._thread.join()
_selector_loops.clear()


Expand All @@ -78,9 +81,9 @@ def __init__(self, real_loop: asyncio.AbstractEventLoop) -> None:
self._real_loop = real_loop

self._select_cond = threading.Condition()
self._select_args: Optional[
Tuple[List[_FileDescriptorLike], List[_FileDescriptorLike]]
] = None
self._select_args: Optional[Tuple[List[_FileDescriptorLike], List[_FileDescriptorLike]]] = (
None
)
self._closing_selector = False
self._thread: Optional[threading.Thread] = None
self._thread_manager_handle = self._thread_manager()
Expand All @@ -93,9 +96,7 @@ async def thread_manager_anext() -> None:
# When the loop starts, start the thread. Not too soon because we can't
# clean up if we get to this point but the event loop is closed without
# starting.
self._real_loop.call_soon(
lambda: self._real_loop.create_task(thread_manager_anext())
)
self._real_loop.call_soon(lambda: self._real_loop.create_task(thread_manager_anext()))

self._readers: Dict[_FileDescriptorLike, Callable] = {}
self._writers: Dict[_FileDescriptorLike, Callable] = {}
Expand Down Expand Up @@ -235,9 +236,7 @@ def _run_select(self) -> None:
# Swallow it too for consistency.
pass

def _handle_select(
self, rs: List[_FileDescriptorLike], ws: List[_FileDescriptorLike]
) -> None:
def _handle_select(self, rs: List[_FileDescriptorLike], ws: List[_FileDescriptorLike]) -> None:
for r in rs:
self._handle_event(r, self._readers)
for w in ws:
Expand Down Expand Up @@ -328,17 +327,23 @@ def close(self) -> None:
self._real_loop.close()

def add_reader(
self, fd: _FileDescriptorLike, callback: Callable[..., None], *args: Any
self,
fd: "_FileDescriptorLike",
callback: Callable[..., None],
*args: Any, # type: ignore
) -> None:
return self._selector.add_reader(fd, callback, *args)

def add_writer(
self, fd: _FileDescriptorLike, callback: Callable[..., None], *args: Any
self,
fd: "_FileDescriptorLike",
callback: Callable[..., None],
*args: Any, # type: ignore
) -> None:
return self._selector.add_writer(fd, callback, *args)

def remove_reader(self, fd: _FileDescriptorLike) -> bool:
def remove_reader(self, fd: "_FileDescriptorLike") -> bool:
return self._selector.remove_reader(fd)

def remove_writer(self, fd: _FileDescriptorLike) -> bool:
def remove_writer(self, fd: "_FileDescriptorLike") -> bool:
return self._selector.remove_writer(fd)
Loading
Loading