使用 specs.frictionlessdata.io 上定义的数据包的实用程序
项目描述
数据包-py
用于处理数据包的库。
【重要提示】我们发布了Frictionless Framework。该框架提供了改进
datapackage的功能,扩展为完整的数据解决方案。现有软件不中断的更改,因此不需要任何操作。请阅读从无摩擦框架迁移指南。datapackage
特征
Package处理数据包的类Resource处理数据资源的类Profile使用配置文件的类validate验证数据包描述符的函数infer推断数据包描述符的函数
内容
入门
安装
该包使用语义版本控制。这意味着主要版本可能包括重大更改。强烈建议datapackage在文件中指定版本范围,setup/requirements例如datapackage>=1.0,<2.0.
$ pip install datapackage
OSX 10.14+
如果cchardet在 Mac OSX 10.14 (Mojave) 或更高版本上安装 datapackage 时收到有关包的错误,请按照以下步骤操作:
- 通过在终端中运行以下命令,确保您拥有最新的 x 代码:
xcode-select --install - 然后转到https://developer.apple.com/download/more/并下载
command line tools. 请注意,这需要 Apple ID。 - 然后,在终端中,运行
open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg您可以在这篇文章中阅读有关这些步骤的更多信息。
文档
介绍
让我们从一个简单的例子开始:
from datapackage import Package
package = Package('datapackage.json')
package.get_resource('resource').read()
使用包
用于处理数据包的类。它提供了各种功能,例如加载本地或远程数据包、推断数据包描述符、保存数据包描述符等等。
考虑我们在一个data目录中有一些本地 csv 文件。让我们使用一个类基于这些数据创建一个数据包Package:
数据/cities.csv
city,location
london,"51.50,-0.11"
paris,"48.85,2.30"
rome,"41.89,12.51"
数据/人口.csv
city,year,population
london,2017,8780000
paris,2017,2240000
rome,2017,2860000
首先我们创建一个空白数据包:
package = Package()
现在我们准备好根据我们拥有的数据文件来推断数据包描述符。因为我们有两个 csv 文件,所以我们使用 glob 模式**/*.csv:
package.infer('**/*.csv')
package.descriptor
#{ profile: 'tabular-data-package',
# resources:
# [ { path: 'data/cities.csv',
# profile: 'tabular-data-resource',
# encoding: 'utf-8',
# name: 'cities',
# format: 'csv',
# mediatype: 'text/csv',
# schema: [Object] },
# { path: 'data/population.csv',
# profile: 'tabular-data-resource',
# encoding: 'utf-8',
# name: 'population',
# format: 'csv',
# mediatype: 'text/csv',
# schema: [Object] } ] }
一个infer方法找到了我们所有的文件并检查它以提取有用的元数据,如配置文件、编码、格式、表模式等。让我们稍微调整一下:
package.descriptor['resources'][1]['schema']['fields'][1]['type'] = 'year'
package.commit()
package.valid # true
因为我们的资源是表格的,所以我们可以将其读取为表格数据:
package.get_resource('population').read(keyed=True)
#[ { city: 'london', year: 2017, population: 8780000 },
# { city: 'paris', year: 2017, population: 2240000 },
# { city: 'rome', year: 2017, population: 2860000 } ]
让我们将描述符作为 zip 文件保存在磁盘上:
package.save('datapackage.zip')
要继续使用数据包,我们只需再次加载它,但这次使用 local datapackage.zip:
package = Package('datapackage.zip')
# Continue the work
这只是对课程的基本介绍Package。要了解更多信息,让我们看一下Package类 API 参考。
使用资源
用于处理数据资源的类。您可以使用方法读取或迭代表格资源,iter/read并使用方法将所有资源作为字节读取或迭代row_iter/row_read。
考虑我们有一些本地 csv 文件。它可以是内联数据或远程链接 -Resource类都支持(当然,浏览器内使用的本地文件除外)。但是data.csv现在说:
city,location
london,"51.50,-0.11"
paris,"48.85,2.30"
rome,N/A
让我们创建并读取一个资源。因为资源是表格的,我们可以使用resource.read带有keyed选项的方法来获取键控行数组:
resource = Resource({path: 'data.csv'})
resource.tabular # true
resource.read(keyed=True)
# [
# {city: 'london', location: '51.50,-0.11'},
# {city: 'paris', location: '48.85,2.30'},
# {city: 'rome', location: 'N/A'},
# ]
resource.headers
# ['city', 'location']
# (reading has to be started first)
正如我们所见,我们的位置只是一个字符串。但它应该是地理点。罗马的位置也不可用,但它也只是一个N/A字符串而不是 Python None。首先我们必须推断资源元数据:
resource.infer()
resource.descriptor
#{ path: 'data.csv',
# profile: 'tabular-data-resource',
# encoding: 'utf-8',
# name: 'data',
# format: 'csv',
# mediatype: 'text/csv',
# schema: { fields: [ [Object], [Object] ], missingValues: [ '' ] } }
resource.read(keyed=True)
# Fails with a data validation error
让我们修复不可用的位置。表模式规范中有一个missingValues属性。作为第一次尝试,我们设置missingValues为N/Ain resource.descriptor.schema。资源描述符可以就地更改,但所有更改应由以下人员提交resource.commit():
resource.descriptor['schema']['missingValues'] = 'N/A'
resource.commit()
resource.valid # False
resource.errors
# [<ValidationError: "'N/A' is not of type 'array'">]
作为一个优秀的公民,我们决定检查资源描述符的有效性。而且是无效的!我们应该使用数组作为missingValues属性。也不要忘记将空字符串作为缺失值:
resource.descriptor['schema']['missingValues'] = ['', 'N/A']
resource.commit()
resource.valid # true
都好。看起来我们已经准备好再次读取我们的数据了:
resource.read(keyed=True)
# [
# {city: 'london', location: [51.50,-0.11]},
# {city: 'paris', location: [48.85,2.30]},
# {city: 'rome', location: null},
# ]
现在我们看到:
- 位置是具有数字纬度和经度的数组
- 罗马的位置是原生 JavaScript
null
而且由于数据读取没有错误,我们可以确定我们的数据对我们的模式是有效的。让我们保存我们的资源描述符:
resource.save('dataresource.json')
让我们检查一下新创建的dataresource.json. 它包含我们的数据文件的路径、推断的元数据和我们的missingValues调整:
{
"path": "data.csv",
"profile": "tabular-data-resource",
"encoding": "utf-8",
"name": "data",
"format": "csv",
"mediatype": "text/csv",
"schema": {
"fields": [
{
"name": "city",
"type": "string",
"format": "default"
},
{
"name": "location",
"type": "geopoint",
"format": "default"
}
],
"missingValues": [
"",
"N/A"
]
}
}
如果我们决定进一步改进它,我们可以更新dataresource.json文件,然后使用本地文件名再次打开它:
resource = Resource('dataresource.json')
# Continue the work
这只是对课程的基本介绍Resource。要了解更多信息,让我们看一下Resource类 API 参考。
与小组合作
代表一组表格资源的类。组可用于将多个资源作为一个读取或将它们导出,例如,作为一个表导出到数据库。要定义组,请将group: <name>字段添加到相应的资源。组的元数据将从“领先”资源的元数据(具有组名称的第一个资源)创建。
假设我们有一个数据包,其中包含两个按年份分区的表和一个单独存储的共享模式:
汽车-2017.csv
name,value
bmw,2017
tesla,2017
nissan,2017
汽车-2018.csv
name,value
bmw,2018
tesla,2018
nissan,2018
汽车.schema.json
{
"fields": [
{
"name": "name",
"type": "string"
},
{
"name": "value",
"type": "integer"
}
]
}
数据包.json
{
"name": "datapackage",
"resources": [
{
"group": "cars",
"name": "cars-2017",
"path": "cars-2017.csv",
"profile": "tabular-data-resource",
"schema": "cars.schema.json"
},
{
"group": "cars",
"name": "cars-2018",
"path": "cars-2018.csv",
"profile": "tabular-data-resource",
"schema": "cars.schema.json"
}
]
}
让我们分别阅读资源:
package = Package('datapackage.json')
package.get_resource('cars-2017').read(keyed=True) == [
{'name': 'bmw', 'value': 2017},
{'name': 'tesla', 'value': 2017},
{'name': 'nissan', 'value': 2017},
]
package.get_resource('cars-2018').read(keyed=True) == [
{'name': 'bmw', 'value': 2018},
{'name': 'tesla', 'value': 2018},
{'name': 'nissan', 'value': 2018},
]
另一方面,这些资源用一个group: cars字段定义。这意味着我们可以将它们视为一个群体:
package = Package('datapackage.json')
package.get_group('cars').read(keyed=True) == [
{'name': 'bmw', 'value': 2017},
{'name': 'tesla', 'value': 2017},
{'name': 'nissan', 'value': 2017},
{'name': 'bmw', 'value': 2018},
{'name': 'tesla', 'value': 2018},
{'name': 'nissan', 'value': 2018},
]
当我们需要将数据包保存到存储中时,我们可以使用这种方法,例如保存到 SQL 数据库中。有merge_groups启用分组行为的标志:
package = Package('datapackage.json')
package.save(storage='sql', engine=engine)
# SQL tables:
# - cars-2017
# - cars-2018
package.save(storage='sql', engine=engine, merge_groups=True)
# SQL tables:
# - cars
使用配置文件
一个表示来自Profiles Registry的 JSON Schema 配置文件的组件:
profile = Profile('data-package')
profile.name # data-package
profile.jsonschema # JSON Schema contents
try:
valid = profile.validate(descriptor)
except exceptions.ValidationError as exception:
for error in exception.errors:
# handle individual error
使用外键
该库支持表模式规范中描述的外键。这意味着如果您的数据包描述符resources[].schema.foreignKeys对某些资源使用属性,则将在读取操作时检查数据完整性。
考虑我们有一个数据包:
DESCRIPTOR = {
'resources': [
{
'name': 'teams',
'data': [
['id', 'name', 'city'],
['1', 'Arsenal', 'London'],
['2', 'Real', 'Madrid'],
['3', 'Bayern', 'Munich'],
],
'schema': {
'fields': [
{'name': 'id', 'type': 'integer'},
{'name': 'name', 'type': 'string'},
{'name': 'city', 'type': 'string'},
],
'foreignKeys': [
{
'fields': 'city',
'reference': {'resource': 'cities', 'fields': 'name'},
},
],
},
}, {
'name': 'cities',
'data': [
['name', 'country'],
['London', 'England'],
['Madrid', 'Spain'],
],
},
],
}
让我们检查teams资源的关系:
from datapackage import Package
package = Package(DESCRIPTOR)
teams = package.get_resource('teams')
teams.check_relations()
# tableschema.exceptions.RelationError: Foreign key "['city']" violation in row "4"
正如我们所见,存在外键违规。那是因为我们的查找表cities没有城市,Munich但我们有一个团队。我们需要在cities资源中修复它:
package.descriptor['resources'][1]['data'].append(['Munich', 'Germany'])
package.commit()
teams = package.get_resource('teams')
teams.check_relations()
# True
固定的!但不仅可以进行检查操作。我们可以使用方法的relations参数resource.iter/read来取消引用资源关系:
teams.read(keyed=True, relations=True)
#[{'id': 1, 'name': 'Arsenal', 'city': {'name': 'London', 'country': 'England}},
# {'id': 2, 'name': 'Real', 'city': {'name': 'Madrid', 'country': 'Spain}},
# {'id': 3, 'name': 'Bayern', 'city': {'name': 'Munich', 'country': 'Germany}}]
我们有一个包含城市数据的字典,而不是简单的城市名称。如果存在完整性问题,这些resource.iter/read方法将失败并显示与错误相同的错误。resource.check_relations但relations=True前提是通过标志。
使用验证/推断
验证数据包描述符的独立函数:
from datapackage import validate, exceptions
try:
valid = validate(descriptor)
except exceptions.ValidationError as exception:
for error in exception.errors:
# handle individual error
用于推断数据包描述符的独立函数。
descriptor = infer('**/*.csv')
#{ profile: 'tabular-data-resource',
# resources:
# [ { path: 'data/cities.csv',
# profile: 'tabular-data-resource',
# encoding: 'utf-8',
# name: 'cities',
# format: 'csv',
# mediatype: 'text/csv',
# schema: [Object] },
# { path: 'data/population.csv',
# profile: 'tabular-data-resource',
# encoding: 'utf-8',
# name: 'population',
# format: 'csv',
# mediatype: 'text/csv',
# schema: [Object] } ] }
经常问的问题
访问代理服务器后面的数据?
在package = Package("https://xxx.json")调用之前设置这些环境变量:
import os
os.environ["HTTP_PROXY"] = 'xxx'
os.environ["HTTPS_PROXY"] = 'xxx'
API 参考
cli
cli()
命令行界面
Usage: datapackage [OPTIONS] COMMAND [ARGS]...
Options:
--version Show the version and exit.
--help Show this message and exit.
Commands:
infer
validate
Package
Package(self,
descriptor=None,
base_path=None,
strict=False,
unsafe=False,
storage=None,
schema=None,
default_base_path=None,
**options)
包装表示
论据
- 描述符(str/dict):数据包描述符为本地路径、url或对象
- base_path (str) : 所有相对路径的基本路径
- strict (bool) : 更改验证行为的严格标志。将其设置为
True会导致对具有无效描述符的任何操作抛出错误 - unsafe (bool) : 如果
True允许不安全的路径。有关更多信息 https://specs.frictionlessdata.io/data-resource/#data-location。默认为False - storage (str/tableschema.Storage) : 存储名称
sql或存储实例 - options (dict) : 用于创建存储的存储选项
加注
DataPackageException: 如果出现问题,会引发错误
package.base_path
包的基本路径
退货
str/None:返回数据包基本路径
package.descriptor
包的描述符
退货
dict: 描述符
package.errors
验证错误
在严格模式下始终为空。
退货
Exception[]: 验证错误
package.profile
包的配置文件
退货
ProfileProfile:类的一个实例
package.resource_names
包的资源名称
退货
str[]:返回资源名称数组
package.resources
包的资源
退货
Resource[]Resource: 返回一个实例数组
package.valid
验证状态
在严格模式下始终为真。
退货
bool: 验证状态
package.get_resource
package.get_resource(name)
按名称获取数据包资源。
论据
- name (str) : 数据资源名称
退货
Resource/None: 如果没有找到,则返回Resource实例或 null
package.add_resource
package.add_resource(descriptor)
将新资源添加到数据包。
数据包描述符将使用新添加的资源描述符进行验证。
论据
- 描述符(dict):数据资源描述符
加注
DataPackageException: 如果出现问题,会引发错误
退货
Resource/None: 返回添加Resource的实例,如果没有添加则返回 null
package.remove_resource
package.remove_resource(name)
按名称删除数据包资源。
数据包描述符将在资源描述符删除后进行验证。
论据
- name (str) : 数据资源名称
加注
DataPackageException: 如果出现问题,会引发错误
退货
Resource/None:如果没有找到,则返回已删除的Resource实例或 null
package.get_group
package.get_group(name)
按名称返回一组表格资源。
有关组的更多信息,请参阅组。
论据
- name (str) : 一组资源的名称
加注
DataPackageException: 如果出现问题,会引发错误
退货
Group/None: 返回一个Group实例,如果没有找到则返回 null
package.infer
package.infer(pattern=False)
推断数据包元数据。
参数
pattern仅适用于本地文件
如果pattern未提供,则仅推断现有资源(添加元数据,如编码、配置文件等)。如果pattern提供了带有文件名的新资源,则将添加和推断模式。它提交对数据包实例的更改。
论据
- 模式(str):新资源的全局模式
退货
dict: 返回数据包描述符
package.commit
package.commit(strict=None)
如果描述符中存在就地更改,则更新数据包实例。
例子
package = Package({
'name': 'package',
'resources': [{'name': 'resource', 'data': ['data']}]
})
package.name # package
package.descriptor['name'] = 'renamed-package'
package.name # package
package.commit()
package.name # renamed-package
论据
- strict (bool) : 改变
strict模式以进行进一步的工作
加注
DataPackageException: 如果出现问题,会引发错误
退货
bool: 成功返回true,不修改返回false
package.save
package.save(target=None,
storage=None,
merge_groups=False,
to_base_path=False,
**options)
保存此数据包
如果传递参数,则将其保存到存储中;如果参数以结尾,storage则将此数据包的描述符保存到 json 文件,否则,将此数据包保存到 zip 文件。target.json
例子
file_or_path它使用此数据包的内容及其资源创建一个 zip 文件。内容存在于本地文件系统中的每个资源都将被复制到 zip 文件中。考虑以下数据包描述符:
{
"name": "gdp",
"resources": [
{"name": "local", "format": "CSV", "path": "data.csv"},
{"name": "inline", "data": [4, 8, 15, 16, 23, 42]},
{"name": "remote", "url": "http://someplace.com/data.csv"}
]
}
zip 文件的最终结构将是:
./datapackage.json
./data/local.csv
与返回的内容datapackage.json相同datapackage.descriptor。资源的文件名是根据它们的name和format字段生成的(如果它们存在的话)。如果资源没有name,它将被使用resource-X,其中X是resources列表中资源的索引(从零开始)。如果资源有format,它将被小写并附加到name,变成“ name.format”。
论据
- target (string/filelike) : 将保存此数据包内容的文件路径或类文件对象。
- storage (str/tableschema.Storage) : 存储名称
sql或存储实例 - merge_groups (bool):如果提供了存储,则将所有组的表格资源保存到一个桶中(例如,保存到一个 SQL 表中)。阅读有关集团的更多信息。
- to_base_path (bool) : 使用 "<base_path>/<target>" 路由将包保存到包的基本路径
- options (dict) : 用于创建存储的存储选项
加注
DataPackageException: 如果在编写包时出现错误,则引发
退货
bool/Storage: 成功返回 true 或Storage实例
Resource
资源(self ,
descriptor = {},
base_path = None ,
strict = False ,
unsafe =