{ "info": { "author": "Jarek Potiuk, Szymon Przedwojski, Kamil Bregu\u0142a, Feng Lu, Cameron Moberg", "author_email": "jarek.potiuk@polidea.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8" ], "description": "\n\n# Oozie to Airflow\n\n[![Build Status](https://travis-ci.org/GoogleCloudPlatform/cloud-composer.svg?branch=master)](https://travis-ci.org/GoogleCloudPlatform/cloud-composer)\n[![codecov](https://codecov.io/gh/GoogleCloudPlatform/cloud-composer/branch/master/graph/badge.svg)](https://codecov.io/gh/GoogleCloudPlatform/cloud-composer)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Updates](https://pyup.io/repos/github/GoogleCloudPlatform/cloud-composer/shield.svg)](https://pyup.io/repos/github/GoogleCloudPlatform/cloud-composer/)\n[![Python 3](https://pyup.io/repos/github/GoogleCloudPlatform/cloud-composer/python-3-shield.svg)](https://pyup.io/repos/github/GoogleCloudPlatform/cloud-composer/)\n\nA tool to easily convert between [Apache Oozie](http://oozie.apache.org/) workflows\nand [Apache Airflow](https://airflow.apache.org) workflows.\n\nThe program targets Apache Airflow >= 1.10 and Apache Oozie 1.0 XML schema.\n\nIf you want to contribute to the project, please take a look at [CONTRIBUTING.md](CONTRIBUTING.md)\n\n# Table of Contents\n\n* [Oozie to Airflow](#oozie-to-airflow)\n* [Table of Contents](#table-of-contents)\n * [Background](#background)\n* [Running the Program](#running-the-program)\n * [Required Python Dependencies](#required-python-dependencies)\n * [Running the conversion](#running-the-conversion)\n * [Structure of the application folder](#structure-of-the-application-folder)\n* [Supported Oozie features](#supported-oozie-features)\n * [Control nodes](#control-nodes)\n * [Fork](#fork)\n * [Join](#join)\n * [Decision](#decision)\n * [Start](#start)\n * [End](#end)\n * [Kill](#kill)\n * [Known Limitations](#known-limitations)\n * [EL Functions](#el-functions)\n* [Examples](#examples)\n * [Demo Example](#demo-example)\n * [Current limitations](#current-limitations)\n * [Output](#output)\n * [Childwf Example](#childwf-example)\n * [Output](#output-1)\n * [Current limitations](#current-limitations-1)\n * [SSH Example](#ssh-example)\n * [Output](#output-2)\n * [Current limitations](#current-limitations-2)\n * [MapReduce Example](#mapreduce-example)\n * [Output](#output-3)\n * [Current limitations](#current-limitations-3)\n * [FS Example](#fs-example)\n * [Output](#output-4)\n * [Current limitations](#current-limitations-4)\n * [Pig Example](#pig-example)\n * [Output](#output-5)\n * [Current limitations](#current-limitations-5)\n * [Shell Example](#shell-example)\n * [Output](#output-6)\n * [Current limitations](#current-limitations-6)\n * [Spark Example](#spark-example)\n * [Output](#output-7)\n * [Current limitations](#current-limitations-7)\n * [Sub\\-workflow Example](#sub-workflow-example)\n * [Output](#output-8)\n * [Current limitations](#current-limitations-8)\n * [Decision Example](#decision-example)\n * [Output](#output-9)\n * [Current limitations](#current-limitations-9)\n * [EL Example](#el-example)\n * [Output](#output-10)\n * [Current limitations](#current-limitations-10)\n\nCreated by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc.go)\n\n## Background\n\nApache Airflow is a workflow management system developed by AirBnB in 2014.\nIt is a platform to programmatically author, schedule, and monitor workflows.\nAirflow workflows are designed as [Directed Acyclic Graphs](https://airflow.apache.org/tutorial.html#example-pipeline-definition)\n(DAGs) of tasks in Python. The Airflow scheduler executes your tasks on an array of\nworkers while following the specified dependencies.\n\nApache Oozie is a workflow scheduler system to manage Apache Hadoop jobs.\nOozie workflows are also designed as [Directed Acyclic Graphs](https://oozie.apache.org/docs/3.1.3-incubating/DG_Overview.html)\n(DAGs) in XML.\n\nThere are a few differences noted below:\n\n\n| | Spec. | Task | Dependencies | \"Subworkflows\" | Parameterization | Notification |\n|---------|--------|-------------|---------------------------------|----------------|------------------------------|---------------------|\n| Oozie | XML | Action Node | Control Node | Subworkflow | EL functions/Properties file | URL based callbacks |\n| Airflow | Python | Operators | Trigger Rules, set_downstream() | SubDag | jinja2 and macros | Callbacks/Emails |\n\n\n# Running the Program\n\n## Required Python Dependencies\n\n* Python >= 3.6\n* See [requirements.txt](requirements.txt)\n\nAdditionally the shell script included in the directory, `init.sh`, can\nbe executed to set up the dependencies and have your local machine ready to convert the examples.\n\n```bash\n# Allow init.sh to execute\n$ chmod +x init.sh\n# Execute init.sh\n$ ./init.sh\n```\n\n## Adding bin directory to your PATH\n\nYou can add the [bin](bin) subdirectory to your PATH, then all the scripts below can be run without adding\nbin path.\n\nYou can do it for example by adding similar line to your `.bash_profile`\nor `bin/postactivate` from your virtual environment:\n\n```bash\nexport PATH=${PATH}:/bin\n```\n\nOtherwise you need to run them from the bin subdirectory - prepending it with the path, for example:\n```bash\n./bin/o2a --help\n```\n\nIn all the examples below it is assumed that the [bin](bin) directory is in your PATH.\n\n## Running the conversion\n\nYou can run the program (minimally) by calling:\n`o2a -i -o `\n\nExample:\n`o2a -i examples/demo -o output/demo`\n\nThis is the full usage guide, available by running `o2a -h`\n\n```\nusage: o2a [-h] -i INPUT_DIRECTORY_PATH -o OUTPUT_DIRECTORY_PATH [-d DAG_NAME]\n [-u USER] [-s START_DAYS_AGO] [-v SCHEDULE_INTERVAL]\n\nConvert Apache Oozie workflows to Apache Airflow workflows.\n\noptional arguments:\n -h, --help show this help message and exit\n -i INPUT_DIRECTORY_PATH, --input-directory-path INPUT_DIRECTORY_PATH\n Path to input directory\n -o OUTPUT_DIRECTORY_PATH, --output-directory-path OUTPUT_DIRECTORY_PATH\n Desired output directory\n -d DAG_NAME, --dag-name DAG_NAME\n Desired DAG name [defaults to input directory name]\n -u USER, --user USER The user to be used in place of all ${user.name}\n [defaults to user who ran the conversion]\n -s START_DAYS_AGO, --start-days-ago START_DAYS_AGO\n Desired DAG start as number of days ago\n -v SCHEDULE_INTERVAL, --schedule-interval SCHEDULE_INTERVAL\n Desired DAG schedule interval as number of days\n```\n\n## Structure of the application folder\n\nThe application folder has to follow the structure defined as follows:\n\n```\n/\n |- job.properties - job properties that are used to run the job\n |- hdfs - folder with application - should be copied to HDFS\n | |- workflow.xml - Oozie workflow xml (1.0 schema)\n | |- ... - additional folders required to be copied to HDFS\n |- configuration.template.properties - template of configuration values used during conversion\n |- configuration.properties - generated properties for configuration values\n```\n\n\n# Supported Oozie features\n\n## Control nodes\n### Fork\n\nA [fork node](https://oozie.apache.org/docs/5.1.0/WorkflowFunctionalSpec.html#a3.1.5_Fork_and_Join_Control_Nodes)\nsplits the path of execution into multiple concurrent paths of execution.\n\n### Join\n\nA [join node](https://oozie.apache.org/docs/5.1.0/WorkflowFunctionalSpec.html#a3.1.5_Fork_and_Join_Control_Nodes)\nwaits until every concurrent execution of the previous fork node arrives to it. The fork and join nodes must be used in pairs. The join node\nassumes concurrent execution paths are children of the same fork node.\n~~~~\n\n ...\n \n \n ...\n \n \n ...\n \n ...\n\n~~~~\n\n### Decision\n\nA [decision node](https://oozie.apache.org/docs/5.1.0/WorkflowFunctionalSpec.html#a3.1.4_Decision_Control_Node)\nenables a workflow to make a selection on the execution path to follow.\n\nThe behavior of a decision node can be seen as a switch-case statement.\n\nA decision node consists of a list of predicates-transition pairs plus a default transition. Predicates are evaluated in order or appearance until one of them evaluates to true and the corresponding transition is taken. If none of the predicates evaluates to true the default transition is taken.\n\nPredicates are JSP Expression Language (EL) expressions (refer to section 4.2 of this document) that resolve into a boolean value, true or false . For example:\n`${fs:fileSize('/usr/foo/myinputdir') gt 10 * GB}`\n\n~~~~\n\n ...\n \n \n [PREDICATE]\n ...\n [PREDICATE]\n \n \n \n ...\n\n~~~~\n### Start\n\nThe [start node](https://oozie.apache.org/docs/5.1.0/WorkflowFunctionalSpec.html#a3.1.1_Start_Control_Node)\nis the entry point for a workflow job, it indicates the first workflow node the workflow job must transition to.\n\nWhen a workflow is started, it automatically transitions to the node specified in the start .\n\nA workflow definition must have one start node.\n\n~~~~\n\n ...\n \n ...\n\n~~~~\n### End\n\nThe [end node](https://oozie.apache.org/docs/5.1.0/WorkflowFunctionalSpec.html#a3.1.2_End_Control_Node)\nis the end for a workflow job, it indicates that the workflow job has completed successfully.\n\nWhen a workflow job reaches the end it finishes successfully (SUCCEEDED).\n\nIf one or more actions started by the workflow job are executing when the end node is reached, the actions will be killed. In this scenario the workflow job is still considered as successfully run.\n\nA workflow definition must have one end node.\n\n~~~~\n\n ...\n \n ...\n\n~~~~\n\n### Kill\n\nThe [kill node](https://oozie.apache.org/docs/5.1.0/WorkflowFunctionalSpec.html#a3.1.3_Kill_Control_Node)\nallows a workflow job to exit with an error.\n\nWhen a workflow job reaches the kill it finishes in error (KILLED).\n\nIf one or more actions started by the workflow job are executing when the kill node is reached, the actions will be killed.\n\nA workflow definition may have zero or more kill nodes.\n\n~~~~\n\n ...\n \n [MESSAGE-TO-LOG]\n \n ...\n\n~~~~\n\n## Known Limitations\n\nThe goal of this program is to mimic both the actions and control flow\nthat is outlined by the Oozie workflow file. Unfortunately there are some\nlimitations as of now that have not been worked around regarding the execution\nflow. The situation where the execution path might not execute correctly is when\nthere are 4 nodes, A, B, C, D, with the following Oozie specified execution paths:\n```\nA executes ok to C\nB executes error to C\n\nA executes error to D\nB executes ok to D\n```\nIn this situation Airflow does not have enough fine grained node execution control.\nThe converter should be able to handle this situation in the future, but it is not\ncurrently guaranteed to work.\n\nThis is because if goes from A to C on ok, and B goes to C on error, C's trigger rule\nwill have to be set to `DUMMY`, but this means that if A goes to error, and B goes to ok\nC will then execute incorrectly.\n\nThis limitation is temporary and will be removed in a future version of Oozie-2-Airflow converter.\n\n\n## EL Functions\n\nAs of now, a very minimal set of [Oozie EL](https://oozie.apache.org/docs/4.0.1/WorkflowFunctionalSpec.html#a4.2_Expression_Language_Functions)\nfunctions are supported. The way they work is that there exists a\ndictionary mapping from each Oozie EL function string to the\ncorresponding Python function. This is in `utils/el_utils.py`.\nThis design allows for custom EL function mapping if one so chooses. By\ndefault everything gets mapped to the module `o2a_libs`. This means in\norder to use EL function mapping, the folder `o2a_libs` should\nbe copied over to the Airflow DAG folder. This should then be picked up and\nparsed by the Airflow workers and then available to all DAGs.\n\n# Examples\n\nAll examples can be found in the [examples](examples) directory.\n\n* [Demo](#demo-example)\n* [SSH](#ssh-example)\n* [MapReduce](#mapreduce-example)\n* [Pig](#pig-example)\n* [Shell](#shell-example)\n* [Sub-workflow](#sub-workflow-example)\n* [Decision](#decision-example)\n* [EL](#el-example)\n\n## Demo Example\n\nThe demo example contains several action and control nodes. The control\nnodes are `fork`, `join`, `decision`, `start`, `end`, and `kill`. As far as action\nnodes go, there are `fs`, `map-reduce`, and `pig`.\n\nMost of these are already supported, but when the program encounters a node it does\nnot know how to parse, it will perform a sort of \"skeleton transformation\" -\nit will convert all the unknown nodes to dummy nodes. This will\nallow users to manually parse the nodes if they so wish as the control flow\nis there.\n\nThe demo can be run as:\n\n`o2a -i examples/demo -o output/demo`\n\nThis will parse and write to an output file in the `output/demo` directory.\n\n### Current limitations\n\nThe decision node is not fully functional as there is not currently\nsupport for all EL functions. So in order for it to run in Airflow you must\nedit the Python output file and change the decision node expression.\n\n### Output\nIn this example the output will appear in `/output/ssh/test_demo_dag.py`.\nAdditionally subworkflow is generated in `/output/ssh/subdag_test.py`.\n\n## Childwf Example\n\nThe childwf example is sub-workflow for the `demo` example. It can be run as:\n\n`o2a -i examples/childwf -o output/childwf`\n\nMake sure to first copy `examples/subwf/configuration.template.properties`, rename it as\n`configuration.properties` and fill in with configuration data.\n\n### Output\nIn this example the output will appear in `output/childwf/test_childwf_dag.py`.\n\n### Current limitations\n\nNo known limitations.\n\n## SSH Example\n\nThe ssh example can be run as:\n\n`o2a -i examples/ssh -o output/ssh`\n\nThis will convert the specified Oozie XML and write the output into the\nspecified output directory, in this case `output/ssh/test_ssh_dag.py`.\n\nThere are some differences between Apache Oozie and Apache Airflow as far as the SSH specification goes.\nIn Airflow you will have to add/edit an SSH-specific connection that contains\nthe credentials required for the specified SSH action. For example, if\nthe SSH node looks like:\n```xml\n\n \n user@apache.org\n echo\n \"Hello Oozie!\"\n \n \n \n\n```\nThen the default Airflow SSH connection, `ssh_default` should have at\nthe very least a password set. This can be found in the Airflow Web UI\nunder **Admin > Connections**. From the command line it is impossible to\nedit connections so you must add one like:\n\n`airflow connections --add --conn_id --conn_type SSH --conn_password `\n\nMore information can be found in [Airflow's documentation](https://airflow.apache.org/cli.html#connections).\n\n### Output\nIn this example the output will appear in `/output/ssh/test_ssh_dag.py`.\n\nThe converted DAG uses the `SSHOperator` in Airflow.\n\n### Current limitations\n\nNo known limitations.\n\n## MapReduce Example\n\nThe MapReduce example can be run as:\n\n`o2a -i examples/mapreduce -o output/mapreduce`\n\nMake sure to first copy `examples/mapreduce/configuration.template.properties`, rename it as\n`configuration.properties` and fill in with configuration data.\n\n### Output\nIn this example the output will appear in `/output/mapreduce/test_mapreduce_dag.py`.\n\nThe converted DAG uses the `DataProcHadoopOperator` in Airflow.\n\n### Current limitations\n\n**1. Exit status not available**\n\nFrom the [Oozie documentation](https://oozie.apache.org/docs/5.1.0/WorkflowFunctionalSpec.html#a3.2.2_Map-Reduce_Action):\n> The counters of the Hadoop job and job exit status (FAILED, KILLED or SUCCEEDED) must be available to the\nworkflow job after the Hadoop jobs ends. This information can be used from within decision nodes and other\nactions configurations.\n\nCurrently we use the `DataProcHadoopOperator` which does not store the job exit status in an XCOM for other tasks to use.\n\n**2. Configuration options**\n\nFrom the [Oozie documentation](https://oozie.apache.org/docs/5.1.0/WorkflowFunctionalSpec.html#a3.2.2_Map-Reduce_Action)\n(the strikethrough is from us):\n> Hadoop JobConf properties can be specified as part of\n> - ~~the config-default.xml or~~\n> - ~~JobConf XML file bundled with the workflow application or~~\n> - ~~\\ tag in workflow definition or~~\n> - Inline map-reduce action configuration or\n> - ~~An implementation of OozieActionConfigurator specified by the tag in workflow definition.~~\n\nCurrently the only supported way of configuring the map-reduce action is with the\ninline action configuration, i.e. using the `` tag in the workflow's XML file definition.\n\n**3. Streaming and pipes**\n\nStreaming and pipes are currently not supported.\n\n## FS Example\n\nThe FS example can be run as:\n\n`o2a -i examples/fs -o output/fs`\n\nMake sure to first copy `examples/fs/configuration.template.properties`, rename it as\n`configuration.properties` and fill in with configuration data.\n\n### Output\nIn this example the output will appear in `/output/fs/test_fs_dag.py`.\n\nThe converted DAG uses the `BashOperator` in Airflow.\n\n### Current limitations\n\nNot all FS operations are currently idempotent. This will be fixed.\n\n## Pig Example\n\nThe Pig example can be run as:\n\n`o2a -i examples/pig -o output/pig`\n\nMake sure to first copy `examples/pig/configuration.template.properties`, rename it as\n`configuration.properties` and fill in with configuration data.\n\n### Output\nIn this example the output will appear in `output/pig/test_pig_dag.py`.\n\nThe converted DAG uses the `DataProcPigOperator` in Airflow.\n\n### Current limitations\n\n**1. Configuration options**\n\nFrom the [Oozie documentation](https://oozie.apache.org/docs/5.1.0/WorkflowFunctionalSpec.html#a3.2.3_Pig_Action)\n(the strikethrough is from us):\n> Hadoop JobConf properties can be specified as part of\n> - ~~the config-default.xml or~~\n> - ~~JobConf XML file bundled with the workflow application or~~\n> - ~~\\ tag in workflow definition or~~\n> - Inline pig action configuration.\n\nCurrently the only supported way of configuring the pig action is with the\ninline action configuration, i.e. using the `` tag in the workflow's XML file definition.\n\n## Shell Example\n\nThe Shell example can be run as:\n\n`o2a -i examples/shell -o output/shell`\n\nMake sure to first copy `examples/shell/configuration.template.properties`, rename it as\n`configuration.properties` and fill in with configuration data.\n\n### Output\nIn this example the output will appear in `output/shell/test_shell_dag.py`.\n\nThe converted DAG uses the `BashOperator` in Airflow, which executes the desired shell\naction with Pig by invoking `gcloud dataproc jobs submit pig --cluster= --region=\n--execute 'sh '`.\n\n### Current limitations\n\n**1. Exit status not available**\n\nFrom the [Oozie documentation](https://oozie.apache.org/docs/5.1.0/DG_ShellActionExtension.html):\n> The output (STDOUT) of the Shell job can be made available to the workflow job after the Shell job ends.\nThis information could be used from within decision nodes.\n\nCurrently we use the `BashOperator` which can store only the last line of the job output in an XCOM.\nIn this case the line is not helpful as it relates to the Dataproc job submission status and\nnot the Shell action's result.\n\n**2. No Shell launcher configuration**\n\nFrom the [Oozie documentation](https://oozie.apache.org/docs/5.1.0/DG_ShellActionExtension.html):\n> Shell launcher configuration can be specified with a file, using the job-xml element, and inline,\nusing the configuration elements.\n\nCurrently there is no way specify the shell launcher configuration (it is ignored).\n\n## Spark Example\n\nThe Shell example can be run as:\n\n`o2a -i examples/spark -o output/spark`\n\nMake sure to first copy `/examples/spark/configuration.template.properties`, rename it as\n`configuration.properties` and fill in with configuration data.\n\n### Output\nIn this example the output will appear in `/output/spark/spark.py`.\n\nThe converted DAG uses the `DataProcSparkOperator` in Airflow.\n\n### Current limitations\n\n**1. Ony tasks written in Java are supported**\n\nFrom the [Oozie documentation](https://oozie.apache.org/docs/5.1.0/DG_ShellActionExtension.html):\n> The jar element indicates a comma separated list of jars or python files.\n\nThe solution was tested with only a single Jar file.\n\n**2. No Spark launcher configuration**\n\nFrom the [Oozie documentation](https://oozie.apache.org/docs/5.1.0/DG_SparkActionExtension.html):\n> Shell launcher configuration can be specified with a file, using the job-xml element, and inline,\nusing the configuration elements.\n\nCurrently there is no way to specify the Spark launcher configuration (it is ignored).\n\n**3. Not all elements are supported**\n\nThe following elements are not supported: `job-tracker`, `name-node`, `master`, `mode`.\n\n## Sub-workflow Example\n\nThe Sub-workflow example can be run as:\n\n`o2a -i examples/subwf -o output/subwf`\n\nMake sure to first copy `examples/subwf/configuration.template.properties`, rename it as\n`configuration.properties` and fill in with configuration data.\n\n### Output\nIn this example the output will appear in `output/subwf/test_subwf_dag.py`.\nAdditionally, a `subdag_test.py` (name to be changed soon) file is generated in the same directory,\nwhich contains the factory method `sub_dag()` returning the actual Airflow subdag.\n\nThe converted DAG uses the `SubDagOperator` in Airflow.\n\n### Current limitations\n\nCurrently generated name of the sub-workflow is fixed which means that only one subworkflow is supported\nper DAG folder. This will be fixed soon.\n\n## Decision Example\n\nThe decision example can be run as:\n\n`o2a -i examples/decision -o output/decision`\n\nMake sure to first copy `examples/decision/configuration.template.properties`, rename it as\n`configuration.properties` and fill in with configuration data.\n\n### Output\nIn this example the output will appear in `output/decision/test_decision_dag.py`.\n\nThe converted DAG uses the `BranchPythonOperator` in Airflow.\n\n### Current limitations\n\nDecision example is not yet fully functional as EL functions are not yet fully implemented so condition is\nhard-coded for now. Once EL functions are implemented, the condition in the example will be updated.\n\n## EL Example\n\nThe Oozie Expression Language (EL) example can be run as:\n`o2a -i examples/el -o output/el`\n\nThis will showcase the ability to use the `o2a_libs` directory to map EL functions\nto Python methods. This example assumes that the user has a valid Apache Airflow\nSSH connection set up and the `o2a_libs` directory has been copied to the dags\nfolder.\n\nPlease keep in mind that as of the current version only a single EL variable\nor single EL function. Variable/function chaining is not currently supported.\n\n### Output\nIn this example the output will appear in `output/el/test_el_dag.py`.\n\n### Current limitations\n\nDecision example is not yet fully functional as EL functions are not yet fully implemented so condition is\nhard-coded for now. Once EL functions are implemented, the condition in the example will be updated.\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/GoogleCloudPlatform/oozie-to-airflow", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "o2a-potiuk", "package_url": "https://pypi.org/project/o2a-potiuk/", "platform": "", "project_url": "https://pypi.org/project/o2a-potiuk/", "project_urls": { "Homepage": "https://github.com/GoogleCloudPlatform/oozie-to-airflow" }, "release_url": "https://pypi.org/project/o2a-potiuk/0.0.1/", "requires_dist": null, "requires_python": "", "summary": "Oozie To Airflow migration tool", "version": "0.0.1" }, "last_serial": 5298390, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "b8ee1a96fcd362fd451a98da8cd7de45", "sha256": "73a92ba7181c9fbcfa03935da3f77a54295ea6f9af8161dd96fa935f3d28e41d" }, "downloads": -1, "filename": "o2a_potiuk-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "b8ee1a96fcd362fd451a98da8cd7de45", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 111418, "upload_time": "2019-05-21T15:15:22", "url": "https://files.pythonhosted.org/packages/2f/b2/11722552e99c2f590dadbb4b9e457e42f2e2ffedad8e85e2c9fae62d0047/o2a_potiuk-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "78d2eb363f060a9fa81f927f7a804ae3", "sha256": "6a72808273fd80763d11579fc8369b27c27219e32fad3f110ac08b19f5406349" }, "downloads": -1, "filename": "o2a-potiuk-0.0.1.tar.gz", "has_sig": false, "md5_digest": "78d2eb363f060a9fa81f927f7a804ae3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 61278, "upload_time": "2019-05-21T15:15:26", "url": "https://files.pythonhosted.org/packages/53/d6/6371ea2ce990b86b3cf2d2966c4a3ca474c940df35b2847d83961974933f/o2a-potiuk-0.0.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "b8ee1a96fcd362fd451a98da8cd7de45", "sha256": "73a92ba7181c9fbcfa03935da3f77a54295ea6f9af8161dd96fa935f3d28e41d" }, "downloads": -1, "filename": "o2a_potiuk-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "b8ee1a96fcd362fd451a98da8cd7de45", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 111418, "upload_time": "2019-05-21T15:15:22", "url": "https://files.pythonhosted.org/packages/2f/b2/11722552e99c2f590dadbb4b9e457e42f2e2ffedad8e85e2c9fae62d0047/o2a_potiuk-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "78d2eb363f060a9fa81f927f7a804ae3", "sha256": "6a72808273fd80763d11579fc8369b27c27219e32fad3f110ac08b19f5406349" }, "downloads": -1, "filename": "o2a-potiuk-0.0.1.tar.gz", "has_sig": false, "md5_digest": "78d2eb363f060a9fa81f927f7a804ae3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 61278, "upload_time": "2019-05-21T15:15:26", "url": "https://files.pythonhosted.org/packages/53/d6/6371ea2ce990b86b3cf2d2966c4a3ca474c940df35b2847d83961974933f/o2a-potiuk-0.0.1.tar.gz" } ] }