Skip to content

Commit

Permalink
Merge pull request #61 from paritytrading/features/quickfix
Browse files Browse the repository at this point in the history
philadelphia-generate: Add QuickFIX support
  • Loading branch information
jvirtanen authored Jun 25, 2018
2 parents 5a6112e + 4c2c40c commit 8173798
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 14 deletions.
6 changes: 4 additions & 2 deletions applications/generate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ Philadelphia Code Generator requires Python 3.5 or newer.
Philadelphia Code Generator supports the following input sources:

- [FIX Repository][]
- [QuickFIX][]

[FIX Repository]: https://www.fixtrading.org/standards/fix-repository/
[QuickFIX]: http://www.quickfixengine.org/

## Development

Run Philadelphia Code Generator with Python:
```
python -m philadelphia.generate <command> <input-path>
python -m philadelphia.generate <command> [<configuration-file>] <input-path>
```

## Installation
Expand All @@ -29,7 +31,7 @@ python setup.py install

Run Philadelphia Code Generator:
```
philadelphia-generate <command> <input-path>
philadelphia-generate <command> [<configuration-file>] <input-path>
```

## License
Expand Down
4 changes: 4 additions & 0 deletions applications/generate/etc/example.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[dialect]
name=Example
class-name-prefix=Example
package-name=com.example.fix
48 changes: 36 additions & 12 deletions applications/generate/philadelphia/generate.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import os.path
import sys

from . import model
from . import quickfix
from . import repository


USAGE = '''\
Usage: philadelphia-generate <command> <input-path>
Usage: philadelphia-generate <command> [<configuration-file>] <input-path>
Commands:
enumerations Generate enumerations
Expand All @@ -14,24 +16,39 @@
'''


def enumerations(path):
dialect = repository.read_dialect(path)
fields = repository.read_fields(path)
def enumerations(config, path):
module = read_module(path)
dialect = read_dialect(config, module, path)
fields = module.read_fields(path)
print(model.format_enumerations(fields, dialect))


def msg_types(path):
dialect = repository.read_dialect(path)
messages = repository.read_messages(path)
def msg_types(config, path):
module = read_module(path)
dialect = read_dialect(config, module, path)
messages = module.read_messages(path)
print(model.format_msg_types(messages, dialect))


def tags(path):
dialect = repository.read_dialect(path)
fields = repository.read_fields(path)
def tags(config, path):
module = read_module(path)
dialect = read_dialect(config, module, path)
fields = module.read_fields(path)
print(model.format_tags(fields, dialect))


def read_dialect(config, module, path):
if config:
return model.read_dialect(config)
if hasattr(module, 'read_dialect'):
return module.read_dialect(path)
sys.exit('error: Missing configuration file')


def read_module(path):
return repository if os.path.isdir(path) else quickfix


COMMANDS = {
'enumerations': enumerations,
'msg-types': msg_types,
Expand All @@ -40,14 +57,21 @@ def tags(path):


def main():
if len(sys.argv) != 3:
if len(sys.argv) != 3 and len(sys.argv) != 4:
sys.exit(USAGE)

command = COMMANDS.get(sys.argv[1])
if not command:
sys.exit('error: {}: Unknown command'.format(sys.argv[1]))

command(sys.argv[2])
if len(sys.argv) == 4:
config = sys.argv[2]
path = sys.argv[3]
else:
config = None
path = sys.argv[2]

command(config, path)


if __name__ == '__main__':
Expand Down
10 changes: 10 additions & 0 deletions applications/generate/philadelphia/model.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import collections
import configparser

from . import java

Expand All @@ -15,6 +16,15 @@
Message = collections.namedtuple('Message', ['name', 'msg_type'])


def read_dialect(filename):
config = configparser.ConfigParser()
config.read(filename)
package_name = config['dialect']['package-name']
class_name_prefix = config['dialect']['class-name-prefix']
name = config['dialect']['name']
return Dialect(package_name, class_name_prefix, name)


def format_enumerations(fields, dialect):
name = '{}Enumerations'.format(dialect.class_name_prefix)
javadoc = 'Enumerations for {}.'.format(dialect.name)
Expand Down
46 changes: 46 additions & 0 deletions applications/generate/philadelphia/quickfix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import xml.etree.ElementTree

from . import model


def read_messages(filename):
def message(elem):
name = elem.get('name')
msgtype = elem.get('msgtype')
return model.Message(name=name, msg_type=msgtype)
root = xml.etree.ElementTree.parse(filename).find('messages')
return [message(elem) for elem in root.findall('message')]


def read_fields(filename):
def value(elem):
enum = elem.get('enum')
description = elem.get('description')
return model.Value(name=description, value=enum)
def field(root):
number = root.get('number')
name = root.get('name')
type_ = _type(root)
if name == 'MsgType' or not type_:
values = []
else:
values = [value(elem) for elem in root.findall('value')]
return model.Field(tag=number, name=name, type_=type_, values=values)
root = xml.etree.ElementTree.parse(filename).find('fields')
return sorted([field(elem) for elem in root.findall('field')],
key=lambda field: int(field.tag))


_TYPES = {
'CHAR': 'char',
'INT': 'int',
'MULTIPLECHARVALUE': 'char',
'MULTIPLESTRINGVALUE': 'String',
'NUMINGROUP': 'int',
'STRING': 'String',
}


def _type(elem):
type_ = elem.get('type')
return _TYPES.get(type_)
2 changes: 2 additions & 0 deletions scripts/archive.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ applications/client/README.md
applications/client/etc/example.conf
applications/client/philadelphia-client.jar
applications/generate/README.md
applications/generate/etc/example.ini
applications/generate/philadelphia/__init__.py
applications/generate/philadelphia/generate.py
applications/generate/philadelphia/java.py
applications/generate/philadelphia/model.py
applications/generate/philadelphia/quickfix.py
applications/generate/philadelphia/repository.py
applications/generate/setup.py
examples/acceptor/README.md
Expand Down

0 comments on commit 8173798

Please sign in to comment.