Giter Site home page Giter Site logo

mongomock's Introduction

image

PyPI package PyPI license PyPI wheel status

image

What is this?

Mongomock is a small library to help testing Python code that interacts with MongoDB via Pymongo.

To understand what it's useful for, we can take the following code:

def increase_votes(collection):
    for document in collection.find():
        collection.update_one(document, {'$set': {'votes': document['votes'] + 1}})

The above code can be tested in several ways:

  1. It can be tested against a real mongodb instance with pymongo.
  2. It can receive a record-replay style mock as an argument. In this manner we record the expected calls (find, and then a series of updates), and replay them later.
  3. It can receive a carefully hand-crafted mock responding to find() and update() appropriately.

Option number 1 is obviously the best approach here, since we are testing against a real mongodb instance. However, a mongodb instance needs to be set up for this, and cleaned before/after the test. You might want to run your tests in continuous integration servers, on your laptop, or other bizarre platforms - which makes the mongodb requirement a liability.

We are left with #2 and #3. Unfortunately they are very high maintenance in real scenarios, since they replicate the series of calls made in the code, violating the DRY rule. Let's see #2 in action - we might write our test like so:

def test_increase_votes():
    objects = [dict(...), dict(...), ...]
    collection_mock = my_favorite_mock_library.create_mock(Collection)
    record()
    collection_mock.find().AndReturn(objects)
    for obj in objects:
        collection_mock.update_one(obj, {'$set': {'votes': obj['votes']}})
    replay()
    increase_votes(collection_mock)
    verify()

Let's assume the code changes one day, because the author just learned about the '$inc' instruction:

def increase_votes(collection):
    collection.update_many({}, {'$inc': {'votes': 1}})

This breaks the test, although the end result being tested is just the same. The test also repeats large portions of the code we already wrote.

We are left, therefore, with option #3 -- you want something to behave like a mongodb database collection, without being one. This is exactly what this library aims to provide. With mongomock, the test simply becomes:

def test_increase_votes():
    collection = mongomock.MongoClient().db.collection
    objects = [dict(votes=1), dict(votes=2), ...]
    for obj in objects:
        obj['_id'] = collection.insert_one(obj).inserted_id
    increase_votes(collection)
    for obj in objects:
        stored_obj = collection.find_one({'_id': obj['_id']})
        stored_obj['votes'] -= 1
        assert stored_obj == obj # by comparing all fields we make sure only votes changed

This code checks increase_votes with respect to its functionality, not syntax or algorithm, and therefore is much more robust as a test.

If the code to be tested is creating the connection itself with pymongo, you can use mongomock.patch (NOTE: you should use pymongo.MongoClient(...) rather than from pymongo import MongoClient, as shown below):

@mongomock.patch(servers=(('server.example.com', 27017),))
def test_increate_votes_endpoint():
  objects = [dict(votes=1), dict(votes=2), ...]
  client = pymongo.MongoClient('server.example.com')
  client.db.collection.insert_many(objects)
  call_endpoint('/votes')
  ... verify client.db.collection

Important Note About Project Status & Development

MongoDB is complex. This library aims at a reasonably complete mock of MongoDB for testing purposes, not a perfect replica. This means some features are not likely to make it in any time soon.

Also, since many corner cases are encountered along the way, our goal is to try and TDD our way into completeness. This means that every time we encounter a missing or broken (incompatible) feature, we write a test for it and fix it. There are probably lots of such issues hiding around lurking, so feel free to open issues and/or pull requests and help the project out!

NOTE: We don't include pymongo functionality as "stubs" or "placeholders". Since this library is used to validate production code, it is unacceptable to behave differently than the real pymongo implementation. In such cases it is better to throw NotImplementedError than implement a modified version of the original behavior.

Upgrading to Pymongo v4

The major version 4 of Pymongo changed the API quite a bit. The Mongomock library has evolved to help you ease the migration:

  1. Upgrade to Mongomock v4 or above: if your tests are running with Pymongo installed, Mongomock will adapt its own API to the version of Pymongo installed.
  2. Upgrade to Pymongo v4 or above: your tests using Mongomock will fail exactly where your code would fail in production, so that you can fix it before releasing.

Contributing

When submitting a PR, please make sure that:

  1. You include tests for the feature you are adding or bug you are fixing. Preferably, the test should compare against the real MongoDB engine (see examples in tests for reference).
  2. No existing test got deleted or unintentionally castrated
  3. The travis build passes on your PR.

To download, setup and perfom tests, run the following commands on Mac / Linux:

git clone [email protected]:mongomock/mongomock.git
pip install tox
cd mongomock
tox

Alternatively, docker-compose can be used to simplify dependency management for local development:

git clone [email protected]:mongomock/mongomock.git
cd mongomock
docker-compose build
docker-compose run --rm mongomock

If you need/want tox to recreate its environments, you can override the container command by running:

docker-compose run --rm mongomock tox -r

Similarly, if you'd like to run tox against a specific environment in the container:

docker-compose run --rm mongomock tox -e py38-pymongo-pyexecjs

If you'd like to run only one test, you can also add the test name at the end of your command:

docker-compose run --rm mongomock tox -e py38-pymongo-pyexecjs tests.test__mongomock.MongoClientCollectionTest.test__aggregate_system_variables_generate_array

NOTE: If the MongoDB image was updated, or you want to try a different MongoDB version in docker-compose, you'll have to issue a docker-compose down before you do anything else to ensure you're running against the intended version.

utcnow ~~~~

When developing features that need to make use of "now," please use the libraries utcnow helper method in the following way:

import mongomock
# Awesome code!
now_reference = mongomock.utcnow()

This provides users a consistent way to mock the notion of "now" in mongomock if they so choose. Please see utcnow docstring for more details.

Branching model

The branching model used for this project follows the gitflow workflow. This means that pull requests should be issued against the develop branch and not the master branch. If you want to contribute to the legacy 2.x branch then your pull request should go into the support/2.x branch.

Releasing

When ready for a release, tag the develop branch with a new tag (please keep semver names) and push your tags to GitHub. The CI should do the rest.

To add release notes, create a release in GitHub's Releases Page then generate the release notes locally with:

python3 -c "from pbr import git; git.write_git_changelog()"

Then you can get the relevant section in the generated Changelog file.

Acknowledgements

Mongomock has originally been developed by Rotem Yaari, then by Martin Domke <https://github.com/mdomke>. It is currently being developed and maintained by Pascal Corpet .

Also, many thanks go to the following people for helping out, contributing pull requests and fixing bugs:

  • Alec Perkins
  • Alexandre Viau
  • Austin W Ellis
  • Andrey Ovchinnikov
  • Arthur Hirata
  • Baruch Oxman
  • Corey Downing
  • Craig Hobbs
  • Daniel Murray
  • David Fischer
  • Diego Garcia
  • Dmitriy Kostochko
  • Drew Winstel
  • Eddie Linder
  • Edward D'Souza
  • Emily Rosengren
  • Eugene Chernyshov
  • Grigoriy Osadchenko
  • Israel Teixeira
  • Jacob Perkins
  • Jason Burchfield
  • Jason Sommer
  • Jeff Browning
  • Jeff McGee
  • Joël Franusic
  • Jonathan Hedén
  • Julian Hille
  • Krzysztof Płocharz
  • Lyon Zhang
  • Lucas Rangel Cezimbra
  • Marc Prewitt
  • Marcin Barczynski
  • Marian Galik
  • Michał Albrycht
  • Mike Ho
  • Nigel Choi
  • Omer Gertel
  • Omer Katz
  • Papp Győző
  • Paul Glass
  • Scott Sexton
  • Srinivas Reddy Thatiparthy
  • Taras Boiko
  • Todd Tomkinson
  • Xinyan Lu
  • Zachary Carter
  • catty (ca77y _at live.com)
  • emosenkis
  • hthieu1110
  • יppetlinskiy
  • pacud
  • tipok
  • waskew (waskew _at narrativescience.com)
  • jmsantorum (jmsantorum [at] gmail [dot] com)
  • lidongyong
  • Juan Gutierrez

mongomock's People

Contributors

baruchoxman avatar ca77y avatar davidfischer-ch avatar drewbrew avatar drorasaf avatar edengreen avatar evgenus avatar gpernot avatar guludo avatar henryykt avatar japerk avatar julierossi avatar lxy1992 avatar mdomke avatar ml-evs avatar mocramis avatar mpenkov avatar omergertel avatar oorijsonar avatar pcorpet avatar scottsexton avatar sm11963 avatar srinivasreddy avatar texuf avatar thedrow avatar touilleman avatar usrlocalben avatar vmalloc avatar ymoran00 avatar zcarter 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

mongomock's Issues

Failure to insert an instance of a class that inherits `dict` to a collection

Consider the class given below, that represents a Mongo document that knows the collection to which it belongs.
When invoking the save method of this class, pymongo handles it fine, but mongomock fails with the error:

TypeError: 'Collection' object is not callable

This is because mongomock uses deepcopy on the saved object (mongomock/__init__.py, line 200), which copies the collection member. pymongo somehow avoids this.

This is the code that raises the above error (replacing mongomock with pymongo makes the code run with no errors):

import mongomock

class Document(dict):
    def __init__(self, collection):
        self.collection = collection
        super(Document, self).__init__()
        self.save()

    def save(self):
        self.collection.save(self)

con = mongomock.Connection()
db = con['db_name']
col = db['col_name']

doc = Document(col)

Selecting a list value fails in mongomock, while succeeding in MongoDB

For example, the following queries will not return anything:
{'list_value':[] }
{'list_value' : ['abc']}

when the doc is {'list_value':['abc']}

Proposed fix:
Change the following block in filtering.py:
elif isinstance(doc_val, (list, tuple)):
if isinstance(search, ObjectId):
is_match = (search in doc_val or str(search) in doc_val)
else:
is_match = search in doc_val

To:
elif isinstance(doc_val, (list, tuple)):
if isinstance(search, ObjectId):
is_match = (search in doc_val or str(search) in doc_val or search == doc_val)
else:
is_match = (search in doc_val or search == doc_val)

Test against a real mongodb instance (compare behavior for each case)

The current test cases are good, but not good enough. It's too easy to misinterpret the mongodb behavior and have both tests and code broken.

There should be a generic case that takes a query or an update, performs it on both mongomock and the real collection, and compares the results with certain comparison rules (e.g. ignore id differences).

SONManipulator support

How do I add SONManipulator to the mock collection instance?
In my project, using PyMongo, I have SONManipulator to store/retrieve a custom object.
When I used the mongomock, mock collection instance was not able to hit the manipulator methods.

Here is the code I want to run tests against. Not sure how do I add the SONManipulator to mongomock collection

class Transform(SONManipulator):     
 def transform_incoming(self, son, collection):
    for (key, value) in son.items():
        if isinstance(value, Custom):
            son[key] = CustomRepository.encode_custom(value)
        elif isinstance(value, dict):  # Make sure we recurse into sub-docs
            son[key] = self.transform_incoming(value, collection)
    return son

 def transform_outgoing(self, son, collection):
    for (key, value) in son.items():
        if isinstance(value, dict):
            if "_type" in value and value["_type"] == "custom":
                son[key] = CustomRepository.decode_custom(value)
            else:  # Again, make sure to recurse into sub-docs
                son[key] = self.transform_outgoing(value, collection)


  class CustomRepository(object):
  def __init__(self):
     client = MongoClient('mongodb://localhost:27017')
     db = client['custom']
     db.add_son_manipulator(Transform())
     self._custom_collection = db.custom

Support for $elemMatch

Exactly as it is said in the title - elemMatch either doesn't work, or works differently from pymongo.

New release

Is there any chance of a new release? It would be much appreciated.

There are features in the repo that aren't in the current PyPI release. It would be great to be able to use some of them...

Cheers

'distinct' does not support array fields

In mongodb, 'distinct' on an array field returns all the different values of the members of the arrays.
E.g. on the following collection distinct would return [1,2,3,4]
{'_id':..., 'val' : [1,2,3]},
{'_id'...., 'val : [2,3,4]}

Collection map_reduce does not handle ObjectId fields

When running map_reduce on a collection, and using a field that is an ObjectId, the returned results do not preserve the ObjectId values.

This is since the json.dumps converts such values to the following:

doc = json.dumps({'rel_id':ObjectId('52530aae4e950d1fe0669036')}, default=js
on_util.default)
doc
'{"rel_id": {"$oid": "52530aae4e950d1fe0669036"}}'

Then, in the 'emit' function in doMap, the above dictionary value is used as a key, and javascript implicitly converts it into a '[object Object'] string.

I've implemented the following patch, but maybe a better fix can be made...

  1. Replacing 'emit' with the following implementation:
    function emit(key, val) {
    if (key['$oid']) {
    mapped_key = '$oid' + key['$oid'];
    }
    else {
    mapped_key = key;
    }
    if(!mappedDict[mapped_key]) {
    mappedDict[mapped_key] = [];
    }
    mappedDict[mapped_key].push(val);
    }
  2. After receiving reduced_rows, do the conversion back to ObjectId:
    reduced_rows = reduce_ctx.call('doReduce', reduce_func, mapped_rows)[:limit]
    for reduced_row in reduced_rows:
    if reduced_row['_id'].startswith('$oid'):
    reduced_row['_id'] = ObjectId(reduced_row['_id'][4:])

Thanks!

Support generators as return values to `__getitem__` on `mongomock.collection.Cursor`

If a call to mongomock.collection.Cursor.__getitem__ expects a mongomock.collection.Cursor and gets a list (for example in mongoengine's slicing methods Model.objects.all()[start:finish]) we get an exception that list has no attribute/method next. The fix is super-easy, you just have to check here

https://github.com/vmalloc/mongomock/blob/master/mongomock/collection.py#L876

to see if the return value would be an instance of list:

    def __getitem__(self, index):
        arr = [x for x in self._dataset]
        count = len(arr)
        self._dataset = iter(arr)
        rval = arr[index]
        if isinstance(arr[index], list):
            return iter(arr[index])
        return arr[index]

There are a few other methods in the Cursor class that could use a little refactoring. distinct, for example, might be better as (for the same reason):

    def distinct(self, key):
        if not isinstance(key, basestring):
            raise TypeError('cursor.distinct key must be a string')
        unique = set()
        for x in iter(self._dataset):
            value = _resolve_key(key, x)
            if value == NOTHING: continue
            unique.add(value)
        self._dataset = (x for x in unique)
        return self

the $or condition for find()

I ran into trying to test with the $or condition not realizing it's not being accounted for.

I almost started writing a solution before I noticed this is an interesting problem, possibly requiring recursiveness. I was going to go only as far as simple fields, but I'm running out of time.

Has anyone come up with an idea on this?

$set on item in nested array does not work

Hi, I have mongo collection my_collection where each item has array with posts.
Looks like this:

{
    _id: ObjectId(),
    posts: [
        {
            _id: ObjectId(),
        }, 
        ...
    ]
}

If I want to set post as read like this:

my_collection.update(
    {'_id': <ObjectId>, 'posts._id': <ObjectId>},
    {'$set': {'posts.$.read': datetime.now()}}
)

I get following error:

Traceback (most recent call last):
  File "mongotest.py", line 16, in <module>
    {'$set': {'posts.$.read': 1}}
  File "/root/.venvs/mongotest/local/lib/python2.7/site-packages/mongomock/collection.py", line 95, in update
    self._update_document_fields(existing_document, v, _set_updater)
  File "/root/.venvs/mongotest/local/lib/python2.7/site-packages/mongomock/collection.py", line 344, in _update_document_fields
    self._update_document_single_field(doc, k, v, updater)
  File "/root/.venvs/mongotest/local/lib/python2.7/site-packages/mongomock/collection.py", line 384, in _update_document_single_field
    doc = doc.setdefault(part, {})
AttributeError: 'list' object has no attribute 'setdefault'

I believe that problem is with posts.$.read. MongoMock expects number not `$.

Full example:

# Install dependencies:
#     pip install mongomock pymongo

import mongomock
from bson.objectid import ObjectId

my_collection = mongomock.Connection().db.my_collection

post_id = ObjectId()
my_collection.insert({'posts': [{'_id': post_id}]})
item = my_collection.find_one()

my_collection.update(
    {'_id': item['_id'], 'posts._id': post_id},
    {'$set': {'posts.$.read': 1}}
)

New release

It's 6 month and 54 commits since last release, with some compatibility fixes (insert optional keywords, etc.), so new release would be great.

`distinct` method doesn't work with nested fields

The following code prints a list containing 1 item ('value') with pymongo, but an empty list when using mongomock.

import mongomock

con = mongomock.Connection()
db = con['db_name']
col = db['col_name']

col.remove()
col.insert({'field1': {'field2': 'value'}})

print(col.find().distinct('field1.field2'))

Misbehavior of upsert with '$set'

Pymongo behavior

from pymongo import Connection
c = Connection()
db = c['test']
db.test.update({'_id':123}, {'$set': {'other': 'thing'}}, upsert=True)
print(list(db.test.find()))

[{u'_id': 123, u'other': u'thing'}]

Mongomock behavior

from mongomock import Connection
c = Connection()
db = c['test']
db.test.update({'_id':123}, {'$set': {'other': 'thing'}}, upsert=True)
print(list(db.test.find()))

 [{'$set': {'other': 'thing'}, '_id': ObjectId('50db6d14421aa928b66f7ff0')}]

$set {'prop.subprop':value}

from the mongodb docs http://docs.mongodb.org/manual/core/update/
db.bios.update(
{ _id: 1 },
{
$set: { 'name.middle': 'Warner' },
}
)

should result in

{
'_id':1
'name'{
'middle':'Warner'
}
}

instead we get

{
'_id':1
'name.middle':'Warner'
}

I'd love to implement this but I'm at a bit of a loss at how to implement it properly. Any tips?

mongomock allows non-string keys

While pymongo doesn't. Actually BSON allows only strings as document/object keys. Using mongomock only I have managed to store dictionaries having tuple keys. This ceased to work when I switched to pymongo for "real" database operations.

pymongo sends errors like this:
<class 'bson.errors.InvalidDocument'>, InvalidDocument('documents must have only string keys, key was (157, 1)',)

Add support for find_and_modify remove kwarg

Ran into this today. The original document is being returned when using the remove and new kwarg...for example:

...find_and_modify(query=query, remove=True)

It causes the following exception:

  File "/Users/paul4611/python-virtualenvs/quasar/lib/python2.7/site-packages/mongomock/__init__.py", line 349, in find_and_modify
    self.update({'_id':old['_id']}, update)
  File "/Users/paul4611/python-virtualenvs/quasar/lib/python2.7/site-packages/mongomock/__init__.py", line 214, in update
    for k, v in iteritems(document):
  File "/Users/paul4611/python-virtualenvs/quasar/lib/python2.7/site-packages/six.py", line 439, in iteritems
    return iter(getattr(d, _iteritems)(**kw))
AttributeError: 'NoneType' object has no attribute 'iteritems'

Missing import in collection.py (_print_deprecation_warning)

ERROR: test_delete (main.ExampleModuleBaseTestCase)

Test of example deletion

Traceback (most recent call last):
File "test.py", line 214, in test_delete
res = self.simulate_delete(path='/example/%s' % 1)
File "test.py", line 131, in simulate_delete
return self.simulate_request(_args, *_kwargs)
File "/home/(...)/lib/python2.7/site-packages/falcon/testing/base.py", line 87, in simulate_request
self.srmock)
File "/home/(...)/local/lib/python2.7/site-packages/falcon/api.py", line 96, in call
responder(req, resp, **params) # pragma: no cover
File "/home/(...)", line 43, in on_delete
self.collection.remove(license, True)
File "/home/(...)/local/lib/python2.7/site-packages/mongomock/collection.py", line 441, in remove
_print_deprecation_warning('search_filter', 'spec_or_id')
NameError: global name '_print_deprecation_warning' is not defined

subselects in list of dicts do not find anything

MongoDB allows searching for a dict inside a list by the dict's keys like this:

> db.test4.insert( { a: [ { b:1, c:2 } ] } )
> db.test4.findOne( { "a.b": 1 } )
{
    "_id" : ObjectId("52c53cb5f9f1bf9d36ef1cf0"),
    "a" : [
        {
            "b" : 1,
            "c" : 2
        }
    ]
}

MongoMock seems to have trouble with that:

db['test4'].insert({'a': [ {'b': 1, 'c': 2} ]})
record = db['test4'].find_one({'a.b': 1})

The above code returns None with MongoMock (but returns the inserted record with PyMongo).

Please let me know if I can help any further...

TypeError: find() got an unexpected keyword argument 'slave_okay'

use mongomock to mock mongoengine Document. it works great with this exception:

from mymodel import Post
from mongomock import Connection
Post._collection = Connection().db.collection
Post._get_db = lambda: Post._collection._Collection__database

post = Post(title='hahah')
post.save()
assert( Post._collection.count() == 1)

Post.objects.first()

the last line raises:

mongoengine/queryset/queryset.pyc in _cursor(self)
   1203 
   1204             self._cursor_obj = self._collection.find(self._query,
-> 1205                                                      **self._cursor_args)
   1206             # Apply where clauses to cursor
   1207             if self._where_clause:

TypeError: find() got an unexpected keyword argument 'slave_okay'

Include an implemented and missing features list to README

It would be great for potential users to be able to quickly see which MongoDB features are implemented and which are missing so they know whether mongomock will be usable for all of their test cases. README seems like a good place for this.

Support for $push

In Collection.update(), I see a check for $pull, but I don't see anything for $push. Any intention to add this functionality soon?

P.S. I really appreciate the work that you've done so far. This package is amazing and makes testing so much simpler. Thank you!!!

P.P.S. I'm not super-well-versed in python, else I would definitely help out. I'm more than happy to help where I can though.

Collection.map_reduce adds to an existing 'out' result collection, without cleaning it first

MongoDB behavior is to clean the 'out' collection, before filling it with the map_reduce results.
The current mongomock behavior results in adding subsequent map-reduce calls results to the same output collection, if the collection name is reused.

I believe that the fix is to add 'out_collection.drop()' in the following block of code in collection.py:

    if isinstance(out, (str, bytes)):
        out_collection = getattr(self._Collection__database, out)
        out_collection.drop()
        out_collection.insert(reduced_rows)

Querying on a member of a list of ObjectIds does not behave as expected

See the following example:

doc = {'rel_id' : [ObjectId('52d669dcad547f059424f783')]}
doc
{'rel_id': [ObjectId('52d669dcad547f059424f783')]}
filter_applies({'rel_id':ObjectId('52d669dcad547f059424f783')}, doc)
False

In MongoDB this would be matched.

I think the bug is in the following lines in filtering.py:
elif isinstance(doc_val, (list, tuple)):
if isinstance(search, ObjectId):
is_match = str(search) in doc_val
else:
is_match = search in doc_val

If it is an ObjectId, you probably need to search it BOTH as a string, and as a regular value...

Return fields with dots

When passing fields list to find(), if a field name contains dots, it is not returned.
For example:

colc.insert({'a':{'b':1}})
colc.find(fields = ['a.b']) # returns {}

New release, please!

It looks like there's been a lot of progress since you released 1.0.1. Could you release a new version to PyPi after my pull request gets resolved?

Thanks! I don't know what I'd do without this project.

Add GridFS mock

I'm using this library to our production code, woking well for tests of pure mongo. : )

However, I cannot test code using gridfs.GridFS.

So, I want GridFS mock functions.

Best.
Kawasaki

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.