A Python client for interacting with 1C systems via OData v3, providing ORM-like functionality, data validation, and query construction.
Project description
OData1C - A Python OData Client for 1C Systems
OData1C is a Python client designed to interact with 1C systems via their OData v3 REST endpoints.
This client aims to simplify and streamline common tasks such as querying entities, applying filters and expansions, creating and updating data, and handling related entities. It uses Pydantic for data validation and Requests for HTTP communication.
While originally inspired by PyOData1C (with only essential OData capabilities for 1C), OData1C has been refined with clearer structure, comprehensive English docstrings, improved maintainability, and extensibility.
Key Features
- OData Integration: Communicates with 1C OData endpoints (primarily tested with OData v3).
- Data Validation: Leverages Pydantic for serialization, deserialization, and validation of model data.
- ORM-Like Interface: Define your entity models as Pydantic classes inheriting from
ODataModel, and useODataandODataManagerclasses to interact with the server. - Complex Query Building:
- Filtering: Apply filters using Django-style lookups or
Qobjects. - Expansion: Fetch related nested entities via
$expand. - Pagination: Limit and skip results using
$topand$skip.
- Filtering: Apply filters using Django-style lookups or
- Chaining API: Methods like
filter(),expand(),top(), andskip()return the manager instance, allowing method chaining and cleaner query construction. - Error Handling: Provides domain-specific exceptions, validation error accumulation, and flexible error handling strategies.
- Context Manager Support: Use
Connectionas a context manager (with ... as ...) to ensure proper resource cleanup.
Installation
pip install odata1c-client
Dependencies
- Python >= 3.12
- Pydantic >= 2.7.0
- Requests >= 2.32.0
Usage
Below is a sample usage example showing how to define models and query data:
from uuid import UUID
from requests.auth import HTTPBasicAuth
from pydantic import Field
from OData1C.connection import Connection
from OData1C.models import ODataModel
from OData1C.odata.manager import OData
class MeasureUnitModel(ODataModel):
uid: UUID = Field(alias='Ref_Key', exclude=True)
name: str = Field(alias='Description', max_length=6)
class NomenclatureModel(ODataModel):
uid: UUID = Field(alias='Ref_Key', exclude=True)
code: str = Field(alias='Code', max_length=12)
name: str = Field(alias='Description', max_length=200)
measure_unit: MeasureUnitModel = Field(alias='Measure_Unit')
nested_models = {
'measure_unit': MeasureUnitModel
}
class NomenclatureOdata(OData):
database = 'database_name'
entity_model = NomenclatureModel
entity_name = 'Catalog_Nomenclature'
with Connection('ODATA_HOST',
'ODATA_PROTOCOL',
HTTPBasicAuth('ODATA_USERNAME', 'ODATA_PASSWORD')) as conn:
nomenclatures = (
NomenclatureOdata.manager(conn)
.expand('measure_unit')
.filter(code__in=['00-123', '00-456'])
.all(ignore_invalid=True)
)
for item in nomenclatures:
print(item.name, item.measure_unit.name)
You can find more examples in OData1C/example.
Connection Class
The Connection class provides an interface for sending HTTP requests to the 1C OData server.
It can be instantiated directly or used as a context manager (with ... as ...) to handle session lifecycle automatically.
Its constructor requires parameters such as host (the domain or IP of the 1C server), protocol (e.g. http or https), and authentication (e.g. HTTPBasicAuth).
You can also specify connection_timeout and read_timeout to control network timings. Internally, Connection uses the Requests library.
Example usage:
with Connection(
host='my1c.domain.ru',
protocol='http',
authentication=HTTPBasicAuth('user', 'pass')) as conn:
# Perform OData operations here
Or without a context manager:
conn = Connection(
host='my1c.domain.ru',
protocol='http',
authentication=HTTPBasicAuth('user', 'pass'))
# Perform OData operations here
Defining Models
Models must inherit from ODataModel (a Pydantic BaseModel subclass).
Use nested_models to specify related models for $expand queries:
class MyNestedModel(ODataModel):
# Define fields and aliases as needed
class MyModel(ODataModel):
# Define fields and aliases
nested_models = {
'some_related_field': MyNestedModel
}
Working with OData Entities
Create a subclass of OData and define:
- database: The service root or database name.
- entity_model: The Pydantic model class for data validation.
- entity_name: The OData entity set name.
class FooOdata(OData):
database = 'my1cdb'
entity_model = MyModel
entity_name = 'bar'
ODataManager
Obtain a manager instance and perform operations:
manager = FooOdata.manager(conn)
items = manager.all()
Common Methods in ODataManager:
-
all(ignore_invalid=False): Executes a GET request and returns validated entities. If
ignore_invalid=True, skips invalid objects and accumulates errors invalidation_errors. -
create(data): Sends a POST request to create a new entity.
datacan be either a dictionary or an instance of theentity_model(for example,MyModel) representing the new entity. -
get(guid): Fetches a single entity by
GUID. -
update(guid, data): Updates an entity identified by
GUIDusing PATCH.datacan be either a dictionary or an instance of theentity_model(for example,MyModel) containing the fields to update. -
post_document(guid, operational_mode=False): Posts (commits) a document by
GUID. -
unpost_document(guid): Unposts (reverts) a previously posted document by
GUID. -
expand(*fields): Specifies which related entities to
$expand. Accepts positional string arguments - field names for which related entities should be retrieved. The passed field names must be declared in theentity_model.nested_models(for example,MyModel.nested_models) dictionary. -
filter(...): Applies
$filterconditions. It accepts keyword arguments as conditions (lookups in Django style) or positionalQobjects. Lookup format:field__operator__annotationwhere:- field is the model field name;
- operator is one of
eq,ne,gt,ge,lt,le,in(defaults toeqif omitted); - annotation (optional) can be
GUIDordatetime.
manager.filter(foo='abc') manager.filter(bar__gt=100) manager.filter(uid_1c__in__guid=[...])
-
skip(n), top(n): Applies
$skipand$topfor pagination.
Filtering with Q
For complex filters, use Q objects and combine them with logical operators:
from OData1C.odata.query import Q
manager.filter(Q(name='Ivanov') & Q(age__gt=30))
Debugging
The ODataManager object has request and response attributes after executing a request. These hold instances of ODataRequest and requests.Response, respectively. You can inspect them for debugging:
with Connection(
host='my1c.domain.ru',
protocol='http',
authentication=HTTPBasicAuth('user', 'pass')) as conn:
manager = FooOdata.manager(conn)
bars = manager.top(3).all()
pprint(manager.request)
pprint(manager.response.json())
Contributing
Contributions are welcome! Please open issues or submit pull requests for improvements or bug fixes.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file odata1c_client-0.1.1.tar.gz.
File metadata
- Download URL: odata1c_client-0.1.1.tar.gz
- Upload date:
- Size: 10.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.4 CPython/3.13.0 Darwin/24.1.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
50ccf1fe6c1ddc323021d2984cdbcb294ada07d8867d5566c8ed13d82adc4c0b
|
|
| MD5 |
12afa0a200bd2a1f52ef5dcea1e1a0cd
|
|
| BLAKE2b-256 |
b50a2b1a41ec208473cd59947230dcc27462662a8edfbec467ec2065eb5b30b2
|
File details
Details for the file odata1c_client-0.1.1-py3-none-any.whl.
File metadata
- Download URL: odata1c_client-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.4 CPython/3.13.0 Darwin/24.1.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4da0514fdc17a24dd84ba9a65a8f40790ea5af5124148ed19c9ca9e972917688
|
|
| MD5 |
5890a39f5729546da4e6b3bb2b8bf30c
|
|
| BLAKE2b-256 |
f5c0b65ec49993c49dfd6437fd84922b51be7f9e66551fea9e14f92e3e2b1daf
|