Tive de trabalhar nessa semana com um caso que me exigiu usar o pycurl no Python.  O problema foi que escrevi um script que rodava baixando artefatos de build no Jenkins usando o módulo requests, e o mesmo não funcionava mais no Gitlab.

Depois de gastar um pouco de tempo no request, e usando o curl do exemplo do site do Gitlab, eu acabei desistindo e indo pra usar o pycurl no script.  De cara descobri que não tinha pycurl instalado.  E no MacOS não foi tão simples como poderia ter sido.  A receita de bolo pra instalar o pycurl foi a seguinte sequência:

helio@MacOS> arch -arm64 brew install openssl curl
helio@MacOS> export PATH=/opt/homebrew/opt/curl/bin:$PATH
helio@MacOS> export LDFLAGS="-L/opt/homebrew/opt/curl/lib":$LDFLAGS
helio@MacOS> export CPPFLAGS="-I/opt/homebrew/opt/curl/include":$CPPFLAGS
helio@MacOS> arch -arm64 pip install --no-cache-dir --compile --ignore-installed --install-option="--with-openssl" --install-option="--openssl-dir=/opt/homebrew/Cellar/openssl@3/3.0.7" pycurl 

Quando algo funciona em curl é fácil escrever o código em python.  Basta rodar com o parâmetro --libcurl foo.c que ele joga o código em funcionou dentro do arquivo.c no formato pra linguagem C, mas é bem próximo do uso em python.

   hnd = curl_easy_init();
  curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
  curl_easy_setopt(hnd, CURLOPT_URL, "https://gitlab.[redacted]/api/v4/projects/[redacted]/jobs/[redacted]/artifacts");
  curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
  curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, slist1);
  curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.86.0");
  curl_easy_setopt(hnd, CURLOPT_FOLLOWLOCATION, 1L);
  curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
  curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
  curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
  curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);

Em python:

             url = "https://gitlab.[redacted]/api/v4/projects/[redacted]/jobs/[redacted]/artifacts"
             buffer = BytesIO()
            c = pycurl.Curl()
            c.setopt(c.URL, url)
            c.setopt(c.BUFFERSIZE, 102400)
            c.setopt(c.NOPROGRESS, 1)
            if GITLAB_PRIVATE_TOKEN:
                c.setopt(c.HTTPHEADER, [ "PRIVATE-TOKEN:" + GITLAB_PRIVATE_TOKEN ])
            else:
                c.setopt(c.HTTPHEADER, [ USERNAME + ":" + PASSWORD])
            c.setopt(c.USERAGENT, "curl/7.84.0")
            c.setopt(c.FOLLOWLOCATION, 1)
            c.setopt(c.HTTP_VERSION, c.CURL_HTTP_VERSION_2TLS)
            c.setopt(c.TCP_KEEPALIVE, 1)
            c.setopt(c.WRITEDATA, buffer)
            c.perform()
            c.close()

E assim o código saiu funcionando.