GithubHelp home page GithubHelp logo

marketsquare / robotframework-requests Goto Github PK

View Code? Open in Web Editor NEW
470.0 45.0 279.0 1.16 MB

Robot Framework keyword library wrapper for requests

Home Page: http://marketsquare.github.io/robotframework-requests/

License: MIT License

Python 61.09% RobotFramework 32.61% Shell 0.04% Batchfile 0.04% HTML 6.22%
robot-framework python requests robotframework-requests

robotframework-requests's Introduction

Python build codecov PyPi downloads Latest Version

🏠 RequestsLibrary is a Robot Framework library aimed to provide HTTP api testing functionalities by wrapping the well known Python Requests Library.

Install stable version

pip install robotframework-requests

Install pre-release version

pip install robotframework-requests --pre

🤖 Quick start

*** Settings ***
Library               RequestsLibrary

*** Test Cases ***

Quick Get Request Test
    ${response}=    GET  https://www.google.com

Quick Get Request With Parameters Test
    ${response}=    GET  https://www.google.com/search  params=query=ciao  expected_status=200

Quick Get A JSON Body Test
    ${response}=    GET  https://jsonplaceholder.typicode.com/posts/1
    Should Be Equal As Strings    1  ${response.json()}[id]

What's new in 0.9

Sessionless keywords are now available, you can just GET, POST, etc.. no need to create a session anymore!

${resp}=  GET  https://www.google.com

Status Should Be and Request Should Be Successfull can use the last response, no need to pass the response anymore!

GET  https://www.google.com
Status Should Be  200

What's new in 0.8

New keywords structure: All requests keywords have been rewritten because of many not backward compatible changes and to allow in the near future requests keywords without a session. Example Get Request become GET On Session and soon there will be also just GET when a session is not needed. Old keywords * Request are now deprecated and will be removed in 1.0.0 version.

Implicit assert on status code: * On Session keywords automatically fail if an error status code is returned. expect_status= could be used to specify a status code (201, OK, Bad request) or any if you want to evaluate the response in any case.

Closer to the original Requests library: New keywords have the same parameter orders and structure as the original. Lot of pre-parsing / encoding has been removed to have a more accurate and unchanged behaviour.

Cleaner project architecture: Main keywords file has been split with a more logic division to allow better and faster maintenance.

🤖 More examples

*** Settings ***                                                                                       
Library    Collections                                                                                 
Library    RequestsLibrary                                                                             
                                                                                                       
Suite Setup    Create Session  jsonplaceholder  https://jsonplaceholder.typicode.com                   
                                                                                                       
*** Test Cases ***                                                                                     
                                                                                                       
Get Request Test                                                                                       
    Create Session    google  http://www.google.com                                                    
                                                                                                       
    ${resp_google}=   GET On Session  google  /  expected_status=200                                   
    ${resp_json}=     GET On Session  jsonplaceholder  /posts/1                                        
                                                                                                       
    Should Be Equal As Strings          ${resp_google.reason}  OK                                      
    Dictionary Should Contain Value     ${resp_json.json()}  sunt aut facere repellat provident        
                                                                                                       
Post Request Test                                                                                      
    &{data}=    Create dictionary  title=Robotframework requests  body=This is a test!  userId=1       
    ${resp}=    POST On Session    jsonplaceholder  /posts  json=${data}  expected_status=anything     
                                                                                                       
    Status Should Be                 201  ${resp}                                                      

📖 Keywords documentation

Robotframework-requests offers a wide set of keywords which can be found in the Keywords documentation

🔬 Test examples

You can find many test examples inside the atests folder.

🤝 Contributing ✍️

Feel free to contribute and open an issue in order to discuss it. Before doing it take a look at the contribution guidelines.

📢 Get in touch with the community via slack and Users group

robotframework-requests's People

Contributors

accesslubos avatar adrianyorke avatar andreagubellini avatar arbulu89 avatar asyrjasalo avatar brucelau-github avatar bulkan avatar caos-maker89 avatar ggrossetie avatar gtoselli avatar ineiros avatar jaloren avatar jstaffans avatar laurentbristiel avatar lsjuanny avatar lucagiove avatar mmikirtumov avatar nicomincuzzi avatar oleduc avatar robinmatz avatar roimvargas avatar svyzz avatar sylvainde avatar tguevin avatar tvainika avatar uvv-gh avatar vkosuri avatar volinthius avatar wolfe1 avatar yanbilik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

robotframework-requests's Issues

get() function uri.strip('/') should uri.strip('') ?

20130910 16:48:40.440 : INFO : ${headers} = {u'charset': u'UTF-8', u'Content-Type': u'application/x-www-form-urlencoded'}
20130910 16:48:40.441 : TRACE : Arguments: [ u'chopper' | u'/api/basic/model/list/' | {u'charset': u'UTF-8', u'Content-Type': u'application/x-www-form-urlencoded'} ]
20130910 16:48:40.458 : DEBUG : "GET /api/basic/model/list HTTP/1.1" 301 281
20130910 16:48:40.477 : DEBUG : "GET /basic/model/list/ HTTP/1.1" 404 378
20130910 16:48:40.478 : TRACE : Return: <Response [404]>
20130910 16:48:40.478 : INFO : ${resp} = <Response [404]>
20130910 16:48:40.479 : TRACE : Arguments: [ 404 | u'200' ]
20130910 16:48:40.479 : INFO :
Argument types are:
<type 'int'>
<type 'unicode'>
20130910 16:48:40.481 : FAIL : 404 != 200
20130910 16:48:40.481 : DEBUG :
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\robot\libraries\BuiltIn.py", line 550, in should_be_equal_as_strings
self._should_be_equal(first, second, msg, values)
File "C:\Python27\lib\site-packages\robot\libraries\BuiltIn.py", line 414, in _should_be_equal
self._include_values(values))
File "C:\Python27\lib\site-packages\robot\utils\asserts.py", line 181, in fail_unless_equal
_report_unequality_failure(first, second, msg, values, '!=')
File "C:\Python27\lib\site-packages\robot\utils\asserts.py", line 244, in _report_unequality_failure
_report_failure(msg)
File "C:\Python27\lib\site-packages\robot\utils\asserts.py", line 230, in _report_failure
raise AssertionError(msg)

AttributeError: 'unicode' object has no attribute 'items'

Hi,
I don't have a request API testing experience so I am new in this field.
I am trying to post a request which contains huge data in input xml
I have created a testcase for post

Create Session httpbin aaa
${resp}= Post httpbin 'Content-Type':'application/xml'
Should Be Equal As Strings ${resp.status_code} 200

When I am trying to run the test case, getting error as "AttributeError: 'unicode' object has no attribute 'items'".

Can you figure out the problem?

Thanks in advance.

Fail to import RequestLibrary in ride editor

I have installed RequestsLibrary using following command - pip install -U robotframework-requests and have added the same in my environment variable and then tried to import in ride editor.

but somehow its not working and coming in RED color which means, there is some error, may be in installation or configuration. At the same, i tried similar steps with another robot library and it was working fine.
so, please help me to install or let me if i need to perform any additional steps.

Extraneous text added to top of XML POST payload

I am getting extra text at the start of my XML file that is causing the XML parser to choke on the POST payload.

Here is my RobotFramework code:
${file_data} Get File ${CURDIR}${/}myFile.xml
${fileDictionary}= Create Dictionary file1 ${file_data}

Create Session my_session ${server}

#Build Request
Set Test Variable ${requestURL} /destination

#Create headers
${headers}= Create Dictionary Authorization clientID
#Send request

${result}= RequestsLibrary.POST my_session ${requestURL} headers=${headers} files=${fileDictionary}

The server logs show the following text appearing before the XML file as part of the payload, and as a result the request is rejected:

8300748641ff46e1a8c03b78a3c58971
Content-Disposition: form-data; name="file1"; filename="file1"
Content-Type: application/octet-stream

How can I keep this text out of the POST payload?

Thanks,
Anders

Resetting dropped connection

Hi,

I am frequently getting Resetting dropped connection from my UUT, are we reusing the same HTTP session?

Any other methods to avoid this this error?

A snapshot from robot test log

resettingdropped

Thanks
Malli

Delete method giving error "TypeError: not a valid non-string sequence or mapping object"

*** Variables ***
${JSON_DATA} {file:{path:"/logo1.png"},"token":"some-valid-oauth-token"}

Create Session test http://some-test-api.com
${headers} Create Dictionary Content-Type application/json
${resp}= Delete test /delete data=${JSON_DATA} headers=${headers}
${jsondata}= To Json ${resp.content}

Fails on third line above with "TypeError: not a valid non-string sequence or mapping object"

Is this something related to keywords.py file not having "data=data" in delete definition on line no. 180 unlike post & put, just a guess?

Note: Above API/JSON works perfectly when cross checked from Postman REST Client in Chrome.

${data} is very complex,so that the case run failed

test case:
${code} Convert to Integer 200
${headers} Create Dictionary Content-Type application/x-www-form-urlencoded charset UTF-8
${data} Create Dictionary boundInfo {"id":"","task_def_id":77,"name":"2013005","task_type":1,"cmd_type":2,"schedule_expr":"0 24 /1 * * *","content_type":"NONE","action":"0","config":""rep":"0","freq":"1","model":"1","datefield":"2013-09-11 17:24:00"","start_time":"2013-09-11 17:24:00","end_time":"","schedule_desc":"\u5168\u5929 \u6bcf\u5c0f\u65f6 \u7b2c24\u5206 ","script":"exp = Expect()\nexp:set_log(true)\nres = exp:open_ssh("-l", "root", "192.168.9.64")\nprint("open:" .. res);\n\nwhile 1 do\n \ res = exp:expect("password", "Are you sure you want to continue connecting")\n \ \ \ if res == 0 \ then\n \ \ \ \ \ \ exp:send("config")\n\tbreak\n \ \ \ elseif res==1 then\n \ \ \ \ \ \ exp:send("yes")\n \ \ \ else \n \ \ \ \ \ \ print("FAILED")\n \ \ \ end\nend\n\nres = exp:expect("root@.]", "again")\nprint("exp:" .. res)\n \ if res == 0 then\n \ \ \ \ print("to send")\n \ \ \ \ exp:send("touch test_lua;ls")\n \ elseif res == 1 then\n \ \ \ \ print("pwd error")\n \ else\n \ \ \ \ print("eof/timeout")\n \ end","script_graphical":"","dest_stags":"VMWARE-564D82825201906F-8EECBE1C33E28ADE","execPlan-inputEl":"on","execTimeDate":"2013-09-11 17:24","repeat":"on","modelSelect":"hourSelect","repeatFreqD-inputEl":1,"repeatFreqM-inputEl":1,"repeatFreqH-inputEl":1,"radioHour":"1","daysofWeekItems":"3","radioMonth":"1","prevDayCheck-inputEl":"1","prevOfDays-inputEl":"1","nextDayCheck-inputEl":"2","nextOfDays-inputEl":"1","radioEndtime":"1","cronValue":"0 24 */1 * * *","metadataConfig-inputEl":""rep":"0","freq":"1","model":"1"","can_runable-inputEl":"1","run_as":"root","nice":5,"level":"5","timeout":"29","desc":"2013005"}
${resp} Post chopper /api/task/bound_task/add_bound_task/ data=${data} headers=${headers}
${jsondata} To Json ${resp.content}
#Log List ${jsondata} level=TRACE
Should Be Equal As Strings ${resp.status_code} 200
#Dictionary Should Contain Value ${jsondata} ${None}
Dictionary Should Contain Value ${jsondata} ${code}
Dictionary Should Contain Value ${jsondata} ${True}
Dictionary Should Not Contain Value ${jsondata} DUPLICATE_NAME

exec rusult:
20130911 17:26:52.538 : FAIL : ValueError: Creating a dictionary failed. There should be an even number of key-value-pairs.
20130911 17:26:52.539 : DEBUG :
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\robot\libraries\Collections.py", line 449, in create_dictionary
raise ValueError("Creating a dictionary failed. There should be "

urlcode error

20130909 17:37:21.726 : TRACE : Return: {u'charset': u'UTF-8', u'Content-Type': u'application/x-www-form-urlencoded'}
20130909 17:37:21.726 : INFO : ${headers2} = {u'charset': u'UTF-8', u'Content-Type': u'application/x-www-form-urlencoded'}
20130909 17:37:21.727 : TRACE : Arguments: [ u'idcInfo' | u'{"id":"","name":"\u6d59\u6c5f\u9f50\u6cbb\u8fd0\u7ef4\u4e2d\u5fc3","abbr":"\u94f6\u4e30\u5927\u53a69\u697c","location":"\u676d\u5dde\u5e02\u6ee8\u6c5f\u533a\u6ee8\u76db\u8def1505\u53f7","admin_uid":1,"minor_admin_uid":1,"locate_engineer":"007","isp":"\u4e2d\u56fd\u7535\u4fe1","comments":"20130909-001"}' ]
20130909 17:37:21.727 : TRACE : Return: {u'idcInfo': u'{"id":"","name":"\u6d59\u6c5f\u9f50\u6cbb\u8fd0\u7ef4\u4e2d\u5fc3","abbr":"\u94f6\u4e30\u5927\u53a69\u697c","location":"\u676d\u5dde\u5e02\u6ee8\u6c5f\u533a\u6ee8\u76db\u8def1505\u53f7","admin_uid":1,"minor_admin_uid":1,"locate_engineer":"007","isp":"\u4e2d\u56fd\u7535\u4fe1","comments":"20130909-001"}'}
20130909 17:37:21.727 : INFO : ${data2} = {u'idcInfo': u'{"id":"","name":"\u6d59\u6c5f\u9f50\u6cbb\u8fd0\u7ef4\u4e2d\u5fc3","abbr":"\u94f6\u4e30\u5927\u53a69\u697c","location":"\u676d\u5dde\u5e02\u6ee8\u6c5f\u533a\u6ee8\u76db\u8def1505\u53f7"...
20130909 17:37:21.728 : TRACE : Arguments: [ u'chopper' | u'/api/basic/idc/add/' | headers={u'charset': u'UTF-8', u'Content-Type': u'application/x-www-form-urlencoded'} | data={u'idcInfo': u'{"id":"","name":"\u6d59\u6c5f\u9f50\u6cbb\u8fd0\u7ef4\u4e2d\u5fc3","abbr":"\u94f6\u4e30\u5927\u53a69\u697c","location":"\u676d\u5dde\u5e02\u6ee8\u6c5f\u533a\u6ee8\u76db\u8def1505\u53f7","admin_uid":1,"minor_admin_uid":1,"locate_engineer":"007","isp":"\u4e2d\u56fd\u7535\u4fe1","comments":"20130909-001"}'} ]
20130909 17:37:21.729 : FAIL : UnicodeEncodeError: 'ascii' codec can't encode characters in position 17-24: ordinal not in range(128)
20130909 17:37:21.729 : DEBUG :
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\RequestsLibrary\keywords.py", line 117, in post
data = urlencode(data)
File "C:\Python27\lib\urllib.py", line 1326, in urlencode
v = quote_plus(str(v))
Ending test: Chopper-Api.Api.Idc

20130909 17:37:21.730 : TRACE : Arguments: [ ]
20130909 17:37:21.730 : TRACE : Return: None

Deprication Warning Use Post Request in the future

Hello,

I am seeing this warning continuously even though i have used Post Request method

Post Entry
    [Arguments]    ${ALIAS}    ${uri}    ${data}
    [Documentation]     Create an instance of a yang list
    ${headers}=    Create Dictionary    Content-Type=application/json
    ${resp}=    Post Request    ${ALIAS}    ${uri}    data=${data}    headers=${headers}
    Run Keyword And Return If    ${resp.status_code} != 200    Append Failed Log    ${resp.status_code}
    Return From Keyword    ${True}    ${resp.json()}

Could you please suggest me did i made any mistake here?

07:59:28.111    INFO    Deprication Warning  Use Post Request in the future

Thanks
Malli

Post Request and Put Request does not support parameter passsing

I was trying to issue POST / PUT request to /uri?key=value with body in xml format but it seems that both POST and PUT request does not support passing of parameters key=value.

I have tried the following:

${resp}=    Post Request    session1    /uri    params=key=value    data=${body}

The following error is encountered:
TypeError: post_request() got an unexpected keyword argument 'params'

Is there other way to pass parameters in POST/PUT request?

max_retries applies only DNS lookups, socket connections and connection timeouts

Other than three we are seeing max_retries won't work, we have to add other meachnasim

https://github.com/kennethreitz/requests/blob/c1f51fd1002850b931aba8e25474ab753cabf687/requests/adapters.py

:param int max_retries: The maximum number of retries each connection
        should attempt. Note, this applies only to failed DNS lookups, socket
        connections and connection timeouts, never to requests where data has
        made it to the server. By default, Requests does not retry failed
        connections. If you need granular control over the conditions under
        which we retry a request, import urllib3's ``Retry`` class and pass
        that instead.

Support for setting allow_redirects param

This is not really an issue, but a request.

Have you considered support for setting the "allow_redirects" parameter? Currently, it defaults to True, but allowing false would allow some advanced test cases. Two examples are:

  1. verify that a site properly provides the expected 301 or 302 response.
  2. use the header from the 301/302 response to manually traverse the redirect sequence.

I added the support to my local copy of "robotframework-requests", but thought it may be a nice add-on in general.

Is it possible to add http debugger information for every operation

Hi

We are sending huge number of requests to NE, Sometimes it is very difficulty to find what inforamtion sent from client to server,

Is there any possibility add looger debug information for every input operation?

I found a example located for python requests

http://docs.python-requests.org/en/master/api/#api-changes

import requests
import logging

# these two lines enable debugging at httplib level (requests->urllib3->httplib)
# you will see the REQUEST, including HEADERS and DATA, and RESPONSE with HEADERS but without DATA.
# the only thing missing will be the response.body which is not logged.
import httplib
httplib.HTTPConnection.debuglevel = 1

logging.basicConfig() # you need to initialize logging, otherwise you will not see anything from requests
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

requests.get('http://httpbin.org/headers')

More inforamtion https://docs.python.org/2/library/httplib.html#httplib.HTTPConnection.set_debuglevel

Thanks
Malli

Retry decorator consumes so much time when we have large number of requests from unit

It seems to the retry decorator consumes so much time when we have large number of requests from unit, it is working fine if we have a small number requests.

Here some statistics i observed using robot profiler

With retry decorator statistics

1    0.000    0.000    0.000    0.000 RequestsKeywords.py:21(__init__)
  248    0.011    0.000  287.346    1.159 RequestsKeywords.py:217(patch_request)
102705    0.816    0.000    4.060    0.000 RequestsKeywords.py:25(_utf8_urlencode)
    4    0.000    0.000    0.002    0.000 RequestsKeywords.py:37(_create_session)
  469    0.008    0.000  431.145    0.919 RequestsKeywords.py:387(_get_request)
101988    0.002    0.000  84256.164    0.809 RequestsKeywords.py:34(f_retry)
101988    2.587    0.000 84456.164    0.828 RequestsKeywords.py:399(_post_request)
  248    0.009    0.000  287.253    1.158 RequestsKeywords.py:412(_patch_request)

Instead I used requests retry method, it was much faster than retry decorator

    if max_retries > 0:
            a = requests.adapters.HTTPAdapter(max_retries=max_retries)
            s.mount('https://', a)
            s.mount('http://', a)

without retry decorator statistics

        1    0.000    0.000    0.000    0.000 RequestsKeywords.py:21(__init__)
      248    0.011    0.000  287.346    1.159 RequestsKeywords.py:217(patch_request)
   102705    0.816    0.000    4.060    0.000 RequestsKeywords.py:25(_utf8_urlencode)
        4    0.000    0.000    0.002    0.000 RequestsKeywords.py:37(_create_session)
      469    0.008    0.000  431.145    0.919 RequestsKeywords.py:387(_get_request)
   101988    2.587    0.000 84456.164    0.828 RequestsKeywords.py:399(_post_request)
      248    0.009    0.000  287.253    1.158 RequestsKeywords.py:412(_patch_request)

@bulkan could you please comment on this?

Version 0.4.1 or 0.5.0 ?

Hi @vkosuri & @oleduc ,

I was about to publish a new version to PyPI but not sure which version number I should go with.

Was #86 a major or minor issue ?

Also @oleduc yes I would like it if you guys can help out here as I don't use RF anymore.

Not working with authenticating Proxy

The RequestsLibrary doesn't work at all behind an authenticating proxy.
The "proxies" setting parameter seems to be ignored.

The GET request is sent directly to the target host, instead of the proxy host
See the "Starting new HTTP connection" entry in the debug log

debug log:
==============================================================================
20140916 10:32:15.811 - INFO - +- START TEST: Get Ext Requests [ ]
------------------------------------------------------------------------------
20140916 10:32:15.811 - INFO - +-- START KW: RequestsLibrary.Create Session [ google | http://www.google.com | proxies= {"http": "http://myuser:[email protected]"} ]
20140916 10:32:15.812 - DEBUG - Creating session: google
20140916 10:32:15.818 - INFO - Argument types are:

20140916 10:32:15.819 - INFO - +-- END KW: RequestsLibrary.Create Session (8)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20140916 10:32:15.819 - INFO - +-- START KW: ${resp} = RequestsLibrary.Get [ google | / ]
20140916 10:32:16.021 - INFO - Starting new HTTP connection (1): www.google.com
20140916 10:34:22.022 - FAIL - ConnectionError: ('Connection aborted.', error(10060, 'A connection attempt failed because the connected party did not properly respond after a perio
d of time, or established connection failed because connected host has failed to respond'))
20140916 10:34:22.022 - DEBUG - Traceback (most recent call last):
  File "c:\Python27\lib\site-packages\RequestsLibrary\keywords.py", line 111, in get
    response = self.get_request(session, uri, headers, params)
  File "c:\Python27\lib\site-packages\RequestsLibrary\keywords.py", line 217, in get_request
    cookies=self.cookies, timeout=self.timeout)
  File "c:\Python27\lib\site-packages\requests\sessions.py", line 463, in get
    return self.request('GET', url, **kwargs)
  File "c:\Python27\lib\site-packages\requests\sessions.py", line 451, in request
    resp = self.send(prep, **send_kwargs)
  File "c:\Python27\lib\site-packages\requests\sessions.py", line 557, in send
    r = adapter.send(request, **kwargs)
  File "c:\Python27\lib\site-packages\requests\adapters.py", line 407, in send
    raise ConnectionError(err, request=request)
20140916 10:34:22.024 - INFO - +-- END KW: ${resp} = RequestsLibrary.Get (126204)
------------------------------------------------------------------------------
20140916 10:34:22.031 - INFO - +- END TEST: Get Ext Requests (126214)
------------------------------------------------------------------------------

Execution output:
==============================================================================
Get Ext Requests                                                      | FAIL |
ConnectionError: ('Connection aborted.', error(10060, 'A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond'))
------------------------------------------------------------------------------
Json                                                                  | FAIL |
1 critical test, 0 passed, 1 failed
1 test total, 0 passed, 1 failed
==============================================================================


My env - Windows 7:
> pip list
certifi (14.05.14)
chardet (2.2.1)
contextdecorator (0.10.0)
pip (1.5.6)
PyYAML (3.11)
requests (2.4.1)
robotframework (2.8.5)
robotframework-requests (0.3.7)
setuptools (5.7)
six (1.8.0)
vcrpy (1.0.3)
> python -V
Python 2.7.8

Test case steps:
    Create Session  google  http://www.google.com       proxies= {"http": "http://myuser:[email protected]"}
    ${resp}=        Get     google                      /
    Should Be Equal As Strings                          ${resp.status_code}     200 
 

I also have a RequestsLibrary running with Jython (2.5.3), and because of v2.5 compatibility I had to use very old libs (requests v0.10.0) and there I got it working (after hacking the requests lib a bit) - The above debug log entries look like this:

NOTE: Here the "Starting new HTTP connection" shows the proxy host

20140916 10:20:33.652 - INFO - +-- START TEST: Get Ext Requests [ ]
------------------------------------------------------------------------------
20140916 10:20:33.654 - INFO - +--- START KW: RequestsLibrary.Create Session [ google | http://www.google.com | proxies= {"http": "http://myuser:[email protected]"} ]
20140916 10:20:33.656 - DEBUG - Creating session: google
20140916 10:20:33.657 - INFO - Argument types are:

20140916 10:20:33.658 - INFO - +--- END KW: RequestsLibrary.Create Session (5)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20140916 10:20:33.660 - INFO - +--- START KW: ${resp} = RequestsLibrary.Get [ google | / ]
20140916 10:20:33.666 - INFO - Starting new HTTP connection (1): my.proxy.com
20140916 10:20:38.570 - INFO - Starting new HTTP connection (1): my.proxy.com
20140916 10:20:38.909 - INFO - ${resp} = 
20140916 10:20:38.910 - INFO - +--- END KW: ${resp} = RequestsLibrary.Get (5249)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20140916 10:20:38.912 - INFO - +--- START KW: BuiltIn.Should Be Equal As Strings [ ${resp.status_code} | 200 ]
20140916 10:20:38.914 - INFO - Argument types are:


20140916 10:20:38.916 - INFO - +--- END KW: BuiltIn.Should Be Equal As Strings (4)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

request for additional functionality

could you add a method like the following to allow Digest authentication?

edit
/usr/local/lib/python2.7/dist-packages/RequestsLibrary/RequestsKeywords.py
to expose the HTTPDigestAuth:

def create_digest_session(self, alias, url, auth, headers={}, cookies=None, timeout=None, proxies=None, verify=False):
   digest_auth = requests.auth.HTTPDigestAuth(*auth) if auth else None
   return self._create_session(alias, url, headers, cookies, digest_auth, timeout, proxies, verify)

Post request fail in 0.3.9 but success in 0.3.8

This is my case lines in Robot,
${policy_data} = BuiltIn.Set Variable {"jsonType":"networkpolicy","ownerId":${ownerId},"name":"${name}","description":"${desc}","type":"NetworkAccessAndSwitching"}
${output} = RequestsLibrary.Post Request new-policy, /services/config/policy/networkpolicies, headers=${headers}, data=${policy_data}

my case worked in 0.3.8, but failed in 0.3.9. I think it maybe the unicode string cause this problem.

Verify parameter should accept String value

Requests library allow to configure the CA bundle file or directory with certificates of trusted CAs with the verify parameter: http://docs.python-requests.org/en/latest/user/advanced/#ssl-cert-verification

In the _create_session function, the verify parameter is converted to boolean: https://github.com/bulkan/robotframework-requests/blob/master/src/RequestsLibrary/RequestsKeywords.py#L129

I think we should allow verify parameter to be a String value to be able to configure CA bundle.

RequestsLibrary always show in red in RIDE with an import error

Is there a reason that RequestsLibrary always shows in red with an import error?

Here is what appears in the RIDE log:

20141112 15:44:39.421 [INFO]: Started RIDE 1.3 using python version 2.7.6 with wx version 2.8.12.1 in darwin.

20141112 15:44:46.382 [WARN]: Importing test library "RequestsLibrary" failed

Traceback (most recent call last):
Importing test library 'RequestsLibrary' failed: ImportError: No module named http_client
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/RequestsLibrary/init.py", line 1, in
from keywords import RequestsKeywords
File "/Library/Python/2.7/site-packages/RequestsLibrary/keywords.py", line 3, in
import vcr
File "/Library/Python/2.7/site-packages/vcr/init.py", line 2, in
from .config import VCR
File "/Library/Python/2.7/site-packages/vcr/config.py", line 6, in
from .cassette import Cassette
File "/Library/Python/2.7/site-packages/vcr/cassette.py", line 12, in
from .patch import CassettePatcherBuilder
File "/Library/Python/2.7/site-packages/vcr/patch.py", line 8, in
from .stubs import VCRHTTPConnection, VCRHTTPSConnection
File "/Library/Python/2.7/site-packages/vcr/stubs/init.py", line 9, in
from six.moves.http_client import (
PYTHONPATH:
/Users/jerry/Downloads/RobotFramework_SwingLibrary/v1.9.1/swinglibrary-1.9.1.jar
/Library/Python/2.7/site-packages/robotide/lib/robot/libraries
/Library/Python/2.7/site-packages/robotide/lib
/usr/local/lib/wxPython-unicode-2.8.12.1/lib/python2.7/site-packages/wx-2.8-mac-unicode
/usr/local/bin
/Library/Python/2.7/site-packages/pip-1.5.6-py2.7.egg
/usr/local/lib/wxPython-unicode-2.8.12.1/lib/python2.7/site-packages
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC
/Library/Python/2.7/site-packages
/usr/local/lib/wxPython-unicode-2.8.12.1/lib/python2.7
.
/Users/jerry/trunk/robotframework/de
/Library/Python/2.7/site-packages/robotide/spec
File "/Library/Python/2.7/site-packages/robotide/spec/librarymanager.py", line 76, in _fetch_keywords
return get_import_result(path, library_args)
File "/Library/Python/2.7/site-packages/robotide/spec/libraryfetcher.py", line 20, in get_import_result
lib = TestLibrary(path, args)
File "/Library/Python/2.7/site-packages/robotide/lib/robot/running/testlibraries.py", line 37, in TestLibrary
libcode = importer.import_class_or_module(name)
File "/Library/Python/2.7/site-packages/robotide/lib/robot/utils/importer.py", line 64, in import_class_or_module
self._raise_import_failed(name, err)
File "/Library/Python/2.7/site-packages/robotide/lib/robot/utils/importer.py", line 102, in _raise_import_failed
raise DataError('\n'.join(msg))

Creating an instance of the test library 'RequestsLibrary' with no arguments failed: AttributeError: 'module' object has no attribute 'settings'

pybot testcase.txt
[ ERROR ] Invalid syntax in file '/Users/jollychang/Works/robotframework-requests/tests/testcase.txt' in table 'Settings': Creating an instance of the test library 'RequestsLibrary' with no arguments failed: AttributeError: 'module' object has no attribute 'settings'
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/robot/running/testlibraries.py", line 184, in _get_instance
return self._libcode(_self.positional_args, *_self.named_args)
File "/Users/jollychang/Works/robotframework-requests/src/RequestsLibrary/keywords.py", line 20, in init
requests.settings.base_headers['User-Agent'] = 'robotframework-requests'

�install by pip or source code is the same

Testcase updation

Due new modification changes in lib, i think it requires test cases updatation also, if so can i submit PR?

Minor typo

Line 183
Method post

`uri` to send the GET request to

should read:

`uri` to send the POST request to

TypeError: unsupported operand type(s) for -=: 'unicode' and 'int'

Observed this when i modified max_retries to some other vales, because robot values are in Unicode while passing other modules

File "/home/mkosuri/venv/local/lib/python2.7/site-packages/RequestsLibrary/RequestsKeywords.py", line 258, in post_request response = self._post_request(session, uri, data, headers, files, redir, timeout) 
File "/home/mkosuri/venv/local/lib/python2.7/site-packages/RequestsLibrary/RequestsKeywords.py", line 556, in _post_request allow_redirects=allow_redirects) 
File "/home/mkosuri/venv/local/lib/python2.7/site-packages/requests/sessions.py", line 511, in post return self.request('POST', url, data=data, json=json, **kwargs) 
File "/home/mkosuri/venv/local/lib/python2.7/site-packages/requests/sessions.py", line 468, in request resp = self.send(prep, **send_kwargs) 
File "/home/mkosuri/venv/local/lib/python2.7/site-packages/requests/sessions.py", line 576, in send r = adapter.send(request, **kwargs) 
File "/home/mkosuri/venv/local/lib/python2.7/site-packages/requests/adapters.py", line 370, in send timeout=timeout File "/home/mkosuri/yang_gen/venv/local/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 609, in urlopen _stacktrace=sys.exc_info()[2]) 
File "/home/mkosuri/venv/local/lib/python2.7/site-packages/requests/packages/urllib3/util/retry.py", line 226, in increment total -= 1

To fix this issue we need type cast max_retries into integer

if max_retries > 0:
    http = requests.adapters.HTTPAdapter(max_retries=Retry(total=int(max_retries), backoff_factor=0.10))
    https = requests.adapters.HTTPAdapter(max_retries=Retry(total=int(max_retries), backoff_factor=0.10))

Documentation html referenced in README.md out of date

The documentation referenced in the readme.md file is out of date. Should be linked to the github repo doc/RequestsLibrary.html somehow (if possible) to always be updated.

Documentation

For individual keyword documentation see the following;

http://bulkan.github.io/robotframework-requests/

You can update the documentation once checked out by going to the top directory of this repo and issuing the following command: python -m robot.libdoc src/RequestsLibrary/RequestsKeywords.py doc/RequestsLibrary.html

The latest keyword documentation checked in references several keywords that are now deprecated and shows all of the new keywords. The documentation above shows only the old keywords and doesn't mention the deprecations at all.

Support for Put request with files and Content-Type multipart/form-data

I have a server that requires files sent over a Put request to update files on the server side. Any chance of supporting files being sent over put, similar to the Post request or is there a way to send them currently? I'm not sure if this is an issue with the framework, but I know this type of request works in other applications (SoapUI and Jmeter). Test case is below.

Verify Update of a Benchmark
     [Documentation]             Verify the update benchmark functionality
     ${headers}=                 Create Dictionary    Content-Type    multipart/form-data
     ${info_content}=            Local.Get File    ${CURDIR}/../resources/benchmarkInfoUpdate.xml
     ${xccdf_content}=           Local.Get File    ${CURDIR}/../resources/sample-xccdf.xml
     ${oval_content}=            Local.Get File    ${CURDIR}/../resources/sample-oval.xml
     ${data}=                    Create Dictionary    benchmarkInfo    ${info_content}    xccdf    ${xccdf_content}    oval    ${oval_content}
     ${update_benchmark}=        HTTP.Put   ${FQDN}   /compliance/api/benchmark/${SAMPLE_ID.text}   data=${data}   headers=${headers} 
     Log To Console              ${update_benchmark.content}
     Should Be Equal As Strings  ${update_benchmark.status_code}    200
     ${update_id}=               Get Element    ${update_benchmark.content}    id
     Should Be Equal As Strings  ${update_id.text}    xccdf_com.vce._benchmark_sample    msg= Benchmark ids do not match ${update_id.text}!/n${SAMPLE_ID.text}

Error: AttributeError: 'unicode' object has no attribute 'items'

Hi,
I don't have a request API testing experience so I am new in this field.
I am trying to post a request which contains huge data in input json
I have followed all the steps given in https://github.com/bulkan/robotframework-requests/blob/master/tests/testcase.txt#L12
I have created a testcase for post

Create Session test URL
${headers} Create Dictionary Content-Type application/json
Set Suite Variable ${data} { "elementToken":"token", "matchCriteria":[{"field":"name","dataType":"string","fieldValue":"Trial", "operator": "equalTo"}], "account": { "annual.Revenue": "456666", "name": "Trial", "numberOfEmployees": "integer", "billing.Address": { "city": "Miami", "country": "US", "countyOrDistrict": "us or fl", "postalCode": "33131", "stateOrProvince": "florida", "street1": "Trade Center", "street2": "North Main rd" }, "shipping.Address": { "city": "denver", "country": "us", "countyOrDistrict": "us or co", "postalCode": "80202", "stateOr.Province": "colorado", "street1": "Main street", "street2": "101 Avenu" } } }
${resp} Post test / data=${data} header=${headers}
Should Be Equal As Strings ${resp.status_code} 200

When I am trying to run the test case, getting error as "AttributeError: 'unicode' object has no attribute 'items'".
I know it's related to ${data}
I even tried to create a list and tried to append the data but it's in vain.

Can you figure out the problem?

Thanks in advance.

dealing with expanded dictionary key-value

hi,
first off, great work on integrating this function into robot.
however, there's a slight problem that i'm running into with this lib.
is there a way to deal with JSON data whose key has extensive nested key-value pairs or even deeper nested objects?
say, by introducing a known tag or something?
e.g.:
{"data":[{"stuff":[
{"onetype":[
{"id":1,"name":"John Doe"},
{"id":2,"name":"Don Joeh"}
]},
{"othertype":[
{"id":2,"company":"ACME"}
]}]
},{"otherstuff":[
{"thing":
[[1,42],[2,2]]
}]
}]}

thanks a lot!!

Posting direct string (not dictionary) with unicode data cause UnicodeEncodeError.

Hi,
I am a beginner using this robotframework library to test my restful http api. I am trying to post a request which contains a json string data (not dictionary data) with multicodes(unicode) characters.

The case like:
++++++++++++++++++++++++++++++++++++++++++++++++++
Post With Unicode Data
Create Session httpbin http://httpbin.org
${resp} Post httpbin /post {'jsonkey':'度假村multicodes-chars'}
+++++++++++++++++++++++++++++++++++++++++++++++++++

That will cause the error [FAIL : UnicodeEncodeError: 'ascii' codec can't encode characters in position ...]
I think the encoding scripts like qq20140211202948 might be applied to the post data before it sent by session.
Does it make sence?
Thanks so much.

Get Request doesn't seem to work properly anymore

I gave version 0.4.0 a try which broke my tests. In the first place it seemed I was using the Get Request keyword in the wrong way (I was passing an URI including GET parameters which returned an error). After fixing this and using the params dictionary I got stuck with RetryExceptions. I was not able to find a reason for this. Testing the URL with a browser worked like a charm so I assume there is a bug in version 0.4.0.

GET Request throws - SSLError: ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)

From the time i have updated robotframework libraries, test scripts written in .tsv format fail all the time with the error - SSLError: ("bad handshake: SysCallError(-1, 'Unexpected EOF')",), though it was working normally earlier. Issue is arising from the RequestsLibrary when i am trying to perform a GET operation (though create session works fine to authenticate the user before performing GET operation). Here's the full traceback details for the error -

Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/RequestsLibrary/RequestsKeywords.py", line 298, in get_request
    session, uri, params, headers, redir, timeout)
  File "/Library/Python/2.7/site-packages/RequestsLibrary/RequestsKeywords.py", line 801, in _get_request
    cookies=self.cookies)
  File "/Library/Python/2.7/site-packages/requests/sessions.py", line 480, in get
    return self.request('GET', url, **kwargs)
  File "/Library/Python/2.7/site-packages/requests/sessions.py", line 468, in request
    resp = self.send(prep, **send_kwargs)
  File "/Library/Python/2.7/site-packages/requests/sessions.py", line 576, in send
    r = adapter.send(request, **kwargs)
  File "/Library/Python/2.7/site-packages/requests/adapters.py", line 447, in send
    raise SSLError(e, request=request)

I have following configuration of robot framework libraries -

Mac OSX (10.11.3)
Python (2.7.10)
openssl (1.0.2f)
requests (2.9.1)
robotframework (3.0)
robotframework-httplibrary (0.4.2)
robotframework-requests (0.4.4)
robotframework-sshlibrary (2.1.2)
pyOpenSSL (0.15.1)

Any help would be appreciated.

Parse XML data fails when parsing request content.

Given an xml file:

<![CDATA[Toinen Saksan-Tanskan sota mullisti Tanskan tulevaisuuden suurvaltana. Sota k\xc3\xa4ytiin vuonna 1864, kun saksalaisvaltiot hy\xc3\xb6kk\xc3\xa4siv\xc3\xa4t Tanskan alueelle vallatakseen Schleswig-Holsteinin.

Parsing XML from {resp.content} fails:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 484: ordinal not in range(128)

Parsing the same XML from file works as expected.

how to deal with http payload

Request URL:http://192.168.9.67/api/script/new
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:1287
Content-Type:multipart/form-data; boundary=----WebKitFormBoundarynV1mT4BonfBJ2BAS
Cookie:session=a9b4d7bc-3c33-4420-9ce3-b51438b23a4c
Host:192.168.9.67
Origin:http://192.168.9.67
Referer:http://192.168.9.67/agent/scripts?random=0.11034976411610842
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36
Request Payload
------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="id"

------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="action"

new
------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="is_binary"

0
------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="current_path"

------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="fileName"

uptime
------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="script"

!/bin/sh

uptime | awk '{printf "{"up_days":%s}\n", $3}'
------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="is_linux"

1
------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="permission_user"

6
------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="permission_group"

4
------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="permission_other"

4
------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="owner"

root
------WebKitFormBoundarynV1mT4BonfBJ2BAS
Content-Disposition: form-data; name="message"

20131220-001
------WebKitFormBoundarynV1mT4BonfBJ2BAS--
Response Headersview source
charset:utf-8
Connection:keep-alive
Content-Length:79
Content-Type:text/html; charset=utf-8
Date:Fri, 20 Dec 2013 08:00:20 GMT
Server:nginx/1.2.6
Set-Cookie:session=a9b4d7bc-3c33-4420-9ce3-b51438b23a4c; Path=/; HttpOnly

Error running pip after requests install, "ImportError: cannot import name IncompleteRead"

After installing robotframework-requests using pip on Ubuntu 14.04 I am getting an error on all pip commands after that.

sudo pip install -U robotframework-selenium2library
Traceback (most recent call last):
File "/usr/bin/pip", line 9, in
load_entry_point('pip==1.5.4', 'console_scripts', 'pip')()
File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 351, in load_entry_point
return get_distribution(dist).load_entry_point(group, name)
File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 2363, in load_entry_point
return ep.load()
File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 2088, in load
entry = import(self.module_name, globals(),globals(), ['name'])
File "/usr/lib/python2.7/dist-packages/pip/init.py", line 11, in
from pip.vcs import git, mercurial, subversion, bazaar # noqa
File "/usr/lib/python2.7/dist-packages/pip/vcs/mercurial.py", line 9, in
from pip.download import path_to_url
File "/usr/lib/python2.7/dist-packages/pip/download.py", line 25, in
from requests.compat import IncompleteRead
ImportError: cannot import name IncompleteRead

Command before this was "sudo pip install -U robotframework-requests"

If I go and remove all of the request files/directories from /usr/local/lib/python2.7/dist-packages directory, then I can run pip normally

License

Hi,

Me and my employers would like to use your software, however you have not decided on a license yet. It would be greatly appreciated if your could pick a license!

http://choosealicense.com/

Thank you.

TypeError: get_request() got an unexpected keyword argument

Encountered TypeError: get_request() got an unexpected keyword argument when url has a query parameter using the following environment:

$ pybot --version
Robot Framework 3.0 (Python 2.7.11 on linux2)

But not encountered in the following enviroment:

>pybot --version
Robot Framework 2.9.2 (Python 2.7.10 on win32)

Code:

*** Settings ***
Test Setup      Create Gateway Session

*** Keywords ***
Create Gateway Session
    Create Session          gateway         ${GATEWAY}

*** Test Cases ***
Get Categories
    ${resp}=                        Get Request             gateway     /category
    Should Be Equal As Strings      ${resp.status_code}     200

Get Categories with pageSize
    ${resp}=                        Get Request             gateway     /category?pageSize=1
    Should Be Equal As Strings      ${resp.status_code}     200

Log:

$ pybot test.robot 
==============================================================================
Test :: Test                                                                  
==============================================================================
Get Categories                                                        | PASS |
------------------------------------------------------------------------------
Get Categories with pageSize                                          | FAIL |
TypeError: get_request() got an unexpected keyword argument '/category?pageSize'
------------------------------------------------------------------------------
Test :: Test                                                          | FAIL |
2 critical tests, 1 passed, 1 failed
2 tests total, 1 passed, 1 failed
==============================================================================

Is there a workaround for this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.