Skip to content

Commit

Permalink
Make python3 compatible (#31)
Browse files Browse the repository at this point in the history
* Make python3 compatible

* Update docstrings to be python3 compliant

* Pin six version in requirements
  • Loading branch information
ColCarroll authored and obi1kenobi committed Sep 18, 2017
1 parent 7fd9770 commit e8d4249
Show file tree
Hide file tree
Showing 28 changed files with 198 additions and 167 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Expand Up @@ -3,10 +3,9 @@ language: python
cache: pip
python:
- "2.7"
# - "3.6" # enable when compliant
- "3.6"
install:
- pip install -r dev-requirements.txt
- pip install -r requirements.txt
- pip install -e .
script:
- flake8 graphql_compiler/
Expand Down
12 changes: 6 additions & 6 deletions graphql_compiler/__init__.py
Expand Up @@ -18,13 +18,13 @@ def graphql_to_match(schema, graphql_query, parameters):
Args:
schema: GraphQL schema object describing the schema of the graph to be queried
graphql_string: the GraphQL query to compile to MATCH, as a basestring
graphql_string: the GraphQL query to compile to MATCH, as a string
parameters: dict, mapping argument name to its value, for every parameter the query expects.
Returns:
a CompilationResult object, containing:
- query: basestring, the resulting compiled and parameterized query string
- language: basestring, specifying the language to which the query was compiled
- query: string, the resulting compiled and parameterized query string
- language: string, specifying the language to which the query was compiled
- output_metadata: dict, output name -> OutputMetadata namedtuple object
- input_metadata: dict, name of input variables -> inferred GraphQL type, based on use
"""
Expand All @@ -38,7 +38,7 @@ def graphql_to_gremlin(schema, graphql_query, parameters, type_equivalence_hints
Args:
schema: GraphQL schema object describing the schema of the graph to be queried
graphql_string: the GraphQL query to compile to Gremlin, as a basestring
graphql_string: the GraphQL query to compile to Gremlin, as a string
parameters: dict, mapping argument name to its value, for every parameter the query expects.
type_equivalence_hints: optional dict of GraphQL interface or type -> GraphQL union.
Used as a workaround for Gremlin's lack of inheritance-awareness.
Expand All @@ -57,8 +57,8 @@ def graphql_to_gremlin(schema, graphql_query, parameters, type_equivalence_hints
Returns:
a CompilationResult object, containing:
- query: basestring, the resulting compiled and parameterized query string
- language: basestring, specifying the language to which the query was compiled
- query: string, the resulting compiled and parameterized query string
- language: string, specifying the language to which the query was compiled
- output_metadata: dict, output name -> OutputMetadata namedtuple object
- input_metadata: dict, name of input variables -> inferred GraphQL type, based on use
"""
Expand Down
40 changes: 21 additions & 19 deletions graphql_compiler/compiler/blocks.py
@@ -1,4 +1,6 @@
# Copyright 2017 Kensho Technologies, Inc.
import six

from .expressions import Expression
from .helpers import (CompilerEntity, ensure_unicode_string, safe_quoted_string,
validate_marked_location, validate_safe_string)
Expand Down Expand Up @@ -37,7 +39,7 @@ def __init__(self, start_class):
"""Construct a QueryRoot object that starts querying at the specified class name.
Args:
start_class: set of basestring, class names from which to start the query.
start_class: set of string, class names from which to start the query.
This will generally be a set of length 1, except when using Gremlin
with a non-final class, where we have to include all subclasses
of the start class. This is done using a Gremlin-only IR lowering step.
Expand All @@ -52,8 +54,8 @@ def __init__(self, start_class):
def validate(self):
"""Ensure that the QueryRoot block is valid."""
if not (isinstance(self.start_class, set) and
all(isinstance(x, basestring) for x in self.start_class)):
raise TypeError(u'Expected set of basestring start_class, got: {} {}'.format(
all(isinstance(x, six.string_types) for x in self.start_class)):
raise TypeError(u'Expected set of string start_class, got: {} {}'.format(
type(self.start_class).__name__, self.start_class))

for cls in self.start_class:
Expand All @@ -80,7 +82,7 @@ def __init__(self, target_class):
"""Construct a CoerceType object that filters out any data that is not of the given types.
Args:
target_class: set of basestring, class names from which to start the query.
target_class: set of string, class names from which to start the query.
This will generally be a set of length 1, except when using Gremlin
with a non-final class, where we have to include all subclasses
of the target class. This is done using a Gremlin-only IR lowering step.
Expand All @@ -95,8 +97,8 @@ def __init__(self, target_class):
def validate(self):
"""Ensure that the CoerceType block is valid."""
if not (isinstance(self.target_class, set) and
all(isinstance(x, basestring) for x in self.target_class)):
raise TypeError(u'Expected set of basestring target_class, got: {} {}'.format(
all(isinstance(x, six.string_types) for x in self.target_class)):
raise TypeError(u'Expected set of string target_class, got: {} {}'.format(
type(self.target_class).__name__, self.target_class))

for cls in self.target_class:
Expand All @@ -115,15 +117,15 @@ def __init__(self, fields):
"""Construct a ConstructResult object that maps the given field names to their expressions.
Args:
fields: dict, variable name basestring -> Expression
fields: dict, variable name string -> Expression
see rules for variable names in validate_safe_string().
Returns:
new ConstructResult object
"""
self.fields = {
ensure_unicode_string(key): value
for key, value in fields.iteritems()
for key, value in six.iteritems(fields)
}

# All key values are normalized to unicode before being passed to the parent constructor,
Expand All @@ -137,7 +139,7 @@ def validate(self):
raise TypeError(u'Expected dict fields, got: {} {}'.format(
type(self.fields).__name__, self.fields))

for key, value in self.fields.iteritems():
for key, value in six.iteritems(self.fields):
validate_safe_string(key)
if not isinstance(value, Expression):
raise TypeError(
Expand All @@ -148,7 +150,7 @@ def visit_and_update_expressions(self, visitor_fn):
"""Create an updated version (if needed) of the ConstructResult via the visitor pattern."""
new_fields = {}

for key, value in self.fields.iteritems():
for key, value in six.iteritems(self.fields):
new_value = value.visit_and_update(visitor_fn)
if new_value is not value:
new_fields[key] = new_value
Expand Down Expand Up @@ -237,8 +239,8 @@ def __init__(self, direction, edge_name, optional=False):
"""Create a new Traverse block in the given direction and across the given edge.
Args:
direction: basestring, 'in' or 'out'
edge_name: basestring obeying variable name rules (see validate_safe_string).
direction: string, 'in' or 'out'
edge_name: string obeying variable name rules (see validate_safe_string).
optional: optional bool, specifying whether the traversal to the given location
is optional (i.e. non-filtering) or mandatory (filtering).
Expand All @@ -253,8 +255,8 @@ def __init__(self, direction, edge_name, optional=False):

def validate(self):
"""Ensure that the Traverse block is valid."""
if not isinstance(self.direction, basestring):
raise TypeError(u'Expected basestring direction, got: {} {}'.format(
if not isinstance(self.direction, six.string_types):
raise TypeError(u'Expected string direction, got: {} {}'.format(
type(self.direction).__name__, self.direction))

if self.direction not in {u'in', u'out'}:
Expand Down Expand Up @@ -302,8 +304,8 @@ def __init__(self, direction, edge_name, depth):
"""Create a new Recurse block which traverses the given edge up to "depth" times.
Args:
direction: basestring, 'in' or 'out'.
edge_name: basestring obeying variable name rules (see validate_safe_string).
direction: string, 'in' or 'out'.
edge_name: string obeying variable name rules (see validate_safe_string).
depth: int, always greater than or equal to 1.
Returns:
Expand All @@ -317,8 +319,8 @@ def __init__(self, direction, edge_name, depth):

def validate(self):
"""Ensure that the Traverse block is valid."""
if not isinstance(self.direction, basestring):
raise TypeError(u'Expected basestring direction, got: {} {}'.format(
if not isinstance(self.direction, six.string_types):
raise TypeError(u'Expected string direction, got: {} {}'.format(
type(self.direction).__name__, self.direction))

if self.direction not in {u'in', u'out'}:
Expand All @@ -344,7 +346,7 @@ def to_gremlin(self):

recurse_steps = [
recurse_base + (recurse_traversal * i)
for i in xrange(self.depth + 1)
for i in six.moves.xrange(self.depth + 1)
]
return template.format(recurse=','.join(recurse_steps))

Expand Down
8 changes: 4 additions & 4 deletions graphql_compiler/compiler/common.py
Expand Up @@ -6,8 +6,8 @@


# The CompilationResult will have the following types for its members:
# - query: basestring, the resulting compiled query string, with placeholders for parameters
# - language: basestring, specifying the language to which the query was compiled
# - query: string, the resulting compiled query string, with placeholders for parameters
# - language: string, specifying the language to which the query was compiled
# - output_metadata: dict, output name -> OutputMetadata namedtuple object
# - input_metadata: dict, name of input variables -> inferred GraphQL type, based on use
CompilationResult = namedtuple('CompilationResult',
Expand All @@ -22,7 +22,7 @@ def compile_graphql_to_match(schema, graphql_string):
Args:
schema: GraphQL schema object describing the schema of the graph to be queried
graphql_string: the GraphQL query to compile to MATCH, as a basestring
graphql_string: the GraphQL query to compile to MATCH, as a string
Returns:
a CompilationResult object
Expand All @@ -46,7 +46,7 @@ def compile_graphql_to_gremlin(schema, graphql_string, type_equivalence_hints=No
Args:
schema: GraphQL schema object describing the schema of the graph to be queried
graphql_string: the GraphQL query to compile to Gremlin, as a basestring
graphql_string: the GraphQL query to compile to Gremlin, as a string
type_equivalence_hints: optional dict of GraphQL interface or type -> GraphQL union.
Used as a workaround for Gremlin's lack of inheritance-awareness.
When this parameter is not specified or is empty, type coercion
Expand Down
27 changes: 14 additions & 13 deletions graphql_compiler/compiler/compiler_frontend.py
Expand Up @@ -60,6 +60,7 @@
from graphql.type.definition import (GraphQLInterfaceType, GraphQLList, GraphQLObjectType,
GraphQLUnionType)
from graphql.validation import validate
import six

from . import blocks, expressions
from ..exceptions import GraphQLCompilationError, GraphQLParsingError, GraphQLValidationError
Expand Down Expand Up @@ -95,7 +96,7 @@ def _get_directives(ast):
ast: GraphQL AST node, obtained from the graphql library
Returns:
dict of basestring to directive object, mapping directive names to their data
dict of string to directive object, mapping directive names to their data
"""
try:
return get_uniquely_named_objects_by_name(ast.directives)
Expand Down Expand Up @@ -225,15 +226,15 @@ def _process_output_source_directive(schema, current_schema_type, ast,

def _validate_property_directives(directives):
"""Validate the directives that appear at a property field."""
for directive_name in directives.iterkeys():
for directive_name in six.iterkeys(directives):
if directive_name in vertex_only_directives:
raise GraphQLCompilationError(
u'Found vertex-only directive {} set on property.'.format(directive_name))


def _validate_vertex_directives(directives):
"""Validate the directives that appear at a vertex field."""
for directive_name in directives.iterkeys():
for directive_name in six.iterkeys(directives):
if directive_name in property_only_directives:
raise GraphQLCompilationError(
u'Found property-only directive {} set on vertex.'.format(directive_name))
Expand Down Expand Up @@ -529,7 +530,7 @@ def _compile_vertex_ast(schema, current_schema_type, ast,
def _validate_fold_has_outputs(fold_data, outputs):
# At least one output in the outputs list must point to the fold_data,
# or the scope corresponding to fold_data had no @outputs and is illegal.
for output in outputs.values():
for output in six.itervalues(outputs):
if output['fold'] is fold_data:
return True

Expand Down Expand Up @@ -651,8 +652,8 @@ def _compile_root_ast_to_ir(schema, ast):
Returns:
tuple of:
- a list of IR basic block objects
- a dict of output name (basestring) -> OutputMetadata object
- a dict of expected input parameters (basestring) -> inferred GraphQL type, based on use
- a dict of output name (string) -> OutputMetadata object
- a dict of expected input parameters (string) -> inferred GraphQL type, based on use
- a dict of location objects -> GraphQL type objects at that location
"""
if len(ast.selection_set.selections) != 1:
Expand Down Expand Up @@ -694,7 +695,7 @@ def _compile_root_ast_to_ir(schema, ast):

# Ensure the GraphQL query root doesn't have any vertex directives
# that are disallowed on the root node.
directives_present_at_root = set(_get_directives(base_ast).iterkeys())
directives_present_at_root = set(six.iterkeys(_get_directives(base_ast)))
disallowed_directives = directives_present_at_root & vertex_directives_prohibited_on_root
if disallowed_directives:
raise GraphQLCompilationError(u'Found prohibited directives on root vertex: '
Expand All @@ -710,7 +711,7 @@ def _compile_root_ast_to_ir(schema, ast):
basic_blocks.append(_compile_output_step(outputs_context))
output_metadata = {
name: OutputMetadata(type=value['type'], optional=value['optional'])
for name, value in outputs_context.iteritems()
for name, value in six.iteritems(outputs_context)
}

return basic_blocks, output_metadata, context['inputs'], context['location_types']
Expand All @@ -720,7 +721,7 @@ def _compile_output_step(outputs):
"""Construct the final ConstructResult basic block that defines the output format of the query.
Args:
outputs: dict, output name (basestring) -> output data dict, specifying the location
outputs: dict, output name (string) -> output data dict, specifying the location
from where to get the data, and whether the data is optional (and therefore
may be missing); missing optional data is replaced with 'null'
Expand All @@ -732,7 +733,7 @@ def _compile_output_step(outputs):
u'one field with the @output directive.')

output_fields = {}
for output_name, output_context in outputs.iteritems():
for output_name, output_context in six.iteritems(outputs):
location = output_context['location']
optional = output_context['optional']
graphql_type = output_context['type']
Expand Down Expand Up @@ -776,13 +777,13 @@ def graphql_to_ir(schema, graphql_string):
Args:
schema: GraphQL schema object, created using the GraphQL library
graphql_string: basestring containing the GraphQL to compile to compiler IR
graphql_string: string containing the GraphQL to compile to compiler IR
Returns:
tuple of:
- a list of IR basic block objects
- a dict of output name (basestring) -> OutputMetadata object
- a dict of expected input parameters (basestring) -> inferred GraphQL type, based on use
- a dict of output name (string) -> OutputMetadata object
- a dict of expected input parameters (string) -> inferred GraphQL type, based on use
- a dict of location objects -> GraphQL type objects at that location
Raises flavors of GraphQLError in the following cases:
Expand Down

0 comments on commit e8d4249

Please sign in to comment.