Git Product home page Git Product logo

pydifact's Introduction

pydifact

A Python library to parse and serialize UN/EDIFACT interchanges.

Preamble

This is a port of metroplex-systems/edifact to Python. Thanks here at the start to Craig Duncan for this cool piece of software. Porting was like a breeze due to the high code quality there. All credits for the initial code here go to him, I just did the translation to Python(3), some "pythonifications" of the code and little improvements.

Why another EDIFACT library?

Because I did not find a decent UN/EDIFACT library for Python, so I decided to port one of the available good PHP libraries to Python. Here is the result.

ATM this is a Work In Progress, the API is not stable yet. Feel free to help.

Install

As usual, use a virtualenv, and install via pip or pipenv:

pip install pydifact

However, it is not stable yet, so the pypi version, including documentation and code examples, could differ from the latest git code. If in doubt, use the git version:

git clone https://github.com/nerdocs/pydifact.git
cd pydifact
pip install -e .

Usage

To read a full Interchange from a file or string, take the Interchange class and iter over the messages and segments:

from pydifact.segmentcollection import Interchange

interchange = Interchange.from_file("./tests/data/wikipedia.edi")
interchange = Interchange.from_str(
    "UNA:+,? '"
    "UNB+UNOC:1+1234+3333+200102:2212+42'"
    "UNH+42z42+PAORES:93:1:IA'"
    "MSG+1:45'"
    "IFT+3+XYZCOMPANY AVAILABILITY'"
    "ERC+A7V:1:AMD'"
    "UNT+5+42z42'UNZ+2+42'"
)
for message in interchange.get_messages():
    for segment in message.segments:
        print("Segment tag: {}, content: {}".format(segment.tag, segment.elements))

You may also want to iterate directly on segments :

from pydifact.segmentcollection import Interchange

interchange = Interchange.from_str(
    "UNA:+,? '"
    "UNB+UNOC:1+1234+3333+200102:2212+42'"
    "UNH+42z42+PAORES:93:1:IA'"
    "MSG+1:45'"
    "IFT+3+XYZCOMPANY AVAILABILITY'"
    "ERC+A7V:1:AMD'"
    "UNT+5+42z42'UNZ+2+42'"
)

for segment in interchange.segments:
    print("Segment tag: {}, content: {}".format(segment.tag, segment.elements))

Or you can create an EDI interchange on the fly:

from pydifact.segmentcollection import Interchange
from pydifact.segments import Segment

interchange = Interchange(syntax_identifier=("IBMA",1),
                          sender="MeMyselfAndIrene",
                          recipient="TheOtherOne",
                          control_reference="KLuzs7c6")
interchange.add_segment(Segment("QTY", ["12", "3"]))

print(interchange.serialize())

You may also want to parse a « raw » segment bunch which is not an interchange :

from pydifact.segmentcollection import RawSegmentCollection

collection = RawSegmentCollection.from_str("UNH+1+ORDERS:D:96A:UN:EAN008'")

for segment in collection.segments:
    print("Segment tag: {}, content: {}".format(segment.tag, segment.elements))

Limitations

  • No support of optional functional groups (UNGUNE),

Alternatives

In python ecosystem:

  • python-edifact - simpler, IMHO less cleaner code, less flexible. may be faster though (not tested). Seems unmaintained.
  • bots - huge, with webinterface (bots-monitor), webserver, bots-engine.
  • edicat - simple, only for separating lines/segments for CLI-piping.

Development

Setup

To develop pydifact, clone the repository and install the dev requirements:

pip install -e .[dev]

This installs all the python packages needed for development and testing.

Code formatting

Format all python files using black before committing.

Happy coding, PR are more than welcome to make this library better, or to add a feature that matches your needs. Nevertheless, don't forget adding tests for every aspect you add in code.

Testing

pydifact uses pytest for testing. Just exec pytest within the project folder to execute the unit tests. Make sure you installed the library properly before using pip install -e .[dev].

There is one test to check the performance of parsing huge files, named test_huge_message - you can skip that test by calling

pytest --ignore tests/test_huge_message.py

This is recommended for fast testing.

License

This library is licensed under the MIT license, see the LICENSE file.

pydifact's People

Contributors

bloodywing avatar dependabot[bot] avatar jocelyndelalande avatar julian-r avatar karelverschraegen avatar maanas avatar mj0nez avatar mohan3d avatar nerdoc avatar nimarb avatar patrickenglert avatar qwyk avatar ronrademaker avatar sydneyuni-jim avatar theangryangel 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

pydifact's Issues

Python <= 3.7 compat broken with 0.1.4 ?

Platform : Debian buster.

  • If I'm using pydifact 0.1.3 with Python 3.7 everything is fine.
  • If using pydifact 0.1.4 with Python 3.9 everything is fine
  • If using pydifact 0.1.4 with python 3.7 it crashes at import time with this stacktrace :
    from pydifact.segmentcollection import RawSegmentCollection
/usr/local/lib/python3.7/dist-packages/pydifact/__init__.py:23: in <module>
    from pydifact import segmentcollection, parser, segments, serializer, token, tokenizer
/usr/local/lib/python3.7/dist-packages/pydifact/segmentcollection.py:37: in <module>
    class AbstractSegmentsContainer:
/usr/local/lib/python3.7/dist-packages/pydifact/segmentcollection.py:95: in AbstractSegmentsContainer
    self, name: str, predicate: Callable[[Segment], bool] = None
E   TypeError: 'ABCMeta' object is not subscriptable

Issue on UNZ segment

Hello
I've recently reinstall pydifact with PyPI.
My programm load a file, do some changes in data and serialize.

All was working with version pydifact-0.0.5. Edifact is parsed ok by my banking software.
But with the last version, when i load an existing edifact file with from_file() and then serialize, my bank software reports error during controls.

UNZ in the original file is : 'UNZ+1+XXXDVINT'
In the serialized file, the function get_footer_segment changes the value by : 'UNZ+17+XXXDVINT'
I not sure (i am not an edifact expert...) but second value should be 1 and not 17.
Maybe the function should only count UNH segment ?

Thanks

Parser drops UNA Segments while converting tokens to segments

Consider an interchange like

UNA:+.? '
UNB+UNOC:1+1234+3333+200102:2212+42'
UNH+42z42+PAORES:93:1:IA'
UNT+2+42z42'
UNZ+1+42'

While the Parser correctly uses the given control characters to convert the tokens to Segments, it does not pass on the UNA Segment to the created Interchange. Therefore, the interchange has no knowledge of any from the default set differing characters:

./tests/test_segmentcollection.py::test_interchange_with_custom_character Failed: [undefined]AssertionError: assert ',' == '.'
  - .
  + ,
def test_interchange_with_custom_character():
        i = Interchange.from_str(
            "UNA:+.? '"
            "UNB+UNOC:1+1234+3333+200102:2212+42'"
            "UNH+42z42+PAORES:93:1:IA'"
            "UNT+2+42z42'"
            "UNZ+1+42'"
        )
>       assert i.characters.decimal_point == "."
E       AssertionError: assert ',' == '.'
E         - .
E         + ,

tests\test_segmentcollection.py:264: AssertionError

or that an UNA segment was parsed:

./tests/test_segmentcollection.py::test_interchange_with_una Failed: [undefined]assert False
 +  where False = <pydifact.segmentcollection.Interchange object at 0x0000010EF8F34B50>.has_una_segment
def test_interchange_with_una():
        i = Interchange.from_str(
            "UNA:+,? '"
            "UNB+UNOC:1+1234+3333+200102:2212+42'"
            "UNH+42z42+PAORES:93:1:IA'"
            "UNT+2+42z42'"
            "UNZ+1+42'"
        )
>       assert i.has_una_segment
E       assert False
E        +  where False = <pydifact.segmentcollection.Interchange object at 0x0000010EF8F34B50>.has_una_segment

tests\test_segmentcollection.py:253: AssertionError

The docstring of convert_tokens_to_segments hints, that passing information of any parsed UNA was intended but has not been implemented yet.

Code example in README not working / import failing

Hi,

I tried to play around a little bit with pydifact but I seem to be unable to get it to run.

I successfully installed it via pip on Windows. When I then try to run the example from the README I get the following error:

Traceback (most recent call last):
  File "g:/test.py", line 1, in <module>
    from pydifact.segmentcollection import SegmentCollection
ModuleNotFoundError: No module named 'pydifact.segmentcollection'

Could you please help me on how to proceed?

Remove old Python(3.5) compatibility

All format strings could be changed into f-Strings - but due to @theangryangel's requirements in a project (see PR), compatibility to Python 3.5 will be maintained until this project is upgraded.

This issue can be closed after his requirement is upgraded.
BTW @theangryangel - what would be nice: a git pre-commit hook that checks compatibility with Python 3.5... or a CI with a Python 3.5 environment... Just if you find time.

Apply fixes for Segmentfactory and Pluginmount

Hey,
first, thanks for this amazing library, it has helped us a lot. I have noticed, that the in #37 proposed changes introduced more than a mapping functionality. With 23f218d fixes for the PluginMount and the SegmentFactory were introduced, which allow the inheritance based extension of Segment, while correctly evaluating the __omitted__ attribute.

With the current release this code

class TestSegment(Segment):

    tag = "TES"

    __omitted__ = False

    def validate(self) -> bool:
        pass


def test_has_plugin():
    plugins = SegmentProvider.plugins
    assert TestSegment in plugins

fails with

./tests/test_segment.py::test_has_plugin Failed: [undefined]assert TestSegment in []
def test_has_plugin():
        plugins = SegmentProvider.plugins
>       assert TestSegment in plugins
E       assert TestSegment in []

tests\test_segment.py:66: AssertionError

Could we merge those changes prior to the mapping extension? I will provide the necessary commits, but the credits belong to @theangryangel.

running the example outputs nothing

Hi,

this is the example, changed sligtly, it shows the input message as output. But the for loop outputs nothing?
Do i maybe need a older python for this?

cat first.py
from pydifact.segmentcollection import Interchange
#interchange = Interchange.from_file("./tests/data/order.edi")
interchange2 = Interchange.from_str(
"UNA:+,? 'UNB+UNOC:1+1234+3333+200102:2212+42'UNH+42z42+PAORES:93:1:IA'UNT+2+42z42'UNZ+2+42'"
)
for message in interchange2.get_messages():
print(message)
print(message.segments)
for segment in message.segments:
print('Segment tag: {}, content: {}'.format(
segment.tag, segment.elements))

Python 3.12

I have run the test suit successfully on my machine. CI should support this from now on as well.

Change license to MIT

I decided to change the license from LGPL to a more "permissive" one like MIT. The "original" license of the php pendant is Apache 2.0 license.
A user asked me if he can use it in a commercial project. MIT helps to spread it more. People that are willing to give something back by creating a PR do that anyways. People who use software illegally do it anyways, even if restrictive, proprietary licenses forbid that.

With this change I hope more people can use this software.

Release on PyPI

I know pydifact is described as unstable, but a PyPI release would make it easier to adopt and might drive some contributors. As far as I can tell, it's not currently available.

Implement high-level containers (Message & Interchange)

In terms of high-level design and rough API, what do you think about :

# Former Message, made abstract class
class AbstractSegmentsContainer:
    @classmethod
    def from_str():
        pass
    @classmethod
    def from_file():
        pass
    @classmethod
    def from_segments():
        pass

    def get_segments():
        pass
    def get_segment():
        pass
    def add_segment():
        pass
    def serialize():
        pass

class Interchange(AbstractSegmentsContainer):
    def __init__(
            delimiters,
            timestamp,
            interchange_control_numbers,
            password_and_application_reference=None
            …
    ):
        pass

    
    def get_messages(msg_type=None):
        """
        Iterate through messages, optionaly filtering by msg_type
        """
    def get_message(msg_type=None):
        """ Same logic as get_segment"""
    

class Message(AbstractSegmentsContainer):
    def __init__(
            message_reference_number,
            message_identifier,
            common_access_reference_number=None,
            status_of_the_transfer=None,
    ):
        pass

It would allow to iterate over the segments as pydifact already does, or to go more semantically, digging Interchange−>Message->Segment.

Il let appart the functional groups for now, as they are optional, but they would fit easily in this model.

Unused property delimiters of Interchange class.

I was trying to serialize an Interchange with custom delimiters property, but it did not seem to have any effect. I was always getting UNA:+,? '. Turns out, in Interchange constructor:

    def __init__(
        self,
        sender: str,
        recipient: str,
        control_reference: str,
        syntax_identifier: Tuple[str, int],
        delimiters: Characters = Characters(),
        timestamp: datetime.datetime = None,
        *args,
        **kwargs
    ):
        super().__init__(*args, **kwargs)
        self.sender = sender
        self.recipient = recipient
        self.control_reference = control_reference
        self.syntax_identifier = syntax_identifier
        self.delimiters = delimiters
        self.timestamp = timestamp or datetime.datetime.now()

the self.delimiters property is never actually used. In serialize() method inherited from AbstractSegmentsContainer, in reality self.characters is passed into Serializer class. I believe this is just misnaming and the delimiters property in Interchange class should be renamed to characters.

New release with changes?

It seems that a lot of changes have been introduced in pydifact since the last release on pypi. Are there plans for a new 1.0 release any time soon?

module 'collections' has no attribute 'Iterable'

"import pydifact" failed as module 'collections' does not seem to have an attribute 'Iterable'.

following the error message

File "/Users/mike2/Documents/Python3/EDI1.py", line 3, in
from pydifact.segmentcollection import Interchange
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pydifact/init.py", line 23, in
from pydifact import segmentcollection, parser, segments, serializer, token, tokenizer
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pydifact/segmentcollection.py", line 382, in
class Interchange(FileSourcableMixin, UNAHandlingMixin, AbstractSegmentsContainer):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pydifact/segmentcollection.py", line 498, in Interchange
cls, segments: Union[list, collections.Iterable]
AttributeError: module 'collections' has no attribute 'Iterable'

How to implement EDIFACT Syntax elements

I just want to gather a few ideas on how to implement interchange syntax elements like UNB, UNH, UNZ etc.: Messages, Control Header, and other things.
There are syntax implemetation guidelines of the UNECE, and other sources in the internet, like here

Best thing would be to write some sort of "syntax description language" which describes these syntax elements, and parse them. There are a few possibilities for the notation of this "syntax description":

  • external files (YAML, TOML, CSV etc.)
  • python classes

I had an idea writing these descriptions as classes, like Django does this in it's ORM, describing a syntax element by a class using attributes:

class CharType(Enum):
    ALPHA = 0
    ALPHANUMERIC = 1
    NUMERIC = 2

class SyntaxElement:
    """Common description of an EDIFACT syntax element"""
    def __init__(
        self,
        id: str,
        mandatory: bool = False,
        type: CharType = None,
        length: int = None,
        max_length: int = None,
    ):
        # checks...

        self.mandatory = mandatory
        self.type = type
        self.max = False
        self.length = 0
        if length:
            self.length = length
        elif max_length:
            self.length = max_length
            self.max = True

The first bytes of an Interchange Control Header would be then:

class InterchangeControlHeader:
    syntax_identifier = SyntaxElement(
        id="0001", mandatory=True, type=CharType.ALPHA, length=4
    )
    syntax_version_number = SyntaxElement(
        id="0002", mandatory=True, type=CharType.ALPHANUMERIC, length=1
    )
    service_code_list_directory_version_number = SyntaxElement(
        id="0080", type=CharType.ALPHANUMERIC, max_length=6
    )
    character_encoding = SyntaxElement(
        id="0133", type=CharType.ALPHANUMERIC, max_length=3
    )

@JocelynDelalande what do you think about that?

Refactor the documentation

Hello,

I want to work on this project, and the first thing I'd like to do is improve the documentation. Is this OK? I have a question already, and as I read the existing documentation (and code) carefully, I'm sure I'll have lots more questions, so I'll be asking them here.

First question: Is AbstractSegmentsContainer meant to be used by the user (i.e. the developer that uses pydifact), or only by the developer (i.e. the developer that develops pydifact itself)? My opinion (and standard practice in projects such as Django) is that if it's an internal, we should not bother the user.

No documentation

Hi

I'm interested in using this module but it needs a basic HOWTO so its possible to see how to use it.

Mike

Doing .serialize() changes the UNA segment

I am running the following code:

from pydifact.message import Message
from pydifact.segments import Segment

INVOIC = Message()

def UNA():
    INVOIC.add_segment(Segment('UNA', ":+.? '"))

UNA()

result = INVOIC.serialize()

As you can see in the UNA segment, I have :+.? ' and this gets converted to :+,? ' when I run the .serialize() line.

I don't want the '.' to get converted to a ','. Is there a way around to stop this from happening?

Parser: enable configurable control characters and Parser reuse

The German energy sector uses a EDIFACT subset for market communication (edi@energy), which implements a set of control characters differing from the current defaults (see the decimal separator on p. 49 Allgemeine Festlegungen zu den EDIFACT- und XML-Nachrichten).

Currently, an UNA segment is only mandatory if any control character differs from the defaults. Therefore, parsing an edi@energy interchange without a UNA-segment is possible and results in errors.

I suggest we allow the injection of a preconfigured Parser in the creation methods FileSourcableMixin.from_file and AbstractSegmentsContainer.from_str, as well as modify the Parser to respect the following order of control characters:

  1. UNA-segment of interchange
  2. characters passed during call-time of parse
  3. preconfigured character set
  4. pydifact defaults

This would have different benefits:

  • the above-mentioned modular control characters
  • reuse of Parser objects
  • as well as enabling new parsers, e.g.:
    • While dealing with large interchanges like load profiles; a Parser which only pareses a subset of segments is especially useful, because converting all segments might take some time, but only a specific segment per message is actually required at this processing step.

I try to draft a PR for the latter one as soon as possible, but as this would be a new feature, I think we should keep it separately, for now. :)

Reference to line/byte from each segment

Btw: It would be nice if each segment had a reference to the exact input line (byte position start/end) to ease debugging. That might also help handling malformed files. (I just swapped our self-written edifact parser against pydifact and it was a pretty pleasant experience. However exact byte positions was the one feature we lost in that process.)

Originally posted by @FelixSchwarz in #24 (comment)

Handling of malformatted EDIFACT files

Hello again :)

I've continued to play a bit with pydifact and I some unexpected behaviour when feeding malformatted EDIFACT files to pydifact
I'm using the following code snippet for testing:

for segment in collection.segments:
    print('{}: {}'.format(segment.tag, segment.elements))

For example, when feeding
IMD+F++:::Item description 'for normals'
This results in the following, which is somewhat ok, although you'd have to check for the validity of each tag:

IMD: ['F', '', ['', '', '', 'Item description ']]
for normals: []

But when I feed the following, pydifact doesn't handle the input gracefully and I'm presented a TypeError:
IMD+F++:::Item description 'for :normals'
Result:

Traceback (most recent call last):
  File "g:/GitHub/file.py", line 2, in <module>
    collection = SegmentCollection.from_file("G:\\GitHub\\DESADV_line_break.txt")
  File "C:\<...>Python\Python38-32\lib\site-packages\pydifact\segmentcollection.py", line 60, in from_file
    return cls.from_str(collection)
  File "C:\<...>Python\Python38-32\lib\site-packages\pydifact\segmentcollection.py", line 70, in from_str
    return cls.from_segments(segments)
  File "C:\<...>Python\Python38-32\lib\site-packages\pydifact\segmentcollection.py", line 85, in from_segments
    return cls().add_segments(segments)
  File "C:\<...>Python\Python38-32\lib\site-packages\pydifact\segmentcollection.py", line 115, in add_segments
    for segment in segments:
  File "C:\<...>Python\Python38-32\lib\site-packages\pydifact\parser.py", line 212, in convert_tokens_to_segments
    yield self.factory.create_segment(name, *segment)
  File "C:\<...>Python\Python38-32\lib\site-packages\pydifact\segments.py", line 78, in create_segment
    return Segment(name, *elements)
  File "C:\<...>Python\Python38-32\lib\site-packages\pydifact\segments.py", line 36, in __init__
    raise TypeError("'tag' argument must be a str")
TypeError: 'tag' argument must be a str

My question is, whether this is considered a bug or rather outside of the scope of pydifact (check for syntax validity somewhere else). And following up on that, what would you consider to be the best way of checking syntax validity (with or without pydifact)?

Confusing naming of `Message`

What is called Message in pydifact is not a message in EDIFACT sense of the term.

This is realy confusing.

As pydifact does not currently handle Message Interchange and Functional group objects.

Here are some ways how pydifact.message.Message could be renamed IMHO :

  • pydifact.document.Document : "document" word as no meaning in EDIFACT
  • pydifact.SegmentCollection would be the more accurate

I know this is painful (because breaking retro-compatibility).

I could be interested (I have my own interest into doing that) into implementing those containers into pydifact, but this bug is a blocker for that.

Encoding helpers

I kinda struggle with edifact encoding, but here what I came up to :

data:

# https://blog.sandro-pereira.com/2009/08/15/edifact-encoding-edi-character-set-support/
# https://www.truugo.com/edifact/d09a/cl0001/
# A bit unsure of how 10646-1 maps exactly to utf-8
EDIFACT_ENCODINGS = {
    "UNOA": "ascii",  # iso-"646",
    "UNOB": "ascii",  # iso-"646",
    "UNOC": "iso-8859-1",
    "UNOD": "iso-8859-2",
    "UNOE": "iso-8859-5",
    "UNOF": "iso-8859-7",
    "UNOG": "iso-8859-3",
    "UNOH": "iso-8859-4",
    "UNOI": "iso-8859-6",
    "UNOJ": "iso-8859-8",
    "UNOK": "iso-8859-9",
    "UNOW": "utf-8",  # "10646-1",
    "UNOX": "iso-2022-jp",  # "2022 2375",
    "UNOY": "utf-8",  # "10646-1",
}

deserializing helper:

def guess_edifact_encoding(stream):
    unb_line = b"\n"
    eof_marker = b""
    while not unb_line.startswith(b"UNB") and unb_line != eof_marker:
        unb_line = stream.readline()

    if not unb_line.startswith(b"UNB"):
        raise ParseError("Missing UNB segment: ")

    else:
        # Must be ASCII-only
        unb_line_s = unb_line.decode()
        parser = Parser()
        unb_segment = list(parser.parse(unb_line_s))[0]
        try:
            # Ignore version, always v1…
            encoding_element = unb_segment.elements[0][0]
            return EDIFACT_ENCODINGS[encoding_element]
        except KeyError:
            raise ParseError(f"Wrong encoding spec : {encoding_element}")

I wonder what pydifact could embed in its scope in terms of :

  • helper (data)
  • serialization helper (like having a Interchange.serialize_to_bytes() helper with automatic encoding selection based on syntax identifier ?)
  • deserialization from bytes handling decoding with a guesser like the one I wrote

Any thought appreciated :-).

serialize with default characters

Hey,

unfortunately, b1215db is raising an issue in case of unspecified characters :

observed behaviour

add.segement(Segment("UNA"))
...

acess the empty elements list in the Message class:

self.characters = Characters.from_str(segment.elements[0]

suggestion

            if segment.elements:
                self.characters = Characters.from_str(segment.elements[0])

I hope that helps 😃

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.