# -*- coding: utf-8 -*-
import os
import glob
import glob
import json
import urllib2
import ogt.ags4
from . import EXAMPLES_DIR, HAVE_YAML
[docs]def to_yaml(data):
"""Serializes python data to a :ref:`yaml` string
:type data: dict or list
:param data: the python data to be encoded
:return: a `tuple` containing
- `str` with the encoded json
- An `Error` message if encoding error, otherwise `None`
"""
if HAVE_YAML == False:
return None, "Error: yaml library not installed"
import yaml
try:
yaml_str = yaml.safe_dump(data, default_flow_style=False )
return yaml_str, None
except Exception as e:
return None, "Error: %s" % str(e)
[docs]def write_yaml_file(file_path, data):
"""Saves python data in a :ref:`json` encoded file
:param file_path: The relative or absolute path of file to save.
:type file_path: str
:param data: The python data to save
:type data: dict or list
:return: `Error` message if write error, otherwise `None`
"""
with open(file_path, "w") as f:
yaml_str, err = to_yaml(data)
if err:
return err
f.write(yaml_str)
f.close()
return None
[docs]def to_json(data, minify=False):
"""Serializes python data to a :ref:`json` string
:type data: dict or list
:param data: the python data to be encoded
:type minify: bool
:param minify:
- When **`False`** the json string is minimized with no spaces, new lines etc.
- When **`True`** the json string is human readable indented with four spaces, and sorted by key.
.. note:: **Important**
- By default this project uses **`minify=False`**.
- For versioning (eg git), it is recommended to use **`minify=False`** as the string
will always be the same, ie sorted keys, and indentation
:return: a `tuple` containing
- `str` with the encoded json
- An `Error` message if encoding error, otherwise `None`
"""
# todo: catch json error
if minify:
return json.dumps(data, ensure_ascii=True, separators=(',', ':')), None
return json.dumps(data, ensure_ascii=True, indent=4, sort_keys=True, separators=(',', ': ')), None
[docs]def write_json_file(file_path, data, minify=False):
"""Saves python data in a :ref:`json` encoded file
:param file_path: The relative or absolute path of file to save.
:type file_path: str
:param data: The python data to save
:type data: dict or list
:param minify: see :func:`~ogt.utils.to_json`
:type minify: bool
:return: `Error` message if write error, otherwise `None`
"""
with open(file_path, "w") as f:
json_str, err = to_json(data, minify=minify)
if err:
return err
f.write(json_str)
f.close()
return None
[docs]def read_json_file(file_path):
"""Read and decodes a :ref:`json` encoded file
:param file_path: The relative or absolute path of file to read.
:type file_path: str
:rtype: tuple
:return:
- A decoded python `dict` or `list`
- An `Error` message if file or decoding error, otherwise `None`
"""
try:
with open(file_path, "r") as f:
data = json.load(f)
return data, None
except Exception as e:
return None, str(e)
[docs]def clean_str(source_str, replace="?"):
"""Ensure :ref:`ASCII` characters, and replace any non ascii
:param source_str: The source str to clean
:type source_str: str
:param replace: The character(s) to replace non ascii characters with
:type replace: str
:return: a `tuple` containing
- The ascii string
- `True` if a non ascii character was encounteres, otherwise `False`
"""
illegal = False
try:
sss = source_str.decode("ascii")
return sss, illegal
except UnicodeDecodeError:
safeS = ""
illegal = True
for cIdx in range(0, len(source_str)):
singleS = source_str[cIdx]
if ord(singleS) < 128:
safeS += singleS
else:
safeS += replace
return safeS, illegal
[docs]def delete_dir_contents(dir_path):
"""Deletes all the contents of a directory, not the directory itself
:type dir_path: str
:param dir_path: The relative or absolute path to the dir
"""
filelist = glob.glob("%s/*" % dir_path)
for f in filelist:
#print "f=", f
pass #os.remove(f)
[docs]def file_size(file_path, human=True):
"""Returns a file's size
:param file_path: relative or absolute path to file
:type file_path: str
:type human: bool
:param human:
- If **False**, return an **int** of the file size in bytes
- If **True** returns a **str** with bytes in Kb, MB
:return: `str` or `int` with the size
"""
b = os.path.getsize(file_path)
if human:
return file_size_format(b)
return b
[docs]def list_examples(sub_dir):
# TODO check dir exists
pth = os.path.join( EXAMPLES_DIR, sub_dir, "*.ags")
xfiles = glob.glob(pth)
return xfiles, None
[docs]def get_example_dirs():
if not os.path.exists(EXAMPLES_DIR):
return None, "dir '%s' not exist " % EXAMPLES_DIR
return sorted(os.listdir(EXAMPLES_DIR)), None
[docs]def to_int(obj):
try:
return int(obj)
except:
pass
return None
[docs]def read_file(file_path):
if not os.path.exists(file_path):
return None, "file path '%s' not exist" % file_path
with open(file_path, "r") as f:
return f.read(), None
return None, "Error reading '%' " % file_path
[docs]def write_file(file_path, contents):
with open(file_path, "w") as f:
f.write(contents)
return None
return "OOPS in write_file()"
[docs]def user_dir():
"""Path to users home dir"""
return os.path.expanduser("~")
[docs]def ogt_dir():
"""Path to open-getechnical cache directory"""
return os.path.join(user_dir(), "open-geotechnical")
[docs]def initialise():
"""Check env is sane and loads the ags data dict file"""
if not os.path.exists(ogt_dir()):
return False, "No data dict"
if not os.path.exists(ags4dd_file()):
return False, "Missing ags4 data dict"
ogt.ags4.AGS4_DD, err = read_json_file(ags4dd_file())
if err:
return False, err
ogt.ags4.AGS4_DD.keys()
return True, None
[docs]def ags4dd_file():
"""
:return: str with path to the `ags4.min.json` data dict file
"""
return os.path.join(ogt_dir(), "ags4.min.json")
[docs]def update():
"""Downloads data dict file from online
:return: An error if one occured, else None
"""
if not os.path.exists(ogt_dir()):
os.makedirs(ogt_dir())
u = "https://open-geotechnical.github.io/data/ags4.min.json"
print "Requesting: %s" % u
try:
response = urllib2.urlopen(u)
except Exception as e:
return e
txt = response.read()
## check its ok
try:
json.loads(txt)
except Exception as e:
return e
write_file(ags4dd_file(), txt)
return None