Added setup.py and other build tools like versioneer. Split functionlaity into modules so that new filters are easier to write.tags/nilmtools-0.1^0
@@ -0,0 +1 @@ | |||
nilmtools/_version.py export-subst |
@@ -0,0 +1,6 @@ | |||
build/ | |||
*.pyc | |||
dist/ | |||
*.egg-info/ | |||
MANIFEST.in | |||
MANIFEST |
@@ -0,0 +1,24 @@ | |||
all: | |||
@echo "Try 'make install'" | |||
version: | |||
python setup.py version | |||
dist: sdist | |||
sdist: | |||
python setup.py sdist | |||
install: | |||
python setup.py install | |||
develop: | |||
python setup.py develop | |||
clean:: | |||
find . -name '*pyc' | xargs rm -f | |||
rm -rf nilmtools.egg-info/ build/ MANIFEST.in | |||
gitclean:: | |||
git clean -dXf | |||
.PHONY: all version dist sdist install clean gitclean |
@@ -0,0 +1,14 @@ | |||
nilmtools: Tools and utilities for interacting with the NILM Database, | |||
or writing programs that interact with the NILM database. | |||
by Jim Paris <jim@jtan.com> | |||
Prerequisites: | |||
# Runtime and build environments | |||
sudo apt-get install python2.7 python2.7-dev python-setuptools | |||
nilmdb (1.3.1+) | |||
Install: | |||
python setup.py install |
@@ -1,155 +0,0 @@ | |||
#!/usr/bin/python | |||
import nilmdb.client | |||
from nilmdb.utils.printf import * | |||
from nilmdb.utils.time import parse_time, format_time | |||
import time | |||
import sys | |||
import re | |||
import argparse | |||
import subprocess | |||
class ParseError(Exception): | |||
def __init__(self, filename, error): | |||
msg = filename + ": " + error | |||
super(ParseError, self).__init__(msg) | |||
parser = argparse.ArgumentParser(description = """\ | |||
Insert data from ethstream, either live (using the system time as a | |||
reference) or prerecorded (using comments in the file as a reference). | |||
The data is assumed to have been recorded at the specified rate. | |||
Small discrepencies between the accumulated timestamps and the | |||
reference time are ignored; larger discrepencies cause gaps to be | |||
created in the stream. Overlapping data returns an error. | |||
""", formatter_class = argparse.RawDescriptionHelpFormatter) | |||
parser.add_argument("-u", "--url", action="store", | |||
default="http://localhost:12380/", | |||
help="NilmDB server URL (default: %(default)s)") | |||
parser.add_argument("-r", "--rate", action="store", default=8000, type=float, | |||
help="Data rate in Hz (default: %(default)s)") | |||
parser.add_argument("-l", "--live", action="store_true", | |||
help="Live capture; use system time to verify rate") | |||
parser.add_argument("path", action="store", | |||
help="Path of stream, e.g. /foo/bar") | |||
parser.add_argument("infile", type=argparse.FileType('r'), nargs='*', | |||
default=[sys.stdin], help="Input files (default: stdin)") | |||
args = parser.parse_args() | |||
printf("Stream path: %s\n", args.path) | |||
printf(" Data rate: %s Hz\n", repr(args.rate)) | |||
client = nilmdb.client.Client(args.url) | |||
# Local copies to save dictionary lookups | |||
live = args.live | |||
# data_ts is the timestamp that we'll use for the current line | |||
data_ts_base = 0 | |||
data_ts_inc = 0 | |||
data_ts_step = 1.0 / args.rate | |||
# clock_ts is the imprecise "real" timestamp (from the filename, | |||
# comments, or or system clock) | |||
clock_ts = None | |||
def print_clock_updated(): | |||
printf("Clock time updated to %s\n", format_time(clock_ts)) | |||
if data_ts_base != 0: | |||
diff = data_ts - clock_ts | |||
if diff >= 0: | |||
printf(" (data timestamp ahead by %.6f sec)\n", diff) | |||
else: | |||
printf(" (data timestamp behind by %.6f sec)\n", -diff) | |||
with client.stream_insert_context(args.path) as stream: | |||
for f in args.infile: | |||
filename = f.name | |||
printf("Processing %s\n", filename) | |||
# If the filename ends in .gz, open it with gzcat instead. | |||
if filename.endswith(".gz"): | |||
p = subprocess.Popen(["gzip", "-dc"], | |||
stdin = f, stdout = subprocess.PIPE) | |||
f = p.stdout | |||
# Try to get a real timestamp from the filename | |||
try: | |||
# Subtract 1 hour because files are created at the end of the hour. | |||
# Hopefully, we'll be able to use internal comments and this value | |||
# won't matter anyway. | |||
clock_ts = parse_time(filename).totimestamp() - 3600 | |||
print_clock_updated() | |||
except ValueError: | |||
pass | |||
truncated_lines = 0 | |||
# Read each line | |||
for line in f: | |||
data_ts = data_ts_base + data_ts_inc * data_ts_step | |||
# If no content other than the newline, skip it | |||
if len(line) <= 1: | |||
continue | |||
# If line starts with a comment, look for a timestamp | |||
if line[0] == '#': | |||
try: | |||
clock_ts = parse_time(line[1:]).totimestamp() | |||
print_clock_updated() | |||
except ValueError: | |||
pass | |||
continue | |||
# If inserting live, use clock timestamp | |||
if live: | |||
clock_ts = time.time() | |||
# If we have a real timestamp, compare it to the data | |||
# timestamp, and make sure things match up. | |||
if clock_ts is not None: | |||
if (data_ts - 10) > clock_ts: | |||
# Accumulated line timestamps are in the future. | |||
# If we were to set data_ts=clock_ts, we'd create | |||
# an overlap, so we have to just bail out here. | |||
err = sprintf("Data is coming in too fast: data time is %s " | |||
"but clock time is only %s", | |||
format_time(data_ts), format_time(clock_ts)) | |||
raise ParseError(filename, err) | |||
if (data_ts + 10) < clock_ts: | |||
# Accumulated line timetamps are in the past. We | |||
# can just skip some time and leave a gap in the | |||
# data. | |||
if data_ts_base != 0: | |||
printf("Skipping data timestamp forward from %s to %s " | |||
"to match clock time\n", | |||
format_time(data_ts), format_time(clock_ts)) | |||
stream.finalize() | |||
data_ts_base = data_ts = clock_ts | |||
data_ts_inc = 0 | |||
# Don't use this clock time anymore until we update it | |||
clock_ts = None | |||
if data_ts_base == 0: | |||
raise ParseError(filename, "No idea what timestamp to use") | |||
# This line is legit, so increment timestamp | |||
data_ts_inc += 1 | |||
# Once in a while a line might be truncated, if we're at | |||
# the end of a file. Ignore it, but if we ignore too many, | |||
# bail out. | |||
if line[-1] != '\n': | |||
truncated_lines += 1 | |||
if truncated_lines > 3: | |||
raise ParseError(filename, "too many short lines") | |||
printf("Ignoring short line in %s\n", filename) | |||
continue | |||
# Insert it | |||
stream.insert("%.6f %s" % (data_ts, line)) | |||
print "Done" |
@@ -0,0 +1,4 @@ | |||
from ._version import get_versions | |||
__version__ = get_versions()['version'] | |||
del get_versions |
@@ -0,0 +1,197 @@ | |||
IN_LONG_VERSION_PY = True | |||
# This file helps to compute a version number in source trees obtained from | |||
# git-archive tarball (such as those provided by githubs download-from-tag | |||
# feature). Distribution tarballs (build by setup.py sdist) and build | |||
# directories (produced by setup.py build) will contain a much shorter file | |||
# that just contains the computed version number. | |||
# This file is released into the public domain. Generated by | |||
# versioneer-0.7+ (https://github.com/warner/python-versioneer) | |||
# these strings will be replaced by git during git-archive | |||
git_refnames = "$Format:%d$" | |||
git_full = "$Format:%H$" | |||
import subprocess | |||
import sys | |||
def run_command(args, cwd=None, verbose=False): | |||
try: | |||
# remember shell=False, so use git.cmd on windows, not just git | |||
p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) | |||
except EnvironmentError: | |||
e = sys.exc_info()[1] | |||
if verbose: | |||
print("unable to run %s" % args[0]) | |||
print(e) | |||
return None | |||
stdout = p.communicate()[0].strip() | |||
if sys.version >= '3': | |||
stdout = stdout.decode() | |||
if p.returncode != 0: | |||
if verbose: | |||
print("unable to run %s (error)" % args[0]) | |||
return None | |||
return stdout | |||
import sys | |||
import re | |||
import os.path | |||
def get_expanded_variables(versionfile_source): | |||
# the code embedded in _version.py can just fetch the value of these | |||
# variables. When used from setup.py, we don't want to import | |||
# _version.py, so we do it with a regexp instead. This function is not | |||
# used from _version.py. | |||
variables = {} | |||
try: | |||
for line in open(versionfile_source,"r").readlines(): | |||
if line.strip().startswith("git_refnames ="): | |||
mo = re.search(r'=\s*"(.*)"', line) | |||
if mo: | |||
variables["refnames"] = mo.group(1) | |||
if line.strip().startswith("git_full ="): | |||
mo = re.search(r'=\s*"(.*)"', line) | |||
if mo: | |||
variables["full"] = mo.group(1) | |||
except EnvironmentError: | |||
pass | |||
return variables | |||
def versions_from_expanded_variables(variables, tag_prefix, verbose=False): | |||
refnames = variables["refnames"].strip() | |||
if refnames.startswith("$Format"): | |||
if verbose: | |||
print("variables are unexpanded, not using") | |||
return {} # unexpanded, so not in an unpacked git-archive tarball | |||
refs = set([r.strip() for r in refnames.strip("()").split(",")]) | |||
for ref in list(refs): | |||
if not re.search(r'\d', ref): | |||
if verbose: | |||
print("discarding '%s', no digits" % ref) | |||
refs.discard(ref) | |||
# Assume all version tags have a digit. git's %d expansion | |||
# behaves like git log --decorate=short and strips out the | |||
# refs/heads/ and refs/tags/ prefixes that would let us | |||
# distinguish between branches and tags. By ignoring refnames | |||
# without digits, we filter out many common branch names like | |||
# "release" and "stabilization", as well as "HEAD" and "master". | |||
if verbose: | |||
print("remaining refs: %s" % ",".join(sorted(refs))) | |||
for ref in sorted(refs): | |||
# sorting will prefer e.g. "2.0" over "2.0rc1" | |||
if ref.startswith(tag_prefix): | |||
r = ref[len(tag_prefix):] | |||
if verbose: | |||
print("picking %s" % r) | |||
return { "version": r, | |||
"full": variables["full"].strip() } | |||
# no suitable tags, so we use the full revision id | |||
if verbose: | |||
print("no suitable tags, using full revision id") | |||
return { "version": variables["full"].strip(), | |||
"full": variables["full"].strip() } | |||
def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): | |||
# this runs 'git' from the root of the source tree. That either means | |||
# someone ran a setup.py command (and this code is in versioneer.py, so | |||
# IN_LONG_VERSION_PY=False, thus the containing directory is the root of | |||
# the source tree), or someone ran a project-specific entry point (and | |||
# this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the | |||
# containing directory is somewhere deeper in the source tree). This only | |||
# gets called if the git-archive 'subst' variables were *not* expanded, | |||
# and _version.py hasn't already been rewritten with a short version | |||
# string, meaning we're inside a checked out source tree. | |||
try: | |||
here = os.path.abspath(__file__) | |||
except NameError: | |||
# some py2exe/bbfreeze/non-CPython implementations don't do __file__ | |||
return {} # not always correct | |||
# versionfile_source is the relative path from the top of the source tree | |||
# (where the .git directory might live) to this file. Invert this to find | |||
# the root from __file__. | |||
root = here | |||
if IN_LONG_VERSION_PY: | |||
for i in range(len(versionfile_source.split("/"))): | |||
root = os.path.dirname(root) | |||
else: | |||
root = os.path.dirname(here) | |||
if not os.path.exists(os.path.join(root, ".git")): | |||
if verbose: | |||
print("no .git in %s" % root) | |||
return {} | |||
GIT = "git" | |||
if sys.platform == "win32": | |||
GIT = "git.cmd" | |||
stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], | |||
cwd=root) | |||
if stdout is None: | |||
return {} | |||
if not stdout.startswith(tag_prefix): | |||
if verbose: | |||
print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix)) | |||
return {} | |||
tag = stdout[len(tag_prefix):] | |||
stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root) | |||
if stdout is None: | |||
return {} | |||
full = stdout.strip() | |||
if tag.endswith("-dirty"): | |||
full += "-dirty" | |||
return {"version": tag, "full": full} | |||
def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False): | |||
if IN_LONG_VERSION_PY: | |||
# We're running from _version.py. If it's from a source tree | |||
# (execute-in-place), we can work upwards to find the root of the | |||
# tree, and then check the parent directory for a version string. If | |||
# it's in an installed application, there's no hope. | |||
try: | |||
here = os.path.abspath(__file__) | |||
except NameError: | |||
# py2exe/bbfreeze/non-CPython don't have __file__ | |||
return {} # without __file__, we have no hope | |||
# versionfile_source is the relative path from the top of the source | |||
# tree to _version.py. Invert this to find the root from __file__. | |||
root = here | |||
for i in range(len(versionfile_source.split("/"))): | |||
root = os.path.dirname(root) | |||
else: | |||
# we're running from versioneer.py, which means we're running from | |||
# the setup.py in a source tree. sys.argv[0] is setup.py in the root. | |||
here = os.path.abspath(sys.argv[0]) | |||
root = os.path.dirname(here) | |||
# Source tarballs conventionally unpack into a directory that includes | |||
# both the project name and a version string. | |||
dirname = os.path.basename(root) | |||
if not dirname.startswith(parentdir_prefix): | |||
if verbose: | |||
print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" % | |||
(root, dirname, parentdir_prefix)) | |||
return None | |||
return {"version": dirname[len(parentdir_prefix):], "full": ""} | |||
tag_prefix = "nilmtools-" | |||
parentdir_prefix = "nilmtools-" | |||
versionfile_source = "nilmtools/_version.py" | |||
def get_versions(default={"version": "unknown", "full": ""}, verbose=False): | |||
variables = { "refnames": git_refnames, "full": git_full } | |||
ver = versions_from_expanded_variables(variables, tag_prefix, verbose) | |||
if not ver: | |||
ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) | |||
if not ver: | |||
ver = versions_from_parentdir(parentdir_prefix, versionfile_source, | |||
verbose) | |||
if not ver: | |||
ver = default | |||
return ver | |||
@@ -0,0 +1,66 @@ | |||
#!/usr/bin/python | |||
import nilmdb.client | |||
from nilmdb.utils.printf import * | |||
from nilmdb.utils.time import parse_time, format_time | |||
import time | |||
import sys | |||
import re | |||
import argparse | |||
class Filter(object): | |||
def __init__(self, description = "Filter data"): | |||
self.args = None | |||
self._client = None | |||
self.parse_args(description) | |||
def parse_args(self, description): | |||
parser = argparse.ArgumentParser( | |||
description = description, | |||
formatter_class = argparse.RawDescriptionHelpFormatter) | |||
parser.add_argument("-u", "--url", action="store", | |||
default="http://localhost:12380/", | |||
help="Server URL (default: %(default)s)") | |||
parser.add_argument("srcpath", action="store", | |||
help="Path of source stream, e.g. /foo/bar") | |||
parser.add_argument("destpath", action="store", | |||
help="Path of destination stream, e.g. /foo/bar") | |||
self.args = parser.parse_args() | |||
self._client = nilmdb.client.Client(args.url) | |||
if args.srcpath == args.destpath: | |||
raise Exception("source and destination path must be different") | |||
# Open and print info about the streams | |||
def stream_info_string(info): | |||
return sprintf("%s (%s), %.2fM rows, %.2f hours\n", | |||
info[0], info[1], info[4] / 1e6, info[5] / 3600) | |||
src = self._client.stream_list(args.srcpath, extended = True) | |||
if len(src) != 1: | |||
raise Exception("source path " + args.srcpath + " not found") | |||
print "Source:", stream_info_string(src[0]) | |||
dest = self._client.stream_list(args.destpath, extended = True) | |||
if len(dest) != 1: | |||
raise Exception("destination path " + args.destpath + " not found") | |||
print " Dest:", stream_info_string(dest[0]) | |||
def intervals(self): | |||
"""Generate all the intervals that this filter should process""" | |||
for i in self._client.stream_intervals( | |||
args.srcpath, diffpath = args.destpath): | |||
yield i | |||
def main(): | |||
# This is just a dummy function; actual filters can use the other | |||
# functions to prepare stuff, and then do something with the data. | |||
f = Filter() | |||
for interval in f.intervals(): | |||
print "Generic filter: need to handle interval:", interval | |||
if __name__ == "__main__": | |||
main() |
@@ -0,0 +1,167 @@ | |||
#!/usr/bin/python | |||
import nilmdb.client | |||
from nilmdb.utils.printf import * | |||
from nilmdb.utils.time import parse_time, format_time | |||
import time | |||
import sys | |||
import re | |||
import argparse | |||
import subprocess | |||
class ParseError(Exception): | |||
def __init__(self, filename, error): | |||
msg = filename + ": " + error | |||
super(ParseError, self).__init__(msg) | |||
def parse_args(): | |||
parser = argparse.ArgumentParser(description = """\ | |||
Insert data from ethstream, either live (using the system time as a | |||
reference) or prerecorded (using comments in the file as a reference). | |||
The data is assumed to have been recorded at the specified rate. | |||
Small discrepencies between the accumulated timestamps and the | |||
reference time are ignored; larger discrepencies cause gaps to be | |||
created in the stream. Overlapping data returns an error. | |||
""", formatter_class = argparse.RawDescriptionHelpFormatter) | |||
parser.add_argument("-u", "--url", action="store", | |||
default="http://localhost:12380/", | |||
help="NilmDB server URL (default: %(default)s)") | |||
parser.add_argument("-r", "--rate", action="store", default=8000, type=float, | |||
help="Data rate in Hz (default: %(default)s)") | |||
parser.add_argument("-l", "--live", action="store_true", | |||
help="Live capture; use system time to verify rate") | |||
parser.add_argument("path", action="store", | |||
help="Path of stream, e.g. /foo/bar") | |||
parser.add_argument("infile", type=argparse.FileType('r'), nargs='*', | |||
default=[sys.stdin], help="Input files (default: stdin)") | |||
args = parser.parse_args() | |||
printf("Stream path: %s\n", args.path) | |||
printf(" Data rate: %s Hz\n", repr(args.rate)) | |||
return args | |||
def main(args = None): | |||
if args is None: | |||
args = parse_args() | |||
client = nilmdb.client.Client(args.url) | |||
# Local copies to save dictionary lookups | |||
live = args.live | |||
# data_ts is the timestamp that we'll use for the current line | |||
data_ts_base = 0 | |||
data_ts_inc = 0 | |||
data_ts_step = 1.0 / args.rate | |||
# clock_ts is the imprecise "real" timestamp (from the filename, | |||
# comments, or or system clock) | |||
clock_ts = None | |||
def print_clock_updated(): | |||
printf("Clock time updated to %s\n", format_time(clock_ts)) | |||
if data_ts_base != 0: | |||
diff = data_ts - clock_ts | |||
if diff >= 0: | |||
printf(" (data timestamp ahead by %.6f sec)\n", diff) | |||
else: | |||
printf(" (data timestamp behind by %.6f sec)\n", -diff) | |||
with client.stream_insert_context(args.path) as stream: | |||
for f in args.infile: | |||
filename = f.name | |||
printf("Processing %s\n", filename) | |||
# If the filename ends in .gz, open it with gzcat instead. | |||
if filename.endswith(".gz"): | |||
p = subprocess.Popen(["gzip", "-dc"], | |||
stdin = f, stdout = subprocess.PIPE) | |||
f = p.stdout | |||
# Try to get a real timestamp from the filename | |||
try: | |||
# Subtract 1 hour because files are created at the end | |||
# of the hour. Hopefully, we'll be able to use | |||
# internal comments and this value won't matter anyway. | |||
clock_ts = parse_time(filename).totimestamp() - 3600 | |||
print_clock_updated() | |||
except ValueError: | |||
pass | |||
truncated_lines = 0 | |||
# Read each line | |||
for line in f: | |||
data_ts = data_ts_base + data_ts_inc * data_ts_step | |||
# If no content other than the newline, skip it | |||
if len(line) <= 1: | |||
continue | |||
# If line starts with a comment, look for a timestamp | |||
if line[0] == '#': | |||
try: | |||
clock_ts = parse_time(line[1:]).totimestamp() | |||
print_clock_updated() | |||
except ValueError: | |||
pass | |||
continue | |||
# If inserting live, use clock timestamp | |||
if live: | |||
clock_ts = time.time() | |||
# If we have a real timestamp, compare it to the data | |||
# timestamp, and make sure things match up. | |||
if clock_ts is not None: | |||
if (data_ts - 10) > clock_ts: | |||
# Accumulated line timestamps are in the future. | |||
# If we were to set data_ts=clock_ts, we'd create | |||
# an overlap, so we have to just bail out here. | |||
err = sprintf("Data is coming in too fast: data time " | |||
"is %s but clock time is only %s", | |||
format_time(data_ts), | |||
format_time(clock_ts)) | |||
raise ParseError(filename, err) | |||
if (data_ts + 10) < clock_ts: | |||
# Accumulated line timetamps are in the past. We | |||
# can just skip some time and leave a gap in the | |||
# data. | |||
if data_ts_base != 0: | |||
printf("Skipping data timestamp forward from " | |||
"%s to %s to match clock time\n", | |||
format_time(data_ts), | |||
format_time(clock_ts)) | |||
stream.finalize() | |||
data_ts_base = data_ts = clock_ts | |||
data_ts_inc = 0 | |||
# Don't use this clock time anymore until we update it | |||
clock_ts = None | |||
if data_ts_base == 0: | |||
raise ParseError(filename, "No idea what timestamp to use") | |||
# This line is legit, so increment timestamp | |||
data_ts_inc += 1 | |||
# Once in a while a line might be truncated, if we're at | |||
# the end of a file. Ignore it, but if we ignore too many, | |||
# bail out. | |||
if line[-1] != '\n': | |||
truncated_lines += 1 | |||
if truncated_lines > 3: | |||
raise ParseError(filename, "too many short lines") | |||
printf("Ignoring short line in %s\n", filename) | |||
continue | |||
# Insert it | |||
stream.insert("%.6f %s" % (data_ts, line)) | |||
print "Done" | |||
if __name__ == "__main__": | |||
main() |
@@ -0,0 +1,75 @@ | |||
#!/usr/bin/python | |||
# To release a new version, tag it: | |||
# git tag -a nilmtools-1.1 -m "Version 1.1" | |||
# git push --tags | |||
# Then just package it up: | |||
# python setup.py sdist | |||
# This is supposed to be using Distribute: | |||
# | |||
# distutils provides a "setup" method. | |||
# setuptools is a set of monkeypatches on top of that. | |||
# distribute is a particular version/implementation of setuptools. | |||
# | |||
# So we don't really know if this is using the old setuptools or the | |||
# Distribute-provided version of setuptools. | |||
import traceback | |||
import sys | |||
import os | |||
try: | |||
from setuptools import setup, find_packages | |||
import distutils.version | |||
except ImportError: | |||
traceback.print_exc() | |||
print "Please install the prerequisites listed in README.txt" | |||
sys.exit(1) | |||
# Versioneer manages version numbers from git tags. | |||
# https://github.com/warner/python-versioneer | |||
import versioneer | |||
versioneer.versionfile_source = 'nilmtools/_version.py' | |||
versioneer.versionfile_build = 'nilmtools/_version.py' | |||
versioneer.tag_prefix = 'nilmtools-' | |||
versioneer.parentdir_prefix = 'nilmtools-' | |||
# Hack to workaround logging/multiprocessing issue: | |||
# https://groups.google.com/d/msg/nose-users/fnJ-kAUbYHQ/_UsLN786ygcJ | |||
try: import multiprocessing | |||
except: pass | |||
# We need a MANIFEST.in. Generate it here rather than polluting the | |||
# repository with yet another setup-related file. | |||
with open("MANIFEST.in", "w") as m: | |||
m.write(""" | |||
# Root | |||
include README.txt | |||
include setup.py | |||
include versioneer.py | |||
include Makefile | |||
""") | |||
# Run setup | |||
setup(name='nilmtools', | |||
version = versioneer.get_version(), | |||
cmdclass = versioneer.get_cmdclass(), | |||
url = 'https://git.jim.sh/jim/lees/nilmtools.git', | |||
author = 'Jim Paris', | |||
description = "NILM Database Tools", | |||
long_description = "NILM Database Tools", | |||
license = "Proprietary", | |||
author_email = 'jim@jtan.com', | |||
install_requires = [ 'nilmdb >= 1.3.0', | |||
], | |||
packages = [ 'nilmtools', | |||
], | |||
entry_points = { | |||
'console_scripts': [ | |||
'nilm-decimate = nilmtools.decimate:main', | |||
'nilm-insert = nilmtools.insert:main', | |||
], | |||
}, | |||
zip_safe = False, | |||
) |
@@ -0,0 +1,655 @@ | |||
#! /usr/bin/python | |||
"""versioneer.py | |||
(like a rocketeer, but for versions) | |||
* https://github.com/warner/python-versioneer | |||
* Brian Warner | |||
* License: Public Domain | |||
* Version: 0.7+ | |||
This file helps distutils-based projects manage their version number by just | |||
creating version-control tags. | |||
For developers who work from a VCS-generated tree (e.g. 'git clone' etc), | |||
each 'setup.py version', 'setup.py build', 'setup.py sdist' will compute a | |||
version number by asking your version-control tool about the current | |||
checkout. The version number will be written into a generated _version.py | |||
file of your choosing, where it can be included by your __init__.py | |||
For users who work from a VCS-generated tarball (e.g. 'git archive'), it will | |||
compute a version number by looking at the name of the directory created when | |||
te tarball is unpacked. This conventionally includes both the name of the | |||
project and a version number. | |||
For users who work from a tarball built by 'setup.py sdist', it will get a | |||
version number from a previously-generated _version.py file. | |||
As a result, loading code directly from the source tree will not result in a | |||
real version. If you want real versions from VCS trees (where you frequently | |||
update from the upstream repository, or do new development), you will need to | |||
do a 'setup.py version' after each update, and load code from the build/ | |||
directory. | |||
You need to provide this code with a few configuration values: | |||
versionfile_source: | |||
A project-relative pathname into which the generated version strings | |||
should be written. This is usually a _version.py next to your project's | |||
main __init__.py file. If your project uses src/myproject/__init__.py, | |||
this should be 'src/myproject/_version.py'. This file should be checked | |||
in to your VCS as usual: the copy created below by 'setup.py | |||
update_files' will include code that parses expanded VCS keywords in | |||
generated tarballs. The 'build' and 'sdist' commands will replace it with | |||
a copy that has just the calculated version string. | |||
versionfile_build: | |||
Like versionfile_source, but relative to the build directory instead of | |||
the source directory. These will differ when your setup.py uses | |||
'package_dir='. If you have package_dir={'myproject': 'src/myproject'}, | |||
then you will probably have versionfile_build='myproject/_version.py' and | |||
versionfile_source='src/myproject/_version.py'. | |||
tag_prefix: a string, like 'PROJECTNAME-', which appears at the start of all | |||
VCS tags. If your tags look like 'myproject-1.2.0', then you | |||
should use tag_prefix='myproject-'. If you use unprefixed tags | |||
like '1.2.0', this should be an empty string. | |||
parentdir_prefix: a string, frequently the same as tag_prefix, which | |||
appears at the start of all unpacked tarball filenames. If | |||
your tarball unpacks into 'myproject-1.2.0', this should | |||
be 'myproject-'. | |||
To use it: | |||
1: include this file in the top level of your project | |||
2: make the following changes to the top of your setup.py: | |||
import versioneer | |||
versioneer.versionfile_source = 'src/myproject/_version.py' | |||
versioneer.versionfile_build = 'myproject/_version.py' | |||
versioneer.tag_prefix = '' # tags are like 1.2.0 | |||
versioneer.parentdir_prefix = 'myproject-' # dirname like 'myproject-1.2.0' | |||
3: add the following arguments to the setup() call in your setup.py: | |||
version=versioneer.get_version(), | |||
cmdclass=versioneer.get_cmdclass(), | |||
4: run 'setup.py update_files', which will create _version.py, and will | |||
append the following to your __init__.py: | |||
from _version import __version__ | |||
5: modify your MANIFEST.in to include versioneer.py | |||
6: add both versioneer.py and the generated _version.py to your VCS | |||
""" | |||
import os, sys, re | |||
from distutils.core import Command | |||
from distutils.command.sdist import sdist as _sdist | |||
from distutils.command.build_py import build_py as _build_py | |||
versionfile_source = None | |||
versionfile_build = None | |||
tag_prefix = None | |||
parentdir_prefix = None | |||
VCS = "git" | |||
IN_LONG_VERSION_PY = False | |||
LONG_VERSION_PY = ''' | |||
IN_LONG_VERSION_PY = True | |||
# This file helps to compute a version number in source trees obtained from | |||
# git-archive tarball (such as those provided by githubs download-from-tag | |||
# feature). Distribution tarballs (build by setup.py sdist) and build | |||
# directories (produced by setup.py build) will contain a much shorter file | |||
# that just contains the computed version number. | |||
# This file is released into the public domain. Generated by | |||
# versioneer-0.7+ (https://github.com/warner/python-versioneer) | |||
# these strings will be replaced by git during git-archive | |||
git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" | |||
git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" | |||
import subprocess | |||
import sys | |||
def run_command(args, cwd=None, verbose=False): | |||
try: | |||
# remember shell=False, so use git.cmd on windows, not just git | |||
p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) | |||
except EnvironmentError: | |||
e = sys.exc_info()[1] | |||
if verbose: | |||
print("unable to run %%s" %% args[0]) | |||
print(e) | |||
return None | |||
stdout = p.communicate()[0].strip() | |||
if sys.version >= '3': | |||
stdout = stdout.decode() | |||
if p.returncode != 0: | |||
if verbose: | |||
print("unable to run %%s (error)" %% args[0]) | |||
return None | |||
return stdout | |||
import sys | |||
import re | |||
import os.path | |||
def get_expanded_variables(versionfile_source): | |||
# the code embedded in _version.py can just fetch the value of these | |||
# variables. When used from setup.py, we don't want to import | |||
# _version.py, so we do it with a regexp instead. This function is not | |||
# used from _version.py. | |||
variables = {} | |||
try: | |||
for line in open(versionfile_source,"r").readlines(): | |||
if line.strip().startswith("git_refnames ="): | |||
mo = re.search(r'=\s*"(.*)"', line) | |||
if mo: | |||
variables["refnames"] = mo.group(1) | |||
if line.strip().startswith("git_full ="): | |||
mo = re.search(r'=\s*"(.*)"', line) | |||
if mo: | |||
variables["full"] = mo.group(1) | |||
except EnvironmentError: | |||
pass | |||
return variables | |||
def versions_from_expanded_variables(variables, tag_prefix, verbose=False): | |||
refnames = variables["refnames"].strip() | |||
if refnames.startswith("$Format"): | |||
if verbose: | |||
print("variables are unexpanded, not using") | |||
return {} # unexpanded, so not in an unpacked git-archive tarball | |||
refs = set([r.strip() for r in refnames.strip("()").split(",")]) | |||
for ref in list(refs): | |||
if not re.search(r'\d', ref): | |||
if verbose: | |||
print("discarding '%%s', no digits" %% ref) | |||
refs.discard(ref) | |||
# Assume all version tags have a digit. git's %%d expansion | |||
# behaves like git log --decorate=short and strips out the | |||
# refs/heads/ and refs/tags/ prefixes that would let us | |||
# distinguish between branches and tags. By ignoring refnames | |||
# without digits, we filter out many common branch names like | |||
# "release" and "stabilization", as well as "HEAD" and "master". | |||
if verbose: | |||
print("remaining refs: %%s" %% ",".join(sorted(refs))) | |||
for ref in sorted(refs): | |||
# sorting will prefer e.g. "2.0" over "2.0rc1" | |||
if ref.startswith(tag_prefix): | |||
r = ref[len(tag_prefix):] | |||
if verbose: | |||
print("picking %%s" %% r) | |||
return { "version": r, | |||
"full": variables["full"].strip() } | |||
# no suitable tags, so we use the full revision id | |||
if verbose: | |||
print("no suitable tags, using full revision id") | |||
return { "version": variables["full"].strip(), | |||
"full": variables["full"].strip() } | |||
def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): | |||
# this runs 'git' from the root of the source tree. That either means | |||
# someone ran a setup.py command (and this code is in versioneer.py, so | |||
# IN_LONG_VERSION_PY=False, thus the containing directory is the root of | |||
# the source tree), or someone ran a project-specific entry point (and | |||
# this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the | |||
# containing directory is somewhere deeper in the source tree). This only | |||
# gets called if the git-archive 'subst' variables were *not* expanded, | |||
# and _version.py hasn't already been rewritten with a short version | |||
# string, meaning we're inside a checked out source tree. | |||
try: | |||
here = os.path.abspath(__file__) | |||
except NameError: | |||
# some py2exe/bbfreeze/non-CPython implementations don't do __file__ | |||
return {} # not always correct | |||
# versionfile_source is the relative path from the top of the source tree | |||
# (where the .git directory might live) to this file. Invert this to find | |||
# the root from __file__. | |||
root = here | |||
if IN_LONG_VERSION_PY: | |||
for i in range(len(versionfile_source.split("/"))): | |||
root = os.path.dirname(root) | |||
else: | |||
root = os.path.dirname(here) | |||
if not os.path.exists(os.path.join(root, ".git")): | |||
if verbose: | |||
print("no .git in %%s" %% root) | |||
return {} | |||
GIT = "git" | |||
if sys.platform == "win32": | |||
GIT = "git.cmd" | |||
stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], | |||
cwd=root) | |||
if stdout is None: | |||
return {} | |||
if not stdout.startswith(tag_prefix): | |||
if verbose: | |||
print("tag '%%s' doesn't start with prefix '%%s'" %% (stdout, tag_prefix)) | |||
return {} | |||
tag = stdout[len(tag_prefix):] | |||
stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root) | |||
if stdout is None: | |||
return {} | |||
full = stdout.strip() | |||
if tag.endswith("-dirty"): | |||
full += "-dirty" | |||
return {"version": tag, "full": full} | |||
def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False): | |||
if IN_LONG_VERSION_PY: | |||
# We're running from _version.py. If it's from a source tree | |||
# (execute-in-place), we can work upwards to find the root of the | |||
# tree, and then check the parent directory for a version string. If | |||
# it's in an installed application, there's no hope. | |||
try: | |||
here = os.path.abspath(__file__) | |||
except NameError: | |||
# py2exe/bbfreeze/non-CPython don't have __file__ | |||
return {} # without __file__, we have no hope | |||
# versionfile_source is the relative path from the top of the source | |||
# tree to _version.py. Invert this to find the root from __file__. | |||
root = here | |||
for i in range(len(versionfile_source.split("/"))): | |||
root = os.path.dirname(root) | |||
else: | |||
# we're running from versioneer.py, which means we're running from | |||
# the setup.py in a source tree. sys.argv[0] is setup.py in the root. | |||
here = os.path.abspath(sys.argv[0]) | |||
root = os.path.dirname(here) | |||
# Source tarballs conventionally unpack into a directory that includes | |||
# both the project name and a version string. | |||
dirname = os.path.basename(root) | |||
if not dirname.startswith(parentdir_prefix): | |||
if verbose: | |||
print("guessing rootdir is '%%s', but '%%s' doesn't start with prefix '%%s'" %% | |||
(root, dirname, parentdir_prefix)) | |||
return None | |||
return {"version": dirname[len(parentdir_prefix):], "full": ""} | |||
tag_prefix = "%(TAG_PREFIX)s" | |||
parentdir_prefix = "%(PARENTDIR_PREFIX)s" | |||
versionfile_source = "%(VERSIONFILE_SOURCE)s" | |||
def get_versions(default={"version": "unknown", "full": ""}, verbose=False): | |||
variables = { "refnames": git_refnames, "full": git_full } | |||
ver = versions_from_expanded_variables(variables, tag_prefix, verbose) | |||
if not ver: | |||
ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) | |||
if not ver: | |||
ver = versions_from_parentdir(parentdir_prefix, versionfile_source, | |||
verbose) | |||
if not ver: | |||
ver = default | |||
return ver | |||
''' | |||
import subprocess | |||
import sys | |||
def run_command(args, cwd=None, verbose=False): | |||
try: | |||
# remember shell=False, so use git.cmd on windows, not just git | |||
p = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd) | |||
except EnvironmentError: | |||
e = sys.exc_info()[1] | |||
if verbose: | |||
print("unable to run %s" % args[0]) | |||
print(e) | |||
return None | |||
stdout = p.communicate()[0].strip() | |||
if sys.version >= '3': | |||
stdout = stdout.decode() | |||
if p.returncode != 0: | |||
if verbose: | |||
print("unable to run %s (error)" % args[0]) | |||
return None | |||
return stdout | |||
import sys | |||
import re | |||
import os.path | |||
def get_expanded_variables(versionfile_source): | |||
# the code embedded in _version.py can just fetch the value of these | |||
# variables. When used from setup.py, we don't want to import | |||
# _version.py, so we do it with a regexp instead. This function is not | |||
# used from _version.py. | |||
variables = {} | |||
try: | |||
for line in open(versionfile_source,"r").readlines(): | |||
if line.strip().startswith("git_refnames ="): | |||
mo = re.search(r'=\s*"(.*)"', line) | |||
if mo: | |||
variables["refnames"] = mo.group(1) | |||
if line.strip().startswith("git_full ="): | |||
mo = re.search(r'=\s*"(.*)"', line) | |||
if mo: | |||
variables["full"] = mo.group(1) | |||
except EnvironmentError: | |||
pass | |||
return variables | |||
def versions_from_expanded_variables(variables, tag_prefix, verbose=False): | |||
refnames = variables["refnames"].strip() | |||
if refnames.startswith("$Format"): | |||
if verbose: | |||
print("variables are unexpanded, not using") | |||
return {} # unexpanded, so not in an unpacked git-archive tarball | |||
refs = set([r.strip() for r in refnames.strip("()").split(",")]) | |||
for ref in list(refs): | |||
if not re.search(r'\d', ref): | |||
if verbose: | |||
print("discarding '%s', no digits" % ref) | |||
refs.discard(ref) | |||
# Assume all version tags have a digit. git's %d expansion | |||
# behaves like git log --decorate=short and strips out the | |||
# refs/heads/ and refs/tags/ prefixes that would let us | |||
# distinguish between branches and tags. By ignoring refnames | |||
# without digits, we filter out many common branch names like | |||
# "release" and "stabilization", as well as "HEAD" and "master". | |||
if verbose: | |||
print("remaining refs: %s" % ",".join(sorted(refs))) | |||
for ref in sorted(refs): | |||
# sorting will prefer e.g. "2.0" over "2.0rc1" | |||
if ref.startswith(tag_prefix): | |||
r = ref[len(tag_prefix):] | |||
if verbose: | |||
print("picking %s" % r) | |||
return { "version": r, | |||
"full": variables["full"].strip() } | |||
# no suitable tags, so we use the full revision id | |||
if verbose: | |||
print("no suitable tags, using full revision id") | |||
return { "version": variables["full"].strip(), | |||
"full": variables["full"].strip() } | |||
def versions_from_vcs(tag_prefix, versionfile_source, verbose=False): | |||
# this runs 'git' from the root of the source tree. That either means | |||
# someone ran a setup.py command (and this code is in versioneer.py, so | |||
# IN_LONG_VERSION_PY=False, thus the containing directory is the root of | |||
# the source tree), or someone ran a project-specific entry point (and | |||
# this code is in _version.py, so IN_LONG_VERSION_PY=True, thus the | |||
# containing directory is somewhere deeper in the source tree). This only | |||
# gets called if the git-archive 'subst' variables were *not* expanded, | |||
# and _version.py hasn't already been rewritten with a short version | |||
# string, meaning we're inside a checked out source tree. | |||
try: | |||
here = os.path.abspath(__file__) | |||
except NameError: | |||
# some py2exe/bbfreeze/non-CPython implementations don't do __file__ | |||
return {} # not always correct | |||
# versionfile_source is the relative path from the top of the source tree | |||
# (where the .git directory might live) to this file. Invert this to find | |||
# the root from __file__. | |||
root = here | |||
if IN_LONG_VERSION_PY: | |||
for i in range(len(versionfile_source.split("/"))): | |||
root = os.path.dirname(root) | |||
else: | |||
root = os.path.dirname(here) | |||
if not os.path.exists(os.path.join(root, ".git")): | |||
if verbose: | |||
print("no .git in %s" % root) | |||
return {} | |||
GIT = "git" | |||
if sys.platform == "win32": | |||
GIT = "git.cmd" | |||
stdout = run_command([GIT, "describe", "--tags", "--dirty", "--always"], | |||
cwd=root) | |||
if stdout is None: | |||
return {} | |||
if not stdout.startswith(tag_prefix): | |||
if verbose: | |||
print("tag '%s' doesn't start with prefix '%s'" % (stdout, tag_prefix)) | |||
return {} | |||
tag = stdout[len(tag_prefix):] | |||
stdout = run_command([GIT, "rev-parse", "HEAD"], cwd=root) | |||
if stdout is None: | |||
return {} | |||
full = stdout.strip() | |||
if tag.endswith("-dirty"): | |||
full += "-dirty" | |||
return {"version": tag, "full": full} | |||
def versions_from_parentdir(parentdir_prefix, versionfile_source, verbose=False): | |||
if IN_LONG_VERSION_PY: | |||
# We're running from _version.py. If it's from a source tree | |||
# (execute-in-place), we can work upwards to find the root of the | |||
# tree, and then check the parent directory for a version string. If | |||
# it's in an installed application, there's no hope. | |||
try: | |||
here = os.path.abspath(__file__) | |||
except NameError: | |||
# py2exe/bbfreeze/non-CPython don't have __file__ | |||
return {} # without __file__, we have no hope | |||
# versionfile_source is the relative path from the top of the source | |||
# tree to _version.py. Invert this to find the root from __file__. | |||
root = here | |||
for i in range(len(versionfile_source.split("/"))): | |||
root = os.path.dirname(root) | |||
else: | |||
# we're running from versioneer.py, which means we're running from | |||
# the setup.py in a source tree. sys.argv[0] is setup.py in the root. | |||
here = os.path.abspath(sys.argv[0]) | |||
root = os.path.dirname(here) | |||
# Source tarballs conventionally unpack into a directory that includes | |||
# both the project name and a version string. | |||
dirname = os.path.basename(root) | |||
if not dirname.startswith(parentdir_prefix): | |||
if verbose: | |||
print("guessing rootdir is '%s', but '%s' doesn't start with prefix '%s'" % | |||
(root, dirname, parentdir_prefix)) | |||
return None | |||
return {"version": dirname[len(parentdir_prefix):], "full": ""} | |||
import sys | |||
def do_vcs_install(versionfile_source, ipy): | |||
GIT = "git" | |||
if sys.platform == "win32": | |||
GIT = "git.cmd" | |||
run_command([GIT, "add", "versioneer.py"]) | |||
run_command([GIT, "add", versionfile_source]) | |||
run_command([GIT, "add", ipy]) | |||
present = False | |||
try: | |||
f = open(".gitattributes", "r") | |||
for line in f.readlines(): | |||
if line.strip().startswith(versionfile_source): | |||
if "export-subst" in line.strip().split()[1:]: | |||
present = True | |||
f.close() | |||
except EnvironmentError: | |||
pass | |||
if not present: | |||
f = open(".gitattributes", "a+") | |||
f.write("%s export-subst\n" % versionfile_source) | |||
f.close() | |||
run_command([GIT, "add", ".gitattributes"]) | |||
SHORT_VERSION_PY = """ | |||
# This file was generated by 'versioneer.py' (0.7+) from | |||
# revision-control system data, or from the parent directory name of an | |||
# unpacked source archive. Distribution tarballs contain a pre-generated copy | |||
# of this file. | |||
version_version = '%(version)s' | |||
version_full = '%(full)s' | |||
def get_versions(default={}, verbose=False): | |||
return {'version': version_version, 'full': version_full} | |||
""" | |||
DEFAULT = {"version": "unknown", "full": "unknown"} | |||
def versions_from_file(filename): | |||
versions = {} | |||
try: | |||
f = open(filename) | |||
except EnvironmentError: | |||
return versions | |||
for line in f.readlines(): | |||
mo = re.match("version_version = '([^']+)'", line) | |||
if mo: | |||
versions["version"] = mo.group(1) | |||
mo = re.match("version_full = '([^']+)'", line) | |||
if mo: | |||
versions["full"] = mo.group(1) | |||
return versions | |||
def write_to_version_file(filename, versions): | |||
f = open(filename, "w") | |||
f.write(SHORT_VERSION_PY % versions) | |||
f.close() | |||
print("set %s to '%s'" % (filename, versions["version"])) | |||
def get_best_versions(versionfile, tag_prefix, parentdir_prefix, | |||
default=DEFAULT, verbose=False): | |||
# returns dict with two keys: 'version' and 'full' | |||
# | |||
# extract version from first of _version.py, 'git describe', parentdir. | |||
# This is meant to work for developers using a source checkout, for users | |||
# of a tarball created by 'setup.py sdist', and for users of a | |||
# tarball/zipball created by 'git archive' or github's download-from-tag | |||
# feature. | |||
variables = get_expanded_variables(versionfile_source) | |||
if variables: | |||
ver = versions_from_expanded_variables(variables, tag_prefix) | |||
if ver: | |||
if verbose: print("got version from expanded variable %s" % ver) | |||
return ver | |||
ver = versions_from_file(versionfile) | |||
if ver: | |||
if verbose: print("got version from file %s %s" % (versionfile, ver)) | |||
return ver | |||
ver = versions_from_vcs(tag_prefix, versionfile_source, verbose) | |||
if ver: | |||
if verbose: print("got version from git %s" % ver) | |||
return ver | |||
ver = versions_from_parentdir(parentdir_prefix, versionfile_source, verbose) | |||
if ver: | |||
if verbose: print("got version from parentdir %s" % ver) | |||
return ver | |||
if verbose: print("got version from default %s" % ver) | |||
return default | |||
def get_versions(default=DEFAULT, verbose=False): | |||
assert versionfile_source is not None, "please set versioneer.versionfile_source" | |||
assert tag_prefix is not None, "please set versioneer.tag_prefix" | |||
assert parentdir_prefix is not None, "please set versioneer.parentdir_prefix" | |||
return get_best_versions(versionfile_source, tag_prefix, parentdir_prefix, | |||
default=default, verbose=verbose) | |||
def get_version(verbose=False): | |||
return get_versions(verbose=verbose)["version"] | |||
class cmd_version(Command): | |||
description = "report generated version string" | |||
user_options = [] | |||
boolean_options = [] | |||
def initialize_options(self): | |||
pass | |||
def finalize_options(self): | |||
pass | |||
def run(self): | |||
ver = get_version(verbose=True) | |||
print("Version is currently: %s" % ver) | |||
class cmd_build_py(_build_py): | |||
def run(self): | |||
versions = get_versions(verbose=True) | |||
_build_py.run(self) | |||
# now locate _version.py in the new build/ directory and replace it | |||
# with an updated value | |||
target_versionfile = os.path.join(self.build_lib, versionfile_build) | |||
print("UPDATING %s" % target_versionfile) | |||
os.unlink(target_versionfile) | |||
f = open(target_versionfile, "w") | |||
f.write(SHORT_VERSION_PY % versions) | |||
f.close() | |||
class cmd_sdist(_sdist): | |||
def run(self): | |||
versions = get_versions(verbose=True) | |||
self._versioneer_generated_versions = versions | |||
# unless we update this, the command will keep using the old version | |||
self.distribution.metadata.version = versions["version"] | |||
return _sdist.run(self) | |||
def make_release_tree(self, base_dir, files): | |||
_sdist.make_release_tree(self, base_dir, files) | |||
# now locate _version.py in the new base_dir directory (remembering | |||
# that it may be a hardlink) and replace it with an updated value | |||
target_versionfile = os.path.join(base_dir, versionfile_source) | |||
print("UPDATING %s" % target_versionfile) | |||
os.unlink(target_versionfile) | |||
f = open(target_versionfile, "w") | |||
f.write(SHORT_VERSION_PY % self._versioneer_generated_versions) | |||
f.close() | |||
INIT_PY_SNIPPET = """ | |||
from ._version import get_versions | |||
__version__ = get_versions()['version'] | |||
del get_versions | |||
""" | |||
class cmd_update_files(Command): | |||
description = "modify __init__.py and create _version.py" | |||
user_options = [] | |||
boolean_options = [] | |||
def initialize_options(self): | |||
pass | |||
def finalize_options(self): | |||
pass | |||
def run(self): | |||
ipy = os.path.join(os.path.dirname(versionfile_source), "__init__.py") | |||
print(" creating %s" % versionfile_source) | |||
f = open(versionfile_source, "w") | |||
f.write(LONG_VERSION_PY % {"DOLLAR": "$", | |||
"TAG_PREFIX": tag_prefix, | |||
"PARENTDIR_PREFIX": parentdir_prefix, | |||
"VERSIONFILE_SOURCE": versionfile_source, | |||
}) | |||
f.close() | |||
try: | |||
old = open(ipy, "r").read() | |||
except EnvironmentError: | |||
old = "" | |||
if INIT_PY_SNIPPET not in old: | |||
print(" appending to %s" % ipy) | |||
f = open(ipy, "a") | |||
f.write(INIT_PY_SNIPPET) | |||
f.close() | |||
else: | |||
print(" %s unmodified" % ipy) | |||
do_vcs_install(versionfile_source, ipy) | |||
def get_cmdclass(): | |||
return {'version': cmd_version, | |||
'update_files': cmd_update_files, | |||
'build_py': cmd_build_py, | |||
'sdist': cmd_sdist, | |||
} |