Skip to content

Commit

Permalink
[improvement] Add abstract visitor class for each union type (#35)
Browse files Browse the repository at this point in the history
* Add abstract visitor class for each union type
  • Loading branch information
Andrew Higgins authored Nov 27, 2018
1 parent a301b96 commit 1eca2a6
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 7 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ and [Intellij IDEA Community Edition](https://www.jetbrains.com/idea/) for Java
1. Generate the IDE configuration: `./gradlew idea`
1. Open projects in Intellij: `open *.ipr`
1. Generate integration test bindings: `./gradlew generate`
1. In `conjure-python-verification/python`:
1. In `conjure-python-verifier/python`:

```shell
$ PIPENV_VENV_IN_PROJECT=1 pipenv --python 3 shell # create the virtual environment
Expand All @@ -35,5 +35,5 @@ and [Intellij IDEA Community Edition](https://www.jetbrains.com/idea/) for Java
### Development tips

- run `./gradlew checkstyleMain checkstyleTest` locally to make sure your code conforms to the code-style.
- Use `tox` in `conjure-python-verification/python` to run all tests using both python 2 and 3
- Use `tox` in `conjure-python-verifier/python` to run all tests using both python 2 and 3

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.palantir.conjure.python.poet;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.palantir.conjure.python.types.ImportTypeVisitor;
import com.palantir.conjure.spec.Documentation;
import java.util.List;
Expand All @@ -26,10 +27,15 @@

@Value.Immutable
public interface UnionSnippet extends PythonSnippet {
PythonImport CONJURE_IMPORT = PythonImport.builder()
.moduleSpecifier(ImportTypeVisitor.CONJURE_PYTHON_CLIENT)
.addNamedImports("ConjureUnionType", "ConjureFieldDefinition")
.build();
ImmutableList<PythonImport> DEFAULT_IMPORTS = ImmutableList.of(
PythonImport.builder()
.moduleSpecifier(ImportTypeVisitor.CONJURE_PYTHON_CLIENT)
.addNamedImports("ConjureUnionType", "ConjureFieldDefinition")
.build(),
PythonImport.builder()
.moduleSpecifier("abc")
.addNamedImports("ABCMeta", "abstractmethod")
.build());

@Override
@Value.Default
Expand Down Expand Up @@ -125,8 +131,45 @@ default void emit(PythonPoetWriter poetWriter) {
poetWriter.decreaseIndent();
});

String visitorName = String.format("%sVisitor", className());

poetWriter.writeLine();
poetWriter.writeIndentedLine("def accept(self, visitor):");
poetWriter.increaseIndent();
poetWriter.writeIndentedLine("# type: (%s) -> Any", visitorName);
poetWriter.writeIndentedLine("if not isinstance(visitor, %s):", visitorName);
poetWriter.increaseIndent();
poetWriter.writeIndentedLine(
"raise ValueError('{} is not an instance of %s'.format(visitor.__class__.__name__))",
visitorName);
poetWriter.decreaseIndent();
options().forEach(option -> {
poetWriter.writeIndentedLine("if self.type == '%s':", option.jsonIdentifier());
poetWriter.increaseIndent();
poetWriter.writeIndentedLine("return visitor._%s(self.%s)", option.attributeName(),
PythonIdentifierSanitizer.sanitize(option.attributeName()));
poetWriter.decreaseIndent();
});
poetWriter.decreaseIndent();
poetWriter.decreaseIndent();
poetWriter.writeLine();
poetWriter.writeLine();

poetWriter.writeIndentedLine(String.format("class %s(ABCMeta('ABC', (object,), {})):", visitorName));
poetWriter.increaseIndent();
options().forEach(option -> {
poetWriter.writeLine();
poetWriter.writeIndentedLine("@abstractmethod");
poetWriter.writeIndentedLine("def _%s(self, %s):", option.attributeName(),
PythonIdentifierSanitizer.sanitize(option.attributeName()));
poetWriter.increaseIndent();
poetWriter.writeIndentedLine("# type: (%s) -> Any", option.myPyType());
poetWriter.writeIndentedLine("pass");
poetWriter.decreaseIndent();
});
poetWriter.decreaseIndent();
poetWriter.writeLine();
poetWriter.writeLine();
}

class Builder extends ImmutableUnionSnippet.Builder {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ private UnionSnippet generateUnion(

return UnionSnippet.builder()
.className(typeDef.getTypeName().getName())
.addImports(UnionSnippet.CONJURE_IMPORT)
.addAllImports(UnionSnippet.DEFAULT_IMPORTS)
.addAllImports(imports)
.docs(typeDef.getDocs())
.options(options)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from abc import ABCMeta, abstractmethod
from conjure_python_client import BinaryType, ConjureBeanType, ConjureEnumType, ConjureFieldDefinition, ConjureUnionType, DictType, ListType, OptionalType
from typing import Any, List, Optional, Set

Expand Down Expand Up @@ -766,6 +767,64 @@ def interface(self):
# type: () -> int
return self._interface

def accept(self, visitor):
# type: (UnionTypeExampleVisitor) -> Any
if not isinstance(visitor, UnionTypeExampleVisitor):
raise ValueError('{} is not an instance of UnionTypeExampleVisitor'.format(visitor.__class__.__name__))
if self.type == 'stringExample':
return visitor._string_example(self.string_example)
if self.type == 'set':
return visitor._set(self.set)
if self.type == 'thisFieldIsAnInteger':
return visitor._this_field_is_an_integer(self.this_field_is_an_integer)
if self.type == 'alsoAnInteger':
return visitor._also_an_integer(self.also_an_integer)
if self.type == 'if':
return visitor._if(self.if_)
if self.type == 'new':
return visitor._new(self.new)
if self.type == 'interface':
return visitor._interface(self.interface)


class UnionTypeExampleVisitor(ABCMeta('ABC', (object,), {})):

@abstractmethod
def _string_example(self, string_example):
# type: (StringExample) -> Any
pass

@abstractmethod
def _set(self, set):
# type: (List[str]) -> Any
pass

@abstractmethod
def _this_field_is_an_integer(self, this_field_is_an_integer):
# type: (int) -> Any
pass

@abstractmethod
def _also_an_integer(self, also_an_integer):
# type: (int) -> Any
pass

@abstractmethod
def _if(self, if_):
# type: (int) -> Any
pass

@abstractmethod
def _new(self, new):
# type: (int) -> Any
pass

@abstractmethod
def _interface(self, interface):
# type: (int) -> Any
pass


class UuidExample(ConjureBeanType):

@classmethod
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from ..product import AnyMapExample, DateTimeAliasExample, ManyFieldExample, ReferenceAliasExample, RidAliasExample, StringAliasExample, StringExample
from ..product_datasets import BackingFileSystem
from abc import ABCMeta, abstractmethod
from conjure_python_client import ConjureBeanType, ConjureDecoder, ConjureEncoder, ConjureFieldDefinition, ConjureUnionType, DictType, Service

class ComplexObjectWithImports(ConjureBeanType):
Expand Down Expand Up @@ -115,6 +116,29 @@ def imported(self):
# type: () -> AnyMapExample
return self._imported

def accept(self, visitor):
# type: (UnionWithImportsVisitor) -> Any
if not isinstance(visitor, UnionWithImportsVisitor):
raise ValueError('{} is not an instance of UnionWithImportsVisitor'.format(visitor.__class__.__name__))
if self.type == 'string':
return visitor._string(self.string)
if self.type == 'imported':
return visitor._imported(self.imported)


class UnionWithImportsVisitor(ABCMeta('ABC', (object,), {})):

@abstractmethod
def _string(self, string):
# type: (str) -> Any
pass

@abstractmethod
def _imported(self, imported):
# type: (AnyMapExample) -> Any
pass


AliasImportedObject = ManyFieldExample

AliasImportedPrimitiveAlias = StringAliasExample
Expand Down

0 comments on commit 1eca2a6

Please sign in to comment.