{ "info": { "author": "yampelo", "author_email": "", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Security", "Topic :: Software Development :: Libraries" ], "description": "\n# Beagle\n\n[![Build Status](https://travis-ci.com/yampelo/beagle.svg?token=ecmfGYY44tZk69KamLJx&branch=master)](https://travis-ci.com/yampelo/beagle) [![Read The Docs](https://readthedocs.org/projects/beagle-graphs/badge/?version=latest)](https://beagle-graphs.readthedocs.io/en/latest/?badge=latest) [![Docker](https://img.shields.io/docker/cloud/build/yampelo/beagle.svg)](https://hub.docker.com/r/yampelo/beagle) [![PyPI](https://img.shields.io/pypi/v/pybeagle.svg?style=flat-square)](https://pypi.org/project/pybeagle/) [![Slack](https://img.shields.io/badge/slack-open-blue.svg)](https://join.slack.com/t/beaglegraph/shared_invite/enQtNjE1MzQyNTE3NTI3LTUzMGNhMzcwN2M5ODg3NGRmNzVmM2ZjMmU0NDk3ODEwMmRkZjEyZWIxYzU5NmM3MWMxOWU4MjVhNWEyNWVkNTI)\n\n\n\n\n\n1. [About Beagle](#about-beagle)\n2. [Installation](#installation)\n 1. [Docker](#docker)\n 2. [Python Package](#python-package)\n 3. [Configuration](#configuration)\n3. [Web Interface](#web-interface)\n 1. [Uploading Data](#uploading-data)\n 2. [Browsing Existing Graphs](#browsing-existing-graphs)\n 3. [Graph Interface](#graph-interface)\n 1. [Inspecting Nodes and Edges](#inspecting-nodes-and-edges)\n 2. [Expanding Neighbours](#expanding-neighbours)\n 3. [Hiding Nodes](#hiding-nodes)\n 4. [Running Mutators](#running-mutators)\n 5. [Toggling Node and Edge Types](#toggling-node-and-edge-types)\n 6. [Undo/Redo Action and Reset](#undoredo-action-and-reset)\n 7. [Graph Perspectives](#graph-perspectives)\n4. [Python Library](#python-library)\n5. [Documentation](#documentation)\n\n\n\n## About Beagle\n\nBeagle is an incident response and digital forensics tool which transforms data sources and logs into graphs. Supported data sources include FireEye HX Triages, Windows EVTX files, SysMon logs and Raw Windows memory images. The resulting Graphs can be sent to graph databases such as Neo4J or DGraph, or they can be kept locally as Python `NetworkX` objects.\n\nBeagle can be used directly as a python library, or through a provided web interface.\n\n
\n\n
\n\nThe library can be used either as a sequence of functional calls.\n\n```python\n>>> from beagle.datasources import SysmonEVTX\n\n>>> graph = SysmonEVTX(\"malicious.evtx\").to_graph()\n>>> graph\n\n```\n\nOr by strictly calling each intermediate step of the data source to graph process.\n\n```python\n>>> from beagle.backends import NetworkX\n>>> from beagle.datasources import SysmonEVTX\n>>> from beagle.transformers import SysmonTransformer\n\n>>> datasource = SysmonEVTX(\"malicious.evtx\")\n\n# Transformers take a datasource, and transform each event\n# into a tuple of one or more nodes.\n>>> transformer = SysmonTransformer(datasource=datasource)\n>>> nodes = transformer.run()\n\n# Transformers output an array of nodes.\n[\n ( process_guid=\"{0ad3e319-0c16-59c8-0000-0010d47d0000}\"),\n ( host=\"DESKTOP-2C3IQHO\" full_path=\"C:\\Windows\\System32\\services.exe\"),\n ...\n]\n\n# Backends take the nodes, and transform them into graphs\n>>> backend = NetworkX(nodes=nodes)\n>>> G = backend.graph()\n\n```\n\nGraphs are centered around the activity of individual **processes**, and are meant primarily to help analysts investigate activity on hosts, not between them.\n\n## Installation\n\n### Docker\n\nBeagle is available as a docker file:\n\n```bash\ndocker pull yampelo/beagle\nmkdir -p data/beagle\ndocker run -v \"$PWD/data/beagle\":\"/data/beagle\" -p 8000:8000 yampelo/beagle\n```\n\n### Python Package\n\nIt is also available as library. Full API Documentation is available on [https://beagle-graphs.readthedocs.io](https://beagle-graphs.readthedocs.io)\n\n```\npip install pybeagle\n```\n*Note: Only Python 3.6+ is currently supported.*\n\nRekall is not automatically installed. To install Rekall execute the following command instead:\n```\npip install pybeagle[rekall]\n```\n\n\n### Configuration\n\n- [Complete overview of each configuration entry](docs/configuration.md)\n\nAny entry in the [configuration file](https://github.com/yampelo/beagle/blob/master/beagle/config_templates/beagle_default.cfg) can be modified using environment variables that follow the following format: `BEAGLE__{SECTION}__{KEY}`. For example, in order to change the VirusTotal API Key used when using the docker image, you would use `-e` parameter and set the `BEAGLE__VIRUSTOTAL__API_KEY` variable:\n\n```bash\ndocker run -v \"data/beagle\":\"/data/beagle\" -p 8000:8000 -e \"BEAGLE__VIRUSTOTAL__API_KEY=$API_KEY\" beagle\n```\n\nEnvironment variables and directories can be easily defined using docker compose\n\n```docker\nversion: \"3\"\n\nservices:\n beagle:\n image: yampelo/beagle\n volumes:\n - /data/beagle:/data/beagle\n ports:\n - \"8000:8000\"\n environment:\n - BEAGLE__VIRUSTOTAL__API_KEY=$key$\n```\n\n## Web Interface\n\nBeagle's docker image comes with a web interface that wraps around the process of both transforming data into graphs, as well as using them to investigate data.\n\n### Uploading Data\n\n
\n\n
\n\nThe upload form wraps around the graph creation process, and automatically uses `NetworkX` as the backend. Depending on the parameters required by the data source, the form will either prompt for a file upload, or text input. For example:\n\n- VT API Sandbox Report asks for the hash to graph.\n- FireEye HX requires the HX triage.\n\nAny graph created is stored locally in the folder defined under the `dir` key from the `storage` section in the configuration. This can be modified by setting the `BEAGLE__STORAGE__DIR` environment variable.\n\nOptionally, a comment can be added to any graph to better help describe it.\n\nEach data source will automatically extract metadata from the provided parameter. The metadata and comment are visible later on when viewing the existing graphs of the datasource.\n\n### Browsing Existing Graphs\n\nClicking on a datasource on the sidebar renders a table of all parsed graphs for that datasource.\n\n
\n\n
\n\n### Graph Interface\n\nViewing a graph in Beagle provides a web interface that allows analysts to quickly pivot around an incident.\n\nThe interface is split into two main parts, the left part which contains various perspectives of the graph (Graph, Tree, Table, etc), and the right part which allows you to filter nodes and edges by type, search for nodes, and expand a node's properties. It also allows you to undo and redo operations you perform on the graph.\n\nAny element in the graph that has a divider above it is collapsible:\n\n
\n\n
\n\n#### Inspecting Nodes and Edges\n\nNodes in the graph display the first 15 characters of a specific field. For example, for a process node, this will be the process name.\n\nEdges simply show the edge type.\n\nA **single** click on a node or edge will focus that node and display its information in the \"Node Info\" panel on the right sidebar.\n\n###### Focusing on a Node\n\n
\n\n
\n\n###### Focusing on an Edge\n\n
\n\n
\n\n#### Expanding Neighbours\n\nA **double click** on a node will pull in any neighbouring nodes. A neighbouring node is any node connected to the clicked-on node by an edge. If there are no neighbors to be pulled in, no change will be seen in the graph.\n\n- This is regardless of direction. That means that a parent process or a child process could be pulled in when double clicking on a node.\n- Beagle will only pull in **25** nodes at a time.\n\n
\n\n
\n\n#### Hiding Nodes\n\nA **long single click** on a node will hide it from the graph, as well as any edges that depend on it.\n\n
\n\n
\n\n#### Running Mutators\n\nRight clicking on a node exposes a context menu that allows you to run [graph mutators](docs/mutators.md). Mutators are functions which take the graph state, and return a new state.\n\nTwo extremely useful mutators are:\n\n1. Backtracking a node: Find the sequence of nodes and edges that led to the creation of this node.\n - Backtracking a process node will show its process tree.\n2. Expanding all descendants: From the current node, show every node that has this node as an ancestor.\n - Expanding a process node will show every child process node it spawned, any file it may have touched, and pretty much every activity that happened as a result of this node.\n\n###### Backtracking a node\n\nBacktracking a node is extremely useful and is similar to doing a root cause infection in log files.\n\n
\n\n
\n\n###### Expanding Node Descendants\n\nExpanding a node's descendants allows you to immediately view everything that happened because of this node. This action reveals the subgraph rooted at the selected node.\n\n
\n\n
\n\n#### Toggling Node and Edge Types\n\nSometimes, a Node or Edge might not be relevant to the current incident, you can toggle edge and node types on and off. As soon as the type is toggled, the nodes or edges of that type are removed from the visible graph.\n\nToggling a node type off prevents that node type to be used when using mutators, or when pulling in neighbours.\n\n
\n\n
\n\n#### Undo/Redo Action and Reset\n\nAny action in the graph is immediately reversible! Using the undo/redo buttons you can revert any action you perform. The reset button sets the graph state to when it loaded, saving you a refresh.\n\n
\n\n
\n\n#### Graph Perspectives\n\nAs you change the graph's current state using the above action, you might also want to view the current set of visible node and edges in a different perspective. The tabs at the top of the graph screen allow you to transform the data into a variety of views:\n\n- Graph (Default perspective)\n- Tree\n- Table\n- Timeline\n- Markdown\n\nEach of the perspectives supports focusing on nodes by clicking on them.\n\n
\n\n
\n\n## Python Library\n\nThe graph generation process can be performed programmatically using the python library. The graph generation process is made up of three steps:\n\n1. `DataSource` classes parse and yield events one by one.\n2. `Transformer` classes take those inputs and transform them into various `Node` classes such as `Process`.\n3. `Backend` classes take the array of nodes, place them into a graph structure, and send them to a desired location.\n\nThe Python package can be installed via pip:\n\n```python\npip install pybeagle\n```\n\nCreating a graph requires chaining these together. This can be done for you using the `to_graph()` function.\n\n```python\nfrom beagle.datasources import HXTriage\n\n# By default, using the to_graph() class uses NetworkX and the first transformer.\nG = HXTriage('test.mans').to_graph()\n\n```\n\nIt can also be done explicitly at each step. Using the functional calls, you can also define which Backend you wish to use for example, to send data to DGraph\n\n```python\nfrom beagle.datasources import HXTriage\nfrom beagle.backends import DGraph\nfrom beagle.transformers import FireEyeHXTransformer\n\n# The data will be sent to the DGraph instance configured in the\n# configuration file\nbackend = HXTriage('test.mans').to_graph(backend=DGraph)\n\n# Can also specify the transformer\nbackend = HXTriage('test.mans').to_transformer(transformer=FireEyeHXTransformer).to_graph(backend=DGraph)\n\n```\n\nWhen calling the `to_graph` or `to_transformer` methods, you can pass in any arguments to those classes:\n\n```python\nfrom beagle.datasources import HXTriage\nfrom beagle.backends import Graphistry\n\n# Send the graphistry, anonymize the data first, and return the URL\ngraphistry_url = HXTriage('test.mans').to_graph(backend=Graphistry, anonymize=True, render=False)\n\n```\n\nYou can also manually invoke each step in the above process, accessing the intermediary outputs\n\n```python\n>>> from beagle.backends import NetworkX\n>>> from beagle.datasources import HXTriage\n>>> from beagle.transformers import FireEyeHXTransformer\n\n>>> datasource = HXTriage(\"test.mans\")\n>>> transformer = FireEyeHXTransformer(datasource=datasource)\n>>> nodes = transformer.run()\n>>> backend = NetworkX(nodes=nodes)\n>>> G = backend.graph()\n```\n\nIf you want to manually call each step, you will need to ensure that the `Transformer` class instance is compatible with the output of the provided `DataSource` class.\n\n- All Backends are compatible with all Transformers.\n\nEach data source defines the list of transformers it is compatible with, and this can be accessed via the `.transformers` attribute:\n\n```python\n>>> from beagle.datasources import HXTriage\n>>> HXTriage.transformers\n[beagle.transformers.fireeye_hx_transformer.FireEyeHXTransformer]\n```\n\n### Controlling Edge Generation\n\nBy default, edges are not condensed, that means that if a process node `u` writes to a file node `v` 5000 times, you will have 5000 edges between those nodes. Sometimes, especially when trying to visualize the data, this may overwhelm an analyst.\n\nYou can condense all 5000 edges into a single edge for that type of action (wrote in this case), by passing the backend class the `consolidate_edges=True` parameter, for example:\n\n```python\nSysmonEVTX(\"data/sysmon/autoruns-sysmon.evtx\").to_graph(NetworkX, consolidate_edges=False)\n# Graph contains 826 nodes and 2469 edges.\n\nSysmonEVTX(\"data/sysmon/autoruns-sysmon.evtx\").to_graph(NetworkX, consolidate_edges=True)\n# Graph contains 826 nodes and 1396 edges\n```\n\nBy default, the web interface will consolidate the edges.\n\n## Documentation\n\n- [REST API Overview](docs/rest_api.md)\n- [Configuration](docs/configuration.md)\n- [Developement](docs/development.md)\n- [Design Logic](docs/design_overview.md)\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/yampelo/beagle", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "pybeagle", "package_url": "https://pypi.org/project/pybeagle/", "platform": "", "project_url": "https://pypi.org/project/pybeagle/", "project_urls": { "Homepage": "https://github.com/yampelo/beagle" }, "release_url": "https://pypi.org/project/pybeagle/1.0.5/", "requires_dist": [ "ansimarkup (==1.4.0)", "atomicwrites (==1.3.0)", "attrs (==19.1.0)", "better-exceptions-fork (==0.2.1.post6)", "certifi (==2019.3.9)", "chardet (==3.0.4)", "click (==7.0)", "colorama (==0.4.1)", "coverage (==5.0a4)", "decorator (==4.4.0)", "flask-sqlalchemy (==2.3.2)", "flask (==1.0.2)", "future (==0.16.0)", "graphistry[networkx] (==0.9.63)", "grpcio (==1.20.0rc3)", "gunicorn (==19.9.0)", "hexdump (==3.3)", "idna (==2.8)", "itsdangerous (==1.1.0)", "jinja2 (==2.10.1)", "loguru (==0.2.5)", "lxml (==4.3.3)", "markupsafe (==1.1.1)", "neo4j (==1.7.2)", "neobolt (==1.7.4)", "neotime (==1.7.4)", "networkx (==2.3rc3)", "numpy (==1.16.2)", "pandas (==0.24.2)", "pluggy (==0.9.0)", "protobuf (==3.6.1)", "py (==1.8.0)", "pydgraph (==1.0.3)", "pygments (==2.3.1)", "pytest-cov (==2.6.1)", "pytest (==4.4.0)", "python-dateutil (==2.8.0)", "python-evtx (==0.6.1)", "pytz (==2018.9)", "requests (==2.21.0)", "six (==1.12.0)", "sqlalchemy (==1.3.2)", "urllib3 (==1.24.1)", "werkzeug (==0.15.2)", "more-itertools (==7.0.0) ; python_version > \"2.7\"", "rekall (==1.7.2rc1) ; extra == 'rekall'" ], "requires_python": ">=3.6.0", "summary": "Beagle is an incident response and digital forensics tool which transforms data sources and logs into graphs", "version": "1.0.5" }, "last_serial": 5329517, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "e7dc6886555b605023fa5e0464fff140", "sha256": "562b335e4c0aa0fd79165f689de1d0e51a34534142c7d8fa4947ae606609a577" }, "downloads": -1, "filename": "pybeagle-1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e7dc6886555b605023fa5e0464fff140", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=3.6.0,<3.7", "size": 62822, "upload_time": "2019-03-24T08:41:34", "url": "https://files.pythonhosted.org/packages/3a/42/82c5d35223b8fe7a8daf0de8212295d2fe59ade632cd8d6afdffb0f27de6/pybeagle-1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "db3e6525297f667c1fcc5275657fdc13", "sha256": "a5cb87c5e10cbdcbb6b7f05b456ce421104a156bbd9c1870ab337d0e43ca576d" }, "downloads": -1, "filename": "pybeagle-1.0.tar.gz", "has_sig": false, "md5_digest": "db3e6525297f667c1fcc5275657fdc13", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6.0,<3.7", "size": 52287, "upload_time": "2019-03-24T08:41:35", "url": "https://files.pythonhosted.org/packages/38/43/40b3dcfa6ff9767222de8b872f4f730abc4c274ca6147771c6caac65c332/pybeagle-1.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "c49f9b5fabcd15c59dd5bcb922a27888", "sha256": "114d4cb98d46e927cfc8c43214349b55ad1f526ba26377ea61e7d4870f16fc90" }, "downloads": -1, "filename": "pybeagle-1.0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "c49f9b5fabcd15c59dd5bcb922a27888", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=3.6.0,<3.7", "size": 62856, "upload_time": "2019-03-24T08:51:50", "url": "https://files.pythonhosted.org/packages/f3/39/9edd05357fb143d408c1311eb7a3e8c21dc78b46bc4c4af0accaa5b0bce4/pybeagle-1.0.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "12c9cae354d7c481376c6fe27aef998e", "sha256": "fe93d062ae20ef643fbeb91a39134cf6ed282ccad242c748def0b3ac326f0636" }, "downloads": -1, "filename": "pybeagle-1.0.1.tar.gz", "has_sig": false, "md5_digest": "12c9cae354d7c481376c6fe27aef998e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6.0,<3.7", "size": 52303, "upload_time": "2019-03-24T08:51:52", "url": "https://files.pythonhosted.org/packages/0d/46/22640e59e5724e34fed04149f7b274cf542fff5ff7bc66a89dc926ba80d1/pybeagle-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "28dbc2d3f8e7c8a334c24a795159acd7", "sha256": "7c13cf1bcacd32e120bc427f5f0525302a377c831f48ca5af3427d887cd3d5cd" }, "downloads": -1, "filename": "pybeagle-1.0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "28dbc2d3f8e7c8a334c24a795159acd7", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=3.6.0", "size": 72213, "upload_time": "2019-04-09T02:52:35", "url": "https://files.pythonhosted.org/packages/68/99/9c1e43d5d8159590e86880a3bdc3a3762bb2995645ff5e1667b23c673a39/pybeagle-1.0.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5c9e9356cd3aa85ef00b9447a4ad5743", "sha256": "855f0035200c97c2be3b26fd30d1de327a5c143b3cdf6f1f86cd4fb58e9911cb" }, "downloads": -1, "filename": "pybeagle-1.0.2.tar.gz", "has_sig": false, "md5_digest": "5c9e9356cd3aa85ef00b9447a4ad5743", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6.0", "size": 58979, "upload_time": "2019-04-09T02:52:37", "url": "https://files.pythonhosted.org/packages/68/93/0fc40bfb6d33f96a898219c8e6ae54650716b6d31060c1afbf8d2b84f032/pybeagle-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "e582920a2aa0e0680738da3a8c820ddb", "sha256": "1302f43f0dc91533d8b59e6c418efbd271db04aa8fba74ed92072373a4d03d49" }, "downloads": -1, "filename": "pybeagle-1.0.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e582920a2aa0e0680738da3a8c820ddb", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=3.6.0", "size": 72459, "upload_time": "2019-05-01T22:40:48", "url": "https://files.pythonhosted.org/packages/a9/33/7ec995c013d86075522d430900f6d861ad002a9ea1155ffb3a5318dca963/pybeagle-1.0.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0244b64ee6dc9504655a8d8b131c2c4a", "sha256": "d8d054dba7b622a1c3eb18b0fab42cf27dabddbbc49db04ff71c514085e051d8" }, "downloads": -1, "filename": "pybeagle-1.0.3.tar.gz", "has_sig": false, "md5_digest": "0244b64ee6dc9504655a8d8b131c2c4a", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6.0", "size": 59472, "upload_time": "2019-05-01T22:40:50", "url": "https://files.pythonhosted.org/packages/3c/18/20f7aef823fe6461eba0bf9d0d0132d5b0e991046edf110e71decd3eacea/pybeagle-1.0.3.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "1070dac5fd444dbcb3aeca12b5a49854", "sha256": "2a64bb7e41825903b5c8092a60360941366aa7823487f8e282e2e4c3727d6ac1" }, "downloads": -1, "filename": "pybeagle-1.0.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "1070dac5fd444dbcb3aeca12b5a49854", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=3.6.0", "size": 72840, "upload_time": "2019-05-28T22:54:30", "url": "https://files.pythonhosted.org/packages/dc/2f/bb7f302bfcfaab19b0c239780f35159eb892319fa6943630a16f97d87f0d/pybeagle-1.0.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "efd5f55640ce43bda725fb617f916add", "sha256": "ae4d404d63e81bd8d6c813aa41e1dd5334fd5d4fbb039a76f2e97848325f9bd3" }, "downloads": -1, "filename": "pybeagle-1.0.4.tar.gz", "has_sig": false, "md5_digest": "efd5f55640ce43bda725fb617f916add", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6.0", "size": 59905, "upload_time": "2019-05-28T22:54:32", "url": "https://files.pythonhosted.org/packages/41/30/87a3d55b9e280cbdfdb539a21f0fdb5d193a77c51918aba7ee5b7a61afbf/pybeagle-1.0.4.tar.gz" } ], "1.0.5": [ { "comment_text": "", "digests": { "md5": "d50a364745ab343f9997846967176ad7", "sha256": "b5294a391cb3b5f983334c5878ecb58045037444829b9d357b796eb6e54a86b4" }, "downloads": -1, "filename": "pybeagle-1.0.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "d50a364745ab343f9997846967176ad7", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=3.6.0", "size": 72872, "upload_time": "2019-05-28T23:34:22", "url": "https://files.pythonhosted.org/packages/0f/3d/abea88e2ec25c27ab80ff98d5a302037ce58e15735b1ad30b1ac2696abab/pybeagle-1.0.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "659fbb367da9922df10318a4601e9ac6", "sha256": "849212f0e9cc597b90de3e1fb52ad04d4db1b03f262f55581c7aeb6f97f727d2" }, "downloads": -1, "filename": "pybeagle-1.0.5.tar.gz", "has_sig": false, "md5_digest": "659fbb367da9922df10318a4601e9ac6", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6.0", "size": 59954, "upload_time": "2019-05-28T23:34:24", "url": "https://files.pythonhosted.org/packages/3a/ae/0e74ef4a8f4eae14218c5d323a59de2172719b810804023a245df6d603de/pybeagle-1.0.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d50a364745ab343f9997846967176ad7", "sha256": "b5294a391cb3b5f983334c5878ecb58045037444829b9d357b796eb6e54a86b4" }, "downloads": -1, "filename": "pybeagle-1.0.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "d50a364745ab343f9997846967176ad7", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=3.6.0", "size": 72872, "upload_time": "2019-05-28T23:34:22", "url": "https://files.pythonhosted.org/packages/0f/3d/abea88e2ec25c27ab80ff98d5a302037ce58e15735b1ad30b1ac2696abab/pybeagle-1.0.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "659fbb367da9922df10318a4601e9ac6", "sha256": "849212f0e9cc597b90de3e1fb52ad04d4db1b03f262f55581c7aeb6f97f727d2" }, "downloads": -1, "filename": "pybeagle-1.0.5.tar.gz", "has_sig": false, "md5_digest": "659fbb367da9922df10318a4601e9ac6", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6.0", "size": 59954, "upload_time": "2019-05-28T23:34:24", "url": "https://files.pythonhosted.org/packages/3a/ae/0e74ef4a8f4eae14218c5d323a59de2172719b810804023a245df6d603de/pybeagle-1.0.5.tar.gz" } ] }