Skip to content

Commit 86eaadc

Browse files
authored
Merge branch 'main' into fix-lang-tags
2 parents 20cc148 + 17de84b commit 86eaadc

8 files changed

Lines changed: 97 additions & 94 deletions

File tree

docs/conf.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
import re
88
import sys
99
from datetime import date
10-
from rdf-sql-bulkloader import __version__
10+
11+
from rdf_sql_bulkloader import __version__
12+
1113
# -- Project information -----------------------------------------------------
1214
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
1315

14-
project = 'rdf-sql-bulkloader'
16+
project = "rdf-sql-bulkloader"
1517
copyright = 'f"{date.today().year}, Chris Mungall <cjmungall@lbl.gov>'
16-
author = 'Chris Mungall <cjmungall@lbl.gov>'
18+
author = "Chris Mungall <cjmungall@lbl.gov>"
1719
release = __version__
1820

1921
# -- General configuration ---------------------------------------------------
@@ -45,13 +47,13 @@
4547
# This pattern also affects html_static_path and html_extra_path.
4648
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
4749

48-
templates_path = ['_templates']
50+
templates_path = ["_templates"]
4951

5052
# -- Options for HTML output -------------------------------------------------
5153
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
5254

53-
html_theme = 'sphinx_rtd_theme'
54-
html_static_path = ['_static']
55+
html_theme = "sphinx_rtd_theme"
56+
html_static_path = ["_static"]
5557

5658
# The name of an image file (relative to this directory) to place at the top
5759
# of the sidebar.

src/rdf_sql_bulkloader/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44
__version__ = metadata.version(__name__)
55

6-
from rdf_sql_bulkloader.loaders.sqlite3_bulkloader import SqliteBulkloader
6+
from rdf_sql_bulkloader.loaders.sqlite3_bulkloader import SqliteBulkloader

src/rdf_sql_bulkloader/cli.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
"""Command line interface for rdf-sql-bulkloader."""
2+
import logging
23
from pathlib import Path
34

45
import click
5-
import logging
66

7-
from rdf_sql_bulkloader import __version__, SqliteBulkloader
7+
from rdf_sql_bulkloader import SqliteBulkloader, __version__
88

99
logger = logging.getLogger(__name__)
1010

11+
1112
@click.group()
1213
@click.option("-v", "--verbose", count=True)
1314
@click.option("-q", "--quiet")
@@ -30,10 +31,9 @@ def main(verbose: int, quiet: bool):
3031

3132
@main.command()
3233
@click.option("--output", "-o", required=True)
33-
@click.option("--force/--no-force",
34-
default=False,
35-
show_default=True,
36-
help="Recreates db if already present")
34+
@click.option(
35+
"--force/--no-force", default=False, show_default=True, help="Recreates db if already present"
36+
)
3737
@click.argument("files", nargs=-1)
3838
def load_sqlite(files, output, force: bool):
3939
"""Run the rdf-sql-bulkloader's demo command."""
@@ -45,13 +45,11 @@ def load_sqlite(files, output, force: bool):
4545
raise ValueError(f"Path exists {output_path}")
4646
loader = SqliteBulkloader(output)
4747
if len(files) > 1:
48-
logging.warning(f"Blank nodes may be shared TODO FIX ME")
48+
logging.warning("Blank nodes may be shared TODO FIX ME")
4949
for file in files:
5050
print(file)
5151
loader.bulkload(file)
5252

53-
54-
5553

5654
if __name__ == "__main__":
5755
main()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""
2+
loaders
3+
4+
Currently only SQLite3 is supported
5+
"""

src/rdf_sql_bulkloader/loaders/bulkloader.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
"""
2+
Base class for loaders
3+
"""
14
import re
25
from abc import ABC
36
from collections import defaultdict
47
from dataclasses import dataclass
58
from pathlib import Path
6-
from typing import Union, Tuple, Iterator, Mapping, Optional, List
9+
from typing import Iterator, List, Mapping, Optional, Tuple, Union
710

8-
import curies
911
import lightrdf
1012
from curies import Converter
1113
from prefixmaps.io.parser import load_multi_context
@@ -16,16 +18,17 @@
1618
re_blank_node = re.compile(r'^riog(\d+)$')
1719

1820

21+
1922
DDL = """
2023
CREATE TABLE statement (
21-
id TEXT,
22-
subject TEXT,
23-
predicate TEXT,
24-
object TEXT,
25-
value TEXT,
26-
datatype TEXT,
27-
language TEXT,
28-
graph TEXT
24+
id TEXT,
25+
subject TEXT,
26+
predicate TEXT,
27+
object TEXT,
28+
value TEXT,
29+
datatype TEXT,
30+
language TEXT,
31+
graph TEXT
2932
);
3033
"""
3134

@@ -70,22 +73,23 @@ def _parse_literal(o: str) -> Tuple[OBJECT_VALUE, OBJECT_DATATYPE, OBJECT_LANG]:
7073
raise ValueError(f"Cannot parse {o}")
7174
return o_value, o_datatype, o_lang
7275

76+
7377
def _parse_literal_as_value(o: str) -> str:
7478
return _parse_literal(o)[0]
7579

7680

77-
7881
@dataclass
7982
class BulkLoader(ABC):
8083
"""
8184
Base class for all bulk loaders
8285
"""
86+
8387
path: str
8488
named_prefix_maps: List[str] = None
8589
prefix_map: PREFIX_MAP = None
8690
converter: Converter = None
8791
index_statements = False
88-
92+
8993
def __post_init__(self):
9094
if self.prefix_map is None:
9195
named_prefix_maps = self.named_prefix_maps
@@ -101,7 +105,7 @@ def _set_converter(self):
101105
self.converter = Converter.from_prefix_map(self.prefix_map)
102106

103107
def bulkload(self, path: str):
104-
raise NotImplemented
108+
raise NotImplementedError
105109

106110
def _parse_node(self, o: str) -> str:
107111
if re_blank_node.match(o):
@@ -131,9 +135,9 @@ def statements(self, path: Union[Path, str]) -> Iterator[STATEMENT]:
131135
prefix_node_map = defaultdict(lambda: [None, None])
132136
statement_node_map = defaultdict(lambda: [None, None])
133137
for s, p, o in doc.search_triples(None, None, None):
134-
if p == 'http://www.w3.org/ns/shacl#prefix':
138+
if p == "http://www.w3.org/ns/shacl#prefix":
135139
prefix_node_map[s][0] = _parse_literal_as_value(o)
136-
elif p == 'http://www.w3.org/ns/shacl#namespace':
140+
elif p == "http://www.w3.org/ns/shacl#namespace":
137141
prefix_node_map[s][1] = _parse_literal_as_value(o)
138142
elif self.index_statements:
139143
# this is optional as it may be inefficient to do at the python level

tests/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import os
22
from pathlib import Path
33

4-
TEST_PREFIX_MAP = {
5-
"GO": "http://purl.obolibrary.org/obo/GO_"
6-
}
4+
TEST_PREFIX_MAP = {"GO": "http://purl.obolibrary.org/obo/GO_"}
75

86
ROOT = os.path.abspath(os.path.dirname(__file__))
97
INPUT_DIR = Path(ROOT) / "input"
@@ -15,6 +13,7 @@
1513
TEST_LANG_INPUT_OWL = INPUT_DIR / f"{TEST_LANG_BASE}.owl"
1614
TEST_LANG_INPUT_TTL = INPUT_DIR / f"{TEST_LANG_BASE}.ttl"
1715

16+
1817
def output_path(fn: str) -> str:
1918
return str(Path(OUTPUT_DIR) / fn)
2019

tests/test_sqlite3_bulkloader.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,34 @@
33
import unittest
44

55
from rdf_sql_bulkloader import SqliteBulkloader
6+
67
from tests import TEST_INPUT_OWL, NUCLEUS, TEST_PREFIX_MAP, TEST_LANG_INPUT_OWL, TEST_LANG_INPUT_TTL
78

8-
CASES =[
9-
(None, 'GO:0005634', 'RO:0002161', 'NCBITaxon:2', None, None, None, None),
10-
(None, 'GO:0005634', 'IAO:0000115', None, "A membrane-bounded organelle of eukaryotic cells in which chromosomes are housed and replicated. In most cells, the nucleus contains all of the cell's chromosomes except the organellar chromosomes, and is the site of RNA synthesis and processing. In some species, or in specialized cell types, RNA metabolism or DNA replication may be absent.", 'http://www.w3.org/2001/XMLSchema#string', None, None),
11-
(None, 'GO:0005634', 'rdf:type', 'owl:Class', None, None, None, None),
9+
DEFN = (
10+
"A membrane-bounded organelle of eukaryotic cells in which chromosomes "
11+
+ "are housed and replicated. In most cells, the nucleus contains all of the cell's "
12+
+ "chromosomes except the organellar chromosomes, and is the site of RNA synthesis "
13+
+ "and processing. In some species, or in specialized cell types, "
14+
+ "RNA metabolism or DNA replication may be absent."
15+
)
16+
17+
18+
CASES = [
19+
(None, "GO:0005634", "RO:0002161", "NCBITaxon:2", None, None, None, None),
20+
(
21+
None,
22+
"GO:0005634",
23+
"IAO:0000115",
24+
None,
25+
DEFN,
26+
"http://www.w3.org/2001/XMLSchema#string",
27+
None,
28+
None,
29+
),
30+
(None, "GO:0005634", "rdf:type", "owl:Class", None, None, None, None),
1231
]
1332

33+
1434
class TestSqlit3BulkLoader(unittest.TestCase):
1535
"""Test sqlite3."""
1636

@@ -47,3 +67,4 @@ def test_lang_tags_ttl(self):
4767
loader.bulkload(TEST_LANG_INPUT_TTL)
4868

4969

70+

tox.ini

Lines changed: 30 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,64 +4,31 @@
44
# and then run "tox" from this directory.
55

66
[tox]
7-
# To use a PEP 517 build-backend you are required to configure tox to use an isolated_build:
8-
# https://tox.readthedocs.io/en/latest/example/package.html
9-
isolated_build = True
10-
skipsdist = True
11-
7+
isolated_build = true
128
envlist =
13-
# always keep coverage-clean first
14-
coverage-clean
159
lint
1610
flake8
17-
mypy
18-
docstr-coverage
19-
py
20-
21-
[testenv]
22-
whitelist_externals =
23-
poetry
24-
commands =
25-
poetry run pytest
26-
description = Run unit tests with pytest. This is a special environment that does not get a name, and
27-
can be referenced with "py".
28-
29-
[testenv:coverage-clean]
30-
deps = coverage
31-
skip_install = true
32-
commands = coverage erase
3311

3412
[testenv:lint]
3513
deps =
3614
black
3715
isort
3816
skip_install = true
3917
commands =
40-
black src/ tests/
41-
isort src/ tests/
18+
black .
19+
isort .
4220
description = Run linters.
4321

44-
[testenv:doclint]
45-
deps =
46-
rstfmt
47-
skip_install = true
48-
commands =
49-
rstfmt docs/source/
50-
description = Run documentation linters.
51-
5222
[testenv:flake8]
5323
skip_install = true
5424
deps =
55-
darglint
5625
flake8<5.0.0
57-
flake8-black
5826
flake8-bandit
27+
flake8-black
5928
flake8-bugbear
6029
flake8-colors
61-
flake8-docstrings
6230
flake8-isort
63-
flake8-print
64-
pydocstyle
31+
pep8-naming
6532
commands =
6633
flake8 src/ tests/
6734
description = Run the flake8 tool with several plugins (bandit, docstrings, import order, pep8 naming).
@@ -72,22 +39,29 @@ description = Run the flake8 tool with several plugins (bandit, docstrings, impo
7239
#########################
7340
[flake8]
7441
ignore =
75-
DAR101 # Missing parameter(s) in Docstring: - with_git_hash
76-
DAR201 # Missing "Returns" in Docstring: - return
77-
DAR301 # Missing "Yields" in Docstring: - yield
78-
E111 # indentation is not a multiple of 4
79-
T201 # print found.
80-
81-
[testenv:mypy]
82-
deps = mypy
83-
skip_install = true
84-
commands = mypy --install-types --non-interactive --ignore-missing-imports src/
85-
description = Run the mypy tool to check static typing on the project.
42+
E203
43+
W503
44+
C901 # needs code change so ignoring for now.
45+
E731 # needs code change so ignoring for now.
46+
S101 # asserts are fine
47+
S106 # flags false positives with test_table_filler
48+
N801 # mixed case is bad but there's a lot of auto-generated code
49+
N815 # same ^
50+
S404 # Consider possible security implications associated with the subprocess module.
51+
S108 # Probable insecure usage of temp file/directory.
52+
S307 # Use of possibly insecure function - consider using safer ast.literal_eval.
53+
S603 # subprocess call - check for execution of untrusted input.
54+
S607 # Starting a process with a partial executable path ["open" in both cases]
55+
S608 # Possible SQL injection vector through string-based query construction.
56+
B024 # StreamingWriter is an abstract base class, but it has no abstract methods.
57+
# Remember to use @abstractmethod, @abstractclassmethod and/or @abstractproperty decorators.
58+
per-file-ignores = __init__.py:F401
8659

87-
[testenv:docstr-coverage]
88-
skip_install = true
89-
deps =
90-
docstr-coverage
91-
commands =
92-
docstr-coverage src/ tests/ --skip-private --skip-magic
93-
description = Run the docstr-coverage tool to check documentation coverage
60+
max-line-length = 120
61+
max-complexity = 13
62+
import-order-style = pycharm
63+
application-import-names =
64+
oaklib
65+
tests
66+
exclude =
67+
datamodels ## datamodels are auto-generated

0 commit comments

Comments
 (0)