forked from dawneye/beancount
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsetup.py
executable file
·297 lines (256 loc) · 10.9 KB
/
setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#!/usr/bin/env python3
"""
Install script for beancount.
"""
__copyright__ = "Copyright (C) 2008-2011, 2013-2016 Martin Blais"
__license__ = "GNU GPLv2"
from os import path
import datetime
import os
import platform
import re
import runpy
import subprocess
import sys
import warnings
# Check if the version is sufficient.
if sys.version_info[:2] < (3,5):
raise SystemExit("ERROR: Insufficient Python version; you need v3.5 or higher.")
# Import setup().
setup_extra_kwargs = {}
if 'BEANCOUNT_DISABLE_SETUPTOOLS' in os.environ:
# Note: this is used for testing only.
from distutils.core import setup, Extension
has_setuptools = False
else:
try:
from setuptools import setup, Extension
has_setuptools = True
setup_extra_kwargs.update(install_requires = [
# Testing support now uses the pytest module.
'pytest',
# This is required to parse dates from command-line options in a
# loose, accepting format. Note that we use dateutil for timezone
# database definitions as well, although it is inferior to pytz, but
# because it can use the OS timezone database in the Windows
# registry. See this article for context:
# https://www.assert.cc/2014/05/25/which-python-time-zone-library.html
# However, for creating offset timezones, we use the datetime.timezone
# helper class because it is built-in.
# Where this matters is for price source fetchers.
# (Note: If pytz supported the Windows registry timezone information,
# I would switch to that.)
'python-dateutil',
# The SQL parser uses PLY in order to parse the input syntax.
'ply',
# The bean-web web application is built on top of this web
# framework.
'bottle',
# This XML parsing library is mainly required to web scrape the
# bean-web pages for testing.
'lxml',
# This library is needed to identify the type of a file for import.
'python-magic',
# This library is needed to parse XML files (for the OFX examples).
'beautifulsoup4',
# This library is needed to make requests for price sources.
'requests',
# This library is needed to identify the character set of a file for
# import, in order to read its contents and match expressions
# against it.
'chardet',
# This library is used to download and convert the documentation
# programmatically and to upload lists of holdings to a Google
# Spreadsheet for live intra-day monitoring.
'google-api-python-client',
])
# A note about setuptools: It's profoundly BROKEN.
#
# - The header files are needed in order to distribution a working
# source distribution.
# - Listing the header files under the extension "sources" fails to
# build; distutils cannot make out the file type.
# - Listing them as "headers" makes them ignored; extra options to
# Extension() appear to be ignored silently.
# - Listing them under setup()'s "headers" makes it recognize them, but
# they do not get included.
# - Listing them with "include_dirs" of the Extension fails as well.
#
# The only way I managed to get this working is by working around and
# including them as "package_data" (see {63fc8d84d30a} below). That
# includes the header files in the sdist, and a source distribution can
# be installed using pip3 (and be built locally). However, the header
# files end up being installed next to the pure Python files in the
# output. This is the sorry situation we're living in, but it works.
#
# If you think I'm a lunatic, fix it and make sure you can make this
# command succeed:
# pytest -s beancount/scripts/setup_test.py
#
except ImportError:
warnings.warn("Setuptools not installed; falling back on distutils. "
"You will have to install dependencies explicitly.")
from distutils.core import setup, Extension
has_setuptools = False
# Make sure we can import hashsrc in order to create a binary with a checksum of
# the C source code. This checksum is used to issue a warning when loading an
# incompatible binary. (Also note that you should _NOT_ add the path of this
# file to the PYTHONPATH directly because it contains a 'parser' module and that
# overrides the stdlib 'parser' module which is used by setuptools, and causes a
# subtle bug. That's why I import this utility directly from path).
hashsrc = runpy.run_path(path.join(path.dirname(__file__),
'beancount/parser/hashsrc.py'))
hash_parser_source_files = hashsrc['hash_parser_source_files']
# Explicitly list the scripts to install.
binaries = [
('bean-bake', 'beancount.scripts.bake'),
('bean-check', 'beancount.scripts.check'),
('bean-doctor', 'beancount.scripts.doctor'),
('bean-example', 'beancount.scripts.example'),
('bean-format', 'beancount.scripts.format'),
('bean-price', 'beancount.prices.price'),
('bean-query', 'beancount.query.shell'),
('bean-report', 'beancount.reports.report'),
('bean-sql', 'beancount.scripts.sql'),
('bean-web', 'beancount.web.web'),
('bean-identify', 'beancount.ingest.identify'),
('bean-extract', 'beancount.ingest.extract'),
('bean-file', 'beancount.ingest.file'),
('treeify', 'beancount.tools.treeify'),
('upload-to-sheets', 'beancount.tools.sheets_upload'),
]
if has_setuptools and platform.system() == 'Windows':
setup_extra_kwargs.update(entry_points={
'console_scripts': [
'{} = {}:main'.format(binary, module)
for binary, module in binaries]
})
else:
setup_extra_kwargs.update(scripts=[
path.join('bin', binary)
for binary, _ in binaries])
def get_cflags():
"Returns suitable CFLAGS for the platform."
if platform.system() == "Windows":
# unistd.h is not available with MSDEV.
# See https://bitbucket.org/blais/beancount/issues/173/
return ["-DYY_NO_UNISTD_H"]
else:
return None
# Read the version.
version_module = runpy.run_path(path.join(path.dirname(__file__),
'beancount/__init__.py'))
version = version_module['__version__']
assert isinstance(version, str)
def get_hg_changeset():
"""Get the Mercurial changeset id."""
try:
output = subprocess.check_output(
['hg', 'parent', '--template', '{node} {date|hgdate}'], shell=False)
vc_changeset, vc_timestamp = output.decode('utf-8').split()[:2]
vc_changeset = 'hg:{}'.format(vc_changeset)
return vc_changeset, vc_timestamp
except (subprocess.CalledProcessError, FileNotFoundError, PermissionError):
return None
def get_git_changeset():
"""Get the Git changeset id."""
try:
output = subprocess.check_output(['git', 'log', '--pretty=%H %ct', '-1'],
shell=False)
match = re.match(r'([0-9a-f]+) ([0-9]+)$', output.decode('utf-8').strip())
if match:
vc_changeset = 'git:{}'.format(match.group(1))
vc_timestamp = match.group(2)
return vc_changeset, vc_timestamp
else:
return None
except (subprocess.CalledProcessError, FileNotFoundError, PermissionError):
return None
# Get the changeset to bake into the binary.
for get_changeset in get_hg_changeset, get_git_changeset:
changeset_timestamp = get_changeset()
if changeset_timestamp is not None:
vc_changeset, vc_timestamp = changeset_timestamp
break
else:
vc_changeset, vc_timestamp = '', 0
# Create a setup.
# Please read: http://furius.ca/beancount/doc/install about version numbers.
setup(
name="beancount",
version=version,
description="Command-line Double-Entry Accounting",
long_description=
"""
A double-entry accounting system that uses text files as input.
Beancount defines a simple data format or "language" that lets you define
financial transaction records in a text file, load them in memory and
generate and export a variety of reports, such as balance sheets or income
statements. It also provides a client with an SQL-like query language to
filter and aggregate financial data, and a web interface which renders
those reports to HTML. Finally, it provides the scaffolding required to
automate the conversion of external data into one's input file in
Beancount syntax.
""",
license="GNU GPLv2 only",
author="Martin Blais",
author_email="[email protected]",
url="http://furius.ca/beancount",
download_url="https://bitbucket.org/blais/beancount",
packages = [
'beancount',
'beancount.parser',
'beancount.core',
'beancount.ops',
'beancount.plugins',
'beancount.query',
'beancount.reports',
'beancount.scripts',
'beancount.prices',
'beancount.prices.sources',
'beancount.web',
'beancount.ingest',
'beancount.ingest.importers',
'beancount.ingest.importers.mixins',
'beancount.utils',
'beancount.tools',
],
package_data = {
'beancount.web': ['*.ico',
'*.html',
'*.css',
'third_party/*.js'],
'beancount.reports': ['*.html'],
'beancount.utils.file_type_testdata': ['*'],
'beancount.parser': ['*.h'], # See note for {63fc8d84d30a} above.
},
ext_modules = [
Extension("beancount.parser._parser",
sources=[
"beancount/parser/lexer.c",
"beancount/parser/grammar.c",
"beancount/parser/parser.c",
],
define_macros=[
('RELEASE_VERSION', version),
('VC_CHANGESET', vc_changeset),
('VC_TIMESTAMP', int(float(vc_timestamp))),
('PARSER_SOURCE_HASH', hash_parser_source_files())],
extra_compile_args=get_cflags()),
],
# Include the Emacs support for completeness, for packagers not to have to
# check out from the repository.
data_files = [
('elisp', ['editors/emacs/beancount.el']),
],
# Add optional arguments that only work with some variants of setup().
**setup_extra_kwargs
)
# Development setup requires two tools IFF you need to change the grammar:
#
# - flex-2.6.4
# - bison-3.0.5
#
# These versions are related to what's on a recent Ubuntu. If you don't change
# the grammar nor the tokenizer, the C sources are checked in so you won't need
# those tools.