A new ecore module: ecore_con
It's now super easy to perform various network task in a full efl fashion. Implemented "Lookup" for dns query and "Url" to perform http requests. "Server" will come soon. Comes with quite complete docs, examples and unit tests
This commit is contained in:
parent
f01ac0788e
commit
eaf3110089
1
CODING
1
CODING
|
@ -32,6 +32,7 @@ Documentation cheatsheet
|
|||
:func:`elm_list_go` (for functions)
|
||||
:attr:`homogeneous` (for properties)
|
||||
:ref:`Elm_List_Mode` (for enums)
|
||||
:data:`ELM_LIST_LIMIT` (for enum values)
|
||||
|
||||
:func:`efl.evas.Object.delete` (for items not in current scope)
|
||||
:func:`~efl.evas.Object.delete` (will show it short, just "delete")
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.. currentmodule:: efl.ecore_con
|
||||
|
||||
:class:`efl.ecore_con.Lookup` Class
|
||||
===================================
|
||||
|
||||
.. autoclass:: efl.ecore_con.Lookup
|
|
@ -0,0 +1,9 @@
|
|||
.. currentmodule:: efl.ecore_con
|
||||
|
||||
:class:`efl.ecore_con.Url` Class
|
||||
===================================
|
||||
|
||||
.. autoclass:: efl.ecore_con.Url
|
||||
.. autoclass:: efl.ecore_con.EventUrlComplete
|
||||
.. autoclass:: efl.ecore_con.EventUrlProgress
|
||||
.. autoclass:: efl.ecore_con.EventUrlData
|
|
@ -73,14 +73,6 @@ error. Any valid file descriptor can be used with this API, regardless of if
|
|||
was gotten with an OS specific API or from ecore.
|
||||
see :py:class:`FdHandler<efl.ecore.FdHandler>`
|
||||
|
||||
File download
|
||||
-------------
|
||||
|
||||
Ecore provide the :py:class:`FileDownload<efl.ecore.FileDownload>` class
|
||||
to perform asyncronous download of files from the net. Two callbacks are
|
||||
used to inform the user while progress occurs and when the download has
|
||||
finished.
|
||||
|
||||
|
||||
File monitor
|
||||
------------
|
||||
|
@ -91,6 +83,25 @@ Events will be generatd everytime a file or directory (that live in the
|
|||
give path) is created/deleted/modified.
|
||||
|
||||
|
||||
File download
|
||||
-------------
|
||||
|
||||
Ecore provide the :py:class:`FileDownload<efl.ecore.FileDownload>` class
|
||||
to perform asyncronous download of files from the net. Two callbacks are
|
||||
used to inform the user while progress occurs and when the download has
|
||||
finished.
|
||||
|
||||
|
||||
Ecore Con
|
||||
---------
|
||||
|
||||
The ecore_con module provide various utilities to perform different network
|
||||
related tasks. Everything provided in a fully async way. Most notable are the
|
||||
:class:`efl.ecore_con.Lookup` class to perform DNS requests, the
|
||||
:class:`efl.ecore_con.Url` class to perform HTTP requests and the
|
||||
:class:`efl.ecore_con.Server` class to implement your own server.
|
||||
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
@ -99,6 +110,7 @@ API Reference
|
|||
:titlesonly:
|
||||
|
||||
module-ecore
|
||||
module-ecore_con
|
||||
|
||||
|
||||
Inheritance diagram
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
.. automodule:: efl.ecore_con
|
||||
:exclude-members: Url, EventUrlComplete, EventUrlProgress, EventUrlData,
|
||||
Lookup, ConEventFilter
|
||||
|
|
@ -29,6 +29,11 @@ cdef object _event_mapping_register(int type, cls):
|
|||
cdef object _event_mapping_unregister(int type):
|
||||
_event_type_mapping.pop(type)
|
||||
|
||||
cdef object _event_mapping_get(int type):
|
||||
if not type in _event_type_mapping:
|
||||
raise ValueError("event type '%d' not registered." % type)
|
||||
return _event_type_mapping.get(type)
|
||||
|
||||
|
||||
cdef Eina_Bool event_handler_cb(void *data, int type, void *event) with gil:
|
||||
cdef EventHandler handler
|
||||
|
@ -65,6 +70,9 @@ cdef class Event(object):
|
|||
cdef int _set_obj(self, void *obj) except 0:
|
||||
raise NotImplementedError("Event._set_obj() not implemented.")
|
||||
|
||||
cdef object _get_obj(self):
|
||||
raise NotImplementedError("Event._get_obj() not implemented.")
|
||||
|
||||
|
||||
cdef class EventHandler(object):
|
||||
def __init__(self, int type, func, *args, **kargs):
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
# Copyright (C) 2007-2015 various contributors (see AUTHORS)
|
||||
#
|
||||
# This file is part of Python-EFL.
|
||||
#
|
||||
# Python-EFL is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# Python-EFL is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from efl.eina cimport *
|
||||
from efl.c_eo cimport Eo as cEo
|
||||
from efl.eo cimport Eo, object_from_instance
|
||||
from efl.ecore cimport Ecore_Event_Handler, Event
|
||||
from efl.utils.conversions cimport _ctouni, eina_list_strings_to_python_list
|
||||
|
||||
|
||||
|
||||
cdef extern from "Ecore_Con.h":
|
||||
|
||||
# where is this defined in real ?
|
||||
cdef struct sockaddr:
|
||||
pass
|
||||
|
||||
# defines
|
||||
int ECORE_CON_EVENT_URL_COMPLETE
|
||||
int ECORE_CON_EVENT_URL_PROGRESS
|
||||
int ECORE_CON_EVENT_URL_DATA
|
||||
|
||||
# typedefs
|
||||
ctypedef cEo Ecore_Con_Url
|
||||
|
||||
ctypedef struct Ecore_Con_Event_Url_Progress_SubParam:
|
||||
double total
|
||||
double now
|
||||
|
||||
ctypedef struct Ecore_Con_Event_Url_Progress:
|
||||
Ecore_Con_Url *url_con
|
||||
Ecore_Con_Event_Url_Progress_SubParam down
|
||||
Ecore_Con_Event_Url_Progress_SubParam up
|
||||
|
||||
ctypedef struct Ecore_Con_Event_Url_Data:
|
||||
Ecore_Con_Url *url_con
|
||||
int size
|
||||
unsigned char *data
|
||||
|
||||
ctypedef struct Ecore_Con_Event_Url_Complete:
|
||||
Ecore_Con_Url *url_con
|
||||
int status
|
||||
|
||||
ctypedef void (*Ecore_Con_Dns_Cb)(const char *canonname, const char *ip,
|
||||
sockaddr *addr, int addrlen, void *data)
|
||||
|
||||
# enums
|
||||
cpdef enum Ecore_Con_Type:
|
||||
ECORE_CON_LOCAL_USER
|
||||
ECORE_CON_LOCAL_SYSTEM
|
||||
ECORE_CON_LOCAL_ABSTRACT
|
||||
ECORE_CON_REMOTE_TCP
|
||||
ECORE_CON_REMOTE_MCAST
|
||||
ECORE_CON_REMOTE_UDP
|
||||
ECORE_CON_REMOTE_BROADCAST
|
||||
ECORE_CON_REMOTE_NODELAY
|
||||
ECORE_CON_REMOTE_CORK
|
||||
ECORE_CON_USE_SSL2
|
||||
ECORE_CON_USE_SSL3
|
||||
ECORE_CON_USE_TLS
|
||||
ECORE_CON_USE_MIXED
|
||||
ECORE_CON_LOAD_CERT
|
||||
ECORE_CON_NO_PROXY
|
||||
ECORE_CON_SOCKET_ACTIVATE
|
||||
ctypedef enum Ecore_Con_Type:
|
||||
pass
|
||||
|
||||
cpdef enum Ecore_Con_Url_Time:
|
||||
ECORE_CON_URL_TIME_NONE
|
||||
ECORE_CON_URL_TIME_IFMODSINCE
|
||||
ECORE_CON_URL_TIME_IFUNMODSINCE
|
||||
ctypedef enum Ecore_Con_Url_Time:
|
||||
pass
|
||||
|
||||
cpdef enum Ecore_Con_Url_Http_Version:
|
||||
ECORE_CON_URL_HTTP_VERSION_1_0
|
||||
ECORE_CON_URL_HTTP_VERSION_1_1
|
||||
ctypedef enum Ecore_Con_Url_Http_Version:
|
||||
pass
|
||||
|
||||
# functions
|
||||
int ecore_con_init()
|
||||
int ecore_con_shutdown()
|
||||
# Ecore_Con_Server *ecore_con_server_connect(Ecore_Con_Type type, const char *name, int port, const void *data)
|
||||
|
||||
int ecore_con_url_init()
|
||||
int ecore_con_url_shutdown()
|
||||
void ecore_con_url_pipeline_set(Eina_Bool enable)
|
||||
Eina_Bool ecore_con_url_pipeline_get()
|
||||
Eina_Bool ecore_con_lookup(const char *name, Ecore_Con_Dns_Cb done_cb, const void *data)
|
||||
|
||||
Ecore_Con_Url *ecore_con_url_new(const char *url)
|
||||
void ecore_con_url_free(Ecore_Con_Url *url_obj)
|
||||
Ecore_Con_Url * ecore_con_url_custom_new(const char *url, const char *custom_request)
|
||||
void ecore_con_url_verbose_set(Ecore_Con_Url *url_con, Eina_Bool verbose)
|
||||
Eina_Bool ecore_con_url_http_version_set(Ecore_Con_Url *url_con, Ecore_Con_Url_Http_Version version)
|
||||
void ecore_con_url_timeout_set(Ecore_Con_Url *url_con, double timeout)
|
||||
int ecore_con_url_status_code_get(Ecore_Con_Url *url_con)
|
||||
Eina_Bool ecore_con_url_get(Ecore_Con_Url *url_con)
|
||||
Eina_Bool ecore_con_url_head(Ecore_Con_Url *url_con)
|
||||
Eina_Bool ecore_con_url_post(Ecore_Con_Url *url_con, const void *data, long length, const char *content_type)
|
||||
Eina_Bool ecore_con_url_ftp_upload(Ecore_Con_Url *url_con, const char *filename, const char *user, const char *passwd, const char *upload_dir)
|
||||
void ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con, Eina_Bool use_epsv)
|
||||
|
||||
Eina_Bool ecore_con_url_url_set(Ecore_Con_Url *obj, const char *url)
|
||||
const char *ecore_con_url_url_get(const Ecore_Con_Url *obj)
|
||||
void ecore_con_url_fd_set(Ecore_Con_Url *url_con, int fd)
|
||||
|
||||
void ecore_con_url_additional_header_add(Ecore_Con_Url *url_con, const char *key, const char *value)
|
||||
void ecore_con_url_additional_headers_clear(Ecore_Con_Url *url_con)
|
||||
const Eina_List *ecore_con_url_response_headers_get(Ecore_Con_Url *url_con)
|
||||
int ecore_con_url_received_bytes_get(Ecore_Con_Url *url_con)
|
||||
Eina_Bool ecore_con_url_httpauth_set(Ecore_Con_Url *url_con, const char *username, const char *password, Eina_Bool safe)
|
||||
void ecore_con_url_time(Ecore_Con_Url *url_con, Ecore_Con_Url_Time time_condition, double timestamp)
|
||||
|
||||
void ecore_con_url_cookies_init(Ecore_Con_Url *url_con)
|
||||
void ecore_con_url_cookies_clear(Ecore_Con_Url *url_con)
|
||||
void ecore_con_url_cookies_session_clear(Ecore_Con_Url *url_con)
|
||||
void ecore_con_url_cookies_ignore_old_session_set(Ecore_Con_Url *url_con, Eina_Bool ignore)
|
||||
void ecore_con_url_cookies_file_add(Ecore_Con_Url *url_con, const char *file_name)
|
||||
Eina_Bool ecore_con_url_cookies_jar_file_set(Ecore_Con_Url *url_con, const char *cookiejar_file)
|
||||
void ecore_con_url_cookies_jar_write(Ecore_Con_Url *url_con)
|
||||
|
||||
void ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_con, Eina_Bool verify)
|
||||
int ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con, const char *ca_path)
|
||||
|
||||
Eina_Bool ecore_con_url_proxy_set(Ecore_Con_Url *url_con, const char *proxy)
|
||||
Eina_Bool ecore_con_url_proxy_username_set(Ecore_Con_Url *url_con, const char *username)
|
||||
Eina_Bool ecore_con_url_proxy_password_set(Ecore_Con_Url *url_con, const char *password)
|
||||
|
||||
|
||||
cdef class Url(Eo):
|
||||
pass
|
||||
|
||||
cdef class Lookup(object):
|
||||
cdef object done_cb
|
||||
cdef tuple args
|
||||
cdef dict kargs
|
||||
|
||||
cdef class EventUrlComplete(Event):
|
||||
cdef readonly Url url
|
||||
cdef readonly int status
|
||||
|
||||
|
||||
cdef class EventUrlProgress(Event):
|
||||
cdef readonly Url url
|
||||
cdef readonly double down_total
|
||||
cdef readonly double down_now
|
||||
cdef readonly double up_total
|
||||
cdef readonly double up_now
|
||||
|
||||
|
||||
cdef class EventUrlData(Event):
|
||||
cdef readonly Url url
|
||||
cdef readonly int size
|
||||
cdef readonly bytes data # TODO :/
|
||||
|
||||
|
||||
cdef class ConEventFilter(object):
|
||||
cdef dict callbacks
|
||||
cdef dict handlers
|
||||
cdef callback_add(self, int ev_type, Eo obj, object func, tuple args, dict kargs)
|
||||
cdef callback_del(self, int ev_type, Eo obj, object func, tuple args, dict kargs)
|
||||
cdef callback_del_full(self, Eo obj)
|
|
@ -0,0 +1,315 @@
|
|||
# Copyright (C) 2007-2015 various contributors (see AUTHORS)
|
||||
#
|
||||
# This file is part of Python-EFL.
|
||||
#
|
||||
# Python-EFL is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# Python-EFL is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
|
||||
:mod:`efl.ecore_con` Module
|
||||
###########################
|
||||
|
||||
The ecore_con module provide various utilities to perform different network
|
||||
related tasks. Everything in a full async ecore way. Most notable are the
|
||||
:class:`Lookup` class to perform DNS requests, the :class:`Url` class to
|
||||
perform HTTP requests and the :class:`Server` class to implement your own
|
||||
server.
|
||||
|
||||
Don't forget about the :class:`efl.ecore.FileDownload` class if what you need
|
||||
is just to fetch some data to file.
|
||||
|
||||
|
||||
Classes
|
||||
=======
|
||||
|
||||
.. toctree::
|
||||
|
||||
class-lookup.rst
|
||||
class-url.rst
|
||||
|
||||
|
||||
|
||||
Enumerations
|
||||
============
|
||||
|
||||
.. _Ecore_Con_Type:
|
||||
|
||||
Ecore Con Type
|
||||
--------------
|
||||
|
||||
Types for an ecore_con client/server object.
|
||||
|
||||
A correct way to set this type is with an ECORE_CON_$TYPE, optionally OR'ed
|
||||
with an ECORE_CON_$USE if encryption is desired, and LOAD_CERT if the
|
||||
previously loaded certificate should be used.
|
||||
|
||||
.. data:: ECORE_CON_LOCAL_USER
|
||||
|
||||
Socket in ~/.ecore.
|
||||
|
||||
.. data:: ECORE_CON_LOCAL_SYSTEM
|
||||
|
||||
Socket in /tmp.
|
||||
|
||||
.. data:: ECORE_CON_LOCAL_ABSTRACT
|
||||
|
||||
Abstract socket.
|
||||
|
||||
.. data:: ECORE_CON_REMOTE_TCP
|
||||
|
||||
Remote server using TCP.
|
||||
|
||||
|
||||
.. data:: ECORE_CON_REMOTE_MCAST
|
||||
|
||||
Remote multicast server.
|
||||
|
||||
|
||||
.. data:: ECORE_CON_REMOTE_UDP
|
||||
|
||||
Remote server using UDP.
|
||||
|
||||
.. data:: ECORE_CON_REMOTE_BROADCAST
|
||||
|
||||
Remote broadcast using UDP.
|
||||
|
||||
.. data:: ECORE_CON_REMOTE_NODELAY
|
||||
|
||||
Remote connection sending packets immediately.
|
||||
|
||||
.. data:: ECORE_CON_REMOTE_CORK
|
||||
|
||||
Remote connection sending data in large chunks. (only on linux)
|
||||
|
||||
.. data:: ECORE_CON_USE_SSL2
|
||||
|
||||
Use SSL2: UNSUPPORTED.
|
||||
|
||||
.. data:: ECORE_CON_USE_SSL3
|
||||
|
||||
Use SSL3: UNSUPPORTED.
|
||||
|
||||
.. data:: ECORE_CON_USE_TLS
|
||||
|
||||
Use TLS.
|
||||
|
||||
.. data:: ECORE_CON_USE_MIXED
|
||||
|
||||
Use both TLS and SSL3.
|
||||
|
||||
.. data:: ECORE_CON_LOAD_CERT
|
||||
|
||||
Attempt to use the loaded certificate.
|
||||
|
||||
.. data:: ECORE_CON_NO_PROXY
|
||||
|
||||
Disable all types of proxy on the server.
|
||||
|
||||
|
||||
.. _Ecore_Con_Url_Time:
|
||||
|
||||
Ecore Con Url Time
|
||||
------------------
|
||||
|
||||
The type of condition to use when making an HTTP request dependent on time, so
|
||||
that headers such as "If-Modified-Since" are used.
|
||||
|
||||
.. data:: ECORE_CON_URL_TIME_NONE
|
||||
|
||||
Do not place time restrictions on the HTTP requests.
|
||||
|
||||
.. data:: ECORE_CON_URL_TIME_IFMODSINCE
|
||||
|
||||
Add the "If-Modified-Since" HTTP header, so that the request is performed by
|
||||
the server only if the target has been modified since the time value passed
|
||||
to it in the request.
|
||||
|
||||
.. data:: ECORE_CON_URL_TIME_IFUNMODSINCE
|
||||
|
||||
Add the "If-Unmodified-Since" HTTP header, so that the request is performed
|
||||
by the server only if the target has NOT been modified since the time value
|
||||
passed to it in the request.
|
||||
|
||||
|
||||
.. _Ecore_Con_Url_Http_Version:
|
||||
|
||||
Ecore Con Url Http Version
|
||||
--------------------------
|
||||
|
||||
The http version to use.
|
||||
|
||||
.. data:: ECORE_CON_URL_HTTP_VERSION_1_0
|
||||
|
||||
HTTP version 1.0.
|
||||
|
||||
.. data:: ECORE_CON_URL_HTTP_VERSION_1_1
|
||||
|
||||
HTTP version 1.1 (default)
|
||||
|
||||
|
||||
Module level functions
|
||||
======================
|
||||
|
||||
"""
|
||||
|
||||
from libc.stdint cimport uintptr_t
|
||||
from cpython cimport PyUnicode_AsUTF8String, Py_INCREF, Py_DECREF
|
||||
|
||||
import traceback
|
||||
import atexit
|
||||
|
||||
|
||||
from efl.ecore cimport _event_mapping_register, _event_mapping_get, \
|
||||
ecore_event_handler_add, ecore_event_handler_del
|
||||
|
||||
|
||||
cdef int _con_events_registered = 0
|
||||
|
||||
|
||||
def init():
|
||||
"""Initialize the Ecore Con library
|
||||
|
||||
.. note::
|
||||
You never need to call this function, it is automatically called when
|
||||
the module is imported.
|
||||
|
||||
.. versionadded:: 1.17
|
||||
|
||||
"""
|
||||
|
||||
ecore_con_init()
|
||||
ecore_con_url_init()
|
||||
|
||||
global _con_events_registered
|
||||
if _con_events_registered == 0:
|
||||
_event_mapping_register(ECORE_CON_EVENT_URL_COMPLETE, EventUrlComplete)
|
||||
_event_mapping_register(ECORE_CON_EVENT_URL_PROGRESS, EventUrlProgress)
|
||||
_event_mapping_register(ECORE_CON_EVENT_URL_DATA, EventUrlData)
|
||||
_con_events_registered = 1
|
||||
|
||||
|
||||
def shutdown():
|
||||
"""Shuts down the Ecore Con library.
|
||||
|
||||
.. note::
|
||||
You never need to call this function, it is automatically called atexit.
|
||||
|
||||
.. versionadded:: 1.17
|
||||
|
||||
"""
|
||||
ecore_con_url_shutdown()
|
||||
ecore_con_shutdown()
|
||||
|
||||
|
||||
cdef Eina_Bool _con_event_filter_cb(void *data, int ev_type, void *ev) with gil:
|
||||
cdef:
|
||||
ConEventFilter filter = <ConEventFilter>data
|
||||
object event_cls
|
||||
Event py_event
|
||||
list cbs
|
||||
Eo obj
|
||||
object func
|
||||
tuple args
|
||||
dict kargs
|
||||
|
||||
# create correct "EventAbc" python object, using the global mapping
|
||||
event_cls = _event_mapping_get(ev_type)
|
||||
if event_cls:
|
||||
py_event = event_cls()
|
||||
py_event._set_obj(ev)
|
||||
|
||||
# do we have callbacks for this object/event ?
|
||||
try:
|
||||
obj = py_event._get_obj()
|
||||
cbs = filter.callbacks.get(ev_type).get(obj)
|
||||
except:
|
||||
cbs = None
|
||||
|
||||
if cbs:
|
||||
cbs = cbs[:] # copy, so we can change filter.callbacks
|
||||
for func, args, kargs in cbs:
|
||||
try:
|
||||
func(py_event, *args, **kargs)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
||||
return 1 # always return true, no matter what
|
||||
|
||||
cdef class ConEventFilter(object):
|
||||
|
||||
"""
|
||||
self.callbacks = {
|
||||
EV_TYPE: {
|
||||
objX: [(cb,args,kargs), ... ]
|
||||
objY: [(cb,args,kargs), ... ]
|
||||
},
|
||||
...
|
||||
}
|
||||
"""
|
||||
|
||||
def __cinit__(self):
|
||||
self.callbacks = {}
|
||||
self.handlers = {}
|
||||
|
||||
cdef callback_add(self, int ev_type, Eo obj, object func, tuple args, dict kargs):
|
||||
# store the function in the callbacks dict
|
||||
if not ev_type in self.callbacks:
|
||||
self.callbacks[ev_type] = {}
|
||||
if not obj in self.callbacks[ev_type]:
|
||||
self.callbacks[ev_type][obj] = []
|
||||
self.callbacks[ev_type][obj].append((func,args,kargs))
|
||||
|
||||
# connect a single ecore signal, one per event_type
|
||||
cdef Ecore_Event_Handler* ee
|
||||
if not ev_type in self.handlers:
|
||||
ee = ecore_event_handler_add(ev_type, _con_event_filter_cb,
|
||||
<void *>self)
|
||||
self.handlers[ev_type] = <uintptr_t><void *>ee
|
||||
|
||||
cdef callback_del(self, int ev_type, Eo obj, object func, tuple args, dict kargs):
|
||||
try:
|
||||
self.callbacks[ev_type][obj].remove((func, args, kargs))
|
||||
except ValueError:
|
||||
raise ValueError(
|
||||
"callback is not registered: %s, args=%s, kargs=%s" %
|
||||
(func, args, kargs))
|
||||
|
||||
# can delete the ecore handler?
|
||||
if self.callbacks.get(ev_type) and self.callbacks.get(ev_type).get(obj):
|
||||
return
|
||||
if ev_type in self.handlers:
|
||||
handler = self.handlers.pop(ev_type)
|
||||
ecore_event_handler_del(<Ecore_Event_Handler *><uintptr_t>handler)
|
||||
|
||||
cdef callback_del_full(self, Eo obj):
|
||||
for ev_type in self.callbacks:
|
||||
if obj in self.callbacks[ev_type]:
|
||||
# remove all the cbs for the obj
|
||||
self.callbacks[ev_type].pop(obj, None)
|
||||
|
||||
# can delete the ecore handler?
|
||||
if len(self.callbacks[ev_type]) < 1 and ev_type in self.handlers:
|
||||
handler = self.handlers.pop(ev_type)
|
||||
ecore_event_handler_del(<Ecore_Event_Handler *><uintptr_t>handler)
|
||||
|
||||
# name suggestions are welcome for this unusual "singleton" instance
|
||||
cdef ConEventFilter GEF = ConEventFilter()
|
||||
|
||||
|
||||
include "efl.ecore_con_lookup.pxi"
|
||||
include "efl.ecore_con_url.pxi"
|
||||
|
||||
|
||||
init()
|
||||
atexit.register(shutdown)
|
|
@ -0,0 +1,88 @@
|
|||
# Copyright (C) 2007-2015 various contributors (see AUTHORS)
|
||||
#
|
||||
# This file is part of Python-EFL.
|
||||
#
|
||||
# Python-EFL is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# Python-EFL is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
cdef void _con_dns_lookup_cb(const char *canonname, const char *ip, sockaddr *sockaddr, int addrlen, void *data) with gil:
|
||||
cdef Lookup self = <Lookup>data
|
||||
|
||||
try:
|
||||
# TODO read sockaddr and replace the placeholder None with something
|
||||
# more usefull from the sockaddr struct.
|
||||
self.done_cb(_ctouni(canonname), _ctouni(ip), None, *self.args, **self.kargs)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
|
||||
Py_DECREF(self)
|
||||
|
||||
|
||||
cdef class Lookup(object):
|
||||
def __init__(self, name, done_cb, *args, **kargs):
|
||||
"""Lookup()
|
||||
|
||||
A simple class to perform asynchronous DNS lookups.
|
||||
|
||||
:param string name: The hostname to query
|
||||
:param callable done_cb: The function to call when done
|
||||
:param \*args: Any other arguments will be passed back in ``done_cb``
|
||||
:param \**kargs: Any other keywords arguments will be passed back in ``done_cb``
|
||||
|
||||
.. versionadded:: 1.17
|
||||
|
||||
Just create an instance and give a callback function to be called
|
||||
when the operation is complete.
|
||||
|
||||
This class performs a DNS lookup on the hostname specified by
|
||||
`name`, then calls `done_cb` with the result and the data given as
|
||||
parameter. The result will be given to the done_cb as follows:
|
||||
|
||||
**expected `done_cb` signature**::
|
||||
|
||||
func(canonname, ip, sockaddr)
|
||||
|
||||
where:
|
||||
* **canonname** (string) is the canonical domain name
|
||||
* **ip** (string) is the recolved ip address
|
||||
* **sockaddr** (None) is a placeholder for future expansion
|
||||
|
||||
|
||||
|
||||
**Usage example**::
|
||||
|
||||
import ecore_con
|
||||
|
||||
def done_cb(canonname, ip, sockaddr):
|
||||
print(canonname)
|
||||
print(ip)
|
||||
|
||||
ecore_con.Lookup('example.com', done_cb)
|
||||
|
||||
|
||||
"""
|
||||
|
||||
if not callable(done_cb):
|
||||
raise TypeError("Parameter 'done_cb' must be callable")
|
||||
|
||||
self.done_cb = done_cb
|
||||
self.args = args
|
||||
self.kargs = kargs
|
||||
|
||||
if isinstance(name, unicode): name = PyUnicode_AsUTF8String(name)
|
||||
ecore_con_lookup(<const char *>name if name is not None else NULL,
|
||||
_con_dns_lookup_cb, <void*>self)
|
||||
|
||||
Py_INCREF(self)
|
||||
|
|
@ -0,0 +1,827 @@
|
|||
# Copyright (C) 2007-2015 various contributors (see AUTHORS)
|
||||
#
|
||||
# This file is part of Python-EFL.
|
||||
#
|
||||
# Python-EFL is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# Python-EFL is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# from efl.ecore cimport EventHandler
|
||||
# from efl.utils.conversions cimport _ctouni as _charp_to_str
|
||||
|
||||
|
||||
|
||||
cdef class EventUrlProgress(Event):
|
||||
"""Represents Ecore_Con_Event_Url_Progress event from C-api.
|
||||
|
||||
This event notifies the progress of the current operation.
|
||||
|
||||
attributes:
|
||||
* url (:class:`Url`): the object that generate the event
|
||||
* down_total(double): total size of the downloading data (in bytes)
|
||||
* down_now(double): current size of the downloading data (in bytes)
|
||||
* up_total(double): total size of the uploading data (in bytes)
|
||||
* up_now(double): current size of the uploading data (in bytes)
|
||||
|
||||
"""
|
||||
cdef int _set_obj(self, void *ev) except 0:
|
||||
cdef Ecore_Con_Event_Url_Progress *event
|
||||
event = <Ecore_Con_Event_Url_Progress*>ev
|
||||
|
||||
self.url = object_from_instance(event.url_con)
|
||||
self.down_total = event.down.total
|
||||
self.down_now = event.down.now
|
||||
self.up_total = event.up.total
|
||||
self.up_now = event.up.now
|
||||
return 1
|
||||
|
||||
cdef object _get_obj(self):
|
||||
return self.url
|
||||
|
||||
cdef class EventUrlComplete(Event):
|
||||
"""Represents Ecore_Con_Event_Url_Complete event from C-api.
|
||||
|
||||
This event notifies the operation is completed.
|
||||
|
||||
attributes:
|
||||
* url (:class:`Url`): the object that generate the event
|
||||
* status(int): HTTP status code of the operation (200, 404, 401, etc.)
|
||||
|
||||
"""
|
||||
cdef int _set_obj(self, void *ev) except 0:
|
||||
cdef Ecore_Con_Event_Url_Complete *event
|
||||
event = <Ecore_Con_Event_Url_Complete*>ev
|
||||
|
||||
self.url = object_from_instance(event.url_con)
|
||||
self.status = event.status
|
||||
return 1
|
||||
|
||||
cdef object _get_obj(self):
|
||||
return self.url
|
||||
|
||||
cdef class EventUrlData(Event):
|
||||
"""Represents Ecore_Con_Event_Url_Data event from C-api.
|
||||
|
||||
This event hold the data while the are received.
|
||||
|
||||
.. note::
|
||||
The data attribute is a raw series of bytes, map to ``str`` in python2
|
||||
and ``bytes`` in python3.
|
||||
|
||||
attributes:
|
||||
* url (:class:`Url`): the object that generate the event
|
||||
* size(int): the size of the current received data (in bytes)
|
||||
* data(bytes): the data received on this event
|
||||
|
||||
"""
|
||||
cdef int _set_obj(self, void *ev) except 0:
|
||||
cdef Ecore_Con_Event_Url_Data *event
|
||||
event = <Ecore_Con_Event_Url_Data*>ev
|
||||
|
||||
self.url = object_from_instance(event.url_con)
|
||||
self.size = event.size
|
||||
self.data = event.data[:event.size] #raw string copy
|
||||
return 1
|
||||
|
||||
cdef object _get_obj(self):
|
||||
return self.url
|
||||
|
||||
|
||||
cdef class Url(Eo):
|
||||
"""
|
||||
|
||||
Utility class to make it easy to perform http requests (POST, GET, etc).
|
||||
|
||||
.. versionadded:: 1.17
|
||||
|
||||
Brief usage:
|
||||
1. Create an :class:`Url` object with ecore_con.Url('myurl')
|
||||
2. Register object callbacks using :func:`on_complete_event_add`,
|
||||
:func:`on_progress_event_add` and :func:`on_data_event_add` to
|
||||
receive the response, e.g. for HTTP/FTP downloads.
|
||||
3. Perform the operation with :func:`get`, :func:`head` and :func:`post`
|
||||
|
||||
If it's necessary use the :attr:`url` property. to change the object url.
|
||||
|
||||
.. note::
|
||||
It is good practice to reuse :class:`Url` objects wherever possible,
|
||||
but bear in mind that each one can only perform one operation at a
|
||||
time. You need to wait for the complete event before re-using or
|
||||
destroying the object.
|
||||
|
||||
.. warning::
|
||||
It is **really important** to call the :func:`delete()` method as soon
|
||||
as you have finished with your object, as it automatically remove all
|
||||
the registered events for you, that will otherwise continue to use
|
||||
resources.
|
||||
|
||||
Basic usage examples::
|
||||
|
||||
# HTTP GET
|
||||
u = ecore.Url("http://www.google.com")
|
||||
u.get()
|
||||
|
||||
# HTTP POST
|
||||
u = ecore.Url('https://httpbin.org/post')
|
||||
u.post(b'my data to post', 'text/txt')
|
||||
|
||||
# FTP download
|
||||
u = ecore.Url("ftp://ftp.example.com/pub/myfile")
|
||||
u.get()
|
||||
|
||||
# FTP upload as ftp://ftp.example.com/file
|
||||
u = ecore.Url("ftp://ftp.example.com")
|
||||
u.ftp_upload("/tmp/file", "user", "pass", None)
|
||||
|
||||
# FTP upload as ftp://ftp.example.com/dir/file
|
||||
u = ecore.Url("ftp://ftp.example.com")
|
||||
u.ftp_upload("/tmp/file", "user", "pass", "dir")
|
||||
|
||||
To actually make something usefull with your request you will need to
|
||||
connect the :class:`EventUrlComplete`, :class:`EventUrlProgress` and
|
||||
:class:`EventUrlData` events using the :func:`on_complete_event_add` and
|
||||
friends functions.
|
||||
|
||||
A more complete example::
|
||||
|
||||
from efl import ecore
|
||||
|
||||
def on_data(event):
|
||||
print("data: " + str(event.data[:80]))
|
||||
# do something here with the received data
|
||||
|
||||
def on_progress(event):
|
||||
# print(event)
|
||||
print("received %d on a total of %d bytes" % (
|
||||
event.down_now, event.down_total))
|
||||
|
||||
def on_complete(event):
|
||||
# print(event)
|
||||
print("http result: %d" % event.status)
|
||||
print("Total received bytes: %d" % event.url.received_bytes)
|
||||
|
||||
u.delete() # don't forget to delete !!
|
||||
|
||||
u = ecore.Url('http://www.google.com', verbose=False)
|
||||
u.on_data_event_add(on_data)
|
||||
u.on_progress_event_add(on_progress)
|
||||
u.on_complete_event_add(on_complete)
|
||||
u.get()
|
||||
|
||||
ecore.main_loop_begin()
|
||||
|
||||
If you need to save the received data to a file use the :attr:`fd`
|
||||
property, as::
|
||||
|
||||
fd = open('/tmp/tmpMxBtta', 'w')
|
||||
u = ecore.Url('http://example.com', fd=fd.fileno())
|
||||
u.get()
|
||||
|
||||
.. seealso::
|
||||
If you just need to download a file please consider using the
|
||||
simpler :class:`efl.ecore.FileDownload` class instead.
|
||||
|
||||
.. seealso::
|
||||
The ecore module level functions :func:`url_pipeline_set` and
|
||||
:func:`url_pipeline_get` to enable HTTP 1.1 pipelining.
|
||||
|
||||
"""
|
||||
def __init__(self, url, custom_request=None, **kargs):
|
||||
"""Url(...)
|
||||
|
||||
:param url: URL that will receive requests.
|
||||
:type url: string
|
||||
:param custom_request: Custom request (e.g. GET, POST, HEAD, PUT, HEAD,
|
||||
SUBSCRIBE and other obscure HTTP requests)
|
||||
:type custom_request: string
|
||||
:param \**kwargs: All the remaining keyword arguments are interpreted
|
||||
as properties of the instance
|
||||
|
||||
.. versionadded:: 1.17
|
||||
|
||||
"""
|
||||
if isinstance(url, unicode): url = PyUnicode_AsUTF8String(url)
|
||||
if custom_request is None:
|
||||
self._set_obj(ecore_con_url_new(
|
||||
<const char *>url if url is not None else NULL))
|
||||
else:
|
||||
if isinstance(custom_request, unicode):
|
||||
custom_request = PyUnicode_AsUTF8String(custom_request)
|
||||
self._set_obj(ecore_con_url_custom_new(
|
||||
<const char *>url if url is not None else NULL,
|
||||
<const char *>custom_request if custom_request is not None else NULL))
|
||||
|
||||
self._set_properties_from_keyword_args(kargs)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s(url=%s)" % (self.__class__.__name__, self.url)
|
||||
|
||||
def delete(self):
|
||||
"""Delete the :class:`Url` object and free all used resources.
|
||||
|
||||
.. note::
|
||||
This is **really important** to call as soon as you have finished
|
||||
with your object, as it automatically remove all the registered
|
||||
events. That will otherwise continue to use resources.
|
||||
|
||||
"""
|
||||
GEF.callback_del_full(self)
|
||||
ecore_con_url_free(self.obj)
|
||||
|
||||
property fd:
|
||||
"""Set up a file to have response data written into.
|
||||
|
||||
This attr can be used to easily setup a file where the downloaded data
|
||||
will be saved.
|
||||
|
||||
Note that :class:`EventUrlData` events will not be emitted if a file
|
||||
has been set to receive the response data.
|
||||
|
||||
.. seealso::
|
||||
If you just need to download a file please consider using the
|
||||
simpler :class:`efl.ecore.FileDownload` class instead.
|
||||
|
||||
:type: int (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, int fd):
|
||||
ecore_con_url_fd_set(self.obj, fd)
|
||||
|
||||
def get(self):
|
||||
"""Send a GET request.
|
||||
|
||||
The request is performed immediately, but you need to setup event
|
||||
handlers with :func:`on_complete_event_add` or
|
||||
:func:`on_complete_event_add` to get more information about its result.
|
||||
|
||||
:return: ``True`` on success, ``False`` on error.
|
||||
|
||||
"""
|
||||
return bool(ecore_con_url_get(self.obj))
|
||||
|
||||
def head(self):
|
||||
"""Send a HEAD request.
|
||||
|
||||
The request is performed immediately, but you need to setup event
|
||||
handlers with :func:`on_complete_event_add` or
|
||||
:func:`on_complete_event_add` to get more information about its result.
|
||||
|
||||
:return: ``True`` on success, ``False`` on error.
|
||||
|
||||
"""
|
||||
return bool(ecore_con_url_head(self.obj))
|
||||
|
||||
def post(self, bytes data, content_type):
|
||||
"""Send a post request.
|
||||
|
||||
The request is performed immediately, but you need to setup event
|
||||
handlers with :func:`on_complete_event_add` or
|
||||
:func:`on_complete_event_add` to get more information about its result.
|
||||
|
||||
:param data: Payload (data sent on the request). Can be ``None``.
|
||||
:type data: bytes
|
||||
:param content_type: Content type of the payload (e.g. `text/xml`).
|
||||
Can be ``None``.
|
||||
:type content_type: string
|
||||
|
||||
:return: ``True`` on success, ``False`` on error.
|
||||
|
||||
"""
|
||||
if isinstance(content_type, unicode):
|
||||
content_type = PyUnicode_AsUTF8String(content_type)
|
||||
return bool(ecore_con_url_post(self.obj,
|
||||
<const void*><const char *>data if data is not None else NULL,
|
||||
len(data),
|
||||
<const char *>content_type if content_type is not None else NULL))
|
||||
|
||||
def time(self, Ecore_Con_Url_Time time_condition, double timestamp):
|
||||
"""Whether HTTP requests should be conditional, dependent on
|
||||
modification time.
|
||||
|
||||
This function may set the header `If-Modified-Since` or
|
||||
`If-Unmodified-Since`, depending on the value of time_condition, with
|
||||
the value timestamp.
|
||||
|
||||
:param time_condition: Condition to use for HTTP requests.
|
||||
:type time_condition: :ref:`Ecore_Con_Url_Time`
|
||||
:param timestamp: Time since 1 Jan 1970 to use in the condition.
|
||||
:type timestamp: double
|
||||
|
||||
"""
|
||||
ecore_con_url_time(self.obj, time_condition, timestamp)
|
||||
|
||||
def ftp_upload(self, filename, user, passwd, upload_dir):
|
||||
"""Upload a file to an ftp site.
|
||||
|
||||
:param string filename: The path to the file to send
|
||||
:param string user: The username to log in with
|
||||
:param string passwd: The password to log in with
|
||||
:param string upload_dir: The directory to which the file will upload
|
||||
|
||||
:return: ``True`` on success, ``False`` otherwise.
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
if isinstance(filename, unicode): filename = PyUnicode_AsUTF8String(filename)
|
||||
if isinstance(user, unicode): user = PyUnicode_AsUTF8String(user)
|
||||
if isinstance(passwd, unicode): passwd = PyUnicode_AsUTF8String(passwd)
|
||||
if isinstance(upload_dir, unicode): upload_dir = PyUnicode_AsUTF8String(upload_dir)
|
||||
return bool(ecore_con_url_ftp_upload(self.obj,
|
||||
<const char *>filename if filename is not None else NULL,
|
||||
<const char *>user if user is not None else NULL,
|
||||
<const char *>passwd if passwd is not None else NULL,
|
||||
<const char *>upload_dir if upload_dir is not None else NULL))
|
||||
|
||||
property ftp_use_epsv:
|
||||
"""Enable or disable EPSV extension.
|
||||
|
||||
:type: bool (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, bint use_epsv):
|
||||
ecore_con_url_ftp_use_epsv_set(self.obj, use_epsv)
|
||||
|
||||
def cookies_init(self):
|
||||
"""Enable the cookie engine for subsequent HTTP requests.
|
||||
|
||||
After this function is called, cookies set by the server in HTTP
|
||||
responses will be parsed and stored, as well as sent back to the server
|
||||
in new HTTP requests.
|
||||
|
||||
"""
|
||||
ecore_con_url_cookies_init(self.obj)
|
||||
|
||||
def cookies_clear(self):
|
||||
"""Clear currently loaded cookies.
|
||||
|
||||
The cleared cookies are removed and will not be sent in subsequent HTTP
|
||||
requests, nor will they be written to the cookiejar file set via
|
||||
:attr:`cookies_jar_file`.
|
||||
|
||||
.. note::
|
||||
This function will initialize the cookie engine if it has not been
|
||||
initialized yet. The cookie files set by
|
||||
:func:`cookies_file_add` aren't loaded immediately, just
|
||||
when the request is started. Thus, if you ask to clear the cookies,
|
||||
but has a file already set by that function, the cookies will then
|
||||
be loaded and you will have old cookies set. In order to don't have
|
||||
any old cookie set, you need to don't call
|
||||
:func:`cookies_file_add` ever on the :class:`Url` class, and
|
||||
call this function to clear any cookie set by a previous request on
|
||||
this handler.
|
||||
|
||||
"""
|
||||
ecore_con_url_cookies_clear(self.obj)
|
||||
|
||||
def cookies_session_clear(self):
|
||||
"""Clear currently loaded session cookies.
|
||||
|
||||
Session cookies are cookies with no expire date set, which usually
|
||||
means they are removed after the current session is closed.
|
||||
|
||||
The cleared cookies are removed and will not be sent in subsequent HTTP
|
||||
requests, nor will they be written to the cookiejar file set via
|
||||
:attr:`cookies_jar_file`.
|
||||
|
||||
.. note::
|
||||
This function will initialize the cookie engine if it has not been
|
||||
initialized yet. The cookie files set by
|
||||
:func:`cookies_file_add` aren't loaded immediately, just
|
||||
when the request is started. Thus, if you ask to clear the session
|
||||
cookies, but has a file already set by that function, the session
|
||||
cookies will then be loaded and you will have old cookies set. In
|
||||
order to don't have any old session cookie set, you need to don't
|
||||
call :func:`cookies_file_add` ever on the :class:`Url` class, and
|
||||
call this function to clear any session cookie set by a previous
|
||||
request on this handler. An easier way to don't use old session
|
||||
cookies is by using the function
|
||||
:attr:`cookies_ignore_old_session`.
|
||||
|
||||
"""
|
||||
ecore_con_url_cookies_session_clear(self.obj)
|
||||
|
||||
def cookies_file_add(self, file_name):
|
||||
"""Add a file to the list of files from which to load cookies.
|
||||
|
||||
Files must contain cookies defined according to two possible formats:
|
||||
* HTTP-style header ("Set-Cookie: ...").
|
||||
* Netscape/Mozilla cookie data format.
|
||||
|
||||
Cookies will only be read from this file. If you want to save cookies
|
||||
to a file, use :attr:`cookies_jar_file`. Also notice that
|
||||
this function supports the both types of cookie file cited above, while
|
||||
:attr:`cookies_jar_file` will save only in the Netscape/Mozilla's
|
||||
format.
|
||||
|
||||
Please notice that the file will not be read immediately, but rather
|
||||
added to a list of files that will be loaded and parsed at a later
|
||||
time.
|
||||
|
||||
.. note::
|
||||
This function will initialize the cookie engine if it has not been
|
||||
initialized yet.
|
||||
|
||||
:param string file_name: Name of the file that will be added to the list.
|
||||
|
||||
"""
|
||||
if isinstance(file_name, unicode):
|
||||
file_name = PyUnicode_AsUTF8String(file_name)
|
||||
ecore_con_url_cookies_file_add(self.obj,
|
||||
<const char *>file_name if file_name is not None else NULL)
|
||||
|
||||
property cookies_jar_file:
|
||||
"""The name of the file to which all current cookies will be written
|
||||
when either cookies are flushed or Ecore_Con is shut down.
|
||||
|
||||
Cookies are written following Netscape/Mozilla's data format, also
|
||||
known as cookie-jar.
|
||||
|
||||
Cookies will only be saved to this file. If you need to read cookies
|
||||
from a file, use ecore_con_url_cookies_file_add() instead.
|
||||
|
||||
.. note::
|
||||
This function will initialize the cookie engine if it has not been
|
||||
initialized yet.
|
||||
|
||||
.. seealso:: :func:`cookies_jar_write`
|
||||
|
||||
:type: string (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, cookiejar_file):
|
||||
if isinstance(cookiejar_file, unicode):
|
||||
cookiejar_file = PyUnicode_AsUTF8String(cookiejar_file)
|
||||
ecore_con_url_cookies_jar_file_set(self.obj,
|
||||
<const char *>cookiejar_file if cookiejar_file is not None else NULL)
|
||||
if isinstance(cookiejar_file, unicode):
|
||||
cookiejar_file = PyUnicode_AsUTF8String(cookiejar_file)
|
||||
ecore_con_url_cookies_jar_file_set(self.obj,
|
||||
<const char *>cookiejar_file if cookiejar_file is not None else NULL)
|
||||
|
||||
def cookies_jar_write(self):
|
||||
"""Write all current cookies to the cookie jar immediately.
|
||||
|
||||
A cookie-jar file must have been previously set by
|
||||
:attr:`cookies_jar_file`, otherwise nothing will be done.
|
||||
|
||||
.. note::
|
||||
This function will initialize the cookie engine if it has not been
|
||||
initialized yet.
|
||||
|
||||
.. seealso:: :attr:`cookies_jar_file`
|
||||
|
||||
"""
|
||||
ecore_con_url_cookies_jar_write(self.obj)
|
||||
|
||||
property cookies_ignore_old_session:
|
||||
"""Control whether session cookies from previous sessions shall be loaded.
|
||||
|
||||
Session cookies are cookies with no expire date set, which usually
|
||||
means they are removed after the current session is closed.
|
||||
|
||||
By default, when Ecore_Con_Url loads cookies from a file, all cookies
|
||||
are loaded, including session cookies, which, most of the time, were
|
||||
supposed to be loaded and valid only for that session.
|
||||
|
||||
If ignore is set to ``True``, when Ecore_Con_Url loads cookies from
|
||||
the files passed to :func:`cookies_file_add`, session cookies
|
||||
will not be loaded.
|
||||
|
||||
:type: bool (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, bint ignore):
|
||||
ecore_con_url_cookies_ignore_old_session_set(self.obj, ignore)
|
||||
|
||||
property ssl_verify_peer:
|
||||
"""Toggle libcurl's verify peer's certificate option.
|
||||
|
||||
If this is ``True``, libcurl will verify the authenticity of the
|
||||
peer's certificate, otherwise it will not. Default behavior of libcurl
|
||||
is to check peer's certificate.
|
||||
|
||||
:type: bool (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, bint verify):
|
||||
ecore_con_url_ssl_verify_peer_set(self.obj, verify)
|
||||
|
||||
property ssl_ca:
|
||||
"""Set a custom CA to trust for SSL/TLS connections.
|
||||
|
||||
Specify the path of a file (in PEM format) containing one or more CA
|
||||
certificate(s) to use for the validation of the server certificate.
|
||||
|
||||
This can also disable CA validation if set to ``None``.
|
||||
However, the server certificate still needs to be valid for the
|
||||
connection to succeed (i.e., the certificate must concern the server
|
||||
the connection is made to).
|
||||
|
||||
:type: string (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, ca_path):
|
||||
if isinstance(ca_path, unicode):
|
||||
ca_path = PyUnicode_AsUTF8String(ca_path)
|
||||
ecore_con_url_ssl_ca_set(self.obj,
|
||||
<const char *>ca_path if ca_path is not None else NULL)
|
||||
|
||||
property proxy:
|
||||
"""Set the HTTP proxy to use.
|
||||
|
||||
The parameter is the host name or dotted IP address. To specify port
|
||||
number in this string, append :[port] to the end of the host name. The
|
||||
proxy string may be prefixed with [protocol]:// since any such prefix
|
||||
will be ignored. The proxy's port number may optionally be specified
|
||||
with the separate option. If not specified, libcurl will default to
|
||||
using port 1080 for proxies.
|
||||
|
||||
Set this to ``None`` to disable the usage of proxy.
|
||||
|
||||
:type: string (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, proxy):
|
||||
if isinstance(proxy, unicode): proxy = PyUnicode_AsUTF8String(proxy)
|
||||
ecore_con_url_proxy_set(self.obj,
|
||||
<const char *>proxy if proxy is not None else NULL)
|
||||
|
||||
property proxy_username:
|
||||
"""Username to use for proxy.
|
||||
|
||||
If socks protocol is used for proxy, protocol should be socks5 and
|
||||
above.
|
||||
|
||||
:type: string (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, user):
|
||||
if isinstance(user, unicode): user = PyUnicode_AsUTF8String(user)
|
||||
ecore_con_url_proxy_username_set(self.obj,
|
||||
<const char *>user if user is not None else NULL)
|
||||
|
||||
property proxy_password:
|
||||
"""Password to use for proxy.
|
||||
|
||||
If socks protocol is used for proxy, protocol should be socks5 and
|
||||
above.
|
||||
|
||||
:type: string (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, passwd):
|
||||
if isinstance(passwd, unicode): passwd = PyUnicode_AsUTF8String(passwd)
|
||||
ecore_con_url_proxy_username_set(self.obj,
|
||||
<const char *>passwd if passwd is not None else NULL)
|
||||
|
||||
property timeout:
|
||||
"""transfer timeout in seconds.
|
||||
|
||||
The maximum time in seconds that you allow the :class:`Url` class
|
||||
transfer operation to take. Normally, name lookups can take a
|
||||
considerable time and limiting operations to less than a few minutes
|
||||
risk aborting perfectly normal operations.
|
||||
|
||||
:type: double (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, double timeout):
|
||||
ecore_con_url_timeout_set(self.obj, timeout)
|
||||
|
||||
property http_version:
|
||||
"""The HTTP version used for the request.
|
||||
|
||||
Can be :data:`ECORE_CON_URL_HTTP_VERSION_1_0` or
|
||||
:data:`ECORE_CON_URL_HTTP_VERSION_1_1`
|
||||
|
||||
:type: :ref:`Ecore_Con_Url_Http_Version` (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, Ecore_Con_Url_Http_Version version):
|
||||
ecore_con_url_http_version_set(self.obj, version)
|
||||
|
||||
property status_code:
|
||||
"""The returned HTTP STATUS code.
|
||||
|
||||
This is used to, at any time, try to return the status code for a
|
||||
transmission.
|
||||
|
||||
:type: int (**readonly**)
|
||||
|
||||
"""
|
||||
def __get__(self):
|
||||
return ecore_con_url_status_code_get(self.obj)
|
||||
|
||||
property url:
|
||||
"""Controls the URL to send the request to.
|
||||
|
||||
:type: string
|
||||
|
||||
"""
|
||||
def __get__(self):
|
||||
return _ctouni(ecore_con_url_url_get(self.obj))
|
||||
|
||||
def __set__(self, url):
|
||||
if isinstance(url, unicode): url = PyUnicode_AsUTF8String(url)
|
||||
ecore_con_url_url_set(self.obj, <const char *>url if url is not None else NULL)
|
||||
|
||||
property verbose:
|
||||
"""Toggle libcurl's verbose output.
|
||||
|
||||
If set to ``True``, libcurl will output a lot of verbose
|
||||
information about its operations, which is useful for debugging. The
|
||||
verbose information will be sent to stderr.
|
||||
|
||||
:type: bool (**writeonly**)
|
||||
|
||||
"""
|
||||
def __set__(self, bint verbose):
|
||||
ecore_con_url_verbose_set(self.obj, verbose)
|
||||
|
||||
def additional_header_add(self, key, value):
|
||||
"""Add an additional header to the request connection object.
|
||||
|
||||
Add an additional header (User-Agent, Content-Type, etc.) to the
|
||||
request connection object. This addition will be valid for only one
|
||||
:func:`get` or :func:`post` call.
|
||||
|
||||
:param string key: Header key
|
||||
:param string value: Header value
|
||||
|
||||
Some functions like :func:`time` also add headers to the request.
|
||||
|
||||
"""
|
||||
if isinstance(key, unicode): key = PyUnicode_AsUTF8String(key)
|
||||
if isinstance(value, unicode): value = PyUnicode_AsUTF8String(value)
|
||||
ecore_con_url_additional_header_add(self.obj,
|
||||
<const char *>key if key is not None else NULL,
|
||||
<const char *>value if value is not None else NULL)
|
||||
|
||||
def additional_headers_clear(self):
|
||||
"""Clean additional headers.
|
||||
|
||||
Clean additional headers associated with a connection object
|
||||
(previously added with :func:additional_header_add`).
|
||||
|
||||
"""
|
||||
ecore_con_url_additional_headers_clear(self.obj)
|
||||
|
||||
property response_headers:
|
||||
"""The headers from last request sent.
|
||||
|
||||
Retrieve a list containing the response headers. This function should
|
||||
be used after an :class:`EventUrlComplete` event (headers should
|
||||
normally be ready at that time).
|
||||
|
||||
:type: list of strings (**readonly**)
|
||||
|
||||
"""
|
||||
def __get__(self):
|
||||
return eina_list_strings_to_python_list(
|
||||
ecore_con_url_response_headers_get(self.obj))
|
||||
|
||||
property received_bytes:
|
||||
"""The number of bytes received.
|
||||
|
||||
Retrieve the number of bytes received on the last request of the
|
||||
:class:`Url` object.
|
||||
|
||||
:type: int (**readonly**)
|
||||
|
||||
"""
|
||||
def __get__(self):
|
||||
return ecore_con_url_received_bytes_get(self.obj)
|
||||
|
||||
def httpauth_set(self, username, password, bint safe):
|
||||
"""Set to use http auth, with given username and password
|
||||
|
||||
:param string username: Username to use in authentication
|
||||
:param string password: Password to use in authentication
|
||||
:param bool safe: Whether to use "safer" methods (eg, NOT http basic auth)
|
||||
|
||||
:return: ``True`` on success, ``False`` on error.
|
||||
:rtype: bool
|
||||
|
||||
.. warning:: Require libcurl >= 7.19.1 to work, otherwise will
|
||||
always return ``False``.
|
||||
|
||||
"""
|
||||
if isinstance(username, unicode):
|
||||
username = PyUnicode_AsUTF8String(username)
|
||||
if isinstance(password, unicode):
|
||||
password = PyUnicode_AsUTF8String(password)
|
||||
return bool(ecore_con_url_httpauth_set(self.obj,
|
||||
<const char *>username if username is not None else NULL,
|
||||
<const char *>password if password is not None else NULL,
|
||||
safe))
|
||||
|
||||
def on_complete_event_add(self, func, *args, **kargs):
|
||||
"""Adds event listener to know when the Url operation is completed.
|
||||
|
||||
The given function will be called with the following signature::
|
||||
|
||||
func(event, *args, **kargs)
|
||||
|
||||
The ``event`` parameter is an :class:`EventUrlComplete` instance.
|
||||
|
||||
:see: :func:`on_complete_event_del`
|
||||
|
||||
"""
|
||||
GEF.callback_add(ECORE_CON_EVENT_URL_COMPLETE, self, func, args, kargs)
|
||||
|
||||
def on_complete_event_del(self, func, *args, **kargs):
|
||||
"""Removes an event listener previously registered
|
||||
|
||||
Parameters must match exactly the ones given in the
|
||||
:func:`on_complete_event_add` call
|
||||
|
||||
:raise ValueError: if parameters don't match an already
|
||||
registered callback.
|
||||
"""
|
||||
GEF.callback_del(ECORE_CON_EVENT_URL_COMPLETE, self, func, args, kargs)
|
||||
|
||||
def on_progress_event_add(self, func, *args, **kargs):
|
||||
"""Adds event listener to know the operation status progress.
|
||||
|
||||
The given function will be called with the following signature::
|
||||
|
||||
func(event, *args, **kargs)
|
||||
|
||||
The ``event`` parameter is an :class:`EventUrlProgress` instance.
|
||||
|
||||
:see: :func:`on_progress_event_del`
|
||||
|
||||
"""
|
||||
GEF.callback_add(ECORE_CON_EVENT_URL_PROGRESS, self, func, args, kargs)
|
||||
|
||||
def on_progress_event_del(self, func, *args, **kargs):
|
||||
"""Removes an event listener previously registered
|
||||
|
||||
Parameters must match exactly the ones given in the
|
||||
:func:`on_progress_event_add` call
|
||||
|
||||
:raise ValueError: if parameters don't match an already
|
||||
registered callback.
|
||||
"""
|
||||
GEF.callback_del(ECORE_CON_EVENT_URL_PROGRESS, self, func, args, kargs)
|
||||
|
||||
def on_data_event_add(self, func, *args, **kargs):
|
||||
"""Adds event listener to collect the data while they are received.
|
||||
|
||||
The given function will be called with the following signature::
|
||||
|
||||
func(event, *args, **kargs)
|
||||
|
||||
The ``event`` parameter is an :class:`EventUrlData` instance.
|
||||
|
||||
:see: :func:`on_data_event_del`
|
||||
|
||||
"""
|
||||
GEF.callback_add(ECORE_CON_EVENT_URL_DATA, self, func, args, kargs)
|
||||
|
||||
def on_data_event_del(self, func, *args, **kargs):
|
||||
"""Removes an event listener previously registered
|
||||
|
||||
Parameters must match exactly the ones given in the
|
||||
:func:`on_data_event_add` call
|
||||
|
||||
:raise ValueError: if parameters don't match an already
|
||||
registered callback.
|
||||
"""
|
||||
GEF.callback_del(ECORE_CON_EVENT_URL_DATA, self, func, args, kargs)
|
||||
|
||||
|
||||
def url_pipeline_set(bint enable):
|
||||
"""Enable or disable HTTP 1.1 pipelining.
|
||||
|
||||
Pipelining allows to send one request after another one, without having to
|
||||
wait for the reply of the first request. The respective replies are
|
||||
received in the order that the requests were sent.
|
||||
|
||||
.. warning:: Enabling this feature will be valid for all requests done
|
||||
using ecore_con_url.
|
||||
|
||||
.. versionadded:: 1.17
|
||||
|
||||
"""
|
||||
ecore_con_url_pipeline_set(enable)
|
||||
|
||||
def url_pipeline_get():
|
||||
"""Is HTTP 1.1 pipelining enable ?
|
||||
|
||||
:return: ``True`` if enable
|
||||
|
||||
.. versionadded:: 1.17
|
||||
|
||||
"""
|
||||
return bool(ecore_con_url_pipeline_get())
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
|
||||
from efl import ecore
|
||||
from efl import ecore_con
|
||||
|
||||
|
||||
def on_complete(canonname, ip):
|
||||
print('Lookup completed')
|
||||
print('Canonname: %s' % canonname)
|
||||
print('Ip: %s' % ip)
|
||||
|
||||
ecore.main_loop_quit()
|
||||
|
||||
ecore_con.Lookup('example.com', on_complete)
|
||||
|
||||
ecore.main_loop_begin()
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
|
||||
from efl import ecore
|
||||
from efl import ecore_con
|
||||
|
||||
def on_data(event):
|
||||
print("data: " + str(event.data))
|
||||
# do something here with the received data
|
||||
|
||||
def on_progress(event):
|
||||
# print(event)
|
||||
print("received %d on a total of %d bytes" % (
|
||||
event.down_now, event.down_total))
|
||||
|
||||
def on_complete(event):
|
||||
# print(event)
|
||||
print("http result: %d" % event.status)
|
||||
print("Total received bytes: %d" % event.url.received_bytes)
|
||||
|
||||
u.delete() # don't forget to delete !!
|
||||
ecore.main_loop_quit()
|
||||
|
||||
u = ecore_con.Url('http://www.example.com', verbose=False)
|
||||
u.on_data_event_add(on_data)
|
||||
u.on_progress_event_add(on_progress)
|
||||
u.on_complete_event_add(on_complete)
|
||||
u.get()
|
||||
|
||||
ecore.main_loop_begin()
|
|
@ -371,6 +371,7 @@ cdef class EventHandler(object):
|
|||
|
||||
cdef class Event(object):
|
||||
cdef int _set_obj(self, void *obj) except 0
|
||||
cdef object _get_obj(self)
|
||||
|
||||
|
||||
cdef class EventSignalUser(Event):
|
||||
|
@ -444,5 +445,7 @@ cdef class FileMonitor:
|
|||
|
||||
cdef object _exec_monitor(self, Ecore_File_Event event, const char *path)
|
||||
|
||||
|
||||
cdef object _event_mapping_register(int type, cls)
|
||||
cdef object _event_mapping_unregister(int type)
|
||||
cdef object _event_mapping_get(int type)
|
||||
|
|
18
setup.py
18
setup.py
|
@ -110,8 +110,9 @@ class CleanGenerated(Command):
|
|||
pass
|
||||
|
||||
def run(self):
|
||||
for lib in ("eo", "evas", "ecore", "ecore_x", "edje", "emotion",
|
||||
"elementary", "ethumb", "dbus_mainloop", "utils"):
|
||||
for lib in ("eo", "evas", "ecore", "ecore_x", "ecore_con", "edje",
|
||||
"emotion", "elementary", "ethumb", "dbus_mainloop",
|
||||
"utils"):
|
||||
lib_path = os.path.join(script_path, "efl", lib)
|
||||
for root, dirs, files in os.walk(lib_path):
|
||||
for f in files:
|
||||
|
@ -307,6 +308,19 @@ if set(("build", "build_ext", "install", "bdist", "sdist")) & set(sys.argv):
|
|||
eina_libs + evas_libs)
|
||||
ext_modules.append(ecore_ext)
|
||||
|
||||
# === Ecore Con ===
|
||||
ecore_con_cflags, ecore_con_libs = pkg_config('EcoreCon', 'ecore-con',
|
||||
EFL_MIN_VER)
|
||||
ecore_con_ext = Extension("ecore_con",
|
||||
["efl/ecore_con/efl.ecore_con" + module_suffix],
|
||||
include_dirs=['include/'],
|
||||
extra_compile_args=list(set(ecore_cflags +
|
||||
ecore_file_cflags +
|
||||
ecore_con_cflags)),
|
||||
extra_link_args=ecore_libs + ecore_file_libs +
|
||||
ecore_con_libs + eina_libs)
|
||||
ext_modules.append(ecore_con_ext)
|
||||
|
||||
# === Ecore X ===
|
||||
try:
|
||||
ecore_input_cflags, ecore_input_libs = pkg_config('EcoreInput',
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import unittest
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from efl import ecore, ecore_con
|
||||
|
||||
|
||||
class TestCon(unittest.TestCase):
|
||||
|
||||
def testLookup(self):
|
||||
def _dns_complete(canonname, ip, sockaddr, arg1, my_karg):
|
||||
self.assertEqual(canonname, 'google-public-dns-a.google.com.')
|
||||
self.assertEqual(ip, '8.8.8.8')
|
||||
self.assertEqual(arg1, "arg1")
|
||||
self.assertEqual(my_karg, 1234)
|
||||
ecore.main_loop_quit()
|
||||
|
||||
ecore_con.Lookup('google-public-dns-a.google.com',
|
||||
_dns_complete, "arg1", my_karg=1234)
|
||||
ecore.main_loop_begin()
|
||||
|
||||
def testUrl(self):
|
||||
self.complete_counter = 0
|
||||
self.progress_counter = 0
|
||||
self.exit_counter = 3 # we expect 3 complete cb calls
|
||||
self.test_url = 'http://www.example.com'
|
||||
self.received_data = []
|
||||
|
||||
def _on_complete(event, add=1):
|
||||
self.assertIsInstance(event, ecore_con.EventUrlComplete)
|
||||
self.assertEqual(event.status, 200) # assume net is ok
|
||||
self.assertEqual(event.url.url, self.test_url)
|
||||
|
||||
self.complete_counter += add
|
||||
self.exit_counter -= 1
|
||||
if self.exit_counter == 0:
|
||||
ecore.main_loop_quit()
|
||||
|
||||
def _on_progress(event, param1, two, one):
|
||||
self.assertIsInstance(event, ecore_con.EventUrlProgress)
|
||||
self.assertEqual(param1, 'param1')
|
||||
self.assertEqual(one, 1)
|
||||
self.assertEqual(two, 2)
|
||||
self.progress_counter += 1
|
||||
|
||||
def _on_data(event):
|
||||
self.assertIsInstance(event, ecore_con.EventUrlData)
|
||||
self.received_data.append(event.data)
|
||||
|
||||
u = ecore_con.Url(self.test_url)
|
||||
self.assertIsInstance(u, ecore_con.Url)
|
||||
|
||||
u.on_complete_event_add(_on_complete, add=100)
|
||||
u.on_complete_event_add(_on_complete, add=10)
|
||||
u.on_complete_event_del(_on_complete, add=100) #test event_del
|
||||
u.on_complete_event_add(_on_complete, add=1)
|
||||
u.on_complete_event_add(_on_complete, add=5)
|
||||
|
||||
u.on_progress_event_add(_on_progress, 'param1', one=1, two=2)
|
||||
u.on_data_event_add(_on_data)
|
||||
|
||||
self.assertTrue(u.get()) #perform the GET request
|
||||
|
||||
ecore.main_loop_begin()
|
||||
|
||||
self.assertEqual(u.status_code, 200) # assume net is ok
|
||||
self.assertEqual(self.complete_counter, 16)
|
||||
self.assertTrue(self.progress_counter > 0)
|
||||
|
||||
data = b''.join(self.received_data)
|
||||
self.assertEqual(len(data), u.received_bytes)
|
||||
|
||||
u.delete()
|
||||
|
||||
def testUrlDelete(self):
|
||||
|
||||
self.test_url1 = 'http://www.example.com'
|
||||
self.test_url2 = 'http://www.google.com'
|
||||
self.complete_counter = 0
|
||||
|
||||
def _on_complete1(event):
|
||||
self.assertIsInstance(event, ecore_con.EventUrlComplete)
|
||||
self.assertEqual(event.url.url, self.test_url1)
|
||||
self.complete_counter += 1
|
||||
|
||||
def _on_complete2(event):
|
||||
self.assertIsInstance(event, ecore_con.EventUrlComplete)
|
||||
self.assertEqual(event.url.url, self.test_url2)
|
||||
self.complete_counter += 10
|
||||
|
||||
u1 = ecore_con.Url(self.test_url1)
|
||||
u1.on_complete_event_add(_on_complete1)
|
||||
|
||||
u2 = ecore_con.Url(self.test_url2)
|
||||
u2.on_complete_event_add(_on_complete2)
|
||||
|
||||
u3 = ecore_con.Url(self.test_url1)
|
||||
u3.on_complete_event_add(_on_complete1)
|
||||
u3.get()
|
||||
u3.delete() # the previous get will not run
|
||||
|
||||
self.assertTrue(u1.get()) #perform the GET request
|
||||
self.assertTrue(u2.get()) #perform the GET request
|
||||
|
||||
ecore.Timer(2.5, lambda: ecore.main_loop_quit())
|
||||
ecore.main_loop_begin()
|
||||
|
||||
self.assertEqual(u1.status_code, 200) # assume net is ok
|
||||
self.assertEqual(u2.status_code, 200) # assume net is ok
|
||||
self.assertEqual(self.complete_counter, 11)
|
||||
|
||||
u1.delete()
|
||||
u2.delete()
|
||||
|
||||
def testUrlToFile(self):
|
||||
self.test_url = 'http://www.example.com'
|
||||
|
||||
def _on_complete(event):
|
||||
ecore.main_loop_quit()
|
||||
|
||||
fd, path = tempfile.mkstemp()
|
||||
u = ecore_con.Url(self.test_url, fd=fd)
|
||||
u.on_complete_event_add(_on_complete)
|
||||
u.get()
|
||||
|
||||
ecore.main_loop_begin()
|
||||
self.assertEqual(u.status_code, 200) # assume net is ok
|
||||
self.assertEqual(os.path.getsize(path), u.received_bytes)
|
||||
os.unlink(path)
|
||||
|
||||
u.delete()
|
||||
|
||||
# def testFtp(self):
|
||||
# pass #TODO
|
||||
|
||||
def testPost(self):
|
||||
self.test_url = 'https://httpbin.org/post'
|
||||
self.data_to_post = b'my data to post'
|
||||
|
||||
def _on_complete(event):
|
||||
ecore.main_loop_quit()
|
||||
|
||||
u = ecore_con.Url(self.test_url)
|
||||
u.on_complete_event_add(_on_complete)
|
||||
# u.post(self.data_to_post, "multipart/form-data")
|
||||
u.post(self.data_to_post, "text/txt")
|
||||
|
||||
ecore.main_loop_begin()
|
||||
self.assertEqual(u.status_code, 200) # assume net is ok
|
||||
|
||||
u.delete()
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(verbosity=2)
|
Loading…
Reference in New Issue