gitdata-lib 0.0.10__tar.gz → 0.0.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/MANIFEST.in +3 -1
  2. {gitdata-lib-0.0.10/gitdata_lib.egg-info → gitdata_lib-0.0.12}/PKG-INFO +11 -8
  3. gitdata_lib-0.0.12/README.md +5 -0
  4. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/__init__.py +2 -9
  5. gitdata_lib-0.0.12/gitdata/__version__.py +1 -0
  6. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/buckets.py +91 -11
  7. gitdata_lib-0.0.12/gitdata/cli/__init__.py +70 -0
  8. gitdata_lib-0.0.12/gitdata/cli/gitdata_get.py +22 -0
  9. gitdata_lib-0.0.12/gitdata/cli/gitdata_scan.py +94 -0
  10. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/config.py +0 -1
  11. gitdata_lib-0.0.12/gitdata/connectors/__init__.py +5 -0
  12. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/connectors/common.py +129 -6
  13. gitdata_lib-0.0.12/gitdata/connectors/fake.py +68 -0
  14. gitdata_lib-0.0.12/gitdata/connectors/http.py +59 -0
  15. gitdata_lib-0.0.12/gitdata/connectors/local.py +92 -0
  16. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/database/common.py +0 -1
  17. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/database/mysql.py +6 -0
  18. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/database/mysql_setup_test_database.sql +0 -2
  19. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/database/sqlite3.py +4 -0
  20. gitdata_lib-0.0.12/gitdata/database/sqlite3_setup.sql +16 -0
  21. gitdata_lib-0.0.12/gitdata/digester.py +94 -0
  22. gitdata_lib-0.0.12/gitdata/graphs.py +278 -0
  23. gitdata_lib-0.0.12/gitdata/repositories.py +110 -0
  24. gitdata_lib-0.0.12/gitdata/sql.py +235 -0
  25. gitdata_lib-0.0.12/gitdata/stores/__init__.py +0 -0
  26. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/stores/common.py +12 -9
  27. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/stores/entities.py +1 -8
  28. gitdata_lib-0.0.12/gitdata/stores/facts.py +297 -0
  29. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/utils.py +30 -0
  30. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12/gitdata_lib.egg-info}/PKG-INFO +11 -8
  31. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata_lib.egg-info/SOURCES.txt +12 -9
  32. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata_lib.egg-info/entry_points.txt +0 -1
  33. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata_lib.egg-info/requires.txt +1 -1
  34. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/requirements.txt +1 -1
  35. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/setup.py +1 -1
  36. gitdata-lib-0.0.10/README.md +0 -6
  37. gitdata-lib-0.0.10/gitdata/__version__.py +0 -1
  38. gitdata-lib-0.0.10/gitdata/cli/__init__.py +0 -39
  39. gitdata-lib-0.0.10/gitdata/connectors/__init__.py +0 -5
  40. gitdata-lib-0.0.10/gitdata/connectors/console.py +0 -18
  41. gitdata-lib-0.0.10/gitdata/connectors/csv.py +0 -26
  42. gitdata-lib-0.0.10/gitdata/connectors/http.py +0 -20
  43. gitdata-lib-0.0.10/gitdata/connectors/json.py +0 -56
  44. gitdata-lib-0.0.10/gitdata/connectors/local.py +0 -41
  45. gitdata-lib-0.0.10/gitdata/connectors/location.py +0 -35
  46. gitdata-lib-0.0.10/gitdata/connectors/rows.py +0 -15
  47. gitdata-lib-0.0.10/gitdata/connectors/system.py +0 -29
  48. gitdata-lib-0.0.10/gitdata/connectors/zip.py +0 -19
  49. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/CHANGELOG.md +0 -0
  50. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/LICENSE +0 -0
  51. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/assets/README.md +0 -0
  52. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/connectors/gitlab.py +0 -0
  53. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/database/__init__.py +0 -0
  54. /gitdata-lib-0.0.10/gitdata/stores/entity_store.sql → /gitdata_lib-0.0.12/gitdata/database/mysql_setup.sql +0 -0
  55. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/database/postgresql.py +0 -0
  56. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/database/sqlite3_setup_test_data.sql +0 -0
  57. {gitdata-lib-0.0.10/gitdata/stores → gitdata_lib-0.0.12/gitdata/ext}/__init__.py +0 -0
  58. /gitdata-lib-0.0.10/gitdata/database/sqlite3_setup.sql → /gitdata_lib-0.0.12/gitdata/ext/connectors/__init__.py +0 -0
  59. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/json.py +0 -0
  60. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/queues.py +0 -0
  61. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata/solutions.py +0 -0
  62. /gitdata-lib-0.0.10/gitdata/stores/records.py → /gitdata_lib-0.0.12/gitdata/stores/tables.py +0 -0
  63. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata_lib.egg-info/dependency_links.txt +0 -0
  64. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/gitdata_lib.egg-info/top_level.txt +0 -0
  65. {gitdata-lib-0.0.10 → gitdata_lib-0.0.12}/setup.cfg +0 -0
@@ -1,2 +1,4 @@
1
1
  include README.md LICENSE CHANGELOG.md requirements.txt
2
- recursive-include gitdata *.py *.html *.pug *.sass *.sql *.ini *.js *.css *.gitinclude *.md *.json *.wsgi *.eot *.svg *.ttf *.woff *.woff2 *.png *.ico *.map *.gif LICENSE
2
+ recursive-include gitdata *.py *.html *.pug *.sass *.sql *.ini *.js *.css *.gitinclude *.md *.json *.wsgi *.eot *.svg *.ttf *.woff *.woff2 *.png *.ico *.map *.gif LICENSE
3
+ recursive-exclude gitdata/ext *.py
4
+ recursive-include gitdata/ext __init__.py
@@ -1,12 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gitdata-lib
3
- Version: 0.0.10
3
+ Version: 0.0.12
4
4
  Summary: Data extraction and analysis library
5
5
  Home-page: https://github.com/gitdata/gitdata-lib
6
6
  Author: DSI Labs
7
7
  Author-email: support@gitdata.com
8
- License: UNKNOWN
9
- Platform: UNKNOWN
10
8
  Classifier: Development Status :: 1 - Planning
11
9
  Classifier: Environment :: Console
12
10
  Classifier: Intended Audience :: Developers
@@ -22,12 +20,17 @@ Classifier: Programming Language :: Python :: 3 :: Only
22
20
  Classifier: Topic :: Database :: Front-Ends
23
21
  Description-Content-Type: text/markdown
24
22
  License-File: LICENSE
23
+ Requires-Dist: python-decouple>=3.4
24
+ Requires-Dist: Unipath>=1.1
25
+ Requires-Dist: PyMySQL==0.10.1
26
+ Requires-Dist: psycopg2-binary==2.9.1
27
+ Requires-Dist: python-dotenv
28
+ Requires-Dist: requests
29
+ Requires-Dist: docopt
30
+ Requires-Dist: faker
25
31
 
26
32
  # GitData Lib
27
33
  Data Wrangling for Everyone.
28
34
 
29
- GitData is an easy to use, fast, scalable, distributed data extraction system
30
- with a rich set of commands that provide ways to gather, manage and query data in
31
- an unusually straightforward way.
32
-
33
-
35
+ GitData is a fast, scalable, distributed data exploration system
36
+ with a rich set of commands that provide ways to gather, manage and query data in an unusually straightforward way.
@@ -0,0 +1,5 @@
1
+ # GitData Lib
2
+ Data Wrangling for Everyone.
3
+
4
+ GitData is a fast, scalable, distributed data exploration system
5
+ with a rich set of commands that provide ways to gather, manage and query data in an unusually straightforward way.
@@ -8,14 +8,7 @@
8
8
  """
9
9
 
10
10
  from .utils import Record
11
- from .stores.records import table_of
11
+ from .stores.tables import table_of
12
12
  from .stores.entities import store_of
13
13
  from .__version__ import __version__
14
- from .connectors.http import HttpConnector
15
-
16
- def fetch(ref):
17
- """Fetch data
18
-
19
- Stub for fetch data function.
20
- """
21
- return Record(HttpConnector().get(ref))
14
+ from .connectors import fetch
@@ -0,0 +1 @@
1
+ __version__ = '0.0.12'
@@ -4,9 +4,11 @@
4
4
  stores blobs of data
5
5
  """
6
6
 
7
+ import io
7
8
  import os
8
- import uuid
9
+ import shutil
9
10
 
11
+ import gitdata
10
12
 
11
13
 
12
14
  def mkdir_p(path):
@@ -19,10 +21,6 @@ def mkdir_p(path):
19
21
  os.makedirs(path)
20
22
 
21
23
 
22
- def new_id():
23
- """Generate a random unique id"""
24
- return uuid.uuid4().hex
25
-
26
24
  class BaseBucket:
27
25
  """BaseBucket"""
28
26
 
@@ -30,7 +28,7 @@ class BaseBucket:
30
28
  class FileBucket(BaseBucket):
31
29
  """File Bucket
32
30
 
33
- FileBucket can store and retreive blobs of binary data. This is
31
+ FileBucket can store and retrieve blobs of binary data. This is
34
32
  useful for storing images or files as attachments where you want
35
33
  to put the binary data somewhere and be able to retreive it later
36
34
  if asked. The id returned is generally stored in a database or
@@ -46,8 +44,7 @@ class FileBucket(BaseBucket):
46
44
  in the site.ini configuration file.
47
45
 
48
46
  >>> import gitdata, tempfile
49
- >>> dir = tempfile.TemporaryDirectory()
50
- >>> path = str(dir)
47
+ >>> path = tempfile.TemporaryDirectory().name
51
48
  >>> ids = ['id_%04d' % (9-i) for i in range(10)]
52
49
  >>> new_id = ids.pop
53
50
 
@@ -83,9 +80,22 @@ class FileBucket(BaseBucket):
83
80
  >>> for item_id in bucket.keys():
84
81
  ... bucket.delete(item_id)
85
82
 
83
+ >>> bucket = FileBucket(path, new_id)
84
+ >>> item_id = bucket.puts(io.BytesIO(b'some data'))
85
+ >>> item_id
86
+ 'id_0004'
87
+ >>> s = bucket.gets(item_id)
88
+ >>> s.read()
89
+ b'some data'
90
+ >>> s.close()
91
+ >>> bucket.exists(item_id)
92
+ True
93
+ >>> bucket.delete(item_id)
94
+ >>> bucket.exists(item_id)
95
+ False
86
96
  """
87
97
 
88
- def __init__(self, path, id_factory=new_id):
98
+ def __init__(self, path, id_factory=gitdata.utils.new_uid):
89
99
  self.path = os.path.realpath(path)
90
100
  self.id_factory = id_factory
91
101
  mkdir_p(self.path)
@@ -95,7 +105,7 @@ class FileBucket(BaseBucket):
95
105
  pathname = os.path.join(self.path, item_id)
96
106
  if os.path.exists(pathname):
97
107
  raise Exception('duplicate item')
98
- f = open(os.path.join(pathname), 'wb')
108
+ f = open(pathname, 'wb')
99
109
  try:
100
110
  f.write(item)
101
111
  finally:
@@ -109,6 +119,26 @@ class FileBucket(BaseBucket):
109
119
  with open(os.path.join(pathname), 'rb') as f:
110
120
  return f.read()
111
121
 
122
+ def puts(self, item):
123
+ item_id = self.id_factory()
124
+ pathname = os.path.join(self.path, item_id)
125
+ if os.path.exists(pathname):
126
+ raise Exception('duplicate item')
127
+ f = open(pathname, 'wb')
128
+ try:
129
+ shutil.copyfileobj(item, f)
130
+ finally:
131
+ f.close()
132
+ return item_id
133
+
134
+ def gets(self, item_id, default=None):
135
+ if not isinstance(item_id, str):
136
+ return default
137
+ pathname = os.path.join(self.path, item_id)
138
+ if not os.path.exists(pathname) and default is not None:
139
+ return default
140
+ return open(os.path.join(pathname), 'rb')
141
+
112
142
  def delete(self, item_id):
113
143
  pathname = os.path.join(self.path, item_id)
114
144
  os.remove(pathname)
@@ -120,5 +150,55 @@ class FileBucket(BaseBucket):
120
150
  def keys(self):
121
151
  return os.listdir(self.path)
122
152
 
153
+ def clear(self):
154
+ for key in self.keys():
155
+ self.delete(key)
156
+
157
+
158
+ class MemoryBucket(BaseBucket):
159
+ """Memory Bucket
160
+
161
+ Memory based bucket.
162
+ """
163
+
164
+ def __init__(self, id_factory=gitdata.utils.new_uid):
165
+ self.id_factory = id_factory
166
+ self.items = {}
167
+
168
+ def put(self, item):
169
+ item_id = self.id_factory()
170
+ if item_id in self.items:
171
+ raise Exception('duplicate item')
172
+ self.items[item_id] = item
173
+ return item_id
174
+
175
+ def get(self, item_id, default=None):
176
+ value = self.items.get(item_id, default)
177
+ return value
178
+
179
+ def puts(self, item):
180
+ item_id = self.id_factory()
181
+ if item_id in self.items:
182
+ raise Exception('duplicate item')
183
+ self.items[item_id] = item.read()
184
+ return item_id
185
+
186
+ def gets(self, item_id, default=None):
187
+ value = self.items.get(item_id)
188
+ return io.BytesIO(value) if value else default
189
+ # return io.BytesIO(self.items.get(item_id, default))
190
+
191
+ def delete(self, item_id):
192
+ self.items.pop(item_id)
193
+
194
+ def exists(self, item_id):
195
+ return item_id in self.items
196
+
197
+ def keys(self):
198
+ return list(self.items.keys())
199
+
200
+ def clear(self):
201
+ self.items.clear()
202
+
123
203
 
124
- Bucket = FileBucket
204
+ Bucket = FileBucket
@@ -0,0 +1,70 @@
1
+ """
2
+ usage: gitdata [options] <command> [<args>...]
3
+
4
+ options:
5
+ -h, --help show help
6
+ -V, --version print version
7
+ -d, --debug debug
8
+
9
+ The most commonly used gitdata commands are:
10
+ fetch fetch data to the local reposotiry
11
+ get get data
12
+ scan scan data
13
+
14
+ See 'gitdata help <command>' for more information on a specific command.
15
+ """
16
+
17
+ import logging
18
+
19
+ from docopt import docopt
20
+ import sys
21
+
22
+ import gitdata
23
+ from gitdata.utils import trim
24
+
25
+
26
+ root_logger = logging.getLogger()
27
+
28
+
29
+ def print_help(doc):
30
+ """Print help text"""
31
+ print(trim(doc))
32
+
33
+
34
+ def main():
35
+ """CLI main"""
36
+
37
+ if len(sys.argv) == 1:
38
+ print_help(__doc__)
39
+ sys.exit()
40
+
41
+ args = docopt(
42
+ __doc__,
43
+ version='gitdata version {}'.format(gitdata.__version__),
44
+ options_first=True
45
+ )
46
+
47
+ if args['--debug']:
48
+ print(args)
49
+ root_logger.setLevel(logging.DEBUG)
50
+
51
+ argv = [args['<command>']] + args['<args>']
52
+
53
+ if args['<command>'] == 'get':
54
+ from gitdata.cli.gitdata_get import get, __doc__ as doc
55
+ args = docopt(doc, argv=argv)
56
+ get(args)
57
+
58
+ elif args['<command>'] == 'scan':
59
+ from gitdata.cli.gitdata_scan import scan_to_console, __doc__ as doc
60
+ args = docopt(doc, argv=argv)
61
+ scan_to_console(args)
62
+
63
+ elif args['<command>'] in ['help', None]:
64
+ if args['<args>'] == ['get']:
65
+ from gitdata.cli.gitdata_get import __doc__ as doc
66
+ exit(doc)
67
+ exit(__doc__)
68
+
69
+ else:
70
+ exit("%r is not a gitdata command. See 'gitdata help'." % args['<command>'])
@@ -0,0 +1,22 @@
1
+ """
2
+ usage: gitdata get [options] [<ref>...]
3
+
4
+ options:
5
+ -h, --help
6
+ """
7
+
8
+ from pprint import pprint
9
+
10
+ import gitdata.connectors.common
11
+
12
+
13
+ def get(args):
14
+ if args['<ref>']:
15
+ for ref in args['<ref>']:
16
+ print('getting', ref)
17
+ pprint(
18
+ gitdata.connectors.common.get(ref),
19
+ )
20
+ else:
21
+ print(__doc__)
22
+ print(args)
@@ -0,0 +1,94 @@
1
+ """
2
+ usage: gitdata scan [options] [<ref>...]
3
+
4
+ options:
5
+ --limit <n>, -n <n> limit number of records displayed
6
+ --name-columns provide synthetic column names (handy for csv files that do not provide a header)
7
+ -h, --help
8
+ """
9
+
10
+ import csv
11
+ import os
12
+
13
+ import gitdata
14
+ from gitdata.connectors.common import load, connect
15
+ from gitdata.connectors.http import HttpConnector
16
+
17
+
18
+ def as_blobs(ref):
19
+ if os.path.isfile(ref):
20
+ with open(ref, 'rb') as f:
21
+ return [f.read()]
22
+
23
+ if ref.startswith('http'):
24
+ http_connector = HttpConnector()
25
+ result = http_connector.get(ref)
26
+ if result:
27
+ return [result['blob'].read()]
28
+
29
+ return []
30
+
31
+
32
+ def as_tables(ref, args):
33
+ for blob in as_blobs(ref):
34
+ rows = []
35
+ try:
36
+ reader = csv.reader(blob.decode('utf8').splitlines())
37
+ except UnicodeDecodeError:
38
+ reader = csv.reader(blob.decode('Latin1').splitlines())
39
+ for row in reader:
40
+ rows.append(row)
41
+ yield gitdata.Record(
42
+ name=ref,
43
+ filename=ref,
44
+ rows=rows,
45
+ columns=[gitdata.Record(name=f'{chr(n+65)}', type='str') for n in range(len(rows[0]))]
46
+ )
47
+
48
+
49
+ def scan(ref, args):
50
+
51
+ def scan_table(table):
52
+ header = gitdata.Record(
53
+ name=table.name,
54
+ row_count=len(table.rows),
55
+ column_count=len(table.rows[0])
56
+ )
57
+
58
+ limit = args['--limit'] and int(args['--limit']) or 5
59
+
60
+ if args['--name-columns']:
61
+ rows = [[t.name for t in table.columns]] + table.rows[:limit]
62
+ else:
63
+ rows = table.rows[:limit]
64
+
65
+ sample = gitdata.utils.ItemList(rows)
66
+ return str(header) + '\n' + str(sample) + str(list())
67
+
68
+ return ''.join(scan_table(table) for table in as_tables(ref, args))
69
+
70
+
71
+ def console(output):
72
+ if output:
73
+ print(output)
74
+ print()
75
+
76
+
77
+ def scan_to_console(args):
78
+ if args['<ref>']:
79
+ for ref in args['<ref>']:
80
+ console(scan(ref, args))
81
+ # connection = connect(ref)
82
+ # if connection:
83
+ # print(connection)
84
+ # for table in connection.get_tables():
85
+ # print(f'scanning {table.name}')
86
+ # else:
87
+ # print(f'unable to connect to {ref}')
88
+
89
+ # g = load(ref)
90
+ # print('scanning', ref)
91
+ # print(repr(g))
92
+ # print(g)
93
+ else:
94
+ print(__doc__)
@@ -152,7 +152,6 @@ def locate_config_file(filename='gitdata.ini', start='.'):
152
152
  return pathname
153
153
 
154
154
  for path in OrderedSet(parents(join(expanduser('~')))) - ancestors:
155
- print(path)
156
155
  pathname = join(path, filename)
157
156
  if exists(pathname):
158
157
  return pathname
@@ -0,0 +1,5 @@
1
+ """
2
+ connectors
3
+ """
4
+
5
+ from .common import explore, connect, fetch, extract
@@ -2,20 +2,25 @@
2
2
  common connector
3
3
  """
4
4
 
5
+ import datetime
6
+ import getpass
5
7
  import inspect
6
8
  import importlib
7
9
  import logging
8
10
  import pkgutil
11
+ import platform
9
12
 
10
13
  import gitdata.connectors
14
+ import gitdata.ext.connectors
15
+ import gitdata.graphs
11
16
  import gitdata.solutions
12
17
 
13
-
14
18
  logger = logging.getLogger(__name__)
15
19
 
16
20
 
17
21
  def get_connectors():
18
22
  """generate connectors"""
23
+
19
24
  path = gitdata.connectors.__path__
20
25
  for _, name, _ in pkgutil.iter_modules(path):
21
26
  if name != 'common':
@@ -30,6 +35,19 @@ def get_connectors():
30
35
  if found:
31
36
  yield obj
32
37
 
38
+ path = gitdata.ext.connectors.__path__
39
+ for _, name, _ in pkgutil.iter_modules(path):
40
+ module = importlib.import_module('gitdata.ext.connectors.' + name)
41
+ for _, obj in inspect.getmembers(module):
42
+ if obj == BaseConnector:
43
+ continue
44
+ try:
45
+ found = issubclass(obj, BaseConnector)
46
+ except TypeError:
47
+ found = False
48
+ if found:
49
+ yield obj
50
+
33
51
 
34
52
  def get_connector_graph():
35
53
  """generate connector graph"""
@@ -103,6 +121,15 @@ class BaseConnector:
103
121
  def connect(self, ref):
104
122
  """Connect to a ref"""
105
123
 
124
+ def extract(self, ref):
125
+ """Extract facts from a ref"""
126
+
127
+ def get_tables(self):
128
+ return []
129
+
130
+ def get_blobs(self):
131
+ return []
132
+
106
133
  # def explore(self, data):
107
134
  # """Explore a graph
108
135
  # """
@@ -113,16 +140,112 @@ def connect(ref):
113
140
  """Return a connection to a ref"""
114
141
 
115
142
  for connector in get_connectors():
116
- if connector.connects(ref):
117
- connection = connector()
118
- connection.connect(ref)
143
+ connection = connector().connect(ref)
144
+ if connection:
119
145
  return connection
120
146
 
121
147
 
122
148
  # connectors = {
123
149
  # connector.__name__: connector for connector in get_connectors()}
124
150
 
125
-
126
-
127
151
  # if 'System' in connectors:
128
152
  # return connectors['System']()
153
+
154
+ def add_connection_metadata(facts):
155
+ facts.update(
156
+ dict(
157
+ collected=datetime.datetime.now(),
158
+ node=platform.node(),
159
+ user=getpass.getuser()
160
+ )
161
+ )
162
+
163
+
164
+ def fetch(ref):
165
+ """Fetch data
166
+
167
+ Fetch the facts in a datasource and store them.
168
+ """
169
+ connectors = get_connectors()
170
+ for connector in connectors:
171
+ if hasattr(connector, 'get'):
172
+ facts = connector().get(ref)
173
+ if facts:
174
+ add_connection_metadata(facts)
175
+ return facts
176
+
177
+ def get(ref):
178
+ """Get Data
179
+
180
+ Get the facts from a datasource.
181
+ """
182
+ connectors = get_connectors()
183
+ for connector in connectors:
184
+ if hasattr(connector, 'get'):
185
+ facts = connector().get(ref)
186
+ if facts:
187
+ add_connection_metadata(facts)
188
+ return facts
189
+
190
+ class Bunch:
191
+ """a handy bunch of variables"""
192
+ tables = []
193
+
194
+ def __init__(self, **kwargs):
195
+ self.__dict__.update(kwargs)
196
+
197
+ def __str__(self):
198
+ return f'{self.__class__.__name__}\n' + '\n '.join(
199
+ f'{k:{(20-len(k))*"."}}: {v!r}'
200
+ for k, v in self.__dict__.items()
201
+ )
202
+
203
+ class State(dict):
204
+ """State of Extraction"""
205
+
206
+ def find(self, kind):
207
+ """Return things of a kind"""
208
+ cache = self.setdefault('_cache', [])
209
+ for thing in self.setdefault(kind, []):
210
+ thing_id = id(thing)
211
+ if thing_id not in cache:
212
+ cache.append(thing_id)
213
+ yield thing
214
+
215
+ def add(self, kind, value):
216
+ """Add a value of a certain kind"""
217
+ self.setdefault(kind, []).append(value)
218
+
219
+
220
+ def extract(ref):
221
+ """Extract a reference
222
+
223
+ Extract data from a reference.
224
+ """
225
+
226
+ connectors = get_connectors()
227
+
228
+ # ref = State(ref=refs)
229
+
230
+ extracting = True
231
+ while extracting:
232
+ extracting = any(
233
+ connector().extract(ref)
234
+ for connector in connectors
235
+ )
236
+ # print(extracting)
237
+
238
+ return Bunch(
239
+ # name=ref.get('name', ref['ref']),
240
+ # ref=ref['ref'],
241
+ # tables=ref['tables'],
242
+ # text=ref['text'],
243
+ )
244
+
245
+
246
+ def load(ref):
247
+ """Get a Graph
248
+ """
249
+ graph = gitdata.graphs.Graph()
250
+ graph.add(get(ref))
251
+ return graph
@@ -0,0 +1,68 @@
1
+ """
2
+ mock data
3
+ """
4
+
5
+ import faker
6
+
7
+ from gitdata.connectors.common import BaseConnector
8
+
9
+
10
+ class FakeConnector(BaseConnector):
11
+
12
+ @property
13
+ def person(self):
14
+ fake = faker.Faker()
15
+ person = fake.profile()
16
+ first_name, last_name = person['name'].split(maxsplit=1)
17
+ return dict(
18
+ first_name=first_name,
19
+ last_name=last_name,
20
+ birthdate=person['birthdate'],
21
+ sex=person['sex']
22
+ )
23
+
24
+ @property
25
+ def people(self):
26
+ while True:
27
+ yield self.person
28
+
29
+ @property
30
+ def address(self):
31
+ fake = faker.Faker()
32
+ return dict(
33
+ street=fake.street_address(),
34
+ city=fake.city(),
35
+ state=fake.state(),
36
+ postal_code=fake.postcode(),
37
+ )
38
+
39
+ @property
40
+ def addresses(self):
41
+ while True:
42
+ yield self.address
43
+
44
+ @property
45
+ def location(self):
46
+ fake = faker.Faker()
47
+ lat, lng, name, country_code, timezone = fake.location_on_land()
48
+ return dict(
49
+ latitude=lat,
50
+ longitude=lng,
51
+ name=name,
52
+ country_code=country_code,
53
+ timezone=timezone,
54
+ )
55
+
56
+ @property
57
+ def locations(self):
58
+ while True:
59
+ yield self.location
60
+
61
+ def get(self, ref):
62
+ if ref.startswith('fake'):
63
+ print('ref is', ref)
64
+ return dict(
65
+ people=self.people,
66
+ addresses=self.addresses,
67
+ locations=self.locations,
68
+ )