Skip to content

Commit 594d094

Browse files
committed
Api object is now passed into the generate() method.
Summary: It's no longer available as an instance variable of the Generator class. Also, the "_logger" instance variable has been converted to "logger". Test Plan: Ran babel and python gen tests Reviewed By: guido
1 parent 42c20ed commit 594d094

File tree

8 files changed

+59
-40
lines changed

8 files changed

+59
-40
lines changed

babelapi/compiler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ def _process_file(self, source_path):
121121
if (inspect.isclass(attr_value)
122122
and issubclass(attr_value, Generator)
123123
and not inspect.isabstract(attr_value)):
124-
generator = attr_value(self.api, self.build_path)
124+
generator = attr_value(self.build_path)
125125
try:
126-
generator.generate()
126+
generator.generate(self.api)
127127
except:
128128
# Tell the user that this isn't a bug with the babel
129129
# parser but a bug with the generator they are using.

babelapi/generator.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,23 @@ class to be recognized as such.
2020
2121
2. Use the family of emit*() functions to write to the output file.
2222
23-
The api attribute holds all information parsed from the specs, and should
24-
be used during generation.
23+
The target_folder_path attribute is the path to the folder where all
24+
generated files should be created.
2525
"""
2626

2727
__metaclass__ = ABCMeta
2828

2929
# Can be overridden by a subclass
3030
tabs_for_indents = False
3131

32-
def __init__(self, api, target_folder_path):
33-
self._logger = logging.getLogger('bablesdk.generator.%s'
34-
% self.__class__.__name__)
35-
self.api = api
32+
def __init__(self, target_folder_path):
33+
"""
34+
Args:
35+
target_folder_path (str): Path to the folder where all generated
36+
files should be created.
37+
"""
38+
self.logger = logging.getLogger('Generator<%s>' %
39+
self.__class__.__name__)
3640
self.target_folder_path = target_folder_path
3741
# Output is a list of strings that should be concatenated together for
3842
# the final output.
@@ -41,10 +45,13 @@ def __init__(self, api, target_folder_path):
4145
self.cur_indent = 0
4246

4347
@abstractmethod
44-
def generate(self):
48+
def generate(self, api):
4549
"""
4650
Subclasses should override this method. It's the entry point that is
4751
invoked by the rest of the toolchain.
52+
53+
Args:
54+
api (babelapi.api.Api): The API specification.
4855
"""
4956
raise NotImplemented
5057

@@ -57,7 +64,7 @@ def output_to_relative_path(self, relative_path):
5764
Clears the output buffer on enter and exit.
5865
"""
5966
full_path = os.path.join(self.target_folder_path, relative_path)
60-
self._logger.info('Generating %s', full_path)
67+
self.logger.info('Generating %s', full_path)
6168
self.output = []
6269
yield
6370
with open(full_path, 'w') as f:
@@ -278,6 +285,6 @@ class CodeGeneratorMonolingual(CodeGenerator):
278285
# An instance of a :class:`babelapi.lang.lang.TargetLanguage` object.
279286
lang = None
280287

281-
def __init__(self, api, target_folder_path):
288+
def __init__(self, target_folder_path):
282289
assert self.lang, 'Language must be specified'
283-
super(CodeGeneratorMonolingual, self).__init__(api, target_folder_path)
290+
super(CodeGeneratorMonolingual, self).__init__(target_folder_path)

doc/generator_ref.rst

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ included generator, since yours will always end in ``.babelg.py``.
5050
Generating Output Files
5151
=======================
5252

53-
To create an output file, use the ``self.output_to_relative_path()`` method.
53+
To create an output file, use the ``output_to_relative_path()`` method.
5454
Its only argument is the path relative to the output directory, which was
5555
specified as an argument to ``babelapi``, where the file should be created.
5656

@@ -61,16 +61,16 @@ Each file contains a one line C++-style comment::
6161
from babelapi.generator import CodeGenerator
6262

6363
class ExampleGenerator(CodeGenerator):
64-
def generate(self):
65-
for namespace_name in self.api.namespaces:
64+
def generate(self, api):
65+
for namespace_name in api.namespaces:
6666
with self.output_to_relative_path(namespace_name + '.cpp'):
6767
self.emit_line('/* {} */'.format(namespace_name))
6868

6969
Using the API Object
7070
====================
7171

72-
Code generators have a ``self.api`` member variable, which represents the input
73-
specs as a Python object. The object is an instance of the ``babelapi.api.Api``
72+
The ``generate`` method receives an ``api`` variable, which represents the API
73+
spec as a Python object. The object is an instance of the ``babelapi.api.Api``
7474
class. From this object, you can access all the defined namespaces, data types,
7575
and routes.
7676

@@ -218,7 +218,7 @@ manager for adding incremental indentation. Here's an example::
218218
from babelapi.generator import CodeGenerator
219219

220220
class ExampleGenerator(CodeGenerator):
221-
def generate(self):
221+
def generate(self, api):
222222
with self.output_to_relative_path('ex_indent.out'):
223223
with self.indent()
224224
self.emit_line('hello')
@@ -238,7 +238,6 @@ future.
238238
Helpers for Code Generation
239239
===========================
240240

241-
242241
``generate_multiline_list(items, before='', after='', delim=('(', ')'), compact=True, sep=',', skip_last_sep=False)``
243242
Given a list of items, emits one item per line. This is convenient for
244243
function prototypes and invocations, as well as for instantiating arrays,
@@ -270,6 +269,19 @@ Helpers for Code Generation
270269
space and then ``after``. ``dent`` is the amount to indent the block. If
271270
none, the default indentation increment is used.
272271

272+
Generator Instance Variables
273+
============================
274+
275+
logger
276+
This is an instance of the `logging.Logger
277+
<https://docs.python.org/2/library/logging.html#logger-objects>`_ class
278+
from the Python standard library. Messages written to the logger will be
279+
output to standard error as the generator runs.
280+
281+
target_folder_path
282+
The path to the output folder. Use this when the
283+
``output_to_relative_path`` method is insufficient for your purposes.
284+
273285
Examples
274286
========
275287

@@ -285,10 +297,10 @@ We'll create a generator ``ex1.babelg.py`` that generates a file called
285297
from babelapi.generator import CodeGenerator
286298

287299
class ExampleGenerator(CodeGenerator):
288-
def generate(self):
300+
def generate(self, api):
289301
"""Generates a file that lists each namespace."""
290302
with self.output_to_relative_path('ex1.out'):
291-
for namespace in self.api.namespaces.values():
303+
for namespace in api.namespaces.values():
292304
self.emit(namespace.name)
293305

294306
We use ``output_to_relative_path()`` a member of ``CodeGenerator`` to specify
@@ -314,9 +326,9 @@ a ``noop()`` function::
314326
from babelapi.generator import CodeGenerator
315327

316328
class ExamplePythonGenerator(CodeGenerator):
317-
def generate(self):
329+
def generate(self, api):
318330
"""Generates a module for each namespace."""
319-
for namespace in self.api.namespaces.values():
331+
for namespace in api.namespaces.values():
320332
# One module per namespace is created. The module takes the name
321333
# of the namespace.
322334
with self.output_to_relative_path('{}.py'.format(namespace.name)):
@@ -365,9 +377,9 @@ declared::
365377
# others use camelcase).
366378
lang = PythonTargetLanguage()
367379

368-
def generate(self):
380+
def generate(self, api):
369381
"""Generates a module for each namespace."""
370-
for namespace in self.api.namespaces.values():
382+
for namespace in api.namespaces.values():
371383
# One module per namespace is created. The module takes the name
372384
# of the namespace.
373385
with self.output_to_relative_path('{}.py'.format(namespace.name)):
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from babelapi.generator import CodeGenerator
22

33
class ExampleGenerator(CodeGenerator):
4-
def generate(self):
4+
def generate(self, api):
55
"""Generates a file that lists each namespace."""
66
with self.output_to_relative_path('ex1.out'):
7-
for namespace in self.api.namespaces.values():
7+
for namespace in api.namespaces.values():
88
self.emit(namespace.name)

example/generator/ex2/ex2.babelg.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from babelapi.generator import CodeGenerator
22

33
class ExamplePythonGenerator(CodeGenerator):
4-
def generate(self):
4+
def generate(self, api):
55
"""Generates a module for each namespace."""
6-
for namespace in self.api.namespaces.values():
6+
for namespace in api.namespaces.values():
77
# One module per namespace is created. The module takes the name
88
# of the namespace.
99
with self.output_to_relative_path('{}.py'.format(namespace.name)):

example/generator/ex3/ex3.babelg.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ class ExamplePythonGenerator(CodeGeneratorMonolingual):
99
# others use camelcase).
1010
lang = PythonTargetLanguage()
1111

12-
def generate(self):
12+
def generate(self, api):
1313
"""Generates a module for each namespace."""
14-
for namespace in self.api.namespaces.values():
14+
for namespace in api.namespaces.values():
1515
# One module per namespace is created. The module takes the name
1616
# of the namespace.
1717
with self.output_to_relative_path('{}.py'.format(namespace.name)):

generator/python/python.babelg.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,21 @@ class PythonGenerator(CodeGeneratorMonolingual):
4444

4545
lang = PythonTargetLanguage()
4646

47-
def generate(self):
47+
def generate(self, api):
4848
"""
4949
Generates a module for each namespace.
5050
5151
Each namespace will have Python classes to represent data types and
5252
routes in the Babel spec.
5353
"""
5454
cur_folder = os.path.dirname(__file__)
55-
self._logger.info('Copying babel_validators.py to output folder')
55+
self.logger.info('Copying babel_validators.py to output folder')
5656
shutil.copy(os.path.join(cur_folder, 'babel_validators.py'),
5757
self.target_folder_path)
58-
self._logger.info('Copying babel_serializers.py to output folder')
58+
self.logger.info('Copying babel_serializers.py to output folder')
5959
shutil.copy(os.path.join(cur_folder, 'babel_serializers.py'),
6060
self.target_folder_path)
61-
for namespace in self.api.namespaces.values():
61+
for namespace in api.namespaces.values():
6262
with self.output_to_relative_path('{}.py'.format(namespace.name)):
6363
self._generate_base_namespace_module(namespace)
6464

test/test_generator.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
class Tester(CodeGenerator):
1717
"""A no-op generator used to test helper methods."""
18-
def generate(self):
18+
def generate(self, api):
1919
pass
2020

2121
class TestGenerator(unittest.TestCase):
@@ -40,13 +40,13 @@ def test_api_namespace(self):
4040
self.assertNotIn(s, route_io)
4141

4242
def test_code_generator_helpers(self):
43-
t = Tester(None, None)
43+
t = Tester(None)
4444
self.assertEqual(t.filter_out_none_valued_keys({}), {})
4545
self.assertEqual(t.filter_out_none_valued_keys({'a': None}), {})
4646
self.assertEqual(t.filter_out_none_valued_keys({'a': None, 'b': 3}), {'b': 3})
4747

4848
def test_code_generator_basic_emitters(self):
49-
t = Tester(None, None)
49+
t = Tester(None)
5050

5151
# Check basic emit
5252
t.emit('hello')
@@ -87,7 +87,7 @@ def test_code_generator_basic_emitters(self):
8787
t.clear_output_buffer()
8888

8989
def test_code_generator_list_gen(self):
90-
t = Tester(None, None)
90+
t = Tester(None)
9191

9292
t.generate_multiline_list(['a=1', 'b=2'])
9393
expected = """\
@@ -164,7 +164,7 @@ def func(
164164
t.clear_output_buffer()
165165

166166
def test_code_generator_block_gen(self):
167-
t = Tester(None, None)
167+
t = Tester(None)
168168

169169
with t.block('int sq(int x)', ';'):
170170
t.emit('return x*x;')

0 commit comments

Comments
 (0)