summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore1
-rw-r--r--__init__.py (renamed from py/__init__.py)16
-rw-r--r--comments.py (renamed from py/comments.py)0
-rw-r--r--compat.py (renamed from py/compat.py)0
-rw-r--r--composer.py (renamed from py/composer.py)0
-rw-r--r--configobjwalker.py (renamed from py/configobjwalker.py)0
-rw-r--r--constructor.py (renamed from py/constructor.py)0
-rw-r--r--cyaml.py (renamed from py/cyaml.py)0
-rw-r--r--dumper.py (renamed from py/dumper.py)0
-rw-r--r--emitter.py (renamed from py/emitter.py)0
-rw-r--r--error.py (renamed from py/error.py)0
-rw-r--r--events.py (renamed from py/events.py)0
-rw-r--r--loader.py (renamed from py/loader.py)2
-rw-r--r--main.py (renamed from py/main.py)0
-rw-r--r--nodes.py (renamed from py/nodes.py)0
-rw-r--r--parser_.py (renamed from py/parser.py)0
-rw-r--r--py/yaml.py527
-rw-r--r--reader.py (renamed from py/reader.py)0
-rw-r--r--representer.py (renamed from py/representer.py)0
-rw-r--r--resolver.py (renamed from py/resolver.py)0
-rw-r--r--scalarstring.py (renamed from py/scalarstring.py)0
-rw-r--r--scanner.py (renamed from py/scanner.py)0
-rw-r--r--serializer.py (renamed from py/serializer.py)0
-rw-r--r--setup.py455
-rw-r--r--tokens.py (renamed from py/tokens.py)0
25 files changed, 324 insertions, 677 deletions
diff --git a/.hgignore b/.hgignore
index 9025cc9..4f52074 100644
--- a/.hgignore
+++ b/.hgignore
@@ -11,6 +11,7 @@ build
*.egg-info
.tox
.cache
+_yaml.so
README.pdf
ruamel
convert
diff --git a/py/__init__.py b/__init__.py
index ac41035..0da3598 100644
--- a/py/__init__.py
+++ b/__init__.py
@@ -2,6 +2,15 @@
from __future__ import absolute_import
+_package_data = dict(
+ full_package_name='ruamel.yaml',
+ version_info=(0, 10, 7),
+ author='Anthon van der Neut',
+ author_email='a.van.der.neut@ruamel.eu',
+ description="ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order", # NOQA
+ entry_points=None,
+ install_requires=['ruamel.base']
+)
def _convert_version(tup):
"""create a PEP 386 pseudo-format conformant string from tuple tup"""
@@ -21,7 +30,8 @@ def _convert_version(tup):
return ret_val
-version_info = (0, 10, 6)
+# <
+version_info = _package_data['version_info']
__version__ = _convert_version(version_info)
del _convert_version
@@ -32,6 +42,8 @@ try:
except ImportError:
__with_libyaml__ = False
+import sys
+
# body extracted to main.py
from .main import *
@@ -39,5 +51,5 @@ def main():
# No direct import of yaml in order not to pollute namespace.
# If other utility 'bodies' exist in this directory a module level
# import here, would get you all of its initialisations/imports as well
- from ruamel.yaml.yaml import main as util_main
+ from ruamel.yaml import main as util_main
util_main()
diff --git a/py/comments.py b/comments.py
index 0db9457..0db9457 100644
--- a/py/comments.py
+++ b/comments.py
diff --git a/py/compat.py b/compat.py
index dc0c51c..dc0c51c 100644
--- a/py/compat.py
+++ b/compat.py
diff --git a/py/composer.py b/composer.py
index 13436c8..13436c8 100644
--- a/py/composer.py
+++ b/composer.py
diff --git a/py/configobjwalker.py b/configobjwalker.py
index 576adcd..576adcd 100644
--- a/py/configobjwalker.py
+++ b/configobjwalker.py
diff --git a/py/constructor.py b/constructor.py
index 5ce8974..5ce8974 100644
--- a/py/constructor.py
+++ b/constructor.py
diff --git a/py/cyaml.py b/cyaml.py
index 1c9036c..1c9036c 100644
--- a/py/cyaml.py
+++ b/cyaml.py
diff --git a/py/dumper.py b/dumper.py
index f83228a..f83228a 100644
--- a/py/dumper.py
+++ b/dumper.py
diff --git a/py/emitter.py b/emitter.py
index 2e5ebdc..2e5ebdc 100644
--- a/py/emitter.py
+++ b/emitter.py
diff --git a/py/error.py b/error.py
index 2b76904..2b76904 100644
--- a/py/error.py
+++ b/error.py
diff --git a/py/events.py b/events.py
index e1b9c62..e1b9c62 100644
--- a/py/events.py
+++ b/events.py
diff --git a/py/loader.py b/loader.py
index 9c17d9b..16f01b6 100644
--- a/py/loader.py
+++ b/loader.py
@@ -4,7 +4,7 @@ __all__ = ['BaseLoader', 'SafeLoader', 'Loader', 'RoundTripLoader']
from .reader import *
from .scanner import *
-from .parser import *
+from .parser_ import *
from .composer import *
from .constructor import *
from .resolver import *
diff --git a/py/main.py b/main.py
index 90ee4d5..90ee4d5 100644
--- a/py/main.py
+++ b/main.py
diff --git a/py/nodes.py b/nodes.py
index 382b492..382b492 100644
--- a/py/nodes.py
+++ b/nodes.py
diff --git a/py/parser.py b/parser_.py
index 0afb596..0afb596 100644
--- a/py/parser.py
+++ b/parser_.py
diff --git a/py/yaml.py b/py/yaml.py
deleted file mode 100644
index 6eda0ab..0000000
--- a/py/yaml.py
+++ /dev/null
@@ -1,527 +0,0 @@
-# coding: utf-8
-
-"""
-this is the source for the yaml utility
-"""
-
-from __future__ import print_function
-from __future__ import absolute_import
-
-
-import sys
-import os
-import io
-from textwrap import dedent
-
-from ruamel.std.argparse import ProgramBase, option, sub_parser, version, \
- CountAction, SmartFormatter
-# from ruamel.appconfig import AppConfig
-from . import __version__
-
-import ruamel.yaml
-from ruamel.yaml.compat import ordereddict, DBG_TOKEN, DBG_EVENT, DBG_NODE
-from ruamel.yaml.configobjwalker import configobj_walker
-
-
-def yaml_to_html2(code):
- buf = io.StringIO()
- buf.write(u'<HTML>\n')
- buf.write(u'<HEAD>\n')
- buf.write(u'</HEAD>\n')
- buf.write(u'<BODY>\n')
- buf.write(u'<TABLE>\n')
- if isinstance(code, dict):
- for k in code:
- buf.write(u' <TR>\n')
- for x in [k] + code[k]:
- buf.write(u' <TD>{0}</TD>\n'.format(x))
- buf.write(u' </TR>\n')
- buf.write(u'<TABLE>\n')
- buf.write(u'</BODY>\n')
- buf.write(u'</HTML>\n')
- return buf.getvalue()
-
-
-def yaml_to_html(code, level):
- if level == 2:
- return yaml_to_html2(code)
- elif level == 3:
- return yaml_to_html3(code)
- raise NotImplementedError
-
-
-class YAML:
- def __init__(self, args, config):
- self._args = args
- self._config = config
-
- def from_ini(self):
- try:
- from configobj import ConfigObj
- except ImportError:
- print("to convert from .ini you need to install configobj:")
- print(" pip install configobj:")
- sys.exit(1)
- errors = 0
- doc = []
- cfg = ConfigObj(open(self._args.file))
- if self._args.test:
- print(ruamel.yaml.dump(cfg))
- return
- for line in configobj_walker(cfg):
- doc.append(line)
- joined = '\n'.join(doc)
- rto = self.round_trip_single(joined)
- if self._args.basename:
- out_fn = os.path.splitext(self._args.file)[0] + '.yaml'
- if self._args.verbose > 0:
- print('writing', out_fn)
- with open(out_fn, 'w') as fp:
- print(rto, end='', file=fp) # already has eol at eof
- else:
- print(rto, end='') # already has eol at eof
- # print()
- # if rto != joined:
- # self.diff(joined, rto, "test.ini")
- return 1 if errors else 0
-
- def test(self):
- self._args.event = self._args.node = True
- dbg = 0
- if self._args.event:
- dbg |= DBG_EVENT
- if self._args.node:
- dbg |= DBG_NODE
- os.environ['YAMLDEBUG'] = str(dbg)
- if False:
- x = ruamel.yaml.comment.Comment()
- print(sys.getsizeof(x))
- return
-
- def print_input(input):
- print(input, end='')
- print('-' * 15)
-
- def print_tokens(input):
- print('Tokens (from scanner) ' + '#' * 50)
- tokens = ruamel.yaml.scan(input, ruamel.yaml.RoundTripLoader)
- for idx, token in enumerate(tokens):
- # print(token.start_mark)
- # print(token.end_mark)
- print("{0:2} {1}".format(idx, token))
-
- def rt_events(input):
- dumper = ruamel.yaml.RoundTripDumper
- events = ruamel.yaml.parse(input, ruamel.yaml.RoundTripLoader)
- print(ruamel.yaml.emit(events, indent=False, Dumper=dumper))
-
- def rt_nodes(input):
- dumper = ruamel.yaml.RoundTripDumper
- nodes = ruamel.yaml.compose(input, ruamel.yaml.RoundTripLoader)
- print(ruamel.yaml.serialize(nodes, indent=False, Dumper=dumper))
-
- def print_events(input):
- print('Events (from parser) ' + '#' * 50)
- events = ruamel.yaml.parse(input, ruamel.yaml.RoundTripLoader)
- for idx, event in enumerate(events):
- print("{0:2} {1}".format(idx, event))
-
- def print_nodes(input):
- print('Nodes (from composer) ' + '#' * 50)
- x = ruamel.yaml.compose(input, ruamel.yaml.RoundTripLoader)
- x.dump() # dump the node
-
- def scan_file(file_name):
- inp = open(file_name).read()
- print('---------\n', file_name)
- print('---', repr(self.first_non_empty_line(inp)))
- print('<<<', repr(self.last_non_empty_line(inp)))
-
- if False:
- for x in self._args.file:
- scan_file(x)
- return
-
- if True:
- import pickle
- lines = 0
- for x in self._args.file:
- print(x, end=' ')
- if x.endswith('.yaml'):
- data = ruamel.yaml.load(open(x))
- print(len(data), end=' ')
- lines += len(data)
- out_name = x.replace('.yaml', '.pickle')
- with open(out_name, 'w') as fp:
- pickle.dump(data, fp)
- elif x.endswith('.pickle'):
- with open(x) as fp:
- data = pickle.load(fp)
- print(len(data), end=' ')
- lines += len(data)
- print()
- print('lines', lines)
- return
-
- input = dedent("""
- application: web2py
- version: 1
- runtime: python27
- api_version: 1
- threadsafe: false
-
- default_expiration: "24h"
-
- handlers:
- - url: /(?P<a>.+?)/static/(?P<b>.+)
- static_files: 'applications/\\1/static/\\2'
- upload: applications/(.+?)/static/(.+)
- secure: optional
- """)
-
- input = dedent("""\
- a:
- b: foo
- c: bar
- """)
-
- print_input(input)
- print_tokens(input)
- print_events(input)
- # rt_events(input)
- print_nodes(input)
- # rt_nodes(input)
-
- data = ruamel.yaml.load(input, ruamel.yaml.RoundTripLoader)
- print('data', data)
- if False:
- data['american'][0] = 'Fijenoord'
- l = data['american']
- l = data
- if True:
- # print type(l), '\n', dir(l)
- comment = getattr(l, '_yaml_comment', None)
- print('comment_1', comment)
- dumper = ruamel.yaml.RoundTripDumper
- print('>>>>>>>>>>')
- # print(ruamel.yaml.dump(data, default_flow_style=False,
- # Dumper=dumper), '===========')
- print("{0}=========".format(ruamel.yaml.dump(
- data,
- indent=4,
- Dumper=dumper)))
- comment = getattr(l, '_yaml_comment', None)
- print('comment_2', comment)
-
- # test end
-
- def from_json(self):
- # use roundtrip to preserve order
- errors = 0
- docs = []
- for file_name in self._args.file:
- if file_name == '-':
- inp = sys.stdin.read()
- else:
- inp = open(file_name).read()
- loader = ruamel.yaml.Loader # RoundTripLoader
- docs.append(ruamel.yaml.load(inp, loader))
- #if self._args.literal:
- # from ruamel.yaml.convert.literal import walk_tree
- # for doc in docs:
- # walk_tree(doc)
- dumper = ruamel.yaml.RoundTripDumper
- print(ruamel.yaml.dump_all(
- docs, Dumper=dumper,
- default_flow_style=self._args.flow))
- return 1 if errors else 0
-
- def to_htmltable(self):
- def vals(x):
- if isinstance(x, list):
- return x
- if isinstance(x, (dict, ordereddict)):
- return x.values()
- return []
-
- def seek_levels(x, count=0):
- my_level = count
- sub_level = 0
- for v in vals(x):
- if v is None:
- continue
- sub_level = max(sub_level, seek_levels(v, my_level+1))
- return max(my_level, sub_level)
-
- inp = open(self._args.file).read()
- loader = ruamel.yaml.RoundTripLoader
- code = ruamel.yaml.load(inp, loader)
- # assert isinstance(code, [ruamel.yaml.comments.CommentedMap])
- assert isinstance(code, (dict, list))
- levels = seek_levels(code)
- if self._args.level:
- print("levels:", levels)
- return
- print(yaml_to_html(code, levels))
-
- def from_html(self):
- from .convert.html import HTML2YAML
- h2y = HTML2YAML(self._args)
- with open(self._args.file) as fp:
- print(h2y(fp.read()))
-
- def from_csv(self):
- from .convert.from_csv import CSV2YAML
- c2y = CSV2YAML(self._args)
- c2y(self._args.file)
-
- def round_trip(self):
- errors = 0
- warnings = 0
- for file_name in self._args.file:
- inp = open(file_name).read()
- e, w, stabilize, outp = self.round_trip_input(inp)
- if w == 0:
- if self._args.verbose > 0:
- print(u"{0}: ok".format(file_name))
- continue
- if self._args.save:
- backup_file_name = file_name + '.orig'
- if not os.path.exists(backup_file_name):
- os.rename(file_name, backup_file_name)
- with open(file_name, 'w') as ofp:
- ofp.write(outp)
- if not self._args.save or self._args.verbose > 0:
- print("{0}:\n {1}".format(file_name, u', '.join(stabilize)))
- self.diff(inp, outp, file_name)
- errors += e
- warnings += w
- if errors > 0:
- return 2
- if warnings > 0:
- return 1
- return 0
-
- def round_trip_input(self, inp):
- errors = 0
- warnings = 0
- stabilize = []
- outp = self.round_trip_single(inp)
- if inp == outp:
- return errors, warnings, stabilize, outp
- warnings += 1
- if inp.split() != outp.split():
- errors += 1
- stabilize.append(u"drops info on round trip")
- else:
- if self.round_trip_single(outp) == outp:
- stabilize.append(u"stabilizes on second round trip")
- else:
- errors += 1
- ncoutp = self.round_trip_single(inp, drop_comment=True)
- if self.round_trip_single(ncoutp, drop_comment=True) == ncoutp:
- stabilize.append(u"ok without comments")
- return errors, warnings, stabilize, outp
-
- def round_trip_single(self, inp, drop_comment=False):
- explicit_start=self.first_non_empty_line(inp) == '---'
- explicit_end=self.last_non_empty_line(inp) == '...'
- indent = self._args.indent
- loader = ruamel.yaml.SafeLoader if drop_comment else \
- ruamel.yaml.RoundTripLoader
- code = ruamel.yaml.load(inp, loader)
- dumper = ruamel.yaml.SafeDumper if drop_comment else \
- ruamel.yaml.RoundTripDumper
- return ruamel.yaml.dump(
- code,
- Dumper=dumper,
- indent=indent,
- explicit_start=explicit_start,
- explicit_end=explicit_end,
- )
-
- def first_non_empty_line(self, txt):
- """return the first non-empty line of a block of text (stripped)
- do not split or strip the complete txt
- """
- pos = txt.find('\n')
- prev_pos = 0
- while pos >= 0:
- segment = txt[prev_pos:pos].strip()
- if segment:
- break
- # print (pos, repr(segment))
- prev_pos = pos
- pos = txt.find('\n', pos+1)
- return segment
-
- def last_non_empty_line(self, txt):
- """return the last non-empty line of a block of text (stripped)
- do not split or strip the complete txt
- """
- pos = txt.rfind('\n')
- prev_pos = len(txt)
- maxloop = 10
- while pos >= 0:
- segment = txt[pos:prev_pos].strip()
- if segment:
- break
- # print (pos, repr(segment))
- prev_pos = pos
- pos = txt.rfind('\n', 0, pos-1)
- maxloop -= 1
- if maxloop < 0:
- break
- return segment
-
- def diff(self, inp, outp, file_name):
- import difflib
- inl = inp.splitlines(True) # True for keepends
- outl = outp.splitlines(True)
- diff = difflib.unified_diff(inl, outl, file_name, 'round trip YAML')
- # 2.6 difflib has trailing space on filename lines %-)
- strip_trailing_space = sys.version_info < (2, 7)
- for line in diff:
- if strip_trailing_space and line[:4] in ['--- ', '+++ ']:
- line = line.rstrip() + '\n'
- sys.stdout.write(line)
-
-
-def to_stdout(*args):
- sys.stdout.write(' '.join(args))
-
-
-class YAML_Cmd(ProgramBase):
- def __init__(self):
- super(YAML_Cmd, self).__init__(
- formatter_class=SmartFormatter,
- aliases=True,
- )
- self._config = None
-
- # you can put these on __init__, but subclassing YAML_Cmd
- # will cause that to break
- @option('--verbose', '-v',
- help='increase verbosity level', action=CountAction,
- const=1, nargs=0, default=0, global_option=True)
- @option('--indent', type=int, global_option=True)
- @version('version: ' + __version__)
- def _pb_init(self):
- # special name for which attribs are included in help
- pass
-
- def run(self):
- self._yaml = YAML(self._args, self._config)
- if self._args.func:
- return self._args.func()
-
- def parse_args(self):
- # self._config = AppConfig(
- # 'yaml',
- # filename=AppConfig.check,
- # parser=self._parser, # sets --config option
- # warning=to_stdout,
- # add_save=False, # add a --save-defaults (to config) option
- # )
- # self._config._file_name can be handed to objects that need
- # to get other information from the configuration directory
- # self._config.set_defaults()
- self._parse_args()
-
- @sub_parser(
- aliases=['round-trip'],
- help='test round trip on YAML data',
- description='test round trip on YAML data',
- )
- @option('--save', action='store_true', help="""save the rewritten data back
- to the input file (if it doesn't exist a '.orig' backup will be made)
- """)
- @option('file', nargs='+')
- def rt(self):
- return self._yaml.round_trip()
-
- @sub_parser(
- aliases=['from-json'],
- help='convert json to block YAML',
- description='convert json to block YAML',
- )
- @option('--flow', action='store_true',
- help='use flow instead of block style')
- #@option('--literal', action='store_true',
- # help='convert scalars with newlines to literal block style')
- @option('file', nargs='+')
- def json(self):
- return self._yaml.from_json()
-
- @sub_parser(
- aliases=['from-ini'],
- help='convert .ini/config to block YAML',
- description='convert .ini/config to block YAML',
- )
- @option('--basename', '-b', action='store_true',
- help='re-use basename of file for .yaml file, instead of writing'
- ' to stdout')
- @option('--test', action='store_true')
- @option('file')
- def ini(self):
- return self._yaml.from_ini()
-
- @sub_parser(
- #aliases=['to-html'],
- help='convert YAML to html tables',
- description="""convert YAML to html tables. If hierarchy is two deep (
- sequence/mapping over sequence/mapping) this is mapped to one table
- If the hierarchy is three deep, a list of 2 deep tables is assumed, but
- any non-list/mapp second level items are considered text.
- Row level keys are inserted in first column (unless --no-row-key),
- item level keys are used as classes for the TD.
- """,
- )
- @option("--level", action='store_true', help="print # levels and exit")
- @option('file')
- def htmltable(self):
- return self._yaml.to_htmltable()
-
- @sub_parser('from-html',
- help='convert HTML to YAML',
- description="""convert HTML to YAML. Tags become keys with as
- value a list. The first item in the list is a key value pair with
- key ".attribute" if attributes are available followed by tag and string
- segment items. Lists with one item are by default flattened.
- """,
- )
- @option("--no-body", action='store_true',
- help="drop top level html and body from HTML code segments")
- @option("--strip", action='store_true',
- help="strip whitespace surrounding strings")
- @option('file')
- def from_html(self):
- return self._yaml.from_html()
-
- @sub_parser('from-csv',
- aliases=['csv'],
- help='convert CSV to YAML',
- description="""convert CSV to YAML.
- By default generates a list of rows, with the items in a 2nd level
- list.
- """,
- )
- @option('--delimiter')
- #@option('--quotechar')
- @option('file')
- def from_csv(self):
- return self._yaml.from_csv()
-
- if 'test' in sys.argv:
- @sub_parser(
- description='internal test function',
- )
- @option('file', nargs='*')
- def test(self):
- return self._yaml.test()
-
-
-def main():
- n = YAML_Cmd()
- n.parse_args()
- sys.exit(n.run())
diff --git a/py/reader.py b/reader.py
index 7bbec42..7bbec42 100644
--- a/py/reader.py
+++ b/reader.py
diff --git a/py/representer.py b/representer.py
index 63c0d0d..63c0d0d 100644
--- a/py/representer.py
+++ b/representer.py
diff --git a/py/resolver.py b/resolver.py
index d385b0e..d385b0e 100644
--- a/py/resolver.py
+++ b/resolver.py
diff --git a/py/scalarstring.py b/scalarstring.py
index a628396..a628396 100644
--- a/py/scalarstring.py
+++ b/scalarstring.py
diff --git a/py/scanner.py b/scanner.py
index 24a13a8..24a13a8 100644
--- a/py/scanner.py
+++ b/scanner.py
diff --git a/py/serializer.py b/serializer.py
index 0bdc558..0bdc558 100644
--- a/py/serializer.py
+++ b/serializer.py
diff --git a/setup.py b/setup.py
index ff0840b..e0b37c5 100644
--- a/setup.py
+++ b/setup.py
@@ -1,34 +1,68 @@
-#! /usr/bin/env python
+# # header
# coding: utf-8
from __future__ import print_function
-import sys
-import os
-import platform
-from textwrap import dedent
+if __name__ != '__main__':
+ raise NotImplementedError('should never include setup.py')
+
+# # definitions
-name_space = 'ruamel'
-package_name = 'yaml'
-full_package_name = name_space + '.' + package_name
+full_package_name = None
+
+
+def _package_data(fn):
+ data = {}
+ with open(fn) as fp:
+ parsing = False
+ for line in fp.readlines():
+ if line.startswith('_package_data'):
+ parsing = True
+ continue
+ if not parsing:
+ continue
+ if line.startswith(')'):
+ break
+ if '# NOQA' in line:
+ line = line.split('# NOQA', 1)[0].rstrip()
+ k, v = [x.strip() for x in line.split('=', 1)]
+ if v[-1] == ',':
+ v = v[:-1]
+ if v[0] in '\'"' and v[0] == v[-1]:
+ data[k] = v[1:-1]
+ elif v == 'None':
+ data[k] = None
+ elif v == 'True':
+ data[k] = True
+ elif v == 'False':
+ data[k] = False
+ elif v[0] == '(' and v[-1] == ')':
+ data[k] = tuple([x.strip()[1:-1] if x[0] in '\'"' else int(x)
+ for x in v[1:-1].split(', ')])
+ elif v[0] == '[' and v[-1] == ']':
+ data[k] = [x.strip()[1:-1] if x[0] in '\'"' else int(x)
+ for x in v[1:-1].split(', ')]
+ else:
+ print('Unknown: >>>>> {0!r} {1!r}'.format(k, v))
+ return data
+
+pkg_data = _package_data('__init__.py')
exclude_files = [
'setup.py',
]
+# # imports
+import os
+import sys
-def get_version():
- v_i = 'version_info = '
- for line in open('py/__init__.py'):
- if not line.startswith(v_i):
- continue
- s_e = line[len(v_i):].strip()[1:-1].split(', ')
- els = [x.strip()[1:-1] if x[0] in '\'"' else int(x) for x in s_e]
- return els
+from setuptools import setup
+from setuptools.command import install_lib
+# # helper
def _check_convert_version(tup):
- """create a PEP 386 pseudo-format conformant string from tuple tup"""
+ """Create a PEP 386 pseudo-format conformant string from tuple tup."""
ret_val = str(tup[0]) # first is always digit
next_sep = "." # separator for next extension, can be "" or "."
nr_digits = 0 # nr of adjacent digits in rest, to verify
@@ -58,29 +92,13 @@ def _check_convert_version(tup):
return ret_val
-version_info = get_version()
+version_info = pkg_data['version_info']
version_str = _check_convert_version(version_info)
-if __name__ == '__main__':
- # put here so setup.py can be imported more easily
- from setuptools import setup, find_packages, Extension, Distribution
- from setuptools.command import install_lib
-
- # windows things this is pure, that way you would get pure python
- # whl files that take precedence on Linux over source with compilable C
- if '--universal' in sys.argv:
- Distribution.is_pure = lambda *args: True
- Distribution.is_pure = lambda *args: False
-
-
class MyInstallLib(install_lib.install_lib):
- "create __init__.py on the fly"
- def run(self):
- install_lib.install_lib.run(self)
-
def install(self):
- fpp = full_package_name.split('.') # full package path
+ fpp = pkg_data['full_package_name'].split('.') # full package path
full_exclude_files = [os.path.join(*(fpp + [x]))
for x in exclude_files]
alt_files = []
@@ -95,127 +113,270 @@ class MyInstallLib(install_lib.install_lib):
return alt_files
-def check_extensions():
- """check if the C module can be build by trying to compile a small
- program against the libyaml development library"""
- if sys.platform == "win32":
- return None
- import tempfile
- import shutil
-
- import distutils.sysconfig
- import distutils.ccompiler
- from distutils.errors import CompileError, LinkError
-
- libraries = ['yaml']
-
- # write a temporary .c file to compile
- c_code = dedent("""
- #include <yaml.h>
-
- int main(int argc, char* argv[])
- {
- yaml_parser_t parser;
- parser = parser; /* prevent warning */
- return 0;
- }
- """)
- tmp_dir = tempfile.mkdtemp(prefix='tmp_ruamel_yaml_')
- ret_val = None
- try:
- bin_file_name = os.path.join(tmp_dir, 'test_yaml')
- file_name = bin_file_name + '.c'
- with open(file_name, 'w') as fp:
- fp.write(c_code)
+class NameSpacePackager(object):
+ def __init__(self, pkg_data):
+ assert isinstance(pkg_data, dict)
+ self._pkg_data = pkg_data
+ self.full_package_name = self._pkg_data['full_package_name']
+ self._split = None
+ self.depth = self.full_package_name.count('.')
+ self.command = None
+ if sys.argv[0] == 'setup.py' and sys.argv[1] == 'install' and \
+ '--single-version-externally-managed' not in sys.argv:
+ print('error: have to install with "pip install ."')
+ sys.exit(1)
+ for x in sys.argv:
+ if x[0] == '-' or x == 'setup.py':
+ continue
+ self.command = x
+ break
- # and try to compile it
- compiler = distutils.ccompiler.new_compiler()
- assert isinstance(compiler, distutils.ccompiler.CCompiler)
- distutils.sysconfig.customize_compiler(compiler)
+ @property
+ def split(self):
+ """split the full package name in list of compontents"""
+ if self._split is None:
+ fpn = self.full_package_name.split('.')
+ self._split = []
+ while fpn:
+ self._split.insert(0, '.'.join(fpn))
+ fpn = fpn[:-1]
+ for d in os.listdir('.'):
+ if not os.path.isdir(d) or d == self._split[0] or d[0] == '_':
+ continue
+ x = os.path.join(d, 'setup.py') # prevent sub-packages in namespace from being included
+ if os.path.exists(x):
+ if not os.path.exists(os.path.join(d, 'tox.ini')):
+ print('\n>>>>> found "{0}" without tox.ini <<<<<\n'
+ ''.format(x))
+ continue
+ x = os.path.join(d, '__init__.py')
+ if os.path.exists(x):
+ self._split.append(self.full_package_name + '.' + d)
+ return self._split
- try:
- compiler.link_executable(
- compiler.compile([file_name]),
- bin_file_name,
- libraries=libraries,
+ @property
+ def namespace_packages(self):
+ return self.split[:self.depth]
+
+ @property
+ def package_dir(self):
+ return {
+ # don't specify empty dir, clashes with package_data spec
+ self.full_package_name: '.',
+ self.split[0]: self.split[0],
+ }
+
+ def create_dirs(self):
+ """create the directories necessary for namespace packaging"""
+ if not os.path.exists(self.split[0]):
+ for d in self.split[:self.depth]:
+ d = os.path.join(*d.split('.'))
+ os.mkdir(d)
+ with open(os.path.join(d, '__init__.py'), 'w') as fp:
+ fp.write('import pkg_resources\n'
+ 'pkg_resources.declare_namespace(__name__)\n')
+ os.symlink(
+ # a.b gives a/b -> ..
+ # a.b.c gives a/b/c -> ../..
+ os.path.join(*['..'] * self.depth),
+ os.path.join(*self.split[self.depth].split('.'))
)
- except CompileError:
- print('libyaml compile error')
- except LinkError:
- print('libyaml link error')
- else:
- ret_val = [
- Extension(
- '_yaml',
- sources=['ext/_yaml.c'],
- libraries=libraries,
- ),
- ]
- except:
- pass
- finally:
- shutil.rmtree(tmp_dir)
- return ret_val
+ def check(self):
+ try:
+ from pip.exceptions import InstallationError
+ except ImportError:
+ return
+ # arg is either develop (pip install -e) or install
+ if self.command not in ['install', 'develop']:
+ return
-def main():
- install_requires = [
- "ruamel.base>=1.0.0",
- "ruamel.std.argparse",
- ]
- # use fast ordereddict for !!omap
- if sys.version_info[0] == 2 and \
- platform.python_implementation() == "CPython":
- install_requires.extend(['ruamel.ordereddict'])
- # if sys.version_info < (3, 4):
- # install_requires.append("")
- packages = [full_package_name] + [
- (full_package_name + '.' + x)
- for x in find_packages('py', exclude=['test'])]
- setup(
- name=full_package_name,
- version=version_str,
- description=full_package_name + " is a YAML parser/emitter that "
- "supports roundtrip preservation of comments, seq/map flow style, and "
- "map key order",
- install_requires=install_requires,
- long_description=open('README.rst').read(),
- url='https://bitbucket.org/ruamel/' + package_name,
- author='Anthon van der Neut',
- author_email='a.van.der.neut@ruamel.eu',
- license="MIT license",
- package_dir={full_package_name: 'py'},
- namespace_packages=[name_space],
- packages=packages,
- ext_modules=check_extensions(),
- #entry_points=mk_entry_points(full_package_name),
- cmdclass={'install_lib': MyInstallLib},
- classifiers=[
- 'Development Status :: 4 - Beta',
+ # if hgi and hgi.base are both in namespace_packages matching
+ # against the top (hgi.) it suffices to find minus-e and non-minus-e
+ # installed packages. As we don't know the order in namespace_packages
+ # do some magic
+ prefix = self.split[0]
+ prefixes = set([prefix, prefix.replace('_', '-')])
+ for p in sys.path:
+ if not p:
+ continue # directory with setup.py
+ if os.path.exists(os.path.join(p, 'setup.py')):
+ continue # some linked in stuff might not be hgi based
+ if not os.path.isdir(p):
+ continue
+ if p.startswith('/tmp/'):
+ continue
+ for fn in os.listdir(p):
+ for pre in prefixes:
+ if fn.startswith(pre):
+ break
+ else:
+ continue
+ full_name = os.path.join(p, fn)
+ # not in prefixes the toplevel is never changed from _ to -
+ if fn == prefix and os.path.isdir(full_name):
+ # directory -> other, non-minus-e, install
+ if self.command == 'develop':
+ raise InstallationError(
+ 'Cannot mix develop (pip install -e),\nwith '
+ 'non-develop installs for package name {0}'.format(
+ fn))
+ elif fn == prefix:
+ raise InstallationError(
+ 'non directory package {0} in {1}'.format(
+ fn, p))
+ for pre in [x + '.' for x in prefixes]:
+ if fn.startswith(pre):
+ break
+ else:
+ continue # hgiabc instead of hgi.
+ if fn.endswith('-link') and self.command == 'install':
+ raise InstallationError(
+ 'Cannot mix non-develop with develop\n(pip install -e)'
+ ' installs for package name {0}'.format(fn))
+
+ def entry_points(self, script_name=None, package_name=None):
+ ep = self._pkg_data.get('entry_points', True)
+ if ep is None:
+ return None
+ if ep is not True:
+ return {'console_scripts': [ep]}
+ if package_name is None:
+ package_name = self.full_package_name
+ if not script_name:
+ script_name = package_name.split('.')[-1]
+ return {'console_scripts': [
+ '{0} = {1}:main'.format(script_name, package_name),
+ ]}
+
+ @property
+ def url(self):
+ return 'https://bitbucket.org/{0}/{1}'.format(
+ *self.full_package_name.split('.', 1))
+
+ @property
+ def author(self):
+ return self._pkg_data['author']
+
+ @property
+ def author_email(self):
+ return self._pkg_data['author_email']
+
+ @property
+ def license(self):
+ lic = self._pkg_data.get('license')
+ if lic is None:
+ # lic_fn = os.path.join(os.path.dirname(__file__), 'LICENSE')
+ # assert os.path.exists(lic_fn)
+ return "MIT license"
+ return license
+
+ @property
+ def description(self):
+ return self._pkg_data['description']
+
+ @property
+ def status(self):
+ # αβ
+ status = self._pkg_data.get('status', 'β')
+ if status == 'α':
+ return (3, 'Alpha')
+ elif status == 'β':
+ return (4, 'Beta')
+ elif 'stable' in status.lower():
+ return (5, 'Production/Stable')
+ raise NotImplementedError
+
+ @property
+ def classifiers(self):
+ return [
+ 'Development Status :: {0} - {1}'.format(*self.status),
'Intended Audience :: Developers',
- 'License :: OSI Approved :: MIT License',
+ 'License :: ' + ('Other/Proprietary License'
+ if self._pkg_data.get('license') else
+ 'OSI Approved :: MIT License'),
'Operating System :: OS Independent',
'Programming Language :: Python',
- "Programming Language :: Python :: 2.6",
- "Programming Language :: Python :: 2.7",
- "Programming Language :: Python :: 3.3",
- "Programming Language :: Python :: 3.4",
- "Programming Language :: Python :: Implementation :: CPython",
- "Programming Language :: Python :: Implementation :: PyPy",
- "Topic :: Software Development :: Libraries :: Python Modules",
- "Topic :: Text Processing :: Markup",
]
- )
+ @property
+ def install_requires(self):
+ return pkg_data.get('install_requires', [])
+
+ @property
+ def data_files(self):
+ df = self._pkg_data.get('data_files', [])
+ if self._pkg_data.get('license') is None:
+ df.append('LICENSE')
+ if not df:
+ return None
+ return [('.', df), ]
+
+ @property
+ def package_data(self):
+ df = self._pkg_data.get('data_files', [])
+ if self._pkg_data.get('license') is None:
+ # include the file
+ df.append('LICENSE')
+ # but don't install it
+ exclude_files.append('LICENSE')
+ if not df:
+ return {}
+ return {self.full_package_name: df}
+
+ def wheel(self, kw, setup):
+ """temporary add setup.cfg if creating a wheel to include LICENSE file
+ https://bitbucket.org/pypa/wheel/issues/47
+ """
+ if 'bdist_wheel' not in sys.argv or not os.path.exists('LICENSE'):
+ return
+ file_name = 'setup.cfg'
+ if os.path.exists(file_name): # add it if not in there?
+ return
+ with open(file_name, 'w') as fp:
+ fp.write('[metadata]\nlicense-file = LICENSE\n')
+ if self._pkg_data.get('universal'):
+ fp.write('[bdist_wheel]\nuniversal = 1\n')
+ try:
+ setup(**kw)
+ except:
+ raise
+ finally:
+ os.remove(file_name)
+ return True
+
+
+# # call setup
+def main():
+ nsp = NameSpacePackager(pkg_data)
+ nsp.check()
+ nsp.create_dirs()
+ kw = dict(
+ name=nsp.full_package_name,
+ namespace_packages=nsp.namespace_packages,
+ version=version_str,
+ packages=nsp.split,
+ url=nsp.url,
+ author=nsp.author,
+ author_email=nsp.author_email,
+ cmdclass={'install_lib': MyInstallLib},
+ package_dir=nsp.package_dir,
+ entry_points=nsp.entry_points(),
+ description=nsp.description,
+ install_requires=nsp.install_requires,
+ license=nsp.license,
+ classifiers=nsp.classifiers,
+ package_data=nsp.package_data,
+ )
+ if '--version' not in sys.argv:
+ for k in sorted(kw):
+ v = kw[k]
+ print(k, '->', v)
+ with open('README.rst') as fp:
+ kw['long_description'] = fp.read()
+ if nsp.wheel(kw, setup):
+ return
+ setup(**kw)
-def mk_entry_points(full_package_name):
- script_name = full_package_name.rsplit('.', 1)[-1]
- return {'console_scripts': [
- '{0} = {1}:main'.format(script_name, full_package_name),
- ]}
-if __name__ == '__main__':
- if 'yamlctest' in sys.argv:
- print(check_extensions())
- sys.exit(1)
- main()
+main()
diff --git a/py/tokens.py b/tokens.py
index 452803f..452803f 100644
--- a/py/tokens.py
+++ b/tokens.py