Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Py3 bindings #51

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
00e8b74
Work-in-progress: Python3 bindings
Mar 12, 2017
be8ab68
Some additional docs
Mar 22, 2017
1687e34
Some additional docs
Mar 22, 2017
f30bc49
Change todo
Mar 24, 2017
7c58bb0
Cleaner create and set semantics
Mar 24, 2017
1724475
Pre-parse avro schemata
Mar 24, 2017
58ebf5a
dumps -> serialize, loads -> parse
Mar 24, 2017
a768e94
TypeError instead of ValidationError for bad calling of init
Mar 24, 2017
de5aa87
Make sure invalid setter changes don't stick
Mar 24, 2017
47e1190
Move union instantiation to constructor
Mar 25, 2017
a1af296
Move data to end of args list in constructor
Mar 25, 2017
dc78001
Move data to end of args list in constructor in union
Mar 25, 2017
4559019
Move data to end of args list in constructor in union
Mar 25, 2017
a26acbd
Add member keys to runtime
Mar 25, 2017
57c2c53
Nicer union behavior
Mar 26, 2017
59d9ed5
some docs around unions
Mar 26, 2017
2784112
Leaner init implementation for records
Mar 26, 2017
47f1d1a
OK unions of collections work now too
Mar 26, 2017
3ec6215
Fix a little bug
Mar 26, 2017
6efac25
Use courier bindings in test case
Mar 29, 2017
47be5cf
More documentation. Generate requirements.txt
Jun 16, 2017
76ab9b9
Fix bug with array slices
Jun 16, 2017
9f37a5c
One additional test case for slices
Jun 16, 2017
51fcf24
wip
Aug 22, 2017
4d89c0a
Beef up union tests some more
Sep 4, 2017
62dea91
Add some docs and switch back to avro validation
Sep 26, 2017
333db00
Switch back to avro validation, prevent validation on creation with data
Sep 27, 2017
432848a
Test validation prevented on creation with data
Sep 27, 2017
fe3106b
Remove unnecessary conditionals when checking for data object
Sep 27, 2017
750604a
Remove unnecessary conditionals when checking for data object
Sep 27, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ private void deleteUnrecognizedFiles(
(Collection<File>)FileUtils.listFiles(targetDirectory, null, true);

for (File existingFile : existingFiles) {
if (!targetFiles.contains(existingFile)) {
// TODO(py3): Get rid of this terrible __init__.py hack before un-WIPping this PR
if (!targetFiles.contains(existingFile) && !existingFile.getAbsoluteFile().getName().contains("__init__.py")) {
FileUtils.forceDelete(existingFile);
}
}
Expand Down Expand Up @@ -176,6 +177,15 @@ private static File writeCode(
directory.getAbsolutePath());
}

// TODO(py3): Get rid of this before PRing for god sake. Find a better way to do this in courier
File py3Init = new File(directory, "__init__.py");
System.err.println(py3Init.getAbsolutePath());
if (!py3Init.exists()) {
if (!py3Init.createNewFile()) {
throw new IllegalArgumentException("Unable to create file " + py3Init.getAbsolutePath());
}
}

if (!file.exists()) {
if (!file.createNewFile()) {
throw new IllegalArgumentException("unable to create file: " + file.getAbsolutePath());
Expand Down
16 changes: 14 additions & 2 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -155,19 +155,25 @@ object Courier extends Build with OverridablePublishSettings {
lazy val typescriptLiteGenerator = Project(id = "typescript-lite-generator", base = typescriptLiteDir / "generator")
.dependsOn(generatorApi)

private[this] val python3Dir = file("python3")
lazy val python3Generator = Project(id = "python3-generator", base = python3Dir / "generator")
.dependsOn(generatorApi)

lazy val cli = Project(id = "courier-cli", base = file("cli"))
.dependsOn(
javaGenerator,
androidGenerator,
scalaGenerator,
typescriptLiteGenerator,
swiftGenerator
swiftGenerator,
python3Generator
).aggregate(
javaGenerator,
androidGenerator,
scalaGenerator,
typescriptLiteGenerator,
swiftGenerator
swiftGenerator,
python3Generator
).settings(
executableFile := {
val exeFile = target.value / "courier"
Expand All @@ -187,6 +193,11 @@ object Courier extends Build with OverridablePublishSettings {
id = "typescript-lite-generator-test", base = typescriptLiteDir / "generator-test")
.dependsOn(typescriptLiteGenerator)

lazy val python3GeneratorTest = Project(
id = "python3-generator-test", base = python3Dir / "generator-test")
.dependsOn(python3Generator)


lazy val courierSbtPlugin = Project(id = "sbt-plugin", base = file("sbt-plugin"))
.dependsOn(scalaGenerator)

Expand Down Expand Up @@ -218,6 +229,7 @@ object Courier extends Build with OverridablePublishSettings {
s";project android-runtime;$publishCommand" +
s";project swift-generator;$publishCommand" +
s";project typescript-lite-generator;$publishCommand" +
s";project python3-generator;$publishCommand" +
s";++$sbtScalaVersion;project scala-generator;$publishCommand" +
s";++$currentScalaVersion;project scala-generator;$publishCommand" +
s";++$sbtScalaVersion;project sbt-plugin;$publishCommand" +
Expand Down
11 changes: 11 additions & 0 deletions python3/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.gradle
build/

generator/build
testsuite/testsuiteTests/generated

# Ignore Gradle GUI config
gradle-app.setting

# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
67 changes: 67 additions & 0 deletions python3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
Python3 Courier Data Binding Generator
==============================================

Courier bindings for Python 3 (tested against Python 3.6)

Features missing in action
--------------------------

Mainline Courier features that are not yet supported, but will be by the time
this thing is ready for submit:
- [ ] **Coercers**
- [ ] **Non-primitive keyed maps**. Hashcode not yet implemented for
non-primitives.
- [ ] **Non-JSON serialization**. Though avro should be trivial with existing
avro libraries.
- [ ] **Default values**.
- [ ] **Flat-typed definitions**.
- [ ] **Optional fields**. Currently all fields in `MyRecord.create` are
required. These should be easy to add.
- [ ] **Deprecation**.
- [ ] **Enum properties**. No `Fruits.BANANA.property("color")`
- [ ] **$UNKNOWN** on enums.

Additional tasks before merging to courier master:
- [ ] Fix the most heinous `TODO` items from the changelist.
- Specifically the ones that alter the general, not-only-py3 code.
- [ ] Hook into the top-level cli
- [ ] Many additional test-cases
- [ ] Populate this documentation

Additional desirable tasks for later:
- [ ] Ship `courier.py` as a package through `pip` instead of through the
generator
- [ ] Examine abstractions that unify code the large amount of overlap between TSLite and Python3 code generation.
Hopefully this can lead to writing new bindings more easily down the road.

Running the generator from the command line
-------------------------------------------

Build a fat jar from source and use that.

```bash
$ sbt
> project python3-generator
> assembly
# Wait for a bit...
[info] Packaging /Users/eboto/code/courier/python3/generator/target/courier-python3-generator-2.0.8.jar ...
```

To see usage, execute `java -jar <the generated jar>`

Runtime library
---------------

All generated Python3 bindings depend on a `courier.py` class. This class provides the consistent
runtime aspect necessary for generated bindings to work. It is shipped with the bindings.

Testing
-------

Not-that-exhaustive tests are run against the reference suite. To execute them:

```bash
$ sbt
> project python3-generator-test
> test
```
49 changes: 49 additions & 0 deletions python3/generator-test/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import sbt.inc.Analysis

name := "courier-python3-generator-test"

packagedArtifacts := Map.empty // do not publish

libraryDependencies ++= Seq(
ExternalDependencies.JodaTime.jodaTime)

autoScalaLibrary := false

crossPaths := false

// Test Generator
forkedVmCourierGeneratorSettings

forkedVmCourierMainClass := "org.coursera.courier.Python3Generator"

forkedVmCourierClasspath := (dependencyClasspath in Runtime in python3Generator).value.files

forkedVmSourceDirectory := (sourceDirectory in referenceSuite).value / "main" / "courier"

forkedVmCourierDest := file("python3") / "testsuite" / "src" / "py3bindings"

forkedVmAdditionalArgs := Seq("STRICT")

(compile in Compile) := {
(forkedVmCourierGenerator in Compile).value

Analysis.Empty
}

lazy val py3Test = taskKey[Boolean]("Executes python unittest")

py3Test in Test := {
// Comment out the following line to just run the tests without
// new generation.
(compile in Compile).value

val result = """./python3/testsuite/full-build.sh"""!

if (result != 0) {
throw new RuntimeException("Python3 Build Failed")
}

true
}

test in Test := (py3Test in Test).value
2 changes: 2 additions & 0 deletions python3/generator/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
src/test/mainGeneratedPegasus
src/main/mainGeneratedPegasus
19 changes: 19 additions & 0 deletions python3/generator/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import sbtassembly.AssemblyPlugin.defaultShellScript

name := "courier-python3-generator"

plainJavaProjectSettings

libraryDependencies ++= Seq(
ExternalDependencies.Rythm.rythmEngine,
ExternalDependencies.Slf4j.slf4jSimple,
ExternalDependencies.Pegasus.dataAvro
)

// Fat Jar
mainClass in assembly := Some("org.coursera.courier.Python3Generator")

assemblyOption in assembly := (assemblyOption in assembly).value.copy(prependShellScript = Some(defaultShellScript))

assemblyJarName in assembly := s"${name.value}-${version.value}.jar"

Loading